55 lines
1.9 KiB
GDScript
55 lines
1.9 KiB
GDScript
extends RefCounted
|
|
|
|
# Cache one simplified silhouette per texture, shared by all ships of that type.
|
|
static var _silhouettes: Dictionary = {}
|
|
|
|
static func attach_to(sprite: Sprite2D) -> void:
|
|
if sprite.texture == null:
|
|
return
|
|
sprite.light_mask = 2
|
|
if sprite.has_node("ShipShadow"):
|
|
return
|
|
var texture := sprite.texture
|
|
var key := texture.get_instance_id()
|
|
if not _silhouettes.has(key):
|
|
var image := texture.get_image()
|
|
if image == null or image.is_empty():
|
|
return
|
|
if image.is_compressed():
|
|
image.decompress()
|
|
var original_size := Vector2(image.get_size())
|
|
var factor := minf(1.0, 128.0 / maxf(original_size.x, original_size.y))
|
|
image.resize(maxi(1, roundi(original_size.x * factor)), maxi(1, roundi(original_size.y * factor)), Image.INTERPOLATE_BILINEAR)
|
|
var bitmap := BitMap.new()
|
|
bitmap.create_from_image_alpha(image, 0.25)
|
|
var polygons := bitmap.opaque_to_polygons(Rect2i(Vector2i.ZERO, image.get_size()), 1.5)
|
|
var silhouette := PackedVector2Array()
|
|
var largest_area := 0.0
|
|
for polygon in polygons:
|
|
var area := _polygon_area(polygon)
|
|
if area > largest_area:
|
|
largest_area = area
|
|
silhouette = polygon
|
|
var image_scale := original_size / Vector2(image.get_size())
|
|
for index in silhouette.size():
|
|
silhouette[index] = silhouette[index] * image_scale - original_size * 0.5
|
|
_silhouettes[key] = silhouette
|
|
var points: PackedVector2Array = _silhouettes[key]
|
|
if points.size() < 3:
|
|
return
|
|
var polygon := OccluderPolygon2D.new()
|
|
polygon.polygon = points
|
|
polygon.cull_mode = OccluderPolygon2D.CULL_DISABLED
|
|
var occluder := LightOccluder2D.new()
|
|
occluder.name = "ShipShadow"
|
|
occluder.occluder = polygon
|
|
occluder.occluder_light_mask = 1
|
|
occluder.show_behind_parent = true
|
|
sprite.add_child(occluder)
|
|
|
|
static func _polygon_area(points: PackedVector2Array) -> float:
|
|
var area := 0.0
|
|
for index in points.size():
|
|
area += points[index].cross(points[(index + 1) % points.size()])
|
|
return absf(area) * 0.5
|