Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 46 additions & 0 deletions Tests/Unit/layered_portrait_coverage_test.gd
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
class_name LayeredPortraitCoverageTest
extends GdUnitTestSuite


func test_coverage_uses_local_transforms_before_entering_tree() -> void:
var portrait := CanvasGroup.new()
portrait.set_script(preload(
"res://addons/dialogic/Modules/LayeredPortrait/layered_portrait.gd"
))
# Reproduce the invalid preview transform reported after selecting an empty
# portrait. Coverage must depend only on transforms below the portrait root.
portrait.position = Vector2(INF, INF)
var layer := Node2D.new()
layer.position = Vector2(30, 20)
portrait.add_child(layer)

var sprite := Sprite2D.new()
sprite.texture = ImageTexture.create_from_image(
Image.create(20, 10, false, Image.FORMAT_RGBA8)
)
sprite.position = Vector2(5, 7)
layer.add_child(sprite)

var coverage: Rect2 = portrait._find_largest_coverage_rect()
assert_bool(coverage.position.is_finite()).is_true()
assert_bool(coverage.size.is_finite()).is_true()
assert_vector(coverage.size).is_equal(Vector2(20, 10))
portrait.free()


func test_coverage_includes_scaled_and_rotated_sprite_corners() -> void:
var portrait := CanvasGroup.new()
portrait.set_script(preload(
"res://addons/dialogic/Modules/LayeredPortrait/layered_portrait.gd"
))
var sprite := Sprite2D.new()
sprite.texture = ImageTexture.create_from_image(
Image.create(20, 10, false, Image.FORMAT_RGBA8)
)
sprite.scale = Vector2(2, 1)
sprite.rotation = PI / 2.0
portrait.add_child(sprite)

var coverage: Rect2 = portrait._find_largest_coverage_rect()
assert_vector(coverage.size).is_equal_approx(Vector2(10, 40), Vector2(0.001, 0.001))
portrait.free()
40 changes: 25 additions & 15 deletions addons/dialogic/Modules/LayeredPortrait/layered_portrait.gd
Original file line number Diff line number Diff line change
Expand Up @@ -215,24 +215,34 @@ func _find_largest_coverage_rect() -> Rect2:
return _cached_coverage_rect

var coverage_rect := Rect2(0, 0, 0, 0)
var has_coverage := false

for sprite: Sprite2D in _find_sprites_recursively(self):
var sprite_size := sprite.get_rect().size
var sprite_position: Vector2 = sprite.global_position-self.global_position

if sprite.centered:
sprite_position -= sprite_size/2

var sprite_width := sprite_size.x * sprite.scale.x
var sprite_height := sprite_size.y * sprite.scale.y

var texture_rect := Rect2(
sprite_position.x,
sprite_position.y,
sprite_width,
sprite_height
# Global transforms can be invalid for tool nodes while the editor is
# rebuilding a portrait preview. Build the transform from local values so
# coverage stays finite even before the nodes enter the scene tree.
var relative_transform := sprite.transform
var parent := sprite.get_parent()
while parent != self:
if parent is Node2D:
relative_transform = parent.transform * relative_transform
parent = parent.get_parent()

var sprite_rect := sprite.get_rect()
var first_corner := relative_transform * sprite_rect.position
var texture_rect := Rect2(first_corner, Vector2.ZERO)
texture_rect = texture_rect.expand(relative_transform * sprite_rect.end)
texture_rect = texture_rect.expand(
relative_transform * Vector2(sprite_rect.end.x, sprite_rect.position.y)
)
texture_rect = texture_rect.expand(
relative_transform * Vector2(sprite_rect.position.x, sprite_rect.end.y)
)
coverage_rect = coverage_rect.merge(texture_rect)
if has_coverage:
coverage_rect = coverage_rect.merge(texture_rect)
else:
coverage_rect = texture_rect
has_coverage = true

coverage_rect.position = _reposition_with_rect(coverage_rect)

Expand Down