From 8b13ba1d7d114101cbb600da776017cdfb2c0562 Mon Sep 17 00:00:00 2001 From: Voyager Date: Mon, 24 Aug 2026 12:01:33 -0400 Subject: [PATCH] Normalize logbook creature portraits --- tests/logbook_validation.gd | 34 +++++++++++++++++++-- ui/components/logbook_portrait.gd | 51 +++++++++++++++++++++++++++++++ ui/logbook_page.gd | 9 ++++-- 3 files changed, 90 insertions(+), 4 deletions(-) diff --git a/tests/logbook_validation.gd b/tests/logbook_validation.gd index a621a8a..74736fa 100644 --- a/tests/logbook_validation.gd +++ b/tests/logbook_validation.gd @@ -162,6 +162,8 @@ func _validate_page() -> void: var shared_material: Material var silhouette_count: int = 0 + var smallest_silhouette_area: float = INF + var largest_silhouette_area: float = 0.0 for category: LogbookCatalog.Category in [ LogbookCatalog.Category.FRESH_WATER, LogbookCatalog.Category.SALT_WATER, @@ -192,8 +194,15 @@ func _validate_page() -> void: assert(portrait != null) assert(portrait.source_texture == fish.display_texture) assert( - portrait.custom_minimum_size - == LogbookPage.CATALOG_PORTRAIT_SIZE + portrait.custom_minimum_size.x + <= LogbookPage.CATALOG_PORTRAIT_SIZE.x + and portrait.custom_minimum_size.y + <= LogbookPage.CATALOG_PORTRAIT_SIZE.y + ) + assert(portrait.get_parent() is CenterContainer) + assert( + (portrait.get_parent() as CenterContainer).custom_minimum_size + == LogbookPage.CATALOG_PORTRAIT_SIZE ) assert( portrait.expand_mode @@ -209,6 +218,19 @@ func _validate_page() -> void: else: assert(portrait.material == shared_material) assert(_texture_has_transparency(portrait.texture)) + var silhouette_area: float = ( + portrait.custom_minimum_size.x + * portrait.custom_minimum_size.y + ) + assert(silhouette_area > 0.0) + smallest_silhouette_area = minf( + smallest_silhouette_area, + silhouette_area, + ) + largest_silhouette_area = maxf( + largest_silhouette_area, + silhouette_area, + ) silhouette_count += 1 for candidate: FishDataType in CatalogResource.candidates: assert(not entry.text.contains(candidate.display_name)) @@ -223,6 +245,9 @@ func _validate_page() -> void: ) ) assert(silhouette_count == 310) + assert( + largest_silhouette_area / smallest_silhouette_area <= 1.12 + ) page.call("_select_category", LogbookCatalog.Category.SHELLFISH) await create_timer(0.25).timeout @@ -269,6 +294,11 @@ func _validate_page() -> void: assert(known_portrait != null) assert(known_portrait.source_texture == bluegill.display_texture) assert(known_portrait.material == null) + assert(known_portrait.get_parent() is CenterContainer) + assert( + (known_portrait.get_parent() as CenterContainer).custom_minimum_size + == LogbookPage.CATALOG_PORTRAIT_SIZE + ) assert(known.button_pressed) _validate_handwritten_logbook_font(page) diff --git a/ui/components/logbook_portrait.gd b/ui/components/logbook_portrait.gd index ef23922..fb5fa4a 100644 --- a/ui/components/logbook_portrait.gd +++ b/ui/components/logbook_portrait.gd @@ -3,6 +3,7 @@ extends TextureRect const ENTRY_FRAME_SIZE := Vector2(86.0, 40.0) const DETAIL_FRAME_SIZE := Vector2(240.0, 132.0) +const UNIFORM_FOOTPRINT_AREA_RATIO: float = 0.6 static var _normalized_textures: Dictionary[String, Texture2D] = {} @@ -52,6 +53,53 @@ func configure_fitted( custom_minimum_size = texture_size * fit_scale +func configure_uniform_footprint( + portrait_texture: Texture2D, + maximum_size: Vector2, + portrait_material: Material = null, +) -> void: + source_texture = portrait_texture + material = portrait_material + texture = _normalize_visible_bounds(portrait_texture) + if texture == null: + custom_minimum_size = Vector2.ZERO + return + custom_minimum_size = uniform_footprint_size( + texture.get_size(), + maximum_size, + ) + + +static func uniform_footprint_size( + visible_size: Vector2, + maximum_size: Vector2, +) -> Vector2: + if ( + visible_size.x <= 0.0 + or visible_size.y <= 0.0 + or maximum_size.x <= 0.0 + or maximum_size.y <= 0.0 + ): + return Vector2.ZERO + var target_area: float = ( + maximum_size.x + * maximum_size.y + * UNIFORM_FOOTPRINT_AREA_RATIO + ) + var area_scale: float = sqrt( + target_area / (visible_size.x * visible_size.y) + ) + var fit_scale: float = minf( + maximum_size.x / visible_size.x, + maximum_size.y / visible_size.y, + ) + var scale: float = minf(area_scale, fit_scale) + return Vector2( + minf(maximum_size.x, maxf(1.0, roundf(visible_size.x * scale))), + minf(maximum_size.y, maxf(1.0, roundf(visible_size.y * scale))), + ) + + static func _normalize_visible_bounds( portrait_texture: Texture2D, ) -> Texture2D: @@ -67,6 +115,9 @@ static func _normalize_visible_bounds( if image == null or image.is_empty(): _normalized_textures[cache_key] = portrait_texture return portrait_texture + if image.is_compressed() and image.decompress() != OK: + _normalized_textures[cache_key] = portrait_texture + return portrait_texture var full_rect := Rect2i(Vector2i.ZERO, image.get_size()) var visible_rect: Rect2i = image.get_used_rect() if visible_rect.size == Vector2i.ZERO or visible_rect == full_rect: diff --git a/ui/logbook_page.gd b/ui/logbook_page.gd index a79239d..c5528e4 100644 --- a/ui/logbook_page.gd +++ b/ui/logbook_page.gd @@ -666,13 +666,18 @@ func _add_entry_content( content.add_theme_constant_override("separation", 4) content_margin.add_child(content) + var portrait_frame := CenterContainer.new() + portrait_frame.custom_minimum_size = CATALOG_PORTRAIT_SIZE + portrait_frame.mouse_filter = Control.MOUSE_FILTER_IGNORE + content.add_child(portrait_frame) + var portrait_view := LogbookPortraitType.new() - portrait_view.configure( + portrait_view.configure_uniform_footprint( portrait, CATALOG_PORTRAIT_SIZE, _silhouette_material if unknown else null, ) - content.add_child(portrait_view) + portrait_frame.add_child(portrait_view) var name_label := _label(_entry_label_text(entry_name), 16) name_label.custom_minimum_size.y = 38.0