Ability to create sprite frames in AnimatedSprite from sprite sheet.
This commit is contained in:
parent
ad1368a625
commit
3f76d2c2f3
61
editor/icons/icon_sprite_sheet.svg
Normal file
61
editor/icons/icon_sprite_sheet.svg
Normal file
@ -0,0 +1,61 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="16"
|
||||
height="16"
|
||||
version="1.1"
|
||||
viewBox="0 0 16 16"
|
||||
id="svg6"
|
||||
sodipodi:docname="icon_sprite_sheet.svg"
|
||||
inkscape:version="0.92.3 (2405546, 2018-03-11)">
|
||||
<metadata
|
||||
id="metadata12">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<defs
|
||||
id="defs10" />
|
||||
<sodipodi:namedview
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1"
|
||||
objecttolerance="10"
|
||||
gridtolerance="10"
|
||||
guidetolerance="10"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:window-width="773"
|
||||
inkscape:window-height="480"
|
||||
id="namedview8"
|
||||
showgrid="false"
|
||||
inkscape:zoom="14.75"
|
||||
inkscape:cx="8"
|
||||
inkscape:cy="8"
|
||||
inkscape:window-x="551"
|
||||
inkscape:window-y="278"
|
||||
inkscape:window-maximized="0"
|
||||
inkscape:current-layer="g4" />
|
||||
<g
|
||||
transform="translate(0 -1036.4)"
|
||||
id="g4">
|
||||
<path
|
||||
transform="translate(0 1036.4)"
|
||||
d="m3 1c-1.1046 0-2 0.89543-2 2v10c0 1.1046 0.89543 2 2 2h10c1.1046 0 2-0.89543 2-2v-10c0-1.1046-0.89543-2-2-2h-10zm0 2h2v2h-2v-2zm4 0h2v2h-2v-2zm4 0h2v2h-2v-2zm-8 4h2v2h-2v-2zm4 0h2v2h-2v-2zm4 0h2v2h-2v-2zm-8 4h2v2h-2v-2zm4 0h2v2h-2v-2zm4 0h2v2h-2v-2z"
|
||||
fill="#a5efac"
|
||||
id="path2"
|
||||
style="fill:#e0e0e0;fill-opacity:1" />
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 1.9 KiB |
@ -38,11 +38,167 @@
|
||||
void SpriteFramesEditor::_gui_input(Ref<InputEvent> p_event) {
|
||||
}
|
||||
|
||||
void SpriteFramesEditor::_open_sprite_sheet() {
|
||||
|
||||
file_split_sheet->clear_filters();
|
||||
List<String> extensions;
|
||||
ResourceLoader::get_recognized_extensions_for_type("Texture", &extensions);
|
||||
for (int i = 0; i < extensions.size(); i++) {
|
||||
file_split_sheet->add_filter("*." + extensions[i]);
|
||||
}
|
||||
|
||||
file_split_sheet->popup_centered_ratio();
|
||||
}
|
||||
|
||||
void SpriteFramesEditor::_sheet_preview_draw() {
|
||||
Size2i size = split_sheet_preview->get_size();
|
||||
int h = split_sheet_h->get_value();
|
||||
int v = split_sheet_v->get_value();
|
||||
const float a = 0.3;
|
||||
for (int i = 1; i < h; i++) {
|
||||
for (int j = 1; j < v; j++) {
|
||||
|
||||
int x = i * size.width / h;
|
||||
int y = i * size.height / v;
|
||||
|
||||
split_sheet_preview->draw_line(Point2(x, 0), Point2(x, size.height), Color(1, 1, 1, a));
|
||||
split_sheet_preview->draw_line(Point2(x + 1, 0), Point2(x + 1, size.height), Color(0, 0, 0, a));
|
||||
|
||||
split_sheet_preview->draw_line(Point2(0, y), Point2(size.width, y), Color(1, 1, 1, a));
|
||||
split_sheet_preview->draw_line(Point2(0, y + 1), Point2(size.width, y + 1), Color(0, 0, 0, a));
|
||||
}
|
||||
}
|
||||
|
||||
Color accent = get_color("accent_color", "Editor");
|
||||
|
||||
for (Set<int>::Element *E = frames_selected.front(); E; E = E->next()) {
|
||||
int idx = E->get();
|
||||
int x = (idx % h) * size.width / h;
|
||||
int y = (idx / v) * size.height / v;
|
||||
int width = size.width / h;
|
||||
int height = size.height / v;
|
||||
|
||||
split_sheet_preview->draw_rect(Rect2(x + 5, y + 5, width - 10, height - 10), Color(0, 0, 0, 0.35), true);
|
||||
split_sheet_preview->draw_rect(Rect2(x + 0, y + 0, width - 0, height - 0), Color(0, 0, 0, 1), false);
|
||||
split_sheet_preview->draw_rect(Rect2(x + 1, y + 1, width - 2, height - 2), Color(0, 0, 0, 1), false);
|
||||
split_sheet_preview->draw_rect(Rect2(x + 2, y + 2, width - 4, height - 4), accent, false);
|
||||
split_sheet_preview->draw_rect(Rect2(x + 3, y + 3, width - 6, height - 6), accent, false);
|
||||
split_sheet_preview->draw_rect(Rect2(x + 4, y + 4, width - 8, height - 8), Color(0, 0, 0, 1), false);
|
||||
split_sheet_preview->draw_rect(Rect2(x + 5, y + 5, width - 10, height - 10), Color(0, 0, 0, 1), false);
|
||||
}
|
||||
|
||||
if (frames_selected.size() == 0) {
|
||||
split_sheet_dialog->get_ok()->set_disabled(true);
|
||||
split_sheet_dialog->get_ok()->set_text(TTR("No frames selected"));
|
||||
} else {
|
||||
split_sheet_dialog->get_ok()->set_disabled(false);
|
||||
split_sheet_dialog->get_ok()->set_text(vformat(TTR("Add %d frame(s)"), frames_selected.size()));
|
||||
}
|
||||
}
|
||||
void SpriteFramesEditor::_sheet_preview_input(const Ref<InputEvent> &p_event) {
|
||||
|
||||
Ref<InputEventMouseButton> mb = p_event;
|
||||
|
||||
if (mb.is_valid() && mb->is_pressed() && mb->get_button_index() == BUTTON_LEFT) {
|
||||
Size2i size = split_sheet_preview->get_size();
|
||||
int h = split_sheet_h->get_value();
|
||||
int v = split_sheet_v->get_value();
|
||||
|
||||
int x = CLAMP(int(mb->get_position().x) * h / size.width, 0, h - 1);
|
||||
int y = CLAMP(int(mb->get_position().y) * v / size.height, 0, v - 1);
|
||||
|
||||
int idx = h * y + x;
|
||||
|
||||
if (mb->get_shift() && last_frame_selected >= 0) {
|
||||
//select multiple
|
||||
int from = idx;
|
||||
int to = last_frame_selected;
|
||||
if (from > to) {
|
||||
SWAP(from, to);
|
||||
}
|
||||
|
||||
for (int i = from; i <= to; i++) {
|
||||
if (mb->get_control()) {
|
||||
frames_selected.erase(i);
|
||||
} else {
|
||||
frames_selected.insert(i);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (frames_selected.has(idx)) {
|
||||
frames_selected.erase(idx);
|
||||
} else {
|
||||
frames_selected.insert(idx);
|
||||
}
|
||||
}
|
||||
|
||||
last_frame_selected = idx;
|
||||
split_sheet_preview->update();
|
||||
}
|
||||
}
|
||||
|
||||
void SpriteFramesEditor::_sheet_add_frames() {
|
||||
|
||||
Size2i size = split_sheet_preview->get_size();
|
||||
int h = split_sheet_h->get_value();
|
||||
int v = split_sheet_v->get_value();
|
||||
|
||||
undo_redo->create_action(TTR("Add Frame"));
|
||||
|
||||
int fc = frames->get_frame_count(edited_anim);
|
||||
|
||||
for (Set<int>::Element *E = frames_selected.front(); E; E = E->next()) {
|
||||
int idx = E->get();
|
||||
int x = (idx % h) * size.width / h;
|
||||
int y = (idx / v) * size.height / v;
|
||||
int width = size.width / h;
|
||||
int height = size.height / v;
|
||||
|
||||
Ref<AtlasTexture> at;
|
||||
at.instance();
|
||||
at->set_atlas(split_sheet_preview->get_texture());
|
||||
at->set_region(Rect2(x, y, width, height));
|
||||
|
||||
undo_redo->add_do_method(frames, "add_frame", edited_anim, at, -1);
|
||||
undo_redo->add_undo_method(frames, "remove_frame", edited_anim, fc);
|
||||
}
|
||||
|
||||
undo_redo->add_do_method(this, "_update_library");
|
||||
undo_redo->add_undo_method(this, "_update_library");
|
||||
undo_redo->commit_action();
|
||||
}
|
||||
|
||||
void SpriteFramesEditor::_sheet_spin_changed(double) {
|
||||
frames_selected.clear();
|
||||
last_frame_selected = -1;
|
||||
split_sheet_preview->update();
|
||||
}
|
||||
|
||||
void SpriteFramesEditor::_prepare_sprite_sheet(const String &p_file) {
|
||||
|
||||
Ref<Resource> texture = ResourceLoader::load(p_file);
|
||||
if (!texture.is_valid()) {
|
||||
EditorNode::get_singleton()->show_warning("Unable to load images");
|
||||
ERR_FAIL_COND(!texture.is_valid());
|
||||
}
|
||||
if (texture != split_sheet_preview->get_texture()) {
|
||||
//different texture, reset to 4x4
|
||||
split_sheet_h->set_value(4);
|
||||
split_sheet_v->set_value(4);
|
||||
}
|
||||
frames_selected.clear();
|
||||
last_frame_selected = -1;
|
||||
|
||||
split_sheet_preview->set_texture(texture);
|
||||
split_sheet_dialog->popup_centered_ratio(0.65);
|
||||
}
|
||||
|
||||
void SpriteFramesEditor::_notification(int p_what) {
|
||||
|
||||
if (p_what == NOTIFICATION_ENTER_TREE) {
|
||||
|
||||
load->set_icon(get_icon("Load", "EditorIcons"));
|
||||
load_sheet->set_icon(get_icon("SpriteSheet", "EditorIcons"));
|
||||
copy->set_icon(get_icon("ActionCopy", "EditorIcons"));
|
||||
paste->set_icon(get_icon("ActionPaste", "EditorIcons"));
|
||||
empty->set_icon(get_icon("InsertBefore", "EditorIcons"));
|
||||
@ -72,6 +228,7 @@ void SpriteFramesEditor::_file_load_request(const PoolVector<String> &p_path, in
|
||||
if (resource.is_null()) {
|
||||
dialog->set_text(TTR("ERROR: Couldn't load frame resource!"));
|
||||
dialog->set_title(TTR("Error!"));
|
||||
|
||||
//dialog->get_cancel()->set_text("Close");
|
||||
dialog->get_ok()->set_text(TTR("Close"));
|
||||
dialog->popup_centered_minsize();
|
||||
@ -655,6 +812,12 @@ void SpriteFramesEditor::_bind_methods() {
|
||||
ClassDB::bind_method(D_METHOD("get_drag_data_fw"), &SpriteFramesEditor::get_drag_data_fw);
|
||||
ClassDB::bind_method(D_METHOD("can_drop_data_fw"), &SpriteFramesEditor::can_drop_data_fw);
|
||||
ClassDB::bind_method(D_METHOD("drop_data_fw"), &SpriteFramesEditor::drop_data_fw);
|
||||
ClassDB::bind_method(D_METHOD("_prepare_sprite_sheet"), &SpriteFramesEditor::_prepare_sprite_sheet);
|
||||
ClassDB::bind_method(D_METHOD("_open_sprite_sheet"), &SpriteFramesEditor::_open_sprite_sheet);
|
||||
ClassDB::bind_method(D_METHOD("_sheet_preview_draw"), &SpriteFramesEditor::_sheet_preview_draw);
|
||||
ClassDB::bind_method(D_METHOD("_sheet_preview_input"), &SpriteFramesEditor::_sheet_preview_input);
|
||||
ClassDB::bind_method(D_METHOD("_sheet_spin_changed"), &SpriteFramesEditor::_sheet_spin_changed);
|
||||
ClassDB::bind_method(D_METHOD("_sheet_add_frames"), &SpriteFramesEditor::_sheet_add_frames);
|
||||
}
|
||||
|
||||
SpriteFramesEditor::SpriteFramesEditor() {
|
||||
@ -712,9 +875,15 @@ SpriteFramesEditor::SpriteFramesEditor() {
|
||||
sub_vb->add_child(hbc);
|
||||
|
||||
load = memnew(ToolButton);
|
||||
load->set_tooltip(TTR("Load Resource"));
|
||||
load->set_tooltip(TTR("Add a Texture from File"));
|
||||
hbc->add_child(load);
|
||||
|
||||
load_sheet = memnew(ToolButton);
|
||||
load_sheet->set_tooltip(TTR("Add frames from a Sprite Sheet"));
|
||||
hbc->add_child(load_sheet);
|
||||
|
||||
hbc->add_child(memnew(VSeparator));
|
||||
|
||||
copy = memnew(ToolButton);
|
||||
copy->set_tooltip(TTR("Copy"));
|
||||
hbc->add_child(copy);
|
||||
@ -723,6 +892,8 @@ SpriteFramesEditor::SpriteFramesEditor() {
|
||||
paste->set_tooltip(TTR("Paste"));
|
||||
hbc->add_child(paste);
|
||||
|
||||
hbc->add_spacer(false);
|
||||
|
||||
empty = memnew(ToolButton);
|
||||
empty->set_tooltip(TTR("Insert Empty (Before)"));
|
||||
hbc->add_child(empty);
|
||||
@ -731,7 +902,7 @@ SpriteFramesEditor::SpriteFramesEditor() {
|
||||
empty2->set_tooltip(TTR("Insert Empty (After)"));
|
||||
hbc->add_child(empty2);
|
||||
|
||||
hbc->add_spacer(false);
|
||||
hbc->add_child(memnew(VSeparator));
|
||||
|
||||
move_up = memnew(ToolButton);
|
||||
move_up->set_tooltip(TTR("Move (Before)"));
|
||||
@ -766,6 +937,7 @@ SpriteFramesEditor::SpriteFramesEditor() {
|
||||
add_child(dialog);
|
||||
|
||||
load->connect("pressed", this, "_load_pressed");
|
||||
load_sheet->connect("pressed", this, "_open_sprite_sheet");
|
||||
_delete->connect("pressed", this, "_delete_pressed");
|
||||
copy->connect("pressed", this, "_copy_pressed");
|
||||
paste->connect("pressed", this, "_paste_pressed");
|
||||
@ -780,6 +952,60 @@ SpriteFramesEditor::SpriteFramesEditor() {
|
||||
updating = false;
|
||||
|
||||
edited_anim = "default";
|
||||
|
||||
split_sheet_dialog = memnew(ConfirmationDialog);
|
||||
add_child(split_sheet_dialog);
|
||||
VBoxContainer *split_sheet_vb = memnew(VBoxContainer);
|
||||
split_sheet_dialog->add_child(split_sheet_vb);
|
||||
split_sheet_dialog->set_title(TTR("Select Frames"));
|
||||
split_sheet_dialog->connect("confirmed", this, "_sheet_add_frames");
|
||||
|
||||
ScrollContainer *scroll = memnew(ScrollContainer);
|
||||
split_sheet_preview = memnew(TextureRect);
|
||||
split_sheet_preview->set_expand(false);
|
||||
split_sheet_preview->set_mouse_filter(MOUSE_FILTER_PASS);
|
||||
split_sheet_preview->connect("draw", this, "_sheet_preview_draw");
|
||||
split_sheet_preview->connect("gui_input", this, "_sheet_preview_input");
|
||||
|
||||
scroll->set_enable_h_scroll(true);
|
||||
scroll->set_enable_v_scroll(true);
|
||||
CenterContainer *cc = memnew(CenterContainer);
|
||||
cc->add_child(split_sheet_preview);
|
||||
cc->set_h_size_flags(SIZE_EXPAND_FILL);
|
||||
cc->set_v_size_flags(SIZE_EXPAND_FILL);
|
||||
scroll->add_child(cc);
|
||||
|
||||
split_sheet_vb->add_margin_child(TTR("Base Image:"), scroll, true);
|
||||
|
||||
HBoxContainer *split_sheet_hb = memnew(HBoxContainer);
|
||||
split_sheet_hb->add_spacer();
|
||||
Label *ss_label = memnew(Label(TTR("Horizontal:")));
|
||||
split_sheet_hb->add_child(ss_label);
|
||||
split_sheet_h = memnew(SpinBox);
|
||||
split_sheet_h->set_min(1);
|
||||
split_sheet_h->set_max(128);
|
||||
split_sheet_h->set_step(1);
|
||||
split_sheet_hb->add_child(split_sheet_h);
|
||||
split_sheet_hb->add_spacer();
|
||||
split_sheet_h->connect("value_changed", this, "_sheet_spin_changed");
|
||||
|
||||
ss_label = memnew(Label(TTR("Vertical:")));
|
||||
split_sheet_hb->add_child(ss_label);
|
||||
split_sheet_v = memnew(SpinBox);
|
||||
split_sheet_v->set_min(1);
|
||||
split_sheet_v->set_max(128);
|
||||
split_sheet_v->set_step(1);
|
||||
split_sheet_hb->add_child(split_sheet_v);
|
||||
split_sheet_hb->add_spacer();
|
||||
split_sheet_v->connect("value_changed", this, "_sheet_spin_changed");
|
||||
|
||||
split_sheet_vb->add_margin_child(TTR("Split Settings:"), split_sheet_hb);
|
||||
|
||||
file_split_sheet = memnew(EditorFileDialog);
|
||||
file_split_sheet->set_title(TTR("Create frames from Sprite Sheet"));
|
||||
file_split_sheet->set_mode(EditorFileDialog::MODE_OPEN_FILE);
|
||||
add_child(file_split_sheet);
|
||||
file_split_sheet->connect("file_selected", this, "_prepare_sprite_sheet");
|
||||
}
|
||||
|
||||
void SpriteFramesEditorPlugin::edit(Object *p_object) {
|
||||
|
@ -37,6 +37,7 @@
|
||||
#include "scene/gui/dialogs.h"
|
||||
#include "scene/gui/file_dialog.h"
|
||||
#include "scene/gui/split_container.h"
|
||||
#include "scene/gui/texture_rect.h"
|
||||
#include "scene/gui/tree.h"
|
||||
|
||||
class SpriteFramesEditor : public HSplitContainer {
|
||||
@ -44,6 +45,7 @@ class SpriteFramesEditor : public HSplitContainer {
|
||||
GDCLASS(SpriteFramesEditor, HSplitContainer);
|
||||
|
||||
ToolButton *load;
|
||||
ToolButton *load_sheet;
|
||||
ToolButton *_delete;
|
||||
ToolButton *copy;
|
||||
ToolButton *paste;
|
||||
@ -71,6 +73,14 @@ class SpriteFramesEditor : public HSplitContainer {
|
||||
|
||||
StringName edited_anim;
|
||||
|
||||
ConfirmationDialog *split_sheet_dialog;
|
||||
TextureRect *split_sheet_preview;
|
||||
SpinBox *split_sheet_h;
|
||||
SpinBox *split_sheet_v;
|
||||
EditorFileDialog *file_split_sheet;
|
||||
Set<int> frames_selected;
|
||||
int last_frame_selected;
|
||||
|
||||
void _load_pressed();
|
||||
void _load_scene_pressed();
|
||||
void _file_load_request(const PoolVector<String> &p_path, int p_at_pos = -1);
|
||||
@ -99,6 +109,13 @@ class SpriteFramesEditor : public HSplitContainer {
|
||||
bool can_drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) const;
|
||||
void drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from);
|
||||
|
||||
void _open_sprite_sheet();
|
||||
void _prepare_sprite_sheet(const String &p_file);
|
||||
void _sheet_preview_draw();
|
||||
void _sheet_spin_changed(double);
|
||||
void _sheet_preview_input(const Ref<InputEvent> &p_event);
|
||||
void _sheet_add_frames();
|
||||
|
||||
protected:
|
||||
void _notification(int p_what);
|
||||
void _gui_input(Ref<InputEvent> p_event);
|
||||
|
Loading…
Reference in New Issue
Block a user