diff options
author | Hop311 <Hop3114@gmail.com> | 2024-02-19 23:35:27 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-02-19 23:35:27 +0100 |
commit | 5d7c6eafe35e2c6e952bc0b3f91d27d760c8e75e (patch) | |
tree | 1912fb231991b53dd638a295bb8d8f84b587885b /extension/src/openvic-extension/classes | |
parent | 275cfbb62fe69828aeb9968110ad822447322a4e (diff) | |
parent | c48d14ca66d47ea7c25bb9a36c3d51f76d8351fc (diff) |
Merge pull request #208 from OpenVicProject/sprite-texture
Added multipurpose GFXSpriteTexture + reworked GFXButtonStateTexture
Diffstat (limited to 'extension/src/openvic-extension/classes')
-rw-r--r-- | extension/src/openvic-extension/classes/GFXButtonStateTexture.cpp | 61 | ||||
-rw-r--r-- | extension/src/openvic-extension/classes/GFXButtonStateTexture.hpp | 32 | ||||
-rw-r--r-- | extension/src/openvic-extension/classes/GFXIconTexture.cpp | 142 | ||||
-rw-r--r-- | extension/src/openvic-extension/classes/GFXMaskedFlagTexture.cpp | 58 | ||||
-rw-r--r-- | extension/src/openvic-extension/classes/GFXMaskedFlagTexture.hpp | 19 | ||||
-rw-r--r-- | extension/src/openvic-extension/classes/GFXSpriteTexture.cpp | 159 | ||||
-rw-r--r-- | extension/src/openvic-extension/classes/GFXSpriteTexture.hpp (renamed from extension/src/openvic-extension/classes/GFXIconTexture.hpp) | 33 | ||||
-rw-r--r-- | extension/src/openvic-extension/classes/GUINode.cpp | 2 | ||||
-rw-r--r-- | extension/src/openvic-extension/classes/GUINode.hpp | 6 |
9 files changed, 283 insertions, 229 deletions
diff --git a/extension/src/openvic-extension/classes/GFXButtonStateTexture.cpp b/extension/src/openvic-extension/classes/GFXButtonStateTexture.cpp index e6dff1f..dcee965 100644 --- a/extension/src/openvic-extension/classes/GFXButtonStateTexture.cpp +++ b/extension/src/openvic-extension/classes/GFXButtonStateTexture.cpp @@ -1,5 +1,7 @@ #include "GFXButtonStateTexture.hpp" +#include <godot_cpp/variant/utility_functions.hpp> + #include "openvic-extension/utility/ClassBindings.hpp" using namespace OpenVic; @@ -9,8 +11,6 @@ void GFXButtonStateTexture::_bind_methods() { OV_BIND_METHOD(GFXButtonStateTexture::set_button_state, { "new_button_state" }); OV_BIND_METHOD(GFXButtonStateTexture::get_button_state); - OV_BIND_SMETHOD(get_generate_state_image_func_name); - OV_BIND_SMETHOD(button_state_to_theme_name, { "button_state" }); OV_BIND_METHOD(GFXButtonStateTexture::get_button_state_theme); @@ -24,14 +24,14 @@ void GFXButtonStateTexture::_bind_methods() { GFXButtonStateTexture::GFXButtonStateTexture() : button_state { HOVER } {} Ref<GFXButtonStateTexture> GFXButtonStateTexture::make_gfx_button_state_texture( - ButtonState button_state, Ref<Image> const& source_image + ButtonState button_state, Ref<Image> const& source_image, Rect2i const& region ) { Ref<GFXButtonStateTexture> button_state_texture; button_state_texture.instantiate(); ERR_FAIL_NULL_V(button_state_texture, nullptr); button_state_texture->set_button_state(button_state); if (source_image.is_valid()) { - ERR_FAIL_COND_V(button_state_texture->generate_state_image(source_image) != OK, nullptr); + ERR_FAIL_COND_V(button_state_texture->generate_state_image(source_image, region) != OK, nullptr); } return button_state_texture; } @@ -41,14 +41,16 @@ void GFXButtonStateTexture::set_button_state(ButtonState new_button_state) { button_state = new_button_state; } -Error GFXButtonStateTexture::generate_state_image(Ref<Image> const& source_image) { +Error GFXButtonStateTexture::generate_state_image(Ref<Image> const& source_image, Rect2i const& region) { ERR_FAIL_COND_V(source_image.is_null() || source_image->is_empty(), FAILED); + const Rect2i source_image_rect { {}, source_image->get_size() }; + ERR_FAIL_COND_V(!region.has_area() || !source_image_rect.encloses(region), FAILED); /* Whether we've already set the ImageTexture to an image of the right dimensions and format, * and so can update it without creating and setting a new image, or not. */ - const bool can_update = state_image.is_valid() && state_image->get_size() == source_image->get_size() + const bool can_update = state_image.is_valid() && state_image->get_size() == region.get_size() && state_image->get_format() == source_image->get_format(); if (!can_update) { - state_image = Image::create(source_image->get_width(), source_image->get_height(), false, source_image->get_format()); + state_image = Image::create(region.size.width, region.size.height, false, source_image->get_format()); ERR_FAIL_NULL_V(state_image, FAILED); } @@ -67,7 +69,7 @@ Error GFXButtonStateTexture::generate_state_image(Ref<Image> const& source_image for (Vector2i point { 0, 0 }; point.y < state_image->get_height(); ++point.y) { for (point.x = 0; point.x < state_image->get_width(); ++point.x) { - state_image->set_pixelv(point, colour_func(source_image->get_pixelv(point))); + state_image->set_pixelv(point, colour_func(source_image->get_pixelv(region.position + point))); } } @@ -79,16 +81,11 @@ Error GFXButtonStateTexture::generate_state_image(Ref<Image> const& source_image return OK; } -StringName const& GFXButtonStateTexture::get_generate_state_image_func_name() { - static const StringName generate_state_image_func_name = "generate_state_image"; - return generate_state_image_func_name; -} - StringName const& GFXButtonStateTexture::button_state_to_theme_name(ButtonState button_state) { static const StringName theme_name_hover = "hover"; static const StringName theme_name_pressed = "pressed"; static const StringName theme_name_disabled = "disabled"; - static const StringName theme_name_error = ""; + static const StringName theme_name_error = "INVALID BUTTON STATE"; switch (button_state) { case HOVER: return theme_name_hover; @@ -104,3 +101,39 @@ StringName const& GFXButtonStateTexture::button_state_to_theme_name(ButtonState StringName const& GFXButtonStateTexture::get_button_state_theme() const { return button_state_to_theme_name(button_state); } + +void GFXButtonStateHavingTexture::_bind_methods() { + OV_BIND_METHOD(GFXButtonStateHavingTexture::get_button_state_texture, { "button_state" }); +} + +void GFXButtonStateHavingTexture::_update_button_states() { + for (Ref<GFXButtonStateTexture>& button_state_texture : button_state_textures) { + if (button_state_texture.is_valid()) { + button_state_texture->generate_state_image(button_image, get_region()); + } + } +} + +void GFXButtonStateHavingTexture::_clear_button_states() { + set_atlas(nullptr); + set_region({}); + button_image.unref(); + for (Ref<GFXButtonStateTexture>& button_state_texture : button_state_textures) { + button_state_texture.unref(); + } +} + +GFXButtonStateHavingTexture::GFXButtonStateHavingTexture() : button_image {}, button_state_textures {} {} + +Ref<GFXButtonStateTexture> GFXButtonStateHavingTexture::get_button_state_texture( + GFXButtonStateTexture::ButtonState button_state +) { + const size_t button_state_index = button_state; + ERR_FAIL_COND_V(button_state_index >= button_state_textures.size(), nullptr); + Ref<GFXButtonStateTexture>& button_state_texture = button_state_textures[button_state_index]; + if (button_state_texture.is_null()) { + button_state_texture = GFXButtonStateTexture::make_gfx_button_state_texture(button_state, button_image, get_region()); + ERR_FAIL_NULL_V(button_state_texture, nullptr); + } + return button_state_texture; +} diff --git a/extension/src/openvic-extension/classes/GFXButtonStateTexture.hpp b/extension/src/openvic-extension/classes/GFXButtonStateTexture.hpp index 32f4087..c98159d 100644 --- a/extension/src/openvic-extension/classes/GFXButtonStateTexture.hpp +++ b/extension/src/openvic-extension/classes/GFXButtonStateTexture.hpp @@ -1,5 +1,6 @@ #pragma once +#include <godot_cpp/classes/atlas_texture.hpp> #include <godot_cpp/classes/image_texture.hpp> #include <openvic-simulation/utility/Getters.hpp> @@ -12,7 +13,8 @@ namespace OpenVic { enum ButtonState { HOVER, PRESSED, - DISABLED + DISABLED, + BUTTON_STATE_COUNT }; private: @@ -27,20 +29,38 @@ namespace OpenVic { /* Create a GFXButtonStateTexture using the specified godot::Image. Returns nullptr if generate_state_image fails. */ static godot::Ref<GFXButtonStateTexture> make_gfx_button_state_texture( - ButtonState button_state, godot::Ref<godot::Image> const& source_image = nullptr + ButtonState button_state, godot::Ref<godot::Image> const& source_image, godot::Rect2i const& region ); /* Set the ButtonState to be generated by this class (calling this does not trigger state image generation). */ void set_button_state(ButtonState new_button_state); - /* Generate a modified version of source_image and update the underlying godot::ImageTexture to use it. */ - godot::Error generate_state_image(godot::Ref<godot::Image> const& source_image); - - static godot::StringName const& get_generate_state_image_func_name(); + /* Generate a modified version of the given region of source_image + * and update the underlying godot::ImageTexture to use it. */ + godot::Error generate_state_image(godot::Ref<godot::Image> const& source_image, godot::Rect2i const& region); static godot::StringName const& button_state_to_theme_name(ButtonState button_state); godot::StringName const& get_button_state_theme() const; }; + + class GFXButtonStateHavingTexture : public godot::AtlasTexture { + GDCLASS(GFXButtonStateHavingTexture, godot::AtlasTexture) + + std::array<godot::Ref<GFXButtonStateTexture>, GFXButtonStateTexture::BUTTON_STATE_COUNT> button_state_textures; + + protected: + static void _bind_methods(); + + godot::Ref<godot::Image> button_image; + + void _update_button_states(); + void _clear_button_states(); + + GFXButtonStateHavingTexture(); + + public: + godot::Ref<GFXButtonStateTexture> get_button_state_texture(GFXButtonStateTexture::ButtonState button_state); + }; } VARIANT_ENUM_CAST(OpenVic::GFXButtonStateTexture::ButtonState); diff --git a/extension/src/openvic-extension/classes/GFXIconTexture.cpp b/extension/src/openvic-extension/classes/GFXIconTexture.cpp deleted file mode 100644 index 99df7e4..0000000 --- a/extension/src/openvic-extension/classes/GFXIconTexture.cpp +++ /dev/null @@ -1,142 +0,0 @@ -#include "GFXIconTexture.hpp" - -#include <godot_cpp/variant/utility_functions.hpp> - -#include "openvic-extension/singletons/AssetManager.hpp" -#include "openvic-extension/utility/ClassBindings.hpp" -#include "openvic-extension/utility/UITools.hpp" -#include "openvic-extension/utility/Utilities.hpp" - -using namespace godot; -using namespace OpenVic; - -using OpenVic::Utilities::std_view_to_godot_string; -using OpenVic::Utilities::std_view_to_godot_string_name; - -StringName const& GFXIconTexture::_signal_image_updated() { - static const StringName signal_image_updated = "image_updated"; - return signal_image_updated; -} - -void GFXIconTexture::_bind_methods() { - OV_BIND_METHOD(GFXIconTexture::clear); - - OV_BIND_METHOD(GFXIconTexture::set_gfx_texture_sprite_name, { "gfx_texture_sprite_name", "icon" }, DEFVAL(GFX::NO_FRAMES)); - OV_BIND_METHOD(GFXIconTexture::get_gfx_texture_sprite_name); - - OV_BIND_METHOD(GFXIconTexture::set_icon_index, { "new_icon_index" }); - OV_BIND_METHOD(GFXIconTexture::get_icon_index); - OV_BIND_METHOD(GFXIconTexture::get_icon_count); - - ADD_PROPERTY(PropertyInfo(Variant::INT, "icon_index"), "set_icon_index", "get_icon_index"); - - ADD_SIGNAL( - MethodInfo(_signal_image_updated(), PropertyInfo(Variant::OBJECT, "source_image", PROPERTY_HINT_RESOURCE_TYPE, "Image")) - ); -} - -GFXIconTexture::GFXIconTexture() - : gfx_texture_sprite { nullptr }, icon_index { GFX::NO_FRAMES }, icon_count { GFX::NO_FRAMES } {} - -Ref<GFXIconTexture> GFXIconTexture::make_gfx_icon_texture( - GFX::TextureSprite const* gfx_texture_sprite, GFX::frame_t icon, - std::vector<Ref<GFXButtonStateTexture>> const& button_state_textures -) { - Ref<GFXIconTexture> icon_texture; - icon_texture.instantiate(); - ERR_FAIL_NULL_V(icon_texture, nullptr); - - for (Ref<GFXButtonStateTexture> const& button_state_texture : button_state_textures) { - icon_texture->connect( - _signal_image_updated(), - Callable { *button_state_texture, GFXButtonStateTexture::get_generate_state_image_func_name() }, - CONNECT_PERSIST - ); - } - - ERR_FAIL_COND_V(icon_texture->set_gfx_texture_sprite(gfx_texture_sprite, icon) != OK, nullptr); - return icon_texture; -} - -void GFXIconTexture::clear() { - gfx_texture_sprite = nullptr; - set_atlas(nullptr); - set_region({}); - icon_index = GFX::NO_FRAMES; - icon_count = GFX::NO_FRAMES; -} - -Error GFXIconTexture::set_gfx_texture_sprite(GFX::TextureSprite const* new_gfx_texture_sprite, GFX::frame_t icon) { - if (gfx_texture_sprite != new_gfx_texture_sprite) { - if (new_gfx_texture_sprite == nullptr) { - clear(); - return OK; - } - AssetManager* asset_manager = AssetManager::get_singleton(); - ERR_FAIL_NULL_V(asset_manager, FAILED); - - const StringName texture_file = std_view_to_godot_string_name(new_gfx_texture_sprite->get_texture_file()); - - /* Needed for GFXButtonStateTexture, AssetManager::get_texture will re-use this image from its internal cache. */ - const Ref<Image> image = asset_manager->get_image(texture_file); - ERR_FAIL_NULL_V_MSG(image, FAILED, vformat("Failed to load image: %s", texture_file)); - - const Ref<ImageTexture> texture = asset_manager->get_texture(texture_file); - ERR_FAIL_NULL_V_MSG(texture, FAILED, vformat("Failed to load texture: %s", texture_file)); - - sprite_image = image; - gfx_texture_sprite = new_gfx_texture_sprite; - set_atlas(texture); - icon_index = GFX::NO_FRAMES; - icon_count = gfx_texture_sprite->get_no_of_frames(); - } - return set_icon_index(icon); -} - -Error GFXIconTexture::set_gfx_texture_sprite_name(String const& gfx_texture_sprite_name, GFX::frame_t icon) { - if (gfx_texture_sprite_name.is_empty()) { - return set_gfx_texture_sprite(nullptr); - } - GFX::Sprite const* sprite = UITools::get_gfx_sprite(gfx_texture_sprite_name); - ERR_FAIL_NULL_V(sprite, FAILED); - GFX::TextureSprite const* new_texture_sprite = sprite->cast_to<GFX::TextureSprite>(); - ERR_FAIL_NULL_V_MSG( - new_texture_sprite, FAILED, vformat( - "Invalid type for GFX sprite %s: %s (expected %s)", gfx_texture_sprite_name, - std_view_to_godot_string(sprite->get_type()), std_view_to_godot_string(GFX::TextureSprite::get_type_static()) - ) - ); - return set_gfx_texture_sprite(new_texture_sprite, icon); -} - -String GFXIconTexture::get_gfx_texture_sprite_name() const { - return gfx_texture_sprite != nullptr ? std_view_to_godot_string(gfx_texture_sprite->get_name()) : String {}; -} - -Error GFXIconTexture::set_icon_index(int32_t new_icon_index) { - const Ref<Texture2D> atlas_texture = get_atlas(); - ERR_FAIL_NULL_V(atlas_texture, FAILED); - const Vector2 size = atlas_texture->get_size(); - if (icon_count <= GFX::NO_FRAMES) { - if (new_icon_index > GFX::NO_FRAMES) { - UtilityFunctions::push_warning("Invalid icon index ", new_icon_index, " for texture with no frames!"); - } - icon_index = GFX::NO_FRAMES; - set_region({ {}, size }); - emit_signal(_signal_image_updated(), sprite_image); - return OK; - } - if (GFX::NO_FRAMES < new_icon_index && new_icon_index <= icon_count) { - icon_index = new_icon_index; - } else { - icon_index = 1; - if (new_icon_index > icon_count) { - UtilityFunctions::push_warning( - "Invalid icon index ", new_icon_index, " out of count ", icon_count, " - defaulting to ", icon_index - ); - } - } - set_region({ (icon_index - 1) * size.x / icon_count, 0, size.x / icon_count, size.y }); - emit_signal(_signal_image_updated(), sprite_image->get_region(get_region())); - return OK; -} diff --git a/extension/src/openvic-extension/classes/GFXMaskedFlagTexture.cpp b/extension/src/openvic-extension/classes/GFXMaskedFlagTexture.cpp index 0a44e56..2c315a9 100644 --- a/extension/src/openvic-extension/classes/GFXMaskedFlagTexture.cpp +++ b/extension/src/openvic-extension/classes/GFXMaskedFlagTexture.cpp @@ -13,28 +13,31 @@ using OpenVic::Utilities::godot_to_std_string; using OpenVic::Utilities::std_view_to_godot_string; using OpenVic::Utilities::std_view_to_godot_string_name; -StringName const& GFXMaskedFlagTexture::_signal_image_updated() { - static const StringName signal_image_updated = "image_updated"; - return signal_image_updated; -} - Error GFXMaskedFlagTexture::_generate_combined_image() { ERR_FAIL_NULL_V(overlay_image, FAILED); /* Whether we've already set the ImageTexture to an image of the right dimensions and format, * and so can update it without creating and setting a new image, or not. */ - const bool can_update = combined_image.is_valid() && combined_image->get_size() == overlay_image->get_size() - && combined_image->get_format() == overlay_image->get_format(); + bool can_update = button_image.is_valid() && button_image->get_size() == overlay_image->get_size() + && button_image->get_format() == overlay_image->get_format(); if (!can_update) { - combined_image = Image::create( + button_image = Image::create( overlay_image->get_width(), overlay_image->get_height(), false, overlay_image->get_format() ); - ERR_FAIL_NULL_V(combined_image, FAILED); + ERR_FAIL_NULL_V(button_image, FAILED); + } + + if (combined_texture.is_null()) { + can_update = false; + combined_texture.instantiate(); + ERR_FAIL_NULL_V(combined_texture, FAILED); + set_atlas(combined_texture); + set_region({ {}, button_image->get_size() }); } if (mask_image.is_valid() && flag_image.is_valid()) { - const Vector2i centre_translation = (mask_image->get_size() - combined_image->get_size()) / 2; - for (Vector2i combined_image_point { 0, 0 }; combined_image_point.y < combined_image->get_height(); ++combined_image_point.y) { - for (combined_image_point.x = 0; combined_image_point.x < combined_image->get_width(); ++combined_image_point.x) { + const Vector2i centre_translation = (mask_image->get_size() - button_image->get_size()) / 2; + for (Vector2i combined_image_point { 0, 0 }; combined_image_point.y < button_image->get_height(); ++combined_image_point.y) { + for (combined_image_point.x = 0; combined_image_point.x < button_image->get_width(); ++combined_image_point.x) { const Color overlay_image_colour = overlay_image->get_pixelv(combined_image_point); // Translate to mask_image coordinates, keeping the centres of each image aligned. const Vector2i mask_image_point = combined_image_point + centre_translation; @@ -47,22 +50,22 @@ Error GFXMaskedFlagTexture::_generate_combined_image() { const Vector2i flag_image_point = mask_image_point * flag_image->get_size() / mask_image->get_size(); Color flag_image_colour = flag_image->get_pixelv(flag_image_point); flag_image_colour.a = mask_image_colour.a; - combined_image->set_pixelv(combined_image_point, flag_image_colour.blend(overlay_image_colour)); + button_image->set_pixelv(combined_image_point, flag_image_colour.blend(overlay_image_colour)); } else { - combined_image->set_pixelv(combined_image_point, overlay_image_colour); + button_image->set_pixelv(combined_image_point, overlay_image_colour); } } } } else { - combined_image->blit_rect(overlay_image, overlay_image->get_used_rect(), {}); + button_image->blit_rect(overlay_image, overlay_image->get_used_rect(), {}); } if (can_update) { - update(combined_image); + combined_texture->update(button_image); } else { - set_image(combined_image); + combined_texture->set_image(button_image); } - emit_signal(_signal_image_updated(), combined_image); + _update_button_states(); return OK; } @@ -76,29 +79,14 @@ void GFXMaskedFlagTexture::_bind_methods() { OV_BIND_METHOD(GFXMaskedFlagTexture::set_flag_country_name, { "new_flag_country_name" }); OV_BIND_METHOD(GFXMaskedFlagTexture::get_flag_country_name); OV_BIND_METHOD(GFXMaskedFlagTexture::get_flag_type); - - ADD_SIGNAL( - MethodInfo(_signal_image_updated(), PropertyInfo(Variant::OBJECT, "source_image", PROPERTY_HINT_RESOURCE_TYPE, "Image")) - ); } GFXMaskedFlagTexture::GFXMaskedFlagTexture() : gfx_masked_flag { nullptr }, flag_country { nullptr } {} -Ref<GFXMaskedFlagTexture> GFXMaskedFlagTexture::make_gfx_masked_flag_texture( - GFX::MaskedFlag const* gfx_masked_flag, std::vector<Ref<GFXButtonStateTexture>> const& button_state_textures -) { +Ref<GFXMaskedFlagTexture> GFXMaskedFlagTexture::make_gfx_masked_flag_texture(GFX::MaskedFlag const* gfx_masked_flag) { Ref<GFXMaskedFlagTexture> masked_flag_texture; masked_flag_texture.instantiate(); ERR_FAIL_NULL_V(masked_flag_texture, nullptr); - - for (Ref<GFXButtonStateTexture> const& button_state_texture : button_state_textures) { - masked_flag_texture->connect( - _signal_image_updated(), - Callable { *button_state_texture, GFXButtonStateTexture::get_generate_state_image_func_name() }, - CONNECT_PERSIST - ); - } - ERR_FAIL_COND_V(masked_flag_texture->set_gfx_masked_flag(gfx_masked_flag) != OK, nullptr); return masked_flag_texture; } @@ -108,6 +96,8 @@ void GFXMaskedFlagTexture::clear() { flag_country = nullptr; flag_type = String {}; + _clear_button_states(); + overlay_image.unref(); mask_image.unref(); flag_image.unref(); diff --git a/extension/src/openvic-extension/classes/GFXMaskedFlagTexture.hpp b/extension/src/openvic-extension/classes/GFXMaskedFlagTexture.hpp index 294b842..1e85dd8 100644 --- a/extension/src/openvic-extension/classes/GFXMaskedFlagTexture.hpp +++ b/extension/src/openvic-extension/classes/GFXMaskedFlagTexture.hpp @@ -1,23 +1,20 @@ #pragma once -#include <godot_cpp/classes/image_texture.hpp> - #include <openvic-simulation/country/Country.hpp> #include <openvic-simulation/interface/GFX.hpp> #include "openvic-extension/classes/GFXButtonStateTexture.hpp" namespace OpenVic { - class GFXMaskedFlagTexture : public godot::ImageTexture { - GDCLASS(GFXMaskedFlagTexture, godot::ImageTexture) + class GFXMaskedFlagTexture : public GFXButtonStateHavingTexture { + GDCLASS(GFXMaskedFlagTexture, GFXButtonStateHavingTexture) GFX::MaskedFlag const* PROPERTY(gfx_masked_flag); Country const* PROPERTY(flag_country); godot::StringName PROPERTY(flag_type); - godot::Ref<godot::Image> overlay_image, mask_image, flag_image, combined_image; - - static godot::StringName const& _signal_image_updated(); + godot::Ref<godot::Image> overlay_image, mask_image, flag_image; + godot::Ref<godot::ImageTexture> combined_texture; godot::Error _generate_combined_image(); @@ -27,12 +24,8 @@ namespace OpenVic { public: GFXMaskedFlagTexture(); - /* Create a GFXMaskedFlagTexture using the specified GFX::MaskedFlag. Returns nullptr if gfx_masked_flag fails. - * Connects the provided GFXButtonStateTextures (if any) to the GFXMaskedFlagTexture's image_updated signal. */ - static godot::Ref<GFXMaskedFlagTexture> make_gfx_masked_flag_texture( - GFX::MaskedFlag const* gfx_masked_flag, - std::vector<godot::Ref<GFXButtonStateTexture>> const& button_state_textures = {} - ); + /* Create a GFXMaskedFlagTexture using the specified GFX::MaskedFlag. Returns nullptr if gfx_masked_flag fails. */ + static godot::Ref<GFXMaskedFlagTexture> make_gfx_masked_flag_texture(GFX::MaskedFlag const* gfx_masked_flag); /* Reset gfx_masked_flag, flag_country and flag_type to nullptr/an empty string, and unreference all images. * This does not affect the godot::ImageTexture, which cannot be reset to a null or empty image. */ diff --git a/extension/src/openvic-extension/classes/GFXSpriteTexture.cpp b/extension/src/openvic-extension/classes/GFXSpriteTexture.cpp new file mode 100644 index 0000000..e002461 --- /dev/null +++ b/extension/src/openvic-extension/classes/GFXSpriteTexture.cpp @@ -0,0 +1,159 @@ +#include "GFXSpriteTexture.hpp" + +#include <godot_cpp/classes/rendering_server.hpp> +#include <godot_cpp/variant/utility_functions.hpp> + +#include "openvic-extension/singletons/AssetManager.hpp" +#include "openvic-extension/utility/ClassBindings.hpp" +#include "openvic-extension/utility/UITools.hpp" +#include "openvic-extension/utility/Utilities.hpp" + +using namespace godot; +using namespace OpenVic; + +using OpenVic::Utilities::std_view_to_godot_string; +using OpenVic::Utilities::std_view_to_godot_string_name; + +void GFXSpriteTexture::_bind_methods() { + OV_BIND_METHOD(GFXSpriteTexture::clear); + + OV_BIND_METHOD(GFXSpriteTexture::set_gfx_texture_sprite_name, { "gfx_texture_sprite_name", "icon" }, DEFVAL(GFX::NO_FRAMES)); + OV_BIND_METHOD(GFXSpriteTexture::get_gfx_texture_sprite_name); + + OV_BIND_METHOD(GFXSpriteTexture::set_icon_index, { "new_icon_index" }); + OV_BIND_METHOD(GFXSpriteTexture::get_icon_index); + OV_BIND_METHOD(GFXSpriteTexture::get_icon_count); + + OV_BIND_METHOD(GFXSpriteTexture::is_cornered_tile_texture); + OV_BIND_METHOD(GFXSpriteTexture::draw_rect_cornered, { "to_canvas_item", "rect" }); + + ADD_PROPERTY(PropertyInfo(Variant::INT, "icon_index"), "set_icon_index", "get_icon_index"); +} + +GFXSpriteTexture::GFXSpriteTexture() + : gfx_texture_sprite { nullptr }, icon_index { GFX::NO_FRAMES }, icon_count { GFX::NO_FRAMES }, + cornered_tile_texture { false }, cornered_tile_border_size {} {} + +Ref<GFXSpriteTexture> GFXSpriteTexture::make_gfx_sprite_texture(GFX::TextureSprite const* gfx_texture_sprite, GFX::frame_t icon) { + Ref<GFXSpriteTexture> texture; + texture.instantiate(); + ERR_FAIL_NULL_V(texture, nullptr); + ERR_FAIL_COND_V(texture->set_gfx_texture_sprite(gfx_texture_sprite, icon) != OK, nullptr); + return texture; +} + +void GFXSpriteTexture::clear() { + gfx_texture_sprite = nullptr; + _clear_button_states(); + icon_index = GFX::NO_FRAMES; + icon_count = GFX::NO_FRAMES; + cornered_tile_texture = false; + cornered_tile_border_size = {}; +} + +Error GFXSpriteTexture::set_gfx_texture_sprite(GFX::TextureSprite const* new_gfx_texture_sprite, GFX::frame_t icon) { + if (gfx_texture_sprite != new_gfx_texture_sprite) { + if (new_gfx_texture_sprite == nullptr) { + clear(); + return OK; + } + AssetManager* asset_manager = AssetManager::get_singleton(); + ERR_FAIL_NULL_V(asset_manager, FAILED); + + const StringName texture_file = std_view_to_godot_string_name(new_gfx_texture_sprite->get_texture_file()); + + /* Needed for GFXButtonStateTexture, AssetManager::get_texture will re-use this image from its internal cache. */ + const Ref<Image> image = asset_manager->get_image(texture_file); + ERR_FAIL_NULL_V_MSG(image, FAILED, vformat("Failed to load image: %s", texture_file)); + + const Ref<ImageTexture> texture = asset_manager->get_texture(texture_file); + ERR_FAIL_NULL_V_MSG(texture, FAILED, vformat("Failed to load texture: %s", texture_file)); + + button_image = image; + gfx_texture_sprite = new_gfx_texture_sprite; + set_atlas(texture); + icon_index = GFX::NO_FRAMES; + + GFX::IconTextureSprite const* const icon_texture_sprite = gfx_texture_sprite->cast_to<GFX::IconTextureSprite>(); + if (icon_texture_sprite != nullptr) { + icon_count = icon_texture_sprite->get_no_of_frames(); + } else { + icon_count = GFX::NO_FRAMES; + } + + GFX::CorneredTileTextureSprite const* const cornered_tile_texture_sprite = + gfx_texture_sprite->cast_to<GFX::CorneredTileTextureSprite>(); + if (cornered_tile_texture_sprite != nullptr) { + cornered_tile_texture = true; + cornered_tile_border_size = Utilities::to_godot_ivec2(cornered_tile_texture_sprite->get_border_size()); + } else { + cornered_tile_texture = false; + cornered_tile_border_size = {}; + } + } + return set_icon_index(icon); +} + +Error GFXSpriteTexture::set_gfx_texture_sprite_name(String const& gfx_texture_sprite_name, GFX::frame_t icon) { + if (gfx_texture_sprite_name.is_empty()) { + return set_gfx_texture_sprite(nullptr); + } + GFX::Sprite const* sprite = UITools::get_gfx_sprite(gfx_texture_sprite_name); + ERR_FAIL_NULL_V(sprite, FAILED); + GFX::TextureSprite const* new_texture_sprite = sprite->cast_to<GFX::TextureSprite>(); + ERR_FAIL_NULL_V_MSG( + new_texture_sprite, FAILED, vformat( + "Invalid type for GFX sprite %s: %s (expected %s)", gfx_texture_sprite_name, + std_view_to_godot_string(sprite->get_type()), std_view_to_godot_string(GFX::TextureSprite::get_type_static()) + ) + ); + return set_gfx_texture_sprite(new_texture_sprite, icon); +} + +String GFXSpriteTexture::get_gfx_texture_sprite_name() const { + return gfx_texture_sprite != nullptr ? std_view_to_godot_string(gfx_texture_sprite->get_name()) : String {}; +} + +Error GFXSpriteTexture::set_icon_index(int32_t new_icon_index) { + const Ref<Texture2D> atlas_texture = get_atlas(); + ERR_FAIL_NULL_V(atlas_texture, FAILED); + const Vector2 size = atlas_texture->get_size(); + if (icon_count <= GFX::NO_FRAMES) { + if (new_icon_index > GFX::NO_FRAMES) { + UtilityFunctions::push_warning("Invalid icon index ", new_icon_index, " for texture with no frames!"); + } + icon_index = GFX::NO_FRAMES; + set_region({ {}, size }); + } else { + if (GFX::NO_FRAMES < new_icon_index && new_icon_index <= icon_count) { + icon_index = new_icon_index; + } else { + icon_index = 1; + if (new_icon_index > icon_count) { + UtilityFunctions::push_warning( + "Invalid icon index ", new_icon_index, " out of count ", icon_count, " - defaulting to ", icon_index + ); + } + } + set_region({ (icon_index - 1) * size.x / icon_count, 0, size.x / icon_count, size.y }); + } + _update_button_states(); + return OK; +} + +void GFXSpriteTexture::draw_rect_cornered(RID const& to_canvas_item, Rect2 const& rect) const { + const Ref<Texture2D> atlas_texture = get_atlas(); + if (atlas_texture.is_valid()) { + if (cornered_tile_texture) { + RenderingServer* rendering_server = RenderingServer::get_singleton(); + if (rendering_server != nullptr) { + rendering_server->canvas_item_add_nine_patch( + to_canvas_item, rect, { {}, atlas_texture->get_size() }, atlas_texture->get_rid(), + cornered_tile_border_size, atlas_texture->get_size() - cornered_tile_border_size + ); + } + } else { + draw_rect(to_canvas_item, rect, false); + } + } +} diff --git a/extension/src/openvic-extension/classes/GFXIconTexture.hpp b/extension/src/openvic-extension/classes/GFXSpriteTexture.hpp index 06dac34..783dfba 100644 --- a/extension/src/openvic-extension/classes/GFXIconTexture.hpp +++ b/extension/src/openvic-extension/classes/GFXSpriteTexture.hpp @@ -7,39 +7,37 @@ #include "openvic-extension/classes/GFXButtonStateTexture.hpp" namespace OpenVic { - class GFXIconTexture : public godot::AtlasTexture { - GDCLASS(GFXIconTexture, godot::AtlasTexture) + class GFXSpriteTexture : public GFXButtonStateHavingTexture { + GDCLASS(GFXSpriteTexture, GFXButtonStateHavingTexture) /* PROPERTY automatically defines getter functions: * - get_gfx_texture_sprite * - get_icon_index - * - get_icon_count */ + * - get_icon_count + * - is_cornered_tile_texture */ GFX::TextureSprite const* PROPERTY(gfx_texture_sprite); GFX::frame_t PROPERTY(icon_index); GFX::frame_t PROPERTY(icon_count); - - godot::Ref<godot::Image> sprite_image; - - static godot::StringName const& _signal_image_updated(); + bool PROPERTY_CUSTOM_PREFIX(cornered_tile_texture, is); + godot::Vector2i cornered_tile_border_size; protected: static void _bind_methods(); public: - GFXIconTexture(); - - /* Create a GFXIconTexture using the specified GFX::TextureSprite and icon index. Returns nullptr if - * set_gfx_texture_sprite fails. Connects the provided GFXButtonStateTextures (if any) to the - * GFXIconTexture's image_updated signal. */ - static godot::Ref<GFXIconTexture> make_gfx_icon_texture( - GFX::TextureSprite const* gfx_texture_sprite, GFX::frame_t icon = GFX::NO_FRAMES, - std::vector<godot::Ref<GFXButtonStateTexture>> const& button_state_textures = {} + GFXSpriteTexture(); + + /* Create a GFXSpriteTexture using the specified GFX::TextureSprite and icon index. Returns nullptr if + * set_gfx_texture_sprite fails. */ + static godot::Ref<GFXSpriteTexture> make_gfx_sprite_texture( + GFX::TextureSprite const* gfx_texture_sprite, GFX::frame_t icon = GFX::NO_FRAMES ); /* Discard the GFX::TextureSprite, atlas texture and icon index. */ void clear(); - /* Set the GFX::TextureSprite, load its texture as an atlas and set its displayed icon */ + /* Set the GFX::TextureSprite, load its texture as an atlas, check if it is an IconTextureSprite, + * and if so set its icon count and the current displayed icon. */ godot::Error set_gfx_texture_sprite( GFX::TextureSprite const* new_gfx_texture_sprite, GFX::frame_t icon = GFX::NO_FRAMES ); @@ -58,5 +56,8 @@ namespace OpenVic { * If zero is used but icon_count is non-zero, icon_index defaults to icon_count (the last frame, * not the first frame because it is often empty). */ godot::Error set_icon_index(GFX::frame_t new_icon_index); + + /* Equivalent to draw_rect, but draws a 9 patch texture if this is a cornered tile texture. */ + void draw_rect_cornered(godot::RID const& to_canvas_item, godot::Rect2 const& rect) const; }; } diff --git a/extension/src/openvic-extension/classes/GUINode.cpp b/extension/src/openvic-extension/classes/GUINode.cpp index f95e3cd..a038df7 100644 --- a/extension/src/openvic-extension/classes/GUINode.cpp +++ b/extension/src/openvic-extension/classes/GUINode.cpp @@ -20,7 +20,7 @@ using namespace OpenVic; F(GUIOverlappingElementsBox, gui_overlapping_elements_box) #define APPLY_TO_TEXTURE_TYPES(F) \ - F(GFXIconTexture, gfx_icon_texture) \ + F(GFXSpriteTexture, gfx_sprite_texture) \ F(GFXMaskedFlagTexture, gfx_masked_flag_texture) \ F(GFXPieChartTexture, gfx_pie_chart_texture) diff --git a/extension/src/openvic-extension/classes/GUINode.hpp b/extension/src/openvic-extension/classes/GUINode.hpp index 0fbfc66..42074e3 100644 --- a/extension/src/openvic-extension/classes/GUINode.hpp +++ b/extension/src/openvic-extension/classes/GUINode.hpp @@ -9,7 +9,7 @@ #include <openvic-simulation/interface/GUI.hpp> -#include "openvic-extension/classes/GFXIconTexture.hpp" +#include "openvic-extension/classes/GFXSpriteTexture.hpp" #include "openvic-extension/classes/GFXMaskedFlagTexture.hpp" #include "openvic-extension/classes/GFXPieChartTexture.hpp" #include "openvic-extension/classes/GUIOverlappingElementsBox.hpp" @@ -52,12 +52,12 @@ namespace OpenVic { /* Helper functions to get textures from TextureRects and Buttons. */ static godot::Ref<godot::Texture2D> get_texture_from_node(godot::Node* node); - static godot::Ref<GFXIconTexture> get_gfx_icon_texture_from_node(godot::Node* node); + static godot::Ref<GFXSpriteTexture> get_gfx_sprite_texture_from_node(godot::Node* node); static godot::Ref<GFXMaskedFlagTexture> get_gfx_masked_flag_texture_from_node(godot::Node* node); static godot::Ref<GFXPieChartTexture> get_gfx_pie_chart_texture_from_node(godot::Node* node); godot::Ref<godot::Texture2D> get_texture_from_nodepath(godot::NodePath const& path) const; - godot::Ref<GFXIconTexture> get_gfx_icon_texture_from_nodepath(godot::NodePath const& path) const; + godot::Ref<GFXSpriteTexture> get_gfx_sprite_texture_from_nodepath(godot::NodePath const& path) const; godot::Ref<GFXMaskedFlagTexture> get_gfx_masked_flag_texture_from_nodepath(godot::NodePath const& path) const; godot::Ref<GFXPieChartTexture> get_gfx_pie_chart_texture_from_nodepath(godot::NodePath const& path) const; |