diff options
24 files changed, 215 insertions, 226 deletions
diff --git a/extension/src/GameSingleton.cpp b/extension/src/GameSingleton.cpp index 41c1b91..64f6fc1 100644 --- a/extension/src/GameSingleton.cpp +++ b/extension/src/GameSingleton.cpp @@ -25,8 +25,10 @@ void GameSingleton::_bind_methods() { ClassDB::bind_method(D_METHOD("get_province_info_from_index", "index"), &GameSingleton::get_province_info_from_index); ClassDB::bind_method(D_METHOD("get_width"), &GameSingleton::get_width); ClassDB::bind_method(D_METHOD("get_height"), &GameSingleton::get_height); - ClassDB::bind_method(D_METHOD("get_province_index_images"), &GameSingleton::get_province_index_images); - ClassDB::bind_method(D_METHOD("get_province_colour_image"), &GameSingleton::get_province_colour_image); + ClassDB::bind_method(D_METHOD("get_aspect_ratio"), &GameSingleton::get_aspect_ratio); + ClassDB::bind_method(D_METHOD("get_province_shape_image_subdivisions"), &GameSingleton::get_province_shape_image_subdivisions); + ClassDB::bind_method(D_METHOD("get_province_shape_texture"), &GameSingleton::get_province_shape_texture); + ClassDB::bind_method(D_METHOD("get_province_colour_texture"), &GameSingleton::get_province_colour_texture); ClassDB::bind_method(D_METHOD("update_colour_image"), &GameSingleton::update_colour_image); ClassDB::bind_method(D_METHOD("get_mapmode_count"), &GameSingleton::get_mapmode_count); @@ -234,7 +236,7 @@ Error GameSingleton::load_region_file(String const& file_path) { } Error GameSingleton::load_province_shape_file(String const& file_path) { - if (province_index_image[0].is_valid()) { + if (province_shape_texture.is_valid()) { UtilityFunctions::push_error("Province shape file has already been loaded, cannot load: ", file_path); return FAILED; } @@ -245,16 +247,15 @@ Error GameSingleton::load_province_shape_file(String const& file_path) { UtilityFunctions::push_error("Failed to load province shape file: ", file_path); return err; } - const int32_t width = province_shape_image->get_width(); - const int32_t height = province_shape_image->get_height(); - if (width < 1 || height < 1) { - UtilityFunctions::push_error("Invalid dimensions (", width, "x", height, ") for province shape file: ", file_path); - err = FAILED; - } - if (width % image_width_divide != 0) { - UtilityFunctions::push_error("Invalid width ", width, " (must be divisible by ", image_width_divide, ") for province shape file: ", file_path); + const Vector2i image_dims = province_shape_image->get_size(); + if (image_dims.x < 1 || image_dims.y < 1) { + UtilityFunctions::push_error("Invalid dimensions (", image_dims.x, "x", image_dims.y, ") for province shape file: ", file_path); err = FAILED; } + static constexpr int32_t GPU_DIM_LIMIT = 0x3FFF; + // For each dimension of the image, this finds the small number of equal subdivisions required get the individual texture dims under GPU_DIM_LIMIT + for (int i = 0; i < 2; ++i) for (image_subdivisions[i] = 1; + image_dims[i] / image_subdivisions[i] > GPU_DIM_LIMIT || image_dims[i] % image_subdivisions[i] != 0; ++image_subdivisions[i]); static constexpr Image::Format expected_format = Image::FORMAT_RGB8; const Image::Format format = province_shape_image->get_format(); if (format != expected_format) { @@ -262,24 +263,37 @@ Error GameSingleton::load_province_shape_file(String const& file_path) { err = FAILED; } if (err != OK) return err; - err = ERR(game_manager.map.generate_province_index_image(width, height, province_shape_image->get_data().ptr())); - - std::vector<index_t> const& province_index_data = game_manager.map.get_province_index_image(); - const int32_t divided_width = width / image_width_divide; - for (int32_t i = 0; i < image_width_divide; ++i) { - PackedByteArray index_data_array; - index_data_array.resize(divided_width * height * sizeof(index_t)); - for (int32_t y = 0; y < height; ++y) - memcpy(index_data_array.ptrw() + y * divided_width * sizeof(index_t), - province_index_data.data() + y * width + i * divided_width, - divided_width * sizeof(index_t)); - province_index_image[i] = Image::create_from_data(divided_width, height, false, Image::FORMAT_RG8, index_data_array); - if (province_index_image[i].is_null()) { - UtilityFunctions::push_error("Failed to create province ID image #", i); - err = FAILED; + err = ERR(game_manager.map.generate_province_shape_image(image_dims.x, image_dims.y, province_shape_image->get_data().ptr())); + + std::vector<Map::shape_pixel_t> const& province_shape_data = game_manager.map.get_province_shape_image(); + const Vector2i divided_dims = image_dims / image_subdivisions; + Array province_shape_images; + province_shape_images.resize(image_subdivisions.x * image_subdivisions.y); + for (int32_t v = 0; v < image_subdivisions.y; ++v) { + for (int32_t u = 0; u < image_subdivisions.x; ++u) { + PackedByteArray index_data_array; + index_data_array.resize(divided_dims.x * divided_dims.y * sizeof(Map::shape_pixel_t)); + + for (int32_t y = 0; y < divided_dims.y; ++y) + memcpy(index_data_array.ptrw() + y * divided_dims.x * sizeof(Map::shape_pixel_t), + province_shape_data.data() + (v * divided_dims.y + y) * image_dims.x + u * divided_dims.x, + divided_dims.x * sizeof(Map::shape_pixel_t)); + + const Ref<Image> province_index_subimage = Image::create_from_data(divided_dims.x, divided_dims.y, false, Image::FORMAT_RGB8, index_data_array); + if (province_index_subimage.is_null()) { + UtilityFunctions::push_error("Failed to create province index image (", u, ", ", v, ")"); + err = FAILED; + } + province_shape_images[u + v * image_subdivisions.x] = province_index_subimage; } } + province_shape_texture.instantiate(); + if (province_shape_texture->create_from_images(province_shape_images) != OK) { + UtilityFunctions::push_error(""); + err = FAILED; + } + if (update_colour_image() != OK) err = FAILED; return err; @@ -370,20 +384,25 @@ int32_t GameSingleton::get_height() const { return game_manager.map.get_height(); } -Array GameSingleton::get_province_index_images() const { - Array ret; - for (int i = 0; i < image_width_divide; ++i) - ret.append(province_index_image[i]); - return ret; +float GameSingleton::get_aspect_ratio() const { + return static_cast<float>(get_width()) / static_cast<float>(get_height()); +} + +Vector2i GameSingleton::get_province_shape_image_subdivisions() const { + return image_subdivisions; +} + +Ref<Texture> GameSingleton::get_province_shape_texture() const { + return province_shape_texture; } -Ref<Image> GameSingleton::get_province_colour_image() const { - return province_colour_image; +Ref<Texture> GameSingleton::get_province_colour_texture() const { + return province_colour_texture; } Error GameSingleton::update_colour_image() { static PackedByteArray colour_data_array; - static constexpr int64_t colour_data_array_size = (MAX_INDEX + 1) * 4; + static constexpr int64_t colour_data_array_size = (MAX_INDEX + 1) * Map::MAPMODE_COLOUR_SIZE; colour_data_array.resize(colour_data_array_size); Error err = OK; @@ -394,11 +413,15 @@ Error GameSingleton::update_colour_image() { if (province_colour_image.is_null()) province_colour_image.instantiate(); province_colour_image->set_data(PROVINCE_INDEX_SQRT, PROVINCE_INDEX_SQRT, - false, Image::FORMAT_RGBA8, colour_data_array); + false, Image::FORMAT_RGB8, colour_data_array); if (province_colour_image.is_null()) { UtilityFunctions::push_error("Failed to update province colour image"); return FAILED; } + if (province_colour_texture.is_null()) + province_colour_texture = ImageTexture::create_from_image(province_colour_image); + else + province_colour_texture->update(province_colour_image); return err; } diff --git a/extension/src/GameSingleton.hpp b/extension/src/GameSingleton.hpp index d9879ef..d17b950 100644 --- a/extension/src/GameSingleton.hpp +++ b/extension/src/GameSingleton.hpp @@ -2,7 +2,8 @@ #include <functional> -#include <godot_cpp/classes/image.hpp> +#include <godot_cpp/classes/image_texture.hpp> +#include <godot_cpp/classes/texture2d_array.hpp> #include "openvic2/GameManager.hpp" @@ -14,8 +15,10 @@ namespace OpenVic2 { GameManager game_manager; - static constexpr int image_width_divide = 2; - godot::Ref<godot::Image> province_index_image[image_width_divide], province_colour_image; + godot::Vector2i image_subdivisions; + godot::Ref<godot::Texture2DArray> province_shape_texture; + godot::Ref<godot::Image> province_colour_image; + godot::Ref<godot::ImageTexture> province_colour_texture; Mapmode::index_t mapmode_index = 0; godot::Error _parse_province_identifier_entry(godot::String const& identifier, godot::Variant const& entry); @@ -40,8 +43,10 @@ namespace OpenVic2 { godot::Dictionary get_province_info_from_index(int32_t index) const; int32_t get_width() const; int32_t get_height() const; - godot::Array get_province_index_images() const; - godot::Ref<godot::Image> get_province_colour_image() const; + float get_aspect_ratio() const; + godot::Vector2i get_province_shape_image_subdivisions() const; + godot::Ref<godot::Texture> get_province_shape_texture() const; + godot::Ref<godot::Texture> get_province_colour_texture() const; godot::Error update_colour_image(); int32_t get_mapmode_count() const; diff --git a/extension/src/MapMesh.cpp b/extension/src/MapMesh.cpp index 91c7611..6d94973 100644 --- a/extension/src/MapMesh.cpp +++ b/extension/src/MapMesh.cpp @@ -50,21 +50,21 @@ float MapMesh::get_repeat_proportion() const { return repeat_proportion; } -void MapMesh::set_subdivide_width(const int divisions) { +void MapMesh::set_subdivide_width(const int32_t divisions) { subdivide_w = divisions > 0 ? divisions : 0; _request_update(); } -int MapMesh::get_subdivide_width() const { +int32_t MapMesh::get_subdivide_width() const { return subdivide_w; } -void MapMesh::set_subdivide_depth(const int divisions) { +void MapMesh::set_subdivide_depth(const int32_t divisions) { subdivide_d = divisions > 0 ? divisions : 0; _request_update(); } -int MapMesh::get_subdivide_depth() const { +int32_t MapMesh::get_subdivide_depth() const { return subdivide_d; } @@ -81,8 +81,8 @@ Array MapMesh::_create_mesh_array() const { Array arr; arr.resize(Mesh::ARRAY_MAX); - const int vertex_count = (subdivide_w + 2) * (subdivide_d + 2); - const int indice_count = (subdivide_w + 1) * (subdivide_d + 1) * 6; + const int32_t vertex_count = (subdivide_w + 2) * (subdivide_d + 2); + const int32_t indice_count = (subdivide_w + 1) * (subdivide_d + 1) * 6; PackedVector3Array points; PackedVector3Array normals; @@ -100,17 +100,17 @@ Array MapMesh::_create_mesh_array() const { const Size2 uv_size{ 1.0f + 2.0f * repeat_proportion, 1.0f }; const Size2 size{ aspect_ratio * uv_size.x, uv_size.y }, start_pos = size * -0.5f; - int point_index = 0, thisrow = 0, prevrow = 0, indice_index = 0; + int32_t point_index = 0, thisrow = 0, prevrow = 0, indice_index = 0; Vector2 subdivide_step{ 1.0f / (subdivide_w + 1.0f) , 1.0f / (subdivide_d + 1.0f) }; Vector3 point{ 0.0f, 0.0f, start_pos.y }; Vector2 point_step = subdivide_step * size; Vector2 uv{}, uv_step = subdivide_step * uv_size; - for (int j = 0; j <= subdivide_d + 1; ++j) { + for (int32_t j = 0; j <= subdivide_d + 1; ++j) { point.x = start_pos.x; uv.x = -repeat_proportion; - for (int i = 0; i <= subdivide_w + 1; ++i) { + for (int32_t i = 0; i <= subdivide_w + 1; ++i) { points[point_index] = point; normals[point_index] = normal; tangents[point_index * 4 + 0] = 1.0f; diff --git a/extension/src/MapMesh.hpp b/extension/src/MapMesh.hpp index d8727cf..89c0147 100644 --- a/extension/src/MapMesh.hpp +++ b/extension/src/MapMesh.hpp @@ -7,7 +7,7 @@ namespace OpenVic2 { GDCLASS(MapMesh, godot::PrimitiveMesh) float aspect_ratio = 2.0f, repeat_proportion = 0.5f; - int subdivide_w = 0, subdivide_d = 0; + int32_t subdivide_w = 0, subdivide_d = 0; protected: static void _bind_methods(); @@ -20,11 +20,11 @@ namespace OpenVic2 { void set_repeat_proportion(const float proportion); float get_repeat_proportion() const; - void set_subdivide_width(const int divisions); - int get_subdivide_width() const; + void set_subdivide_width(const int32_t divisions); + int32_t get_subdivide_width() const; - void set_subdivide_depth(const int divisions); - int get_subdivide_depth() const; + void set_subdivide_depth(const int32_t divisions); + int32_t get_subdivide_depth() const; godot::AABB get_core_aabb() const; bool is_valid_uv_coord(godot::Vector2 const& uv) const; diff --git a/extension/src/openvic2/map/Map.cpp b/extension/src/openvic2/map/Map.cpp index 90f2420..4e7c0bb 100644 --- a/extension/src/openvic2/map/Map.cpp +++ b/extension/src/openvic2/map/Map.cpp @@ -159,7 +159,7 @@ Province const* Map::get_province_by_colour(colour_t colour) const { } index_t Map::get_province_index_at(size_t x, size_t y) const { - if (x < width && y < height) return province_index_image[x + y * width]; + if (x < width && y < height) return province_shape_image[x + y * width].index; return NULL_INDEX; } @@ -175,8 +175,8 @@ static colour_t colour_at(uint8_t const* colour_data, int32_t idx) { return (colour_data[idx * 3] << 16) | (colour_data[idx * 3 + 1] << 8) | colour_data[idx * 3 + 2]; } -return_t Map::generate_province_index_image(size_t new_width, size_t new_height, uint8_t const* colour_data) { - if (!province_index_image.empty()) { +return_t Map::generate_province_shape_image(size_t new_width, size_t new_height, uint8_t const* colour_data) { + if (!province_shape_image.empty()) { Logger::error("Province index image has already been generated!"); return FAILURE; } @@ -194,7 +194,7 @@ return_t Map::generate_province_index_image(size_t new_width, size_t new_height, } width = new_width; height = new_height; - province_index_image.resize(width * height); + province_shape_image.resize(width * height); std::vector<bool> province_checklist(provinces.get_item_count()); return_t ret = SUCCESS; @@ -207,22 +207,23 @@ return_t Map::generate_province_index_image(size_t new_width, size_t new_height, if (x > 0) { const int32_t jdx = idx - 1; if (colour_at(colour_data, jdx) == colour) { - province_index_image[idx] = province_index_image[jdx]; + province_shape_image[idx] = province_shape_image[jdx]; continue; } } if (y > 0) { const int32_t jdx = idx - width; if (colour_at(colour_data, jdx) == colour) { - province_index_image[idx] = province_index_image[jdx]; + province_shape_image[idx] = province_shape_image[jdx]; continue; } } Province const* province = get_province_by_colour(colour); if (province != nullptr) { const index_t index = province->get_index(); - province_index_image[idx] = index; province_checklist[index - 1] = true; + province_shape_image[idx].index = index; + province_shape_image[idx].terrain = !province->is_water(); continue; } if (unrecognised_colours.find(colour) == unrecognised_colours.end()) { @@ -230,7 +231,8 @@ return_t Map::generate_province_index_image(size_t new_width, size_t new_height, Logger::error("Unrecognised province colour ", Province::colour_to_hex_string(colour), " at (", x, ", ", y, ")"); ret = FAILURE; } - province_index_image[idx] = NULL_INDEX; + province_shape_image[idx].index = NULL_INDEX; + province_shape_image[idx].terrain = 0; } } @@ -251,8 +253,8 @@ size_t Map::get_height() const { return height; } -std::vector<index_t> const& Map::get_province_index_image() const { - return province_index_image; +std::vector<Map::shape_pixel_t> const& Map::get_province_shape_image() const { + return province_shape_image; } return_t Map::add_mapmode(std::string const& identifier, Mapmode::colour_func_t colour_func) { @@ -293,13 +295,14 @@ return_t Map::generate_mapmode_colours(Mapmode::index_t index, uint8_t* target) Logger::error("Invalid mapmode index: ", index); return FAILURE; } - target += 4; // Skip past Province::NULL_INDEX + // Skip past Province::NULL_INDEX + for (size_t i = 0; i < MAPMODE_COLOUR_SIZE; ++i) + *target++ = 0; for (Province const& province : provinces.get_items()) { const colour_t colour = mapmode->get_colour(*this, province); *target++ = (colour >> 16) & 0xFF; *target++ = (colour >> 8) & 0xFF; *target++ = colour & 0xFF; - *target++ = province.is_water() ? 0 : 255; } return SUCCESS; } diff --git a/extension/src/openvic2/map/Map.hpp b/extension/src/openvic2/map/Map.hpp index 9150772..a664d96 100644 --- a/extension/src/openvic2/map/Map.hpp +++ b/extension/src/openvic2/map/Map.hpp @@ -26,6 +26,12 @@ namespace OpenVic2 { * MAP-4 */ struct Map { + #pragma pack(push, 1) + struct shape_pixel_t { + Province::index_t index; + uint8_t terrain; + }; + #pragma pack(pop) private: IdentifierRegistry<Province> provinces; IdentifierRegistry<Region> regions; @@ -34,7 +40,7 @@ namespace OpenVic2 { size_t water_province_count = 0; size_t width = 0, height = 0; - std::vector<index_t> province_index_image; + std::vector<shape_pixel_t> province_shape_image; public: Map(); @@ -57,16 +63,17 @@ namespace OpenVic2 { Region* get_region_by_identifier(std::string const& identifier); Region const* get_region_by_identifier(std::string const& identifier) const; - return_t generate_province_index_image(size_t new_width, size_t new_height, uint8_t const* colour_data); + return_t generate_province_shape_image(size_t new_width, size_t new_height, uint8_t const* colour_data); size_t get_width() const; size_t get_height() const; - std::vector<index_t> const& get_province_index_image() const; + std::vector<shape_pixel_t> const& get_province_shape_image() const; return_t add_mapmode(std::string const& identifier, Mapmode::colour_func_t colour_func); void lock_mapmodes(); size_t get_mapmode_count() const; Mapmode const* get_mapmode_by_index(Mapmode::index_t index) const; Mapmode const* get_mapmode_by_identifier(std::string const& identifier) const; + static constexpr size_t MAPMODE_COLOUR_SIZE = 3; return_t generate_mapmode_colours(Mapmode::index_t index, uint8_t* target) const; return_t generate_province_buildings(BuildingManager const& manager); diff --git a/game/art/ui/minimap.png b/game/art/ui/minimap.png Binary files differdeleted file mode 100644 index 9922b28..0000000 --- a/game/art/ui/minimap.png +++ /dev/null diff --git a/game/art/ui/minimap.png.import b/game/art/ui/minimap.png.import deleted file mode 100644 index 36f22e7..0000000 --- a/game/art/ui/minimap.png.import +++ /dev/null @@ -1,34 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://c0sm1jfu4kyv3" -path="res://.godot/imported/minimap.png-05ee44469856e77fd05107fe9e259e25.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://art/ui/minimap.png" -dest_files=["res://.godot/imported/minimap.png-05ee44469856e77fd05107fe9e259e25.ctex"] - -[params] - -compress/mode=3 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/hdr_compression=1 -compress/normal_map=2 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/fix_alpha_border=false -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=0 diff --git a/game/art/ui/minimap_frame.png b/game/art/ui/minimap_frame.png Binary files differdeleted file mode 100644 index 21aa2ce..0000000 --- a/game/art/ui/minimap_frame.png +++ /dev/null diff --git a/game/art/ui/minimap_frame.png.import b/game/art/ui/minimap_frame.png.import deleted file mode 100644 index 3d2aeee..0000000 --- a/game/art/ui/minimap_frame.png.import +++ /dev/null @@ -1,34 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://vr1hq2stk8ny" -path="res://.godot/imported/minimap_frame.png-3668393435d2582fb1dc8a9598573e80.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://art/ui/minimap_frame.png" -dest_files=["res://.godot/imported/minimap_frame.png-3668393435d2582fb1dc8a9598573e80.ctex"] - -[params] - -compress/mode=3 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/hdr_compression=1 -compress/normal_map=2 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/fix_alpha_border=false -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=0 diff --git a/game/project.godot b/game/project.godot index ff4081e..c10465d 100644 --- a/game/project.godot +++ b/game/project.godot @@ -22,10 +22,9 @@ config/project_settings_override.template="user://settings.cfg" Events="*res://src/Autoload/Events.gd" Resolution="*res://src/Autoload/Resolution.gd" -MusicConductor="*res://src/MusicConductor/MusicConductor.tscn" SoundManager="*res://src/Autoload/SoundManager.gd" +MusicConductor="*res://src/MusicConductor/MusicConductor.tscn" Keychain="*res://addons/keychain/Keychain.gd" -GameDebug="*res://src/Autoload/GameDebug.gd" [display] diff --git a/game/src/Autoload/Events.gd b/game/src/Autoload/Events.gd index 7540d3e..f94d338 100644 --- a/game/src/Autoload/Events.gd +++ b/game/src/Autoload/Events.gd @@ -1,7 +1,9 @@ extends Node +var GameDebug = preload("Events/GameDebug.gd").new() var Options = preload("Events/Options.gd").new() var Localisation = preload("Events/Localisation.gd").new() +var ShaderManager = preload("Events/ShaderManager.gd").new() const _province_identifier_file : String = "res://common/map/provinces.json" const _water_province_file : String = "res://common/map/water.json" diff --git a/game/src/Autoload/GameDebug.gd b/game/src/Autoload/Events/GameDebug.gd index 6f10bf5..4e8931f 100644 --- a/game/src/Autoload/GameDebug.gd +++ b/game/src/Autoload/Events/GameDebug.gd @@ -1,8 +1,8 @@ -extends Node +extends RefCounted # REQUIREMENTS: # * SS-56 -func _ready(): +func _init(): for engine_args in OS.get_cmdline_args(): match(engine_args): "--game-debug": @@ -15,6 +15,7 @@ func _ready(): func set_debug_mode(value : bool) -> void: ProjectSettings.set_setting("openvic2/debug/enabled", value) + print("Set debug mode to: ", value) func is_debug_mode() -> bool: return ProjectSettings.get_setting("openvic2/debug/enabled", false) diff --git a/game/src/Autoload/Events/ShaderManager.gd b/game/src/Autoload/Events/ShaderManager.gd new file mode 100644 index 0000000..96ed5b4 --- /dev/null +++ b/game/src/Autoload/Events/ShaderManager.gd @@ -0,0 +1,40 @@ +extends RefCounted + +const param_province_shape : StringName = &"province_shape_tex" +const param_province_shape_subdivisions : StringName = &"province_shape_subdivisions" +const param_province_colour : StringName = &"province_colour_tex" +const param_hover_index : StringName = &"hover_index" +const param_selected_index : StringName = &"selected_index" +const param_terrain_tile_factor : StringName = &"terrain_tile_factor" + +func set_up_shader(material : Material, add_colour_texture : bool) -> Error: + # Shader Material + if material == null: + push_error("material is null!") + return FAILED + if not material is ShaderMaterial: + push_error("Invalid map mesh material class: ", material.get_class()) + return FAILED + var shader_material : ShaderMaterial = material + + # Province shape texture + var province_shape_texture := GameSingleton.get_province_shape_texture() + if province_shape_texture == null: + push_error("Failed to get province shape texture!") + return FAILED + shader_material.set_shader_parameter(param_province_shape, province_shape_texture) + var subdivisions := GameSingleton.get_province_shape_image_subdivisions() + if subdivisions.x < 1 or subdivisions.y < 1: + push_error("Invalid province shape image subdivision: ", subdivisions.x, "x", subdivisions.y) + return FAILED + shader_material.set_shader_parameter(param_province_shape_subdivisions, Vector2(subdivisions)) + + if add_colour_texture: + # Province colour texture + var map_province_colour_texture := GameSingleton.get_province_colour_texture() + if map_province_colour_texture == null: + push_error("Failed to get province colour image!") + return FAILED + shader_material.set_shader_parameter(param_province_colour, map_province_colour_texture) + + return OK diff --git a/game/src/Autoload/Resolution.gd b/game/src/Autoload/Resolution.gd index e1e788b..35ecbb3 100644 --- a/game/src/Autoload/Resolution.gd +++ b/game/src/Autoload/Resolution.gd @@ -62,7 +62,7 @@ func get_resolution_display_name(resolution_value : Vector2i) -> StringName: func get_resolution_value_from_string(resolution_string : String) -> Vector2i: if not resolution_string.is_empty(): for resolution in _resolutions.values(): - if resolution_string == resolution.get(name) or resolution_string == resolution.display_name: + if resolution_string == resolution.name or resolution_string == resolution.display_name: return resolution.value var result := _regex.search(resolution_string) if result: return Vector2i(result.get_string(1).to_int(), result.get_string(2).to_int()) diff --git a/game/src/GameSession/GameSession.tscn b/game/src/GameSession/GameSession.tscn index b993acf..98b43dd 100644 --- a/game/src/GameSession/GameSession.tscn +++ b/game/src/GameSession/GameSession.tscn @@ -69,7 +69,6 @@ grow_horizontal = 0 [connection signal="province_selected" from="MapView" to="ProvinceOverviewPanel" method="_on_province_selected"] [connection signal="options_button_pressed" from="GameSessionMenu" to="OptionsMenu" method="show"] [connection signal="game_session_menu_button_pressed" from="MapControlPanel" to="." method="_on_game_session_menu_button_pressed"] -[connection signal="mapmode_changed" from="MapControlPanel" to="MapView" method="_update_colour_texture"] [connection signal="minimap_clicked" from="MapControlPanel" to="MapView" method="_on_minimap_clicked"] [connection signal="mouse_entered" from="MapControlPanel" to="MapView" method="_on_mouse_exited_viewport"] [connection signal="mouse_exited" from="MapControlPanel" to="MapView" method="_on_mouse_entered_viewport"] diff --git a/game/src/GameSession/MapControlPanel.gd b/game/src/GameSession/MapControlPanel.gd index 73d7e06..508f692 100644 --- a/game/src/GameSession/MapControlPanel.gd +++ b/game/src/GameSession/MapControlPanel.gd @@ -1,7 +1,6 @@ extends PanelContainer signal game_session_menu_button_pressed -signal mapmode_changed signal map_view_camera_changed(near_left : Vector2, far_left : Vector2, far_right : Vector2, near_right : Vector2) signal minimap_clicked(pos_clicked : Vector2) signal zoom_in_button_pressed @@ -40,7 +39,7 @@ func _on_game_session_menu_button_pressed() -> void: # * UIFUN-129, UIFUN-133 func _mapmode_pressed(button : BaseButton) -> void: GameSingleton.set_mapmode(button.tooltip_text) - mapmode_changed.emit() + GameSingleton.update_colour_image() func _on_map_view_camera_changed(near_left : Vector2, far_left : Vector2, far_right : Vector2, near_right : Vector2) -> void: map_view_camera_changed.emit(near_left, far_left, far_right, near_right) diff --git a/game/src/GameSession/MapControlPanel.tscn b/game/src/GameSession/MapControlPanel.tscn index 18b1c3f..ae4c3dc 100644 --- a/game/src/GameSession/MapControlPanel.tscn +++ b/game/src/GameSession/MapControlPanel.tscn @@ -1,9 +1,12 @@ [gd_scene load_steps=7 format=3 uid="uid://g524p8lr574w"] [ext_resource type="Script" path="res://src/GameSession/MapControlPanel.gd" id="1_ign64"] -[ext_resource type="Texture2D" uid="uid://c0sm1jfu4kyv3" path="res://art/ui/minimap.png" id="2_r613r"] +[ext_resource type="Shader" path="res://src/GameSession/Minimap.gdshader" id="2_rinsg"] [ext_resource type="Script" path="res://src/GameSession/Minimap.gd" id="3_s4dml"] -[ext_resource type="Texture2D" uid="uid://vr1hq2stk8ny" path="res://art/ui/minimap_frame.png" id="4_f1exl"] + +[sub_resource type="ShaderMaterial" id="ShaderMaterial_bhuqb"] +shader = ExtResource("2_rinsg") +shader_parameter/province_shape_subdivisions = null [sub_resource type="InputEventAction" id="InputEventAction_5nck3"] action = &"ui_cancel" @@ -41,28 +44,21 @@ columns = 11 [node name="Minimap" type="PanelContainer" parent="MapPanelMargin/MapPanelList/MapDisplayList"] editor_description = "UI-549" layout_mode = 2 +size_flags_horizontal = 4 +size_flags_vertical = 4 mouse_filter = 1 -[node name="MinimapTexture" type="TextureRect" parent="MapPanelMargin/MapPanelList/MapDisplayList/Minimap"] +[node name="MinimapTexture" type="ColorRect" parent="MapPanelMargin/MapPanelList/MapDisplayList/Minimap"] editor_description = "UI-751, FS-338" +material = SubResource("ShaderMaterial_bhuqb") layout_mode = 2 -texture = ExtResource("2_r613r") +color = Color(0.921569, 0.835294, 0.701961, 1) -[node name="ViewportQuad" type="Control" parent="MapPanelMargin/MapPanelList/MapDisplayList/Minimap"] +[node name="ViewportQuad" type="Control" parent="MapPanelMargin/MapPanelList/MapDisplayList/Minimap" node_paths=PackedStringArray("_minimap_texture")] layout_mode = 2 mouse_filter = 2 script = ExtResource("3_s4dml") - -[node name="Frame" type="NinePatchRect" parent="MapPanelMargin/MapPanelList/MapDisplayList/Minimap"] -layout_mode = 2 -texture = ExtResource("4_f1exl") -draw_center = false -patch_margin_left = 10 -patch_margin_top = 10 -patch_margin_right = 10 -patch_margin_bottom = 10 -axis_stretch_horizontal = 1 -axis_stretch_vertical = 1 +_minimap_texture = NodePath("../MinimapTexture") [node name="AuxiliaryPanel" type="VBoxContainer" parent="MapPanelMargin/MapPanelList"] editor_description = "UI-761" diff --git a/game/src/GameSession/MapView.gd b/game/src/GameSession/MapView.gd index e74ea59..340083f 100644 --- a/game/src/GameSession/MapView.gd +++ b/game/src/GameSession/MapView.gd @@ -12,12 +12,6 @@ const _action_zoom_out : StringName = &"map_zoom_out" const _action_drag : StringName = &"map_drag" const _action_click : StringName = &"map_click" -const _shader_param_province_index : StringName = &"province_index_tex" -const _shader_param_province_colour : StringName = &"province_colour_tex" -const _shader_param_hover_index : StringName = &"hover_index" -const _shader_param_selected_index : StringName = &"selected_index" -const _shader_param_terrain_tile_factor : StringName = &"terrain_tile_factor" - @export var _camera : Camera3D @export var _cardinal_move_speed : float = 1.0 @@ -40,9 +34,6 @@ var _mouse_over_viewport : bool = true @export var _map_mesh_instance : MeshInstance3D var _map_mesh : MapMesh var _map_shader_material : ShaderMaterial -var _map_image_size : Vector2 -var _map_province_colour_image : Image -var _map_province_colour_texture : ImageTexture var _map_mesh_corner : Vector2 var _map_mesh_dims : Vector2 @@ -68,42 +59,19 @@ func _ready(): # Shader Material var map_material := _map_mesh_instance.get_active_material(0) - if map_material == null: - push_error("Map mesh is missing material!") - return - if not map_material is ShaderMaterial: - push_error("Invalid map mesh material class: ", map_material.get_class()) + if Events.ShaderManager.set_up_shader(map_material, true) != OK: + push_error("Failed to set up map shader") return _map_shader_material = map_material - # Province index textures - var map_province_index_images := GameSingleton.get_province_index_images() - if map_province_index_images == null or map_province_index_images.is_empty(): - push_error("Failed to get province index image!") - return - var province_index_texture := Texture2DArray.new() - if province_index_texture.create_from_images(map_province_index_images) != OK: - push_error("Failed to generate province index texture array!") - return - _map_shader_material.set_shader_parameter(_shader_param_province_index, province_index_texture) - - # Province colour texture - _map_province_colour_image = GameSingleton.get_province_colour_image() - if _map_province_colour_image == null: - push_error("Failed to get province colour image!") - return - _map_province_colour_texture = ImageTexture.create_from_image(_map_province_colour_image) - _map_shader_material.set_shader_parameter(_shader_param_province_colour, _map_province_colour_texture) - if not _map_mesh_instance.mesh is MapMesh: push_error("Invalid map mesh class: ", _map_mesh_instance.mesh.get_class(), "(expected MapMesh)") return _map_mesh = _map_mesh_instance.mesh # Set map mesh size and get bounds - _map_image_size = Vector2(Vector2i(GameSingleton.get_width(), GameSingleton.get_height())) - _map_mesh.aspect_ratio = _map_image_size.x / _map_image_size.y - _map_shader_material.set_shader_parameter(_shader_param_terrain_tile_factor, _map_image_size.y / 64.0) + _map_mesh.aspect_ratio = GameSingleton.get_aspect_ratio() + _map_shader_material.set_shader_parameter(Events.ShaderManager.param_terrain_tile_factor, float(GameSingleton.get_height()) / 64.0) var map_mesh_aabb := _map_mesh.get_core_aabb() * _map_mesh_instance.transform _map_mesh_corner = Vector2( min(map_mesh_aabb.position.x, map_mesh_aabb.end.x), @@ -121,10 +89,6 @@ func _notification(what : int): NOTIFICATION_WM_MOUSE_EXIT: # Mouse out of window _on_mouse_exited_viewport() -func _update_colour_texture() -> void: - GameSingleton.update_colour_image() - _map_province_colour_texture.update(_map_province_colour_image) - func _world_to_map_coords(pos : Vector3) -> Vector2: return (Vector2(pos.x, pos.z) - _map_mesh_corner) / _map_mesh_dims @@ -154,7 +118,7 @@ func _unhandled_input(event : InputEvent): # Check if the mouse is outside of bounds if _map_mesh.is_valid_uv_coord(_mouse_pos_map): var selected_index := GameSingleton.get_province_index_from_uv_coords(_mouse_pos_map) - _map_shader_material.set_shader_parameter(_shader_param_selected_index, selected_index) + _map_shader_material.set_shader_parameter(Events.ShaderManager.param_selected_index, selected_index) province_selected.emit(selected_index) else: print("Clicked outside the map!") @@ -251,7 +215,7 @@ func _update_mouse_map_position() -> void: _mouse_pos_map = _viewport_to_map_coords(_mouse_pos_viewport) var hover_index := GameSingleton.get_province_index_from_uv_coords(_mouse_pos_map) if _mouse_over_viewport: - _map_shader_material.set_shader_parameter(_shader_param_hover_index, hover_index) + _map_shader_material.set_shader_parameter(Events.ShaderManager.param_hover_index, hover_index) func _on_mouse_entered_viewport(): _mouse_over_viewport = true diff --git a/game/src/GameSession/MapView.tscn b/game/src/GameSession/MapView.tscn index c8934c5..efbad4e 100644 --- a/game/src/GameSession/MapView.tscn +++ b/game/src/GameSession/MapView.tscn @@ -7,6 +7,7 @@ [sub_resource type="ShaderMaterial" id="ShaderMaterial_tayeg"] render_priority = 0 shader = ExtResource("1_upocn") +shader_parameter/province_index_subdivisions = null shader_parameter/hover_index = null shader_parameter/selected_index = null shader_parameter/terrain_tile_factor = null diff --git a/game/src/GameSession/Minimap.gd b/game/src/GameSession/Minimap.gd index 25c7cac..05c662b 100644 --- a/game/src/GameSession/Minimap.gd +++ b/game/src/GameSession/Minimap.gd @@ -4,8 +4,15 @@ signal minimap_clicked(pos_clicked : Vector2) const _action_click : StringName = &"map_click" +@export var _minimap_texture : Control + var _viewport_points : PackedVector2Array +func _ready(): + _minimap_texture.custom_minimum_size = Vector2(GameSingleton.get_aspect_ratio(), 1.0) * 150 + if Events.ShaderManager.set_up_shader(_minimap_texture.get_material(), false) != OK: + push_error("Failed to set up minimap shader") + # REQUIREMENTS # * SS-80 # * UI-752 diff --git a/game/src/GameSession/Minimap.gdshader b/game/src/GameSession/Minimap.gdshader new file mode 100644 index 0000000..9afd470 --- /dev/null +++ b/game/src/GameSession/Minimap.gdshader @@ -0,0 +1,7 @@ +shader_type canvas_item; + +#include "ProvinceIndexSampler.gdshaderinc" + +void fragment() { + COLOR.rgb = mix(COLOR.rgb, vec3(0.5), float(read_uvec3(UV).b != 0u)); +} diff --git a/game/src/GameSession/ProvinceIndexSampler.gdshaderinc b/game/src/GameSession/ProvinceIndexSampler.gdshaderinc new file mode 100644 index 0000000..65f73d8 --- /dev/null +++ b/game/src/GameSession/ProvinceIndexSampler.gdshaderinc @@ -0,0 +1,18 @@ + +// Province shape texture +uniform sampler2DArray province_shape_tex : repeat_enable, filter_nearest; +// Province shape subdivisions +uniform vec2 province_shape_subdivisions; + +uvec3 vec3_to_uvec3(vec3 v) { + return uvec3(v * 255.0); +} +uvec3 read_uvec3(vec2 uv) { + uv *= province_shape_subdivisions; + vec2 subdivision_coords = mod(floor(uv), province_shape_subdivisions); + float idx = subdivision_coords.x + subdivision_coords.y * province_shape_subdivisions.x; + return vec3_to_uvec3(texture(province_shape_tex, vec3(uv, idx)).rgb); +} +uint uvec2_to_uint(uvec2 v) { + return (v.y << 8u) | v.x; +} diff --git a/game/src/GameSession/TerrainMap.gdshader b/game/src/GameSession/TerrainMap.gdshader index 305a34b..05928f3 100644 --- a/game/src/GameSession/TerrainMap.gdshader +++ b/game/src/GameSession/TerrainMap.gdshader @@ -2,40 +2,26 @@ shader_type spatial; render_mode unshaded; -// Cosmetic farmlands terrain texture -uniform sampler2D farmlands_tex: source_color, repeat_enable, filter_linear; -// Province index texture -uniform sampler2DArray province_index_tex : source_color, repeat_enable, filter_nearest; +#include "ProvinceIndexSampler.gdshaderinc" + // Province colour texture uniform sampler2D province_colour_tex: source_color, repeat_enable, filter_nearest; // Index of the mouse over the map mesh uniform uint hover_index; // Index of the currently selected province uniform uint selected_index; +// Cosmetic farmlands terrain texture +uniform sampler2D farmlands_tex: source_color, repeat_enable, filter_linear; // The number of times the terrain textures should tile vertically uniform float terrain_tile_factor; -uvec2 vec2_to_uvec2(vec2 v) { - return uvec2(v * 255.0); -} -uvec2 read_uvec2(vec2 uv) { - float width_divisions = float(textureSize(province_index_tex, 0).z); - uv.x *= width_divisions; - float idx = mod(floor(uv.x), width_divisions); - return vec2_to_uvec2(texture(province_index_tex, vec3(uv, idx)).rg); -} -uint uvec2_to_uint(uvec2 v) { - return (v.y << 8u) | v.x; -} - const vec3 water_colour = vec3(0, 0, 1); vec3 get_terrain_colour(vec2 uv, vec2 corner, vec2 half_pixel_size, vec2 terrain_uv) { - uvec2 index_split = read_uvec2(fma(corner, half_pixel_size, uv)); - uint index = uvec2_to_uint(index_split); - vec4 province_data = texelFetch(province_colour_tex, ivec2(index_split), 0); - vec3 province_colour = province_data.rgb; - float is_land = province_data.a; + uvec3 province_data = read_uvec3(fma(corner, half_pixel_size, uv)); + uint index = uvec2_to_uint(province_data.rg); + float is_land = float(province_data.b != 0u); + vec3 province_colour = texelFetch(province_colour_tex, ivec2(province_data.rg), 0).rgb; vec3 farmlands_colour = texture(farmlands_tex, terrain_uv).rgb; vec3 terrain_colour = mix(water_colour, farmlands_colour, is_land); float mix_val = 0.4 + float(index == hover_index) * 0.2 + float(index == selected_index) * 0.2; @@ -44,7 +30,7 @@ vec3 get_terrain_colour(vec2 uv, vec2 corner, vec2 half_pixel_size, vec2 terrain } vec3 mix_terrain_colour(vec2 uv) { - vec2 map_size = vec2(textureSize(province_index_tex, 0).xy); + vec2 map_size = vec2(textureSize(province_shape_tex, 0).xy); vec2 pixel_offset = fract(fma(uv, map_size, vec2(0.5))); vec2 half_pixel_size = 0.49 / map_size; |