summaryrefslogtreecommitdiff
path: root/editor/plugins
diff options
context:
space:
mode:
Diffstat (limited to 'editor/plugins')
-rw-r--r--editor/plugins/asset_library_editor_plugin.cpp2
-rw-r--r--editor/plugins/material_editor_plugin.cpp204
-rw-r--r--editor/plugins/material_editor_plugin.h65
-rw-r--r--editor/plugins/mesh_editor_plugin.cpp77
-rw-r--r--editor/plugins/mesh_editor_plugin.h15
-rw-r--r--editor/plugins/particles_2d_editor_plugin.cpp5
-rw-r--r--editor/plugins/particles_editor_plugin.cpp6
-rw-r--r--editor/plugins/path_editor_plugin.cpp4
-rw-r--r--editor/plugins/path_editor_plugin.h1
-rw-r--r--editor/plugins/script_editor_plugin.cpp3
-rw-r--r--editor/plugins/script_text_editor.cpp4
-rw-r--r--editor/plugins/shader_editor_plugin.cpp18
-rw-r--r--editor/plugins/spatial_editor_plugin.cpp145
-rw-r--r--editor/plugins/spatial_editor_plugin.h5
-rw-r--r--editor/plugins/sprite_editor_plugin.cpp2
-rw-r--r--editor/plugins/texture_editor_plugin.cpp44
-rw-r--r--editor/plugins/texture_editor_plugin.h16
-rw-r--r--editor/plugins/tile_set_editor_plugin.cpp558
-rw-r--r--editor/plugins/tile_set_editor_plugin.h28
19 files changed, 1029 insertions, 173 deletions
diff --git a/editor/plugins/asset_library_editor_plugin.cpp b/editor/plugins/asset_library_editor_plugin.cpp
index ab3936407b..a9e9607bc5 100644
--- a/editor/plugins/asset_library_editor_plugin.cpp
+++ b/editor/plugins/asset_library_editor_plugin.cpp
@@ -177,6 +177,8 @@ void EditorAssetLibraryItemDescription::set_image(int p_type, int p_index, const
thumbnail = thumbnail->duplicate();
Point2 overlay_pos = Point2((thumbnail->get_width() - overlay->get_width()) / 2, (thumbnail->get_height() - overlay->get_height()) / 2);
+ // Overlay and thumbnail need the same format for `blend_rect` to work.
+ thumbnail->convert(Image::FORMAT_RGBA8);
thumbnail->lock();
thumbnail->blend_rect(overlay, overlay->get_used_rect(), overlay_pos);
thumbnail->unlock();
diff --git a/editor/plugins/material_editor_plugin.cpp b/editor/plugins/material_editor_plugin.cpp
index ce8cc77802..ebacccb03c 100644
--- a/editor/plugins/material_editor_plugin.cpp
+++ b/editor/plugins/material_editor_plugin.cpp
@@ -32,6 +32,210 @@
#include "scene/resources/particles_material.h"
+void MaterialEditor::_notification(int p_what) {
+
+ if (p_what == NOTIFICATION_PHYSICS_PROCESS) {
+ }
+
+ if (p_what == NOTIFICATION_READY) {
+
+ //get_scene()->connect("node_removed",this,"_node_removed");
+
+ if (first_enter) {
+ //it's in propertyeditor so.. could be moved around
+
+ light_1_switch->set_normal_texture(get_icon("MaterialPreviewLight1", "EditorIcons"));
+ light_1_switch->set_pressed_texture(get_icon("MaterialPreviewLight1Off", "EditorIcons"));
+ light_2_switch->set_normal_texture(get_icon("MaterialPreviewLight2", "EditorIcons"));
+ light_2_switch->set_pressed_texture(get_icon("MaterialPreviewLight2Off", "EditorIcons"));
+
+ sphere_switch->set_normal_texture(get_icon("MaterialPreviewSphereOff", "EditorIcons"));
+ sphere_switch->set_pressed_texture(get_icon("MaterialPreviewSphere", "EditorIcons"));
+ box_switch->set_normal_texture(get_icon("MaterialPreviewCubeOff", "EditorIcons"));
+ box_switch->set_pressed_texture(get_icon("MaterialPreviewCube", "EditorIcons"));
+
+ first_enter = false;
+ }
+ }
+
+ if (p_what == NOTIFICATION_DRAW) {
+
+ Ref<Texture> checkerboard = get_icon("Checkerboard", "EditorIcons");
+ Size2 size = get_size();
+
+ draw_texture_rect(checkerboard, Rect2(Point2(), size), true);
+ }
+}
+
+void MaterialEditor::edit(Ref<Material> p_material, const Ref<Environment> &p_env) {
+
+ material = p_material;
+ camera->set_environment(p_env);
+ if (!material.is_null()) {
+ sphere_instance->set_material_override(material);
+ box_instance->set_material_override(material);
+ } else {
+
+ hide();
+ }
+}
+
+void MaterialEditor::_button_pressed(Node *p_button) {
+
+ if (p_button == light_1_switch) {
+ light1->set_visible(!light_1_switch->is_pressed());
+ }
+
+ if (p_button == light_2_switch) {
+ light2->set_visible(!light_2_switch->is_pressed());
+ }
+
+ if (p_button == box_switch) {
+ box_instance->show();
+ sphere_instance->hide();
+ box_switch->set_pressed(true);
+ sphere_switch->set_pressed(false);
+ }
+
+ if (p_button == sphere_switch) {
+ box_instance->hide();
+ sphere_instance->show();
+ box_switch->set_pressed(false);
+ sphere_switch->set_pressed(true);
+ }
+}
+
+void MaterialEditor::_bind_methods() {
+
+ ClassDB::bind_method(D_METHOD("_button_pressed"), &MaterialEditor::_button_pressed);
+}
+
+MaterialEditor::MaterialEditor() {
+
+ vc = memnew(ViewportContainer);
+ vc->set_stretch(true);
+ add_child(vc);
+ vc->set_anchors_and_margins_preset(PRESET_WIDE);
+ viewport = memnew(Viewport);
+ Ref<World> world;
+ world.instance();
+ viewport->set_world(world); //use own world
+ vc->add_child(viewport);
+ viewport->set_disable_input(true);
+ viewport->set_transparent_background(true);
+ viewport->set_msaa(Viewport::MSAA_4X);
+
+ camera = memnew(Camera);
+ camera->set_transform(Transform(Basis(), Vector3(0, 0, 3)));
+ camera->set_perspective(45, 0.1, 10);
+ camera->make_current();
+ viewport->add_child(camera);
+
+ light1 = memnew(DirectionalLight);
+ light1->set_transform(Transform().looking_at(Vector3(-1, -1, -1), Vector3(0, 1, 0)));
+ viewport->add_child(light1);
+
+ light2 = memnew(DirectionalLight);
+ light2->set_transform(Transform().looking_at(Vector3(0, 1, 0), Vector3(0, 0, 1)));
+ light2->set_color(Color(0.7, 0.7, 0.7));
+ viewport->add_child(light2);
+
+ sphere_instance = memnew(MeshInstance);
+ viewport->add_child(sphere_instance);
+
+ box_instance = memnew(MeshInstance);
+ viewport->add_child(box_instance);
+
+ Transform box_xform;
+ box_xform.basis.rotate(Vector3(1, 0, 0), Math::deg2rad(25.0));
+ box_xform.basis = box_xform.basis * Basis().rotated(Vector3(0, 1, 0), Math::deg2rad(-25.0));
+ box_xform.basis.scale(Vector3(0.8, 0.8, 0.8));
+ box_xform.origin.y = 0.2;
+ box_instance->set_transform(box_xform);
+
+ sphere_mesh.instance();
+ sphere_instance->set_mesh(sphere_mesh);
+ box_mesh.instance();
+ box_instance->set_mesh(box_mesh);
+ box_instance->hide();
+
+ set_custom_minimum_size(Size2(1, 150) * EDSCALE);
+
+ HBoxContainer *hb = memnew(HBoxContainer);
+ add_child(hb);
+ hb->set_anchors_and_margins_preset(Control::PRESET_WIDE, Control::PRESET_MODE_MINSIZE, 2);
+
+ VBoxContainer *vb_shape = memnew(VBoxContainer);
+ hb->add_child(vb_shape);
+
+ sphere_switch = memnew(TextureButton);
+ sphere_switch->set_toggle_mode(true);
+ sphere_switch->set_pressed(true);
+ vb_shape->add_child(sphere_switch);
+ sphere_switch->connect("pressed", this, "_button_pressed", varray(sphere_switch));
+
+ box_switch = memnew(TextureButton);
+ box_switch->set_toggle_mode(true);
+ box_switch->set_pressed(false);
+ vb_shape->add_child(box_switch);
+ box_switch->connect("pressed", this, "_button_pressed", varray(box_switch));
+
+ hb->add_spacer();
+
+ VBoxContainer *vb_light = memnew(VBoxContainer);
+ hb->add_child(vb_light);
+
+ light_1_switch = memnew(TextureButton);
+ light_1_switch->set_toggle_mode(true);
+ vb_light->add_child(light_1_switch);
+ light_1_switch->connect("pressed", this, "_button_pressed", varray(light_1_switch));
+
+ light_2_switch = memnew(TextureButton);
+ light_2_switch->set_toggle_mode(true);
+ vb_light->add_child(light_2_switch);
+ light_2_switch->connect("pressed", this, "_button_pressed", varray(light_2_switch));
+
+ first_enter = true;
+}
+
+///////////////////////
+
+bool EditorInspectorPluginMaterial::can_handle(Object *p_object) {
+
+ Material *material = Object::cast_to<Material>(p_object);
+ if (!material)
+ return false;
+
+ return material->get_shader_mode() == Shader::MODE_SPATIAL;
+}
+
+void EditorInspectorPluginMaterial::parse_begin(Object *p_object) {
+
+ Material *material = Object::cast_to<Material>(p_object);
+ if (!material) {
+ return;
+ }
+ Ref<Material> m(material);
+
+ MaterialEditor *editor = memnew(MaterialEditor);
+ editor->edit(m, env);
+ add_custom_control(editor);
+}
+
+EditorInspectorPluginMaterial::EditorInspectorPluginMaterial() {
+ env.instance();
+ Ref<ProceduralSky> proc_sky = memnew(ProceduralSky(true));
+ env->set_sky(proc_sky);
+ env->set_background(Environment::BG_COLOR_SKY);
+}
+
+MaterialEditorPlugin::MaterialEditorPlugin(EditorNode *p_node) {
+
+ Ref<EditorInspectorPluginMaterial> plugin;
+ plugin.instance();
+ add_inspector_plugin(plugin);
+}
+
String SpatialMaterialConversionPlugin::converts_to() const {
return "ShaderMaterial";
diff --git a/editor/plugins/material_editor_plugin.h b/editor/plugins/material_editor_plugin.h
index 39935d3e12..c3f14c27e5 100644
--- a/editor/plugins/material_editor_plugin.h
+++ b/editor/plugins/material_editor_plugin.h
@@ -32,6 +32,71 @@
#define MATERIAL_EDITOR_PLUGIN_H
#include "editor/property_editor.h"
+#include "scene/resources/primitive_meshes.h"
+
+#include "editor/editor_node.h"
+#include "editor/editor_plugin.h"
+#include "scene/3d/camera.h"
+#include "scene/3d/light.h"
+#include "scene/3d/mesh_instance.h"
+#include "scene/resources/material.h"
+
+class MaterialEditor : public Control {
+
+ GDCLASS(MaterialEditor, Control);
+
+ ViewportContainer *vc;
+ Viewport *viewport;
+ MeshInstance *sphere_instance;
+ MeshInstance *box_instance;
+ DirectionalLight *light1;
+ DirectionalLight *light2;
+ Camera *camera;
+
+ Ref<SphereMesh> sphere_mesh;
+ Ref<CubeMesh> box_mesh;
+
+ TextureButton *sphere_switch;
+ TextureButton *box_switch;
+
+ TextureButton *light_1_switch;
+ TextureButton *light_2_switch;
+
+ Ref<Material> material;
+
+ void _button_pressed(Node *p_button);
+ bool first_enter;
+
+protected:
+ void _notification(int p_what);
+
+ static void _bind_methods();
+
+public:
+ void edit(Ref<Material> p_material, const Ref<Environment> &p_env);
+ MaterialEditor();
+};
+
+class EditorInspectorPluginMaterial : public EditorInspectorPlugin {
+ GDCLASS(EditorInspectorPluginMaterial, EditorInspectorPlugin)
+ Ref<Environment> env;
+
+public:
+ virtual bool can_handle(Object *p_object);
+ virtual void parse_begin(Object *p_object);
+
+ EditorInspectorPluginMaterial();
+};
+
+class MaterialEditorPlugin : public EditorPlugin {
+
+ GDCLASS(MaterialEditorPlugin, EditorPlugin);
+
+public:
+ virtual String get_name() const { return "Material"; }
+
+ MaterialEditorPlugin(EditorNode *p_node);
+};
class SpatialMaterialConversionPlugin : public EditorResourceConversionPlugin {
GDCLASS(SpatialMaterialConversionPlugin, EditorResourceConversionPlugin)
diff --git a/editor/plugins/mesh_editor_plugin.cpp b/editor/plugins/mesh_editor_plugin.cpp
index fcf515e3fc..6203035e25 100644
--- a/editor/plugins/mesh_editor_plugin.cpp
+++ b/editor/plugins/mesh_editor_plugin.cpp
@@ -80,26 +80,21 @@ void MeshEditor::edit(Ref<Mesh> p_mesh) {
mesh = p_mesh;
mesh_instance->set_mesh(mesh);
- if (mesh.is_null()) {
-
- hide();
- } else {
- rot_x = 0;
- rot_y = 0;
- _update_rotation();
-
- AABB aabb = mesh->get_aabb();
- Vector3 ofs = aabb.position + aabb.size * 0.5;
- float m = aabb.get_longest_axis_size();
- if (m != 0) {
- m = 1.0 / m;
- m *= 0.5;
- Transform xform;
- xform.basis.scale(Vector3(m, m, m));
- xform.origin = -xform.basis.xform(ofs); //-ofs*m;
- //xform.origin.z -= aabb.get_longest_axis_size() * 2;
- mesh_instance->set_transform(xform);
- }
+ rot_x = Math::deg2rad(-15.0);
+ rot_y = Math::deg2rad(30.0);
+ _update_rotation();
+
+ AABB aabb = mesh->get_aabb();
+ Vector3 ofs = aabb.position + aabb.size * 0.5;
+ float m = aabb.get_longest_axis_size();
+ if (m != 0) {
+ m = 1.0 / m;
+ m *= 0.5;
+ Transform xform;
+ xform.basis.scale(Vector3(m, m, m));
+ xform.origin = -xform.basis.xform(ofs); //-ofs*m;
+ //xform.origin.z -= aabb.get_longest_axis_size() * 2;
+ mesh_instance->set_transform(xform);
}
}
@@ -128,8 +123,8 @@ MeshEditor::MeshEditor() {
viewport->set_world(world); //use own world
add_child(viewport);
viewport->set_disable_input(true);
+ viewport->set_msaa(Viewport::MSAA_2X);
set_stretch(true);
-
camera = memnew(Camera);
camera->set_transform(Transform(Basis(), Vector3(0, 0, 1.1)));
camera->set_perspective(45, 0.1, 10);
@@ -176,39 +171,29 @@ MeshEditor::MeshEditor() {
rot_y = 0;
}
-void MeshEditorPlugin::edit(Object *p_object) {
-
- Mesh *s = Object::cast_to<Mesh>(p_object);
- if (!s)
- return;
-
- mesh_editor->edit(Ref<Mesh>(s));
-}
+///////////////////////
-bool MeshEditorPlugin::handles(Object *p_object) const {
+bool EditorInspectorPluginMesh::can_handle(Object *p_object) {
- return p_object->is_class("Mesh");
+ return Object::cast_to<Mesh>(p_object) != NULL;
}
-void MeshEditorPlugin::make_visible(bool p_visible) {
+void EditorInspectorPluginMesh::parse_begin(Object *p_object) {
- if (p_visible) {
- mesh_editor->show();
- //mesh_editor->set_process(true);
- } else {
-
- mesh_editor->hide();
- //mesh_editor->set_process(false);
+ Mesh *mesh = Object::cast_to<Mesh>(p_object);
+ if (!mesh) {
+ return;
}
+ Ref<Mesh> m(mesh);
+
+ MeshEditor *editor = memnew(MeshEditor);
+ editor->edit(m);
+ add_custom_control(editor);
}
MeshEditorPlugin::MeshEditorPlugin(EditorNode *p_node) {
- editor = p_node;
- mesh_editor = memnew(MeshEditor);
- add_control_to_container(CONTAINER_PROPERTY_EDITOR_BOTTOM, mesh_editor);
- mesh_editor->hide();
-}
-
-MeshEditorPlugin::~MeshEditorPlugin() {
+ Ref<EditorInspectorPluginMesh> plugin;
+ plugin.instance();
+ add_inspector_plugin(plugin);
}
diff --git a/editor/plugins/mesh_editor_plugin.h b/editor/plugins/mesh_editor_plugin.h
index 0275f45be9..8ada2dac90 100644
--- a/editor/plugins/mesh_editor_plugin.h
+++ b/editor/plugins/mesh_editor_plugin.h
@@ -72,22 +72,21 @@ public:
MeshEditor();
};
+class EditorInspectorPluginMesh : public EditorInspectorPlugin {
+ GDCLASS(EditorInspectorPluginMesh, EditorInspectorPlugin)
+public:
+ virtual bool can_handle(Object *p_object);
+ virtual void parse_begin(Object *p_object);
+};
+
class MeshEditorPlugin : public EditorPlugin {
GDCLASS(MeshEditorPlugin, EditorPlugin);
- MeshEditor *mesh_editor;
- EditorNode *editor;
-
public:
virtual String get_name() const { return "Mesh"; }
- bool has_main_screen() const { return false; }
- virtual void edit(Object *p_object);
- virtual bool handles(Object *p_object) const;
- virtual void make_visible(bool p_visible);
MeshEditorPlugin(EditorNode *p_node);
- ~MeshEditorPlugin();
};
#endif
diff --git a/editor/plugins/particles_2d_editor_plugin.cpp b/editor/plugins/particles_2d_editor_plugin.cpp
index bb7d50a9c1..d00687f7ea 100644
--- a/editor/plugins/particles_2d_editor_plugin.cpp
+++ b/editor/plugins/particles_2d_editor_plugin.cpp
@@ -133,7 +133,10 @@ void Particles2DEditorPlugin::_generate_visibility_rect() {
particles->set_emitting(false);
}
- particles->set_visibility_rect(rect);
+ undo_redo->create_action(TTR("Generate Visibility Rect"));
+ undo_redo->add_do_method(particles, "set_visibility_rect", rect);
+ undo_redo->add_undo_method(particles, "set_visibility_rect", particles->get_visibility_rect());
+ undo_redo->commit_action();
}
void Particles2DEditorPlugin::_generate_emission_mask() {
diff --git a/editor/plugins/particles_editor_plugin.cpp b/editor/plugins/particles_editor_plugin.cpp
index 95828064ac..0032850535 100644
--- a/editor/plugins/particles_editor_plugin.cpp
+++ b/editor/plugins/particles_editor_plugin.cpp
@@ -353,7 +353,11 @@ void ParticlesEditor::_generate_aabb() {
node->set_emitting(false);
}
- node->set_visibility_aabb(rect);
+ UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
+ ur->create_action(TTR("Generate Visibility AABB"));
+ ur->add_do_method(node, "set_visibility_aabb", rect);
+ ur->add_undo_method(node, "set_visibility_aabb", node->get_visibility_aabb());
+ ur->commit_action();
}
void ParticlesEditor::edit(Particles *p_particles) {
diff --git a/editor/plugins/path_editor_plugin.cpp b/editor/plugins/path_editor_plugin.cpp
index 6efa76ef80..88dc258c5f 100644
--- a/editor/plugins/path_editor_plugin.cpp
+++ b/editor/plugins/path_editor_plugin.cpp
@@ -638,6 +638,10 @@ String PathSpatialGizmoPlugin::get_name() const {
return "Path";
}
+int PathSpatialGizmoPlugin::get_priority() const {
+ return -1;
+}
+
PathSpatialGizmoPlugin::PathSpatialGizmoPlugin() {
Color path_color = EDITOR_DEF("editors/3d_gizmos/gizmo_colors/path", Color(0.5, 0.5, 1.0, 0.8));
diff --git a/editor/plugins/path_editor_plugin.h b/editor/plugins/path_editor_plugin.h
index ce3d3799d4..5482d09377 100644
--- a/editor/plugins/path_editor_plugin.h
+++ b/editor/plugins/path_editor_plugin.h
@@ -62,6 +62,7 @@ protected:
public:
String get_name() const;
+ int get_priority() const;
PathSpatialGizmoPlugin();
};
diff --git a/editor/plugins/script_editor_plugin.cpp b/editor/plugins/script_editor_plugin.cpp
index 9e65d9de10..e648fa0820 100644
--- a/editor/plugins/script_editor_plugin.cpp
+++ b/editor/plugins/script_editor_plugin.cpp
@@ -2206,6 +2206,9 @@ void ScriptEditor::_script_split_dragged(float) {
Variant ScriptEditor::get_drag_data_fw(const Point2 &p_point, Control *p_from) {
+ if (tab_container->get_child_count() == 0)
+ return Variant();
+
Node *cur_node = tab_container->get_child(tab_container->get_current_tab());
HBoxContainer *drag_preview = memnew(HBoxContainer);
diff --git a/editor/plugins/script_text_editor.cpp b/editor/plugins/script_text_editor.cpp
index e95b1356bf..554e12f9fd 100644
--- a/editor/plugins/script_text_editor.cpp
+++ b/editor/plugins/script_text_editor.cpp
@@ -620,7 +620,9 @@ void ScriptTextEditor::_lookup_symbol(const String &p_symbol, int p_row, int p_c
}
ScriptLanguage::LookupResult result;
- if (p_symbol.is_resource_file()) {
+ if (ScriptServer::is_global_class(p_symbol)) {
+ EditorNode::get_singleton()->load_resource(ScriptServer::get_global_class_path(p_symbol));
+ } else if (p_symbol.is_resource_file()) {
List<String> scene_extensions;
ResourceLoader::get_recognized_extensions_for_type("PackedScene", &scene_extensions);
diff --git a/editor/plugins/shader_editor_plugin.cpp b/editor/plugins/shader_editor_plugin.cpp
index 020a68a7ed..2b6ceac8e2 100644
--- a/editor/plugins/shader_editor_plugin.cpp
+++ b/editor/plugins/shader_editor_plugin.cpp
@@ -47,6 +47,9 @@ Ref<Shader> ShaderTextEditor::get_edited_shader() const {
}
void ShaderTextEditor::set_edited_shader(const Ref<Shader> &p_shader) {
+ if (shader == p_shader) {
+ return;
+ }
shader = p_shader;
_load_theme_settings();
@@ -352,8 +355,8 @@ void ShaderEditor::_menu_option(int p_option) {
void ShaderEditor::_notification(int p_what) {
if (p_what == NOTIFICATION_VISIBILITY_CHANGED) {
- if (is_visible_in_tree())
- shader_editor->get_text_edit()->grab_focus();
+ //if (is_visible_in_tree())
+ // shader_editor->get_text_edit()->grab_focus();
}
}
@@ -415,6 +418,9 @@ void ShaderEditor::edit(const Ref<Shader> &p_shader) {
if (p_shader.is_null() || !p_shader->is_text_shader())
return;
+ if (shader == p_shader)
+ return;
+
shader = p_shader;
shader_editor->set_edited_shader(p_shader);
@@ -438,8 +444,12 @@ void ShaderEditor::save_external_data() {
void ShaderEditor::apply_shaders() {
if (shader.is_valid()) {
- shader->set_code(shader_editor->get_text_edit()->get_text());
- shader->set_edited(true);
+ String shader_code = shader->get_code();
+ String editor_code = shader_editor->get_text_edit()->get_text();
+ if (shader_code != editor_code) {
+ shader->set_code(editor_code);
+ shader->set_edited(true);
+ }
}
}
diff --git a/editor/plugins/spatial_editor_plugin.cpp b/editor/plugins/spatial_editor_plugin.cpp
index 1e9ff87fd3..765d198f79 100644
--- a/editor/plugins/spatial_editor_plugin.cpp
+++ b/editor/plugins/spatial_editor_plugin.cpp
@@ -1021,7 +1021,7 @@ void SpatialEditorViewport::_sinput(const Ref<InputEvent> &p_event) {
}
_edit.mouse_pos = b->get_position();
- _edit.snap = false;
+ _edit.snap = spatial_editor->is_snap_enabled();
_edit.mode = TRANSFORM_NONE;
//gizmo has priority over everything
@@ -1772,7 +1772,7 @@ void SpatialEditorViewport::_sinput(const Ref<InputEvent> &p_event) {
if (ED_IS_SHORTCUT("spatial_editor/snap", p_event)) {
if (_edit.mode != TRANSFORM_NONE) {
- _edit.snap = true;
+ _edit.snap = !_edit.snap;
}
}
if (ED_IS_SHORTCUT("spatial_editor/bottom_view", p_event)) {
@@ -2108,9 +2108,11 @@ void SpatialEditorViewport::_notification(int p_what) {
set_process(visible);
- if (visible)
+ if (visible) {
_update_camera(0);
-
+ } else {
+ set_freelook_active(false);
+ }
call_deferred("update_transform_gizmo_view");
}
@@ -4115,10 +4117,10 @@ Dictionary SpatialEditor::get_state() const {
d["zfar"] = get_zfar();
Dictionary gizmos_status;
- for (int i = 0; i < gizmo_plugins.size(); i++) {
- if (!gizmo_plugins[i]->can_be_hidden()) continue;
+ for (int i = 0; i < gizmo_plugins_by_name.size(); i++) {
+ if (!gizmo_plugins_by_name[i]->can_be_hidden()) continue;
int state = gizmos_menu->get_item_state(gizmos_menu->get_item_index(i));
- String name = gizmo_plugins[i]->get_name();
+ String name = gizmo_plugins_by_name[i]->get_name();
gizmos_status[name] = state;
}
@@ -4168,9 +4170,13 @@ void SpatialEditor::set_state(const Dictionary &p_state) {
if (d.has("viewports")) {
Array vp = d["viewports"];
- ERR_FAIL_COND(vp.size() > 4);
+ uint32_t vp_size = static_cast<uint32_t>(vp.size());
+ if (vp_size > VIEWPORTS_COUNT) {
+ WARN_PRINT("Ignoring superfluous viewport settings from spatial editor state.")
+ vp_size = VIEWPORTS_COUNT;
+ }
- for (uint32_t i = 0; i < VIEWPORTS_COUNT; i++) {
+ for (uint32_t i = 0; i < vp_size; i++) {
viewports[i]->set_state(vp[i]);
}
}
@@ -4203,32 +4209,19 @@ void SpatialEditor::set_state(const Dictionary &p_state) {
List<Variant> keys;
gizmos_status.get_key_list(&keys);
- for (int j = 0; j < gizmo_plugins.size(); ++j) {
- if (!gizmo_plugins[j]->can_be_hidden()) continue;
- int state = EditorSpatialGizmoPlugin::ON_TOP;
+ for (int j = 0; j < gizmo_plugins_by_name.size(); ++j) {
+ if (!gizmo_plugins_by_name[j]->can_be_hidden()) continue;
+ int state = EditorSpatialGizmoPlugin::VISIBLE;
for (int i = 0; i < keys.size(); i++) {
- if (gizmo_plugins.write[j]->get_name() == keys[i]) {
+ if (gizmo_plugins_by_name.write[j]->get_name() == keys[i]) {
state = gizmos_status[keys[i]];
+ break;
}
}
- const int idx = gizmos_menu->get_item_index(j);
-
- gizmos_menu->set_item_multistate(idx, state);
- gizmo_plugins.write[j]->set_state(state);
-
- switch (state) {
- case EditorSpatialGizmoPlugin::VISIBLE:
- gizmos_menu->set_item_icon(idx, gizmos_menu->get_icon("visibility_visible"));
- break;
- case EditorSpatialGizmoPlugin::ON_TOP:
- gizmos_menu->set_item_icon(idx, gizmos_menu->get_icon("visibility_xray"));
- break;
- case EditorSpatialGizmoPlugin::HIDDEN:
- gizmos_menu->set_item_icon(idx, gizmos_menu->get_icon("visibility_hidden"));
- break;
- }
+ gizmo_plugins_by_name.write[j]->set_state(state);
}
+ _update_gizmos_menu();
}
}
@@ -4342,7 +4335,7 @@ void SpatialEditor::_menu_gizmo_toggled(int p_option) {
break;
}
- gizmo_plugins.write[p_option]->set_state(state);
+ gizmo_plugins_by_name.write[p_option]->set_state(state);
update_all_gizmos();
}
@@ -4838,30 +4831,46 @@ void SpatialEditor::_init_indicators() {
_generate_selection_box();
}
-struct _GizmoPluginComparator {
-
- bool operator()(const Ref<EditorSpatialGizmoPlugin> &p_a, const Ref<EditorSpatialGizmoPlugin> &p_b) const {
- return p_a->get_name() < p_b->get_name();
- }
-};
-
void SpatialEditor::_update_gizmos_menu() {
gizmos_menu->clear();
- gizmo_plugins.sort_custom<_GizmoPluginComparator>();
- for (int i = 0; i < gizmo_plugins.size(); ++i) {
- if (!gizmo_plugins[i]->can_be_hidden()) continue;
- String plugin_name = gizmo_plugins[i]->get_name();
- gizmos_menu->add_multistate_item(TTR(plugin_name), 3, EditorSpatialGizmoPlugin::VISIBLE, i);
- gizmos_menu->set_item_icon(gizmos_menu->get_item_index(i), gizmos_menu->get_icon("visibility_visible"));
+ for (int i = 0; i < gizmo_plugins_by_name.size(); ++i) {
+ if (!gizmo_plugins_by_name[i]->can_be_hidden()) continue;
+ String plugin_name = gizmo_plugins_by_name[i]->get_name();
+ const int plugin_state = gizmo_plugins_by_name[i]->get_state();
+ gizmos_menu->add_multistate_item(TTR(plugin_name), 3, plugin_state, i);
+ const int idx = gizmos_menu->get_item_index(i);
+ switch (plugin_state) {
+ case EditorSpatialGizmoPlugin::VISIBLE:
+ gizmos_menu->set_item_icon(idx, gizmos_menu->get_icon("visibility_visible"));
+ break;
+ case EditorSpatialGizmoPlugin::ON_TOP:
+ gizmos_menu->set_item_icon(idx, gizmos_menu->get_icon("visibility_xray"));
+ break;
+ case EditorSpatialGizmoPlugin::HIDDEN:
+ gizmos_menu->set_item_icon(idx, gizmos_menu->get_icon("visibility_hidden"));
+ break;
+ }
}
}
void SpatialEditor::_update_gizmos_menu_theme() {
- for (int i = 0; i < gizmo_plugins.size(); ++i) {
- if (!gizmo_plugins[i]->can_be_hidden()) continue;
- gizmos_menu->set_item_icon(gizmos_menu->get_item_index(i), gizmos_menu->get_icon("visibility_visible"));
+ for (int i = 0; i < gizmo_plugins_by_name.size(); ++i) {
+ if (!gizmo_plugins_by_name[i]->can_be_hidden()) continue;
+ const int plugin_state = gizmo_plugins_by_name[i]->get_state();
+ const int idx = gizmos_menu->get_item_index(i);
+ switch (plugin_state) {
+ case EditorSpatialGizmoPlugin::VISIBLE:
+ gizmos_menu->set_item_icon(idx, gizmos_menu->get_icon("visibility_visible"));
+ break;
+ case EditorSpatialGizmoPlugin::ON_TOP:
+ gizmos_menu->set_item_icon(idx, gizmos_menu->get_icon("visibility_xray"));
+ break;
+ case EditorSpatialGizmoPlugin::HIDDEN:
+ gizmos_menu->set_item_icon(idx, gizmos_menu->get_icon("visibility_hidden"));
+ break;
+ }
}
}
@@ -5223,8 +5232,8 @@ void SpatialEditor::_request_gizmo(Object *p_obj) {
Ref<EditorSpatialGizmo> seg;
- for (int i = 0; i < gizmo_plugins.size(); ++i) {
- seg = gizmo_plugins.write[i]->get_gizmo(sp);
+ for (int i = 0; i < gizmo_plugins_by_priority.size(); ++i) {
+ seg = gizmo_plugins_by_priority.write[i]->get_gizmo(sp);
if (seg.is_valid()) {
sp->set_gizmo(seg);
@@ -5749,15 +5758,39 @@ void SpatialEditorPlugin::snap_cursor_to_plane(const Plane &p_plane) {
spatial_editor->snap_cursor_to_plane(p_plane);
}
+struct _GizmoPluginPriorityComparator {
+
+ bool operator()(const Ref<EditorSpatialGizmoPlugin> &p_a, const Ref<EditorSpatialGizmoPlugin> &p_b) const {
+ if (p_a->get_priority() == p_b->get_priority()) {
+ return p_a->get_name() < p_b->get_name();
+ }
+ return p_a->get_priority() > p_b->get_priority();
+ }
+};
+
+struct _GizmoPluginNameComparator {
+
+ bool operator()(const Ref<EditorSpatialGizmoPlugin> &p_a, const Ref<EditorSpatialGizmoPlugin> &p_b) const {
+ return p_a->get_name() < p_b->get_name();
+ }
+};
+
void SpatialEditor::add_gizmo_plugin(Ref<EditorSpatialGizmoPlugin> p_plugin) {
ERR_FAIL_NULL(p_plugin.ptr());
- gizmo_plugins.push_back(p_plugin);
+
+ gizmo_plugins_by_priority.push_back(p_plugin);
+ gizmo_plugins_by_priority.sort_custom<_GizmoPluginPriorityComparator>();
+
+ gizmo_plugins_by_name.push_back(p_plugin);
+ gizmo_plugins_by_name.sort_custom<_GizmoPluginNameComparator>();
+
_update_gizmos_menu();
SpatialEditor::get_singleton()->update_all_gizmos();
}
void SpatialEditor::remove_gizmo_plugin(Ref<EditorSpatialGizmoPlugin> p_plugin) {
- gizmo_plugins.erase(p_plugin);
+ gizmo_plugins_by_priority.erase(p_plugin);
+ gizmo_plugins_by_name.erase(p_plugin);
_update_gizmos_menu();
}
@@ -5910,6 +5943,13 @@ String EditorSpatialGizmoPlugin::get_name() const {
return TTR("Nameless gizmo");
}
+int EditorSpatialGizmoPlugin::get_priority() const {
+ if (get_script_instance() && get_script_instance()->has_method("get_priority")) {
+ return get_script_instance()->call("get_priority");
+ }
+ return 0;
+}
+
Ref<EditorSpatialGizmo> EditorSpatialGizmoPlugin::get_gizmo(Spatial *p_spatial) {
if (get_script_instance() && get_script_instance()->has_method("get_gizmo")) {
@@ -5942,6 +5982,7 @@ void EditorSpatialGizmoPlugin::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_material", "name", "gizmo"), &EditorSpatialGizmoPlugin::get_material); //, DEFVAL(Ref<EditorSpatialGizmo>()));
BIND_VMETHOD(MethodInfo(Variant::STRING, "get_name"));
+ BIND_VMETHOD(MethodInfo(Variant::STRING, "get_priority"));
BIND_VMETHOD(MethodInfo(Variant::BOOL, "can_be_hidden"));
BIND_VMETHOD(MethodInfo(Variant::BOOL, "is_selectable_when_hidden"));
@@ -6041,6 +6082,10 @@ void EditorSpatialGizmoPlugin::set_state(int p_state) {
}
}
+int EditorSpatialGizmoPlugin::get_state() const {
+ return current_state;
+}
+
void EditorSpatialGizmoPlugin::unregister_gizmo(EditorSpatialGizmo *p_gizmo) {
current_gizmos.erase(p_gizmo);
}
diff --git a/editor/plugins/spatial_editor_plugin.h b/editor/plugins/spatial_editor_plugin.h
index 6256b8b055..4a9d34a7f7 100644
--- a/editor/plugins/spatial_editor_plugin.h
+++ b/editor/plugins/spatial_editor_plugin.h
@@ -639,7 +639,8 @@ private:
static SpatialEditor *singleton;
void _node_removed(Node *p_node);
- Vector<Ref<EditorSpatialGizmoPlugin> > gizmo_plugins;
+ Vector<Ref<EditorSpatialGizmoPlugin> > gizmo_plugins_by_priority;
+ Vector<Ref<EditorSpatialGizmoPlugin> > gizmo_plugins_by_name;
void _register_all_gizmos();
@@ -782,6 +783,7 @@ public:
Ref<SpatialMaterial> get_material(const String &p_name, const Ref<EditorSpatialGizmo> &p_gizmo = Ref<EditorSpatialGizmo>());
virtual String get_name() const;
+ virtual int get_priority() const;
virtual bool can_be_hidden() const;
virtual bool is_selectable_when_hidden() const;
@@ -794,6 +796,7 @@ public:
Ref<EditorSpatialGizmo> get_gizmo(Spatial *p_spatial);
void set_state(int p_state);
+ int get_state() const;
void unregister_gizmo(EditorSpatialGizmo *p_gizmo);
EditorSpatialGizmoPlugin();
diff --git a/editor/plugins/sprite_editor_plugin.cpp b/editor/plugins/sprite_editor_plugin.cpp
index c1718dd8bf..3854d27567 100644
--- a/editor/plugins/sprite_editor_plugin.cpp
+++ b/editor/plugins/sprite_editor_plugin.cpp
@@ -91,6 +91,8 @@ Vector<Vector2> expand(const Vector<Vector2> &points, const Rect2i &rect, float
Vector<Vector2> outPoints;
ClipperLib::PolyNode *p2 = out.GetFirst();
+ ERR_FAIL_COND_V(!p2, points);
+
while (p2->IsHole()) {
p2 = p2->GetNext();
}
diff --git a/editor/plugins/texture_editor_plugin.cpp b/editor/plugins/texture_editor_plugin.cpp
index 0482ae86f3..0aa4a7662c 100644
--- a/editor/plugins/texture_editor_plugin.cpp
+++ b/editor/plugins/texture_editor_plugin.cpp
@@ -138,39 +138,33 @@ TextureEditor::TextureEditor() {
set_custom_minimum_size(Size2(1, 150));
}
-void TextureEditorPlugin::edit(Object *p_object) {
-
- Texture *s = Object::cast_to<Texture>(p_object);
- if (!s)
- return;
-
- texture_editor->edit(Ref<Texture>(s));
+TextureEditor::~TextureEditor() {
+ if (!texture.is_null()) {
+ texture->remove_change_receptor(this);
+ }
}
+//
+bool EditorInspectorPluginTexture::can_handle(Object *p_object) {
-bool TextureEditorPlugin::handles(Object *p_object) const {
-
- return p_object->is_class("Texture");
+ return Object::cast_to<ImageTexture>(p_object) != NULL || Object::cast_to<AtlasTexture>(p_object) != NULL || Object::cast_to<StreamTexture>(p_object) != NULL || Object::cast_to<LargeTexture>(p_object) != NULL || Object::cast_to<AnimatedTexture>(p_object) != NULL;
}
-void TextureEditorPlugin::make_visible(bool p_visible) {
+void EditorInspectorPluginTexture::parse_begin(Object *p_object) {
- if (p_visible) {
- texture_editor->show();
- //texture_editor->set_process(true);
- } else {
-
- texture_editor->hide();
- //texture_editor->set_process(false);
+ Texture *texture = Object::cast_to<Texture>(p_object);
+ if (!texture) {
+ return;
}
+ Ref<Texture> m(texture);
+
+ TextureEditor *editor = memnew(TextureEditor);
+ editor->edit(m);
+ add_custom_control(editor);
}
TextureEditorPlugin::TextureEditorPlugin(EditorNode *p_node) {
- editor = p_node;
- texture_editor = memnew(TextureEditor);
- add_control_to_container(CONTAINER_PROPERTY_EDITOR_BOTTOM, texture_editor);
- texture_editor->hide();
-}
-
-TextureEditorPlugin::~TextureEditorPlugin() {
+ Ref<EditorInspectorPluginTexture> plugin;
+ plugin.instance();
+ add_inspector_plugin(plugin);
}
diff --git a/editor/plugins/texture_editor_plugin.h b/editor/plugins/texture_editor_plugin.h
index 80ff4d6416..bcbda1fbd7 100644
--- a/editor/plugins/texture_editor_plugin.h
+++ b/editor/plugins/texture_editor_plugin.h
@@ -50,24 +50,24 @@ protected:
public:
void edit(Ref<Texture> p_texture);
TextureEditor();
+ ~TextureEditor();
+};
+
+class EditorInspectorPluginTexture : public EditorInspectorPlugin {
+ GDCLASS(EditorInspectorPluginTexture, EditorInspectorPlugin)
+public:
+ virtual bool can_handle(Object *p_object);
+ virtual void parse_begin(Object *p_object);
};
class TextureEditorPlugin : public EditorPlugin {
GDCLASS(TextureEditorPlugin, EditorPlugin);
- TextureEditor *texture_editor;
- EditorNode *editor;
-
public:
virtual String get_name() const { return "Texture"; }
- bool has_main_screen() const { return false; }
- virtual void edit(Object *p_object);
- virtual bool handles(Object *p_object) const;
- virtual void make_visible(bool p_visible);
TextureEditorPlugin(EditorNode *p_node);
- ~TextureEditorPlugin();
};
#endif // TEXTURE_EDITOR_PLUGIN_H
diff --git a/editor/plugins/tile_set_editor_plugin.cpp b/editor/plugins/tile_set_editor_plugin.cpp
index 5b34aaa92a..dc099b84a7 100644
--- a/editor/plugins/tile_set_editor_plugin.cpp
+++ b/editor/plugins/tile_set_editor_plugin.cpp
@@ -201,6 +201,7 @@ void TileSetEditor::_bind_methods() {
ClassDB::bind_method("_zoom_out", &TileSetEditor::_zoom_out);
ClassDB::bind_method("_zoom_reset", &TileSetEditor::_zoom_reset);
ClassDB::bind_method("_select_edited_shape_coord", &TileSetEditor::_select_edited_shape_coord);
+ ClassDB::bind_method("_sort_tiles", &TileSetEditor::_sort_tiles);
ClassDB::bind_method("edit", &TileSetEditor::edit);
ClassDB::bind_method("add_texture", &TileSetEditor::add_texture);
@@ -234,6 +235,8 @@ void TileSetEditor::_notification(int p_what) {
tools[BITMASK_CLEAR]->set_icon(get_icon("Clear", "EditorIcons"));
tools[SHAPE_NEW_POLYGON]->set_icon(get_icon("CollisionPolygon2D", "EditorIcons"));
tools[SHAPE_NEW_RECTANGLE]->set_icon(get_icon("CollisionShape2D", "EditorIcons"));
+ tools[SELECT_PREVIOUS]->set_icon(get_icon("ArrowLeft", "EditorIcons"));
+ tools[SELECT_NEXT]->set_icon(get_icon("ArrowRight", "EditorIcons"));
tools[SHAPE_DELETE]->set_icon(get_icon("Remove", "EditorIcons"));
tools[SHAPE_KEEP_INSIDE_TILE]->set_icon(get_icon("Snap", "EditorIcons"));
tools[TOOL_GRID_SNAP]->set_icon(get_icon("SnapGrid", "EditorIcons"));
@@ -241,6 +244,7 @@ void TileSetEditor::_notification(int p_what) {
tools[ZOOM_1]->set_icon(get_icon("ZoomReset", "EditorIcons"));
tools[ZOOM_IN]->set_icon(get_icon("ZoomMore", "EditorIcons"));
tools[VISIBLE_INFO]->set_icon(get_icon("InformationSign", "EditorIcons"));
+ _update_toggle_shape_button();
tool_editmode[EDITMODE_REGION]->set_icon(get_icon("RegionEdit", "EditorIcons"));
tool_editmode[EDITMODE_COLLISION]->set_icon(get_icon("StaticBody2D", "EditorIcons"));
@@ -324,11 +328,29 @@ TileSetEditor::TileSetEditor(EditorNode *p_editor) {
tool_workspacemode[i]->connect("pressed", this, "_on_workspace_mode_changed", varray(i));
tool_hb->add_child(tool_workspacemode[i]);
}
+
Control *spacer = memnew(Control);
spacer->set_h_size_flags(Control::SIZE_EXPAND_FILL);
tool_hb->add_child(spacer);
tool_hb->move_child(spacer, WORKSPACE_CREATE_SINGLE);
+ tools[SELECT_NEXT] = memnew(ToolButton);
+ tool_hb->add_child(tools[SELECT_NEXT]);
+ tool_hb->move_child(tools[SELECT_NEXT], WORKSPACE_CREATE_SINGLE);
+ tools[SELECT_NEXT]->set_shortcut(ED_SHORTCUT("tileset_editor/next_shape", TTR("Next Coordinate"), KEY_PAGEDOWN));
+ tools[SELECT_NEXT]->connect("pressed", this, "_on_tool_clicked", varray(SELECT_NEXT));
+ tools[SELECT_NEXT]->set_tooltip(TTR("Select the next shape, subtile, or Tile."));
+ tools[SELECT_PREVIOUS] = memnew(ToolButton);
+ tool_hb->add_child(tools[SELECT_PREVIOUS]);
+ tool_hb->move_child(tools[SELECT_PREVIOUS], WORKSPACE_CREATE_SINGLE);
+ tools[SELECT_PREVIOUS]->set_shortcut(ED_SHORTCUT("tileset_editor/previous_shape", TTR("Previous Coordinate"), KEY_PAGEUP));
+ tools[SELECT_PREVIOUS]->set_tooltip(TTR("Select the previous shape, subtile, or Tile."));
+ tools[SELECT_PREVIOUS]->connect("pressed", this, "_on_tool_clicked", varray(SELECT_PREVIOUS));
+
+ VSeparator *separator_shape_selection = memnew(VSeparator);
+ tool_hb->add_child(separator_shape_selection);
+ tool_hb->move_child(separator_shape_selection, WORKSPACE_CREATE_SINGLE);
+
tool_workspacemode[WORKSPACE_EDIT]->set_pressed(true);
workspace_mode = WORKSPACE_EDIT;
@@ -391,6 +413,12 @@ TileSetEditor::TileSetEditor(EditorNode *p_editor) {
tools[SHAPE_NEW_POLYGON]->set_button_group(tg);
tools[SHAPE_NEW_POLYGON]->set_tooltip(TTR("Create a new polygon."));
+ separator_shape_toggle = memnew(VSeparator);
+ toolbar->add_child(separator_shape_toggle);
+ tools[SHAPE_TOGGLE_TYPE] = memnew(ToolButton);
+ tools[SHAPE_TOGGLE_TYPE]->connect("pressed", this, "_on_tool_clicked", varray(SHAPE_TOGGLE_TYPE));
+ toolbar->add_child(tools[SHAPE_TOGGLE_TYPE]);
+
separator_delete = memnew(VSeparator);
toolbar->add_child(separator_delete);
tools[SHAPE_DELETE] = memnew(ToolButton);
@@ -744,6 +772,7 @@ void TileSetEditor::_on_edit_mode_changed(int p_edit_mode) {
} break;
default: {}
}
+ _update_toggle_shape_button();
workspace->update();
}
@@ -1375,8 +1404,7 @@ void TileSetEditor::_on_workspace_input(const Ref<InputEvent> &p_ie) {
}
undo_redo->create_action(TTR("Edit Collision Polygon"));
- undo_redo->add_do_method(edited_collision_shape.ptr(), "set_points", points);
- undo_redo->add_undo_method(edited_collision_shape.ptr(), "set_points", edited_collision_shape->get_points());
+ _set_edited_shape_points(points);
undo_redo->add_do_method(this, "_select_edited_shape_coord");
undo_redo->add_undo_method(this, "_select_edited_shape_coord");
undo_redo->commit_action();
@@ -1454,7 +1482,7 @@ void TileSetEditor::_on_workspace_input(const Ref<InputEvent> &p_ie) {
workspace->update();
} else {
creating_shape = true;
- edited_collision_shape = Ref<ConvexPolygonShape2D>();
+ _set_edited_collision_shape(Ref<ConvexPolygonShape2D>());
current_shape.resize(0);
current_shape.push_back(snap_point(pos));
workspace->update();
@@ -1474,7 +1502,7 @@ void TileSetEditor::_on_workspace_input(const Ref<InputEvent> &p_ie) {
} else if (tools[SHAPE_NEW_RECTANGLE]->is_pressed()) {
if (mb.is_valid()) {
if (mb->is_pressed() && mb->get_button_index() == BUTTON_LEFT) {
- edited_collision_shape = Ref<ConvexPolygonShape2D>();
+ _set_edited_collision_shape(Ref<ConvexPolygonShape2D>());
current_shape.resize(0);
current_shape.push_back(snap_point(shape_anchor));
current_shape.push_back(snap_point(shape_anchor + Vector2(current_tile_region.size.x, 0)));
@@ -1519,6 +1547,49 @@ void TileSetEditor::_on_tool_clicked(int p_tool) {
undo_redo->add_do_method(workspace, "update");
undo_redo->add_undo_method(workspace, "update");
undo_redo->commit_action();
+ } else if (p_tool == SHAPE_TOGGLE_TYPE) {
+ if (edited_collision_shape.is_valid()) {
+ Ref<ConvexPolygonShape2D> convex = edited_collision_shape;
+ Ref<ConcavePolygonShape2D> concave = edited_collision_shape;
+ Ref<Shape2D> previous_shape = edited_collision_shape;
+ Array sd = tileset->call("tile_get_shapes", get_current_tile());
+
+ if (convex.is_valid()) {
+ // Make concave
+ undo_redo->create_action(TTR("Make Polygon Concave"));
+ Ref<ConcavePolygonShape2D> _concave = memnew(ConcavePolygonShape2D);
+ edited_collision_shape = _concave;
+ _set_edited_shape_points(_get_collision_shape_points(convex));
+ } else if (concave.is_valid()) {
+ // Make convex
+ undo_redo->create_action(TTR("Make Polygon Convex"));
+ Ref<ConvexPolygonShape2D> _convex = memnew(ConvexPolygonShape2D);
+ edited_collision_shape = _convex;
+ _set_edited_shape_points(_get_collision_shape_points(concave));
+ } else {
+ // Shoudn't haphen
+ }
+ for (int i = 0; i < sd.size(); i++) {
+ if (sd[i].get("shape") == previous_shape) {
+ undo_redo->add_undo_method(tileset.ptr(), "tile_set_shapes", get_current_tile(), sd.duplicate());
+ sd.remove(i);
+ sd.insert(i, edited_collision_shape);
+ undo_redo->add_do_method(tileset.ptr(), "tile_set_shapes", get_current_tile(), sd);
+ undo_redo->add_do_method(this, "_select_edited_shape_coord");
+ undo_redo->add_undo_method(this, "_select_edited_shape_coord");
+ undo_redo->commit_action();
+ break;
+ }
+ }
+ _update_toggle_shape_button();
+ workspace->update();
+ workspace_container->update();
+ helper->_change_notify("");
+ }
+ } else if (p_tool == SELECT_NEXT) {
+ _select_next_shape();
+ } else if (p_tool == SELECT_PREVIOUS) {
+ _select_previous_shape();
} else if (p_tool == SHAPE_DELETE) {
if (creating_shape) {
creating_shape = false;
@@ -1641,6 +1712,378 @@ void TileSetEditor::_on_grid_snap_toggled(bool p_val) {
workspace->update();
}
+Vector<Vector2> TileSetEditor::_get_collision_shape_points(const Ref<Shape2D> &p_shape) {
+ Ref<ConvexPolygonShape2D> convex = p_shape;
+ Ref<ConcavePolygonShape2D> concave = p_shape;
+ if (convex.is_valid()) {
+ return convex->get_points();
+ } else if (concave.is_valid()) {
+ Vector<Vector2> points;
+ for (int i = 0; i < concave->get_segments().size(); i += 2) {
+ points.push_back(concave->get_segments()[i]);
+ }
+ return points;
+ } else {
+ return Vector<Vector2>();
+ }
+}
+
+Vector<Vector2> TileSetEditor::_get_edited_shape_points() {
+ return _get_collision_shape_points(edited_collision_shape);
+}
+
+void TileSetEditor::_set_edited_shape_points(const Vector<Vector2> points) {
+ Ref<ConvexPolygonShape2D> convex = edited_collision_shape;
+ Ref<ConcavePolygonShape2D> concave = edited_collision_shape;
+ if (convex.is_valid()) {
+ undo_redo->add_do_method(convex.ptr(), "set_points", points);
+ undo_redo->add_undo_method(convex.ptr(), "set_points", _get_edited_shape_points());
+ } else if (concave.is_valid()) {
+ PoolVector2Array segments;
+ for (int i = 0; i < points.size() - 1; i++) {
+ segments.push_back(points[i]);
+ segments.push_back(points[i + 1]);
+ }
+ segments.push_back(points[points.size() - 1]);
+ segments.push_back(points[0]);
+ concave->set_segments(segments);
+ undo_redo->add_do_method(concave.ptr(), "set_segments", segments);
+ undo_redo->add_undo_method(concave.ptr(), "set_segments", concave->get_segments());
+ } else {
+ // Invalid shape
+ }
+}
+
+void TileSetEditor::_update_tile_data() {
+ current_tile_data.clear();
+ if (get_current_tile() < 0)
+ return;
+
+ Vector<TileSet::ShapeData> sd = tileset->tile_get_shapes(get_current_tile());
+ if (tileset->tile_get_tile_mode(get_current_tile()) == TileSet::SINGLE_TILE) {
+ SubtileData data;
+ for (int i = 0; i < sd.size(); i++) {
+ data.collisions.push_back(sd[i].shape);
+ }
+ data.navigation_shape = tileset->tile_get_navigation_polygon(get_current_tile());
+ data.occlusion_shape = tileset->tile_get_light_occluder(get_current_tile());
+ current_tile_data[Vector2i()] = data;
+ } else {
+ int spacing = tileset->autotile_get_spacing(get_current_tile());
+ Vector2 size = tileset->tile_get_region(get_current_tile()).size;
+ Vector2i cell_count = size / (tileset->autotile_get_size(get_current_tile()) + Vector2(spacing, spacing));
+ for (int y = 0; y < cell_count.y; y++) {
+ for (int x = 0; x < cell_count.x; x++) {
+ SubtileData data;
+ Vector2i coord(x, y);
+ for (int i = 0; i < sd.size(); i++) {
+ if (sd[i].autotile_coord == coord) {
+ data.collisions.push_back(sd[i].shape);
+ }
+ }
+ data.navigation_shape = tileset->autotile_get_navigation_polygon(get_current_tile(), coord);
+ data.occlusion_shape = tileset->tile_get_light_occluder(get_current_tile());
+ current_tile_data[coord] = data;
+ }
+ }
+ }
+}
+
+void TileSetEditor::_update_toggle_shape_button() {
+ Ref<ConvexPolygonShape2D> convex = edited_collision_shape;
+ Ref<ConcavePolygonShape2D> concave = edited_collision_shape;
+ separator_shape_toggle->show();
+ tools[SHAPE_TOGGLE_TYPE]->show();
+ if (edit_mode != EDITMODE_COLLISION || !edited_collision_shape.is_valid()) {
+ separator_shape_toggle->hide();
+ tools[SHAPE_TOGGLE_TYPE]->hide();
+ } else if (concave.is_valid()) {
+ tools[SHAPE_TOGGLE_TYPE]->set_icon(get_icon("ConvexPolygonShape2D", "EditorIcons"));
+ tools[SHAPE_TOGGLE_TYPE]->set_text("Make Convex");
+ } else if (convex.is_valid()) {
+ tools[SHAPE_TOGGLE_TYPE]->set_icon(get_icon("ConcavePolygonShape2D", "EditorIcons"));
+ tools[SHAPE_TOGGLE_TYPE]->set_text("Make Concave");
+ } else {
+ // Shoudn't happen
+ separator_shape_toggle->hide();
+ tools[SHAPE_TOGGLE_TYPE]->hide();
+ }
+}
+
+void TileSetEditor::_select_next_tile() {
+ Array tiles = _get_tiles_in_current_texture(true);
+ if (tiles.size() == 0) {
+ set_current_tile(-1);
+ } else if (get_current_tile() == -1) {
+ set_current_tile(tiles[0]);
+ } else {
+ int index = tiles.find(get_current_tile());
+ if (index < 0) {
+ set_current_tile(tiles[0]);
+ } else if (index == tiles.size() - 1) {
+ set_current_tile(tiles[0]);
+ } else {
+ set_current_tile(tiles[index + 1]);
+ }
+ }
+ if (get_current_tile() == -1) {
+ return;
+ } else if (tileset->tile_get_tile_mode(get_current_tile()) == TileSet::SINGLE_TILE) {
+ return;
+ } else {
+ switch (edit_mode) {
+ case EDITMODE_COLLISION:
+ case EDITMODE_OCCLUSION:
+ case EDITMODE_NAVIGATION:
+ case EDITMODE_PRIORITY:
+ case EDITMODE_Z_INDEX: {
+ edited_shape_coord = Vector2();
+ _select_edited_shape_coord();
+ } break;
+ default: {}
+ }
+ }
+}
+
+void TileSetEditor::_select_previous_tile() {
+ Array tiles = _get_tiles_in_current_texture(true);
+ if (tiles.size() == 0) {
+ set_current_tile(-1);
+ } else if (get_current_tile() == -1) {
+ set_current_tile(tiles[tiles.size() - 1]);
+ } else {
+ int index = tiles.find(get_current_tile());
+ if (index <= 0) {
+ set_current_tile(tiles[tiles.size() - 1]);
+ } else {
+ set_current_tile(tiles[index - 1]);
+ }
+ }
+ if (get_current_tile() == -1) {
+ return;
+ } else if (tileset->tile_get_tile_mode(get_current_tile()) == TileSet::SINGLE_TILE) {
+ return;
+ } else {
+ switch (edit_mode) {
+ case EDITMODE_COLLISION:
+ case EDITMODE_OCCLUSION:
+ case EDITMODE_NAVIGATION:
+ case EDITMODE_PRIORITY:
+ case EDITMODE_Z_INDEX: {
+ int spacing = tileset->autotile_get_spacing(get_current_tile());
+ Vector2 size = tileset->tile_get_region(get_current_tile()).size;
+ Vector2i cell_count = size / (tileset->autotile_get_size(get_current_tile()) + Vector2(spacing, spacing));
+ cell_count -= Vector2(1, 1);
+ edited_shape_coord = cell_count;
+ _select_edited_shape_coord();
+ } break;
+ default: {}
+ }
+ }
+}
+
+Array TileSetEditor::_get_tiles_in_current_texture(bool sorted) {
+ Array a;
+ List<int> all_tiles;
+ if (!get_current_texture().is_valid()) {
+ return a;
+ }
+ tileset->get_tile_list(&all_tiles);
+ for (int i = 0; i < all_tiles.size(); i++) {
+ if (tileset->tile_get_texture(all_tiles[i]) == get_current_texture()) {
+ a.push_back(all_tiles[i]);
+ }
+ }
+ if (sorted) {
+ a.sort_custom(this, "_sort_tiles");
+ }
+ return a;
+}
+
+bool TileSetEditor::_sort_tiles(Variant p_a, Variant p_b) {
+ int a = p_a;
+ int b = p_b;
+
+ Vector2 pos_a = tileset->tile_get_region(a).position;
+ Vector2 pos_b = tileset->tile_get_region(b).position;
+ if (pos_a.y < pos_b.y) {
+ return true;
+
+ } else if (pos_a.y == pos_b.y) {
+ if (pos_a.x < pos_b.x) {
+ return true;
+ } else {
+ return false;
+ }
+ } else {
+ return false;
+ }
+}
+
+void TileSetEditor::_select_next_subtile() {
+ if (get_current_tile() == -1) {
+ _select_next_tile();
+ return;
+ }
+ if (tileset->tile_get_tile_mode(get_current_tile()) == TileSet::SINGLE_TILE) {
+ _select_next_tile();
+ } else if (edit_mode == EDITMODE_REGION || edit_mode == EDITMODE_BITMASK || edit_mode == EDITMODE_ICON) {
+ _select_next_tile();
+ } else {
+ int spacing = tileset->autotile_get_spacing(get_current_tile());
+ Vector2 size = tileset->tile_get_region(get_current_tile()).size;
+ Vector2i cell_count = size / (tileset->autotile_get_size(get_current_tile()) + Vector2(spacing, spacing));
+ if (edited_shape_coord.x >= cell_count.x - 1 && edited_shape_coord.y >= cell_count.y - 1) {
+ _select_next_tile();
+ } else {
+ edited_shape_coord.x++;
+ if (edited_shape_coord.x >= cell_count.x) {
+ edited_shape_coord.x = 0;
+ edited_shape_coord.y++;
+ }
+ _select_edited_shape_coord();
+ }
+ }
+}
+
+void TileSetEditor::_select_previous_subtile() {
+ if (get_current_tile() == -1) {
+ _select_previous_tile();
+ return;
+ }
+ if (tileset->tile_get_tile_mode(get_current_tile()) == TileSet::SINGLE_TILE) {
+ _select_previous_tile();
+ } else if (edit_mode == EDITMODE_REGION || edit_mode == EDITMODE_BITMASK || edit_mode == EDITMODE_ICON) {
+ _select_previous_tile();
+ } else {
+ int spacing = tileset->autotile_get_spacing(get_current_tile());
+ Vector2 size = tileset->tile_get_region(get_current_tile()).size;
+ Vector2i cell_count = size / (tileset->autotile_get_size(get_current_tile()) + Vector2(spacing, spacing));
+ if (edited_shape_coord.x <= 0 && edited_shape_coord.y <= 0) {
+ _select_previous_tile();
+ } else {
+ edited_shape_coord.x--;
+ if (edited_shape_coord.x == -1) {
+ edited_shape_coord.x = cell_count.x - 1;
+ edited_shape_coord.y--;
+ }
+ _select_edited_shape_coord();
+ }
+ }
+}
+
+void TileSetEditor::_select_next_shape() {
+ if (get_current_tile() == -1) {
+ _select_next_subtile();
+ } else if (edit_mode != EDITMODE_COLLISION) {
+ _select_next_subtile();
+ } else {
+ Vector2i edited_coord = Vector2();
+ if (tileset->tile_get_tile_mode(get_current_tile()) != TileSet::SINGLE_TILE) {
+ edited_coord = edited_shape_coord;
+ }
+ SubtileData data = current_tile_data[edited_coord];
+ if (data.collisions.size() == 0) {
+ _select_next_subtile();
+ } else {
+ int index = data.collisions.find(edited_collision_shape);
+ if (index < 0) {
+ _set_edited_collision_shape(data.collisions[0]);
+ } else if (index == data.collisions.size() - 1) {
+ _select_next_subtile();
+ } else {
+ _set_edited_collision_shape(data.collisions[index + 1]);
+ }
+ }
+ current_shape.resize(0);
+ Rect2 current_tile_region = tileset->tile_get_region(get_current_tile());
+ current_tile_region.position += WORKSPACE_MARGIN;
+
+ int spacing = tileset->autotile_get_spacing(get_current_tile());
+ Vector2 size = tileset->autotile_get_size(get_current_tile());
+ Vector2 shape_anchor = edited_shape_coord;
+ shape_anchor.x *= (size.x + spacing);
+ shape_anchor.y *= (size.y + spacing);
+ current_tile_region.position += shape_anchor;
+
+ if (edited_collision_shape.is_valid()) {
+ for (int i = 0; i < _get_edited_shape_points().size(); i++) {
+ current_shape.push_back(_get_edited_shape_points()[i] + current_tile_region.position);
+ }
+ }
+ workspace->update();
+ workspace_container->update();
+ helper->_change_notify("");
+ }
+}
+
+void TileSetEditor::_select_previous_shape() {
+ if (get_current_tile() == -1) {
+ _select_previous_subtile();
+ if (get_current_tile() != -1 && edit_mode == EDITMODE_COLLISION) {
+ SubtileData data = current_tile_data[Vector2i(edited_shape_coord)];
+ if (data.collisions.size() > 1) {
+ _set_edited_collision_shape(data.collisions[data.collisions.size() - 1]);
+ }
+ } else {
+ return;
+ }
+ } else if (edit_mode != EDITMODE_COLLISION) {
+ _select_previous_subtile();
+ } else {
+ Vector2i edited_coord = Vector2();
+ if (tileset->tile_get_tile_mode(get_current_tile()) != TileSet::SINGLE_TILE) {
+ edited_coord = edited_shape_coord;
+ }
+ SubtileData data = current_tile_data[edited_coord];
+ if (data.collisions.size() == 0) {
+ _select_previous_subtile();
+ data = current_tile_data[Vector2i(edited_shape_coord)];
+ if (data.collisions.size() > 1) {
+ _set_edited_collision_shape(data.collisions[data.collisions.size() - 1]);
+ }
+ } else {
+ int index = data.collisions.find(edited_collision_shape);
+ if (index < 0) {
+ _set_edited_collision_shape(data.collisions[data.collisions.size() - 1]);
+ } else if (index == 0) {
+ _select_previous_subtile();
+ data = current_tile_data[Vector2i(edited_shape_coord)];
+ if (data.collisions.size() > 1) {
+ _set_edited_collision_shape(data.collisions[data.collisions.size() - 1]);
+ }
+ } else {
+ _set_edited_collision_shape(data.collisions[index - 1]);
+ }
+ }
+
+ current_shape.resize(0);
+ Rect2 current_tile_region = tileset->tile_get_region(get_current_tile());
+ current_tile_region.position += WORKSPACE_MARGIN;
+
+ int spacing = tileset->autotile_get_spacing(get_current_tile());
+ Vector2 size = tileset->autotile_get_size(get_current_tile());
+ Vector2 shape_anchor = edited_shape_coord;
+ shape_anchor.x *= (size.x + spacing);
+ shape_anchor.y *= (size.y + spacing);
+ current_tile_region.position += shape_anchor;
+
+ if (edited_collision_shape.is_valid()) {
+ for (int i = 0; i < _get_edited_shape_points().size(); i++) {
+ current_shape.push_back(_get_edited_shape_points()[i] + current_tile_region.position);
+ }
+ }
+ workspace->update();
+ workspace_container->update();
+ helper->_change_notify("");
+ }
+}
+
+void TileSetEditor::_set_edited_collision_shape(const Ref<Shape2D> &p_shape) {
+ edited_collision_shape = p_shape;
+ _update_toggle_shape_button();
+}
+
void TileSetEditor::_set_snap_step(Vector2 p_val) {
snap_step.x = CLAMP(p_val.x, 0, 256);
snap_step.y = CLAMP(p_val.y, 0, 256);
@@ -1937,16 +2380,29 @@ void TileSetEditor::draw_polygon_shapes() {
}
anchor += WORKSPACE_MARGIN;
anchor += tileset->tile_get_region(t_id).position;
- Ref<ConvexPolygonShape2D> shape = sd[i].shape;
+ Ref<Shape2D> shape = sd[i].shape;
if (shape.is_valid()) {
Color c_bg;
Color c_border;
+ Ref<ConvexPolygonShape2D> convex = shape;
+ bool is_convex = convex.is_valid();
if ((tileset->tile_get_tile_mode(get_current_tile()) == TileSet::SINGLE_TILE || coord == edited_shape_coord) && sd[i].shape == edited_collision_shape) {
- c_bg = Color(0, 1, 1, 0.5);
- c_border = Color(0, 1, 1);
+ if (is_convex) {
+ c_bg = Color(0, 1, 1, 0.5);
+ c_border = Color(0, 1, 1);
+ } else {
+ c_bg = Color(0.8, 0, 1, 0.5);
+ c_border = Color(0.8, 0, 1);
+ }
} else {
- c_bg = Color(0.9, 0.7, 0.07, 0.5);
- c_border = Color(0.9, 0.7, 0.07, 1);
+ if (is_convex) {
+ c_bg = Color(0.9, 0.7, 0.07, 0.5);
+ c_border = Color(0.9, 0.7, 0.07, 1);
+
+ } else {
+ c_bg = Color(0.9, 0.45, 0.075, 0.5);
+ c_border = Color(0.9, 0.45, 0.075);
+ }
}
Vector<Vector2> polygon;
Vector<Color> colors;
@@ -1956,8 +2412,8 @@ void TileSetEditor::draw_polygon_shapes() {
colors.push_back(c_bg);
}
} else {
- for (int j = 0; j < shape->get_points().size(); j++) {
- polygon.push_back(shape->get_points()[j] + anchor);
+ for (int j = 0; j < _get_collision_shape_points(shape).size(); j++) {
+ polygon.push_back(_get_collision_shape_points(shape)[j] + anchor);
colors.push_back(c_bg);
}
}
@@ -2004,10 +2460,12 @@ void TileSetEditor::draw_polygon_shapes() {
workspace->draw_polygon(polygon, colors);
if (!creating_shape) {
- for (int j = 0; j < polygon.size() - 1; j++) {
- workspace->draw_line(polygon[j], polygon[j + 1], c_border, 1, true);
+ if (polygon.size() > 1) {
+ for (int j = 0; j < polygon.size() - 1; j++) {
+ workspace->draw_line(polygon[j], polygon[j + 1], c_border, 1, true);
+ }
+ workspace->draw_line(polygon[polygon.size() - 1], polygon[0], c_border, 1, true);
}
- workspace->draw_line(polygon[polygon.size() - 1], polygon[0], c_border, 1, true);
}
if (shape == edited_occlusion_shape) {
draw_handles = true;
@@ -2174,11 +2632,11 @@ void TileSetEditor::close_shape(const Vector2 &shape_anchor) {
if (current_shape.size() >= 3) {
Ref<ConvexPolygonShape2D> shape = memnew(ConvexPolygonShape2D);
- Vector<Vector2> segments;
+ Vector<Vector2> points;
float p_total = 0;
for (int i = 0; i < current_shape.size(); i++) {
- segments.push_back(current_shape[i] - shape_anchor);
+ points.push_back(current_shape[i] - shape_anchor);
if (i != current_shape.size() - 1)
p_total += ((current_shape[i + 1].x - current_shape[i].x) * (-current_shape[i + 1].y + (-current_shape[i].y)));
@@ -2187,9 +2645,9 @@ void TileSetEditor::close_shape(const Vector2 &shape_anchor) {
}
if (p_total < 0)
- segments.invert();
+ points.invert();
- shape->set_points(segments);
+ shape->set_points(points);
undo_redo->create_action(TTR("Create Collision Polygon"));
// Necessary to get the version that returns a Array instead of a Vector.
@@ -2274,6 +2732,7 @@ void TileSetEditor::close_shape(const Vector2 &shape_anchor) {
}
void TileSetEditor::select_coord(const Vector2 &coord) {
+ _update_tile_data();
current_shape = PoolVector2Array();
if (get_current_tile() == -1)
return;
@@ -2281,7 +2740,7 @@ void TileSetEditor::select_coord(const Vector2 &coord) {
current_tile_region.position += WORKSPACE_MARGIN;
if (tileset->tile_get_tile_mode(get_current_tile()) == TileSet::SINGLE_TILE) {
if (edited_collision_shape != tileset->tile_get_shape(get_current_tile(), 0))
- edited_collision_shape = tileset->tile_get_shape(get_current_tile(), 0);
+ _set_edited_collision_shape(tileset->tile_get_shape(get_current_tile(), 0));
if (edited_occlusion_shape != tileset->tile_get_light_occluder(get_current_tile()))
edited_occlusion_shape = tileset->tile_get_light_occluder(get_current_tile());
if (edited_navigation_shape != tileset->tile_get_navigation_polygon(get_current_tile()))
@@ -2290,8 +2749,8 @@ void TileSetEditor::select_coord(const Vector2 &coord) {
if (edit_mode == EDITMODE_COLLISION) {
current_shape.resize(0);
if (edited_collision_shape.is_valid()) {
- for (int i = 0; i < edited_collision_shape->get_points().size(); i++) {
- current_shape.push_back(edited_collision_shape->get_points()[i] + current_tile_region.position);
+ for (int i = 0; i < _get_edited_shape_points().size(); i++) {
+ current_shape.push_back(_get_edited_shape_points()[i] + current_tile_region.position);
}
}
} else if (edit_mode == EDITMODE_OCCLUSION) {
@@ -2318,13 +2777,13 @@ void TileSetEditor::select_coord(const Vector2 &coord) {
for (int i = 0; i < sd.size(); i++) {
if (sd[i].autotile_coord == coord) {
if (edited_collision_shape != sd[i].shape)
- edited_collision_shape = sd[i].shape;
+ _set_edited_collision_shape(sd[i].shape);
found_collision_shape = true;
break;
}
}
if (!found_collision_shape)
- edited_collision_shape = Ref<ConvexPolygonShape2D>(NULL);
+ _set_edited_collision_shape(Ref<ConvexPolygonShape2D>(NULL));
if (edited_occlusion_shape != tileset->autotile_get_light_occluder(get_current_tile(), coord))
edited_occlusion_shape = tileset->autotile_get_light_occluder(get_current_tile(), coord);
if (edited_navigation_shape != tileset->autotile_get_navigation_polygon(get_current_tile(), coord))
@@ -2339,8 +2798,8 @@ void TileSetEditor::select_coord(const Vector2 &coord) {
if (edit_mode == EDITMODE_COLLISION) {
current_shape.resize(0);
if (edited_collision_shape.is_valid()) {
- for (int j = 0; j < edited_collision_shape->get_points().size(); j++) {
- current_shape.push_back(edited_collision_shape->get_points()[j] + shape_anchor);
+ for (int j = 0; j < _get_edited_shape_points().size(); j++) {
+ current_shape.push_back(_get_edited_shape_points()[j] + shape_anchor);
}
}
} else if (edit_mode == EDITMODE_OCCLUSION) {
@@ -2461,7 +2920,8 @@ void TileSetEditor::update_texture_list_icon() {
for (int current_idx = 0; current_idx < texture_list->get_item_count(); current_idx++) {
RID rid = texture_list->get_item_metadata(current_idx);
texture_list->set_item_icon(current_idx, texture_map[rid]);
- texture_list->set_item_icon_region(current_idx, Rect2(0, 0, 150, 100));
+ Size2 texture_size = texture_map[rid]->get_size();
+ texture_list->set_item_icon_region(current_idx, Rect2(0, 0, MIN(texture_size.x, 150), MIN(texture_size.y, 100)));
}
texture_list->update();
}
@@ -2474,10 +2934,14 @@ void TileSetEditor::update_workspace_tile_mode() {
for (int i = 1; i < WORKSPACE_MODE_MAX; i++) {
tool_workspacemode[i]->set_disabled(true);
}
+ tools[SELECT_NEXT]->set_disabled(true);
+ tools[SELECT_PREVIOUS]->set_disabled(true);
} else {
for (int i = 1; i < WORKSPACE_MODE_MAX; i++) {
tool_workspacemode[i]->set_disabled(false);
}
+ tools[SELECT_NEXT]->set_disabled(false);
+ tools[SELECT_PREVIOUS]->set_disabled(false);
}
if (workspace_mode != WORKSPACE_EDIT) {
@@ -2495,7 +2959,7 @@ void TileSetEditor::update_workspace_tile_mode() {
for (int i = 0; i < EDITMODE_MAX; i++) {
tool_editmode[i]->hide();
}
- for (int i = 0; i < ZOOM_OUT; i++) {
+ for (int i = TOOL_SELECT; i < ZOOM_OUT; i++) {
tools[i]->hide();
}
@@ -2661,6 +3125,24 @@ bool TilesetEditorContext::_set(const StringName &p_name, const Variant &p_value
} else if (name == "tileset_script") {
tileset->set_script(p_value);
return true;
+ } else if (name == "selected_collision_one_way") {
+ Vector<TileSet::ShapeData> sd = tileset->tile_get_shapes(tileset_editor->get_current_tile());
+ for (int index = 0; index < sd.size(); index++) {
+ if (sd[index].shape == tileset_editor->edited_collision_shape) {
+ tileset->tile_set_shape_one_way(tileset_editor->get_current_tile(), index, p_value);
+ return true;
+ }
+ }
+ return false;
+ } else if (name == "selected_collision_one_way_margin") {
+ Vector<TileSet::ShapeData> sd = tileset->tile_get_shapes(tileset_editor->get_current_tile());
+ for (int index = 0; index < sd.size(); index++) {
+ if (sd[index].shape == tileset_editor->edited_collision_shape) {
+ tileset->tile_set_shape_one_way_margin(tileset_editor->get_current_tile(), index, p_value);
+ return true;
+ }
+ }
+ return false;
}
tileset_editor->err_dialog->set_text(TTR("This property can't be changed."));
@@ -2703,6 +3185,24 @@ bool TilesetEditorContext::_get(const StringName &p_name, Variant &r_ret) const
} else if (name == "selected_collision") {
r_ret = tileset_editor->edited_collision_shape;
v = true;
+ } else if (name == "selected_collision_one_way") {
+ Vector<TileSet::ShapeData> sd = tileset->tile_get_shapes(tileset_editor->get_current_tile());
+ for (int index = 0; index < sd.size(); index++) {
+ if (sd[index].shape == tileset_editor->edited_collision_shape) {
+ r_ret = sd[index].one_way_collision;
+ v = true;
+ break;
+ }
+ }
+ } else if (name == "selected_collision_one_way_margin") {
+ Vector<TileSet::ShapeData> sd = tileset->tile_get_shapes(tileset_editor->get_current_tile());
+ for (int index = 0; index < sd.size(); index++) {
+ if (sd[index].shape == tileset_editor->edited_collision_shape) {
+ r_ret = sd[index].one_way_collision_margin;
+ v = true;
+ break;
+ }
+ }
} else if (name == "selected_navigation") {
r_ret = tileset_editor->edited_navigation_shape;
v = true;
@@ -2749,6 +3249,10 @@ void TilesetEditorContext::_get_property_list(List<PropertyInfo> *p_list) const
}
if (tileset_editor->edit_mode == TileSetEditor::EDITMODE_COLLISION && tileset_editor->edited_collision_shape.is_valid()) {
p_list->push_back(PropertyInfo(Variant::OBJECT, "selected_collision", PROPERTY_HINT_RESOURCE_TYPE, tileset_editor->edited_collision_shape->get_class()));
+ if (tileset_editor->edited_collision_shape.is_valid()) {
+ p_list->push_back(PropertyInfo(Variant::BOOL, "selected_collision_one_way", PROPERTY_HINT_NONE));
+ p_list->push_back(PropertyInfo(Variant::REAL, "selected_collision_one_way_margin", PROPERTY_HINT_NONE));
+ }
}
if (tileset_editor->edit_mode == TileSetEditor::EDITMODE_NAVIGATION && tileset_editor->edited_navigation_shape.is_valid()) {
p_list->push_back(PropertyInfo(Variant::OBJECT, "selected_navigation", PROPERTY_HINT_RESOURCE_TYPE, tileset_editor->edited_navigation_shape->get_class()));
diff --git a/editor/plugins/tile_set_editor_plugin.h b/editor/plugins/tile_set_editor_plugin.h
index 9c4aa80dcb..2827964592 100644
--- a/editor/plugins/tile_set_editor_plugin.h
+++ b/editor/plugins/tile_set_editor_plugin.h
@@ -34,6 +34,7 @@
#include "editor/editor_name_dialog.h"
#include "editor/editor_node.h"
#include "scene/2d/sprite.h"
+#include "scene/resources/concave_polygon_shape_2d.h"
#include "scene/resources/convex_polygon_shape_2d.h"
#include "scene/resources/tile_set.h"
@@ -76,12 +77,15 @@ class TileSetEditor : public HSplitContainer {
};
enum TileSetTools {
+ SELECT_PREVIOUS,
+ SELECT_NEXT,
TOOL_SELECT,
BITMASK_COPY,
BITMASK_PASTE,
BITMASK_CLEAR,
SHAPE_NEW_POLYGON,
SHAPE_NEW_RECTANGLE,
+ SHAPE_TOGGLE_TYPE,
SHAPE_DELETE,
SHAPE_KEEP_INSIDE_TILE,
TOOL_GRID_SNAP,
@@ -92,6 +96,12 @@ class TileSetEditor : public HSplitContainer {
TOOL_MAX
};
+ struct SubtileData {
+ Array collisions;
+ Ref<OccluderPolygon2D> occlusion_shape;
+ Ref<NavigationPolygon> navigation_shape;
+ };
+
Ref<TileSet> tileset;
TilesetEditorContext *helper;
EditorNode *editor;
@@ -115,13 +125,14 @@ class TileSetEditor : public HSplitContainer {
bool draw_edited_region;
Vector2 edited_shape_coord;
PoolVector2Array current_shape;
+ Map<Vector2i, SubtileData> current_tile_data;
Map<Vector2, uint16_t> bitmask_map_copy;
Vector2 snap_step;
Vector2 snap_offset;
Vector2 snap_separation;
- Ref<ConvexPolygonShape2D> edited_collision_shape;
+ Ref<Shape2D> edited_collision_shape;
Ref<OccluderPolygon2D> edited_occlusion_shape;
Ref<NavigationPolygon> edited_navigation_shape;
@@ -137,6 +148,7 @@ class TileSetEditor : public HSplitContainer {
HSeparator *separator_editmode;
HBoxContainer *toolbar;
ToolButton *tools[TOOL_MAX];
+ VSeparator *separator_shape_toggle;
VSeparator *separator_bitmask;
VSeparator *separator_delete;
VSeparator *separator_grid;
@@ -188,6 +200,20 @@ private:
void _on_priority_changed(float val);
void _on_z_index_changed(float val);
void _on_grid_snap_toggled(bool p_val);
+ Vector<Vector2> _get_collision_shape_points(const Ref<Shape2D> &p_shape);
+ Vector<Vector2> _get_edited_shape_points();
+ void _set_edited_shape_points(const Vector<Vector2> points);
+ void _update_tile_data();
+ void _update_toggle_shape_button();
+ void _select_next_tile();
+ void _select_previous_tile();
+ Array _get_tiles_in_current_texture(bool sorted = false);
+ bool _sort_tiles(Variant p_a, Variant p_b);
+ void _select_next_subtile();
+ void _select_previous_subtile();
+ void _select_next_shape();
+ void _select_previous_shape();
+ void _set_edited_collision_shape(const Ref<Shape2D> &p_shape);
void _set_snap_step(Vector2 p_val);
void _set_snap_off(Vector2 p_val);
void _set_snap_sep(Vector2 p_val);