mirror of
https://github.com/tonytins/dressupzack
synced 2025-06-25 08:04:43 -04:00
Further simplified design
- Removed a tone of bloat - Use simple arrows to scroll through items instead of drag-and-drop
This commit is contained in:
parent
3097f5063a
commit
6d75d04fc3
40 changed files with 1610 additions and 1161 deletions
Binary file not shown.
Before Width: | Height: | Size: 913 B |
|
@ -1,34 +0,0 @@
|
|||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://bnkl8rujlgv0h"
|
||||
path="res://.godot/imported/Checker.png-95b82ca4c05ab143e1e16c56d598421b.ctex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://addons/SpritesheetGenerator/Checker.png"
|
||||
dest_files=["res://.godot/imported/Checker.png-95b82ca4c05ab143e1e16c56d598421b.ctex"]
|
||||
|
||||
[params]
|
||||
|
||||
compress/mode=0
|
||||
compress/high_quality=false
|
||||
compress/lossy_quality=0.7
|
||||
compress/hdr_compression=1
|
||||
compress/normal_map=0
|
||||
compress/channel_pack=0
|
||||
mipmaps/generate=false
|
||||
mipmaps/limit=-1
|
||||
roughness/mode=0
|
||||
roughness/src_normal=""
|
||||
process/fix_alpha_border=true
|
||||
process/premult_alpha=false
|
||||
process/normal_map_invert_y=false
|
||||
process/hdr_as_srgb=false
|
||||
process/hdr_clamp_exposure=false
|
||||
process/size_limit=0
|
||||
detect_3d/compress_to=1
|
|
@ -1,13 +0,0 @@
|
|||
@tool
|
||||
extends EditorPlugin
|
||||
|
||||
func _enter_tree() -> void:
|
||||
add_tool_menu_item("Open Spritesheet Generator", run_generator)
|
||||
get_editor_interface().get_command_palette().add_command("Open Spritesheet Generator", "addons/open_spritesheet_generator", run_generator)
|
||||
|
||||
func _exit_tree() -> void:
|
||||
remove_tool_menu_item("Open Spritesheet Generator")
|
||||
get_editor_interface().get_command_palette().remove_command("addons/open_spritesheet_generator")
|
||||
|
||||
func run_generator():
|
||||
get_editor_interface().play_custom_scene("res://addons/SpritesheetGenerator/SpritesheetGenerator.tscn")
|
|
@ -1,77 +0,0 @@
|
|||
[gd_scene load_steps=3 format=3 uid="uid://cd5wndu01c1sn"]
|
||||
|
||||
[sub_resource type="StyleBoxFlat" id="2"]
|
||||
resource_local_to_scene = true
|
||||
bg_color = Color(0, 0.501961, 0.501961, 1)
|
||||
|
||||
[sub_resource type="GDScript" id="3"]
|
||||
resource_name = "Prefab"
|
||||
script/source = "extends PanelContainer
|
||||
|
||||
var odd: Vector2
|
||||
|
||||
func set_frame_margin(margin: Vector2):
|
||||
$MarginContainer.add_theme_constant_override(&\"margin_left\", margin.x)
|
||||
$MarginContainer.add_theme_constant_override(&\"margin_top\", margin.y)
|
||||
|
||||
margin += odd
|
||||
|
||||
$MarginContainer.add_theme_constant_override(&\"margin_right\", margin.x)
|
||||
$MarginContainer.add_theme_constant_override(&\"margin_bottom\", margin.y)
|
||||
|
||||
func set_texture(texture: Texture2D):
|
||||
%TextureRect.texture = texture
|
||||
odd = Vector2(int(get_texture_size().x) % 2, int(get_texture_size().y) % 2)
|
||||
|
||||
func get_texture_size() -> Vector2:
|
||||
return %TextureRect.texture.get_size()
|
||||
|
||||
func get_position2() -> Vector2:
|
||||
return position + %TextureRect.position
|
||||
|
||||
func get_texture_data() -> Image:
|
||||
return %TextureRect.texture.get_image()
|
||||
|
||||
func set_display_background(display: bool):
|
||||
get_theme_stylebox(&\"panel\").draw_center = display
|
||||
|
||||
func set_background_color(color: Color):
|
||||
get_theme_stylebox(&\"panel\").bg_color = color
|
||||
|
||||
func _get_drag_data(p: Vector2):
|
||||
var preview = TextureRect.new()
|
||||
preview.texture = %TextureRect.texture
|
||||
preview.ignore_texture_size = true
|
||||
preview.stretch_mode = TextureRect.STRETCH_KEEP_ASPECT_CENTERED
|
||||
preview.size = Vector2(64, 64)
|
||||
set_drag_preview(preview)
|
||||
return {type = \"SpritesheetFrame\", node = self}
|
||||
|
||||
func _can_drop_data(p: Vector2, data) -> bool:
|
||||
return data is Dictionary and data.get(\"type\", \"\") == \"SpritesheetFrame\"
|
||||
|
||||
func _drop_data(p: Vector2, data) -> void:
|
||||
var index = get_index()
|
||||
get_parent().move_child(self, data.node.get_index())
|
||||
get_parent().move_child(data.node, index)
|
||||
get_tree().current_scene.refresh_grid()
|
||||
|
||||
func _gui_input(event: InputEvent) -> void:
|
||||
if event is InputEventMouseButton:
|
||||
if event.pressed and event.button_index == MOUSE_BUTTON_RIGHT:
|
||||
get_tree().current_scene.remove_frame.call_deferred(self)
|
||||
"
|
||||
|
||||
[node name="FramePrefab" type="PanelContainer" groups=["frame"]]
|
||||
theme_override_styles/panel = SubResource("2")
|
||||
script = SubResource("3")
|
||||
|
||||
[node name="MarginContainer" type="MarginContainer" parent="."]
|
||||
layout_mode = 2
|
||||
mouse_filter = 2
|
||||
|
||||
[node name="TextureRect" type="TextureRect" parent="MarginContainer"]
|
||||
unique_name_in_owner = true
|
||||
texture_filter = 1
|
||||
layout_mode = 2
|
||||
stretch_mode = 4
|
|
@ -1,714 +0,0 @@
|
|||
[gd_scene load_steps=5 format=3 uid="uid://bf3b0i8scthbm"]
|
||||
|
||||
[ext_resource type="Texture2D" uid="uid://bnkl8rujlgv0h" path="res://addons/SpritesheetGenerator/Checker.png" id="1_hs1uu"]
|
||||
|
||||
[sub_resource type="GDScript" id="1"]
|
||||
resource_name = "Generator"
|
||||
script/source = "extends Control
|
||||
|
||||
const SUPPORTED_FORMATS: PackedStringArray = [\"bmp\", \"dds\", \"exr\", \"hdr\", \"jpg\", \"jpeg\", \"png\", \"tga\", \"svg\", \"svgz\", \"webp\"]
|
||||
|
||||
@onready var grid := %GridContainer
|
||||
|
||||
var file_list: Array
|
||||
var image_list: Array
|
||||
var texture_list: Array
|
||||
|
||||
var images_to_process: Array
|
||||
var images_to_texturize: Array
|
||||
var first_time := true
|
||||
var image_count: int
|
||||
var output_path: String
|
||||
|
||||
var auto := true
|
||||
var margin := Vector2.ONE
|
||||
|
||||
var pan_origin: Vector2
|
||||
var pan_start: Vector2
|
||||
|
||||
signal images_processed
|
||||
|
||||
func _enter_tree() -> void:
|
||||
$SplitDialog.hide()
|
||||
$StashDialog.hide()
|
||||
|
||||
func _ready():
|
||||
$Status.text = $Status.text % \", \".join(SUPPORTED_FORMATS)
|
||||
|
||||
get_viewport().files_dropped.connect(load_files)
|
||||
grid.minimum_size_changed.connect(refresh_background)
|
||||
set_process(false)
|
||||
|
||||
func refresh_background():
|
||||
%Background.custom_minimum_size = grid.get_minimum_size()
|
||||
|
||||
func load_files(files: PackedStringArray):
|
||||
file_list.clear()
|
||||
image_list.clear()
|
||||
|
||||
%CustomName.text = \"\"
|
||||
%Reload.disabled = false
|
||||
%SavePNG.disabled = false
|
||||
|
||||
if files.size() == 1 and not FileAccess.file_exists(files[0]):
|
||||
var dir := DirAccess.open(files[0])
|
||||
if not dir:
|
||||
show_error(\"Can't open directory.\")
|
||||
return
|
||||
|
||||
for file in dir.get_files():
|
||||
if file.get_extension() in SUPPORTED_FORMATS:
|
||||
file_list.append(str(dir.get_current_dir().path_join(file)))
|
||||
else:
|
||||
var wrong_count: int
|
||||
for file in files:
|
||||
if file.get_extension() in SUPPORTED_FORMATS:
|
||||
file_list.append(file)
|
||||
else:
|
||||
wrong_count += 1
|
||||
|
||||
if wrong_count > 0:
|
||||
show_error(\"Skipped %s file(s) with unsupported extension.\" % wrong_count)
|
||||
|
||||
if file_list.is_empty():
|
||||
show_error(\"No valid files or directories to process.\")
|
||||
return
|
||||
|
||||
load_images()
|
||||
|
||||
func load_images():
|
||||
texture_list.clear()
|
||||
|
||||
for image in grid.get_children():
|
||||
image.free()
|
||||
|
||||
for image in %StashImages.get_children():
|
||||
image.free()
|
||||
update_stash()
|
||||
|
||||
var size_map: Dictionary
|
||||
|
||||
if not file_list.is_empty():
|
||||
image_list = file_list.map(func(file: String):
|
||||
var image := Image.load_from_file(file)
|
||||
if image:
|
||||
image.set_meta(&\"path\", file)
|
||||
return image)
|
||||
|
||||
for image in image_list:
|
||||
if not image:
|
||||
continue
|
||||
|
||||
if not image.get_size() in size_map:
|
||||
size_map[image.get_size()] = []
|
||||
size_map[image.get_size()].append(image)
|
||||
|
||||
var output_name: String
|
||||
var most_common_size: Vector2i
|
||||
var most_common_count: int
|
||||
|
||||
for size in size_map:
|
||||
if size_map[size].size() > most_common_count:
|
||||
most_common_size = size
|
||||
most_common_count = size_map[size].size()
|
||||
|
||||
for image in size_map[most_common_size]:
|
||||
if output_path.is_empty():
|
||||
var path: String = image.get_meta(&\"path\", \"\")
|
||||
output_path = path.get_base_dir()
|
||||
output_name = path.get_base_dir().get_file()
|
||||
|
||||
images_to_process.append(image)
|
||||
size_map.clear()
|
||||
|
||||
if not output_name.is_empty() and %CustomName.text.is_empty():
|
||||
%CustomName.text = output_name
|
||||
update_save_button()
|
||||
|
||||
if images_to_process.size() < file_list.size():
|
||||
show_error(\"Rejected %s image(s) due to size mismatch.\" % (file_list.size() - images_to_process.size()))
|
||||
|
||||
if images_to_process.size() == 1:
|
||||
if file_list.size() > 1:
|
||||
images_to_process.clear()
|
||||
show_error(\"Only one dropped image was valid.\")
|
||||
else:
|
||||
%SplitPreview.texture = ImageTexture.create_from_image(images_to_process[0])
|
||||
$SplitDialog.reset_size()
|
||||
$SplitDialog.popup_centered()
|
||||
|
||||
return
|
||||
|
||||
$Status.show()
|
||||
%CenterContainer.hide()
|
||||
|
||||
image_count = images_to_process.size()
|
||||
%Columns.max_value = image_count
|
||||
|
||||
threshold = %Threshold.value
|
||||
min_x = 9999999
|
||||
min_y = 9999999
|
||||
max_x = -9999999
|
||||
max_y = -9999999
|
||||
|
||||
set_process(true)
|
||||
|
||||
await images_processed
|
||||
|
||||
for texture in texture_list:
|
||||
add_frame(texture)
|
||||
|
||||
toggle_auto(auto)
|
||||
refresh_margin()
|
||||
|
||||
$Status.hide()
|
||||
%CenterContainer.show()
|
||||
|
||||
var threshold: float
|
||||
var min_x: int
|
||||
var min_y: int
|
||||
var max_x: int
|
||||
var max_y: int
|
||||
|
||||
func _process(delta: float) -> void:
|
||||
if not images_to_process.is_empty():
|
||||
var image: Image = images_to_process.pop_front()
|
||||
$Status.text = str(\"Preprocessing image \", image_count - images_to_process.size(), \"/\", image_count)
|
||||
|
||||
for x in image.get_width():
|
||||
for y in image.get_height():
|
||||
if image.get_pixel(x, y).a >= threshold:
|
||||
min_x = mini(min_x, x)
|
||||
min_y = mini(min_y, y)
|
||||
max_x = maxi(max_x, x)
|
||||
max_y = maxi(max_y, y)
|
||||
|
||||
images_to_texturize.append(image)
|
||||
elif not images_to_texturize.is_empty():
|
||||
var rect := Rect2i(min_x, min_y, max_x - min_x + 1, max_y - min_y + 1)
|
||||
var image: Image = images_to_texturize.pop_front()
|
||||
$Status.text = str(\"Creating texture \", image_count - images_to_texturize.size(), \"/\", image_count)
|
||||
|
||||
var true_image := Image.create(rect.size.x, rect.size.y, false, image.get_format())
|
||||
true_image.blit_rect(image, rect, Vector2())
|
||||
|
||||
var texture := ImageTexture.create_from_image(true_image)
|
||||
texture_list.append(texture)
|
||||
|
||||
if images_to_texturize.is_empty():
|
||||
set_process(false)
|
||||
images_processed.emit()
|
||||
if first_time:
|
||||
recenter()
|
||||
first_time = false
|
||||
|
||||
func toggle_grid(show: bool) -> void:
|
||||
get_tree().call_group(&\"frame\", &\"set_display_background\", show)
|
||||
|
||||
func toggle_auto(button_pressed: bool) -> void:
|
||||
%Columns.editable = not button_pressed
|
||||
auto = button_pressed
|
||||
|
||||
if button_pressed:
|
||||
var best: int
|
||||
var best_score = -9999999
|
||||
|
||||
for i in range(1, image_count + 1):
|
||||
var cols = i
|
||||
var rows = ceili(image_count / float(i))
|
||||
|
||||
var score = image_count - cols * rows - maxi(cols, rows) - rows
|
||||
if score > best_score:
|
||||
best = i
|
||||
best_score = score
|
||||
|
||||
grid.columns = best
|
||||
else:
|
||||
grid.columns = %Columns.value
|
||||
refresh_grid()
|
||||
|
||||
func hmargin_changed(value: float) -> void:
|
||||
margin.x = value
|
||||
refresh_margin()
|
||||
|
||||
func vmargin_changed(value: float) -> void:
|
||||
margin.y = value
|
||||
refresh_margin()
|
||||
|
||||
func refresh_margin():
|
||||
get_tree().call_group(&\"frame\", &\"set_frame_margin\", margin)
|
||||
|
||||
func columns_changed(value: float) -> void:
|
||||
grid.columns = value
|
||||
refresh_grid()
|
||||
|
||||
func refresh_grid():
|
||||
var coord: Vector2
|
||||
var dark = false
|
||||
|
||||
for rect in grid.get_children():
|
||||
rect.set_background_color(Color(0, 0, 0, 0.2 if dark else 0.1))
|
||||
dark = not dark
|
||||
coord.x += 1
|
||||
|
||||
if coord.x == grid.columns:
|
||||
coord.x = 0
|
||||
coord.y += 1
|
||||
dark = int(coord.y) % 2 == 1
|
||||
|
||||
func save_png() -> void:
|
||||
var image_size: Vector2 = grid.get_child(0).get_minimum_size()
|
||||
|
||||
var image := Image.create(image_size.x * grid.columns, image_size.y * (ceil(grid.get_child_count() / float(grid.columns))), false, Image.FORMAT_RGBA8)
|
||||
|
||||
for rect in grid.get_children():
|
||||
image.blit_rect(rect.get_texture_data(), Rect2(Vector2(), image_size), rect.get_position2())
|
||||
|
||||
image.save_png(output_path.path_join(%CustomName.text) + \".png\")
|
||||
|
||||
func show_error(text: String):
|
||||
if not %Error.visible:
|
||||
%Error.show()
|
||||
else:
|
||||
%Error.text += \"\\n\"
|
||||
%Error.text += text
|
||||
%Timer.start()
|
||||
|
||||
func error_hidden() -> void:
|
||||
%Error.text = \"\"
|
||||
|
||||
func _input(event: InputEvent) -> void:
|
||||
if event is InputEventMouseButton:
|
||||
var cc: Control = %CenterContainer
|
||||
|
||||
if event.button_index == MOUSE_BUTTON_MIDDLE:
|
||||
if event.pressed:
|
||||
pan_origin = get_local_mouse_position()
|
||||
pan_start = cc.position
|
||||
else:
|
||||
pan_origin = Vector2()
|
||||
|
||||
if event.button_index == MOUSE_BUTTON_WHEEL_DOWN:
|
||||
var lm = cc.get_local_mouse_position()
|
||||
cc.scale -= Vector2.ONE * 0.05
|
||||
if cc.scale.x <= 0:
|
||||
cc.scale = Vector2.ONE * 0.05
|
||||
|
||||
cc.position -= (lm - cc.get_local_mouse_position()) * cc.scale
|
||||
elif event.button_index == MOUSE_BUTTON_WHEEL_UP:
|
||||
var lm = cc.get_local_mouse_position()
|
||||
cc.scale += Vector2.ONE * 0.05
|
||||
cc.position -= (lm - cc.get_local_mouse_position()) * cc.scale
|
||||
|
||||
if event is InputEventMouseMotion:
|
||||
if pan_origin != Vector2():
|
||||
%CenterContainer.position = pan_start + (get_local_mouse_position() - pan_origin)
|
||||
|
||||
func recenter() -> void:
|
||||
%CenterContainer.position = get_viewport().size / 2 - Vector2i(%CenterContainer.size) / 2
|
||||
%CenterContainer.scale = Vector2.ONE
|
||||
|
||||
func update_split_preview():
|
||||
%SplitPreview.queue_redraw()
|
||||
|
||||
func draw_split_preview() -> void:
|
||||
var preview: TextureRect = %SplitPreview
|
||||
var frame_count := Vector2(%SplitX.value, %SplitY.value)
|
||||
var frame_size := preview.size / frame_count
|
||||
|
||||
for x in range(1, frame_count.x):
|
||||
for y in int(frame_count.y):
|
||||
preview.draw_line(frame_size * Vector2(x, y), frame_size * Vector2(x, y + 1), Color.WHITE)
|
||||
preview.draw_line(frame_size * Vector2(x, y) + Vector2.RIGHT, frame_size * Vector2(x, y + 1) + Vector2.RIGHT, Color.BLACK)
|
||||
|
||||
for y in range(1, frame_count.y):
|
||||
for x in int(frame_count.x):
|
||||
preview.draw_line(frame_size * Vector2(x, y), frame_size * Vector2(x + 1, y), Color.WHITE)
|
||||
preview.draw_line(frame_size * Vector2(x, y) + Vector2.DOWN, frame_size * Vector2(x + 1, y) + Vector2.DOWN, Color.BLACK)
|
||||
|
||||
func split_spritesheet() -> void:
|
||||
file_list.clear()
|
||||
image_list.clear()
|
||||
|
||||
var image: Image = images_to_process[0]
|
||||
var sub_image_size := image.get_size() / Vector2i(%SplitX.value, %SplitY.value)
|
||||
|
||||
for y in %SplitY.value:
|
||||
for x in %SplitX.value:
|
||||
image_list.append(image.get_region(Rect2i(Vector2i(x, y) * sub_image_size, sub_image_size)))
|
||||
|
||||
images_to_process.clear()
|
||||
load_images()
|
||||
|
||||
func remove_frame(frame):
|
||||
var image: Image = frame.get_texture_data()
|
||||
var texture := ImageTexture.create_from_image(image)
|
||||
|
||||
var button := TextureButton.new()
|
||||
button.texture_normal = texture
|
||||
button.custom_minimum_size = Vector2(128, 128)
|
||||
button.stretch_mode = TextureButton.STRETCH_KEEP_ASPECT_CENTERED
|
||||
button.ignore_texture_size = true
|
||||
button.pressed.connect(re_add_image.bind(button), CONNECT_DEFERRED)
|
||||
%StashImages.add_child(button)
|
||||
|
||||
var ref := ReferenceRect.new()
|
||||
button.add_child(ref)
|
||||
ref.set_anchors_and_offsets_preset(Control.PRESET_FULL_RECT)
|
||||
ref.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
||||
ref.editor_only = false
|
||||
|
||||
frame.free()
|
||||
refresh_grid()
|
||||
update_stash()
|
||||
|
||||
func update_stash():
|
||||
%Stash.disabled = %StashImages.get_child_count() == 0
|
||||
|
||||
func re_add_image(tb: TextureButton):
|
||||
add_frame(tb.texture_normal)
|
||||
tb.free()
|
||||
refresh_grid()
|
||||
update_stash()
|
||||
|
||||
if %Stash.disabled:
|
||||
$StashDialog.hide()
|
||||
|
||||
func add_frame(texture: Texture2D):
|
||||
var rect := preload(\"res://addons/SpritesheetGenerator/SpritesheetFrame.tscn\").instantiate()
|
||||
rect.set_texture(texture)
|
||||
rect.set_display_background(%DisplayGrid.button_pressed)
|
||||
rect.set_frame_margin(margin)
|
||||
grid.add_child(rect)
|
||||
|
||||
func update_save_button() -> void:
|
||||
%SavePNG.disabled = %CustomName.text.is_empty()
|
||||
"
|
||||
|
||||
[sub_resource type="StyleBoxFlat" id="5"]
|
||||
content_margin_left = 20.0
|
||||
content_margin_top = 20.0
|
||||
content_margin_right = 20.0
|
||||
content_margin_bottom = 20.0
|
||||
bg_color = Color(0, 0, 0, 0.25098)
|
||||
|
||||
[sub_resource type="StyleBoxTexture" id="StyleBoxTexture_kjgn5"]
|
||||
texture = ExtResource("1_hs1uu")
|
||||
axis_stretch_horizontal = 1
|
||||
axis_stretch_vertical = 1
|
||||
|
||||
[node name="Main" type="HBoxContainer"]
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
mouse_filter = 2
|
||||
script = SubResource("1")
|
||||
|
||||
[node name="MarginContainer" type="PanelContainer" parent="."]
|
||||
layout_mode = 2
|
||||
theme_override_styles/panel = SubResource("5")
|
||||
|
||||
[node name="VBoxContainer" type="VBoxContainer" parent="MarginContainer"]
|
||||
layout_mode = 2
|
||||
theme_override_constants/separation = 10
|
||||
|
||||
[node name="Label5" type="Label" parent="MarginContainer/VBoxContainer"]
|
||||
layout_mode = 2
|
||||
text = "Alpha Threshold"
|
||||
horizontal_alignment = 1
|
||||
|
||||
[node name="Threshold" type="SpinBox" parent="MarginContainer/VBoxContainer"]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 2
|
||||
max_value = 1.0
|
||||
step = 0.005
|
||||
value = 0.9
|
||||
|
||||
[node name="Reload" type="Button" parent="MarginContainer/VBoxContainer"]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 2
|
||||
disabled = true
|
||||
text = "Reload"
|
||||
|
||||
[node name="HSeparator" type="HSeparator" parent="MarginContainer/VBoxContainer"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Label" type="Label" parent="MarginContainer/VBoxContainer"]
|
||||
layout_mode = 2
|
||||
text = "Columns"
|
||||
horizontal_alignment = 1
|
||||
|
||||
[node name="Columns" type="SpinBox" parent="MarginContainer/VBoxContainer"]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 2
|
||||
min_value = 1.0
|
||||
value = 1.0
|
||||
editable = false
|
||||
|
||||
[node name="Grid" type="CheckButton" parent="MarginContainer/VBoxContainer"]
|
||||
layout_mode = 2
|
||||
button_pressed = true
|
||||
text = "Auto"
|
||||
|
||||
[node name="Label3" type="Label" parent="MarginContainer/VBoxContainer"]
|
||||
layout_mode = 2
|
||||
text = "Horizontal Margin"
|
||||
horizontal_alignment = 1
|
||||
|
||||
[node name="MarginH" type="SpinBox" parent="MarginContainer/VBoxContainer"]
|
||||
layout_mode = 2
|
||||
value = 1.0
|
||||
suffix = "px"
|
||||
|
||||
[node name="Label4" type="Label" parent="MarginContainer/VBoxContainer"]
|
||||
layout_mode = 2
|
||||
text = "Vertical Margin"
|
||||
horizontal_alignment = 1
|
||||
|
||||
[node name="MarginV" type="SpinBox" parent="MarginContainer/VBoxContainer"]
|
||||
layout_mode = 2
|
||||
max_value = 128.0
|
||||
value = 1.0
|
||||
suffix = "px"
|
||||
|
||||
[node name="Stash" type="Button" parent="MarginContainer/VBoxContainer"]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 2
|
||||
disabled = true
|
||||
text = "Image Stash"
|
||||
|
||||
[node name="HSeparator2" type="HSeparator" parent="MarginContainer/VBoxContainer"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Button" type="Button" parent="MarginContainer/VBoxContainer"]
|
||||
layout_mode = 2
|
||||
text = "Recenter View
|
||||
"
|
||||
|
||||
[node name="DisplayGrid" type="CheckBox" parent="MarginContainer/VBoxContainer"]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 2
|
||||
button_pressed = true
|
||||
text = "Show Grid"
|
||||
|
||||
[node name="HSeparator3" type="HSeparator" parent="MarginContainer/VBoxContainer"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="HBoxContainer" type="HBoxContainer" parent="MarginContainer/VBoxContainer"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="CustomName" type="LineEdit" parent="MarginContainer/VBoxContainer/HBoxContainer"]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
placeholder_text = "Image Name"
|
||||
|
||||
[node name="SavePNG" type="Button" parent="MarginContainer/VBoxContainer"]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 2
|
||||
disabled = true
|
||||
text = "Save PNG"
|
||||
|
||||
[node name="Status" type="Label" parent="."]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
size_flags_vertical = 3
|
||||
text = "Drop folder or image files here to start.
|
||||
|
||||
Images should be of the same size. If their sizes don't match, the generator will try to use the dominating size.
|
||||
|
||||
The images will be automatically cropped based on the Alpha Threshold value. Greater value means more exact crop.
|
||||
|
||||
Supported formats: %s
|
||||
|
||||
If you drop a single image, the generator will instead edit it as spritesheet."
|
||||
horizontal_alignment = 1
|
||||
vertical_alignment = 1
|
||||
|
||||
[node name="View" type="CanvasLayer" parent="."]
|
||||
layer = -1
|
||||
|
||||
[node name="CenterContainer" type="CenterContainer" parent="View"]
|
||||
unique_name_in_owner = true
|
||||
visible = false
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
size_flags_horizontal = 3
|
||||
|
||||
[node name="Background" type="ColorRect" parent="View/CenterContainer"]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 2
|
||||
mouse_filter = 1
|
||||
color = Color(0, 0.501961, 0.501961, 1)
|
||||
|
||||
[node name="GridContainer" type="GridContainer" parent="View/CenterContainer"]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 2
|
||||
theme_override_constants/h_separation = 0
|
||||
theme_override_constants/v_separation = 0
|
||||
columns = 3
|
||||
|
||||
[node name="VBoxContainer" type="GridContainer" parent="View"]
|
||||
anchors_preset = 3
|
||||
anchor_left = 1.0
|
||||
anchor_top = 1.0
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
offset_left = -40.0
|
||||
offset_top = -40.0
|
||||
grow_horizontal = 0
|
||||
grow_vertical = 0
|
||||
mouse_filter = 2
|
||||
columns = 3
|
||||
|
||||
[node name="Label" type="Label" parent="View/VBoxContainer"]
|
||||
layout_mode = 2
|
||||
text = "LMB"
|
||||
horizontal_alignment = 1
|
||||
|
||||
[node name="VSeparator" type="VSeparator" parent="View/VBoxContainer"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Label2" type="Label" parent="View/VBoxContainer"]
|
||||
layout_mode = 2
|
||||
text = "rearrange images"
|
||||
|
||||
[node name="Label3" type="Label" parent="View/VBoxContainer"]
|
||||
layout_mode = 2
|
||||
text = "RMB"
|
||||
horizontal_alignment = 1
|
||||
|
||||
[node name="VSeparator2" type="VSeparator" parent="View/VBoxContainer"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Label4" type="Label" parent="View/VBoxContainer"]
|
||||
layout_mode = 2
|
||||
text = "delete images"
|
||||
|
||||
[node name="Label5" type="Label" parent="View/VBoxContainer"]
|
||||
layout_mode = 2
|
||||
text = "MMB"
|
||||
horizontal_alignment = 1
|
||||
|
||||
[node name="VSeparator3" type="VSeparator" parent="View/VBoxContainer"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Label6" type="Label" parent="View/VBoxContainer"]
|
||||
layout_mode = 2
|
||||
text = "pan view"
|
||||
|
||||
[node name="CanvasLayer" type="CanvasLayer" parent="."]
|
||||
|
||||
[node name="Error" type="Label" parent="CanvasLayer"]
|
||||
unique_name_in_owner = true
|
||||
modulate = Color(1, 0, 0, 1)
|
||||
anchors_preset = 12
|
||||
anchor_top = 1.0
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
offset_top = -14.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 0
|
||||
size_flags_vertical = 0
|
||||
horizontal_alignment = 1
|
||||
|
||||
[node name="Timer" type="Timer" parent="CanvasLayer"]
|
||||
unique_name_in_owner = true
|
||||
wait_time = 5.0
|
||||
one_shot = true
|
||||
|
||||
[node name="SplitDialog" type="ConfirmationDialog" parent="."]
|
||||
title = "Edit Spritesheet"
|
||||
position = Vector2i(-500, 0)
|
||||
size = Vector2i(272, 343)
|
||||
visible = true
|
||||
|
||||
[node name="VBoxContainer" type="VBoxContainer" parent="SplitDialog"]
|
||||
offset_left = 8.0
|
||||
offset_top = 8.0
|
||||
offset_right = 264.0
|
||||
offset_bottom = 294.0
|
||||
|
||||
[node name="Label" type="Label" parent="SplitDialog/VBoxContainer"]
|
||||
layout_mode = 2
|
||||
text = "Split Frames"
|
||||
horizontal_alignment = 1
|
||||
|
||||
[node name="HBoxContainer" type="HBoxContainer" parent="SplitDialog/VBoxContainer"]
|
||||
layout_mode = 2
|
||||
alignment = 1
|
||||
|
||||
[node name="SplitX" type="SpinBox" parent="SplitDialog/VBoxContainer/HBoxContainer"]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 2
|
||||
min_value = 1.0
|
||||
max_value = 1000.0
|
||||
value = 1.0
|
||||
select_all_on_focus = true
|
||||
|
||||
[node name="Label" type="Label" parent="SplitDialog/VBoxContainer/HBoxContainer"]
|
||||
layout_mode = 2
|
||||
text = "x"
|
||||
|
||||
[node name="SplitY" type="SpinBox" parent="SplitDialog/VBoxContainer/HBoxContainer"]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 2
|
||||
min_value = 1.0
|
||||
max_value = 1000.0
|
||||
value = 1.0
|
||||
select_all_on_focus = true
|
||||
|
||||
[node name="CenterContainer" type="CenterContainer" parent="SplitDialog/VBoxContainer"]
|
||||
layout_mode = 2
|
||||
size_flags_vertical = 3
|
||||
|
||||
[node name="PanelContainer" type="PanelContainer" parent="SplitDialog/VBoxContainer/CenterContainer"]
|
||||
layout_mode = 2
|
||||
theme_override_styles/panel = SubResource("StyleBoxTexture_kjgn5")
|
||||
|
||||
[node name="SplitPreview" type="TextureRect" parent="SplitDialog/VBoxContainer/CenterContainer/PanelContainer"]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 2
|
||||
|
||||
[node name="StashDialog" type="AcceptDialog" parent="."]
|
||||
title = "Image Stash"
|
||||
position = Vector2i(-500, 500)
|
||||
size = Vector2i(309, 100)
|
||||
visible = true
|
||||
|
||||
[node name="VBoxContainer" type="VBoxContainer" parent="StashDialog"]
|
||||
offset_left = 8.0
|
||||
offset_top = 8.0
|
||||
offset_right = 301.0
|
||||
offset_bottom = 51.0
|
||||
|
||||
[node name="Label" type="Label" parent="StashDialog/VBoxContainer"]
|
||||
layout_mode = 2
|
||||
text = "Click frame to re-add it to spritesheet."
|
||||
horizontal_alignment = 1
|
||||
|
||||
[node name="StashImages" type="HFlowContainer" parent="StashDialog/VBoxContainer"]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 2
|
||||
|
||||
[connection signal="pressed" from="MarginContainer/VBoxContainer/Reload" to="." method="load_images"]
|
||||
[connection signal="value_changed" from="MarginContainer/VBoxContainer/Columns" to="." method="columns_changed"]
|
||||
[connection signal="toggled" from="MarginContainer/VBoxContainer/Grid" to="." method="toggle_auto"]
|
||||
[connection signal="value_changed" from="MarginContainer/VBoxContainer/MarginH" to="." method="hmargin_changed"]
|
||||
[connection signal="value_changed" from="MarginContainer/VBoxContainer/MarginV" to="." method="vmargin_changed"]
|
||||
[connection signal="pressed" from="MarginContainer/VBoxContainer/Stash" to="StashDialog" method="popup_centered_ratio" binds= [0.5]]
|
||||
[connection signal="pressed" from="MarginContainer/VBoxContainer/Button" to="." method="recenter"]
|
||||
[connection signal="toggled" from="MarginContainer/VBoxContainer/DisplayGrid" to="." method="toggle_grid"]
|
||||
[connection signal="text_changed" from="MarginContainer/VBoxContainer/HBoxContainer/CustomName" to="." method="update_save_button" unbinds=1]
|
||||
[connection signal="pressed" from="MarginContainer/VBoxContainer/SavePNG" to="." method="save_png"]
|
||||
[connection signal="hidden" from="CanvasLayer/Error" to="." method="error_hidden"]
|
||||
[connection signal="timeout" from="CanvasLayer/Timer" to="CanvasLayer/Error" method="hide"]
|
||||
[connection signal="confirmed" from="SplitDialog" to="." method="split_spritesheet"]
|
||||
[connection signal="value_changed" from="SplitDialog/VBoxContainer/HBoxContainer/SplitX" to="." method="update_split_preview" unbinds=1]
|
||||
[connection signal="value_changed" from="SplitDialog/VBoxContainer/HBoxContainer/SplitY" to="." method="update_split_preview" unbinds=1]
|
||||
[connection signal="draw" from="SplitDialog/VBoxContainer/CenterContainer/PanelContainer/SplitPreview" to="." method="draw_split_preview"]
|
|
@ -1,7 +0,0 @@
|
|||
[plugin]
|
||||
|
||||
name="Spritesheet Generator"
|
||||
description="Generates cropped spritesheets from multiple images."
|
||||
author="KoBeWi"
|
||||
version="1.2"
|
||||
script="SpriteSheetGenerator.gd"
|
Loading…
Add table
Add a link
Reference in a new issue