diff options
author | Hop311 <Hop3114@gmail.com> | 2023-04-29 00:40:18 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-04-29 00:40:18 +0200 |
commit | 05937359e8c53ee76dc3ce537dd70083a016f766 (patch) | |
tree | 899b97479f6a1aabbfe352747bea162ce5720193 /extension/src | |
parent | 10053cf259c55ee45803268a844edf1011d8a16b (diff) | |
parent | 5022ec800b096e9a85d6ef07ca4b652abb8625ee (diff) |
Merge pull request #101 from OpenVic2Project/more-image-processing
Dynamic minimap + vertical map subdivision
Diffstat (limited to 'extension/src')
-rw-r--r-- | extension/src/GameSingleton.cpp | 96 | ||||
-rw-r--r-- | extension/src/GameSingleton.hpp | 15 | ||||
-rw-r--r-- | extension/src/MapMesh.cpp | 18 | ||||
-rw-r--r-- | extension/src/MapMesh.hpp | 10 | ||||
-rw-r--r-- | extension/src/openvic2/map/Map.cpp | 27 | ||||
-rw-r--r-- | extension/src/openvic2/map/Map.hpp | 13 |
6 files changed, 108 insertions, 71 deletions
diff --git a/extension/src/GameSingleton.cpp b/extension/src/GameSingleton.cpp index 3811dea..4d5728a 100644 --- a/extension/src/GameSingleton.cpp +++ b/extension/src/GameSingleton.cpp @@ -24,8 +24,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); @@ -231,7 +233,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; } @@ -242,16 +244,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) { @@ -259,24 +260,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<Province::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(Province::index_t)); - for (int32_t y = 0; y < height; ++y) - memcpy(index_data_array.ptrw() + y * divided_width * sizeof(Province::index_t), - province_index_data.data() + y * width + i * divided_width, - divided_width * sizeof(Province::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; @@ -366,20 +380,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 = (Province::MAX_INDEX + 1) * 4; + static constexpr int64_t colour_data_array_size = (Province::MAX_INDEX + 1) * Map::MAPMODE_COLOUR_SIZE; colour_data_array.resize(colour_data_array_size); Error err = OK; @@ -387,14 +406,17 @@ Error GameSingleton::update_colour_image() { err = FAILED; static constexpr int32_t PROVINCE_INDEX_SQRT = 1 << (sizeof(Province::index_t) * 4); - if (province_colour_image.is_null()) - province_colour_image.instantiate(); + 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 b5cf144..428b749 100644 --- a/extension/src/openvic2/map/Map.cpp +++ b/extension/src/openvic2/map/Map.cpp @@ -157,7 +157,7 @@ Province const* Map::get_province_by_colour(Province::colour_t colour) const { } Province::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 Province::NULL_INDEX; } @@ -173,8 +173,8 @@ static Province::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; } @@ -192,7 +192,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; @@ -205,22 +205,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 Province::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()) { @@ -228,7 +229,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] = Province::NULL_INDEX; + province_shape_image[idx].index = Province::NULL_INDEX; + province_shape_image[idx].terrain = 0; } } @@ -249,8 +251,8 @@ size_t Map::get_height() const { return height; } -std::vector<Province::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) { @@ -291,13 +293,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 Province::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 ebc23be..dea9b29 100644 --- a/extension/src/openvic2/map/Map.hpp +++ b/extension/src/openvic2/map/Map.hpp @@ -25,6 +25,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; @@ -33,7 +39,7 @@ namespace OpenVic2 { size_t water_province_count = 0; size_t width = 0, height = 0; - std::vector<Province::index_t> province_index_image; + std::vector<shape_pixel_t> province_shape_image; public: Map(); @@ -56,16 +62,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<Province::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); |