aboutsummaryrefslogtreecommitdiff
path: root/extension
diff options
context:
space:
mode:
Diffstat (limited to 'extension')
-rw-r--r--extension/src/openvic-extension/singletons/AssetManager.cpp130
-rw-r--r--extension/src/openvic-extension/singletons/AssetManager.hpp43
-rw-r--r--extension/src/openvic-extension/singletons/GameSingleton.cpp2
-rw-r--r--extension/src/openvic-extension/utility/UITools.cpp24
4 files changed, 147 insertions, 52 deletions
diff --git a/extension/src/openvic-extension/singletons/AssetManager.cpp b/extension/src/openvic-extension/singletons/AssetManager.cpp
index 083d934..6646c8b 100644
--- a/extension/src/openvic-extension/singletons/AssetManager.cpp
+++ b/extension/src/openvic-extension/singletons/AssetManager.cpp
@@ -13,9 +13,14 @@ using OpenVic::Utilities::godot_to_std_string;
using OpenVic::Utilities::std_to_godot_string;
void AssetManager::_bind_methods() {
- OV_BIND_METHOD(AssetManager::get_image, { "path", "cache", "flip_y" }, DEFVAL(true), DEFVAL(false));
- OV_BIND_METHOD(AssetManager::get_texture, { "path", "flip_y" }, DEFVAL(false));
+ OV_BIND_METHOD(AssetManager::get_image, { "path", "load_flags" }, DEFVAL(LOAD_FLAG_CACHE_IMAGE));
+ OV_BIND_METHOD(AssetManager::get_texture, { "path", "load_flags" }, DEFVAL(LOAD_FLAG_CACHE_TEXTURE));
OV_BIND_METHOD(AssetManager::get_font, { "name" });
+
+ BIND_ENUM_CONSTANT(LOAD_FLAG_NONE);
+ BIND_ENUM_CONSTANT(LOAD_FLAG_CACHE_IMAGE);
+ BIND_ENUM_CONSTANT(LOAD_FLAG_CACHE_TEXTURE);
+ BIND_ENUM_CONSTANT(LOAD_FLAG_FLIP_Y);
}
AssetManager* AssetManager::get_singleton() {
@@ -32,55 +37,95 @@ AssetManager::~AssetManager() {
_singleton = nullptr;
}
-Ref<Image> AssetManager::_load_image(StringName const& path) {
+Ref<Image> AssetManager::_load_image(StringName const& path, bool flip_y) {
GameSingleton* game_singleton = GameSingleton::get_singleton();
ERR_FAIL_NULL_V(game_singleton, nullptr);
+
const String lookedup_path =
std_to_godot_string(game_singleton->get_dataloader().lookup_image_file(godot_to_std_string(path)).string());
ERR_FAIL_COND_V_MSG(lookedup_path.is_empty(), nullptr, vformat("Failed to look up image: %s", path));
+
const Ref<Image> image = Utilities::load_godot_image(lookedup_path);
ERR_FAIL_COND_V_MSG(
- image.is_null() || image->is_empty(), nullptr, vformat("Failed to load image: %s (looked up: %s)", path, lookedup_path)
+ image.is_null() || image->is_empty(), nullptr,
+ vformat("Failed to load image: %s (looked up: %s)", path, lookedup_path)
);
- return image;
-}
-AssetManager::image_asset_t* AssetManager::_get_image_asset(StringName const& path, bool flip_y) {
- image_asset_map_t::iterator it = image_assets.find(path);
- if (it != image_assets.end()) {
- return &it.value();
- }
- const Ref<Image> image = _load_image(path);
- ERR_FAIL_NULL_V(image, nullptr);
if (flip_y) {
image->flip_y();
}
- return &image_assets.emplace(std::move(path), AssetManager::image_asset_t { image, nullptr }).first.value();
+
+ return image;
}
-Ref<Image> AssetManager::get_image(StringName const& path, bool cache, bool flip_y) {
- if (cache) {
- image_asset_t const* asset = _get_image_asset(path, flip_y);
- ERR_FAIL_NULL_V(asset, nullptr);
- return asset->image;
+Ref<Image> AssetManager::get_image(StringName const& path, LoadFlags load_flags) {
+ /* Check for an existing image entry indicating a previous load attempt, whether successful or not. */
+ const image_asset_map_t::iterator it = image_assets.find(path);
+ if (it != image_assets.end()) {
+ std::optional<Ref<Image>> const& cached_image = it->second.image;
+
+ if (cached_image.has_value()) {
+ ERR_FAIL_NULL_V_MSG(*cached_image, nullptr, vformat("Failed to load image previously: %s", path));
+
+ return *cached_image;
+ }
+ }
+
+ /* No load attempt has been made yet, so we try now. */
+ const Ref<Image> image = _load_image(path, load_flags & LOAD_FLAG_FLIP_Y);
+
+ if (image.is_valid()) {
+ if (load_flags & LOAD_FLAG_CACHE_IMAGE) {
+ image_assets[path].image = image;
+ }
+
+ return image;
} else {
- return _load_image(path);
+ /* Mark both image and texture as failures, regardless of cache flags, in case of future load/creation attempts. */
+ image_assets[path] = { nullptr, nullptr };
+
+ ERR_FAIL_V_MSG(nullptr, vformat("Failed to load image: %s", path));
}
}
-Ref<ImageTexture> AssetManager::get_texture(StringName const& path, bool flip_y) {
- image_asset_t* asset = _get_image_asset(path, flip_y);
- ERR_FAIL_NULL_V(asset, nullptr);
- if (asset->texture.is_null()) {
- asset->texture = ImageTexture::create_from_image(asset->image);
- ERR_FAIL_NULL_V_MSG(asset->texture, nullptr, vformat("Failed to turn image into texture: %s", path));
+Ref<ImageTexture> AssetManager::get_texture(StringName const& path, LoadFlags load_flags) {
+ /* Check for an existing texture entry indicating a previous creation attempt, whether successful or not. */
+ const image_asset_map_t::const_iterator it = image_assets.find(path);
+ if (it != image_assets.end()) {
+ std::optional<Ref<ImageTexture>> const& cached_texture = it->second.texture;
+
+ if (cached_texture.has_value()) {
+ ERR_FAIL_NULL_V_MSG(*cached_texture, nullptr, vformat("Failed to create texture previously: %s", path));
+
+ return *cached_texture;
+ }
+ }
+
+ /* No creation attempt has yet been made, so we try now starting by finding the corresponding image. */
+ const Ref<Image> image = get_image(path, load_flags);
+ ERR_FAIL_NULL_V_MSG(image, nullptr, vformat("Failed to load image for texture: %s", path));
+
+ const Ref<ImageTexture> texture = ImageTexture::create_from_image(image);
+
+ if (texture.is_valid()) {
+ if (load_flags & LOAD_FLAG_CACHE_TEXTURE) {
+ image_assets[path].texture = texture;
+ }
+
+ return texture;
+ } else {
+ /* Mark texture as a failure, regardless of cache flags, in case of future creation attempts. */
+ image_assets[path].texture = nullptr;
+
+ ERR_FAIL_V_MSG(nullptr, vformat("Failed to create texture: %s", path));
}
- return asset->texture;
}
Ref<Font> AssetManager::get_font(StringName const& name) {
const font_map_t::const_iterator it = fonts.find(name);
if (it != fonts.end()) {
+ ERR_FAIL_NULL_V_MSG(it->second, nullptr, vformat("Failed to load font previously: %s", name));
+
return it->second;
}
@@ -89,18 +134,35 @@ Ref<Font> AssetManager::get_font(StringName const& name) {
static const String image_ext = ".tga";
const StringName image_path = font_dir + name + image_ext;
- const Ref<Image> image = get_image(image_path);
- ERR_FAIL_NULL_V_MSG(image, nullptr, vformat("Failed to load font image %s for the font named %s", image_path, name));
+ const Ref<Image> image = get_image(image_path, LOAD_FLAG_NONE);
+ if (image.is_null()) {
+ fonts.emplace(name, nullptr);
+
+ ERR_FAIL_V_MSG(nullptr, vformat("Failed to load font image %s for the font named %s", image_path, name));
+ }
+
GameSingleton* game_singleton = GameSingleton::get_singleton();
ERR_FAIL_NULL_V(game_singleton, nullptr);
+
const String font_path = font_dir + name + font_ext;
const String lookedup_font_path =
std_to_godot_string(game_singleton->get_dataloader().lookup_file(godot_to_std_string(font_path)).string());
+ if (lookedup_font_path.is_empty()) {
+ fonts.emplace(name, nullptr);
+
+ ERR_FAIL_V_MSG(nullptr, vformat("Failed to look up font: %s", font_path));
+ }
+
const Ref<Font> font = Utilities::load_godot_font(lookedup_font_path, image);
- ERR_FAIL_NULL_V_MSG(
- font, nullptr,
- vformat("Failed to load font file %s (looked up: %s) for the font named %s", font_path, lookedup_font_path, name)
- );
- fonts.emplace(std::move(name), font);
+ if (font.is_null()) {
+ fonts.emplace(name, nullptr);
+
+ ERR_FAIL_V_MSG(
+ nullptr,
+ vformat("Failed to load font file %s (looked up: %s) for the font named %s", font_path, lookedup_font_path, name)
+ );
+ }
+
+ fonts.emplace(name, font);
return font;
}
diff --git a/extension/src/openvic-extension/singletons/AssetManager.hpp b/extension/src/openvic-extension/singletons/AssetManager.hpp
index c718d2a..0856d05 100644
--- a/extension/src/openvic-extension/singletons/AssetManager.hpp
+++ b/extension/src/openvic-extension/singletons/AssetManager.hpp
@@ -13,9 +13,22 @@ namespace OpenVic {
static inline AssetManager* _singleton = nullptr;
+ public:
+ enum LoadFlags {
+ LOAD_FLAG_NONE = 0,
+ LOAD_FLAG_CACHE_IMAGE = 1 << 0,
+ LOAD_FLAG_CACHE_TEXTURE = 1 << 1,
+ LOAD_FLAG_FLIP_Y = 1 << 2
+ };
+
+ constexpr friend LoadFlags operator|(LoadFlags lhs, LoadFlags rhs) {
+ return static_cast<LoadFlags>(static_cast<int>(lhs) | static_cast<int>(rhs));
+ }
+
+ private:
struct image_asset_t {
- godot::Ref<godot::Image> image;
- godot::Ref<godot::ImageTexture> texture;
+ std::optional<godot::Ref<godot::Image>> image;
+ std::optional<godot::Ref<godot::ImageTexture>> texture;
};
/* deque_ordered_map to avoid the need to reallocate. */
using image_asset_map_t = deque_ordered_map<godot::StringName, image_asset_t>;
@@ -24,8 +37,7 @@ namespace OpenVic {
image_asset_map_t image_assets;
font_map_t fonts;
- static godot::Ref<godot::Image> _load_image(godot::StringName const& path);
- image_asset_t* _get_image_asset(godot::StringName const& path, bool flip_y);
+ static godot::Ref<godot::Image> _load_image(godot::StringName const& path, bool flip_y);
protected:
static void _bind_methods();
@@ -37,16 +49,27 @@ namespace OpenVic {
~AssetManager();
/* Search for and load an image at the specified path relative to the game defines, first checking the AssetManager's
- * image cache (if cache is true) in case it has already been loaded, and returning nullptr if image loading fails. */
- godot::Ref<godot::Image> get_image(godot::StringName const& path, bool cache = true, bool flip_y = false);
+ * image cache in case it has already been loaded, and returning nullptr if image loading fails. If the cache image
+ * load flag is set then the loaded image will be stored in the AssetManager's image cache for future access; if the
+ * flip y load flag is set then the image will be flipped vertically before being returned (if the image is already
+ * in the cache then no flipping will occur, regardless of whether it was orginally flipped or not). */
+ godot::Ref<godot::Image> get_image(godot::StringName const& path, LoadFlags load_flags = LOAD_FLAG_CACHE_IMAGE);
- /* Create a texture from an image found at the specified path relative to the game defines, fist checking
- * AssetManager's texture cache in case it has already been loaded, and returning nullptr if image loading
- * or texture creation fails. */
- godot::Ref<godot::ImageTexture> get_texture(godot::StringName const& path, bool flip_y = false);
+ /* Create a texture from an image found at the specified path relative to the game defines, fist checking the
+ * AssetManager's texture cache in case it has already been loaded, and returning nullptr if image loading or texture
+ * creation fails. If the cache image load flag is set then the loaded image will be stored in the AssetManager's
+ * image cache for future access; if the cache texture load flag is set then the created texture will be stored in the
+ * AssetManager's texture cache for future access; if the flip y load flag is set then the image will be flipped
+ * vertically before being used to create the texture (if the image is already in the cache then no flipping will
+ * occur, regardless of whether it was orginally flipped or not). */
+ godot::Ref<godot::ImageTexture> get_texture(
+ godot::StringName const& path, LoadFlags load_flags = LOAD_FLAG_CACHE_TEXTURE
+ );
/* Search for and load a font with the specified name from the game defines' font directory, first checking the
* AssetManager's font cache in case it has already been loaded, and returning nullptr if font loading fails. */
godot::Ref<godot::Font> get_font(godot::StringName const& name);
};
}
+
+VARIANT_ENUM_CAST(OpenVic::AssetManager::LoadFlags);
diff --git a/extension/src/openvic-extension/singletons/GameSingleton.cpp b/extension/src/openvic-extension/singletons/GameSingleton.cpp
index df0e9a0..b8aef4f 100644
--- a/extension/src/openvic-extension/singletons/GameSingleton.cpp
+++ b/extension/src/openvic-extension/singletons/GameSingleton.cpp
@@ -339,7 +339,7 @@ Error GameSingleton::_load_terrain_variants() {
AssetManager* asset_manager = AssetManager::get_singleton();
ERR_FAIL_NULL_V(asset_manager, FAILED);
// Load the terrain texture sheet and prepare to slice it up
- Ref<Image> terrain_sheet = asset_manager->get_image(terrain_texturesheet_path);
+ Ref<Image> terrain_sheet = asset_manager->get_image(terrain_texturesheet_path, AssetManager::LOAD_FLAG_NONE);
ERR_FAIL_NULL_V_MSG(terrain_sheet, FAILED, vformat("Failed to load terrain texture sheet: %s", terrain_texturesheet_path));
static constexpr int32_t SHEET_DIMS = 8, SHEET_SIZE = SHEET_DIMS * SHEET_DIMS;
diff --git a/extension/src/openvic-extension/utility/UITools.cpp b/extension/src/openvic-extension/utility/UITools.cpp
index 4af2b74..510c6da 100644
--- a/extension/src/openvic-extension/utility/UITools.cpp
+++ b/extension/src/openvic-extension/utility/UITools.cpp
@@ -187,10 +187,12 @@ static bool generate_icon(generate_gui_args_t&& args) {
GFX::ProgressBar const* progress_bar = icon.get_sprite()->cast_to<GFX::ProgressBar>();
+ using enum AssetManager::LoadFlags;
+
Ref<ImageTexture> back_texture;
if (!progress_bar->get_back_texture_file().empty()) {
const StringName back_texture_file = std_view_to_godot_string_name(progress_bar->get_back_texture_file());
- back_texture = args.asset_manager.get_texture(back_texture_file, true);
+ back_texture = args.asset_manager.get_texture(back_texture_file, LOAD_FLAG_CACHE_TEXTURE | LOAD_FLAG_FLIP_Y);
if (back_texture.is_null()) {
UtilityFunctions::push_error(
"Failed to load progress bar sprite back texture ", back_texture_file, " for GUI icon ", icon_name
@@ -221,11 +223,14 @@ static bool generate_icon(generate_gui_args_t&& args) {
Ref<ImageTexture> progress_texture;
if (!progress_bar->get_progress_texture_file().empty()) {
- const StringName progress_texture_file = std_view_to_godot_string_name(progress_bar->get_progress_texture_file());
- progress_texture = args.asset_manager.get_texture(progress_texture_file, true);
+ const StringName progress_texture_file =
+ std_view_to_godot_string_name(progress_bar->get_progress_texture_file());
+ progress_texture =
+ args.asset_manager.get_texture(progress_texture_file, LOAD_FLAG_CACHE_TEXTURE | LOAD_FLAG_FLIP_Y);
if (progress_texture.is_null()) {
UtilityFunctions::push_error(
- "Failed to load progress bar sprite progress texture ", progress_texture_file, " for GUI icon ", icon_name
+ "Failed to load progress bar sprite progress texture ", progress_texture_file, " for GUI icon ",
+ icon_name
);
ret = false;
}
@@ -237,7 +242,8 @@ static bool generate_icon(generate_gui_args_t&& args) {
);
if (progress_texture.is_null()) {
UtilityFunctions::push_error(
- "Failed to generate progress bar sprite ", progress_colour, " progress texture for GUI icon ", icon_name
+ "Failed to generate progress bar sprite ", progress_colour, " progress texture for GUI icon ",
+ icon_name
);
ret = false;
}
@@ -252,7 +258,9 @@ static bool generate_icon(generate_gui_args_t&& args) {
}
// TODO - work out why progress bar is missing bottom border pixel (e.g. province building expansion bar)
- godot_progress_bar->set_custom_minimum_size(Utilities::to_godot_fvec2(static_cast<fvec2_t>(progress_bar->get_size())));
+ godot_progress_bar->set_custom_minimum_size(
+ Utilities::to_godot_fvec2(static_cast<fvec2_t>(progress_bar->get_size()))
+ );
args.result = godot_progress_bar;
} else if (icon.get_sprite()->is_type<GFX::PieChart>()) {
@@ -286,7 +294,9 @@ static bool generate_icon(generate_gui_args_t&& args) {
const float rotation = icon.get_rotation();
if (rotation != 0.0f) {
args.result->set_position(
- args.result->get_position() - args.result->get_custom_minimum_size().height * Vector2 { sin(rotation), cos(rotation) - 1.0f }
+ args.result->get_position() - args.result->get_custom_minimum_size().height * Vector2 {
+ sin(rotation), cos(rotation) - 1.0f
+ }
);
args.result->set_rotation(-rotation);
}