aboutsummaryrefslogtreecommitdiff
path: root/game
diff options
context:
space:
mode:
Diffstat (limited to 'game')
-rw-r--r--game/project.godot4
-rw-r--r--game/src/Game/GameSession/MapText.gd50
-rw-r--r--game/src/Game/GameSession/MapView.gd64
-rw-r--r--game/src/Game/GameSession/MapView.tscn12
-rw-r--r--game/src/Game/GameSession/NationManagementScreen/PopulationMenu.gd574
-rw-r--r--game/src/Game/GameSession/ProvinceOverviewPanel.gd9
-rw-r--r--game/src/Game/GameSession/TerrainMap.gdshader119
7 files changed, 776 insertions, 56 deletions
diff --git a/game/project.godot b/game/project.godot
index 9d005b0..ac627a3 100644
--- a/game/project.godot
+++ b/game/project.godot
@@ -58,6 +58,10 @@ window/per_pixel_transparency/allowed=true
enabled=PackedStringArray("res://addons/keychain/plugin.cfg", "res://addons/openvic-plugin/plugin.cfg")
+[filesystem]
+
+import/blender/enabled=false
+
[gui]
theme/custom="res://assets/graphics/theme/default_theme.tres"
diff --git a/game/src/Game/GameSession/MapText.gd b/game/src/Game/GameSession/MapText.gd
new file mode 100644
index 0000000..22eba10
--- /dev/null
+++ b/game/src/Game/GameSession/MapText.gd
@@ -0,0 +1,50 @@
+class_name MapText
+extends Node3D
+
+@export var _map_view : MapView
+
+var _province_name_font : Font
+
+const _province_name_scale : float = 1.0 / 48.0
+
+func _ready() -> void:
+ _province_name_font = AssetManager.get_font(&"mapfont_56")
+
+func _clear_children() -> void:
+ var child_count : int = get_child_count()
+ while child_count > 0:
+ child_count -= 1
+ remove_child(get_child(child_count))
+
+func generate_map_names() -> void:
+ _clear_children()
+
+ for dict : Dictionary in GameSingleton.get_province_names():
+ _add_province_name(dict)
+
+func _add_province_name(dict : Dictionary) -> void:
+ const identifier_key : StringName = &"identifier"
+ const position_key : StringName = &"position"
+ const rotation_key : StringName = &"rotation"
+ const scale_key : StringName = &"scale"
+
+ var label : Label3D = Label3D.new()
+
+ label.set_draw_flag(Label3D.FLAG_DOUBLE_SIDED, false)
+ label.set_modulate(Color.BLACK)
+ label.set_outline_size(0)
+ label.set_font(_province_name_font)
+ label.set_vertical_alignment(VERTICAL_ALIGNMENT_BOTTOM)
+
+ var identifier : String = dict[identifier_key]
+ label.set_name(identifier)
+ label.set_text(GUINode.format_province_name(identifier))
+
+ label.set_position(_map_view._map_to_world_coords(dict[position_key]) + Vector3(0, 0.001, 0))
+
+ label.rotate_x(-PI / 2)
+ label.rotate_y(dict.get(rotation_key, 0.0))
+
+ label.scale *= dict.get(scale_key, 1.0) * _province_name_scale
+
+ add_child(label)
diff --git a/game/src/Game/GameSession/MapView.gd b/game/src/Game/GameSession/MapView.gd
index f522bcb..2ab7c34 100644
--- a/game/src/Game/GameSession/MapView.gd
+++ b/game/src/Game/GameSession/MapView.gd
@@ -1,6 +1,9 @@
+class_name MapView
extends Node3D
signal map_view_camera_changed(near_left : Vector2, far_left : Vector2, far_right : Vector2, near_right : Vector2)
+signal parchment_view_changed(is_parchment_view : bool)
+signal detailed_view_changed(is_detailed_view : bool)
const _action_north : StringName = &"map_north"
const _action_east : StringName = &"map_east"
@@ -22,9 +25,9 @@ var _drag_active : bool = false
var _mouse_over_viewport : bool = true
var _window_in_focus : bool = true
-@export var _zoom_target_min : float = 0.15
+@export var _zoom_target_min : float = 0.10
@export var _zoom_target_max : float = 5.0
-@export var _zoom_target_step : float = (_zoom_target_max - _zoom_target_min) / 64.0
+@export var _zoom_target_step : float = (_zoom_target_max - _zoom_target_min) / 40.0
@export var _zoom_epsilon : float = _zoom_target_step * 0.005
@export var _zoom_speed : float = 5.0
# _zoom_target's starting value is ignored as it is updated to the camera's height by _ready,
@@ -35,8 +38,13 @@ var _zoom_target : float = _zoom_target_max:
const _zoom_position_multiplier = 3.14159 # Horizontal movement coefficient during zoom
var _zoom_position : Vector2
-# Display the detailed terrain map below this height, and the parchment map above it
+# Display the parchment map above this height
@export var _zoom_parchment_threshold : float = _zoom_target_min + (_zoom_target_max - _zoom_target_min) / 4
+# Display details like models and province names below this height
+@export var _zoom_detailed_threshold : float = _zoom_parchment_threshold / 2
+
+var _is_parchment_view : bool = false
+var _is_detailed_view : bool = false
@export var _map_mesh_instance : MeshInstance3D
var _map_mesh : MapMesh
@@ -50,6 +58,8 @@ var _mouse_pos_viewport : Vector2 = Vector2(0.5, 0.5)
var _mouse_pos_map : Vector2 = Vector2(0.5, 0.5)
var _viewport_dims : Vector2 = Vector2(1, 1)
+@export var _map_text : MapText
+
# ??? Strange Godot/GDExtension Bug ???
# Upon first opening a clone of this repo with the Godot Editor,
# if GameSingleton.get_province_index_image is called before MapMesh
@@ -61,7 +71,12 @@ func _ready() -> void:
if not _camera:
push_error("MapView's _camera variable hasn't been set!")
return
+
+ # Start just under the parchment threshold
+ _camera.position.y = _zoom_parchment_threshold - _zoom_target_step
_zoom_target = _camera.position.y
+ _update_view_states(true)
+
if not _map_mesh_instance:
push_error("MapView's _map_mesh_instance variable hasn't been set!")
return
@@ -105,6 +120,8 @@ func _ready() -> void:
scaled_dims.z *= 2.0
(_map_background_instance.mesh as PlaneMesh).set_size(Vector2(scaled_dims.x, scaled_dims.z))
+ _map_text.generate_map_names()
+
func _notification(what : int) -> void:
match what:
NOTIFICATION_WM_MOUSE_ENTER: # Mouse inside window
@@ -119,6 +136,10 @@ func _notification(what : int) -> void:
func _world_to_map_coords(pos : Vector3) -> Vector2:
return (Vector2(pos.x, pos.z) - _map_mesh_corner) / _map_mesh_dims
+func _map_to_world_coords(pos : Vector2) -> Vector3:
+ pos = pos * _map_mesh_dims + _map_mesh_corner
+ return Vector3(pos.x, 0, pos.y)
+
func _viewport_to_map_coords(pos_viewport : Vector2) -> Vector2:
var ray_origin := _camera.project_ray_origin(pos_viewport)
var ray_normal := _camera.project_ray_normal(pos_viewport)
@@ -149,12 +170,13 @@ func _on_province_selected(index : int) -> void:
# REQUIREMENTS
# * SS-31
func _unhandled_input(event : InputEvent) -> void:
- if _mouse_over_viewport and event.is_action_pressed(_action_click):
- # Check if the mouse is outside of bounds
- if _map_mesh.is_valid_uv_coord(_mouse_pos_map):
- GameSingleton.set_selected_province(GameSingleton.get_province_index_from_uv_coords(_mouse_pos_map))
- else:
- print("Clicked outside the map!")
+ if event.is_action_pressed(_action_click):
+ if _mouse_over_viewport:
+ # Check if the mouse is outside of bounds
+ if _map_mesh.is_valid_uv_coord(_mouse_pos_map):
+ GameSingleton.set_selected_province(GameSingleton.get_province_index_from_uv_coords(_mouse_pos_map))
+ else:
+ print("Clicked outside the map!")
elif event.is_action_pressed(_action_drag):
if _drag_active:
push_warning("Drag being activated while already active!")
@@ -221,6 +243,17 @@ func _clamp_over_map() -> void:
_camera.position.x = _map_mesh_corner.x + fposmod(_camera.position.x - _map_mesh_corner.x, _map_mesh_dims.x)
_camera.position.z = clamp(_camera.position.z, _map_mesh_corner.y, _map_mesh_corner.y + _map_mesh_dims.y)
+func _update_view_states(force_signal : bool) -> void:
+ var new_is_parchment_view : bool = _camera.position.y >= _zoom_parchment_threshold - _zoom_epsilon
+ if force_signal or new_is_parchment_view != _is_parchment_view:
+ _is_parchment_view = new_is_parchment_view
+ parchment_view_changed.emit(_is_parchment_view)
+
+ var new_is_detailed_view : bool = _camera.position.y <= _zoom_detailed_threshold + _zoom_epsilon
+ if force_signal or new_is_detailed_view != _is_detailed_view:
+ _is_detailed_view = new_is_detailed_view
+ detailed_view_changed.emit(_is_detailed_view)
+
# REQUIREMENTS
# * SS-74
# * UIFUN-123
@@ -237,12 +270,17 @@ func _zoom_process(delta : float) -> void:
_zoom_position.y * zoom_delta * int(_mouse_over_viewport)
)
# TODO - smooth transition similar to smooth zoom
- var parchment_mapmode : bool = GameSingleton.is_parchment_mapmode_allowed() and _camera.position.y > _zoom_parchment_threshold
+ _update_view_states(false)
+ var parchment_mapmode : bool = GameSingleton.is_parchment_mapmode_allowed() and _is_parchment_view
_map_shader_material.set_shader_parameter(GameLoader.ShaderManager.param_parchment_mix, float(parchment_mapmode))
func _update_orientation() -> void:
const up := Vector3(0, 0, -1)
- var dir := Vector3(0, -1, -1.25 * exp(-10 * _camera.position.y - _zoom_target_min))
+ var dir := Vector3(0, -1, 0)
+ if _is_detailed_view:
+ # Zero at the transition point, increases as you zoom further in
+ var delta : float = (_zoom_detailed_threshold - _camera.position.y) / _zoom_detailed_threshold
+ dir.z = -(delta ** 4)
_camera.look_at(_camera.position + dir, up)
func _update_minimap_viewport() -> void:
@@ -253,9 +291,9 @@ func _update_minimap_viewport() -> void:
map_view_camera_changed.emit(near_left, far_left, far_right, near_right)
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:
+ _mouse_pos_map = _viewport_to_map_coords(_mouse_pos_viewport)
+ var hover_index := GameSingleton.get_province_index_from_uv_coords(_mouse_pos_map)
_map_shader_material.set_shader_parameter(GameLoader.ShaderManager.param_hover_index, hover_index)
func _on_mouse_entered_viewport() -> void:
diff --git a/game/src/Game/GameSession/MapView.tscn b/game/src/Game/GameSession/MapView.tscn
index bf22ef8..dff02a6 100644
--- a/game/src/Game/GameSession/MapView.tscn
+++ b/game/src/Game/GameSession/MapView.tscn
@@ -1,7 +1,8 @@
-[gd_scene load_steps=7 format=3 uid="uid://dkehmdnuxih2r"]
+[gd_scene load_steps=8 format=3 uid="uid://dkehmdnuxih2r"]
[ext_resource type="Script" path="res://src/Game/GameSession/MapView.gd" id="1_exccw"]
[ext_resource type="Shader" path="res://src/Game/GameSession/TerrainMap.gdshader" id="1_upocn"]
+[ext_resource type="Script" path="res://src/Game/GameSession/MapText.gd" id="2_13bgq"]
[sub_resource type="ShaderMaterial" id="ShaderMaterial_tayeg"]
render_priority = 0
@@ -23,17 +24,22 @@ albedo_color = Color(0, 0, 0, 1)
material = SubResource("StandardMaterial3D_irk50")
size = Vector2(6, 2)
-[node name="MapView" type="Node3D" node_paths=PackedStringArray("_camera", "_map_mesh_instance", "_map_background_instance")]
+[node name="MapView" type="Node3D" node_paths=PackedStringArray("_camera", "_map_mesh_instance", "_map_background_instance", "_map_text")]
editor_description = "SS-73"
script = ExtResource("1_exccw")
_camera = NodePath("MapCamera")
_map_mesh_instance = NodePath("MapMeshInstance")
_map_background_instance = NodePath("MapBackgroundInstance")
+_map_text = NodePath("MapText")
[node name="MapCamera" type="Camera3D" parent="."]
transform = Transform3D(1, 0, 0, 0, 0.707107, 0.707107, 0, -0.707107, 0.707107, 0.25, 1.5, -2.75)
near = 0.01
+[node name="MapText" type="Node3D" parent="." node_paths=PackedStringArray("_map_view")]
+script = ExtResource("2_13bgq")
+_map_view = NodePath("..")
+
[node name="MapMeshInstance" type="MeshInstance3D" parent="."]
editor_description = "FS-343"
transform = Transform3D(10, 0, 0, 0, 10, 0, 0, 0, 10, 0, 0, 0)
@@ -43,3 +49,5 @@ mesh = SubResource("MapMesh_3gtsd")
[node name="MapBackgroundInstance" type="MeshInstance3D" parent="."]
transform = Transform3D(10, 0, 0, 0, 10, 0, 0, 0, 10, 0, -1, 0)
mesh = SubResource("PlaneMesh_fnhgl")
+
+[connection signal="detailed_view_changed" from="." to="MapText" method="set_visible"]
diff --git a/game/src/Game/GameSession/NationManagementScreen/PopulationMenu.gd b/game/src/Game/GameSession/NationManagementScreen/PopulationMenu.gd
index 29bd56b..5de2d25 100644
--- a/game/src/Game/GameSession/NationManagementScreen/PopulationMenu.gd
+++ b/game/src/Game/GameSession/NationManagementScreen/PopulationMenu.gd
@@ -4,19 +4,371 @@ var _active : bool = false
const _screen : NationManagement.Screen = NationManagement.Screen.POPULATION
+const _scene_name : String = "country_pops"
+
+var _pop_screen_panel : Panel
+
+var _province_listbox : GUIListBox
+var _province_list_scroll_index : int = 0
+var _province_list_types : Array[MenuSingleton.ProvinceListEntry]
+var _province_list_indices : PackedInt32Array
+var _province_list_panels : Array[Panel]
+var _province_list_button_icons : Array[GFXSpriteTexture]
+var _province_list_name_labels : Array[Label]
+var _province_list_size_labels : Array[Label]
+var _province_list_growth_icons : Array[GFXSpriteTexture]
+var _province_list_colony_buttons : Array[Button]
+var _province_list_national_focus_icons : Array[GFXSpriteTexture]
+var _province_list_expand_icons : Array[GFXSpriteTexture]
+
+var _pop_filter_buttons : Array[Button]
+var _pop_filter_icons : Array[GFXSpriteTexture]
+var _pop_filter_selected_icons : Array[GFXButtonStateTexture]
+var _pop_filter_hover_icons : Array[GFXButtonStateTexture]
+
+var _distribution_charts : Array[GFXPieChartTexture]
+var _distribution_lists : Array[GUIListBox]
+
+var _pop_list_scrollbar : GUIScrollbar
+var _pop_list_scroll_index : int = 0
+
+var _pop_list_rows : Array[Panel]
+var _pop_list_size_labels : Array[Label]
+var _pop_list_type_buttons : Array[Button]
+var _pop_list_type_icons : Array[GFXSpriteTexture]
+var _pop_list_producing_icons : Array[GFXSpriteTexture]
+var _pop_list_culture_labels : Array[Label]
+var _pop_list_religion_icons : Array[GFXSpriteTexture]
+var _pop_list_location_labels : Array[Label]
+var _pop_list_militancy_labels : Array[Label]
+var _pop_list_consciousness_labels : Array[Label]
+var _pop_list_ideology_charts : Array[GFXPieChartTexture]
+var _pop_list_issues_charts : Array[GFXPieChartTexture]
+var _pop_list_unemployment_progressbars : Array[TextureProgressBar]
+var _pop_list_cash_labels : Array[Label]
+var _pop_list_life_needs_progressbars : Array[TextureProgressBar]
+var _pop_list_everyday_needs_progressbars : Array[TextureProgressBar]
+var _pop_list_luxury_needs_progressbars : Array[TextureProgressBar]
+var _pop_list_rebel_icons : Array[GFXSpriteTexture]
+var _pop_list_social_movement_icons : Array[GFXSpriteTexture]
+var _pop_list_political_movement_icons : Array[GFXSpriteTexture]
+var _pop_list_national_movement_flags : Array[GFXMaskedFlagTexture]
+var _pop_list_size_change_icons : Array[GFXSpriteTexture]
+var _pop_list_literacy_labels : Array[Label]
+
func _ready() -> void:
GameSingleton.gamestate_updated.connect(_update_info)
+ MenuSingleton.population_menu_province_list_changed.connect(_setup_province_list)
+ MenuSingleton.population_menu_province_list_selected_changed.connect(_update_province_list)
+ MenuSingleton.population_menu_pops_changed.connect(_update_pops)
Events.NationManagementScreens.update_active_nation_management_screen.connect(_on_update_active_nation_management_screen)
- add_gui_element("country_pops", "country_pop")
+ add_gui_element(_scene_name, "country_pop")
var close_button : Button = get_button_from_nodepath(^"./country_pop/close_button")
if close_button:
close_button.pressed.connect(Events.NationManagementScreens.close_nation_management_screen.bind(_screen))
+ _pop_screen_panel = get_panel_from_nodepath(^"./country_pop")
+
+ # province list is set up via the population_menu_provinces_changed signal
+ _setup_sort_buttons()
+ _setup_pop_filter_buttons()
+ _setup_distribution_windows()
+ _setup_pop_list()
+
_update_info()
+func _generate_province_list_row(index : int, type : MenuSingleton.ProvinceListEntry) -> Error:
+ while _province_list_types.size() <= index:
+ _province_list_types.push_back(MenuSingleton.LIST_ENTRY_NONE)
+ _province_list_indices.push_back(-1)
+ _province_list_panels.push_back(null)
+ _province_list_button_icons.push_back(null)
+ _province_list_name_labels.push_back(null)
+ _province_list_size_labels.push_back(null)
+ _province_list_growth_icons.push_back(null)
+ _province_list_colony_buttons.push_back(null)
+ _province_list_national_focus_icons.push_back(null)
+ _province_list_expand_icons.push_back(null)
+
+ if _province_list_types[index] == type:
+ return OK
+
+ if _province_list_panels[index]:
+ _province_listbox.remove_child(_province_list_panels[index])
+
+ _province_list_types[index] = MenuSingleton.LIST_ENTRY_NONE
+ _province_list_indices[index] = -1
+ _province_list_panels[index] = null
+ _province_list_button_icons[index] = null
+ _province_list_name_labels[index] = null
+ _province_list_size_labels[index] = null
+ _province_list_growth_icons[index] = null
+ _province_list_colony_buttons[index] = null
+ _province_list_national_focus_icons[index] = null
+ _province_list_expand_icons[index] = null
+
+ if type == MenuSingleton.LIST_ENTRY_NONE:
+ return OK
+
+ const gui_element_names : Dictionary = {
+ MenuSingleton.LIST_ENTRY_COUNTRY: "poplistitem_country",
+ MenuSingleton.LIST_ENTRY_STATE: "poplistitem_state",
+ MenuSingleton.LIST_ENTRY_PROVINCE: "poplistitem_province"
+ }
+
+ var entry_panel : Panel = GUINode.generate_gui_element(_scene_name, gui_element_names[type])
+
+ if not entry_panel:
+ return FAILED
+
+ _province_list_types[index] = type
+
+ _province_list_panels[index] = entry_panel
+
+ var base_button : Button = GUINode.get_button_from_node(entry_panel.get_node(^"./poplistbutton"))
+ if base_button:
+ base_button.pressed.connect(
+ func() -> void: MenuSingleton.population_menu_select_province_list_entry(_province_list_indices[index])
+ )
+ _province_list_button_icons[index] = GUINode.get_gfx_sprite_texture_from_node(base_button)
+
+ _province_list_name_labels[index] = GUINode.get_label_from_node(entry_panel.get_node(^"./poplist_name"))
+
+ _province_list_size_labels[index] = GUINode.get_label_from_node(entry_panel.get_node(^"./poplist_numpops"))
+
+ _province_list_growth_icons[index] = GUINode.get_gfx_sprite_texture_from_node(entry_panel.get_node(^"./growth_indicator"))
+
+ if type == MenuSingleton.LIST_ENTRY_STATE:
+ _province_list_colony_buttons[index] = GUINode.get_button_from_node(entry_panel.get_node(^"./colonial_state_icon"))
+
+ var national_focus_button : Button = GUINode.get_button_from_node(entry_panel.get_node(^"./state_focus"))
+ if national_focus_button:
+ # TODO - connect national focus button to national focus selection submenu
+ _province_list_national_focus_icons[index] = GUINode.get_gfx_sprite_texture_from_node(national_focus_button)
+
+ var expand_button : Button = GUINode.get_button_from_node(entry_panel.get_node(^"./expand"))
+ if expand_button:
+ expand_button.pressed.connect(
+ func() -> void: MenuSingleton.population_menu_toggle_expanded(_province_list_indices[index])
+ )
+ _province_list_expand_icons[index] = GUINode.get_gfx_sprite_texture_from_node(expand_button)
+
+ _province_listbox.add_child(entry_panel)
+ _province_listbox.move_child(entry_panel, index)
+
+ return OK
+
+func _setup_province_list() -> void:
+ if not _province_listbox:
+ _province_listbox = get_gui_listbox_from_nodepath(^"./country_pop/pop_province_list")
+
+ if not _province_listbox:
+ return
+ _province_listbox.scroll_index_changed.connect(_update_province_list)
+
+ if _province_list_panels.size() < 1 or not _province_list_panels[0]:
+ if _generate_province_list_row(0, MenuSingleton.LIST_ENTRY_COUNTRY) != OK or _province_list_panels.size() < 1 or not _province_list_panels[0]:
+ push_error("Failed to generate country row in population menu province list to determine row height!")
+ return
+
+ _province_listbox.set_fixed(MenuSingleton.get_population_menu_province_list_row_count(), _province_list_panels[0].size.y, false)
+
+func _setup_sort_buttons() -> void:
+ # button_path : NodePath, clear_text : bool, sort_key : GameSingleton.PopSortKey
+ const sort_button_info : Array[Array] = [
+ [^"./country_pop/sortby_size_button", false, MenuSingleton.SORT_SIZE],
+ [^"./country_pop/sortby_type_button", false, MenuSingleton.SORT_TYPE],
+ [^"./country_pop/sortby_nationality_button", false, MenuSingleton.SORT_CULTURE],
+ [^"./country_pop/sortby_religion_button", false, MenuSingleton.SORT_RELIGION],
+ [^"./country_pop/sortby_location_button", false, MenuSingleton.SORT_LOCATION],
+ [^"./country_pop/sortby_mil_button", true, MenuSingleton.SORT_MILITANCY],
+ [^"./country_pop/sortby_con_button", true, MenuSingleton.SORT_CONSCIOUSNESS],
+ [^"./country_pop/sortby_ideology_button", true, MenuSingleton.SORT_IDEOLOGY],
+ [^"./country_pop/sortby_issues_button", true, MenuSingleton.SORT_ISSUES],
+ [^"./country_pop/sortby_unemployment_button", true, MenuSingleton.SORT_UNEMPLOYMENT],
+ [^"./country_pop/sortby_cash_button", true, MenuSingleton.SORT_CASH],
+ [^"./country_pop/sortby_subsistence_button", true, MenuSingleton.SORT_LIFE_NEEDS],
+ [^"./country_pop/sortby_eve_button", true, MenuSingleton.SORT_EVERYDAY_NEEDS],
+ [^"./country_pop/sortby_luxury_button", true, MenuSingleton.SORT_LUXURY_NEEDS],
+ [^"./country_pop/sortby_revoltrisk_button", true, MenuSingleton.SORT_REBEL_FACTION],
+ [^"./country_pop/sortby_change_button", true, MenuSingleton.SORT_SIZE_CHANGE],
+ [^"./country_pop/sortby_literacy_button", true, MenuSingleton.SORT_LITERACY]
+ ]
+
+ for button_info : Array in sort_button_info:
+ var sort_button : Button = get_button_from_nodepath(button_info[0])
+ if sort_button:
+ if button_info[1]:
+ sort_button.set_text("")
+ sort_button.pressed.connect(MenuSingleton.population_menu_select_sort_key.bind(button_info[2]))
+
+func _setup_pop_filter_buttons() -> void:
+ if not _pop_screen_panel:
+ push_error("Cannot set up pop filter buttons without pop screen to add them to")
+ return
+
+ var pop_filter_sprite_indices : PackedInt32Array = MenuSingleton.get_population_menu_pop_filter_setup_info()
+
+ var pop_filter_start : Vector2 = GUINode.get_gui_position(_scene_name, "popfilter_start")
+ var pop_filter_step : Vector2 = GUINode.get_gui_position(_scene_name, "popfilter_offset")
+
+ for index : int in pop_filter_sprite_indices.size():
+ var pop_filter_button : Button = GUINode.get_button_from_node(GUINode.generate_gui_element(_scene_name, "pop_filter_button"))
+ var pop_filter_icon : GFXSpriteTexture = null
+ var pop_filter_selected_icon : GFXButtonStateTexture = null
+ var pop_filter_hover_icon : GFXButtonStateTexture = null
+
+ if pop_filter_button:
+ _pop_screen_panel.add_child(pop_filter_button)
+ pop_filter_button.set_position(pop_filter_start + pop_filter_step * index)
+ pop_filter_button.pressed.connect(MenuSingleton.population_menu_toggle_pop_filter.bind(index))
+ pop_filter_icon = GUINode.get_gfx_sprite_texture_from_node(pop_filter_button)
+
+ if pop_filter_icon:
+ pop_filter_icon.set_icon_index(pop_filter_sprite_indices[index])
+ pop_filter_selected_icon = pop_filter_icon.get_button_state_texture(GFXButtonStateTexture.SELECTED)
+ pop_filter_hover_icon = pop_filter_icon.get_button_state_texture(GFXButtonStateTexture.HOVER)
+
+ _pop_filter_buttons.push_back(pop_filter_button)
+ _pop_filter_icons.push_back(pop_filter_icon)
+ _pop_filter_selected_icons.push_back(pop_filter_selected_icon)
+ _pop_filter_hover_icons.push_back(pop_filter_hover_icon)
+
+ var select_all_button : Button = get_button_from_nodepath(^"./country_pop/popfilter_ALL")
+ if select_all_button:
+ select_all_button.pressed.connect(MenuSingleton.population_menu_select_all_pop_filters)
+
+ var deselect_all_button : Button = get_button_from_nodepath(^"./country_pop/popfilter_DESELECT_ALL")
+ if deselect_all_button:
+ deselect_all_button.pressed.connect(MenuSingleton.population_menu_deselect_all_pop_filters)
+
+func _setup_distribution_windows() -> void:
+ if not _pop_screen_panel:
+ push_error("Cannot set up distribution windows without pop screen to add them to")
+ return
+
+ const columns : int = 3
+
+ var distribution_names : PackedStringArray = MenuSingleton.get_population_menu_distribution_setup_info()
+
+ var distribution_start : Vector2 = GUINode.get_gui_position(_scene_name, "popdistribution_start")
+ var distribution_step : Vector2 = GUINode.get_gui_position(_scene_name, "popdistribution_offset")
+
+ for index : int in distribution_names.size():
+ var distribution_panel : Panel = GUINode.generate_gui_element(_scene_name, "distribution_window")
+ var distribution_chart : GFXPieChartTexture = null
+ var distribution_list : GUIListBox = null
+
+ if distribution_panel:
+ _pop_screen_panel.add_child(distribution_panel)
+ distribution_panel.set_position(distribution_start + distribution_step * Vector2(index % columns, index / columns))
+
+ var name_label : Label = GUINode.get_label_from_node(distribution_panel.get_node(^"./item_name"))
+ if name_label:
+ name_label.text = distribution_names[index]
+
+ distribution_chart = GUINode.get_gfx_pie_chart_texture_from_node(distribution_panel.get_node(^"./chart"))
+ distribution_list = GUINode.get_gui_listbox_from_node(distribution_panel.get_node(^"./member_names"))
+
+ _distribution_charts.push_back(distribution_chart)
+ _distribution_lists.push_back(distribution_list)
+
+func _setup_pop_list() -> void:
+ _pop_list_scrollbar = get_gui_scrollbar_from_nodepath(^"./country_pop/external_scroll_slider")
+
+ var pop_list_panel : Panel = get_panel_from_nodepath(^"./country_pop/pop_list")
+ if not pop_list_panel:
+ return
+
+ if _pop_list_scrollbar:
+ _pop_list_scrollbar.value_changed.connect(
+ func (value : int) -> void:
+ _pop_list_scroll_index = value
+ _update_pop_list()
+ )
+
+ pop_list_panel.gui_input.connect(
+ func (event : InputEvent) -> void:
+ if event is InputEventMouseButton:
+ if event.is_pressed():
+ if event.get_button_index() == MOUSE_BUTTON_WHEEL_UP:
+ _pop_list_scrollbar.decrement_value()
+ elif event.get_button_index() == MOUSE_BUTTON_WHEEL_DOWN:
+ _pop_list_scrollbar.increment_value()
+ )
+
+ var height : float = 0.0
+ while height < pop_list_panel.size.y:
+ var pop_row_panel : Panel = GUINode.generate_gui_element(_scene_name, "popinfomember_popview")
+ if not pop_row_panel:
+ break
+
+ pop_list_panel.add_child(pop_row_panel)
+ pop_row_panel.set_position(Vector2(0, height))
+ height += pop_row_panel.size.y
+ _pop_list_rows.push_back(pop_row_panel)
+
+ _pop_list_size_labels.push_back(GUINode.get_label_from_node(pop_row_panel.get_node(^"./pop_size")))
+
+ var pop_type_button : Button = GUINode.get_button_from_node(pop_row_panel.get_node(^"./pop_type"))
+ # TODO - open pop details menu on pop type button press
+ _pop_list_type_buttons.push_back(pop_type_button)
+
+ _pop_list_type_icons.push_back(GUINode.get_gfx_sprite_texture_from_node(pop_type_button))
+
+ _pop_list_producing_icons.push_back(GUINode.get_gfx_sprite_texture_from_node(pop_row_panel.get_node(^"./pop_producing_icon")))
+
+ var culture_label : Label = GUINode.get_label_from_node(pop_row_panel.get_node(^"./pop_nation"))
+ if culture_label:
+ culture_label.set_text_overrun_behavior(TextServer.OVERRUN_TRIM_ELLIPSIS)
+ _pop_list_culture_labels.push_back(culture_label)
+
+ _pop_list_religion_icons.push_back(GUINode.get_gfx_sprite_texture_from_node(pop_row_panel.get_node(^"./pop_religion")))
+
+ var location_label : Label = GUINode.get_label_from_node(pop_row_panel.get_node(^"./pop_location"))
+ if location_label:
+ location_label.set_text_overrun_behavior(TextServer.OVERRUN_TRIM_ELLIPSIS)
+ _pop_list_location_labels.push_back(location_label)
+
+ _pop_list_militancy_labels.push_back(GUINode.get_label_from_node(pop_row_panel.get_node(^"./pop_mil")))
+
+ _pop_list_consciousness_labels.push_back(GUINode.get_label_from_node(pop_row_panel.get_node(^"./pop_con")))
+
+ _pop_list_ideology_charts.push_back(GUINode.get_gfx_pie_chart_texture_from_node(pop_row_panel.get_node(^"./pop_ideology")))
+
+ _pop_list_issues_charts.push_back(GUINode.get_gfx_pie_chart_texture_from_node(pop_row_panel.get_node(^"./pop_issues")))
+
+ _pop_list_unemployment_progressbars.push_back(GUINode.get_progress_bar_from_node(pop_row_panel.get_node(^"./pop_unemployment_bar")))
+
+ _pop_list_cash_labels.push_back(GUINode.get_label_from_node(pop_row_panel.get_node(^"./pop_cash")))
+
+ var pop_list_life_needs_progressbar : TextureProgressBar = GUINode.get_progress_bar_from_node(pop_row_panel.get_node(^"./lifeneed_progress"))
+ if pop_list_life_needs_progressbar:
+ pop_list_life_needs_progressbar.position += Vector2(1, 0)
+ _pop_list_life_needs_progressbars.push_back(pop_list_life_needs_progressbar)
+
+ var pop_list_everyday_needs_progressbar : TextureProgressBar = GUINode.get_progress_bar_from_node(pop_row_panel.get_node(^"./eveneed_progress"))
+ if pop_list_everyday_needs_progressbar:
+ pop_list_everyday_needs_progressbar.position += Vector2(1, 0)
+ _pop_list_everyday_needs_progressbars.push_back(pop_list_everyday_needs_progressbar)
+
+ _pop_list_luxury_needs_progressbars.push_back(GUINode.get_progress_bar_from_node(pop_row_panel.get_node(^"./luxneed_progress")))
+
+ _pop_list_rebel_icons.push_back(GUINode.get_gfx_sprite_texture_from_node(pop_row_panel.get_node(^"./pop_revolt")))
+
+ _pop_list_social_movement_icons.push_back(GUINode.get_gfx_sprite_texture_from_node(pop_row_panel.get_node(^"./pop_movement_social")))
+
+ _pop_list_political_movement_icons.push_back(GUINode.get_gfx_sprite_texture_from_node(pop_row_panel.get_node(^"./pop_movement_political")))
+
+ _pop_list_national_movement_flags.push_back(GUINode.get_gfx_masked_flag_texture_from_node(pop_row_panel.get_node(^"./pop_movement_flag")))
+
+ _pop_list_size_change_icons.push_back(GUINode.get_gfx_sprite_texture_from_node(pop_row_panel.get_node(^"./growth_indicator")))
+
+ _pop_list_literacy_labels.push_back(GUINode.get_label_from_node(pop_row_panel.get_node(^"./pop_literacy")))
+
func _notification(what : int) -> void:
match what:
NOTIFICATION_TRANSLATION_CHANGED:
@@ -28,7 +380,225 @@ func _on_update_active_nation_management_screen(active_screen : NationManagement
func _update_info() -> void:
if _active:
- # TODO - update UI state
+ # Province list
+ _update_province_list()
+
+ # Pop filter buttons, Distributions, Pop list
+ _update_pops()
+
show()
else:
hide()
+
+func get_growth_icon_index(size_change : int) -> int:
+ return 1 + int(size_change <= 0) + int(size_change < 0)
+
+func _update_province_list(scroll_index : int = -1) -> void:
+ if not _province_listbox:
+ return
+
+ if scroll_index >= 0:
+ _province_listbox.set_scroll_index(scroll_index, false)
+
+ _province_list_scroll_index = _province_listbox.get_scroll_index()
+
+ var province_list_info_list : Array[Dictionary] = MenuSingleton.get_population_menu_province_list_rows(_province_list_scroll_index, _province_listbox.get_fixed_visible_items())
+
+ for index : int in province_list_info_list.size():
+ const type_key : StringName = &"type"
+ const index_key : StringName = &"index"
+ const name_key : StringName = &"name"
+ const size_key : StringName = &"size"
+ const change_key : StringName = &"change"
+ const selected_key : StringName = &"selected"
+ const expanded_key : StringName = &"expanded"
+ const colony_key : StringName = &"colony"
+
+ var province_list_info : Dictionary = province_list_info_list[index]
+
+ var type : MenuSingleton.ProvinceListEntry = province_list_info[type_key]
+
+ if _generate_province_list_row(index, type) != OK:
+ continue
+
+ if type == MenuSingleton.LIST_ENTRY_NONE or type != _province_list_types[index]:
+ continue
+
+ _province_list_indices[index] = province_list_info[index_key]
+
+ if _province_list_button_icons[index]:
+ _province_list_button_icons[index].set_icon_index(1 + int(province_list_info[selected_key]))
+
+ if _province_list_name_labels[index]:
+ _province_list_name_labels[index].set_text(
+ GUINode.format_province_name(province_list_info[name_key]) if type == MenuSingleton.LIST_ENTRY_PROVINCE
+ else province_list_info[name_key]
+ )
+
+ if _province_list_size_labels[index]:
+ _province_list_size_labels[index].set_text(GUINode.int_to_formatted_string(province_list_info[size_key]))
+
+ if _province_list_growth_icons[index]:
+ _province_list_growth_icons[index].set_icon_index(get_growth_icon_index(province_list_info[change_key]))
+
+ if type == MenuSingleton.LIST_ENTRY_STATE:
+ if _province_list_colony_buttons[index]:
+ _province_list_colony_buttons[index].set_visible(province_list_info[colony_key])
+
+ if _province_list_expand_icons[index]:
+ _province_list_expand_icons[index].set_icon_index(1 + int(province_list_info[expanded_key]))
+
+ # TODO - set _province_list_national_focus_icons[index]
+
+ # Clear any excess rows
+ for index : int in range(province_list_info_list.size(), _province_list_types.size()):
+ _generate_province_list_row(index, MenuSingleton.LIST_ENTRY_NONE)
+
+func _update_pops() -> void:
+ _update_pop_filters()
+ _update_distributions()
+ _update_pop_list()
+
+func _update_pop_filters() -> void:
+ var pop_filter_info_list : Array[Dictionary] = MenuSingleton.get_population_menu_pop_filter_info()
+
+ for index : int in pop_filter_info_list.size():
+ const pop_filter_count_key : StringName = &"count"
+ const pop_filter_change_key : StringName = &"change"
+ const pop_filter_selected_key : StringName = &"selected"
+
+ var pop_filter_info : Dictionary = pop_filter_info_list[index]
+
+ var pop_filter_button : Button = _pop_filter_buttons[index]
+ if not pop_filter_button:
+ continue
+ pop_filter_button.disabled = pop_filter_info[pop_filter_count_key] <= 0
+
+ const normal_theme : StringName = &"normal"
+ const hover_theme : StringName = &"hover"
+
+ if pop_filter_info[pop_filter_selected_key] or pop_filter_button.disabled:
+ pop_filter_button.get_theme_stylebox(normal_theme).set_texture(_pop_filter_icons[index])
+ pop_filter_button.get_theme_stylebox(hover_theme).set_texture(_pop_filter_hover_icons[index])
+ else:
+ pop_filter_button.get_theme_stylebox(normal_theme).set_texture(_pop_filter_selected_icons[index])
+ pop_filter_button.get_theme_stylebox(hover_theme).set_texture(_pop_filter_selected_icons[index])
+ # TODO - size and promotion/demotion change tooltip
+
+func _update_distributions():
+ const slice_identifier_key : StringName = &"identifier"
+ const slice_colour_key : StringName = &"colour"
+ const slice_weight_key : StringName = &"weight"
+
+ var distribution_info_list : Array[Array] = MenuSingleton.get_population_menu_distribution_info()
+
+ for distribution_index : int in distribution_info_list.size():
+ var distribution_info : Array[Dictionary] = distribution_info_list[distribution_index]
+
+ if _distribution_charts[distribution_index]:
+ _distribution_charts[distribution_index].set_slices_array(distribution_info)
+
+ if _distribution_lists[distribution_index]:
+ distribution_info.sort_custom(func(a : Dictionary, b : Dictionary) -> bool: return a[slice_weight_key] > b[slice_weight_key])
+
+ var list : GUIListBox = _distribution_lists[distribution_index]
+
+ list.clear_children(distribution_info.size())
+
+ while list.get_child_count() < distribution_info.size():
+ var child : Panel = GUINode.generate_gui_element(_scene_name, "pop_legend_item")
+ if not child:
+ break
+ child.set_mouse_filter(Control.MOUSE_FILTER_IGNORE)
+ list.add_child(child)
+
+ for list_index in min(list.get_child_count(), distribution_info.size()):
+
+ var child : Panel = list.get_child(list_index)
+
+ var distribution_row : Dictionary = distribution_info[list_index]
+
+ var colour_icon_rect : TextureRect = GUINode.get_texture_rect_from_node(child.get_node(^"./legend_color"))
+ if colour_icon_rect:
+ colour_icon_rect.set_modulate(distribution_row[slice_colour_key])
+
+ var identifier_label : Label = GUINode.get_label_from_node(child.get_node(^"./legend_title"))
+ if identifier_label:
+ identifier_label.set_text_overrun_behavior(TextServer.OVERRUN_TRIM_ELLIPSIS)
+ identifier_label.set_text(distribution_row[slice_identifier_key])
+
+ var weight_label : Label = GUINode.get_label_from_node(child.get_node(^"./legend_value"))
+ if weight_label:
+ weight_label.set_text("%s%%" % GUINode.float_to_formatted_string(distribution_row[slice_weight_key] * 100.0, 1))
+
+func _update_pop_list() -> void:
+ if _pop_list_scrollbar:
+ var max_scroll_index : int = MenuSingleton.get_population_menu_pop_row_count() - _pop_list_rows.size()
+ if max_scroll_index > 0:
+ _pop_list_scrollbar.set_limits(0, max_scroll_index)
+ _pop_list_scrollbar.show()
+ else:
+ _pop_list_scrollbar.set_limits(0, 0)
+ _pop_list_scrollbar.hide()
+
+ var pop_rows = MenuSingleton.get_population_menu_pop_rows(_pop_list_scroll_index, _pop_list_rows.size())
+
+ for index : int in _pop_list_rows.size():
+ if not _pop_list_rows[index]:
+ continue
+ if index < pop_rows.size():
+ const pop_size_key : StringName = &"size"
+ const pop_type_icon_key : StringName = &"pop_type_icon"
+ const pop_culture_key : StringName = &"culture"
+ const pop_religion_icon_key : StringName = &"religion_icon"
+ const pop_location_key : StringName = &"location"
+ const pop_militancy_key : StringName = &"militancy"
+ const pop_consciousness_key : StringName = &"consciousness"
+ const pop_ideology_key : StringName = &"ideology"
+ const pop_issues_key : StringName = &"issues"
+ const pop_unemployment_key : StringName = &"unemployment"
+ const pop_cash_key : StringName = &"cash"
+ const pop_life_needs_key : StringName = &"life_needs"
+ const pop_everyday_needs_key : StringName = &"everyday_needs"
+ const pop_luxury_needs_key : StringName = &"luxury_needs"
+ const pop_size_change_key : StringName = &"size_change"
+ const pop_literacy_key : StringName = &"literacy"
+
+ var pop_row : Dictionary = pop_rows[index]
+
+ if _pop_list_size_labels[index]:
+ _pop_list_size_labels[index].set_text(GUINode.int_to_formatted_string(pop_row[pop_size_key]))
+ if _pop_list_type_icons[index]:
+ _pop_list_type_icons[index].set_icon_index(pop_row[pop_type_icon_key])
+ if _pop_list_culture_labels[index]:
+ _pop_list_culture_labels[index].set_text(pop_row[pop_culture_key])
+ if _pop_list_religion_icons[index]:
+ _pop_list_religion_icons[index].set_icon_index(pop_row[pop_religion_icon_key])
+ if _pop_list_location_labels[index]:
+ _pop_list_location_labels[index].set_text(GUINode.format_province_name(pop_row[pop_location_key]))
+ if _pop_list_militancy_labels[index]:
+ _pop_list_militancy_labels[index].set_text(GUINode.float_to_formatted_string(pop_row[pop_militancy_key], 2))
+ if _pop_list_consciousness_labels[index]:
+ _pop_list_consciousness_labels[index].set_text(GUINode.float_to_formatted_string(pop_row[pop_consciousness_key], 2))
+ if _pop_list_ideology_charts[index]:
+ _pop_list_ideology_charts[index].set_slices_array(pop_row[pop_ideology_key])
+ if _pop_list_issues_charts[index]:
+ _pop_list_issues_charts[index].set_slices_array(pop_row[pop_issues_key])
+ if _pop_list_unemployment_progressbars[index]:
+ _pop_list_unemployment_progressbars[index].set_value_no_signal(pop_row[pop_unemployment_key])
+ if _pop_list_cash_labels[index]:
+ _pop_list_cash_labels[index].set_text(GUINode.float_to_formatted_string(pop_row[pop_cash_key], 2))
+ if _pop_list_life_needs_progressbars[index]:
+ _pop_list_life_needs_progressbars[index].set_value_no_signal(pop_row[pop_life_needs_key])
+ if _pop_list_everyday_needs_progressbars[index]:
+ _pop_list_everyday_needs_progressbars[index].set_value_no_signal(pop_row[pop_everyday_needs_key])
+ if _pop_list_luxury_needs_progressbars[index]:
+ _pop_list_luxury_needs_progressbars[index].set_value_no_signal(pop_row[pop_luxury_needs_key])
+ if _pop_list_size_change_icons[index]:
+ _pop_list_size_change_icons[index].set_icon_index(get_growth_icon_index(pop_row[pop_size_change_key]))
+ if _pop_list_literacy_labels[index]:
+ _pop_list_literacy_labels[index].set_text("%s%%" % GUINode.float_to_formatted_string(pop_row[pop_literacy_key], 2))
+
+ _pop_list_rows[index].show()
+ else:
+ _pop_list_rows[index].hide()
diff --git a/game/src/Game/GameSession/ProvinceOverviewPanel.gd b/game/src/Game/GameSession/ProvinceOverviewPanel.gd
index 731d02c..13e7111 100644
--- a/game/src/Game/GameSession/ProvinceOverviewPanel.gd
+++ b/game/src/Game/GameSession/ProvinceOverviewPanel.gd
@@ -166,6 +166,15 @@ func _ready() -> void:
_pop_types_piechart = get_gfx_pie_chart_texture_from_nodepath(^"./province_view/province_statistics/workforce_chart")
_pop_ideologies_piechart = get_gfx_pie_chart_texture_from_nodepath(^"./province_view/province_statistics/ideology_chart")
_pop_cultures_piechart = get_gfx_pie_chart_texture_from_nodepath(^"./province_view/province_statistics/culture_chart")
+ var population_menu_button : Button = get_button_from_nodepath(^"./province_view/province_statistics/open_popscreen")
+ if population_menu_button:
+ population_menu_button.pressed.connect(
+ func() -> void:
+ pass
+ MenuSingleton.population_menu_select_province(_selected_index)
+ _on_close_button_pressed()
+ Events.NationManagementScreens.open_nation_management_screen(NationManagement.Screen.POPULATION)
+ )
_supply_limit_label = get_label_from_nodepath(^"./province_view/province_statistics/supply_limit_label")
_cores_overlapping_elements_box = get_gui_overlapping_elements_box_from_nodepath(^"./province_view/province_statistics/core_icons")
if _cores_overlapping_elements_box and _cores_overlapping_elements_box.set_gui_child_element_name("province_interface", "province_core") != OK:
diff --git a/game/src/Game/GameSession/TerrainMap.gdshader b/game/src/Game/GameSession/TerrainMap.gdshader
index 98f9efd..467e277 100644
--- a/game/src/Game/GameSession/TerrainMap.gdshader
+++ b/game/src/Game/GameSession/TerrainMap.gdshader
@@ -34,37 +34,87 @@ uniform sampler2D colormap_water_tex: repeat_enable, filter_linear;
// Overlay map tint
uniform sampler2D colormap_overlay_tex: repeat_enable, filter_linear;
-struct terrain_args_t {
- vec2 uv, half_pixel_size; // Components for calculating terrain sampling UV
+struct corner_args_t {
+ vec2 uv, half_pixel_size; // Components for calculating a corner's sampling UV
vec2 terrain_uv; // UV coordinates scaled for terrain texture tiling
vec3 land_tint_colour, water_tint_colour; // Colours for tinting the terrain
+ float stripe_mask; // Weight for mixing base and stripe province colours
+};
+
+struct corner_ret_t {
+ vec3 terrain_colour;
+ vec4 province_colour;
+ float highlight_mix_val;
};
// Calculate terrain colour at the specified corner of the current pixel
-vec3 get_terrain_colour(const terrain_args_t terrain_args, const vec2 corner) {
+corner_ret_t get_corner_colour(const corner_args_t corner_args, const vec2 corner) {
+ corner_ret_t ret;
+
+ uvec3 province_data = read_uvec3(fma(corner, corner_args.half_pixel_size, corner_args.uv));
+
// Find the terrain index at the specified corner of the current pixel
- uint terrain_index = read_uvec3(fma(corner, terrain_args.half_pixel_size, terrain_args.uv)).z;
+ uint terrain_index = province_data.z;
// Get the tinted land colour at the current position
- vec3 land_colour = texture(terrain_tex, vec3(terrain_args.terrain_uv, float(terrain_index))).rgb;
- land_colour = mix(land_colour, terrain_args.land_tint_colour, 0.3);
+ vec3 land_colour = texture(terrain_tex, vec3(corner_args.terrain_uv, float(terrain_index))).rgb;
+ land_colour = mix(land_colour, corner_args.land_tint_colour, 0.3);
// TODO - proper water texture
- vec3 water_colour = terrain_args.water_tint_colour;
+ vec3 water_colour = corner_args.water_tint_colour;
// Select land or water colour based on the terrain index (0 is water, otherwise land)
- vec3 terrain_colour = mix(land_colour, water_colour, float(terrain_index == 0u));
+ ret.terrain_colour = mix(land_colour, water_colour, float(terrain_index == 0u));
+
+ uint province_index = uvec2_to_uint(province_data.xy);
+
+ // Get base and stripe colours for province at the current position
+ province_data.x *= 2u; // Double "x coordinate" as colours come in (base, stripe) pairs
+ vec4 province_base_colour = texelFetch(province_colour_tex, ivec2(province_data.xy), 0);
+
+ province_data.x += 1u; // Add 1 to "x coordinate" to move from base to strip colour
+ vec4 province_stripe_colour = texelFetch(province_colour_tex, ivec2(province_data.xy), 0);
+
+ // Blend the base and stripe colours according to the current position's stripe mask value
+ ret.province_colour = mix(province_base_colour, province_stripe_colour, corner_args.stripe_mask);
+
+ ret.province_colour = mix(ret.province_colour, vec4(corner_args.water_tint_colour, 0.0), float(terrain_index == 0u));
+
+ ret.highlight_mix_val = 0.4 * (
+ float(province_index == hover_index) + float(province_index == selected_index)
+ ) * float(province_index != 0u);
- return terrain_colour;
+ return ret;
}
// Blend together terrain colours from the four corners of the current pixel
-vec3 mix_terrain_colour(const terrain_args_t terrain_args, const vec2 pixel_offset) {
- return mix(
- mix(get_terrain_colour(terrain_args, vec2(-1, -1)), get_terrain_colour(terrain_args, vec2(+1, -1)), pixel_offset.x),
- mix(get_terrain_colour(terrain_args, vec2(-1, +1)), get_terrain_colour(terrain_args, vec2(+1, +1)), pixel_offset.x),
+corner_ret_t mix_terrain_colour(const corner_args_t corner_args, const vec2 pixel_offset) {
+ corner_ret_t mm = get_corner_colour(corner_args, vec2(-1, -1));
+ corner_ret_t pm = get_corner_colour(corner_args, vec2(+1, -1));
+ corner_ret_t mp = get_corner_colour(corner_args, vec2(-1, +1));
+ corner_ret_t pp = get_corner_colour(corner_args, vec2(+1, +1));
+
+ corner_ret_t ret;
+
+ ret.terrain_colour = mix(
+ mix(mm.terrain_colour, pm.terrain_colour, pixel_offset.x),
+ mix(mp.terrain_colour, pp.terrain_colour, pixel_offset.x),
+ pixel_offset.y
+ );
+
+ ret.province_colour = mix(
+ mix(mm.province_colour, pm.province_colour, pixel_offset.x),
+ mix(mp.province_colour, pp.province_colour, pixel_offset.x),
+ pixel_offset.y
+ );
+
+ ret.highlight_mix_val = mix(
+ mix(mm.highlight_mix_val, pm.highlight_mix_val, pixel_offset.x),
+ mix(mp.highlight_mix_val, pp.highlight_mix_val, pixel_offset.x),
pixel_offset.y
);
+
+ return ret;
}
// Mix overlay and base colours, used for the parchment map
@@ -84,41 +134,33 @@ vec3 get_map_colour(vec2 uv) {
// Offset of uv_map_pixels from the top left corner of the current pixel
vec2 pixel_offset = fract(uv_map_pixels);
- terrain_args_t terrain_args;
- terrain_args.uv = uv;
- terrain_args.half_pixel_size = 0.49 / map_size;
+ corner_args_t corner_args;
+ corner_args.uv = uv;
+ corner_args.half_pixel_size = 0.49 / map_size;
// Terrain texture tiling UV
- terrain_args.terrain_uv = 0.5 - uv_map_pixels * terrain_tile_factor;
+ corner_args.terrain_uv = 0.5 - uv_map_pixels * terrain_tile_factor;
+
+ vec2 stripe_uv = uv_map_pixels * stripe_tile_factor;
+ // Stripe mask value - between 0 (base) and 1 (stripe)
+ corner_args.stripe_mask = texture(stripe_tex, stripe_uv).b;
vec2 colormap_uv = vec2(uv.x, 1.0 - uv.y);
// Terrain tinting colours
- terrain_args.land_tint_colour = texture(colormap_land_tex, colormap_uv).rgb;
- terrain_args.water_tint_colour = texture(colormap_water_tex, colormap_uv).rgb;
+ corner_args.land_tint_colour = texture(colormap_land_tex, colormap_uv).rgb;
+ corner_args.water_tint_colour = texture(colormap_water_tex, colormap_uv).rgb;
// Parchment tint colour
vec3 overlay_tint_colour = texture(colormap_overlay_tex, colormap_uv).rgb;
- // Blended terrain colour (average of four corners of current pixel)
- vec3 terrain_colour = mix_terrain_colour(terrain_args, pixel_offset);
+ corner_ret_t colours = mix_terrain_colour(corner_args, pixel_offset);
- vec2 stripe_uv = uv_map_pixels * stripe_tile_factor;
- // Stripe mask value - between 0 (base) and 1 (stripe)
- float stripe_mask = texture(stripe_tex, stripe_uv).b;
+ // Blended terrain colour (average of four corners of current pixel)
+ vec3 terrain_colour = colours.terrain_colour;
vec2 overlay_uv = vec2(uv_map_pixels.x, map_size.y - uv_map_pixels.y) * overlay_tile_factor;
// Parchment overlay colour
vec3 overlay_colour = texture(overlay_tex, overlay_uv).rgb;
- // Current province index as a pair of byte coordinates and as a combined 16 bit value
- uvec2 province_data = read_uvec3(uv).xy;
- uint province_index = uvec2_to_uint(province_data);
-
- // Get base and stripe colours for province at the current position
- province_data.x *= 2u; // Double "x coordinate" as colours come in (base, stripe) pairs
- vec4 province_base_colour = texelFetch(province_colour_tex, ivec2(province_data), 0);
- province_data.x += 1u; // Add 1 to "x coordinate" to move from base to strip colour
- vec4 province_stripe_colour = texelFetch(province_colour_tex, ivec2(province_data), 0);
- // Blend the base and stripe colours according to the current position's stripe mask value
- vec4 province_colour = mix(province_base_colour, province_stripe_colour, stripe_mask);
+ vec4 province_colour = colours.province_colour;
// Darken the province colour
province_colour.rgb -= 0.7;
@@ -129,22 +171,21 @@ vec3 get_map_colour(vec2 uv) {
// Near colour is either the terrain's luma component tinted with the province colour and brightened,
// or the normal terrain colour
vec3 near_province_colour = mix(vec3(terrain_luma), province_colour.rgb, 0.3) * 1.5;
- vec3 near_colour = mix(near_province_colour, terrain_colour, float(province_colour.a == 0.0));
+ vec3 near_colour = mix(terrain_colour, near_province_colour, province_colour.a);
// Far colour is either the province colour mixed with the overlay texture, tinted with the overlay colormap and brightened,
// or the normal terrain colour mixed with the overlay texture (primarily for water)
vec3 far_province_colour = mix_overlay(overlay_colour, province_colour.rgb);
far_province_colour = mix(overlay_tint_colour, far_province_colour, 0.3) * 1.5;
vec3 far_terrain_colour = mix_overlay(overlay_colour, terrain_colour);
- vec3 far_colour = mix(far_province_colour, far_terrain_colour, float(province_colour.a == 0.0));
+ vec3 far_colour = mix(far_terrain_colour, far_province_colour, province_colour.a);
// Blend the near (detailed terrain) and far (parchment) colours according to the parchment mix factor (0 for near, 1 for far)
vec3 final_colour = mix(near_colour, far_colour, parchment_mix);
// Significantly brighted the colour if it is hovered over and/or selected, but not if it has province index 0 (all invalid pixels)
const vec3 highlight_colour = vec3(1.0);
- float highlight_mix_val = 0.4 * (float(province_index == hover_index) + float(province_index == selected_index)) * float(province_index != 0u);
- vec3 highlighted_colour = mix(final_colour, highlight_colour, highlight_mix_val);
+ vec3 highlighted_colour = mix(final_colour, highlight_colour, colours.highlight_mix_val);
return highlighted_colour;
}