aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--extension/src/GameSingleton.cpp93
-rw-r--r--extension/src/GameSingleton.hpp15
-rw-r--r--extension/src/MapMesh.cpp18
-rw-r--r--extension/src/MapMesh.hpp10
-rw-r--r--extension/src/openvic2/map/Map.cpp27
-rw-r--r--extension/src/openvic2/map/Map.hpp13
-rw-r--r--game/art/ui/minimap.pngbin122017 -> 0 bytes
-rw-r--r--game/art/ui/minimap.png.import34
-rw-r--r--game/art/ui/minimap_frame.pngbin1043 -> 0 bytes
-rw-r--r--game/art/ui/minimap_frame.png.import34
-rw-r--r--game/project.godot3
-rw-r--r--game/src/Autoload/Events.gd2
-rw-r--r--game/src/Autoload/Events/GameDebug.gd (renamed from game/src/Autoload/GameDebug.gd)5
-rw-r--r--game/src/Autoload/Events/ShaderManager.gd40
-rw-r--r--game/src/Autoload/Resolution.gd2
-rw-r--r--game/src/GameSession/GameSession.tscn1
-rw-r--r--game/src/GameSession/MapControlPanel.gd3
-rw-r--r--game/src/GameSession/MapControlPanel.tscn28
-rw-r--r--game/src/GameSession/MapView.gd48
-rw-r--r--game/src/GameSession/MapView.tscn1
-rw-r--r--game/src/GameSession/Minimap.gd7
-rw-r--r--game/src/GameSession/Minimap.gdshader7
-rw-r--r--game/src/GameSession/ProvinceIndexSampler.gdshaderinc18
-rw-r--r--game/src/GameSession/TerrainMap.gdshader32
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
deleted file mode 100644
index 9922b28..0000000
--- a/game/art/ui/minimap.png
+++ /dev/null
Binary files differ
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
deleted file mode 100644
index 21aa2ce..0000000
--- a/game/art/ui/minimap_frame.png
+++ /dev/null
Binary files differ
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;