aboutsummaryrefslogtreecommitdiff
path: root/extension/src/openvic2
diff options
context:
space:
mode:
Diffstat (limited to 'extension/src/openvic2')
-rw-r--r--extension/src/openvic2/Map.cpp253
-rw-r--r--extension/src/openvic2/Map.hpp38
-rw-r--r--extension/src/openvic2/Province.cpp40
-rw-r--r--extension/src/openvic2/Region.cpp26
-rw-r--r--extension/src/openvic2/Types.hpp7
5 files changed, 288 insertions, 76 deletions
diff --git a/extension/src/openvic2/Map.cpp b/extension/src/openvic2/Map.cpp
index 6e1c08a..921f371 100644
--- a/extension/src/openvic2/Map.cpp
+++ b/extension/src/openvic2/Map.cpp
@@ -1,126 +1,91 @@
#include "Map.hpp"
#include <cassert>
-#include <sstream>
-#include <iomanip>
using namespace OpenVic2;
-Province::Province(index_t new_index, std::string const& new_identifier, colour_t new_colour) :
- index(new_index), identifier(new_identifier), colour(new_colour) {
- assert(index != NULL_INDEX);
- assert(!identifier.empty());
- assert(colour != NULL_COLOUR);
-}
+static const std::string SEPARATOR = "\n - ";
-std::string Province::colour_to_hex_string(colour_t colour) {
- std::ostringstream stream;
- stream << std::hex << std::setfill('0') << std::setw(6) << colour;
- return stream.str();
+Mapmode::Mapmode(index_t new_index, std::string const& new_identifier, colour_func_t new_colour_func)
+ : index(new_index), identifier(new_identifier), colour_func(new_colour_func) {
+ assert(!identifier.empty());
+ assert(colour_func != nullptr);
}
-Province::index_t Province::get_index() const {
+Mapmode::index_t Mapmode::get_index() const {
return index;
}
-std::string const& Province::get_identifier() const {
+std::string const& Mapmode::get_identifier() const {
return identifier;
}
-Province::colour_t Province::get_colour() const {
- return colour;
-}
-
-Region* Province::get_region() const {
- return region;
-}
-
-std::string Province::to_string() const {
- return "(#" + std::to_string(index) + ", " + identifier + ", 0x" + colour_to_hex_string(colour) + ")";
-}
-
-Region::Region(std::string const& new_identifier) : identifier(new_identifier) {
- assert(!identifier.empty());
-}
-
-std::string const& Region::get_identifier() const {
- return identifier;
-}
-
-size_t Region::get_province_count() const {
- return provinces.size();
-}
-
-bool Region::contains_province(Province const* province) const {
- return province && std::find(provinces.begin(), provinces.end(), province) != provinces.end();
-}
-
-std::vector<Province*> const& Region::get_provinces() const {
- return provinces;
+Mapmode::colour_func_t Mapmode::get_colour_func() const {
+ return colour_func;
}
-bool Map::add_province(std::string const& identifier, Province::colour_t colour, std::string& error_message) {
+return_t Map::add_province(std::string const& identifier, Province::colour_t colour, std::string& error_message) {
if (provinces_locked) {
error_message = "The map's province list has already been locked!";
- return false;
+ return FAILURE;
}
if (provinces.size() >= Province::MAX_INDEX) {
error_message = "The map's province list is full - there can be at most " + std::to_string(Province::MAX_INDEX) + " provinces";
- return false;
+ return FAILURE;
}
if (identifier.empty()) {
error_message = "Empty province identifier for colour " + Province::colour_to_hex_string(colour);
- return false;
+ return FAILURE;
}
if (colour == Province::NULL_COLOUR || colour > Province::MAX_COLOUR) {
error_message = "Invalid province colour: " + Province::colour_to_hex_string(colour);
- return false;
+ return FAILURE;
}
Province new_province{ static_cast<Province::index_t>(provinces.size() + 1), identifier, colour };
for (Province const& province : provinces) {
- if (province.identifier == identifier) {
+ if (province.get_identifier() == identifier) {
error_message = "Duplicate province identifiers: " + province.to_string() + " and " + new_province.to_string();
- return false;
+ return FAILURE;
}
- if (province.colour == colour) {
+ if (province.get_colour() == colour) {
error_message = "Duplicate province colours: " + province.to_string() + " and " + new_province.to_string();
- return false;
+ return FAILURE;
}
}
provinces.push_back(new_province);
error_message = "Added province: " + new_province.to_string();
- return true;
+ return SUCCESS;
}
void Map::lock_provinces() {
provinces_locked = true;
}
-bool Map::add_region(std::string const& identifier, std::vector<std::string> const& province_identifiers, std::string& error_message) {
+return_t Map::add_region(std::string const& identifier, std::vector<std::string> const& province_identifiers, std::string& error_message) {
if (regions_locked) {
error_message = "The map's region list has already been locked!";
- return false;
+ return FAILURE;
}
if (identifier.empty()) {
error_message = "Empty region identifier!";
- return false;
+ return FAILURE;
}
if (provinces.empty()) {
error_message = "Empty province list for region " + identifier;
- return false;
+ return FAILURE;
}
Region new_region{ identifier };
error_message = "Error message for region: " + identifier;
- static const std::string SEPARATOR = "\n - ";
for (std::string const& province_identifier : province_identifiers) {
Province* province = get_province_by_identifier(province_identifier);
- if (province) {
+ if (province != nullptr) {
if (new_region.contains_province(province))
error_message += SEPARATOR + "Duplicate province identifier " + province_identifier;
else {
- if (province->region) {
+ size_t other_region_index = reinterpret_cast<size_t>(province->get_region());
+ if (other_region_index != 0) {
+ other_region_index--;
error_message += SEPARATOR + "Province " + province_identifier + " is already part of ";
- const size_t other_region_index = reinterpret_cast<size_t>(province->region) - 1;
if (other_region_index < regions.size())
error_message += regions[other_region_index].get_identifier();
else
@@ -131,12 +96,12 @@ bool Map::add_region(std::string const& identifier, std::vector<std::string> con
}
if (!new_region.get_province_count()) {
error_message += SEPARATOR + "No valid provinces in region's list";
- return false;
+ return FAILURE;
}
for (Region const& region : regions) {
- if (region.identifier == identifier) {
+ if (region.get_identifier() == identifier) {
error_message += SEPARATOR + "Duplicate region identifiers: " + region.get_identifier() + " and " + identifier;
- return false;
+ return FAILURE;
}
}
regions.push_back(new_region);
@@ -144,15 +109,15 @@ bool Map::add_region(std::string const& identifier, std::vector<std::string> con
// Used to detect provinces listed in multiple regions, will
// be corrected once regions is stable (i.e. lock_regions).
Region* tmp_region_index = reinterpret_cast<Region*>(regions.size());
- for (Province* province : new_region.provinces)
+ for (Province* province : new_region.get_provinces())
province->region = tmp_region_index;
- return true;
+ return SUCCESS;
}
void Map::lock_regions() {
regions_locked = true;
for (Region& region : regions)
- for (Province* province : region.provinces)
+ for (Province* province : region.get_provinces())
province->region = &region;
}
@@ -171,27 +136,171 @@ Province const* Map::get_province_by_index(Province::index_t index) const {
Province* Map::get_province_by_identifier(std::string const& identifier) {
if (!identifier.empty())
for (Province& province : provinces)
- if (province.identifier == identifier) return &province;
+ if (province.get_identifier() == identifier) return &province;
return nullptr;
}
Province const* Map::get_province_by_identifier(std::string const& identifier) const {
if (!identifier.empty())
for (Province const& province : provinces)
- if (province.identifier == identifier) return &province;
+ if (province.get_identifier() == identifier) return &province;
return nullptr;
}
Province* Map::get_province_by_colour(Province::colour_t colour) {
if (colour != Province::NULL_COLOUR)
for (Province& province : provinces)
- if (province.colour == colour) return &province;
+ if (province.get_colour() == colour) return &province;
return nullptr;
}
Province const* Map::get_province_by_colour(Province::colour_t colour) const {
if (colour != Province::NULL_COLOUR)
for (Province const& province : provinces)
- if (province.colour == colour) return &province;
+ if (province.get_colour() == colour) return &province;
+ return nullptr;
+}
+
+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, std::string& error_message) {
+ if (!province_index_image.empty()) {
+ error_message = "Province index image has already been generated!";
+ return FAILURE;
+ }
+ if (!provinces_locked) {
+ error_message = "Province index image cannot be generated until after provinces are locked!";
+ return FAILURE;
+ }
+ if (new_width < 1 || new_height < 1) {
+ error_message = "Invalid province image dimensions: " + std::to_string(new_width) + "x" + std::to_string(new_height);
+ return FAILURE;
+ }
+ if (colour_data == nullptr) {
+ error_message = "Province colour data pointer is null!";
+ return FAILURE;
+ }
+ width = new_width;
+ height = new_height;
+ province_index_image.resize(width * height);
+
+ std::vector<bool> province_checklist(provinces.size());
+ return_t ret = SUCCESS;
+
+ error_message = "Error message for province index image generation:";
+
+ for (int32_t y = 0; y < height; ++y) {
+ for (int32_t x = 0; x < width; ++x) {
+ const int32_t idx = x + y * width;
+ const Province::colour_t colour = colour_at(colour_data, idx);
+ if (colour == Province::NULL_COLOUR) {
+ province_index_image[idx] = Province::NULL_INDEX;
+ continue;
+ }
+ if (x > 0) {
+ const int32_t jdx = idx - 1;
+ if (colour_at(colour_data, jdx) == colour) {
+ province_index_image[idx] = province_index_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];
+ 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;
+ continue;
+ }
+ error_message += SEPARATOR + "Unrecognised province colour " + Province::colour_to_hex_string(colour) + " at (" + std::to_string(x) + ", " + std::to_string(x) + ")";
+ ret = FAILURE;
+ province_index_image[idx] = Province::NULL_INDEX;
+ }
+ }
+
+ for (size_t idx = 0; idx < province_checklist.size(); ++idx) {
+ if (!province_checklist[idx]) {
+ error_message += SEPARATOR + "Province missing from shape image: " + provinces[idx].to_string();
+ ret = FAILURE;
+ }
+ }
+
+ error_message += SEPARATOR + "Generated province index image";
+ return ret;
+}
+
+size_t Map::get_width() const {
+ return width;
+}
+
+size_t Map::get_height() const {
+ return height;
+}
+
+std::vector<Province::index_t> const& Map::get_province_index_image() const {
+ return province_index_image;
+}
+
+return_t Map::add_mapmode(std::string const& identifier, Mapmode::colour_func_t colour_func, std::string& error_message) {
+ if (identifier.empty()) {
+ error_message = "Empty mapmode identifier!";
+ return FAILURE;
+ }
+ if (colour_func == nullptr) {
+ error_message = "Mapmode colour function is null for identifier: " + identifier;
+ return FAILURE;
+ }
+ Mapmode new_mapmode{ mapmodes.size(), identifier, colour_func };
+ for (Mapmode const& mapmode : mapmodes) {
+ if (mapmode.get_identifier() == identifier) {
+ error_message = "Duplicate mapmode identifiers: " + mapmode.get_identifier() + " and " + identifier;
+ return FAILURE;
+ }
+ }
+ mapmodes.push_back(new_mapmode);
+ error_message = "Added mapmode: " + identifier;
+ return SUCCESS;
+}
+
+size_t Map::get_mapmode_count() const {
+ return mapmodes.size();
+}
+
+Mapmode const* Map::get_mapmode_by_index(size_t index) const {
+ return index < mapmodes.size() ? &mapmodes[index] : nullptr;
+}
+
+Mapmode const* Map::get_mapmode_by_identifier(std::string const& identifier) const {
+ if (!identifier.empty())
+ for (Mapmode const& mapmode : mapmodes)
+ if (mapmode.get_identifier() == identifier) return &mapmode;
return nullptr;
}
+
+return_t Map::generate_mapmode_colours(Mapmode::index_t index, uint8_t* target, std::string& error_message) const {
+ if (target == nullptr) {
+ error_message = "Mapmode colour target pointer is null!";
+ return FAILURE;
+ }
+ if (index >= mapmodes.size()) {
+ error_message = "Invalid mapmode index: " + std::to_string(index);
+ return FAILURE;
+ }
+ Mapmode const& mapmode = mapmodes[index];
+ target += 3; // Skip past Province::NULL_INDEX
+ for (Province const& province : provinces) {
+ const Province::colour_t colour = (*mapmode.get_colour_func())(*this, province);
+ *target++ = (colour >> 16) & 0xFF;
+ *target++ = (colour >> 8) & 0xFF;
+ *target++ = colour & 0xFF;
+ }
+ return SUCCESS;
+}
diff --git a/extension/src/openvic2/Map.hpp b/extension/src/openvic2/Map.hpp
index 1527f1a..2fa8bc8 100644
--- a/extension/src/openvic2/Map.hpp
+++ b/extension/src/openvic2/Map.hpp
@@ -4,8 +4,9 @@
#include <cstdint>
#include <vector>
-namespace OpenVic2 {
+#include "Types.hpp"
+namespace OpenVic2 {
struct Region;
struct Province {
@@ -45,16 +46,35 @@ namespace OpenVic2 {
std::vector<Province*> const& get_provinces() const;
};
+ struct Mapmode {
+ using colour_func_t = Province::colour_t (*)(Map const& map, Province const& province);
+ using index_t = size_t;
+ friend struct Map;
+ private:
+ index_t index;
+ std::string identifier;
+ colour_func_t colour_func;
+
+ Mapmode(index_t new_index, std::string const& new_identifier, colour_func_t new_colour_func);
+ public:
+ index_t get_index() const;
+ std::string const& get_identifier() const;
+ colour_func_t get_colour_func() const;
+ };
+
struct Map {
private:
std::vector<Province> provinces;
std::vector<Region> regions;
bool provinces_locked = false, regions_locked = false;
+ size_t width = 0, height = 0;
+ std::vector<Province::index_t> province_index_image;
+ std::vector<Mapmode> mapmodes;
public:
- bool add_province(std::string const& identifier, Province::colour_t colour, std::string& error_message);
+ return_t add_province(std::string const& identifier, Province::colour_t colour, std::string& error_message);
void lock_provinces();
- bool add_region(std::string const& identifier, std::vector<std::string> const& province_identifiers, std::string& error_message);
+ return_t add_region(std::string const& identifier, std::vector<std::string> const& province_identifiers, std::string& error_message);
void lock_regions();
size_t get_province_count() const;
@@ -64,6 +84,16 @@ namespace OpenVic2 {
Province const* get_province_by_identifier(std::string const& identifier) const;
Province* get_province_by_colour(Province::colour_t colour);
Province const* get_province_by_colour(Province::colour_t colour) const;
- };
+ return_t generate_province_index_image(size_t new_width, size_t new_height, uint8_t const* colour_data, std::string& error_message);
+ size_t get_width() const;
+ size_t get_height() const;
+ std::vector<Province::index_t> const& get_province_index_image() const;
+
+ return_t add_mapmode(std::string const& identifier, Mapmode::colour_func_t colour_func, std::string& error_message);
+ 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;
+ return_t generate_mapmode_colours(Mapmode::index_t index, uint8_t* target, std::string& error_message) const;
+ };
}
diff --git a/extension/src/openvic2/Province.cpp b/extension/src/openvic2/Province.cpp
new file mode 100644
index 0000000..49f1b0e
--- /dev/null
+++ b/extension/src/openvic2/Province.cpp
@@ -0,0 +1,40 @@
+#include "Map.hpp"
+
+#include <cassert>
+#include <sstream>
+#include <iomanip>
+
+using namespace OpenVic2;
+
+Province::Province(index_t new_index, std::string const& new_identifier, colour_t new_colour) :
+ index(new_index), identifier(new_identifier), colour(new_colour) {
+ assert(index != NULL_INDEX);
+ assert(!identifier.empty());
+ assert(colour != NULL_COLOUR);
+}
+
+std::string Province::colour_to_hex_string(colour_t colour) {
+ std::ostringstream stream;
+ stream << std::hex << std::setfill('0') << std::setw(6) << colour;
+ return stream.str();
+}
+
+Province::index_t Province::get_index() const {
+ return index;
+}
+
+std::string const& Province::get_identifier() const {
+ return identifier;
+}
+
+Province::colour_t Province::get_colour() const {
+ return colour;
+}
+
+Region* Province::get_region() const {
+ return region;
+}
+
+std::string Province::to_string() const {
+ return "(#" + std::to_string(index) + ", " + identifier + ", 0x" + colour_to_hex_string(colour) + ")";
+}
diff --git a/extension/src/openvic2/Region.cpp b/extension/src/openvic2/Region.cpp
new file mode 100644
index 0000000..6ee05f5
--- /dev/null
+++ b/extension/src/openvic2/Region.cpp
@@ -0,0 +1,26 @@
+#include "Map.hpp"
+
+#include <cassert>
+#include <algorithm>
+
+using namespace OpenVic2;
+
+Region::Region(std::string const& new_identifier) : identifier(new_identifier) {
+ assert(!identifier.empty());
+}
+
+std::string const& Region::get_identifier() const {
+ return identifier;
+}
+
+size_t Region::get_province_count() const {
+ return provinces.size();
+}
+
+bool Region::contains_province(Province const* province) const {
+ return province && std::find(provinces.begin(), provinces.end(), province) != provinces.end();
+}
+
+std::vector<Province*> const& Region::get_provinces() const {
+ return provinces;
+}
diff --git a/extension/src/openvic2/Types.hpp b/extension/src/openvic2/Types.hpp
new file mode 100644
index 0000000..0fb1c8b
--- /dev/null
+++ b/extension/src/openvic2/Types.hpp
@@ -0,0 +1,7 @@
+#pragma once
+
+namespace OpenVic2 {
+ using return_t = bool;
+ // This mirrors godot::Error, where `OK = 0` and `FAILED = 1`.
+ static const return_t SUCCESS = false, FAILURE = true;
+}