Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Piecharts (gd 4.1) #146

Merged
merged 4 commits into from
Aug 17, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
83 changes: 77 additions & 6 deletions extension/src/GameSingleton.cpp
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
#include "GameSingleton.hpp"

#include <cassert>

#include <godot_cpp/variant/utility_functions.hpp>

#include "openvic/utility/Logger.hpp"
Expand All @@ -11,10 +9,9 @@
using namespace godot;
using namespace OpenVic;

TerrainVariant::TerrainVariant(std::string const& new_identfier,
TerrainVariant::TerrainVariant(const std::string_view new_identfier,
colour_t new_colour, Ref<Image> const& new_image)
: HasIdentifier { new_identfier },
HasColour { new_colour, true },
: HasIdentifierAndColour { new_identfier, new_colour, true },
image { new_image } {}

Ref<Image> TerrainVariant::get_image() const {
Expand Down Expand Up @@ -75,6 +72,9 @@ void GameSingleton::_bind_methods() {
ClassDB::bind_static_method("GameSingleton", D_METHOD("get_province_info_region_key"), &GameSingleton::get_province_info_region_key);
ClassDB::bind_static_method("GameSingleton", D_METHOD("get_province_info_life_rating_key"), &GameSingleton::get_province_info_life_rating_key);
ClassDB::bind_static_method("GameSingleton", D_METHOD("get_province_info_total_population_key"), &GameSingleton::get_province_info_total_population_key);
ClassDB::bind_static_method("GameSingleton", D_METHOD("get_province_info_pop_types_key"), &GameSingleton::get_province_info_pop_types_key);
ClassDB::bind_static_method("GameSingleton", D_METHOD("get_province_info_pop_ideologies_key"), &GameSingleton::get_province_info_pop_ideologies_key);
ClassDB::bind_static_method("GameSingleton", D_METHOD("get_province_info_pop_cultures_key"), &GameSingleton::get_province_info_pop_cultures_key);
ClassDB::bind_static_method("GameSingleton", D_METHOD("get_province_info_rgo_key"), &GameSingleton::get_province_info_rgo_key);
ClassDB::bind_static_method("GameSingleton", D_METHOD("get_province_info_buildings_key"), &GameSingleton::get_province_info_buildings_key);

Expand All @@ -84,6 +84,25 @@ void GameSingleton::_bind_methods() {
ClassDB::bind_static_method("GameSingleton", D_METHOD("get_building_info_start_date_key"), &GameSingleton::get_building_info_start_date_key);
ClassDB::bind_static_method("GameSingleton", D_METHOD("get_building_info_end_date_key"), &GameSingleton::get_building_info_end_date_key);
ClassDB::bind_static_method("GameSingleton", D_METHOD("get_building_info_expansion_progress_key"), &GameSingleton::get_building_info_expansion_progress_key);

ClassDB::bind_static_method("GameSingleton", D_METHOD("get_piechart_info_size_key"), &GameSingleton::get_piechart_info_size_key);
ClassDB::bind_static_method("GameSingleton", D_METHOD("get_piechart_info_colour_key"), &GameSingleton::get_piechart_info_colour_key);

ClassDB::bind_static_method("GameSingleton", D_METHOD("draw_pie_chart", "image", "stopAngles", "colours", "radius",
"shadow_displacement", "shadow_tightness", "shadow_radius", "shadow_thickness",
"trim_colour", "trim_size", "gradient_falloff", "gradient_base",
"donut", "donut_inner_trim", "donut_inner_radius"), &GameSingleton::draw_pie_chart);
}

void GameSingleton::draw_pie_chart(Ref<Image> image,
Array const& stopAngles, Array const& colours, float radius,
Vector2 shadow_displacement, float shadow_tightness, float shadow_radius, float shadow_thickness,
Color trim_colour, float trim_size, float gradient_falloff, float gradient_base,
bool donut, bool donut_inner_trim, float donut_inner_radius) {

OpenVic::draw_pie_chart(image, stopAngles, colours, radius, shadow_displacement, shadow_tightness, shadow_radius, shadow_thickness,
trim_colour, trim_size, gradient_falloff, gradient_base,
donut, donut_inner_trim, donut_inner_radius);
}

GameSingleton* GameSingleton::get_singleton() {
Expand Down Expand Up @@ -153,11 +172,25 @@ Error GameSingleton::_load_hardcoded_defines() {
}
return HIGH_ALPHA_VALUE | val;
}
return HIGH_ALPHA_VALUE;
return NULL_COLOUR;
} },
{ "mapmode_population",
[](Map const& map, Province const& province) -> colour_t {
return HIGH_ALPHA_VALUE | (fraction_to_colour_byte(province.get_total_population(), map.get_highest_province_population() + 1, 0.1f, 1.0f) << 8);
} },
{ "mapmode_culture",
[](Map const& map, Province const& province) -> colour_t {
distribution_t const& cultures = province.get_culture_distribution();
if (!cultures.empty()) {
// This breaks if replaced with distribution_t::value_type, something
// about operator=(volatile const&) being deleted.
std::pair<HasIdentifierAndColour const*, float> culture = *cultures.begin();
for (distribution_t::value_type const p : cultures) {
if (p.second > culture.second) culture = p;
}
return HIGH_ALPHA_VALUE | culture.first->get_colour();
}
return NULL_COLOUR;
} }
};
for (mapmode_t const& mapmode : mapmodes)
Expand Down Expand Up @@ -208,6 +241,18 @@ StringName const& GameSingleton::get_province_info_total_population_key() {
static const StringName key = "total_population";
return key;
}
StringName const& GameSingleton::get_province_info_pop_types_key() {
static const StringName key = "pop_types";
return key;
}
StringName const& GameSingleton::get_province_info_pop_ideologies_key() {
static const StringName key = "pop_ideologies";
return key;
}
StringName const& GameSingleton::get_province_info_pop_cultures_key() {
static const StringName key = "pop_cultures";
return key;
}
StringName const& GameSingleton::get_province_info_rgo_key() {
static const StringName key = "rgo";
return key;
Expand Down Expand Up @@ -242,6 +287,26 @@ StringName const& GameSingleton::get_building_info_expansion_progress_key() {
return key;
}

StringName const& GameSingleton::get_piechart_info_size_key() {
static const StringName key = "size";
return key;
}
StringName const& GameSingleton::get_piechart_info_colour_key() {
static const StringName key = "colour";
return key;
}

Dictionary GameSingleton::_distribution_to_dictionary(distribution_t const& dist) const {
Dictionary dict;
for (distribution_t::value_type const& p : dist) {
Dictionary sub_dict;
sub_dict[get_piechart_info_size_key()] = p.second;
sub_dict[get_piechart_info_colour_key()] = to_godot_color(p.first->get_colour());
dict[std_to_godot_string(p.first->get_identifier())] = sub_dict;
}
return dict;
}

Dictionary GameSingleton::get_province_info_from_index(int32_t index) const {
Province const* province = game_manager.map.get_province_by_index(index);
if (province == nullptr) return {};
Expand All @@ -257,6 +322,12 @@ Dictionary GameSingleton::get_province_info_from_index(int32_t index) const {

ret[get_province_info_life_rating_key()] = province->get_life_rating();
ret[get_province_info_total_population_key()] = province->get_total_population();
distribution_t const& pop_types = province->get_pop_type_distribution();
if (!pop_types.empty()) ret[get_province_info_pop_types_key()] = _distribution_to_dictionary(pop_types);
//distribution_t const& ideologies = province->get_ideology_distribution();
//if (!ideologies.empty()) ret[get_province_info_pop_ideologies_key()] = _distribution_to_dictionary(ideologies);
distribution_t const& cultures = province->get_culture_distribution();
if (!cultures.empty()) ret[get_province_info_pop_cultures_key()] = _distribution_to_dictionary(cultures);

std::vector<Building> const& buildings = province->get_buildings();
if (!buildings.empty()) {
Expand Down
18 changes: 16 additions & 2 deletions extension/src/GameSingleton.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,13 @@
#include "openvic/GameManager.hpp"

namespace OpenVic {
struct TerrainVariant : HasIdentifier, HasColour {
struct TerrainVariant : HasIdentifierAndColour {
friend class GameSingleton;

private:
const godot::Ref<godot::Image> image;

TerrainVariant(std::string const& new_identfier, colour_t new_colour,
TerrainVariant(const std::string_view new_identfier, colour_t new_colour,
godot::Ref<godot::Image> const& new_image);
public:
static constexpr size_t MAX_INDEX = 1 << (8 * sizeof(Map::terrain_t));
Expand Down Expand Up @@ -64,10 +64,18 @@ namespace OpenVic {
godot::Error _update_colour_image();
void _on_state_updated();

godot::Dictionary _distribution_to_dictionary(distribution_t const& dist) const;

protected:
static void _bind_methods();

public:
static void draw_pie_chart(godot::Ref<godot::Image> image,
godot::Array const& stopAngles, godot::Array const& colours, float radius,
godot::Vector2 shadow_displacement, float shadow_tightness, float shadow_radius, float shadow_thickness,
godot::Color trim_colour, float trim_size, float gradient_falloff, float gradient_base,
bool donut, bool donut_inner_trim, float donut_inner_radius);

static GameSingleton* get_singleton();

GameSingleton();
Expand Down Expand Up @@ -106,6 +114,9 @@ namespace OpenVic {
static godot::StringName const& get_province_info_region_key();
static godot::StringName const& get_province_info_life_rating_key();
static godot::StringName const& get_province_info_total_population_key();
static godot::StringName const& get_province_info_pop_types_key();
static godot::StringName const& get_province_info_pop_ideologies_key();
static godot::StringName const& get_province_info_pop_cultures_key();
static godot::StringName const& get_province_info_rgo_key();
static godot::StringName const& get_province_info_buildings_key();

Expand All @@ -116,6 +127,9 @@ namespace OpenVic {
static godot::StringName const& get_building_info_end_date_key();
static godot::StringName const& get_building_info_expansion_progress_key();

static godot::StringName const& get_piechart_info_size_key();
static godot::StringName const& get_piechart_info_colour_key();

/* Get info to display in Province Overview Panel, packaged in
* a Dictionary using the StringNames above as keys.
*/
Expand Down
80 changes: 40 additions & 40 deletions extension/src/LoadGameCompatibility.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,57 +17,57 @@ Error GameSingleton::_load_province_identifier_file_compatibility_mode(String co
Error err = FileAccess::get_open_error();
if (err != OK || file.is_null()) {
UtilityFunctions::push_error("Failed to load compatibility mode province identifier file: ", file_path);
return err == OK ? FAILED : err;
}

int line_number = 0;
while (!file->eof_reached()) {
const PackedStringArray line = file->get_csv_line(";");
line_number++;
if (err == OK) err = FAILED;
} else {
int line_number = 0;
while (!file->eof_reached()) {
const PackedStringArray line = file->get_csv_line(";");
line_number++;

if (line.is_empty() || (line.size() == 1 && line[0].is_empty()))
continue;
if (line.is_empty() || (line.size() == 1 && line[0].is_empty()))
continue;

if (line_number < 2) continue; // skip header line
index_t id = NULL_INDEX;
colour_t colour = NULL_COLOUR;
if (line.size() > 0) {
if (line[0].is_empty()) {
id = game_manager.map.get_province_count() + 1;
} else if (line[0].is_valid_int()) {
const int64_t val = line[0].to_int();
if (val > NULL_INDEX && val <= MAX_INDEX) id = val;
}
for (int i = 1; i < 4; ++i) {
if (line.size() > i) {
if (line[i].is_valid_int()) {
const int64_t int_val = line[i].to_int();
if (int_val >= NULL_COLOUR && int_val <= FULL_COLOUR) {
colour = (colour << 8) | int_val;
continue;
}
} else if (line[i].is_valid_float()) {
const double double_val = line[i].to_float();
if (std::trunc(double_val) == double_val) {
const int64_t int_val = double_val;
if (line_number < 2) continue; // skip header line
index_t id = NULL_INDEX;
colour_t colour = NULL_COLOUR;
if (line.size() > 0) {
if (line[0].is_empty()) {
id = game_manager.map.get_province_count() + 1;
} else if (line[0].is_valid_int()) {
const int64_t val = line[0].to_int();
if (val > NULL_INDEX && val <= MAX_INDEX) id = val;
}
for (int i = 1; i < 4; ++i) {
if (line.size() > i) {
if (line[i].is_valid_int()) {
const int64_t int_val = line[i].to_int();
if (int_val >= NULL_COLOUR && int_val <= FULL_COLOUR) {
colour = (colour << 8) | int_val;
continue;
}
} else if (line[i].is_valid_float()) {
const double double_val = line[i].to_float();
if (std::trunc(double_val) == double_val) {
const int64_t int_val = double_val;
if (int_val >= NULL_COLOUR && int_val <= FULL_COLOUR) {
colour = (colour << 8) | int_val;
continue;
}
}
}
}
colour = NULL_COLOUR;
break;
}
colour = NULL_COLOUR;
break;
}
if (id == NULL_INDEX || colour == NULL_COLOUR) {
UtilityFunctions::push_error("Invalid province ID-colour entry \"", line, "\" on line ", line_number, " in file: ", file_path);
err = FAILED;
continue;
}
static const std::string province_prefix = "PROV";
if (game_manager.map.add_province(province_prefix + std::to_string(id), colour) != SUCCESS) err = FAILED;
}
if (id == NULL_INDEX || colour == NULL_COLOUR) {
UtilityFunctions::push_error("Invalid province ID-colour entry \"", line, "\" on line ", line_number, " in file: ", file_path);
err = FAILED;
continue;
}
static const std::string province_prefix = "PROV";
if (game_manager.map.add_province(province_prefix + std::to_string(id), colour) != SUCCESS) err = FAILED;
}
game_manager.map.lock_provinces();
return err;
Expand Down
12 changes: 8 additions & 4 deletions extension/src/LoadGameOpenVic.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,11 @@ Error GameSingleton::_parse_region_entry(String const& identifier, Variant const
UtilityFunctions::push_error("Invalid province list for region \"", identifier, "\": ", entry);
return FAILED;
}
return ERR(game_manager.map.add_region(godot_to_std_string(identifier), province_identifiers));
std::vector<std::string_view> province_identifier_views;
for (std::string const& str : province_identifiers) {
province_identifier_views.push_back(str);
}
return ERR(game_manager.map.add_region(godot_to_std_string(identifier), province_identifier_views));
}

Error GameSingleton::_load_region_file(String const& file_path) {
Expand Down Expand Up @@ -271,7 +275,7 @@ Error GameSingleton::_load_map_images(String const& province_image_path, String

// Generate interleaved province and terrain ID image
if (game_manager.map.generate_province_shape_image(province_dims.x, province_dims.y, province_image->get_data().ptr(),
terrain_image->get_data().ptr(), terrain_variant_map) != SUCCESS) err = FAILED;
terrain_image->get_data().ptr(), terrain_variant_map, true) != SUCCESS) 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
Expand Down Expand Up @@ -364,8 +368,8 @@ Error GameSingleton::_parse_good_entry(String const& identifier, Variant const&
if (var_overseas_maintenance.get_type() == Variant::BOOL) overseas_maintenance = var_overseas_maintenance;
else UtilityFunctions::push_error("Invalid good overseas maintenance bool value for ", identifier, ": ", var_overseas_maintenance);

return ERR(game_manager.good_manager.add_good(godot_to_std_string(identifier), godot_to_std_string(category),
colour, base_price, default_available, tradeable, currency, overseas_maintenance));
return ERR(game_manager.good_manager.add_good(godot_to_std_string(identifier), colour, godot_to_std_string(category),
base_price, default_available, tradeable, currency, overseas_maintenance));
}

Error GameSingleton::_load_goods(String const& defines_path, String const& icons_dir_path) {
Expand Down
Loading