Skip to content

Commit

Permalink
Smooth province edges and zoom tweaks
Browse files Browse the repository at this point in the history
  • Loading branch information
Hop311 committed Apr 22, 2024
1 parent 747ccf4 commit 4af4638
Show file tree
Hide file tree
Showing 3 changed files with 100 additions and 49 deletions.
4 changes: 4 additions & 0 deletions game/project.godot
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
26 changes: 16 additions & 10 deletions game/src/Game/GameSession/MapView.gd
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
class_name MapView
extends Node3D

signal map_view_camera_changed(near_left : Vector2, far_left : Vector2, far_right : Vector2, near_right : Vector2)
Expand All @@ -22,7 +23,7 @@ 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_epsilon : float = _zoom_target_step * 0.005
Expand Down Expand Up @@ -119,6 +120,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)
Expand Down Expand Up @@ -149,12 +154,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!")
Expand Down Expand Up @@ -242,7 +248,7 @@ func _zoom_process(delta : float) -> void:

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, -1.25 * exp(-1.5 * _camera.position.y - _zoom_target_min))
_camera.look_at(_camera.position + dir, up)

func _update_minimap_viewport() -> void:
Expand All @@ -253,9 +259,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:
Expand Down
119 changes: 80 additions & 39 deletions game/src/Game/GameSession/TerrainMap.gdshader
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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;

Expand All @@ -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;
}
Expand Down

0 comments on commit 4af4638

Please sign in to comment.