93 lines
3.8 KiB
GDScript
93 lines
3.8 KiB
GDScript
@tool
|
|
extends Object
|
|
class_name SVSSceneExporter
|
|
|
|
|
|
static func export_image(export_root_node : Node, stored_box_ref : Dictionary[String, Vector2] = {},
|
|
render_parent := Node.new(), forward_aa := true) -> Image:
|
|
var sub_viewport := SubViewport.new()
|
|
render_parent.add_child(sub_viewport)
|
|
sub_viewport.transparent_bg = true
|
|
sub_viewport.render_target_update_mode = SubViewport.UPDATE_ONCE
|
|
var copied : Node = export_root_node.duplicate()
|
|
sub_viewport.add_child(copied)
|
|
var box = copied.get_bounding_box() if copied is ScalableVectorShape2D else [Vector2.ZERO]
|
|
var child_list := copied.get_children()
|
|
var min_x = box.map(func(corner): return corner.x).min()
|
|
var min_y = box.map(func(corner): return corner.y).min()
|
|
var max_x = box.map(func(corner): return corner.x).max()
|
|
var max_y = box.map(func(corner): return corner.y).max()
|
|
|
|
while child_list.size() > 0:
|
|
var child : Node = child_list.pop_back()
|
|
if child is Camera2D:
|
|
child.enabled = false
|
|
child_list.append_array(child.get_children())
|
|
if child is ScalableVectorShape2D:
|
|
var box1 = child.get_bounding_box()
|
|
var min_x1 = box1.map(func(corner): return corner.x).min()
|
|
var min_y1 = box1.map(func(corner): return corner.y).min()
|
|
var max_x1 = box1.map(func(corner): return corner.x).max()
|
|
var max_y1 = box1.map(func(corner): return corner.y).max()
|
|
min_x = floori(min_x if min_x1 > min_x else min_x1)
|
|
min_y = floori(min_y if min_y1 > min_y else min_y1)
|
|
max_x = ceili(max_x if max_x1 < max_x else max_x1)
|
|
max_y = ceili(max_y if max_y1 < max_y else max_y1)
|
|
sub_viewport.canvas_transform.origin = -Vector2(min_x, min_y)
|
|
sub_viewport.size = Vector2(max_x, max_y) - Vector2(min_x, min_y)
|
|
if forward_aa:
|
|
sub_viewport.msaa_2d = Viewport.MSAA_8X
|
|
else:
|
|
sub_viewport.screen_space_aa = Viewport.SCREEN_SPACE_AA_FXAA
|
|
|
|
stored_box_ref["tl"] = Vector2(min_x, min_y)
|
|
stored_box_ref["br"] = Vector2(max_x, max_y)
|
|
await RenderingServer.frame_post_draw
|
|
var img = sub_viewport.get_texture().get_image()
|
|
sub_viewport.queue_free()
|
|
return img
|
|
|
|
|
|
static func export_sprite_frames(root_node : Node,
|
|
animation_player : AnimationPlayer,
|
|
anim_name : String, fps : int,
|
|
render_parent : Node, on_progress : Callable,
|
|
forward_aa := false) -> Array[Image]:
|
|
var interval := 1.0 / fps
|
|
animation_player.stop()
|
|
animation_player.current_animation = anim_name
|
|
animation_player.get_animation(anim_name)
|
|
var boxes : Array[Dictionary] = []
|
|
var images : Array[Image] = []
|
|
var frame_count := ceili(animation_player.current_animation_length / interval)
|
|
if on_progress:
|
|
on_progress.call("Rendering animation %s at %d fps to %d frames" % [anim_name, fps, frame_count])
|
|
# Render each frame into an image
|
|
for idx in range(frame_count):
|
|
var pos = idx * interval
|
|
if pos > animation_player.current_animation_length:
|
|
pos = animation_player.current_animation_length
|
|
animation_player.seek(pos, true)
|
|
animation_player.pause()
|
|
var box : Dictionary[String, Vector2] = {}
|
|
var im = await export_image(root_node, box, render_parent, forward_aa)
|
|
boxes.append(box)
|
|
images.append(im)
|
|
animation_player.stop()
|
|
|
|
# Determine the bounding box into which all the rendered images would fit
|
|
var min_x = boxes.map(func(box): return box["tl"].x).min()
|
|
var min_y = boxes.map(func(box): return box["tl"].y).min()
|
|
var max_x = boxes.map(func(box): return box["br"].x).max()
|
|
var max_y = boxes.map(func(box): return box["br"].y).max()
|
|
var return_list : Array[Image] = []
|
|
|
|
# rerender and realign the images such that they all have the same size
|
|
for idx in images.size():
|
|
var im : Image = Image.create_empty(ceili(max_x) - floori(min_x), ceili(max_y) - floor(min_y), false, images[idx].get_format())
|
|
for x in images[idx].get_size().x:
|
|
for y in images[idx].get_size().y:
|
|
im.set_pixel(floori(boxes[idx]["tl"].x) - min_x + x, floori(boxes[idx]["tl"].y) - min_y + y, images[idx].get_pixel(x, y))
|
|
return_list.append(im)
|
|
return return_list
|