3#include <glm/gtx/intersect.hpp>
4#include <glm/gtx/polar_coordinates.hpp>
5#include <glm/gtc/constants.hpp>
6#include <glm/gtx/transform.hpp>
44 glm::vec2 offset = glm::vec2(glm::mod(
pos.x, 1.f) - 0.5f,
pos.y - 0.5f);
50 auto pt = state.world.province_get_port_to(p);
54 auto adj = state.world.get_province_adjacency_by_province_pair(p, pt);
56 auto id = adj.index();
57 auto& map_data = state.map_state.map_data;
58 auto&
border = map_data.borders[id];
60 glm::vec2 map_size = glm::vec2(map_data.size_x, map_data.size_y);
62 return vertex.position * map_size;
66 return prov_id.index() >= state.province_definitions.first_sea_province.index();
71 return state.world.province_get_mid_point(prov_id);
77 return state.world.province_get_mid_point(prov_id);
85 auto cid = state.selected_trade_good;
97 state.world.for_each_trade_route([&](dcon::trade_route_id trade_route) {
98 auto current_volume = std::abs(state.world.trade_route_get_volume(trade_route, cid));
99 if(current_volume > 0.f) {
100 total = total + current_volume;
105 auto average = total / (count + 1);
107 state.world.for_each_trade_route([&](dcon::trade_route_id trade_route) {
108 auto current_volume = state.world.trade_route_get_volume(trade_route, cid);
111 ? state.world.trade_route_get_connected_markets(trade_route, 0)
112 : state.world.trade_route_get_connected_markets(trade_route, 1);
114 current_volume <= 0.f
115 ? state.world.trade_route_get_connected_markets(trade_route, 0)
116 : state.world.trade_route_get_connected_markets(trade_route, 1);
118 auto s_origin = state.world.market_get_zone_from_local_market(origin);
119 auto s_target = state.world.market_get_zone_from_local_market(target);
121 auto p_origin = state.world.state_instance_get_capital(s_origin);
122 auto p_target = state.world.state_instance_get_capital(s_target);
124 auto sat = state.world.market_get_direct_demand_satisfaction(origin, cid);
126 auto absolute_volume = std::abs(sat * current_volume);
129 auto selected_province = state.map_state.get_selected_province();
131 if (absolute_volume >= std::clamp(average, 0.001f, 5.f)) {
135 else if(selected_province) {
136 auto selected_province_state = state.world.province_get_state_membership(selected_province);
138 if(absolute_volume <= 0.001f) {
142 if(selected_province_state.id != s_origin && selected_province_state.id != s_target) {
150 auto width = std::log(1.f + absolute_volume * 100.f) * 300.f;
155 bool is_sea = state.world.trade_route_get_distance(trade_route) == state.world.trade_route_get_sea_distance(trade_route);
161 if(coast_origin != p_origin) {
165 p_origin, coast_origin,
174 coast_origin, coast_target,
177 std::sin((
float)(trade_route.value)) * 50.f,
178 std::cos((
float)(trade_route.value)) * 50.f
181 if(coast_target != p_target) {
185 coast_target, p_target,
241 for(
auto selected_army : state.selected_armies) {
242 if(
auto ps = state.world.army_get_path(selected_army); ps.size() > 0) {
243 auto dest_controller = state.world.province_get_nation_from_province_control(ps[0]);
244 if(state.world.army_get_black_flag(selected_army) || state.world.army_get_is_retreating(selected_army)) {
249 }
else if(state.world.army_get_is_ai_controlled(selected_army)) {
250 if(state.local_player_nation && dest_controller &&
military::are_at_war(state, dest_controller, state.local_player_nation)) {
261 }
else if(state.local_player_nation && dest_controller &&
military::are_at_war(state, dest_controller, state.local_player_nation)) {
274 for(
auto selected_navy : state.selected_navies) {
275 if(state.world.navy_get_is_retreating(selected_navy)) {
288 for(
auto map_army : state.world.in_army) {
289 if(!state.world.army_is_valid(map_army)) {
294 auto pc = map_army.get_army_location().get_location().id;
300 if(map_army.get_battle_from_army_battle_participation()) {
304 if(std::find(state.selected_armies.begin(), state.selected_armies.end(), map_army) != state.selected_armies.end()) {
308 if(
auto ps = state.world.army_get_path(map_army); ps.size() > 0) {
309 auto army_controller = state.world.army_get_controller_from_army_control(map_army);
310 if(state.local_player_nation && army_controller &&
military::are_at_war(state, army_controller, state.local_player_nation)) {
311 if(state.world.army_get_is_retreating(map_army)) {
323 else if (state.local_player_nation == army_controller) {
331 for(
auto map_navy : state.world.in_navy) {
332 if(!state.world.navy_is_valid(map_navy)) {
337 auto pc = map_navy.get_navy_location().get_location().id;
343 if(map_navy.get_battle_from_navy_battle_participation()) {
347 if(std::find(state.selected_navies.begin(), state.selected_navies.end(), map_navy) != state.selected_navies.end()) {
351 if(
auto ps = state.world.navy_get_path(map_navy); ps.size() > 0) {
352 auto navy_controller = state.world.navy_get_controller_from_navy_control(map_navy);
354 if(state.world.navy_get_is_retreating(map_navy)) {
365 }
else if (state.local_player_nation == navy_controller) {
398 glBindBuffer(GL_ARRAY_BUFFER, 0);
402 if(p.x <= bbox[1].x) {
404 }
if(p.y <= bbox[2].y) {
406 }
if(p.x >= bbox[3].x) {
408 }
if(p.y >= bbox[4].y) {
414 if(p.x <= bbox[1].x) {
416 }
if(p.y <= bbox[2].y) {
418 }
if(p.x >= bbox[3].x) {
420 }
if(p.y >= bbox[4].y) {
439 auto olr = state.world.nation_get_overlord_as_subject(n);
440 auto ol = state.world.overlord_get_ruler(olr);
443 while(ol && state.world.nation_get_owned_province_count(ol) > 0) {
444 olr = state.world.nation_get_overlord_as_subject(ol);
446 ol = state.world.overlord_get_ruler(olr);
456 std::vector<text_line_generator_data> text_data;
457 std::vector<bool> visited(65536,
false);
458 std::vector<bool> visited_sea_provinces(65536,
false);
459 std::vector<bool> friendly_sea_provinces(65536,
false);
460 std::vector<uint16_t> group_of_regions;
462 std::unordered_map<uint16_t, std::set<uint16_t>> regions_graph;
466 float step_x = float(map_data.
size_x) / float(samples_N);
467 float step_y = float(map_data.
size_y) / float(samples_M);
486 for(
auto candidate : state.world.in_province) {
487 auto rid = candidate.get_connected_region_id();
489 auto nation =
get_top_overlord(state, state.world.province_get_nation_from_province_ownership(candidate));
491 for(
auto adj : candidate.get_province_adjacency()) {
492 auto indx = adj.get_connected_provinces(0) != candidate.id ? 0 : 1;
493 auto neighbor = adj.get_connected_provinces(indx);
496 if(neighbor.id.index() >= state.province_definitions.first_sea_province.index()) {
497 for(
auto adj_of_neighbor : neighbor.get_province_adjacency()) {
498 auto indx2 = adj_of_neighbor.get_connected_provinces(0) != neighbor.id ? 0 : 1;
499 auto neighbor_of_neighbor = adj_of_neighbor.get_connected_provinces(indx2);
502 glm::vec2 point_candidate = candidate.get_mid_point();
503 glm::vec2 point_potential_friend = neighbor_of_neighbor.get_mid_point();
505 if(glm::distance(point_candidate, point_potential_friend) > map_data.
size_x * 0.5f) {
507 }
else if(neighbor_of_neighbor.id.index() < state.province_definitions.first_sea_province.index()) {
508 auto nation_2 =
get_top_overlord(state, state.world.province_get_nation_from_province_ownership(neighbor_of_neighbor));
509 if(nation == nation_2)
510 regions_graph[rid].insert(neighbor_of_neighbor.get_connected_region_id());
514 auto nation_2 =
get_top_overlord(state, state.world.province_get_nation_from_province_ownership(neighbor));
515 if(nation == nation_2)
516 regions_graph[rid].insert(neighbor.get_connected_region_id());
520 for(
auto p : state.world.in_province) {
521 if(p.id.index() >= state.province_definitions.first_sea_province.index())
523 auto rid = p.get_connected_region_id();
524 if(visited[uint16_t(rid)])
526 visited[uint16_t(rid)] =
true;
528 auto n = p.get_nation_from_province_ownership();
532 group_of_regions.clear();
533 group_of_regions.push_back(rid);
535 int vacant_index = 1;
536 while(first_index < vacant_index) {
537 auto current_region = group_of_regions[first_index];
539 for(
auto neighbour_region : regions_graph[current_region]) {
540 if(!visited[neighbour_region]) {
541 group_of_regions.push_back(neighbour_region);
542 visited[neighbour_region] =
true;
547 if(!n || n.get_owned_province_count() == 0)
552 if(nation_name.starts_with(prefix_remove)) {
553 nation_name.erase(0, prefix_remove.size());
556 if(acronym_expand.size() > 0 && nation_name.starts_with(acronym_expand)) {
557 nation_name.erase(0, acronym_expand.size());
559 nation_name.insert(0, acronym_expand_to.data(), acronym_expand_to.size());
562 std::string name = nation_name;
563 bool connected_to_capital =
false;
564 for(
auto visited_region : group_of_regions) {
565 if(n.get_capital().get_connected_region_id() == visited_region) {
566 connected_to_capital =
true;
575 if(!connected_to_capital) {
580 ankerl::unordered_dense::map<int32_t, uint32_t>
map;
582 dcon::province_id last_province;
583 bool in_same_state =
true;
584 for(
auto visited_region : group_of_regions) {
585 for(
auto candidate : state.world.in_province) {
586 if(candidate.get_connected_region_id() == visited_region) {
587 if(candidate.get_state_membership() != p.get_state_membership())
588 in_same_state =
false;
590 for(
const auto core : candidate.get_core_as_province()) {
592 if(
auto const it =
map.find(core.get_identity().id.index()); it !=
map.end()) {
595 map.insert_or_assign(core.get_identity().id.index(), v);
600 if(in_same_state ==
true) {
603 if(total_provinces <= 2) {
607 for(
const auto& e :
map) {
608 if(
float(e.second) /
float(total_provinces) >= 0.75f) {
610 auto const nid = dcon::national_identity_id(dcon::national_identity_id::value_base_t(e.first));
611 if(
auto k = state.world.national_identity_get_name(nid); state.key_is_localized(k)) {
612 if(nid == n.get_primary_culture().get_group_from_culture_group_membership().get_identity_from_cultural_union_of()
613 || nid == n.get_identity_from_identity_holder()) {
614 if(n.get_capital().get_continent() == p.get_continent()) {
618 auto p1 = n.get_capital().get_mid_point();
619 auto p2 = p.get_mid_point();
620 auto radians = glm::atan(p1.y - p2.y, p2.x - p1.x);
621 auto degrees = std::fmod(glm::degrees(radians) + 45.f, 360.f);
623 degrees = 360.f + degrees;
625 assert(degrees >= 0.f && degrees <= 360.f);
628 if(degrees >= 0.f && degrees < 90.f) {
630 }
else if(degrees >= 90.f && degrees < 180.f) {
632 }
else if(degrees >= 180.f && degrees < 270.f) {
634 }
else if(degrees >= 270.f && degrees < 360.f) {
653 float rough_box_left = std::numeric_limits<float>::max();
654 float rough_box_right = 0;
655 float rough_box_bottom = std::numeric_limits<float>::max();
656 float rough_box_top = 0;
658 for(
auto visited_region : group_of_regions) {
659 for(
auto candidate : state.world.in_province) {
660 if(candidate.get_connected_region_id() == visited_region) {
661 glm::vec2 mid_point = candidate.get_mid_point();
663 if(mid_point.x < rough_box_left) {
664 rough_box_left = mid_point.x;
666 if(mid_point.x > rough_box_right) {
667 rough_box_right = mid_point.x;
669 if(mid_point.y < rough_box_bottom) {
670 rough_box_bottom = mid_point.y;
672 if(mid_point.y > rough_box_top) {
673 rough_box_top = mid_point.y;
679 if(rough_box_right - rough_box_left > map_data.
size_x * 0.9f) {
684 std::vector<glm::vec2> points;
685 std::vector<glm::vec2> bad_points;
687 rough_box_bottom = std::max(0.f, rough_box_bottom - step_y);
688 rough_box_top = std::min(
float(map_data.
size_y), rough_box_top + step_y);
689 rough_box_left = std::max(0.f, rough_box_left - step_x);
690 rough_box_right = std::min(
float(map_data.
size_x), rough_box_right + step_x);
692 float rough_box_width = rough_box_right - rough_box_left;
693 float rough_box_height = rough_box_top - rough_box_bottom;
695 float rough_box_ratio = rough_box_width / rough_box_height;
696 float height_steps = 15.f;
697 float width_steps = std::max(10.f, height_steps * rough_box_ratio);
699 glm::vec2 local_step = glm::vec2(rough_box_width, rough_box_height) / glm::vec2(width_steps, height_steps);
703 float counter_from_the_bottom = 0.f;
704 float best_y_length_real = 0.f;
705 float best_y_left_x = 0.f;
708 for(
int j = 0; j < height_steps; j++) {
709 float y = rough_box_bottom + j * local_step.y;
711 for(
int i = 0; i < width_steps; i++) {
712 float x = rough_box_left + float(i) * local_step.x;
713 glm::vec2 candidate = { x, y };
714 auto idx = int32_t(y) * int32_t(map_data.
size_x) + int32_t(x);
717 for(
auto visited_region : group_of_regions) {
718 if(fat_id.get_connected_region_id() == visited_region) {
719 points.push_back(candidate);
726 float points_above = 0.f;
728 for(
int j = 0; j < height_steps; j++) {
729 float y = rough_box_bottom + j * local_step.y;
731 float current_length = 0.f;
732 float left_x = (float)(map_data.
size_x);
734 for(
int i = 0; i < width_steps; i++) {
735 float x = rough_box_left + float(i) * local_step.x;
737 glm::vec2 candidate = { x, y };
739 auto idx = int32_t(y) * int32_t(map_data.
size_x) + int32_t(x);
742 for(
auto visited_region : group_of_regions)
743 if(fat_id.get_connected_region_id() == visited_region) {
745 current_length += local_step.x;
753 if(points_above * 2.f > points.size()) {
755 best_y_length_real = current_length;
757 best_y_left_x = left_x;
762 if(points.size() < 2) {
767 size_t min_amount = 2;
774 size_t num_of_clusters = std::max(min_amount, (
size_t)(points.size() / 40));
775 size_t neighbours_requirement = std::clamp(
int(std::log(num_of_clusters + 1)), 1, 3);
777 if(points.size() < num_of_clusters) {
778 num_of_clusters = points.size();
781 std::vector<glm::vec2> centroids;
783 for(
size_t i = 0; i < num_of_clusters; i++) {
784 centroids.push_back(points[i]);
787 for(
int step = 0; step < 100; step++) {
788 std::vector<glm::vec2> new_centroids;
789 std::vector<int> counters;
790 for(
size_t i = 0; i < num_of_clusters; i++) {
791 new_centroids.push_back(glm::vec2(0, 0));
792 counters.push_back(0);
796 for(
size_t i = 0; i < points.size(); i++) {
798 float best_dist = std::numeric_limits<float>::max();
801 for(
size_t cluster = 0; cluster < num_of_clusters; cluster++) {
802 if(best_dist > glm::distance(centroids[cluster], points[i])) {
804 best_dist = glm::distance(centroids[cluster], points[i]);
808 new_centroids[closest] += points[i];
809 counters[closest] += 1;
812 for(
size_t i = 0; i < num_of_clusters; i++) {
813 new_centroids[i] /= counters[i];
816 centroids = new_centroids;
819 std::vector<size_t> good_centroids;
822 std::vector<glm::vec2> final_points;
824 for(
size_t i = 0; i < num_of_clusters; i++) {
825 float locally_good_distance = std::numeric_limits<float>::max();
826 for(
size_t j = 0; j < num_of_clusters; j++) {
828 if(locally_good_distance > glm::distance(centroids[i], centroids[j]))
829 locally_good_distance = glm::distance(centroids[i], centroids[j]);
832 size_t counter_of_neighbors = 0;
833 for(
size_t j = 0; j < num_of_clusters; j++) {
837 if(glm::distance(centroids[i], centroids[j]) < locally_good_distance * 1.2f) {
838 counter_of_neighbors++;
841 if(counter_of_neighbors >= neighbours_requirement) {
842 good_centroids.push_back(i);
843 final_points.push_back(centroids[i]);
848 if(good_centroids.size() <= 1) {
849 good_centroids.clear();
850 final_points.clear();
851 for(
size_t i = 0; i < num_of_clusters; i++) {
852 good_centroids.push_back(i);
853 final_points.push_back(centroids[i]);
859 std::vector<glm::vec2> good_points;
861 glm::vec2 sum_points = { 0.f, 0.f };
865 for(
auto point : points) {
867 float best_dist = std::numeric_limits<float>::max();
870 for(
size_t cluster = 0; cluster < num_of_clusters; cluster++) {
871 if(best_dist > glm::distance(centroids[cluster], point)) {
873 best_dist = glm::distance(centroids[cluster], point);
878 bool is_good =
false;
879 for(
size_t i = 0; i < good_centroids.size(); i++) {
880 if(closest == good_centroids[i])
885 good_points.push_back(point);
890 points = good_points;
894 glm::vec2 center = sum_points / (float)(points.size());
899 for(
auto point : points) {
900 auto dif_v = point - center;
901 total_sum += dif_v.x * dif_v.x;
904 float mse = total_sum / points.size();
906 float limit = mse * 3;
915 for(
auto point: points) {
917 glm::vec2 current = point - center;
918 if((current.x > right) && (current.x * current.x < limit)) {
921 if(current.y > top) {
924 if((current.x < left) && (current.x * current.x < limit)) {
927 if(current.y < bottom) {
932 std::vector<glm::vec2> key_points;
934 key_points.push_back(center + glm::vec2(left, 0));
935 key_points.push_back(center + glm::vec2(0, bottom + local_step.y));
936 key_points.push_back(center + glm::vec2(right, 0));
937 key_points.push_back(center + glm::vec2(0, top - local_step.y));
939 std::array<glm::vec2, 5> key_provs{
947 for(
auto key_point : key_points) {
953 glm::vec2 map_size{ float(state.map_state.map_data.size_x), float(state.map_state.map_data.size_y) };
954 glm::vec2 basis{ key_provs[1].x, key_provs[2].y };
955 glm::vec2 ratio{ key_provs[3].x - key_provs[1].x, key_provs[4].y - key_provs[2].y };
957 if(ratio.x < 0.001f || ratio.y < 0.001f)
960 points = final_points;
963 float lambda = 0.00001f;
971 std::vector<float> out_y;
972 std::vector<float> out_x;
973 std::vector<float> w;
974 std::vector<std::array<float, 4>> in_x;
975 std::vector<std::array<float, 4>> in_y;
977 for (
auto point : points) {
983 if(e.x > basis.x + ratio.x) {
991 out_y.push_back(e.y);
992 out_x.push_back(e.x);
995 in_x.push_back(std::array<float, 4>{ l_0 * 1.f, l_1* e.x, l_1* e.x* e.x, l_3* e.x* e.x* e.x});
996 in_y.push_back(std::array<float, 4>{ l_0 * 1.f, l_1* e.y, l_1* e.y* e.y, l_3* e.y* e.y* e.y});
1000 float name_extent = f.text_extent(state, prepared_name, 0,
uint32_t(prepared_name.glyph_info.size()), 1);
1002 bool use_quadratic =
false;
1018 glm::mat4x4 m0(0.f);
1019 for(glm::length_t i = 0; i < m0.length(); i++)
1020 for(glm::length_t j = 0; j < m0.length(); j++)
1021 for(glm::length_t r = 0; r < glm::length_t(in_x.size()); r++)
1022 m0[i][j] += in_x[r][j] * w[r] * in_x[r][i] / in_x.size();
1023 for(glm::length_t i = 0; i < m0.length(); i++)
1025 m0 = glm::inverse(m0);
1027 for(glm::length_t i = 0; i < m1.length(); i++)
1028 for(glm::length_t r = 0; r < glm::length_t(in_x.size()); r++)
1029 m1[i] += in_x[r][i] * w[r] * out_y[r] / in_x.size();
1031 for(glm::length_t i = 0; i < mo.length(); i++)
1032 for(glm::length_t j = 0; j < mo.length(); j++)
1033 mo[i] += m0[i][j] * m1[j];
1036 auto poly_fn = [&](
float x) {
1037 return mo[0] * l_0 + mo[1] * x * l_1 + mo[2] * x * x * l_2 + mo[3] * x * x * x * l_3;
1039 auto dx_fn = [&](
float x) {
1040 return mo[1] * l_1 + 2.f * mo[2] * x * l_2 + 3.f * mo[3] * x * x * l_3;
1042 auto error_grad = [&](
float x,
float y) {
1043 float error_linear = poly_fn(x) - y;
1044 return glm::vec4(error_linear * error_linear * error_linear * error_linear * error_linear * mo);
1047 auto regularisation_grad = [&]() {
1048 return glm::vec4(0, 0, mo[2] / 4.f, mo[3] / 6.f);
1051 float xstep = (1.f / float(name_extent * 2.f));
1052 for(
float x = 0.f; x <= 1.f; x += xstep) {
1053 float y = poly_fn(x);
1054 if(y < 0.f || y > 1.f) {
1055 use_quadratic =
true;
1059 float dx = glm::abs(dx_fn(x) - dx_fn(x - xstep));
1060 if(dx / xstep >= 0.45f) {
1061 use_quadratic =
true;
1067 text_data.emplace_back(std::move(prepared_name), mo, basis, ratio);
1070 bool use_linear =
false;
1073 glm::mat3x3 m0(0.f);
1074 for(glm::length_t i = 0; i < m0.length(); i++)
1075 for(glm::length_t j = 0; j < m0.length(); j++)
1076 for(glm::length_t r = 0; r < glm::length_t(in_x.size()); r++)
1077 m0[i][j] += in_x[r][j] * w[r] * in_x[r][i] / in_x.size();
1078 for(glm::length_t i = 0; i < m0.length(); i++)
1080 m0 = glm::inverse(m0);
1082 for(glm::length_t i = 0; i < m1.length(); i++)
1083 for(glm::length_t r = 0; r < glm::length_t(in_x.size()); r++)
1084 m1[i] += in_x[r][i] * w[r] * out_y[r] / in_x.size();
1086 for(glm::length_t i = 0; i < mo.length(); i++)
1087 for(glm::length_t j = 0; j < mo.length(); j++)
1088 mo[i] += m0[i][j] * m1[j];
1091 auto poly_fn = [&](
float x) {
1092 return mo[0] * l_0 + mo[1] * x * l_1 + mo[2] * x * x * l_2;
1094 auto dx_fn = [&](
float x) {
1095 return mo[1] * l_1 + 2.f * mo[2] * x * l_2;
1097 float xstep = (1.f / float(name_extent * 2.f));
1098 for(
float x = 0.f; x <= 1.f; x += xstep) {
1099 float y = poly_fn(x);
1100 if(y < 0.f || y > 1.f) {
1105 float dx = glm::abs(dx_fn(x) - dx_fn(x - xstep));
1106 if(dx / xstep >= 0.45f) {
1112 text_data.emplace_back(std::move(prepared_name), glm::vec4(mo, 0.f), basis, ratio);
1117 glm::mat2x2 m0(0.f);
1118 for(glm::length_t i = 0; i < m0.length(); i++)
1119 for(glm::length_t j = 0; j < m0.length(); j++)
1120 for(glm::length_t r = 0; r < glm::length_t(in_x.size()); r++)
1121 m0[i][j] += in_x[r][j] * w[r] * in_x[r][i];
1122 for(glm::length_t i = 0; i < m0.length(); i++)
1124 m0 = glm::inverse(m0);
1126 for(glm::length_t i = 0; i < m1.length(); i++)
1127 for(glm::length_t r = 0; r < glm::length_t(in_x.size()); r++)
1128 m1[i] += in_x[r][i] * w[r] * out_y[r];
1130 for(glm::length_t i = 0; i < mo.length(); i++)
1131 for(glm::length_t j = 0; j < mo.length(); j++)
1132 mo[i] += m0[i][j] * m1[j];
1136 auto poly_fn = [&](
float x) {
1137 return mo[0] * l_0 + mo[1] * x * l_1;
1144 if(abs(mo[1]) > 0.05) {
1146 float left_side = 0.f;
1147 float right_side = 1.f;
1150 left_side = -mo[0] / mo[1];
1151 right_side = (1.f - mo[0]) / mo[1];
1152 }
else if(mo[1] < -0.01f) {
1153 left_side = (1.f - mo[0]) / mo[1];
1154 right_side = -mo[0] / mo[1];
1157 left_side = std::clamp(left_side, 0.f, 1.f);
1158 right_side = std::clamp(right_side, 0.f, 1.f);
1160 float length_in_box_units = glm::length(ratio * glm::vec2(poly_fn(left_side), poly_fn(right_side)));
1162 if(best_y_length_real * 1.05f >= length_in_box_units) {
1163 basis.x = best_y_left_x;
1164 ratio.x = best_y_length_real;
1165 mo[0] = (best_y - basis.y) / ratio.y;
1171 if(ratio.x <= map_size.x * 0.75f && ratio.y <= map_size.y * 0.75f)
1172 text_data.emplace_back(std::move(prepared_name), glm::vec4(mo, 0.f, 0.f), basis, ratio);
1177 if(state.cheat_data.province_names) {
1178 std::vector<text_line_generator_data> p_text_data;
1179 for(
auto p : state.world.in_province) {
1182 p_text_data.emplace_back(
text::stored_glyphs(state,
text::font_selection::map_font, name), glm::vec4(0.f, 0.f, 0.f, 0.f), p.get_mid_point() - glm::vec2(5.f, 0.f), glm::vec2(10.f, 10.f));
1190 std::chrono::time_point<std::chrono::steady_clock> now = std::chrono::steady_clock::now();
1192 if(
last_update_time == std::chrono::time_point<std::chrono::steady_clock>{})
1195 if(state.selected_trade_good && state.update_trade_flow.load(std::memory_order::acquire)) {
1197 state.update_trade_flow.store(
false, std::memory_order_release);
1202 if(state.user_settings.railroads_enabled && state.railroad_built.load(std::memory_order::acquire)) {
1203 state.map_state.map_data.update_railroad_paths(state);
1204 state.railroad_built.store(
false, std::memory_order::release);
1207 auto microseconds_since_last_update = std::chrono::duration_cast<std::chrono::microseconds>(now -
last_update_time);
1208 float seconds_since_last_update = (float)(microseconds_since_last_update.count() / 1e6);
1215 glm::vec2 arrow_key_velocity_vector{};
1217 arrow_key_velocity_vector.x -= 1.f;
1220 arrow_key_velocity_vector.x += 1.f;
1223 arrow_key_velocity_vector.y -= 1.f;
1226 arrow_key_velocity_vector.y += 1.f;
1228 arrow_key_velocity_vector = glm::normalize(arrow_key_velocity_vector);
1229 arrow_key_velocity_vector *= 0.175f;
1231 arrow_key_velocity_vector *= glm::e<float>();
1235 if(state.user_settings.mouse_edge_scrolling) {
1236 glm::vec2 mouse_pos_percent{ state.mouse_x_position / float(state.x_size), state.mouse_y_position / float(state.y_size) };
1237 glm::vec2 cursor_velocity_vector{ 0.0f, 0.0f };
1240 if(mouse_pos_percent.x < 0.02f) {
1241 cursor_velocity_vector.x -= 1.f;
1242 }
else if(mouse_pos_percent.x > 0.98f) {
1243 cursor_velocity_vector.x += 1.f;
1245 if(mouse_pos_percent.y < 0.02f) {
1246 cursor_velocity_vector.y -= 1.f;
1247 }
else if(mouse_pos_percent.y > 0.98f) {
1248 cursor_velocity_vector.y += 1.f;
1252 if(glm::length(cursor_velocity_vector) != 0.0f) {
1253 cursor_velocity_vector = glm::normalize(cursor_velocity_vector);
1254 cursor_velocity_vector *= 0.175f;
1265 pos.x = glm::mod(
pos.x, 1.f);
1266 pos.y = glm::clamp(
pos.y, 0.f, 1.f);
1268 glm::vec2 mouse_pos{ state.mouse_x_position, state.mouse_y_position };
1269 glm::vec2 screen_size{ state.x_size, state.y_size };
1270 glm::vec2 screen_center = screen_size / 2.f;
1272 glm::vec2 pos_before_zoom;
1273 bool valid_pos =
screen_to_map(mouse_pos, screen_size, view_mode, pos_before_zoom);
1275 auto zoom_diff = (
zoom_change * seconds_since_last_update) / (1 /
zoom);
1277 zoom_change *= std::exp(-seconds_since_last_update * state.user_settings.zoom_speed);
1280 glm::vec2 pos_after_zoom;
1281 if(valid_pos &&
screen_to_map(mouse_pos, screen_size, view_mode, pos_after_zoom)) {
1282 switch(state.user_settings.zoom_mode) {
1284 pos += pos_before_zoom - pos_after_zoom;
1287 pos -= pos_before_zoom - pos_after_zoom;
1291 pos -= pos_before_zoom - pos_after_zoom;
1293 pos += pos_before_zoom - pos_after_zoom;
1298 pos += pos_before_zoom - pos_after_zoom;
1300 pos -= pos_before_zoom - pos_after_zoom;
1311 static float keyboard_zoom_change = 0.f;
1313 keyboard_zoom_change += 0.1f;
1316 keyboard_zoom_change -= 0.1f;
1319 glm::vec2 pos_before_keyboard_zoom;
1320 valid_pos =
screen_to_map(screen_center, screen_size, view_mode, pos_before_keyboard_zoom);
1322 auto keyboard_zoom_diff = (keyboard_zoom_change * seconds_since_last_update) / (1 /
zoom);
1323 zoom += keyboard_zoom_diff;
1324 keyboard_zoom_change *= std::exp(-seconds_since_last_update * state.user_settings.zoom_speed);
1327 glm::vec2 pos_after_keyboard_zoom;
1328 if(valid_pos &&
screen_to_map(screen_center, screen_size, view_mode, pos_after_keyboard_zoom)) {
1329 pos += pos_before_keyboard_zoom - pos_after_keyboard_zoom;
1333 globe_rotation = glm::rotate(glm::mat4(1.f), (0.25f -
pos.x) * 2 * glm::pi<float>(), glm::vec3(0, 0, 1));
1335 glm::vec3 axis = glm::vec3(
globe_rotation * glm::vec4(1, 0, 0, 0));
1337 axis = glm::normalize(axis);
1344 state.update_trade_flow.store(
true, std::memory_order::release);
1417 pos.x = glm::mod(new_pos.x, 1.f);
1418 pos.y = glm::clamp(new_pos.y, 0.f, 1.0f);
1425 auto map_pos = state.world.province_get_mid_point(p);
1428 map_pos.y = 1.0f - map_pos.y;
1434 constexpr auto zoom_speed_factor = 15.f;
1440 auto mouse_pos = glm::vec2(x, y);
1441 auto screen_size = glm::vec2(screen_size_x, screen_size_y);
1449 if((mouse_diff.x > std::ceil(screen_size_x * 0.0025f) || mouse_diff.y > std::ceil(screen_size_y * 0.0025f))
1453 auto pos2 = mouse_pos / screen_size;
1454 auto pixel_size = glm::vec2(1) / screen_size;
1463 screen_pos -= screen_size * 0.5f;
1464 screen_pos /= screen_size;
1465 screen_pos.x *= screen_size.x / screen_size.y;
1467 float cursor_radius = glm::length(screen_pos);
1468 glm::vec3 cursor_pos = glm::vec3(screen_pos.x, -10 *
zoom, -screen_pos.y);
1469 glm::vec3 cursor_direction = glm::vec3(0, 1, 0);
1470 glm::vec3 sphere_center = glm::vec3(0, 0, 0);
1471 float sphere_radius =
zoom / glm::pi<float>();
1473 glm::vec3 intersection_pos;
1474 glm::vec3 intersection_normal;
1476 if(glm::intersectRaySphere(cursor_pos, cursor_direction, sphere_center, sphere_radius, intersection_pos,
1477 intersection_normal)) {
1478 intersection_pos = glm::mat3(glm::inverse(
globe_rotation)) * intersection_pos;
1479 float theta = std::acos(std::clamp(intersection_pos.z / glm::length(intersection_pos), -1.f, 1.f));
1480 float phi = std::atan2(intersection_pos.y, intersection_pos.x);
1481 float pi = glm::pi<float>();
1482 map_pos = glm::vec2((phi / (2 * pi)) + 0.5f, theta / pi);
1487 float aspect_ratio = screen_size.x / screen_size.y;
1488 float pi = glm::pi<float>();
1491 screen_pos -= screen_size * 0.5f;
1492 screen_pos /= -screen_size;
1495 float near_plane = 0.1f;
1496 float far_plane = 1.2f;
1497 float right = near_plane * tan(pi / 6.f) /
zoom * aspect_ratio * 2.f;
1498 float top = near_plane * tan(pi / 6.f) /
zoom * 2.f;
1501 screen_pos.x *= right;
1502 screen_pos.y *= top;
1505 float cursor_radius = glm::length(screen_pos);
1506 glm::vec3 camera = glm::vec3(0.f, 0.f, 0.f);
1507 glm::vec3 cursor_pos = glm::vec3(screen_pos.x, screen_pos.y, -near_plane);
1508 glm::vec3 cursor_direction = glm::normalize(cursor_pos);
1509 glm::vec3 sphere_center = glm::vec3(0.f, 0.f, -1.2f);
1510 float sphere_radius = 1.f / pi;
1513 glm::vec3 intersection_pos;
1514 glm::vec3 intersection_normal;
1516 if(glm::intersectRaySphere(camera, cursor_direction, sphere_center, sphere_radius, intersection_pos,
1517 intersection_normal)) {
1518 intersection_pos -= sphere_center;
1520 intersection_pos = glm::vec3(-intersection_pos.x, -intersection_pos.z, intersection_pos.y);
1522 intersection_pos = glm::mat3(glm::inverse(
globe_rotation)) * intersection_pos;
1523 float theta = std::acos(std::clamp(intersection_pos.z / glm::length(intersection_pos), -1.f, 1.f));
1524 float phi = std::atan2(intersection_pos.y, intersection_pos.x);
1525 map_pos = glm::vec2((phi / (2.f * pi)) + 0.5f, theta / pi);
1530 screen_pos -= screen_size * 0.5f;
1531 screen_pos /= screen_size;
1532 screen_pos.x *= screen_size.x / screen_size.y;
1537 map_pos = screen_pos;
1543 auto mouse_pos = glm::vec2(x, y);
1544 auto screen_size = glm::vec2(screen_size_x, screen_size_y);
1569 auto mouse_pos = glm::vec2(x, y);
1571 if(mouse_diff.x <= std::ceil(screen_size_x * 0.0025f) && mouse_diff.y <= std::ceil(screen_size_y * 0.0025f)) {
1572 auto screen_size = glm::vec2(screen_size_x, screen_size_y);
1581 state.user_settings.interface_volume * state.user_settings.master_volume);
1598 auto mouse_pos = glm::vec2(x, y);
1599 auto screen_size = glm::vec2(screen_size_x, screen_size_y);
1614 auto mouse_pos = glm::vec2(x, y);
1615 auto screen_size = glm::vec2(screen_size_x, screen_size_y);
1618 return dcon::province_id{};
1630 return dcon::province_id{};
1635 switch(state.user_settings.map_is_globe) {
1638 glm::vec3 cartesian_coords;
1639 float section = 200;
1640 float pi = glm::pi<float>();
1641 float angle_x1 = 2 * pi * std::floor(map_pos.x * section) / section;
1642 float angle_x2 = 2 * pi * std::floor(map_pos.x * section + 1) / section;
1643 if(!std::isfinite(angle_x1)) {
1647 if(!std::isfinite(angle_x2)) {
1651 if(!std::isfinite(map_pos.x)) {
1655 if(!std::isfinite(map_pos.y)) {
1659 cartesian_coords.x = std::lerp(std::cos(angle_x1), std::cos(angle_x2), std::fmod(map_pos.x * section, 1.f));
1660 cartesian_coords.y = std::lerp(std::sin(angle_x1), std::sin(angle_x2), std::fmod(map_pos.x * section, 1.f));
1662 float angle_y = (1.f - map_pos.y) * pi;
1663 cartesian_coords.x *= std::sin(angle_y);
1664 cartesian_coords.y *= std::sin(angle_y);
1665 cartesian_coords.z = std::cos(angle_y);
1667 cartesian_coords /= glm::pi<float>();
1668 cartesian_coords.x *= -1;
1669 cartesian_coords.y *= -1;
1670 if(cartesian_coords.y > 0) {
1673 cartesian_coords += glm::vec3(0.5f);
1675 screen_pos = glm::vec2(cartesian_coords.x, cartesian_coords.z);
1676 screen_pos = (2.f * screen_pos - glm::vec2(1.f));
1678 screen_pos.x *= screen_size.y / screen_size.x;
1679 screen_pos = ((screen_pos + glm::vec2(1.f)) * 0.5f);
1680 screen_pos *= screen_size;
1685 float aspect_ratio = screen_size.x / screen_size.y;
1687 glm::vec3 cartesian_coords;
1688 float section = 200;
1689 float angle_x1 = 2.f * glm::pi<float>() * std::floor(map_pos.x * section) / section;
1690 float angle_x2 = 2.f * glm::pi<float>() * std::floor(map_pos.x * section + 1) / section;
1691 if(!std::isfinite(angle_x1)) {
1695 if(!std::isfinite(angle_x2)) {
1699 if(!std::isfinite(map_pos.x)) {
1703 if(!std::isfinite(map_pos.y)) {
1707 cartesian_coords.x = std::lerp(std::cos(angle_x1), std::cos(angle_x2), std::fmod(map_pos.x * section, 1.f));
1708 cartesian_coords.y = std::lerp(std::sin(angle_x1), std::sin(angle_x2), std::fmod(map_pos.x * section, 1.f));
1710 float angle_y = (map_pos.y) * glm::pi<float>();
1711 cartesian_coords.x *= std::sin(angle_y);
1712 cartesian_coords.y *= std::sin(angle_y);
1713 cartesian_coords.z = std::cos(angle_y);
1715 glm::vec3 temp_vector = cartesian_coords;
1718 cartesian_coords.z *= -1;
1720 cartesian_coords.z *= -1;
1722 cartesian_coords /= glm::pi<float>();
1723 cartesian_coords.x *= -1;
1724 cartesian_coords.z *= -1;
1726 float temp = cartesian_coords.z;
1727 cartesian_coords.z = cartesian_coords.y;
1728 cartesian_coords.y = temp;
1731 cartesian_coords.z -= 1.2f;
1732 float near_plane = 0.1f;
1735 constexpr float tangent_length_square = 1.2f * 1.2f - 1 / glm::pi<float>() / glm::pi<float>();
1736 float far_plane = tangent_length_square / 1.2f;
1738 float right = near_plane * tan(glm::pi<float>() / 6.f) /
zoom;
1739 float top = near_plane * tan(glm::pi<float>() / 6.f) /
zoom;
1741 cartesian_coords.x *= near_plane / right;
1742 cartesian_coords.y *= near_plane / top;
1745 float w = -cartesian_coords.z;
1746 cartesian_coords.z = -(far_plane + near_plane) / (far_plane - near_plane) * cartesian_coords.z - 2 * far_plane * near_plane / (far_plane - near_plane);
1748 if(cartesian_coords.z > far_plane) {
1752 screen_pos = glm::vec2(cartesian_coords.x, cartesian_coords.y) / w;
1755 screen_pos.x *= screen_size.y / screen_size.x;
1756 screen_pos = ((screen_pos + glm::vec2(1.f)) * 0.5f);
1757 screen_pos *= screen_size;
1764 if(map_pos.x >= 0.5f)
1766 if(map_pos.x < -0.5f)
1772 map_pos.x *= screen_size.y / screen_size.x;
1773 map_pos *= screen_size;
1774 map_pos += screen_size * 0.5f;
1775 screen_pos = map_pos;
1776 if(screen_pos.x >=
float(std::numeric_limits<int16_t>::max() / 2))
1778 if(screen_pos.x <=
float(std::numeric_limits<int16_t>::min() / 2))
1780 if(screen_pos.y >=
float(std::numeric_limits<int16_t>::max() / 2))
1782 if(screen_pos.y <=
float(std::numeric_limits<int16_t>::min() / 2))
1795 new_pos.y = 1.f - new_pos.y;
std::vector< GLsizei > trade_flow_arrow_counts
std::vector< curved_line_vertex > retreat_unit_arrow_vertices
void load_map(sys::state &state)
void set_selected_province(sys::state &state, dcon::province_id province_id)
std::vector< GLsizei > strategy_unit_arrow_counts
static constexpr uint32_t vo_objective_unit_arrow
std::vector< curved_line_vertex > attack_unit_arrow_vertices
static constexpr uint32_t vo_unit_arrow
std::vector< textured_line_with_width_vertex > trade_flow_vertices
std::vector< GLint > objective_unit_arrow_starts
void set_province_text_lines(sys::state &state, std::vector< text_line_generator_data > const &data)
std::vector< uint16_t > province_id_map
std::vector< curved_line_vertex > other_objective_unit_arrow_vertices
std::vector< GLsizei > other_objective_unit_arrow_counts
std::vector< curved_line_vertex > unit_arrow_vertices
std::vector< GLsizei > retreat_unit_arrow_counts
std::vector< curved_line_vertex > strategy_unit_arrow_vertices
static constexpr uint32_t vo_attack_unit_arrow
static constexpr uint32_t vo_trade_flow
static constexpr uint32_t vo_other_objective_unit_arrow
std::vector< GLint > retreat_unit_arrow_starts
std::vector< GLsizei > objective_unit_arrow_counts
std::vector< GLint > attack_unit_arrow_starts
std::vector< GLsizei > unit_arrow_counts
void render(sys::state &state, glm::vec2 screen_size, glm::vec2 offset, float zoom, map_view map_view_mode, map_mode::mode active_map_mode, glm::mat3 globe_rotation, float time_counter)
static constexpr uint32_t vo_retreat_unit_arrow
void set_text_lines(sys::state &state, std::vector< text_line_generator_data > const &data)
static constexpr uint32_t vo_strategy_unit_arrow
GLuint vbo_array[vo_count]
std::vector< GLint > trade_flow_arrow_starts
std::vector< GLsizei > attack_unit_arrow_counts
std::vector< GLint > strategy_unit_arrow_starts
std::vector< GLint > unit_arrow_starts
std::vector< GLint > other_objective_unit_arrow_starts
void set_drag_box(bool draw_box, glm::vec2 pos1, glm::vec2 pos2, glm::vec2 pixel_size)
std::vector< curved_line_vertex > objective_unit_arrow_vertices
void set_province_color(std::vector< uint32_t > const &prov_color)
bool map_to_screen(sys::state &state, glm::vec2 map_pos, glm::vec2 screen_size, glm::vec2 &screen_pos)
glm::vec2 last_camera_drag_pos
void on_mouse_wheel(int32_t x, int32_t y, int32_t screen_size_x, int32_t screen_size_y, sys::key_modifiers mod, float amount)
void on_lbutton_up(sys::state &state, int32_t x, int32_t y, int32_t screen_size_x, int32_t screen_size_y, sys::key_modifiers mod)
void on_mbuttom_up(int32_t x, int32_t y, sys::key_modifiers mod)
void on_mbuttom_down(int32_t x, int32_t y, int32_t screen_size_x, int32_t screen_size_y, sys::key_modifiers mod)
bool screen_to_map(glm::vec2 screen_pos, glm::vec2 screen_size, map_view view_mode, glm::vec2 &map_pos)
void set_selected_province(dcon::province_id prov_id)
bool unhandled_province_selection
map_view current_view(sys::state &state)
void update(sys::state &state)
std::chrono::time_point< std::chrono::steady_clock > last_update_time
dcon::province_id get_selected_province()
void on_key_up(sys::virtual_key keycode, sys::key_modifiers mod)
void set_terrain_map_mode()
void load_map(sys::state &state)
dcon::province_id selected_province
void on_rbutton_down(sys::state &state, int32_t x, int32_t y, int32_t screen_size_x, int32_t screen_size_y, sys::key_modifiers mod)
void on_key_down(sys::virtual_key keycode, sys::key_modifiers mod)
void set_province_color(std::vector< uint32_t > const &prov_color, map_mode::mode map_mode)
glm::vec2 last_unit_box_drag_pos
void on_lbutton_down(sys::state &state, int32_t x, int32_t y, int32_t screen_size_x, int32_t screen_size_y, sys::key_modifiers mod)
glm::vec2 normalize_map_coord(glm::vec2 pos)
map_mode::mode active_map_mode
void on_mouse_move(int32_t x, int32_t y, int32_t screen_size_x, int32_t screen_size_y, sys::key_modifiers mod)
void center_map_on_province(sys::state &state, dcon::province_id)
void render(sys::state &state, uint32_t screen_x, uint32_t screen_y)
dcon::province_id get_province_under_mouse(sys::state &state, int32_t x, int32_t y, int32_t screen_size_x, int32_t screen_size_y)
bool right_arrow_key_down
void set_pos(glm::vec2 pos)
#define assert(condition)
pop_satisfaction_wrapper_fat fatten(data_container const &c, pop_satisfaction_wrapper_id id) noexcept
void update_map_mode(sys::state &state)
void update_unit_arrows(sys::state &state, display_data &map_data)
glm::vec2 get_army_location(sys::state &state, dcon::province_id prov_id)
void make_army_path(sys::state &state, std::vector< map::curved_line_vertex > &buffer, dcon::army_id selected_army, float size_x, float size_y)
glm::vec2 get_navy_location(sys::state &state, dcon::province_id prov_id)
glm::vec2 get_port_location(sys::state &state, dcon::province_id p)
void make_land_path(sys::state &state, std::vector< map::textured_line_with_width_vertex > &buffer, dcon::province_id origin, dcon::province_id target, float width, float size_x, float size_y)
void make_sea_path(sys::state &state, std::vector< map::textured_line_with_width_vertex > &buffer, dcon::province_id origin, dcon::province_id target, float width, float size_x, float size_y, float shift_x, float shift_y)
bool is_inside_bbox(std::array< glm::vec2, 5 > &bbox, glm::vec2 p)
dcon::nation_id get_top_overlord(sys::state &state, dcon::nation_id n)
void update_bbox_negative(std::array< glm::vec2, 5 > &bbox, glm::vec2 p)
void make_army_direction(sys::state &state, std::vector< map::curved_line_vertex > &buffer, dcon::army_id selected_army, float size_x, float size_y)
void make_navy_path(sys::state &state, std::vector< map::curved_line_vertex > &buffer, dcon::navy_id selected_navy, float size_x, float size_y)
bool is_sea_province(sys::state &state, dcon::province_id prov_id)
void update_bbox(std::array< glm::vec2, 5 > &bbox, glm::vec2 p)
void update_trade_flow_arrows(sys::state &state, display_data &map_data)
void make_navy_direction(sys::state &state, std::vector< map::curved_line_vertex > &buffer, dcon::navy_id selected_navy, float size_x, float size_y)
void update_text_lines(sys::state &state, display_data &map_data)
bool are_at_war(sys::state const &state, dcon::nation_id a, dcon::nation_id b)
dcon::province_id state_get_coastal_capital(sys::state &state, dcon::state_instance_id s)
constexpr dcon::province_id from_map_id(uint16_t id)
constexpr uint16_t to_map_id(dcon::province_id id)
audio_instance & get_random_province_select_sound(sys::state &state)
void play_interface_sound(sys::state &state, audio_instance &s, float volume)
std::string resolve_string_substitution(sys::state &state, dcon::text_key source_text, substitution_map const &mp)
void add_to_substitution_map(substitution_map &mp, variable_type key, substitution value)
dcon::text_key get_adjective(sys::state &state, dcon::nation_id id)
ankerl::unordered_dense::map< uint32_t, substitution > substitution_map
std::string produce_simple_string(sys::state const &state, dcon::text_key id)
dcon::text_key get_name(sys::state &state, dcon::nation_id id)
Holds important data about the game world, state, and other data regarding windowing,...