summaryrefslogtreecommitdiff
path: root/editor/plugins
diff options
context:
space:
mode:
Diffstat (limited to 'editor/plugins')
-rw-r--r--editor/plugins/abstract_polygon_2d_editor.cpp7
-rw-r--r--editor/plugins/animation_blend_tree_editor_plugin.cpp52
-rw-r--r--editor/plugins/animation_blend_tree_editor_plugin.h4
-rw-r--r--editor/plugins/asset_library_editor_plugin.cpp2
-rw-r--r--editor/plugins/canvas_item_editor_plugin.cpp104
-rw-r--r--editor/plugins/canvas_item_editor_plugin.h5
-rw-r--r--editor/plugins/collision_shape_2d_editor_plugin.cpp15
-rw-r--r--editor/plugins/cpu_particles_2d_editor_plugin.cpp307
-rw-r--r--editor/plugins/cpu_particles_2d_editor_plugin.h92
-rw-r--r--editor/plugins/mesh_library_editor_plugin.cpp5
-rw-r--r--editor/plugins/particles_2d_editor_plugin.cpp2
-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.cpp25
-rw-r--r--editor/plugins/script_editor_plugin.h2
-rw-r--r--editor/plugins/script_text_editor.cpp112
-rw-r--r--editor/plugins/script_text_editor.h1
-rw-r--r--editor/plugins/shader_editor_plugin.cpp50
-rw-r--r--editor/plugins/spatial_editor_plugin.cpp154
-rw-r--r--editor/plugins/spatial_editor_plugin.h5
-rw-r--r--editor/plugins/sprite_frames_editor_plugin.cpp6
-rw-r--r--editor/plugins/texture_editor_plugin.cpp7
-rw-r--r--editor/plugins/texture_editor_plugin.h1
-rw-r--r--editor/plugins/texture_region_editor_plugin.cpp64
-rw-r--r--editor/plugins/texture_region_editor_plugin.h1
-rw-r--r--editor/plugins/tile_map_editor_plugin.cpp36
-rw-r--r--editor/plugins/tile_set_editor_plugin.cpp122
-rw-r--r--editor/plugins/tile_set_editor_plugin.h2
-rw-r--r--editor/plugins/visual_shader_editor_plugin.cpp806
-rw-r--r--editor/plugins/visual_shader_editor_plugin.h59
30 files changed, 1675 insertions, 378 deletions
diff --git a/editor/plugins/abstract_polygon_2d_editor.cpp b/editor/plugins/abstract_polygon_2d_editor.cpp
index 28f786e99a..4a4e7f25b8 100644
--- a/editor/plugins/abstract_polygon_2d_editor.cpp
+++ b/editor/plugins/abstract_polygon_2d_editor.cpp
@@ -638,6 +638,13 @@ void AbstractPolygon2DEditor::forward_canvas_draw_over_viewport(Control *p_overl
const Color modulate = vertex == active_point ? Color(0.5, 1, 2) : Color(1, 1, 1);
p_overlay->draw_texture(handle, point - handle->get_size() * 0.5, modulate);
+
+ if (vertex == hover_point) {
+ Ref<Font> font = get_font("font", "Label");
+ String num = String::num(vertex.vertex);
+ Size2 num_size = font->get_string_size(num);
+ p_overlay->draw_string(font, point - num_size * 0.5, num, Color(1.0, 1.0, 1.0, 0.5));
+ }
}
}
diff --git a/editor/plugins/animation_blend_tree_editor_plugin.cpp b/editor/plugins/animation_blend_tree_editor_plugin.cpp
index afe2573898..f13c2170ea 100644
--- a/editor/plugins/animation_blend_tree_editor_plugin.cpp
+++ b/editor/plugins/animation_blend_tree_editor_plugin.cpp
@@ -80,6 +80,7 @@ void AnimationNodeBlendTreeEditor::_update_options_menu() {
}
add_node->get_popup()->add_separator();
add_node->get_popup()->add_item(TTR("Load..."), MENU_LOAD_FILE);
+ use_popup_menu_position = false;
}
Size2 AnimationNodeBlendTreeEditor::get_minimum_size() const {
@@ -240,7 +241,7 @@ void AnimationNodeBlendTreeEditor::_update_graph() {
if (EditorSettings::get_singleton()->get("interface/theme/use_graph_node_headers")) {
Ref<StyleBoxFlat> sb = node->get_stylebox("frame", "GraphNode");
- Color c = sb->get_border_color(MARGIN_TOP);
+ Color c = sb->get_border_color();
Color mono_color = ((c.r + c.g + c.b) / 3) < 0.7 ? Color(1.0, 1.0, 1.0) : Color(0.0, 0.0, 0.0);
mono_color.a = 0.85;
c = mono_color;
@@ -317,7 +318,15 @@ void AnimationNodeBlendTreeEditor::_add_node(int p_idx) {
EditorNode::get_singleton()->show_warning(TTR("Output node can't be added to the blend tree."));
return;
}
- Point2 instance_pos = graph->get_scroll_ofs() + graph->get_size() * 0.5;
+
+ Point2 instance_pos = graph->get_scroll_ofs();
+ if (use_popup_menu_position) {
+ instance_pos += popup_menu_position;
+ } else {
+ instance_pos += graph->get_size() * 0.5;
+ }
+
+ instance_pos /= graph->get_zoom();
int base = 1;
String name = base_name;
@@ -412,6 +421,40 @@ void AnimationNodeBlendTreeEditor::_delete_request(const String &p_which) {
undo_redo->commit_action();
}
+void AnimationNodeBlendTreeEditor::_delete_nodes_request() {
+
+ List<StringName> to_erase;
+
+ for (int i = 0; i < graph->get_child_count(); i++) {
+ GraphNode *gn = Object::cast_to<GraphNode>(graph->get_child(i));
+ if (gn) {
+ if (gn->is_selected() && gn->is_close_button_visible()) {
+ to_erase.push_back(gn->get_name());
+ }
+ }
+ }
+
+ if (to_erase.empty())
+ return;
+
+ undo_redo->create_action(TTR("Delete Node(s)"));
+
+ for (List<StringName>::Element *F = to_erase.front(); F; F = F->next()) {
+ _delete_request(F->get());
+ }
+
+ undo_redo->commit_action();
+}
+
+void AnimationNodeBlendTreeEditor::_popup_request(const Vector2 &p_position) {
+
+ _update_options_menu();
+ use_popup_menu_position = true;
+ popup_menu_position = graph->get_local_mouse_position();
+ add_node->get_popup()->set_position(p_position);
+ add_node->get_popup()->popup();
+}
+
void AnimationNodeBlendTreeEditor::_node_selected(Object *p_node) {
GraphNode *gn = Object::cast_to<GraphNode>(p_node);
@@ -730,6 +773,8 @@ void AnimationNodeBlendTreeEditor::_bind_methods() {
ClassDB::bind_method("_open_in_editor", &AnimationNodeBlendTreeEditor::_open_in_editor);
ClassDB::bind_method("_scroll_changed", &AnimationNodeBlendTreeEditor::_scroll_changed);
ClassDB::bind_method("_delete_request", &AnimationNodeBlendTreeEditor::_delete_request);
+ ClassDB::bind_method("_delete_nodes_request", &AnimationNodeBlendTreeEditor::_delete_nodes_request);
+ ClassDB::bind_method("_popup_request", &AnimationNodeBlendTreeEditor::_popup_request);
ClassDB::bind_method("_edit_filters", &AnimationNodeBlendTreeEditor::_edit_filters);
ClassDB::bind_method("_update_filters", &AnimationNodeBlendTreeEditor::_update_filters);
ClassDB::bind_method("_filter_edited", &AnimationNodeBlendTreeEditor::_filter_edited);
@@ -850,6 +895,7 @@ AnimationNodeBlendTreeEditor::AnimationNodeBlendTreeEditor() {
singleton = this;
updating = false;
+ use_popup_menu_position = false;
graph = memnew(GraphEdit);
add_child(graph);
@@ -860,6 +906,8 @@ AnimationNodeBlendTreeEditor::AnimationNodeBlendTreeEditor() {
graph->connect("disconnection_request", this, "_disconnection_request", varray(), CONNECT_DEFERRED);
graph->connect("node_selected", this, "_node_selected");
graph->connect("scroll_offset_changed", this, "_scroll_changed");
+ graph->connect("delete_nodes_request", this, "_delete_nodes_request");
+ graph->connect("popup_request", this, "_popup_request");
VSeparator *vs = memnew(VSeparator);
graph->get_zoom_hbox()->add_child(vs);
diff --git a/editor/plugins/animation_blend_tree_editor_plugin.h b/editor/plugins/animation_blend_tree_editor_plugin.h
index f2a77cecb4..cb40159a40 100644
--- a/editor/plugins/animation_blend_tree_editor_plugin.h
+++ b/editor/plugins/animation_blend_tree_editor_plugin.h
@@ -51,6 +51,8 @@ class AnimationNodeBlendTreeEditor : public AnimationTreeNodeEditorPlugin {
Ref<AnimationNodeBlendTree> blend_tree;
GraphEdit *graph;
MenuButton *add_node;
+ Vector2 popup_menu_position;
+ bool use_popup_menu_position;
PanelContainer *error_panel;
Label *error_label;
@@ -97,6 +99,8 @@ class AnimationNodeBlendTreeEditor : public AnimationTreeNodeEditorPlugin {
void _open_in_editor(const String &p_which);
void _anim_selected(int p_index, Array p_options, const String &p_node);
void _delete_request(const String &p_which);
+ void _delete_nodes_request();
+ void _popup_request(const Vector2 &p_position);
bool _update_filters(const Ref<AnimationNode> &anode);
void _edit_filters(const String &p_which);
diff --git a/editor/plugins/asset_library_editor_plugin.cpp b/editor/plugins/asset_library_editor_plugin.cpp
index a9e9607bc5..6d2cdfc583 100644
--- a/editor/plugins/asset_library_editor_plugin.cpp
+++ b/editor/plugins/asset_library_editor_plugin.cpp
@@ -818,7 +818,7 @@ void EditorAssetLibrary::_image_request_completed(int p_status, int p_code, cons
_image_update(p_code == HTTPClient::RESPONSE_NOT_MODIFIED, true, p_data, p_queue_id);
} else {
- // WARN_PRINTS("Error getting image file from URL: " + image_queue[p_queue_id].image_url);
+ WARN_PRINTS("Error getting image file from URL: " + image_queue[p_queue_id].image_url);
Object *obj = ObjectDB::get_instance(image_queue[p_queue_id].target);
if (obj) {
obj->call("set_image", image_queue[p_queue_id].image_type, image_queue[p_queue_id].image_index, get_icon("DefaultProjectIcon", "EditorIcons"));
diff --git a/editor/plugins/canvas_item_editor_plugin.cpp b/editor/plugins/canvas_item_editor_plugin.cpp
index ac05b03ed2..c3cac582ad 100644
--- a/editor/plugins/canvas_item_editor_plugin.cpp
+++ b/editor/plugins/canvas_item_editor_plugin.cpp
@@ -1072,36 +1072,36 @@ bool CanvasItemEditor::_gui_input_zoom_or_pan(const Ref<InputEvent> &p_event) {
}
}
- if (drag_type == DRAG_NONE) {
+ if (!panning) {
if (b->is_pressed() &&
(b->get_button_index() == BUTTON_MIDDLE ||
(b->get_button_index() == BUTTON_LEFT && tool == TOOL_PAN) ||
(b->get_button_index() == BUTTON_LEFT && !EditorSettings::get_singleton()->get("editors/2d/simple_spacebar_panning") && Input::get_singleton()->is_key_pressed(KEY_SPACE)))) {
// Pan the viewport
- drag_type = DRAG_PAN;
+ panning = true;
}
}
- if (drag_type == DRAG_PAN) {
+ if (panning) {
if (!b->is_pressed()) {
// Stop panning the viewport (for any mouse button press)
- drag_type = DRAG_NONE;
+ panning = false;
}
}
}
Ref<InputEventKey> k = p_event;
if (k.is_valid()) {
- if (k->get_scancode() == KEY_SPACE && EditorSettings::get_singleton()->get("editors/2d/simple_spacebar_panning")) {
- if (drag_type == DRAG_NONE) {
+ if (k->get_scancode() == KEY_SPACE && (EditorSettings::get_singleton()->get("editors/2d/simple_spacebar_panning") || drag_type != DRAG_NONE)) {
+ if (!panning) {
if (k->is_pressed() && !k->is_echo()) {
//Pan the viewport
- drag_type = DRAG_PAN;
+ panning = true;
}
- } else if (drag_type == DRAG_PAN) {
+ } else if (panning) {
if (!k->is_pressed()) {
// Stop panning the viewport (for any mouse button press)
- drag_type = DRAG_NONE;
+ panning = false;
}
}
}
@@ -1109,7 +1109,7 @@ bool CanvasItemEditor::_gui_input_zoom_or_pan(const Ref<InputEvent> &p_event) {
Ref<InputEventMouseMotion> m = p_event;
if (m.is_valid()) {
- if (drag_type == DRAG_PAN) {
+ if (panning) {
// Pan the viewport
Point2i relative;
if (bool(EditorSettings::get_singleton()->get("editors/2d/warped_mouse_panning"))) {
@@ -2190,32 +2190,34 @@ bool CanvasItemEditor::_gui_input_hover(const Ref<InputEvent> &p_event) {
void CanvasItemEditor::_gui_input_viewport(const Ref<InputEvent> &p_event) {
bool accepted = false;
- if ((accepted = _gui_input_rulers_and_guides(p_event))) {
- //printf("Rulers and guides\n");
- } else if ((accepted = editor->get_editor_plugins_over()->forward_gui_input(p_event))) {
- //printf("Plugin\n");
- } else if ((accepted = _gui_input_open_scene_on_double_click(p_event))) {
- //printf("Open scene on double click\n");
- } else if ((accepted = _gui_input_anchors(p_event))) {
- //printf("Anchors\n");
- } else if ((accepted = _gui_input_scale(p_event))) {
- //printf("Set scale\n");
- } else if ((accepted = _gui_input_pivot(p_event))) {
- //printf("Set pivot\n");
- } else if ((accepted = _gui_input_resize(p_event))) {
- //printf("Resize\n");
- } else if ((accepted = _gui_input_rotate(p_event))) {
- //printf("Rotate\n");
- } else if ((accepted = _gui_input_move(p_event))) {
- //printf("Move\n");
- } else if ((accepted = _gui_input_zoom_or_pan(p_event))) {
- //printf("Zoom or pan\n");
- } else if ((accepted = _gui_input_select(p_event))) {
- //printf("Selection\n");
- } else {
- //printf("Not accepted\n");
+ if (EditorSettings::get_singleton()->get("editors/2d/simple_spacebar_panning") || !Input::get_singleton()->is_key_pressed(KEY_SPACE)) {
+ if ((accepted = _gui_input_rulers_and_guides(p_event))) {
+ //printf("Rulers and guides\n");
+ } else if ((accepted = editor->get_editor_plugins_over()->forward_gui_input(p_event))) {
+ //printf("Plugin\n");
+ } else if ((accepted = _gui_input_open_scene_on_double_click(p_event))) {
+ //printf("Open scene on double click\n");
+ } else if ((accepted = _gui_input_anchors(p_event))) {
+ //printf("Anchors\n");
+ } else if ((accepted = _gui_input_scale(p_event))) {
+ //printf("Set scale\n");
+ } else if ((accepted = _gui_input_pivot(p_event))) {
+ //printf("Set pivot\n");
+ } else if ((accepted = _gui_input_resize(p_event))) {
+ //printf("Resize\n");
+ } else if ((accepted = _gui_input_rotate(p_event))) {
+ //printf("Rotate\n");
+ } else if ((accepted = _gui_input_move(p_event))) {
+ //printf("Move\n");
+ } else if ((accepted = _gui_input_select(p_event))) {
+ //printf("Selection\n");
+ } else {
+ //printf("Not accepted\n");
+ }
}
+ accepted = (_gui_input_zoom_or_pan(p_event) || accepted);
+
if (accepted)
accept_event();
@@ -2259,8 +2261,6 @@ void CanvasItemEditor::_gui_input_viewport(const Ref<InputEvent> &p_event) {
case DRAG_MOVE:
c = CURSOR_MOVE;
break;
- case DRAG_PAN:
- c = CURSOR_DRAG;
default:
break;
}
@@ -2597,6 +2597,7 @@ void CanvasItemEditor::_draw_control_helpers(Control *control) {
case DRAG_TOP_LEFT:
case DRAG_BOTTOM_LEFT:
_draw_margin_at_position(control->get_size().width, parent_transform.xform(Vector2((node_pos_in_parent[0] + node_pos_in_parent[2]) / 2, node_pos_in_parent[3])) + Vector2(0, 5), MARGIN_BOTTOM);
+ FALLTHROUGH;
case DRAG_MOVE:
start = Vector2(node_pos_in_parent[0], Math::lerp(node_pos_in_parent[1], node_pos_in_parent[3], ratio));
end = start - Vector2(control->get_margin(MARGIN_LEFT), 0);
@@ -2611,6 +2612,7 @@ void CanvasItemEditor::_draw_control_helpers(Control *control) {
case DRAG_TOP_RIGHT:
case DRAG_BOTTOM_RIGHT:
_draw_margin_at_position(control->get_size().width, parent_transform.xform(Vector2((node_pos_in_parent[0] + node_pos_in_parent[2]) / 2, node_pos_in_parent[3])) + Vector2(0, 5), MARGIN_BOTTOM);
+ FALLTHROUGH;
case DRAG_MOVE:
start = Vector2(node_pos_in_parent[2], Math::lerp(node_pos_in_parent[3], node_pos_in_parent[1], ratio));
end = start - Vector2(control->get_margin(MARGIN_RIGHT), 0);
@@ -2625,6 +2627,7 @@ void CanvasItemEditor::_draw_control_helpers(Control *control) {
case DRAG_TOP_LEFT:
case DRAG_TOP_RIGHT:
_draw_margin_at_position(control->get_size().height, parent_transform.xform(Vector2(node_pos_in_parent[2], (node_pos_in_parent[1] + node_pos_in_parent[3]) / 2)) + Vector2(5, 0), MARGIN_RIGHT);
+ FALLTHROUGH;
case DRAG_MOVE:
start = Vector2(Math::lerp(node_pos_in_parent[0], node_pos_in_parent[2], ratio), node_pos_in_parent[1]);
end = start - Vector2(0, control->get_margin(MARGIN_TOP));
@@ -2639,6 +2642,7 @@ void CanvasItemEditor::_draw_control_helpers(Control *control) {
case DRAG_BOTTOM_LEFT:
case DRAG_BOTTOM_RIGHT:
_draw_margin_at_position(control->get_size().height, parent_transform.xform(Vector2(node_pos_in_parent[2], (node_pos_in_parent[1] + node_pos_in_parent[3]) / 2) + Vector2(5, 0)), MARGIN_RIGHT);
+ FALLTHROUGH;
case DRAG_MOVE:
start = Vector2(Math::lerp(node_pos_in_parent[2], node_pos_in_parent[0], ratio), node_pos_in_parent[3]);
end = start - Vector2(0, control->get_margin(MARGIN_BOTTOM));
@@ -2828,13 +2832,20 @@ void CanvasItemEditor::_draw_selection() {
Point2 bsfrom = transform.xform(drag_from);
Point2 bsto = transform.xform(box_selecting_to);
- VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(bsfrom, bsto - bsfrom), Color(0.7, 0.7, 1.0, 0.3));
+ VisualServer::get_singleton()->canvas_item_add_rect(
+ ci,
+ Rect2(bsfrom, bsto - bsfrom),
+ get_color("accent_color", "Editor") * Color(1, 1, 1, 0.375));
}
- Color rotate_color(0.4, 0.7, 1.0, 0.8);
if (drag_type == DRAG_ROTATE) {
// Draw the line when rotating a node
- viewport->draw_line(transform.xform(drag_rotation_center), transform.xform(drag_to), rotate_color);
+ viewport->draw_line(
+ transform.xform(drag_rotation_center),
+ transform.xform(drag_to),
+ get_color("accent_color", "Editor") * Color(1, 1, 1, 0.6),
+ Math::round(2 * EDSCALE),
+ true);
}
}
@@ -4144,6 +4155,14 @@ void CanvasItemEditor::_popup_callback(int p_op) {
_focus_selection(p_op);
} break;
+ case PREVIEW_CANVAS_SCALE: {
+
+ bool preview = view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(PREVIEW_CANVAS_SCALE));
+ preview = !preview;
+ VS::get_singleton()->canvas_set_disable_scale(!preview);
+ view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(PREVIEW_CANVAS_SCALE), preview);
+
+ } break;
case SKELETON_MAKE_BONES: {
Map<Node *, Object *> &selection = editor_selection->get_selection();
@@ -4162,6 +4181,7 @@ void CanvasItemEditor::_popup_callback(int p_op) {
if (!skeleton_show_bones)
skeleton_menu->get_popup()->activate_item(skeleton_menu->get_popup()->get_item_index(SKELETON_SHOW_BONES));
}
+ _queue_update_bone_list();
viewport->update();
} break;
@@ -4181,6 +4201,7 @@ void CanvasItemEditor::_popup_callback(int p_op) {
if (!skeleton_show_bones)
skeleton_menu->get_popup()->activate_item(skeleton_menu->get_popup()->get_item_index(SKELETON_SHOW_BONES));
}
+ _queue_update_bone_list();
viewport->update();
} break;
@@ -4569,6 +4590,7 @@ CanvasItemEditor::CanvasItemEditor(EditorNode *p_editor) {
drag_to = Vector2();
dragged_guide_pos = Point2();
dragged_guide_index = -1;
+ panning = false;
bone_last_frame = 0;
@@ -4817,6 +4839,8 @@ CanvasItemEditor::CanvasItemEditor(EditorNode *p_editor) {
p->add_separator();
p->add_shortcut(ED_SHORTCUT("canvas_item_editor/center_selection", TTR("Center Selection"), KEY_F), VIEW_CENTER_TO_SELECTION);
p->add_shortcut(ED_SHORTCUT("canvas_item_editor/frame_selection", TTR("Frame Selection"), KEY_MASK_SHIFT | KEY_F), VIEW_FRAME_TO_SELECTION);
+ p->add_separator();
+ p->add_check_shortcut(ED_SHORTCUT("canvas_item_editor/preview_canvas_scale", TTR("Preview Canvas Scale"), KEY_MASK_SHIFT | KEY_MASK_CMD | KEY_P), PREVIEW_CANVAS_SCALE);
presets_menu = memnew(MenuButton);
presets_menu->set_text(TTR("Layout"));
@@ -4922,7 +4946,6 @@ void CanvasItemEditorPlugin::make_visible(bool p_visible) {
canvas_item_editor->show();
canvas_item_editor->set_physics_process(true);
VisualServer::get_singleton()->viewport_set_hide_canvas(editor->get_scene_root()->get_viewport_rid(), false);
- canvas_item_editor->viewport->grab_focus();
} else {
@@ -5415,6 +5438,7 @@ CanvasItemEditorViewport::CanvasItemEditorViewport(EditorNode *p_node, CanvasIte
label_desc->add_constant_override("line_spacing", 0);
label_desc->hide();
editor->get_gui_base()->add_child(label_desc);
+ VS::get_singleton()->canvas_set_disable_scale(true);
}
CanvasItemEditorViewport::~CanvasItemEditorViewport() {
diff --git a/editor/plugins/canvas_item_editor_plugin.h b/editor/plugins/canvas_item_editor_plugin.h
index 7b6563944e..9173c55ae0 100644
--- a/editor/plugins/canvas_item_editor_plugin.h
+++ b/editor/plugins/canvas_item_editor_plugin.h
@@ -171,6 +171,7 @@ private:
ANIM_CLEAR_POSE,
VIEW_CENTER_TO_SELECTION,
VIEW_FRAME_TO_SELECTION,
+ PREVIEW_CANVAS_SCALE,
SKELETON_MAKE_BONES,
SKELETON_CLEAR_BONES,
SKELETON_SHOW_BONES,
@@ -204,8 +205,7 @@ private:
DRAG_V_GUIDE,
DRAG_H_GUIDE,
DRAG_DOUBLE_GUIDE,
- DRAG_KEY_MOVE,
- DRAG_PAN
+ DRAG_KEY_MOVE
};
EditorSelection *editor_selection;
@@ -261,6 +261,7 @@ private:
bool key_pos;
bool key_rot;
bool key_scale;
+ bool panning;
MenuOption last_option;
diff --git a/editor/plugins/collision_shape_2d_editor_plugin.cpp b/editor/plugins/collision_shape_2d_editor_plugin.cpp
index 10023d88bf..c8561d22a4 100644
--- a/editor/plugins/collision_shape_2d_editor_plugin.cpp
+++ b/editor/plugins/collision_shape_2d_editor_plugin.cpp
@@ -93,7 +93,7 @@ Variant CollisionShape2DEditor::get_handle_value(int idx) const {
case RECTANGLE_SHAPE: {
Ref<RectangleShape2D> rect = node->get_shape();
- if (idx < 2) {
+ if (idx < 3) {
return rect->get_extents().abs();
}
@@ -175,12 +175,15 @@ void CollisionShape2DEditor::set_handle(int idx, Point2 &p_point) {
} break;
case RECTANGLE_SHAPE: {
- if (idx < 2) {
+ if (idx < 3) {
Ref<RectangleShape2D> rect = node->get_shape();
Vector2 extents = rect->get_extents();
- extents[idx] = p_point[idx];
-
+ if (idx == 2) {
+ extents = p_point;
+ } else {
+ extents[idx] = p_point[idx];
+ }
rect->set_extents(extents.abs());
canvas_item_editor->update_viewport();
@@ -496,13 +499,15 @@ void CollisionShape2DEditor::forward_canvas_draw_over_viewport(Control *p_overla
case RECTANGLE_SHAPE: {
Ref<RectangleShape2D> shape = node->get_shape();
- handles.resize(2);
+ handles.resize(3);
Vector2 ext = shape->get_extents();
handles.write[0] = Point2(ext.x, 0);
handles.write[1] = Point2(0, -ext.y);
+ handles.write[2] = Point2(ext.x, -ext.y);
p_overlay->draw_texture(h, gt.xform(handles[0]) - size);
p_overlay->draw_texture(h, gt.xform(handles[1]) - size);
+ p_overlay->draw_texture(h, gt.xform(handles[2]) - size);
} break;
diff --git a/editor/plugins/cpu_particles_2d_editor_plugin.cpp b/editor/plugins/cpu_particles_2d_editor_plugin.cpp
new file mode 100644
index 0000000000..559558cdb8
--- /dev/null
+++ b/editor/plugins/cpu_particles_2d_editor_plugin.cpp
@@ -0,0 +1,307 @@
+/*************************************************************************/
+/* cpu_particles_2d_editor_plugin.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "cpu_particles_2d_editor_plugin.h"
+
+#include "canvas_item_editor_plugin.h"
+#include "core/io/image_loader.h"
+#include "scene/2d/cpu_particles_2d.h"
+#include "scene/gui/separator.h"
+#include "scene/resources/particles_material.h"
+
+void CPUParticles2DEditorPlugin::edit(Object *p_object) {
+
+ particles = Object::cast_to<CPUParticles2D>(p_object);
+}
+
+bool CPUParticles2DEditorPlugin::handles(Object *p_object) const {
+
+ return p_object->is_class("CPUParticles2D");
+}
+
+void CPUParticles2DEditorPlugin::make_visible(bool p_visible) {
+
+ if (p_visible) {
+
+ toolbar->show();
+ } else {
+
+ toolbar->hide();
+ }
+}
+
+void CPUParticles2DEditorPlugin::_file_selected(const String &p_file) {
+
+ source_emission_file = p_file;
+ emission_mask->popup_centered_minsize();
+}
+
+void CPUParticles2DEditorPlugin::_menu_callback(int p_idx) {
+
+ switch (p_idx) {
+ case MENU_LOAD_EMISSION_MASK: {
+
+ file->popup_centered_ratio();
+
+ } break;
+ case MENU_CLEAR_EMISSION_MASK: {
+
+ emission_mask->popup_centered_minsize();
+ } break;
+ }
+}
+
+void CPUParticles2DEditorPlugin::_generate_emission_mask() {
+
+ Ref<Image> img;
+ img.instance();
+ Error err = ImageLoader::load_image(source_emission_file, img);
+ ERR_EXPLAIN(TTR("Error loading image:") + " " + source_emission_file);
+ ERR_FAIL_COND(err != OK);
+
+ if (img->is_compressed()) {
+ img->decompress();
+ }
+ img->convert(Image::FORMAT_RGBA8);
+ ERR_FAIL_COND(img->get_format() != Image::FORMAT_RGBA8);
+ Size2i s = Size2(img->get_width(), img->get_height());
+ ERR_FAIL_COND(s.width == 0 || s.height == 0);
+
+ Vector<Point2> valid_positions;
+ Vector<Point2> valid_normals;
+ Vector<uint8_t> valid_colors;
+
+ valid_positions.resize(s.width * s.height);
+
+ EmissionMode emode = (EmissionMode)emission_mask_mode->get_selected();
+
+ if (emode == EMISSION_MODE_BORDER_DIRECTED) {
+ valid_normals.resize(s.width * s.height);
+ }
+
+ bool capture_colors = emission_colors->is_pressed();
+
+ if (capture_colors) {
+ valid_colors.resize(s.width * s.height * 4);
+ }
+
+ int vpc = 0;
+
+ {
+ PoolVector<uint8_t> data = img->get_data();
+ PoolVector<uint8_t>::Read r = data.read();
+
+ for (int i = 0; i < s.width; i++) {
+ for (int j = 0; j < s.height; j++) {
+
+ uint8_t a = r[(j * s.width + i) * 4 + 3];
+
+ if (a > 128) {
+
+ if (emode == EMISSION_MODE_SOLID) {
+
+ if (capture_colors) {
+ valid_colors.write[vpc * 4 + 0] = r[(j * s.width + i) * 4 + 0];
+ valid_colors.write[vpc * 4 + 1] = r[(j * s.width + i) * 4 + 1];
+ valid_colors.write[vpc * 4 + 2] = r[(j * s.width + i) * 4 + 2];
+ valid_colors.write[vpc * 4 + 3] = r[(j * s.width + i) * 4 + 3];
+ }
+ valid_positions.write[vpc++] = Point2(i, j);
+
+ } else {
+
+ bool on_border = false;
+ for (int x = i - 1; x <= i + 1; x++) {
+ for (int y = j - 1; y <= j + 1; y++) {
+
+ if (x < 0 || y < 0 || x >= s.width || y >= s.height || r[(y * s.width + x) * 4 + 3] <= 128) {
+ on_border = true;
+ break;
+ }
+ }
+
+ if (on_border)
+ break;
+ }
+
+ if (on_border) {
+ valid_positions.write[vpc] = Point2(i, j);
+
+ if (emode == EMISSION_MODE_BORDER_DIRECTED) {
+ Vector2 normal;
+ for (int x = i - 2; x <= i + 2; x++) {
+ for (int y = j - 2; y <= j + 2; y++) {
+
+ if (x == i && y == j)
+ continue;
+
+ if (x < 0 || y < 0 || x >= s.width || y >= s.height || r[(y * s.width + x) * 4 + 3] <= 128) {
+ normal += Vector2(x - i, y - j).normalized();
+ }
+ }
+ }
+
+ normal.normalize();
+ valid_normals.write[vpc] = normal;
+ }
+
+ if (capture_colors) {
+ valid_colors.write[vpc * 4 + 0] = r[(j * s.width + i) * 4 + 0];
+ valid_colors.write[vpc * 4 + 1] = r[(j * s.width + i) * 4 + 1];
+ valid_colors.write[vpc * 4 + 2] = r[(j * s.width + i) * 4 + 2];
+ valid_colors.write[vpc * 4 + 3] = r[(j * s.width + i) * 4 + 3];
+ }
+
+ vpc++;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ valid_positions.resize(vpc);
+ if (valid_normals.size()) {
+ valid_normals.resize(vpc);
+ }
+
+ ERR_EXPLAIN(TTR("No pixels with transparency > 128 in image..."));
+ ERR_FAIL_COND(valid_positions.size() == 0);
+
+ if (capture_colors) {
+ PoolColorArray pca;
+ pca.resize(vpc);
+ PoolColorArray::Write pcaw = pca.write();
+ for (int i = 0; i < vpc; i += 1) {
+ Color color;
+ color.r = valid_colors[i * 4 + 0] / 255.0f;
+ color.g = valid_colors[i * 4 + 1] / 255.0f;
+ color.b = valid_colors[i * 4 + 2] / 255.0f;
+ color.a = valid_colors[i * 4 + 3] / 255.0f;
+ pcaw[i] = color;
+ }
+ particles->set_emission_colors(pca);
+ }
+
+ if (valid_normals.size()) {
+ particles->set_emission_shape(CPUParticles2D::EMISSION_SHAPE_DIRECTED_POINTS);
+ PoolVector2Array norms;
+ norms.resize(valid_normals.size());
+ PoolVector2Array::Write normsw = norms.write();
+ for (int i = 0; i < valid_normals.size(); i += 1) {
+ normsw[i] = valid_normals[i];
+ }
+ particles->set_emission_normals(norms);
+ } else {
+ particles->set_emission_shape(CPUParticles2D::EMISSION_SHAPE_POINTS);
+ }
+
+ {
+ PoolVector2Array points;
+ points.resize(valid_positions.size());
+ PoolVector2Array::Write pointsw = points.write();
+ for (int i = 0; i < valid_positions.size(); i += 1) {
+ pointsw[i] = valid_positions[i];
+ }
+ particles->set_emission_points(points);
+ }
+}
+
+void CPUParticles2DEditorPlugin::_notification(int p_what) {
+
+ if (p_what == NOTIFICATION_ENTER_TREE) {
+
+ menu->get_popup()->connect("id_pressed", this, "_menu_callback");
+ menu->set_icon(menu->get_popup()->get_icon("Particles2D", "EditorIcons"));
+ file->connect("file_selected", this, "_file_selected");
+ }
+}
+
+void CPUParticles2DEditorPlugin::_bind_methods() {
+
+ ClassDB::bind_method(D_METHOD("_menu_callback"), &CPUParticles2DEditorPlugin::_menu_callback);
+ ClassDB::bind_method(D_METHOD("_file_selected"), &CPUParticles2DEditorPlugin::_file_selected);
+ ClassDB::bind_method(D_METHOD("_generate_emission_mask"), &CPUParticles2DEditorPlugin::_generate_emission_mask);
+}
+
+CPUParticles2DEditorPlugin::CPUParticles2DEditorPlugin(EditorNode *p_node) {
+
+ particles = NULL;
+ editor = p_node;
+ undo_redo = editor->get_undo_redo();
+
+ toolbar = memnew(HBoxContainer);
+ add_control_to_container(CONTAINER_CANVAS_EDITOR_MENU, toolbar);
+ toolbar->hide();
+
+ toolbar->add_child(memnew(VSeparator));
+
+ menu = memnew(MenuButton);
+ menu->get_popup()->add_item(TTR("Load Emission Mask"), MENU_LOAD_EMISSION_MASK);
+ // menu->get_popup()->add_item(TTR("Clear Emission Mask"), MENU_CLEAR_EMISSION_MASK);
+ menu->set_text(TTR("Particles"));
+ toolbar->add_child(menu);
+
+ file = memnew(EditorFileDialog);
+ List<String> ext;
+ ImageLoader::get_recognized_extensions(&ext);
+ for (List<String>::Element *E = ext.front(); E; E = E->next()) {
+ file->add_filter("*." + E->get() + "; " + E->get().to_upper());
+ }
+ file->set_mode(EditorFileDialog::MODE_OPEN_FILE);
+ toolbar->add_child(file);
+
+ epoints = memnew(SpinBox);
+ epoints->set_min(1);
+ epoints->set_max(8192);
+ epoints->set_step(1);
+ epoints->set_value(512);
+ file->get_vbox()->add_margin_child(TTR("Generated Point Count:"), epoints);
+
+ emission_mask = memnew(ConfirmationDialog);
+ emission_mask->set_title(TTR("Load Emission Mask"));
+ VBoxContainer *emvb = memnew(VBoxContainer);
+ emission_mask->add_child(emvb);
+ emission_mask_mode = memnew(OptionButton);
+ emvb->add_margin_child(TTR("Emission Mask"), emission_mask_mode);
+ emission_mask_mode->add_item("Solid Pixels", EMISSION_MODE_SOLID);
+ emission_mask_mode->add_item("Border Pixels", EMISSION_MODE_BORDER);
+ emission_mask_mode->add_item("Directed Border Pixels", EMISSION_MODE_BORDER_DIRECTED);
+ emission_colors = memnew(CheckBox);
+ emission_colors->set_text(TTR("Capture from Pixel"));
+ emvb->add_margin_child(TTR("Emission Colors"), emission_colors);
+
+ toolbar->add_child(emission_mask);
+
+ emission_mask->connect("confirmed", this, "_generate_emission_mask");
+}
+
+CPUParticles2DEditorPlugin::~CPUParticles2DEditorPlugin() {
+}
diff --git a/editor/plugins/cpu_particles_2d_editor_plugin.h b/editor/plugins/cpu_particles_2d_editor_plugin.h
new file mode 100644
index 0000000000..f715abd87b
--- /dev/null
+++ b/editor/plugins/cpu_particles_2d_editor_plugin.h
@@ -0,0 +1,92 @@
+/*************************************************************************/
+/* cpu_particles_2d_editor_plugin.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef CPU_PARTICLES_2D_EDITOR_PLUGIN_H
+#define CPU_PARTICLES_2D_EDITOR_PLUGIN_H
+
+#include "editor/editor_node.h"
+#include "editor/editor_plugin.h"
+#include "scene/2d/collision_polygon_2d.h"
+#include "scene/2d/cpu_particles_2d.h"
+#include "scene/gui/box_container.h"
+#include "scene/gui/file_dialog.h"
+
+class CPUParticles2DEditorPlugin : public EditorPlugin {
+
+ GDCLASS(CPUParticles2DEditorPlugin, EditorPlugin);
+
+ enum {
+ MENU_LOAD_EMISSION_MASK,
+ MENU_CLEAR_EMISSION_MASK
+ };
+
+ enum EmissionMode {
+ EMISSION_MODE_SOLID,
+ EMISSION_MODE_BORDER,
+ EMISSION_MODE_BORDER_DIRECTED
+ };
+
+ CPUParticles2D *particles;
+
+ EditorFileDialog *file;
+ EditorNode *editor;
+
+ HBoxContainer *toolbar;
+ MenuButton *menu;
+
+ SpinBox *epoints;
+
+ ConfirmationDialog *emission_mask;
+ OptionButton *emission_mask_mode;
+ CheckBox *emission_colors;
+
+ String source_emission_file;
+
+ UndoRedo *undo_redo;
+ void _file_selected(const String &p_file);
+ void _menu_callback(int p_idx);
+ void _generate_emission_mask();
+
+protected:
+ void _notification(int p_what);
+ static void _bind_methods();
+
+public:
+ virtual String get_name() const { return "CPUParticles2D"; }
+ 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);
+
+ CPUParticles2DEditorPlugin(EditorNode *p_node);
+ ~CPUParticles2DEditorPlugin();
+};
+
+#endif // CPU_PARTICLES_2D_EDITOR_PLUGIN_H
diff --git a/editor/plugins/mesh_library_editor_plugin.cpp b/editor/plugins/mesh_library_editor_plugin.cpp
index aedac7b45d..89eb253afe 100644
--- a/editor/plugins/mesh_library_editor_plugin.cpp
+++ b/editor/plugins/mesh_library_editor_plugin.cpp
@@ -127,7 +127,7 @@ void MeshLibraryEditor::_import_scene(Node *p_scene, Ref<MeshLibrary> p_library,
continue;
MeshLibrary::ShapeData shape_data;
shape_data.shape = collision;
- shape_data.local_transform = sb->shape_owner_get_transform(E->get());
+ shape_data.local_transform = sb->get_transform() * sb->shape_owner_get_transform(E->get());
collisions.push_back(shape_data);
}
}
@@ -136,17 +136,20 @@ void MeshLibraryEditor::_import_scene(Node *p_scene, Ref<MeshLibrary> p_library,
p_library->set_item_shapes(id, collisions);
Ref<NavigationMesh> navmesh;
+ Transform navmesh_transform;
for (int j = 0; j < mi->get_child_count(); j++) {
Node *child2 = mi->get_child(j);
if (!Object::cast_to<NavigationMeshInstance>(child2))
continue;
NavigationMeshInstance *sb = Object::cast_to<NavigationMeshInstance>(child2);
navmesh = sb->get_navigation_mesh();
+ navmesh_transform = sb->get_transform();
if (!navmesh.is_null())
break;
}
if (!navmesh.is_null()) {
p_library->set_item_navmesh(id, navmesh);
+ p_library->set_item_navmesh_transform(id, navmesh_transform);
}
}
diff --git a/editor/plugins/particles_2d_editor_plugin.cpp b/editor/plugins/particles_2d_editor_plugin.cpp
index d00687f7ea..70d4919e9f 100644
--- a/editor/plugins/particles_2d_editor_plugin.cpp
+++ b/editor/plugins/particles_2d_editor_plugin.cpp
@@ -408,7 +408,7 @@ Particles2DEditorPlugin::Particles2DEditorPlugin(EditorNode *p_node) {
generate_visibility_rect->connect("confirmed", this, "_generate_visibility_rect");
emission_mask = memnew(ConfirmationDialog);
- emission_mask->set_title(TTR("Generate Visibility Rect"));
+ emission_mask->set_title(TTR("Load Emission Mask"));
VBoxContainer *emvb = memnew(VBoxContainer);
emission_mask->add_child(emvb);
emission_mask_mode = memnew(OptionButton);
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..42aba78e96 100644
--- a/editor/plugins/script_editor_plugin.cpp
+++ b/editor/plugins/script_editor_plugin.cpp
@@ -849,8 +849,7 @@ void ScriptEditor::_file_dialog_action(String p_file) {
}
file->close();
memdelete(file);
-
- // fallthrough to open the file.
+ FALLTHROUGH;
}
case FILE_OPEN: {
@@ -979,6 +978,10 @@ void ScriptEditor::_menu_option(int p_option) {
OS::get_singleton()->shell_open("https://docs.godotengine.org/");
} break;
+ case REQUEST_DOCS: {
+
+ OS::get_singleton()->shell_open("https://github.com/godotengine/godot-docs/issues/new");
+ } break;
case WINDOW_NEXT: {
@@ -1308,6 +1311,7 @@ void ScriptEditor::_notification(int p_what) {
EditorSettings::get_singleton()->connect("settings_changed", this, "_editor_settings_changed");
help_search->set_icon(get_icon("HelpSearch", "EditorIcons"));
site_search->set_icon(get_icon("Instance", "EditorIcons"));
+ request_docs->set_icon(get_icon("Issue", "EditorIcons"));
script_forward->set_icon(get_icon("Forward", "EditorIcons"));
script_back->set_icon(get_icon("Back", "EditorIcons"));
@@ -1951,8 +1955,9 @@ bool ScriptEditor::edit(const RES &p_resource, int p_line, int p_col, bool p_gra
if (is_visible_in_tree())
se->ensure_focus();
- if (p_line >= 0)
+ if (p_line > 0) {
se->goto_line(p_line - 1);
+ }
}
return true;
}
@@ -2012,8 +2017,9 @@ bool ScriptEditor::edit(const RES &p_resource, int p_line, int p_col, bool p_gra
_test_script_times_on_disk(p_resource);
_update_modified_scripts_for_external_editor(p_resource);
- if (p_line >= 0)
+ if (p_line > 0) {
se->goto_line(p_line - 1);
+ }
notify_script_changed(p_resource);
_add_recent_script(p_resource->get_path());
@@ -2206,6 +2212,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);
@@ -3074,7 +3083,13 @@ ScriptEditor::ScriptEditor(EditorNode *p_editor) {
site_search->set_text(TTR("Online Docs"));
site_search->connect("pressed", this, "_menu_option", varray(SEARCH_WEBSITE));
menu_hb->add_child(site_search);
- site_search->set_tooltip(TTR("Open Godot online documentation"));
+ site_search->set_tooltip(TTR("Open Godot online documentation."));
+
+ request_docs = memnew(ToolButton);
+ request_docs->set_text(TTR("Request Docs"));
+ request_docs->connect("pressed", this, "_menu_option", varray(REQUEST_DOCS));
+ menu_hb->add_child(request_docs);
+ request_docs->set_tooltip(TTR("Help improve the Godot documentation by giving feedback."));
help_search = memnew(ToolButton);
help_search->set_text(TTR("Search Help"));
diff --git a/editor/plugins/script_editor_plugin.h b/editor/plugins/script_editor_plugin.h
index 11f4589f00..954b014935 100644
--- a/editor/plugins/script_editor_plugin.h
+++ b/editor/plugins/script_editor_plugin.h
@@ -157,6 +157,7 @@ class ScriptEditor : public PanelContainer {
DEBUG_WITH_EXTERNAL_EDITOR,
SEARCH_HELP,
SEARCH_WEBSITE,
+ REQUEST_DOCS,
HELP_SEARCH_FIND,
HELP_SEARCH_FIND_NEXT,
WINDOW_MOVE_UP,
@@ -200,6 +201,7 @@ class ScriptEditor : public PanelContainer {
Button *help_search;
Button *site_search;
+ Button *request_docs;
EditorHelpSearch *help_search_dialog;
ItemList *script_list;
diff --git a/editor/plugins/script_text_editor.cpp b/editor/plugins/script_text_editor.cpp
index e95b1356bf..9fc42e3862 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);
@@ -794,92 +796,7 @@ void ScriptTextEditor::_edit_option(int p_op) {
} break;
case EDIT_TOGGLE_COMMENT: {
- Ref<Script> scr = script;
- if (scr.is_null())
- return;
-
- String delimiter = "#";
- List<String> comment_delimiters;
- scr->get_language()->get_comment_delimiters(&comment_delimiters);
-
- for (List<String>::Element *E = comment_delimiters.front(); E; E = E->next()) {
- String script_delimiter = E->get();
- if (script_delimiter.find(" ") == -1) {
- delimiter = script_delimiter;
- break;
- }
- }
-
- tx->begin_complex_operation();
- if (tx->is_selection_active()) {
- int begin = tx->get_selection_from_line();
- int end = tx->get_selection_to_line();
-
- // End of selection ends on the first column of the last line, ignore it.
- if (tx->get_selection_to_column() == 0)
- end -= 1;
-
- int col_to = tx->get_selection_to_column();
- int cursor_pos = tx->cursor_get_column();
-
- // Check if all lines in the selected block are commented
- bool is_commented = true;
- for (int i = begin; i <= end; i++) {
- if (!tx->get_line(i).begins_with(delimiter)) {
- is_commented = false;
- break;
- }
- }
- for (int i = begin; i <= end; i++) {
- String line_text = tx->get_line(i);
-
- if (line_text.strip_edges().empty()) {
- line_text = delimiter;
- } else {
- if (is_commented) {
- line_text = line_text.substr(delimiter.length(), line_text.length());
- } else {
- line_text = delimiter + line_text;
- }
- }
- tx->set_line(i, line_text);
- }
-
- // Adjust selection & cursor position.
- int offset = is_commented ? -1 : 1;
- int col_from = tx->get_selection_from_column() > 0 ? tx->get_selection_from_column() + offset : 0;
-
- if (is_commented && tx->cursor_get_column() == tx->get_line(tx->cursor_get_line()).length() + 1)
- cursor_pos += 1;
-
- if (tx->get_selection_to_column() != 0 && col_to != tx->get_line(tx->get_selection_to_line()).length() + 1)
- col_to += offset;
-
- if (tx->cursor_get_column() != 0)
- cursor_pos += offset;
-
- tx->select(begin, col_from, tx->get_selection_to_line(), col_to);
- tx->cursor_set_column(cursor_pos);
-
- } else {
- int begin = tx->cursor_get_line();
- String line_text = tx->get_line(begin);
-
- int col = tx->cursor_get_column();
- if (line_text.begins_with(delimiter)) {
- line_text = line_text.substr(delimiter.length(), line_text.length());
- col -= 1;
- } else {
- line_text = delimiter + line_text;
- col += 1;
- }
-
- tx->set_line(begin, line_text);
- tx->cursor_set_column(col);
- }
- tx->end_complex_operation();
- tx->update();
-
+ _edit_option_toggle_inline_comment();
} break;
case EDIT_COMPLETE: {
@@ -993,7 +910,7 @@ void ScriptTextEditor::_edit_option(int p_op) {
tx->set_line_as_breakpoint(line, dobreak);
ScriptEditor::get_singleton()->get_debugger()->set_breakpoint(script->get_path(), line + 1, dobreak);
}
- }
+ } break;
case DEBUG_GOTO_NEXT_BREAKPOINT: {
List<int> bpoints;
@@ -1066,6 +983,25 @@ void ScriptTextEditor::_edit_option(int p_op) {
}
}
+void ScriptTextEditor::_edit_option_toggle_inline_comment() {
+ if (script.is_null())
+ return;
+
+ String delimiter = "#";
+ List<String> comment_delimiters;
+ script->get_language()->get_comment_delimiters(&comment_delimiters);
+
+ for (List<String>::Element *E = comment_delimiters.front(); E; E = E->next()) {
+ String script_delimiter = E->get();
+ if (script_delimiter.find(" ") == -1) {
+ delimiter = script_delimiter;
+ break;
+ }
+ }
+
+ code_editor->toggle_inline_comment(delimiter);
+}
+
void ScriptTextEditor::add_syntax_highlighter(SyntaxHighlighter *p_highlighter) {
highlighters[p_highlighter->get_name()] = p_highlighter;
highlighter_menu->add_radio_check_item(p_highlighter->get_name());
diff --git a/editor/plugins/script_text_editor.h b/editor/plugins/script_text_editor.h
index f83aadddef..b081a31c18 100644
--- a/editor/plugins/script_text_editor.h
+++ b/editor/plugins/script_text_editor.h
@@ -136,6 +136,7 @@ protected:
void _change_syntax_highlighter(int p_idx);
void _edit_option(int p_op);
+ void _edit_option_toggle_inline_comment();
void _make_context_menu(bool p_selection, bool p_color, bool p_foldable, bool p_open_docs, bool p_goto_definition);
void _text_edit_gui_input(const Ref<InputEvent> &ev);
void _color_changed(const Color &p_color);
diff --git a/editor/plugins/shader_editor_plugin.cpp b/editor/plugins/shader_editor_plugin.cpp
index 2b6ceac8e2..d39e521113 100644
--- a/editor/plugins/shader_editor_plugin.cpp
+++ b/editor/plugins/shader_editor_plugin.cpp
@@ -248,19 +248,19 @@ void ShaderEditor::_menu_option(int p_option) {
} break;
case EDIT_INDENT_LEFT: {
- TextEdit *tx = shader_editor->get_text_edit();
if (shader.is_null())
return;
+ TextEdit *tx = shader_editor->get_text_edit();
tx->indent_left();
} break;
case EDIT_INDENT_RIGHT: {
- TextEdit *tx = shader_editor->get_text_edit();
if (shader.is_null())
return;
+ TextEdit *tx = shader_editor->get_text_edit();
tx->indent_right();
} break;
@@ -272,54 +272,10 @@ void ShaderEditor::_menu_option(int p_option) {
} break;
case EDIT_TOGGLE_COMMENT: {
- TextEdit *tx = shader_editor->get_text_edit();
if (shader.is_null())
return;
- tx->begin_complex_operation();
- if (tx->is_selection_active()) {
- int begin = tx->get_selection_from_line();
- int end = tx->get_selection_to_line();
-
- // End of selection ends on the first column of the last line, ignore it.
- if (tx->get_selection_to_column() == 0)
- end -= 1;
-
- // Check if all lines in the selected block are commented
- bool is_commented = true;
- for (int i = begin; i <= end; i++) {
- if (!tx->get_line(i).begins_with("//")) {
- is_commented = false;
- break;
- }
- }
- for (int i = begin; i <= end; i++) {
- String line_text = tx->get_line(i);
-
- if (line_text.strip_edges().empty()) {
- line_text = "//";
- } else {
- if (is_commented) {
- line_text = line_text.substr(2, line_text.length());
- } else {
- line_text = "//" + line_text;
- }
- }
- tx->set_line(i, line_text);
- }
- } else {
- int begin = tx->cursor_get_line();
- String line_text = tx->get_line(begin);
-
- if (line_text.begins_with("//"))
- line_text = line_text.substr(2, line_text.length());
- else
- line_text = "//" + line_text;
- tx->set_line(begin, line_text);
- }
- tx->end_complex_operation();
- tx->update();
- //tx->deselect();
+ shader_editor->toggle_inline_comment("//");
} break;
case EDIT_COMPLETE: {
diff --git a/editor/plugins/spatial_editor_plugin.cpp b/editor/plugins/spatial_editor_plugin.cpp
index ed11d26f25..f48887d342 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)) {
@@ -2382,7 +2382,10 @@ void SpatialEditorViewport::_draw() {
if (cursor.region_select) {
- VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(cursor.region_begin, cursor.region_end - cursor.region_begin), Color(0.7, 0.7, 1.0, 0.3));
+ VisualServer::get_singleton()->canvas_item_add_rect(
+ ci,
+ Rect2(cursor.region_begin, cursor.region_end - cursor.region_begin),
+ get_color("accent_color", "Editor") * Color(1, 1, 1, 0.375));
}
if (message_time > 0) {
@@ -2396,7 +2399,13 @@ void SpatialEditorViewport::_draw() {
if (_edit.mode == TRANSFORM_ROTATE) {
Point2 center = _point_to_screen(_edit.center);
- VisualServer::get_singleton()->canvas_item_add_line(ci, _edit.mouse_pos, center, Color(0.4, 0.7, 1.0, 0.8));
+ VisualServer::get_singleton()->canvas_item_add_line(
+ ci,
+ _edit.mouse_pos,
+ center,
+ get_color("accent_color", "Editor") * Color(1, 1, 1, 0.6),
+ Math::round(2 * EDSCALE),
+ true);
}
if (previewing) {
@@ -3001,7 +3010,7 @@ void SpatialEditorViewport::set_state(const Dictionary &p_state) {
previewing = Object::cast_to<Camera>(pv);
previewing->connect("tree_exiting", this, "_preview_exited_scene");
VS::get_singleton()->viewport_attach_camera(viewport->get_viewport_rid(), previewing->get_camera()); //replace
- view_menu->hide();
+ view_menu->set_disabled(true);
surface->update();
preview_camera->set_pressed(true);
preview_camera->show();
@@ -4117,10 +4126,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;
}
@@ -4170,9 +4179,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]);
}
}
@@ -4205,32 +4218,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();
}
}
@@ -4344,7 +4344,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();
}
@@ -4840,30 +4840,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;
+ }
}
}
@@ -5225,8 +5241,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);
@@ -5751,15 +5767,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();
}
@@ -5912,6 +5952,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")) {
@@ -5944,6 +5991,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"));
@@ -6043,6 +6091,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_frames_editor_plugin.cpp b/editor/plugins/sprite_frames_editor_plugin.cpp
index 89bb7440fe..5ba2fde763 100644
--- a/editor/plugins/sprite_frames_editor_plugin.cpp
+++ b/editor/plugins/sprite_frames_editor_plugin.cpp
@@ -347,9 +347,6 @@ void SpriteFramesEditor::_animation_name_edited() {
for (List<Node *>::Element *E = nodes.front(); E; E = E->next()) {
String current = E->get()->call("get_animation");
- if (current != edited_anim)
- continue;
-
undo_redo->add_do_method(E->get(), "set_animation", name);
undo_redo->add_undo_method(E->get(), "set_animation", edited_anim);
}
@@ -382,9 +379,6 @@ void SpriteFramesEditor::_animation_add() {
for (List<Node *>::Element *E = nodes.front(); E; E = E->next()) {
String current = E->get()->call("get_animation");
- if (frames->has_animation(current))
- continue;
-
undo_redo->add_do_method(E->get(), "set_animation", name);
undo_redo->add_undo_method(E->get(), "set_animation", current);
}
diff --git a/editor/plugins/texture_editor_plugin.cpp b/editor/plugins/texture_editor_plugin.cpp
index 831b2f3f16..0aa4a7662c 100644
--- a/editor/plugins/texture_editor_plugin.cpp
+++ b/editor/plugins/texture_editor_plugin.cpp
@@ -138,10 +138,15 @@ TextureEditor::TextureEditor() {
set_custom_minimum_size(Size2(1, 150));
}
+TextureEditor::~TextureEditor() {
+ if (!texture.is_null()) {
+ texture->remove_change_receptor(this);
+ }
+}
//
bool EditorInspectorPluginTexture::can_handle(Object *p_object) {
- return Object::cast_to<Texture>(p_object) != NULL;
+ 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 EditorInspectorPluginTexture::parse_begin(Object *p_object) {
diff --git a/editor/plugins/texture_editor_plugin.h b/editor/plugins/texture_editor_plugin.h
index 9c7d33df5a..bcbda1fbd7 100644
--- a/editor/plugins/texture_editor_plugin.h
+++ b/editor/plugins/texture_editor_plugin.h
@@ -50,6 +50,7 @@ protected:
public:
void edit(Ref<Texture> p_texture);
TextureEditor();
+ ~TextureEditor();
};
class EditorInspectorPluginTexture : public EditorInspectorPlugin {
diff --git a/editor/plugins/texture_region_editor_plugin.cpp b/editor/plugins/texture_region_editor_plugin.cpp
index 3eeb871380..f741040fa8 100644
--- a/editor/plugins/texture_region_editor_plugin.cpp
+++ b/editor/plugins/texture_region_editor_plugin.cpp
@@ -64,7 +64,7 @@ void TextureRegionEditor::_region_draw() {
return;
Transform2D mtx;
- mtx.elements[2] = -draw_ofs;
+ mtx.elements[2] = -draw_ofs * draw_zoom;
mtx.scale_basis(Vector2(draw_zoom, draw_zoom));
VS::get_singleton()->canvas_item_add_set_transform(edit_draw->get_canvas_item(), mtx);
@@ -128,7 +128,7 @@ void TextureRegionEditor::_region_draw() {
};
for (int i = 0; i < 4; i++) {
int next = (i + 1) % 4;
- edit_draw->draw_line(endpoints[i] - draw_ofs, endpoints[next] - draw_ofs, Color(0.3, 0.7, 1, 1), 2);
+ edit_draw->draw_line(endpoints[i] - draw_ofs * draw_zoom, endpoints[next] - draw_ofs * draw_zoom, Color(0.3, 0.7, 1, 1), 2);
}
}
}
@@ -153,16 +153,16 @@ void TextureRegionEditor::_region_draw() {
Vector2 ofs = ((endpoints[i] - endpoints[prev]).normalized() + ((endpoints[i] - endpoints[next]).normalized())).normalized();
ofs *= 1.4144 * (select_handle->get_size().width / 2);
- edit_draw->draw_line(endpoints[i] - draw_ofs, endpoints[next] - draw_ofs, color, 2);
+ edit_draw->draw_line(endpoints[i] - draw_ofs * draw_zoom, endpoints[next] - draw_ofs * draw_zoom, color, 2);
if (snap_mode != SNAP_AUTOSLICE)
- edit_draw->draw_texture(select_handle, (endpoints[i] + ofs - (select_handle->get_size() / 2)).floor() - draw_ofs);
+ edit_draw->draw_texture(select_handle, (endpoints[i] + ofs - (select_handle->get_size() / 2)).floor() - draw_ofs * draw_zoom);
ofs = (endpoints[next] - endpoints[i]) / 2;
ofs += (endpoints[next] - endpoints[i]).tangent().normalized() * (select_handle->get_size().width / 2);
if (snap_mode != SNAP_AUTOSLICE)
- edit_draw->draw_texture(select_handle, (endpoints[i] + ofs - (select_handle->get_size() / 2)).floor() - draw_ofs);
+ edit_draw->draw_texture(select_handle, (endpoints[i] + ofs - (select_handle->get_size() / 2)).floor() - draw_ofs * draw_zoom);
scroll_rect.expand_to(endpoints[i]);
}
@@ -205,10 +205,10 @@ void TextureRegionEditor::_region_draw() {
margins[3] = obj_styleBox->get_margin_size(MARGIN_RIGHT);
}
Vector2 pos[4] = {
- mtx.basis_xform(Vector2(0, margins[0])) + Vector2(0, endpoints[0].y - draw_ofs.y),
- -mtx.basis_xform(Vector2(0, margins[1])) + Vector2(0, endpoints[2].y - draw_ofs.y),
- mtx.basis_xform(Vector2(margins[2], 0)) + Vector2(endpoints[0].x - draw_ofs.x, 0),
- -mtx.basis_xform(Vector2(margins[3], 0)) + Vector2(endpoints[2].x - draw_ofs.x, 0)
+ mtx.basis_xform(Vector2(0, margins[0])) + Vector2(0, endpoints[0].y - draw_ofs.y * draw_zoom),
+ -mtx.basis_xform(Vector2(0, margins[1])) + Vector2(0, endpoints[2].y - draw_ofs.y * draw_zoom),
+ mtx.basis_xform(Vector2(margins[2], 0)) + Vector2(endpoints[0].x - draw_ofs.x * draw_zoom, 0),
+ -mtx.basis_xform(Vector2(margins[3], 0)) + Vector2(endpoints[2].x - draw_ofs.x * draw_zoom, 0)
};
draw_margin_line(edit_draw, pos[0], pos[0] + Vector2(edit_draw->get_size().x, 0));
@@ -220,7 +220,7 @@ void TextureRegionEditor::_region_draw() {
void TextureRegionEditor::_region_input(const Ref<InputEvent> &p_input) {
Transform2D mtx;
- mtx.elements[2] = -draw_ofs;
+ mtx.elements[2] = -draw_ofs * draw_zoom;
mtx.scale_basis(Vector2(draw_zoom, draw_zoom));
Vector2 endpoints[8] = {
@@ -255,10 +255,10 @@ void TextureRegionEditor::_region_input(const Ref<InputEvent> &p_input) {
margins[3] = obj_styleBox->get_margin_size(MARGIN_RIGHT);
}
Vector2 pos[4] = {
- mtx.basis_xform(rect.position + Vector2(0, margins[0])) - draw_ofs,
- mtx.basis_xform(rect.position + rect.size - Vector2(0, margins[1])) - draw_ofs,
- mtx.basis_xform(rect.position + Vector2(margins[2], 0)) - draw_ofs,
- mtx.basis_xform(rect.position + rect.size - Vector2(margins[3], 0)) - draw_ofs
+ mtx.basis_xform(rect.position + Vector2(0, margins[0])) - draw_ofs * draw_zoom,
+ mtx.basis_xform(rect.position + rect.size - Vector2(0, margins[1])) - draw_ofs * draw_zoom,
+ mtx.basis_xform(rect.position + Vector2(margins[2], 0)) - draw_ofs * draw_zoom,
+ mtx.basis_xform(rect.position + rect.size - Vector2(margins[3], 0)) - draw_ofs * draw_zoom
};
if (Math::abs(mb->get_position().y - pos[0].y) < 8) {
edited_margin = 0;
@@ -415,9 +415,9 @@ void TextureRegionEditor::_region_input(const Ref<InputEvent> &p_input) {
}
}
} else if (mb->get_button_index() == BUTTON_WHEEL_UP && mb->is_pressed()) {
- _zoom_in();
+ _zoom_on_position(draw_zoom * ((0.95 + (0.05 * mb->get_factor())) / 0.95), mb->get_position());
} else if (mb->get_button_index() == BUTTON_WHEEL_DOWN && mb->is_pressed()) {
- _zoom_out();
+ _zoom_on_position(draw_zoom * (1 - (0.05 * mb->get_factor())), mb->get_position());
}
}
@@ -427,7 +427,7 @@ void TextureRegionEditor::_region_input(const Ref<InputEvent> &p_input) {
if (mm->get_button_mask() & BUTTON_MASK_MIDDLE || Input::get_singleton()->is_key_pressed(KEY_SPACE)) {
- Vector2 draged(mm->get_relative().x, mm->get_relative().y);
+ Vector2 draged(mm->get_relative().x / draw_zoom, mm->get_relative().y / draw_zoom);
hscroll->set_value(hscroll->get_value() - draged.x);
vscroll->set_value(vscroll->get_value() - draged.y);
@@ -578,25 +578,30 @@ void TextureRegionEditor::_set_snap_sep_y(float p_val) {
edit_draw->update();
}
+void TextureRegionEditor::_zoom_on_position(float p_zoom, Point2 p_position) {
+ if (p_zoom < 0.25 || p_zoom > 8)
+ return;
+
+ float prev_zoom = draw_zoom;
+ draw_zoom = p_zoom;
+ Point2 ofs = p_position;
+ ofs = ofs / prev_zoom - ofs / draw_zoom;
+ draw_ofs.x = Math::round(draw_ofs.x + ofs.x);
+ draw_ofs.y = Math::round(draw_ofs.y + ofs.y);
+
+ edit_draw->update();
+}
+
void TextureRegionEditor::_zoom_in() {
- if (draw_zoom < 8) {
- draw_zoom *= 2;
- edit_draw->update();
- }
+ _zoom_on_position(draw_zoom * 1.5, edit_draw->get_size() / 2.0);
}
void TextureRegionEditor::_zoom_reset() {
- if (draw_zoom == 1)
- return;
- draw_zoom = 1;
- edit_draw->update();
+ _zoom_on_position(1.0, edit_draw->get_size() / 2.0);
}
void TextureRegionEditor::_zoom_out() {
- if (draw_zoom > 0.25) {
- draw_zoom /= 2;
- edit_draw->update();
- }
+ _zoom_on_position(draw_zoom / 1.5, edit_draw->get_size() / 2.0);
}
void TextureRegionEditor::apply_rect(const Rect2 &p_rect) {
@@ -743,6 +748,7 @@ void TextureRegionEditor::_bind_methods() {
ClassDB::bind_method(D_METHOD("_set_snap_step_y"), &TextureRegionEditor::_set_snap_step_y);
ClassDB::bind_method(D_METHOD("_set_snap_sep_x"), &TextureRegionEditor::_set_snap_sep_x);
ClassDB::bind_method(D_METHOD("_set_snap_sep_y"), &TextureRegionEditor::_set_snap_sep_y);
+ ClassDB::bind_method(D_METHOD("_zoom_on_position"), &TextureRegionEditor::_zoom_on_position);
ClassDB::bind_method(D_METHOD("_zoom_in"), &TextureRegionEditor::_zoom_in);
ClassDB::bind_method(D_METHOD("_zoom_reset"), &TextureRegionEditor::_zoom_reset);
ClassDB::bind_method(D_METHOD("_zoom_out"), &TextureRegionEditor::_zoom_out);
diff --git a/editor/plugins/texture_region_editor_plugin.h b/editor/plugins/texture_region_editor_plugin.h
index 19eaef9bc3..a49e0fb96c 100644
--- a/editor/plugins/texture_region_editor_plugin.h
+++ b/editor/plugins/texture_region_editor_plugin.h
@@ -110,6 +110,7 @@ class TextureRegionEditor : public VBoxContainer {
void _set_snap_step_y(float p_val);
void _set_snap_sep_x(float p_val);
void _set_snap_sep_y(float p_val);
+ void _zoom_on_position(float p_zoom, Point2 p_position = Point2());
void _zoom_in();
void _zoom_reset();
void _zoom_out();
diff --git a/editor/plugins/tile_map_editor_plugin.cpp b/editor/plugins/tile_map_editor_plugin.cpp
index 1a367b61dd..33e4bb2336 100644
--- a/editor/plugins/tile_map_editor_plugin.cpp
+++ b/editor/plugins/tile_map_editor_plugin.cpp
@@ -299,7 +299,11 @@ void TileMapEditor::_set_cell(const Point2i &p_pos, Vector<int> p_values, bool p
}
}
- node->set_cell(p_pos.x, p_pos.y, p_value, p_flip_h, p_flip_v, p_transpose, p_autotile_coord);
+ Variant v_pos_x = p_pos.x, v_pos_y = p_pos.y, v_tile = p_value, v_flip_h = p_flip_h, v_flip_v = p_flip_v, v_transpose = p_transpose, v_autotile_coord = Vector2(p_autotile_coord.x, p_autotile_coord.y);
+ const Variant *args[7] = { &v_pos_x, &v_pos_y, &v_tile, &v_flip_h, &v_flip_v, &v_transpose, &v_autotile_coord };
+ Variant::CallError ce;
+ node->call("set_cell", args, 7, ce);
+
if (manual_autotile || (p_value != -1 && node->get_tileset()->tile_get_tile_mode(p_value) == TileSet::ATLAS_TILE)) {
if (current != -1) {
node->set_cell_autotile_coord(p_pos.x, p_pos.y, position);
@@ -477,10 +481,10 @@ void TileMapEditor::_update_palette() {
if (sel_tile != TileMap::INVALID_CELL) {
if ((manual_autotile && tileset->tile_get_tile_mode(sel_tile) == TileSet::AUTO_TILE) || tileset->tile_get_tile_mode(sel_tile) == TileSet::ATLAS_TILE) {
- const Map<Vector2, uint16_t> &tiles2 = tileset->autotile_get_bitmask_map(sel_tile);
+ const Map<Vector2, uint32_t> &tiles2 = tileset->autotile_get_bitmask_map(sel_tile);
Vector<Vector2> entries2;
- for (const Map<Vector2, uint16_t>::Element *E = tiles2.front(); E; E = E->next()) {
+ for (const Map<Vector2, uint32_t>::Element *E = tiles2.front(); E; E = E->next()) {
entries2.push_back(E->key());
}
entries2.sort();
@@ -1434,9 +1438,9 @@ void TileMapEditor::forward_canvas_draw_over_viewport(Control *p_overlay) {
aabb.expand_to(node->world_to_map(xform_inv.xform(screen_size)));
Rect2i si = aabb.grow(1.0);
- if (node->get_half_offset() != TileMap::HALF_OFFSET_X) {
+ if (node->get_half_offset() != TileMap::HALF_OFFSET_X && node->get_half_offset() != TileMap::HALF_OFFSET_NEGATIVE_X) {
- int max_lines = 2000; //avoid crash if size too smal
+ int max_lines = 2000; //avoid crash if size too small
for (int i = (si.position.x) - 1; i <= (si.position.x + si.size.x); i++) {
@@ -1450,7 +1454,7 @@ void TileMapEditor::forward_canvas_draw_over_viewport(Control *p_overlay) {
}
} else {
- int max_lines = 10000; //avoid crash if size too smal
+ int max_lines = 10000; //avoid crash if size too small
for (int i = (si.position.x) - 1; i <= (si.position.x + si.size.x); i++) {
@@ -1458,23 +1462,26 @@ void TileMapEditor::forward_canvas_draw_over_viewport(Control *p_overlay) {
Vector2 ofs;
if (ABS(j) & 1) {
- ofs = cell_xf[0] * 0.5;
+ ofs = cell_xf[0] * (node->get_half_offset() == TileMap::HALF_OFFSET_X ? 0.5 : -0.5);
}
Vector2 from = xform.xform(node->map_to_world(Vector2(i, j), true) + ofs);
Vector2 to = xform.xform(node->map_to_world(Vector2(i, j + 1), true) + ofs);
+
Color col = i == 0 ? Color(1, 0.8, 0.2, 0.5) : Color(1, 0.3, 0.1, 0.2);
p_overlay->draw_line(from, to, col, 1);
- if (max_lines-- == 0)
+ if (--max_lines == 0)
break;
}
+ if (max_lines == 0)
+ break;
}
}
int max_lines = 10000; //avoid crash if size too smal
- if (node->get_half_offset() != TileMap::HALF_OFFSET_Y) {
+ if (node->get_half_offset() != TileMap::HALF_OFFSET_Y && node->get_half_offset() != TileMap::HALF_OFFSET_NEGATIVE_Y) {
for (int i = (si.position.y) - 1; i <= (si.position.y + si.size.y); i++) {
@@ -1495,17 +1502,20 @@ void TileMapEditor::forward_canvas_draw_over_viewport(Control *p_overlay) {
Vector2 ofs;
if (ABS(j) & 1) {
- ofs = cell_xf[1] * 0.5;
+ ofs = cell_xf[1] * (node->get_half_offset() == TileMap::HALF_OFFSET_Y ? 0.5 : -0.5);
}
Vector2 from = xform.xform(node->map_to_world(Vector2(j, i), true) + ofs);
Vector2 to = xform.xform(node->map_to_world(Vector2(j + 1, i), true) + ofs);
+
Color col = i == 0 ? Color(1, 0.8, 0.2, 0.5) : Color(1, 0.3, 0.1, 0.2);
p_overlay->draw_line(from, to, col, 1);
- if (max_lines-- == 0)
+ if (--max_lines == 0)
break;
}
+ if (max_lines == 0)
+ break;
}
}
}
@@ -1533,8 +1543,12 @@ void TileMapEditor::forward_canvas_draw_over_viewport(Control *p_overlay) {
for (int i = 0; i < 4; i++) {
if (node->get_half_offset() == TileMap::HALF_OFFSET_X && ABS(over_tile.y) & 1)
endpoints[i] += cell_xf[0] * 0.5;
+ if (node->get_half_offset() == TileMap::HALF_OFFSET_NEGATIVE_X && ABS(over_tile.y) & 1)
+ endpoints[i] += cell_xf[0] * -0.5;
if (node->get_half_offset() == TileMap::HALF_OFFSET_Y && ABS(over_tile.x) & 1)
endpoints[i] += cell_xf[1] * 0.5;
+ if (node->get_half_offset() == TileMap::HALF_OFFSET_NEGATIVE_Y && ABS(over_tile.x) & 1)
+ endpoints[i] += cell_xf[1] * -0.5;
endpoints[i] = xform.xform(endpoints[i]);
}
Color col;
diff --git a/editor/plugins/tile_set_editor_plugin.cpp b/editor/plugins/tile_set_editor_plugin.cpp
index dc099b84a7..5bc1067718 100644
--- a/editor/plugins/tile_set_editor_plugin.cpp
+++ b/editor/plugins/tile_set_editor_plugin.cpp
@@ -734,7 +734,7 @@ void TileSetEditor::_on_edit_mode_changed(int p_edit_mode) {
tools[SHAPE_KEEP_INSIDE_TILE]->hide();
tools[TOOL_SELECT]->set_pressed(true);
- tools[TOOL_SELECT]->set_tooltip(TTR("LMB: Set bit on.\nRMB: Set bit off.\nClick on another Tile to edit it."));
+ tools[TOOL_SELECT]->set_tooltip(TTR("LMB: Set bit on.\nRMB: Set bit off.\nShift+LMB: Set wildcard bit.\nClick on another Tile to edit it."));
spin_priority->hide();
} break;
case EDITMODE_Z_INDEX:
@@ -818,52 +818,92 @@ void TileSetEditor::_on_workspace_draw() {
} break;
case EDITMODE_BITMASK: {
Color c(1, 0, 0, 0.5);
+ Color ci(0.3, 0.6, 1, 0.5);
for (float x = 0; x < region.size.x / (spacing + size.x); x++) {
for (float y = 0; y < region.size.y / (spacing + size.y); y++) {
Vector2 coord(x, y);
Point2 anchor(coord.x * (spacing + size.x), coord.y * (spacing + size.y));
anchor += WORKSPACE_MARGIN;
anchor += region.position;
- uint16_t mask = tileset->autotile_get_bitmask(get_current_tile(), coord);
+ uint32_t mask = tileset->autotile_get_bitmask(get_current_tile(), coord);
if (tileset->autotile_get_bitmask_mode(get_current_tile()) == TileSet::BITMASK_2X2) {
- if (mask & TileSet::BIND_TOPLEFT) {
+ if (mask & TileSet::BIND_IGNORE_TOPLEFT) {
+ workspace->draw_rect(Rect2(anchor, size / 4), ci);
+ workspace->draw_rect(Rect2(anchor + size / 4, size / 4), ci);
+ } else if (mask & TileSet::BIND_TOPLEFT) {
workspace->draw_rect(Rect2(anchor, size / 2), c);
}
- if (mask & TileSet::BIND_TOPRIGHT) {
+ if (mask & TileSet::BIND_IGNORE_TOPRIGHT) {
+ workspace->draw_rect(Rect2(anchor + Vector2(size.x / 2, 0), size / 4), ci);
+ workspace->draw_rect(Rect2(anchor + Vector2(size.x * 3 / 4, size.y / 4), size / 4), ci);
+ } else if (mask & TileSet::BIND_TOPRIGHT) {
workspace->draw_rect(Rect2(anchor + Vector2(size.x / 2, 0), size / 2), c);
}
- if (mask & TileSet::BIND_BOTTOMLEFT) {
+ if (mask & TileSet::BIND_IGNORE_BOTTOMLEFT) {
+ workspace->draw_rect(Rect2(anchor + Vector2(0, size.y / 2), size / 4), ci);
+ workspace->draw_rect(Rect2(anchor + Vector2(size.x / 4, size.y * 3 / 4), size / 4), ci);
+ } else if (mask & TileSet::BIND_BOTTOMLEFT) {
workspace->draw_rect(Rect2(anchor + Vector2(0, size.y / 2), size / 2), c);
}
- if (mask & TileSet::BIND_BOTTOMRIGHT) {
+ if (mask & TileSet::BIND_IGNORE_BOTTOMRIGHT) {
+ workspace->draw_rect(Rect2(anchor + size / 2, size / 4), ci);
+ workspace->draw_rect(Rect2(anchor + size * 3 / 4, size / 4), ci);
+ } else if (mask & TileSet::BIND_BOTTOMRIGHT) {
workspace->draw_rect(Rect2(anchor + size / 2, size / 2), c);
}
} else {
- if (mask & TileSet::BIND_TOPLEFT) {
+ if (mask & TileSet::BIND_IGNORE_TOPLEFT) {
+ workspace->draw_rect(Rect2(anchor, size / 6), ci);
+ workspace->draw_rect(Rect2(anchor + size / 6, size / 6), ci);
+ } else if (mask & TileSet::BIND_TOPLEFT) {
workspace->draw_rect(Rect2(anchor, size / 3), c);
}
- if (mask & TileSet::BIND_TOP) {
+ if (mask & TileSet::BIND_IGNORE_TOP) {
+ workspace->draw_rect(Rect2(anchor + Vector2(size.x / 3, 0), size / 6), ci);
+ workspace->draw_rect(Rect2(anchor + Vector2(size.x / 2, size.y / 6), size / 6), ci);
+ } else if (mask & TileSet::BIND_TOP) {
workspace->draw_rect(Rect2(anchor + Vector2(size.x / 3, 0), size / 3), c);
}
- if (mask & TileSet::BIND_TOPRIGHT) {
+ if (mask & TileSet::BIND_IGNORE_TOPRIGHT) {
+ workspace->draw_rect(Rect2(anchor + Vector2(size.x * 4 / 6, 0), size / 6), ci);
+ workspace->draw_rect(Rect2(anchor + Vector2(size.x * 5 / 6, size.y / 6), size / 6), ci);
+ } else if (mask & TileSet::BIND_TOPRIGHT) {
workspace->draw_rect(Rect2(anchor + Vector2((size.x / 3) * 2, 0), size / 3), c);
}
- if (mask & TileSet::BIND_LEFT) {
+ if (mask & TileSet::BIND_IGNORE_LEFT) {
+ workspace->draw_rect(Rect2(anchor + Vector2(0, size.y / 3), size / 6), ci);
+ workspace->draw_rect(Rect2(anchor + Vector2(size.x / 6, size.y / 2), size / 6), ci);
+ } else if (mask & TileSet::BIND_LEFT) {
workspace->draw_rect(Rect2(anchor + Vector2(0, size.y / 3), size / 3), c);
}
- if (mask & TileSet::BIND_CENTER) {
+ if (mask & TileSet::BIND_IGNORE_CENTER) {
+ workspace->draw_rect(Rect2(anchor + size / 3, size / 6), ci);
+ workspace->draw_rect(Rect2(anchor + size / 2, size / 6), ci);
+ } else if (mask & TileSet::BIND_CENTER) {
workspace->draw_rect(Rect2(anchor + Vector2(size.x / 3, size.y / 3), size / 3), c);
}
- if (mask & TileSet::BIND_RIGHT) {
+ if (mask & TileSet::BIND_IGNORE_RIGHT) {
+ workspace->draw_rect(Rect2(anchor + Vector2(size.x * 4 / 6, size.y / 3), size / 6), ci);
+ workspace->draw_rect(Rect2(anchor + Vector2(size.x * 5 / 6, size.y / 2), size / 6), ci);
+ } else if (mask & TileSet::BIND_RIGHT) {
workspace->draw_rect(Rect2(anchor + Vector2((size.x / 3) * 2, size.y / 3), size / 3), c);
}
- if (mask & TileSet::BIND_BOTTOMLEFT) {
+ if (mask & TileSet::BIND_IGNORE_BOTTOMLEFT) {
+ workspace->draw_rect(Rect2(anchor + Vector2(0, size.y * 4 / 6), size / 6), ci);
+ workspace->draw_rect(Rect2(anchor + Vector2(size.x / 6, size.y * 5 / 6), size / 6), ci);
+ } else if (mask & TileSet::BIND_BOTTOMLEFT) {
workspace->draw_rect(Rect2(anchor + Vector2(0, (size.y / 3) * 2), size / 3), c);
}
- if (mask & TileSet::BIND_BOTTOM) {
+ if (mask & TileSet::BIND_IGNORE_BOTTOM) {
+ workspace->draw_rect(Rect2(anchor + Vector2(size.x / 3, size.y * 4 / 6), size / 6), ci);
+ workspace->draw_rect(Rect2(anchor + Vector2(size.x / 2, size.y * 5 / 6), size / 6), ci);
+ } else if (mask & TileSet::BIND_BOTTOM) {
workspace->draw_rect(Rect2(anchor + Vector2(size.x / 3, (size.y / 3) * 2), size / 3), c);
}
- if (mask & TileSet::BIND_BOTTOMRIGHT) {
+ if (mask & TileSet::BIND_IGNORE_BOTTOMRIGHT) {
+ workspace->draw_rect(Rect2(anchor + size * 4 / 6, size / 6), ci);
+ workspace->draw_rect(Rect2(anchor + size * 5 / 6, size / 6), ci);
+ } else if (mask & TileSet::BIND_BOTTOMRIGHT) {
workspace->draw_rect(Rect2(anchor + (size / 3) * 2, size / 3), c);
}
}
@@ -882,10 +922,10 @@ void TileSetEditor::_on_workspace_draw() {
} break;
case EDITMODE_PRIORITY: {
spin_priority->set_value(tileset->autotile_get_subtile_priority(get_current_tile(), edited_shape_coord));
- uint16_t mask = tileset->autotile_get_bitmask(get_current_tile(), edited_shape_coord);
+ uint32_t mask = tileset->autotile_get_bitmask(get_current_tile(), edited_shape_coord);
Vector<Vector2> queue_others;
int total = 0;
- for (Map<Vector2, uint16_t>::Element *E = tileset->autotile_get_bitmask_map(get_current_tile()).front(); E; E = E->next()) {
+ for (Map<Vector2, uint32_t>::Element *E = tileset->autotile_get_bitmask_map(get_current_tile()).front(); E; E = E->next()) {
if (E->value() == mask) {
total += tileset->autotile_get_subtile_priority(get_current_tile(), E->key());
if (E->key() != edited_shape_coord) {
@@ -1037,6 +1077,7 @@ void TileSetEditor::_on_workspace_input(const Ref<InputEvent> &p_ie) {
static bool dragging;
static bool erasing;
+ static bool alternative;
draw_edited_region = false;
Rect2 current_tile_region = Rect2();
@@ -1220,10 +1261,11 @@ void TileSetEditor::_on_workspace_input(const Ref<InputEvent> &p_ie) {
if ((mb->get_button_index() == BUTTON_RIGHT || mb->get_button_index() == BUTTON_LEFT) && current_tile_region.has_point(mb->get_position())) {
dragging = true;
erasing = (mb->get_button_index() == BUTTON_RIGHT);
+ alternative = Input::get_singleton()->is_key_pressed(KEY_SHIFT);
Vector2 coord((int)((mb->get_position().x - current_tile_region.position.x) / (spacing + size.x)), (int)((mb->get_position().y - current_tile_region.position.y) / (spacing + size.y)));
Vector2 pos(coord.x * (spacing + size.x), coord.y * (spacing + size.y));
pos = mb->get_position() - (pos + current_tile_region.position);
- uint16_t bit = 0;
+ uint32_t bit = 0;
if (tileset->autotile_get_bitmask_mode(get_current_tile()) == TileSet::BITMASK_2X2) {
if (pos.x < size.x / 2) {
if (pos.y < size.y / 2) {
@@ -1266,13 +1308,19 @@ void TileSetEditor::_on_workspace_input(const Ref<InputEvent> &p_ie) {
}
}
- uint16_t old_mask = tileset->autotile_get_bitmask(get_current_tile(), coord);
- uint16_t new_mask = old_mask;
- if (erasing) {
+ uint32_t old_mask = tileset->autotile_get_bitmask(get_current_tile(), coord);
+ uint32_t new_mask = old_mask;
+ if (alternative) {
new_mask &= ~bit;
+ new_mask |= (bit << 16);
+ } else if (erasing) {
+ new_mask &= ~bit;
+ new_mask &= ~(bit << 16);
} else {
new_mask |= bit;
+ new_mask &= ~(bit << 16);
}
+
if (old_mask != new_mask) {
undo_redo->create_action(TTR("Edit Tile Bitmask"));
undo_redo->add_do_method(tileset.ptr(), "autotile_set_bitmask", get_current_tile(), coord, new_mask);
@@ -1286,6 +1334,7 @@ void TileSetEditor::_on_workspace_input(const Ref<InputEvent> &p_ie) {
if ((erasing && mb->get_button_index() == BUTTON_RIGHT) || (!erasing && mb->get_button_index() == BUTTON_LEFT)) {
dragging = false;
erasing = false;
+ alternative = false;
}
}
}
@@ -1294,7 +1343,7 @@ void TileSetEditor::_on_workspace_input(const Ref<InputEvent> &p_ie) {
Vector2 coord((int)((mm->get_position().x - current_tile_region.position.x) / (spacing + size.x)), (int)((mm->get_position().y - current_tile_region.position.y) / (spacing + size.y)));
Vector2 pos(coord.x * (spacing + size.x), coord.y * (spacing + size.y));
pos = mm->get_position() - (pos + current_tile_region.position);
- uint16_t bit = 0;
+ uint32_t bit = 0;
if (tileset->autotile_get_bitmask_mode(get_current_tile()) == TileSet::BITMASK_2X2) {
if (pos.x < size.x / 2) {
if (pos.y < size.y / 2) {
@@ -1337,12 +1386,17 @@ void TileSetEditor::_on_workspace_input(const Ref<InputEvent> &p_ie) {
}
}
- uint16_t old_mask = tileset->autotile_get_bitmask(get_current_tile(), coord);
- uint16_t new_mask = old_mask;
- if (erasing) {
+ uint32_t old_mask = tileset->autotile_get_bitmask(get_current_tile(), coord);
+ uint32_t new_mask = old_mask;
+ if (alternative) {
new_mask &= ~bit;
+ new_mask |= (bit << 16);
+ } else if (erasing) {
+ new_mask &= ~bit;
+ new_mask &= ~(bit << 16);
} else {
new_mask |= bit;
+ new_mask &= ~(bit << 16);
}
if (old_mask != new_mask) {
undo_redo->create_action(TTR("Edit Tile Bitmask"));
@@ -1529,10 +1583,10 @@ void TileSetEditor::_on_tool_clicked(int p_tool) {
undo_redo->create_action(TTR("Paste Tile Bitmask"));
undo_redo->add_do_method(tileset.ptr(), "autotile_clear_bitmask_map", get_current_tile());
undo_redo->add_undo_method(tileset.ptr(), "autotile_clear_bitmask_map", get_current_tile());
- for (Map<Vector2, uint16_t>::Element *E = bitmask_map_copy.front(); E; E = E->next()) {
+ for (Map<Vector2, uint32_t>::Element *E = bitmask_map_copy.front(); E; E = E->next()) {
undo_redo->add_do_method(tileset.ptr(), "autotile_set_bitmask", get_current_tile(), E->key(), E->value());
}
- for (Map<Vector2, uint16_t>::Element *E = tileset->autotile_get_bitmask_map(get_current_tile()).front(); E; E = E->next()) {
+ for (Map<Vector2, uint32_t>::Element *E = tileset->autotile_get_bitmask_map(get_current_tile()).front(); E; E = E->next()) {
undo_redo->add_undo_method(tileset.ptr(), "autotile_set_bitmask", get_current_tile(), E->key(), E->value());
}
undo_redo->add_do_method(workspace, "update");
@@ -1541,7 +1595,7 @@ void TileSetEditor::_on_tool_clicked(int p_tool) {
} else if (p_tool == BITMASK_CLEAR) {
undo_redo->create_action(TTR("Clear Tile Bitmask"));
undo_redo->add_do_method(tileset.ptr(), "autotile_clear_bitmask_map", get_current_tile());
- for (Map<Vector2, uint16_t>::Element *E = tileset->autotile_get_bitmask_map(get_current_tile()).front(); E; E = E->next()) {
+ for (Map<Vector2, uint32_t>::Element *E = tileset->autotile_get_bitmask_map(get_current_tile()).front(); E; E = E->next()) {
undo_redo->add_undo_method(tileset.ptr(), "autotile_set_bitmask", get_current_tile(), E->key(), E->value());
}
undo_redo->add_do_method(workspace, "update");
@@ -2139,8 +2193,8 @@ void TileSetEditor::_undo_tile_removal(int p_id) {
for (Map<Vector2, Ref<NavigationPolygon> >::Element *E = navigation_map.front(); E; E = E->next()) {
undo_redo->add_undo_method(tileset.ptr(), "autotile_set_navigation_polygon", p_id, E->value(), E->key());
}
- Map<Vector2, uint16_t> bitmask_map = tileset->autotile_get_bitmask_map(p_id);
- for (Map<Vector2, uint16_t>::Element *E = bitmask_map.front(); E; E = E->next()) {
+ Map<Vector2, uint32_t> bitmask_map = tileset->autotile_get_bitmask_map(p_id);
+ for (Map<Vector2, uint32_t>::Element *E = bitmask_map.front(); E; E = E->next()) {
undo_redo->add_undo_method(tileset.ptr(), "autotile_set_bitmask", p_id, E->key(), E->value());
}
Map<Vector2, int> priority_map = tileset->autotile_get_priority_map(p_id);
@@ -2417,9 +2471,11 @@ void TileSetEditor::draw_polygon_shapes() {
colors.push_back(c_bg);
}
}
- if (polygon.size() > 2) {
- workspace->draw_polygon(polygon, colors);
- }
+
+ if (polygon.size() < 3)
+ continue;
+
+ workspace->draw_polygon(polygon, colors);
if (coord == edited_shape_coord || tileset->tile_get_tile_mode(get_current_tile()) == TileSet::SINGLE_TILE) {
if (!creating_shape) {
diff --git a/editor/plugins/tile_set_editor_plugin.h b/editor/plugins/tile_set_editor_plugin.h
index 2827964592..1176e1bb92 100644
--- a/editor/plugins/tile_set_editor_plugin.h
+++ b/editor/plugins/tile_set_editor_plugin.h
@@ -126,7 +126,7 @@ class TileSetEditor : public HSplitContainer {
Vector2 edited_shape_coord;
PoolVector2Array current_shape;
Map<Vector2i, SubtileData> current_tile_data;
- Map<Vector2, uint16_t> bitmask_map_copy;
+ Map<Vector2, uint32_t> bitmask_map_copy;
Vector2 snap_step;
Vector2 snap_offset;
diff --git a/editor/plugins/visual_shader_editor_plugin.cpp b/editor/plugins/visual_shader_editor_plugin.cpp
index 7bd26de092..f71ff84bbe 100644
--- a/editor/plugins/visual_shader_editor_plugin.cpp
+++ b/editor/plugins/visual_shader_editor_plugin.cpp
@@ -39,6 +39,7 @@
#include "scene/gui/menu_button.h"
#include "scene/gui/panel.h"
#include "scene/main/viewport.h"
+#include "scene/resources/visual_shader_nodes.h"
Control *VisualShaderNodePlugin::create_editor(const Ref<VisualShaderNode> &p_node) {
@@ -107,16 +108,174 @@ void VisualShaderEditor::remove_custom_type(const Ref<Script> &p_script) {
_update_options_menu();
}
+bool VisualShaderEditor::_is_available(int p_mode) {
+
+ int current_mode = edit_type->get_selected();
+
+ if (p_mode != -1) {
+
+ switch (current_mode) {
+ case VisualShader::TYPE_VERTEX:
+ current_mode = 1;
+ break;
+ case VisualShader::TYPE_FRAGMENT:
+ current_mode = 2;
+ break;
+ case VisualShader::TYPE_LIGHT:
+ current_mode = 4;
+ break;
+ default:
+ break;
+ }
+
+ int temp_mode = 0;
+
+ if (p_mode & VisualShader::TYPE_FRAGMENT) {
+ temp_mode |= 2;
+ }
+
+ if (p_mode & VisualShader::TYPE_LIGHT) {
+ temp_mode |= 4;
+ }
+
+ if (temp_mode == 0) {
+ temp_mode |= 1;
+ }
+
+ p_mode = temp_mode;
+ }
+
+ if (p_mode != -1 && ((p_mode & current_mode) == 0)) {
+ return false;
+ }
+ return true;
+}
+
void VisualShaderEditor::_update_options_menu() {
+ node_desc->set_text("");
+ members_dialog->get_ok()->set_disabled(true);
+
String prev_category;
- add_node->get_popup()->clear();
- for (int i = 0; i < add_options.size(); i++) {
- if (prev_category != add_options[i].category) {
- add_node->get_popup()->add_separator(add_options[i].category);
+ String prev_sub_category;
+
+ members->clear();
+ TreeItem *root = members->create_item();
+ TreeItem *category = NULL;
+ TreeItem *sub_category = NULL;
+
+ String filter = node_filter->get_text().strip_edges();
+ bool use_filter = !filter.empty();
+
+ Vector<String> categories;
+ Vector<String> sub_categories;
+
+ int item_count = 0;
+ int item_count2 = 0;
+
+ for (int i = 0; i < add_options.size() + 1; i++) {
+
+ if (i == add_options.size()) {
+ if (sub_category != NULL && item_count2 == 0) {
+ memdelete(sub_category);
+ --item_count;
+ }
+ if (category != NULL && item_count == 0) {
+ memdelete(category);
+ }
+ break;
+ }
+
+ if (!use_filter || add_options[i].name.findn(filter) != -1) {
+
+ if (prev_category != add_options[i].category) {
+ if (category != NULL && item_count == 0) {
+ memdelete(category);
+ }
+
+ item_count = 0;
+ prev_sub_category = "";
+ category = members->create_item(root);
+ category->set_text(0, add_options[i].category);
+ if (!use_filter)
+ category->set_collapsed(true);
+ }
+
+ if (add_options[i].sub_category != "") {
+ if (prev_sub_category != add_options[i].sub_category) {
+ if (category != NULL) {
+ if (sub_category != NULL && item_count2 == 0) {
+ memdelete(sub_category);
+ --item_count;
+ }
+ ++item_count;
+ item_count2 = 0;
+ sub_category = members->create_item(category);
+ sub_category->set_text(0, add_options[i].sub_category);
+ if (!use_filter)
+ sub_category->set_collapsed(true);
+ }
+ }
+ if (sub_category != NULL) {
+ if (_is_available(add_options[i].mode)) {
+ ++item_count2;
+ TreeItem *item = members->create_item(sub_category);
+ item->set_text(0, add_options[i].name);
+ switch (add_options[i].return_type) {
+ case VisualShaderNode::PORT_TYPE_SCALAR:
+ item->set_icon(0, EditorNode::get_singleton()->get_gui_base()->get_icon("float", "EditorIcons"));
+ break;
+ case VisualShaderNode::PORT_TYPE_VECTOR:
+ item->set_icon(0, EditorNode::get_singleton()->get_gui_base()->get_icon("Vector3", "EditorIcons"));
+ break;
+ case VisualShaderNode::PORT_TYPE_BOOLEAN:
+ item->set_icon(0, EditorNode::get_singleton()->get_gui_base()->get_icon("bool", "EditorIcons"));
+ break;
+ case VisualShaderNode::PORT_TYPE_TRANSFORM:
+ item->set_icon(0, EditorNode::get_singleton()->get_gui_base()->get_icon("Transform", "EditorIcons"));
+ break;
+ case VisualShaderNode::PORT_TYPE_COLOR:
+ item->set_icon(0, EditorNode::get_singleton()->get_gui_base()->get_icon("Color", "EditorIcons"));
+ break;
+ default:
+ break;
+ }
+ item->set_meta("id", i);
+ }
+ }
+ } else {
+ if (category != NULL) {
+ if (_is_available(add_options[i].mode)) {
+ ++item_count;
+ TreeItem *item = members->create_item(category);
+ item->set_text(0, add_options[i].name);
+ switch (add_options[i].return_type) {
+ case VisualShaderNode::PORT_TYPE_SCALAR:
+ item->set_icon(0, EditorNode::get_singleton()->get_gui_base()->get_icon("float", "EditorIcons"));
+ break;
+ case VisualShaderNode::PORT_TYPE_VECTOR:
+ item->set_icon(0, EditorNode::get_singleton()->get_gui_base()->get_icon("Vector3", "EditorIcons"));
+ break;
+ case VisualShaderNode::PORT_TYPE_BOOLEAN:
+ item->set_icon(0, EditorNode::get_singleton()->get_gui_base()->get_icon("bool", "EditorIcons"));
+ break;
+ case VisualShaderNode::PORT_TYPE_TRANSFORM:
+ item->set_icon(0, EditorNode::get_singleton()->get_gui_base()->get_icon("Transform", "EditorIcons"));
+ break;
+ case VisualShaderNode::PORT_TYPE_COLOR:
+ item->set_icon(0, EditorNode::get_singleton()->get_gui_base()->get_icon("Color", "EditorIcons"));
+ break;
+ default:
+ break;
+ }
+ item->set_meta("id", i);
+ }
+ }
+ }
+
+ prev_sub_category = add_options[i].sub_category;
+ prev_category = add_options[i].category;
}
- add_node->get_popup()->add_item(add_options[i].name, i);
- prev_category = add_options[i].category;
}
}
@@ -165,10 +324,11 @@ void VisualShaderEditor::_update_graph() {
}
}
- static const Color type_color[3] = {
- Color::html("#61daf4"),
- Color::html("#d67dee"),
- Color::html("#f6a86e")
+ static const Color type_color[4] = {
+ Color::html("#61daf4"), // scalar
+ Color::html("#d67dee"), // vector
+ Color::html("#8da6f0"), // boolean
+ Color::html("#f6a86e") // transform
};
List<VisualShader::Connection> connections;
@@ -344,7 +504,7 @@ void VisualShaderEditor::_update_graph() {
if (EditorSettings::get_singleton()->get("interface/theme/use_graph_node_headers")) {
Ref<StyleBoxFlat> sb = node->get_stylebox("frame", "GraphNode");
- Color c = sb->get_border_color(MARGIN_TOP);
+ Color c = sb->get_border_color();
Color mono_color = ((c.r + c.g + c.b) / 3) < 0.7 ? Color(1.0, 1.0, 1.0) : Color(0.0, 0.0, 0.0);
mono_color.a = 0.85;
c = mono_color;
@@ -462,7 +622,7 @@ void VisualShaderEditor::_edit_port_default_input(Object *p_button, int p_node,
editing_port = p_port;
}
-void VisualShaderEditor::_add_node(int p_idx) {
+void VisualShaderEditor::_add_node(int p_idx, int p_op_idx) {
ERR_FAIL_INDEX(p_idx, add_options.size());
@@ -471,6 +631,70 @@ void VisualShaderEditor::_add_node(int p_idx) {
if (add_options[p_idx].type != String()) {
VisualShaderNode *vsn = Object::cast_to<VisualShaderNode>(ClassDB::instance(add_options[p_idx].type));
ERR_FAIL_COND(!vsn);
+
+ if (p_op_idx != -1) {
+
+ VisualShaderNodeInput *input = Object::cast_to<VisualShaderNodeInput>(vsn);
+
+ if (input) {
+ input->set_input_name(add_options[p_idx].sub_func_str);
+ }
+
+ VisualShaderNodeColorOp *colorOp = Object::cast_to<VisualShaderNodeColorOp>(vsn);
+
+ if (colorOp) {
+ colorOp->set_operator((VisualShaderNodeColorOp::Operator)p_op_idx);
+ }
+
+ VisualShaderNodeColorFunc *colorFunc = Object::cast_to<VisualShaderNodeColorFunc>(vsn);
+
+ if (colorFunc) {
+ colorFunc->set_function((VisualShaderNodeColorFunc::Function)p_op_idx);
+ }
+
+ VisualShaderNodeScalarOp *scalarOp = Object::cast_to<VisualShaderNodeScalarOp>(vsn);
+
+ if (scalarOp) {
+ scalarOp->set_operator((VisualShaderNodeScalarOp::Operator)p_op_idx);
+ }
+
+ VisualShaderNodeScalarFunc *scalarFunc = Object::cast_to<VisualShaderNodeScalarFunc>(vsn);
+
+ if (scalarFunc) {
+ scalarFunc->set_function((VisualShaderNodeScalarFunc::Function)p_op_idx);
+ }
+
+ VisualShaderNodeVectorOp *vecOp = Object::cast_to<VisualShaderNodeVectorOp>(vsn);
+
+ if (vecOp) {
+ vecOp->set_operator((VisualShaderNodeVectorOp::Operator)p_op_idx);
+ }
+
+ VisualShaderNodeVectorFunc *vecFunc = Object::cast_to<VisualShaderNodeVectorFunc>(vsn);
+
+ if (vecFunc) {
+ vecFunc->set_function((VisualShaderNodeVectorFunc::Function)p_op_idx);
+ }
+
+ VisualShaderNodeTransformFunc *matFunc = Object::cast_to<VisualShaderNodeTransformFunc>(vsn);
+
+ if (matFunc) {
+ matFunc->set_function((VisualShaderNodeTransformFunc::Function)p_op_idx);
+ }
+
+ VisualShaderNodeScalarDerivativeFunc *sderFunc = Object::cast_to<VisualShaderNodeScalarDerivativeFunc>(vsn);
+
+ if (sderFunc) {
+ sderFunc->set_function((VisualShaderNodeScalarDerivativeFunc::Function)p_op_idx);
+ }
+
+ VisualShaderNodeVectorDerivativeFunc *vderFunc = Object::cast_to<VisualShaderNodeVectorDerivativeFunc>(vsn);
+
+ if (vderFunc) {
+ vderFunc->set_function((VisualShaderNodeVectorDerivativeFunc::Function)p_op_idx);
+ }
+ }
+
vsnode = Ref<VisualShaderNode>(vsn);
} else {
ERR_FAIL_COND(add_options[p_idx].script.is_null());
@@ -481,7 +705,15 @@ void VisualShaderEditor::_add_node(int p_idx) {
vsnode->set_script(add_options[p_idx].script.get_ref_ptr());
}
- Point2 position = (graph->get_scroll_ofs() + graph->get_size() * 0.5) / EDSCALE;
+ Point2 position = graph->get_scroll_ofs();
+
+ if (saved_node_pos_dirty) {
+ position += saved_node_pos;
+ } else {
+ position += graph->get_size() * 0.5;
+ position /= EDSCALE;
+ }
+ saved_node_pos_dirty = false;
VisualShader::Type type = VisualShader::Type(edit_type->get_selected());
@@ -600,29 +832,82 @@ void VisualShaderEditor::_node_selected(Object *p_node) {
//EditorNode::get_singleton()->push_item(vsnode.ptr(), "", true);
}
+void VisualShaderEditor::_member_gui_input(const Ref<InputEvent> p_event) {
+ Ref<InputEventMouseButton> mb = p_event;
+ Ref<InputEventKey> key = p_event;
+
+ if (mb.is_valid()) {
+ if (mb->is_pressed() && mb->get_button_index() == BUTTON_LEFT && mb->is_doubleclick()) {
+ _member_create();
+ }
+ } else if (key.is_valid()) {
+ if (key->is_pressed() && key->get_scancode() == KEY_ENTER) {
+ _member_create();
+ }
+ }
+}
+
void VisualShaderEditor::_input(const Ref<InputEvent> p_event) {
if (graph->has_focus()) {
Ref<InputEventMouseButton> mb = p_event;
if (mb.is_valid() && mb->is_pressed() && mb->get_button_index() == BUTTON_RIGHT) {
- add_node->get_popup()->set_position(get_viewport()->get_mouse_position());
- add_node->get_popup()->show_modal();
+ saved_node_pos_dirty = true;
+ saved_node_pos = graph->get_local_mouse_position();
+
+ Point2 gpos = Input::get_singleton()->get_mouse_position();
+ members_dialog->popup();
+ members_dialog->set_position(gpos);
}
}
}
+void VisualShaderEditor::_show_members_dialog() {
+ saved_node_pos_dirty = false;
+ members_dialog->popup();
+ members_dialog->set_position(graph->get_global_position() + Point2(5 * EDSCALE, 65 * EDSCALE));
+}
+
void VisualShaderEditor::_notification(int p_what) {
+ if (p_what == NOTIFICATION_ENTER_TREE) {
+
+ node_filter->set_clear_button_enabled(true);
+
+ // collapse tree by default
+
+ TreeItem *category = members->get_root()->get_children();
+ while (category) {
+ category->set_collapsed(true);
+ TreeItem *sub_category = category->get_children();
+ while (sub_category) {
+ sub_category->set_collapsed(true);
+ sub_category = sub_category->get_next();
+ }
+ category = category->get_next();
+ }
+ }
+
+ if (p_what == NOTIFICATION_DRAG_BEGIN) {
+ Dictionary dd = get_viewport()->gui_get_drag_data();
+ if (members->is_visible_in_tree() && dd.has("id")) {
+ members->set_drop_mode_flags(Tree::DROP_MODE_ON_ITEM);
+ }
+ } else if (p_what == NOTIFICATION_DRAG_END) {
+ members->set_drop_mode_flags(0);
+ }
if (p_what == NOTIFICATION_ENTER_TREE || p_what == NOTIFICATION_THEME_CHANGED) {
error_panel->add_style_override("panel", get_stylebox("bg", "Tree"));
error_label->add_color_override("font_color", get_color("error_color", "Editor"));
+ node_filter->set_right_icon(Control::get_icon("Search", "EditorIcons"));
+
+ tools->set_icon(EditorNode::get_singleton()->get_gui_base()->get_icon("Tools", "EditorIcons"));
+
if (p_what == NOTIFICATION_THEME_CHANGED && is_visible_in_tree())
_update_graph();
- }
-
- if (p_what == NOTIFICATION_PROCESS) {
+ } else if (p_what == NOTIFICATION_PROCESS) {
}
}
@@ -719,6 +1004,7 @@ void VisualShaderEditor::_duplicate_nodes() {
}
void VisualShaderEditor::_mode_selected(int p_id) {
+ _update_options_menu();
_update_graph();
}
@@ -756,6 +1042,128 @@ void VisualShaderEditor::_input_select_item(Ref<VisualShaderNodeInput> input, St
undo_redo->commit_action();
}
+void VisualShaderEditor::_member_filter_changed(const String &p_text) {
+ _update_options_menu();
+}
+
+void VisualShaderEditor::_member_selected() {
+ TreeItem *item = members->get_selected();
+
+ if (item != NULL && item->has_meta("id")) {
+ members_dialog->get_ok()->set_disabled(false);
+ node_desc->set_text(add_options[item->get_meta("id")].description);
+ } else {
+ members_dialog->get_ok()->set_disabled(true);
+ node_desc->set_text("");
+ }
+}
+
+void VisualShaderEditor::_member_unselected() {
+}
+
+void VisualShaderEditor::_member_create() {
+ TreeItem *item = members->get_selected();
+ if (item != NULL && item->has_meta("id")) {
+ int idx = members->get_selected()->get_meta("id");
+ _add_node(idx, add_options[idx].sub_func);
+ members_dialog->hide();
+ }
+}
+
+void VisualShaderEditor::_tools_menu_option(int p_idx) {
+
+ TreeItem *category = members->get_root()->get_children();
+
+ switch (p_idx) {
+ case EXPAND_ALL:
+
+ while (category) {
+ category->set_collapsed(false);
+ TreeItem *sub_category = category->get_children();
+ while (sub_category) {
+ sub_category->set_collapsed(false);
+ sub_category = sub_category->get_next();
+ }
+ category = category->get_next();
+ }
+
+ break;
+
+ case COLLAPSE_ALL:
+
+ while (category) {
+ category->set_collapsed(true);
+ TreeItem *sub_category = category->get_children();
+ while (sub_category) {
+ sub_category->set_collapsed(true);
+ sub_category = sub_category->get_next();
+ }
+ category = category->get_next();
+ }
+
+ break;
+ default:
+ break;
+ }
+}
+
+Variant VisualShaderEditor::get_drag_data_fw(const Point2 &p_point, Control *p_from) {
+
+ if (p_from == members) {
+ TreeItem *it = members->get_item_at_position(p_point);
+ if (!it)
+ return Variant();
+ if (!it->has_meta("id"))
+ return Variant();
+
+ int id = it->get_meta("id");
+ AddOption op = add_options[id];
+
+ Dictionary d;
+ d["id"] = id;
+ if (op.sub_func == -1) {
+ d["sub_func"] = op.sub_func_str;
+ } else {
+ d["sub_func"] = op.sub_func;
+ }
+
+ Label *label = memnew(Label);
+ label->set_text(it->get_text(0));
+ set_drag_preview(label);
+ return d;
+ }
+ return Variant();
+}
+
+bool VisualShaderEditor::can_drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) const {
+
+ if (p_from == graph) {
+
+ Dictionary d = p_data;
+
+ if (d.has("id")) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+void VisualShaderEditor::drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) {
+
+ if (p_from == graph) {
+
+ Dictionary d = p_data;
+
+ if (d.has("id")) {
+ int idx = d["id"];
+ saved_node_pos = p_point;
+ saved_node_pos_dirty = true;
+ _add_node(idx, add_options[idx].sub_func);
+ }
+ }
+}
+
void VisualShaderEditor::_bind_methods() {
ClassDB::bind_method("_update_graph", &VisualShaderEditor::_update_graph);
@@ -777,6 +1185,19 @@ void VisualShaderEditor::_bind_methods() {
ClassDB::bind_method("_input_select_item", &VisualShaderEditor::_input_select_item);
ClassDB::bind_method("_preview_select_port", &VisualShaderEditor::_preview_select_port);
ClassDB::bind_method("_input", &VisualShaderEditor::_input);
+
+ ClassDB::bind_method(D_METHOD("get_drag_data_fw"), &VisualShaderEditor::get_drag_data_fw);
+ ClassDB::bind_method(D_METHOD("can_drop_data_fw"), &VisualShaderEditor::can_drop_data_fw);
+ ClassDB::bind_method(D_METHOD("drop_data_fw"), &VisualShaderEditor::drop_data_fw);
+
+ ClassDB::bind_method("_is_available", &VisualShaderEditor::_is_available);
+ ClassDB::bind_method("_tools_menu_option", &VisualShaderEditor::_tools_menu_option);
+ ClassDB::bind_method("_show_members_dialog", &VisualShaderEditor::_show_members_dialog);
+ ClassDB::bind_method("_member_gui_input", &VisualShaderEditor::_member_gui_input);
+ ClassDB::bind_method("_member_filter_changed", &VisualShaderEditor::_member_filter_changed);
+ ClassDB::bind_method("_member_selected", &VisualShaderEditor::_member_selected);
+ ClassDB::bind_method("_member_unselected", &VisualShaderEditor::_member_unselected);
+ ClassDB::bind_method("_member_create", &VisualShaderEditor::_member_create);
}
VisualShaderEditor *VisualShaderEditor::singleton = NULL;
@@ -785,10 +1206,14 @@ VisualShaderEditor::VisualShaderEditor() {
singleton = this;
updating = false;
+ saved_node_pos_dirty = false;
+ saved_node_pos = Point2(0, 0);
graph = memnew(GraphEdit);
add_child(graph);
+ graph->set_drag_forwarding(this);
graph->add_valid_right_disconnect_type(VisualShaderNode::PORT_TYPE_SCALAR);
+ graph->add_valid_right_disconnect_type(VisualShaderNode::PORT_TYPE_BOOLEAN);
graph->add_valid_right_disconnect_type(VisualShaderNode::PORT_TYPE_VECTOR);
graph->add_valid_right_disconnect_type(VisualShaderNode::PORT_TYPE_TRANSFORM);
//graph->add_valid_left_disconnect_type(0);
@@ -800,8 +1225,13 @@ VisualShaderEditor::VisualShaderEditor() {
graph->connect("duplicate_nodes_request", this, "_duplicate_nodes");
graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_SCALAR, VisualShaderNode::PORT_TYPE_SCALAR);
graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_SCALAR, VisualShaderNode::PORT_TYPE_VECTOR);
+ graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_SCALAR, VisualShaderNode::PORT_TYPE_BOOLEAN);
graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_VECTOR, VisualShaderNode::PORT_TYPE_SCALAR);
graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_VECTOR, VisualShaderNode::PORT_TYPE_VECTOR);
+ graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_VECTOR, VisualShaderNode::PORT_TYPE_BOOLEAN);
+ graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_BOOLEAN, VisualShaderNode::PORT_TYPE_SCALAR);
+ graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_BOOLEAN, VisualShaderNode::PORT_TYPE_VECTOR);
+ graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_BOOLEAN, VisualShaderNode::PORT_TYPE_BOOLEAN);
graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_TRANSFORM, VisualShaderNode::PORT_TYPE_TRANSFORM);
VSeparator *vs = memnew(VSeparator);
@@ -817,40 +1247,315 @@ VisualShaderEditor::VisualShaderEditor() {
graph->get_zoom_hbox()->add_child(edit_type);
graph->get_zoom_hbox()->move_child(edit_type, 0);
- add_node = memnew(MenuButton);
+ add_node = memnew(ToolButton);
graph->get_zoom_hbox()->add_child(add_node);
add_node->set_text(TTR("Add Node..."));
graph->get_zoom_hbox()->move_child(add_node, 0);
- add_node->get_popup()->connect("id_pressed", this, "_add_node");
-
- add_options.push_back(AddOption("Scalar", "Constants", "VisualShaderNodeScalarConstant"));
- add_options.push_back(AddOption("Vector", "Constants", "VisualShaderNodeVec3Constant"));
- add_options.push_back(AddOption("Color", "Constants", "VisualShaderNodeColorConstant"));
- add_options.push_back(AddOption("Transform", "Constants", "VisualShaderNodeTransformConstant"));
- add_options.push_back(AddOption("Texture", "Constants", "VisualShaderNodeTexture"));
- add_options.push_back(AddOption("CubeMap", "Constants", "VisualShaderNodeCubeMap"));
- add_options.push_back(AddOption("ScalarOp", "Operators", "VisualShaderNodeScalarOp"));
- add_options.push_back(AddOption("VectorOp", "Operators", "VisualShaderNodeVectorOp"));
- add_options.push_back(AddOption("ColorOp", "Operators", "VisualShaderNodeColorOp"));
- add_options.push_back(AddOption("TransformMult", "Operators", "VisualShaderNodeTransformMult"));
- add_options.push_back(AddOption("TransformVectorMult", "Operators", "VisualShaderNodeTransformVecMult"));
- add_options.push_back(AddOption("ScalarFunc", "Functions", "VisualShaderNodeScalarFunc"));
- add_options.push_back(AddOption("VectorFunc", "Functions", "VisualShaderNodeVectorFunc"));
- add_options.push_back(AddOption("DotProduct", "Functions", "VisualShaderNodeDotProduct"));
- add_options.push_back(AddOption("VectorLen", "Functions", "VisualShaderNodeVectorLen"));
- add_options.push_back(AddOption("ScalarInterp", "Interpolation", "VisualShaderNodeScalarInterp"));
- add_options.push_back(AddOption("VectorInterp", "Interpolation", "VisualShaderNodeVectorInterp"));
- add_options.push_back(AddOption("VectorCompose", "Compose", "VisualShaderNodeVectorCompose"));
- add_options.push_back(AddOption("TransformCompose", "Compose", "VisualShaderNodeTransformCompose"));
- add_options.push_back(AddOption("VectorDecompose", "Decompose", "VisualShaderNodeVectorDecompose"));
- add_options.push_back(AddOption("TransformDecompose", "Decompose", "VisualShaderNodeTransformDecompose"));
- add_options.push_back(AddOption("Scalar", "Uniforms", "VisualShaderNodeScalarUniform"));
- add_options.push_back(AddOption("Vector", "Uniforms", "VisualShaderNodeVec3Uniform"));
- add_options.push_back(AddOption("Color", "Uniforms", "VisualShaderNodeColorUniform"));
- add_options.push_back(AddOption("Transform", "Uniforms", "VisualShaderNodeTransformUniform"));
- add_options.push_back(AddOption("Texture", "Uniforms", "VisualShaderNodeTextureUniform"));
- add_options.push_back(AddOption("CubeMap", "Uniforms", "VisualShaderNodeCubeMapUniform"));
- add_options.push_back(AddOption("Input", "Inputs", "VisualShaderNodeInput"));
+ add_node->connect("pressed", this, "_show_members_dialog");
+
+ ///////////////////////////////////////
+ // SHADER NODES TREE
+ ///////////////////////////////////////
+
+ VBoxContainer *members_vb = memnew(VBoxContainer);
+ members_vb->set_v_size_flags(SIZE_EXPAND_FILL);
+
+ HBoxContainer *filter_hb = memnew(HBoxContainer);
+ members_vb->add_child(filter_hb);
+
+ node_filter = memnew(LineEdit);
+ filter_hb->add_child(node_filter);
+ node_filter->connect("text_changed", this, "_member_filter_changed");
+ node_filter->set_h_size_flags(SIZE_EXPAND_FILL);
+ node_filter->set_placeholder(TTR("Search"));
+
+ tools = memnew(MenuButton);
+ filter_hb->add_child(tools);
+ tools->set_tooltip(TTR("Options"));
+ tools->get_popup()->connect("id_pressed", this, "_tools_menu_option");
+ tools->get_popup()->add_item(TTR("Expand All"), EXPAND_ALL);
+ tools->get_popup()->add_item(TTR("Collapse All"), COLLAPSE_ALL);
+
+ members = memnew(Tree);
+ members_vb->add_child(members);
+ members->set_drag_forwarding(this);
+ members->set_h_size_flags(SIZE_EXPAND_FILL);
+ members->set_v_size_flags(SIZE_EXPAND_FILL);
+ members->set_hide_root(true);
+ members->set_allow_reselect(true);
+ members->set_hide_folding(false);
+ members->set_custom_minimum_size(Size2(180 * EDSCALE, 200 * EDSCALE));
+ members->connect("item_selected", this, "_member_selected");
+ members->connect("nothing_selected", this, "_member_unselected");
+ members->connect("gui_input", this, "_member_gui_input");
+
+ Label *desc_label = memnew(Label);
+ members_vb->add_child(desc_label);
+ desc_label->set_text(TTR("Description:"));
+
+ node_desc = memnew(RichTextLabel);
+ members_vb->add_child(node_desc);
+ node_desc->set_h_size_flags(SIZE_EXPAND_FILL);
+ node_desc->set_v_size_flags(SIZE_FILL);
+ node_desc->set_custom_minimum_size(Size2(0, 70 * EDSCALE));
+
+ members_dialog = memnew(ConfirmationDialog);
+ members_dialog->set_title(TTR("Create Shader Node"));
+ members_dialog->add_child(members_vb);
+ members_dialog->get_ok()->set_text(TTR("Create"));
+ members_dialog->get_ok()->connect("pressed", this, "_member_create");
+ members_dialog->get_ok()->set_disabled(true);
+ members_dialog->set_resizable(true);
+ members_dialog->set_as_minsize();
+ add_child(members_dialog);
+
+ alert = memnew(AcceptDialog);
+ alert->set_as_minsize();
+ alert->get_label()->set_autowrap(true);
+ alert->get_label()->set_align(Label::ALIGN_CENTER);
+ alert->get_label()->set_valign(Label::VALIGN_CENTER);
+ alert->get_label()->set_custom_minimum_size(Size2(400, 60) * EDSCALE);
+ add_child(alert);
+
+ ///////////////////////////////////////
+ // SHADER NODES TREE OPTIONS
+ ///////////////////////////////////////
+
+ // COLOR
+
+ add_options.push_back(AddOption("ColorFunc", "Color", "Common", "VisualShaderNodeColorFunc", TTR("Color function."), -1, VisualShaderNode::PORT_TYPE_VECTOR));
+ add_options.push_back(AddOption("ColorOp", "Color", "Common", "VisualShaderNodeColorOp", TTR("Color operator."), -1, VisualShaderNode::PORT_TYPE_VECTOR));
+
+ add_options.push_back(AddOption("Grayscale", "Color", "Functions", "VisualShaderNodeColorFunc", TTR("Grayscale function."), VisualShaderNodeColorFunc::FUNC_GRAYSCALE, VisualShaderNode::PORT_TYPE_VECTOR));
+ add_options.push_back(AddOption("HSV2RGB", "Color", "Functions", "VisualShaderNodeVectorFunc", TTR("Converts HSV vector to RGB equivalent."), VisualShaderNodeVectorFunc::FUNC_HSV2RGB, VisualShaderNode::PORT_TYPE_VECTOR));
+ add_options.push_back(AddOption("RGB2HSV", "Color", "Functions", "VisualShaderNodeVectorFunc", TTR("Converts RGB vector to HSV equivalent."), VisualShaderNodeVectorFunc::FUNC_RGB2HSV, VisualShaderNode::PORT_TYPE_VECTOR));
+ add_options.push_back(AddOption("Sepia", "Color", "Functions", "VisualShaderNodeColorFunc", TTR("Sepia function."), VisualShaderNodeColorFunc::FUNC_SEPIA, VisualShaderNode::PORT_TYPE_VECTOR));
+
+ add_options.push_back(AddOption("Burn", "Color", "Operators", "VisualShaderNodeColorOp", TTR("Burn operator."), VisualShaderNodeColorOp::OP_BURN, VisualShaderNode::PORT_TYPE_VECTOR));
+ add_options.push_back(AddOption("Darken", "Color", "Operators", "VisualShaderNodeColorOp", TTR("Darken operator."), VisualShaderNodeColorOp::OP_DARKEN, VisualShaderNode::PORT_TYPE_VECTOR));
+ add_options.push_back(AddOption("Difference", "Color", "Operators", "VisualShaderNodeColorOp", TTR("Difference operator."), VisualShaderNodeColorOp::OP_DIFFERENCE, VisualShaderNode::PORT_TYPE_VECTOR));
+ add_options.push_back(AddOption("Dodge", "Color", "Operators", "VisualShaderNodeColorOp", TTR("Dodge operator."), VisualShaderNodeColorOp::OP_DODGE, VisualShaderNode::PORT_TYPE_VECTOR));
+ add_options.push_back(AddOption("HardLight", "Color", "Operators", "VisualShaderNodeColorOp", TTR("HardLight operator"), VisualShaderNodeColorOp::OP_HARD_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR));
+ add_options.push_back(AddOption("Lighten", "Color", "Operators", "VisualShaderNodeColorOp", TTR("Lighten operator."), VisualShaderNodeColorOp::OP_LIGHTEN, VisualShaderNode::PORT_TYPE_VECTOR));
+ add_options.push_back(AddOption("Overlay", "Color", "Operators", "VisualShaderNodeColorOp", TTR("Overlay operator."), VisualShaderNodeColorOp::OP_OVERLAY, VisualShaderNode::PORT_TYPE_VECTOR));
+ add_options.push_back(AddOption("Screen", "Color", "Operators", "VisualShaderNodeColorOp", TTR("Screen operator."), VisualShaderNodeColorOp::OP_SCREEN, VisualShaderNode::PORT_TYPE_VECTOR));
+ add_options.push_back(AddOption("SoftLight", "Color", "Operators", "VisualShaderNodeColorOp", TTR("SoftLight operator."), VisualShaderNodeColorOp::OP_SOFT_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR));
+
+ add_options.push_back(AddOption("ColorConstant", "Color", "Variables", "VisualShaderNodeColorConstant", TTR("Color constant."), -1, VisualShaderNode::PORT_TYPE_COLOR));
+ add_options.push_back(AddOption("ColorUniform", "Color", "Variables", "VisualShaderNodeColorUniform", TTR("Color uniform."), -1, VisualShaderNode::PORT_TYPE_COLOR));
+
+ // BOOLEAN
+
+ add_options.push_back(AddOption("BooleanConstant", "Boolean", "Variables", "VisualShaderNodeBooleanConstant", TTR("Boolean constant."), -1, VisualShaderNode::PORT_TYPE_BOOLEAN));
+ add_options.push_back(AddOption("BooleanUniform", "Boolean", "Variables", "VisualShaderNodeBooleanUniform", TTR("Boolean uniform."), -1, VisualShaderNode::PORT_TYPE_BOOLEAN));
+
+ // INPUT
+
+ add_options.push_back(AddOption("Camera", "Input", "All", "VisualShaderNodeInput", TTR("'camera' input parameter for all shader modes."), "camera", VisualShaderNode::PORT_TYPE_TRANSFORM));
+ add_options.push_back(AddOption("InvCamera", "Input", "All", "VisualShaderNodeInput", TTR("'inv_camera' input parameter for all shader modes."), "inv_camera", VisualShaderNode::PORT_TYPE_TRANSFORM));
+ add_options.push_back(AddOption("InvProjection", "Input", "All", "VisualShaderNodeInput", TTR("'inv_projection' input parameter for all shader modes."), "inv_projection", VisualShaderNode::PORT_TYPE_TRANSFORM));
+ add_options.push_back(AddOption("Normal", "Input", "All", "VisualShaderNodeInput", TTR("'normal' input parameter for all shader modes."), "normal", VisualShaderNode::PORT_TYPE_VECTOR));
+ add_options.push_back(AddOption("Projection", "Input", "All", "VisualShaderNodeInput", TTR("'projection' input parameter for all shader modes."), "projection", VisualShaderNode::PORT_TYPE_TRANSFORM));
+ add_options.push_back(AddOption("Time", "Input", "All", "VisualShaderNodeInput", TTR("'time' input parameter for all shader modes."), "time", VisualShaderNode::PORT_TYPE_SCALAR));
+ add_options.push_back(AddOption("ViewportSize", "Input", "All", "VisualShaderNodeInput", TTR("'viewport_size' input parameter for all shader modes."), "viewport_size", VisualShaderNode::PORT_TYPE_VECTOR));
+ add_options.push_back(AddOption("World", "Input", "All", "VisualShaderNodeInput", TTR("'world' input parameter for all shader modes."), "world", VisualShaderNode::PORT_TYPE_TRANSFORM));
+
+ add_options.push_back(AddOption("Input", "Input", "Common", "VisualShaderNodeInput", TTR("Input parameter.")));
+
+ add_options.push_back(AddOption("Alpha", "Input", "Fragment", "VisualShaderNodeInput", TTR("'alpha' input parameter for fragment shader mode."), "alpha", VisualShaderNode::PORT_TYPE_SCALAR, VisualShader::TYPE_FRAGMENT));
+ add_options.push_back(AddOption("Binormal", "Input", "Fragment", "VisualShaderNodeInput", TTR("'binormal' input parameter for fragment shader mode."), "binormal", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_FRAGMENT));
+ add_options.push_back(AddOption("Color", "Input", "Fragment", "VisualShaderNodeInput", TTR("'color' input parameter for fragment shader mode."), "color", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_FRAGMENT));
+ add_options.push_back(AddOption("FragCoord", "Input", "Fragment", "VisualShaderNodeInput", TTR("'fragcoord' input parameter for fragment shader mode."), "fragcoord", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_FRAGMENT));
+ add_options.push_back(AddOption("PointCoord", "Input", "Fragment", "VisualShaderNodeInput", TTR("'point_coord' input parameter for fragment shader mode."), "point_coord", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_FRAGMENT));
+ add_options.push_back(AddOption("ScreenUV", "Input", "Fragment", "VisualShaderNodeInput", TTR("'screen_uv' input parameter for fragment shader mode."), "screen_uv", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_FRAGMENT));
+ add_options.push_back(AddOption("Side", "Input", "Fragment", "VisualShaderNodeInput", TTR("'side' input parameter for fragment shader mode."), "side", VisualShaderNode::PORT_TYPE_SCALAR, VisualShader::TYPE_FRAGMENT));
+ add_options.push_back(AddOption("Tangent", "Input", "Fragment", "VisualShaderNodeInput", TTR("'tangent' input parameter for fragment shader mode."), "tangent", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_FRAGMENT));
+ add_options.push_back(AddOption("UV", "Input", "Fragment", "VisualShaderNodeInput", TTR("'uv' input parameter for fragment shader mode."), "uv", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_FRAGMENT));
+ add_options.push_back(AddOption("UV2", "Input", "Fragment", "VisualShaderNodeInput", TTR("'uv2' input parameter for fragment shader mode."), "uv2", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_FRAGMENT));
+ add_options.push_back(AddOption("Vertex", "Input", "Fragment", "VisualShaderNodeInput", TTR("'vertex' input parameter for fragment shader mode."), "vertex", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_FRAGMENT));
+ add_options.push_back(AddOption("View", "Input", "Fragment", "VisualShaderNodeInput", TTR("'view' input parameter for fragment shader mode."), "view", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_FRAGMENT));
+
+ add_options.push_back(AddOption("Albedo", "Input", "Light", "VisualShaderNodeInput", TTR("'albedo' input parameter for light shader mode."), "albedo", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_LIGHT));
+ add_options.push_back(AddOption("Attenuation", "Input", "Light", "VisualShaderNodeInput", TTR("'attenuation' input parameter for light shader mode."), "attenuation", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_LIGHT));
+ add_options.push_back(AddOption("Diffuse", "Input", "Light", "VisualShaderNodeInput", TTR("'diffuse' input parameter for light shader mode."), "diffuse", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_LIGHT));
+ add_options.push_back(AddOption("FragCoord", "Input", "Light", "VisualShaderNodeInput", TTR("'fragcoord' input parameter for light shader mode."), "fragcoord", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_LIGHT));
+ add_options.push_back(AddOption("Light", "Input", "Light", "VisualShaderNodeInput", TTR("'light' input parameter for light shader mode."), "light", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_LIGHT));
+ add_options.push_back(AddOption("LightColor", "Input", "Light", "VisualShaderNodeInput", TTR("'light_color' input parameter for light shader mode."), "light_color", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_LIGHT));
+ add_options.push_back(AddOption("Roughness", "Input", "Light", "VisualShaderNodeInput", TTR("'roughness' input parameter for light shader mode."), "roughness", VisualShaderNode::PORT_TYPE_SCALAR, VisualShader::TYPE_LIGHT));
+ add_options.push_back(AddOption("Specular", "Input", "Light", "VisualShaderNodeInput", TTR("'specular' input parameter for light shader mode."), "specular", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_LIGHT));
+ add_options.push_back(AddOption("Transmission", "Input", "Light", "VisualShaderNodeInput", TTR("'transmission' input parameter for light shader mode."), "transmission", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_LIGHT));
+ add_options.push_back(AddOption("View", "Input", "Light", "VisualShaderNodeInput", TTR("'view' input parameter for light shader mode."), "view", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_LIGHT));
+
+ add_options.push_back(AddOption("Alpha", "Input", "Vertex", "VisualShaderNodeInput", TTR("'alpha' input parameter for vertex shader mode."), "alpha", VisualShaderNode::PORT_TYPE_SCALAR, VisualShader::TYPE_VERTEX));
+ add_options.push_back(AddOption("Binormal", "Input", "Vertex", "VisualShaderNodeInput", TTR("'binormal' input parameter for vertex shader mode."), "binormal", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_VERTEX));
+ add_options.push_back(AddOption("Color", "Input", "Vertex", "VisualShaderNodeInput", TTR("'color' input parameter for vertex shader mode."), "color", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_VERTEX));
+ add_options.push_back(AddOption("ModelView", "Input", "Vertex", "VisualShaderNodeInput", TTR("'modelview' input parameter for vertex shader mode."), "modelview", VisualShaderNode::PORT_TYPE_TRANSFORM, VisualShader::TYPE_VERTEX));
+ add_options.push_back(AddOption("PointSize", "Input", "Vertex", "VisualShaderNodeInput", TTR("'point_size' input parameter for vertex shader mode."), "point_size", VisualShaderNode::PORT_TYPE_SCALAR, VisualShader::TYPE_VERTEX));
+ add_options.push_back(AddOption("Tangent", "Input", "Vertex", "VisualShaderNodeInput", TTR("'tangent' input parameter for vertex shader mode."), "tangent", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_VERTEX));
+ add_options.push_back(AddOption("UV", "Input", "Vertex", "VisualShaderNodeInput", TTR("'uv' input parameter for vertex shader mode."), "uv", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_VERTEX));
+ add_options.push_back(AddOption("UV2", "Input", "Vertex", "VisualShaderNodeInput", TTR("'uv2' input parameter for vertex shader mode."), "uv2", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_VERTEX));
+ add_options.push_back(AddOption("Vertex", "Input", "Vertex", "VisualShaderNodeInput", TTR("'vertex' input parameter for vertex shader mode."), "vertex", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_VERTEX));
+
+ // SCALAR
+
+ add_options.push_back(AddOption("ScalarFunc", "Scalar", "Common", "VisualShaderNodeScalarFunc", TTR("Scalar function."), -1, VisualShaderNode::PORT_TYPE_SCALAR));
+ add_options.push_back(AddOption("ScalarOp", "Scalar", "Common", "VisualShaderNodeScalarOp", TTR("Scalar operator."), -1, VisualShaderNode::PORT_TYPE_SCALAR));
+
+ add_options.push_back(AddOption("Abs", "Scalar", "Functions", "VisualShaderNodeScalarFunc", TTR("Returns the absolute value of the parameter."), VisualShaderNodeScalarFunc::FUNC_ABS, VisualShaderNode::PORT_TYPE_SCALAR));
+ add_options.push_back(AddOption("ACos", "Scalar", "Functions", "VisualShaderNodeScalarFunc", TTR("Returns the arc-cosine of the parameter."), VisualShaderNodeScalarFunc::FUNC_ACOS, VisualShaderNode::PORT_TYPE_SCALAR));
+ add_options.push_back(AddOption("ACosH", "Scalar", "Functions", "VisualShaderNodeScalarFunc", TTR("(GLES3 only) Returns the inverse hyperbolic cosine of the parameter."), VisualShaderNodeScalarFunc::FUNC_ACOSH, VisualShaderNode::PORT_TYPE_SCALAR));
+ add_options.push_back(AddOption("ASin", "Scalar", "Functions", "VisualShaderNodeScalarFunc", TTR("Returns the arc-sine of the parameter."), VisualShaderNodeScalarFunc::FUNC_ASIN, VisualShaderNode::PORT_TYPE_SCALAR));
+ add_options.push_back(AddOption("ASinH", "Scalar", "Functions", "VisualShaderNodeScalarFunc", TTR("(GLES3 only) Returns the inverse hyperbolic sine of the parameter."), VisualShaderNodeScalarFunc::FUNC_ASINH, VisualShaderNode::PORT_TYPE_SCALAR));
+ add_options.push_back(AddOption("ATan", "Scalar", "Functions", "VisualShaderNodeScalarFunc", TTR("Returns the arc-tangent of the parameter."), VisualShaderNodeScalarFunc::FUNC_ATAN, VisualShaderNode::PORT_TYPE_SCALAR));
+ add_options.push_back(AddOption("ATan2", "Scalar", "Functions", "VisualShaderNodeScalarOp", TTR("Returns the arc-tangent of the parameters."), VisualShaderNodeScalarOp::OP_ATAN2, VisualShaderNode::PORT_TYPE_SCALAR));
+ add_options.push_back(AddOption("ATanH", "Scalar", "Functions", "VisualShaderNodeScalarFunc", TTR("(GLES3 only) Returns the inverse hyperbolic tangent of the parameter."), VisualShaderNodeScalarFunc::FUNC_ATANH, VisualShaderNode::PORT_TYPE_SCALAR));
+ add_options.push_back(AddOption("Ceil", "Scalar", "Functions", "VisualShaderNodeScalarFunc", TTR("Finds the nearest integer that is greater than or equal to the parameter."), VisualShaderNodeScalarFunc::FUNC_CEIL, VisualShaderNode::PORT_TYPE_SCALAR));
+ add_options.push_back(AddOption("Clamp", "Scalar", "Functions", "VisualShaderNodeScalarClamp", TTR("Constrains a value to lie between two further values."), -1, VisualShaderNode::PORT_TYPE_SCALAR));
+ add_options.push_back(AddOption("Cos", "Scalar", "Functions", "VisualShaderNodeScalarFunc", TTR("Returns the cosine of the parameter."), VisualShaderNodeScalarFunc::FUNC_COS, VisualShaderNode::PORT_TYPE_SCALAR));
+ add_options.push_back(AddOption("CosH", "Scalar", "Functions", "VisualShaderNodeScalarFunc", TTR("(GLES3 only) Returns the hyperbolic cosine of the parameter."), VisualShaderNodeScalarFunc::FUNC_COSH, VisualShaderNode::PORT_TYPE_SCALAR));
+ add_options.push_back(AddOption("Degrees", "Scalar", "Functions", "VisualShaderNodeScalarFunc", TTR("Converts a quantity in radians to degrees."), VisualShaderNodeScalarFunc::FUNC_DEGREES, VisualShaderNode::PORT_TYPE_SCALAR));
+ add_options.push_back(AddOption("Exp", "Scalar", "Functions", "VisualShaderNodeScalarFunc", TTR("Base-e Exponential."), VisualShaderNodeScalarFunc::FUNC_EXP, VisualShaderNode::PORT_TYPE_SCALAR));
+ add_options.push_back(AddOption("Exp2", "Scalar", "Functions", "VisualShaderNodeScalarFunc", TTR("Base-2 Exponential."), VisualShaderNodeScalarFunc::FUNC_EXP2, VisualShaderNode::PORT_TYPE_SCALAR));
+ add_options.push_back(AddOption("Floor", "Scalar", "Functions", "VisualShaderNodeScalarFunc", TTR("Finds the nearest integer less than or equal to the parameter."), VisualShaderNodeScalarFunc::FUNC_FLOOR, VisualShaderNode::PORT_TYPE_SCALAR));
+ add_options.push_back(AddOption("Fract", "Scalar", "Functions", "VisualShaderNodeScalarFunc", TTR("Computes the fractional part of the argument."), VisualShaderNodeScalarFunc::FUNC_FRAC, VisualShaderNode::PORT_TYPE_SCALAR));
+ add_options.push_back(AddOption("InverseSqrt", "Scalar", "Functions", "VisualShaderNodeScalarFunc", TTR("Returns the inverse of the square root of the parameter."), VisualShaderNodeScalarFunc::FUNC_INVERSE_SQRT, VisualShaderNode::PORT_TYPE_SCALAR));
+ add_options.push_back(AddOption("Log", "Scalar", "Functions", "VisualShaderNodeScalarFunc", TTR("Natural logarithm."), VisualShaderNodeScalarFunc::FUNC_LOG, VisualShaderNode::PORT_TYPE_SCALAR));
+ add_options.push_back(AddOption("Log2", "Scalar", "Functions", "VisualShaderNodeScalarFunc", TTR("Base-2 logarithm."), VisualShaderNodeScalarFunc::FUNC_LOG2, VisualShaderNode::PORT_TYPE_SCALAR));
+ add_options.push_back(AddOption("Max", "Scalar", "Functions", "VisualShaderNodeScalarOp", TTR("Returns the greater of two values."), VisualShaderNodeScalarOp::OP_MAX, VisualShaderNode::PORT_TYPE_SCALAR));
+ add_options.push_back(AddOption("Min", "Scalar", "Functions", "VisualShaderNodeScalarOp", TTR("Returns the lesser of two values."), VisualShaderNodeScalarOp::OP_MIN, VisualShaderNode::PORT_TYPE_SCALAR));
+ add_options.push_back(AddOption("Mix", "Scalar", "Functions", "VisualShaderNodeScalarInterp", TTR("Linear interpolation between two scalars."), -1, VisualShaderNode::PORT_TYPE_SCALAR));
+ add_options.push_back(AddOption("Negate", "Scalar", "Functions", "VisualShaderNodeScalarFunc", TTR("Returns the opposite value of the parameter."), VisualShaderNodeScalarFunc::FUNC_NEGATE, VisualShaderNode::PORT_TYPE_SCALAR));
+ add_options.push_back(AddOption("Pow", "Scalar", "Functions", "VisualShaderNodeScalarOp", TTR("Returns the value of the first parameter raised to the power of the second."), VisualShaderNodeScalarOp::OP_POW, VisualShaderNode::PORT_TYPE_SCALAR));
+ add_options.push_back(AddOption("Radians", "Scalar", "Functions", "VisualShaderNodeScalarFunc", TTR("Converts a quantity in degrees to radians."), VisualShaderNodeScalarFunc::FUNC_RADIANS, VisualShaderNode::PORT_TYPE_SCALAR));
+ add_options.push_back(AddOption("Reciprocal", "Scalar", "Functions", "VisualShaderNodeScalarFunc", TTR("1.0 / scalar"), VisualShaderNodeScalarFunc::FUNC_RECIPROCAL, VisualShaderNode::PORT_TYPE_SCALAR));
+ add_options.push_back(AddOption("Round", "Scalar", "Functions", "VisualShaderNodeScalarFunc", TTR("(GLES3 only) Finds the nearest integer to the parameter."), VisualShaderNodeScalarFunc::FUNC_ROUND, VisualShaderNode::PORT_TYPE_SCALAR));
+ add_options.push_back(AddOption("RoundEven", "Scalar", "Functions", "VisualShaderNodeScalarFunc", TTR("(GLES3 only) Finds the nearest even integer to the parameter."), VisualShaderNodeScalarFunc::FUNC_ROUNDEVEN, VisualShaderNode::PORT_TYPE_SCALAR));
+ add_options.push_back(AddOption("Saturate", "Scalar", "Functions", "VisualShaderNodeScalarFunc", TTR("Clamps the value between 0.0 and 1.0."), VisualShaderNodeScalarFunc::FUNC_SATURATE, VisualShaderNode::PORT_TYPE_SCALAR));
+ add_options.push_back(AddOption("Sign", "Scalar", "Functions", "VisualShaderNodeScalarFunc", TTR("Extracts the sign of the parameter."), VisualShaderNodeScalarFunc::FUNC_SIGN, VisualShaderNode::PORT_TYPE_SCALAR));
+ add_options.push_back(AddOption("Sin", "Scalar", "Functions", "VisualShaderNodeScalarFunc", TTR("Returns the sine of the parameter."), VisualShaderNodeScalarFunc::FUNC_SIN, VisualShaderNode::PORT_TYPE_SCALAR));
+ add_options.push_back(AddOption("SinH", "Scalar", "Functions", "VisualShaderNodeScalarFunc", TTR("(GLES3 only) Returns the hyperbolic sine of the parameter."), VisualShaderNodeScalarFunc::FUNC_SINH, VisualShaderNode::PORT_TYPE_SCALAR));
+ add_options.push_back(AddOption("Sqrt", "Scalar", "Functions", "VisualShaderNodeScalarFunc", TTR("Returns the square root of the parameter."), VisualShaderNodeScalarFunc::FUNC_SQRT, VisualShaderNode::PORT_TYPE_SCALAR));
+ add_options.push_back(AddOption("SmoothStep", "Scalar", "Functions", "VisualShaderNodeScalarSmoothStep", TTR("SmoothStep function( scalar(edge0), scalar(edge1), scalar(x) ).\n\nReturns 0.0 if 'x' is smaller then 'edge0' and 1.0 if x is larger than 'edge1'. Otherwise the return value is interpolated between 0.0 and 1.0 using Hermite polynomials."), -1, VisualShaderNode::PORT_TYPE_SCALAR));
+ add_options.push_back(AddOption("Step", "Scalar", "Functions", "VisualShaderNodeScalarOp", TTR("Step function( scalar(edge), scalar(x) ).\n\nReturns 0.0 if 'x' is smaller then 'edge' and otherwise 1.0."), VisualShaderNodeScalarOp::OP_STEP, VisualShaderNode::PORT_TYPE_SCALAR));
+ add_options.push_back(AddOption("Tan", "Scalar", "Functions", "VisualShaderNodeScalarFunc", TTR("Returns the tangent of the parameter."), VisualShaderNodeScalarFunc::FUNC_TAN, VisualShaderNode::PORT_TYPE_SCALAR));
+ add_options.push_back(AddOption("TanH", "Scalar", "Functions", "VisualShaderNodeScalarFunc", TTR("(GLES3 only) Returns the hyperbolic tangent of the parameter."), VisualShaderNodeScalarFunc::FUNC_TANH, VisualShaderNode::PORT_TYPE_SCALAR));
+ add_options.push_back(AddOption("Trunc", "Scalar", "Functions", "VisualShaderNodeScalarFunc", TTR("(GLES3 only) Finds the truncated value of the parameter."), VisualShaderNodeScalarFunc::FUNC_TRUNC, VisualShaderNode::PORT_TYPE_SCALAR));
+
+ add_options.push_back(AddOption("Add", "Scalar", "Operators", "VisualShaderNodeScalarOp", TTR("Adds scalar to scalar."), VisualShaderNodeScalarOp::OP_ADD, VisualShaderNode::PORT_TYPE_SCALAR));
+ add_options.push_back(AddOption("Divide", "Scalar", "Operators", "VisualShaderNodeScalarOp", TTR("Divides scalar by scalar."), VisualShaderNodeScalarOp::OP_DIV, VisualShaderNode::PORT_TYPE_SCALAR));
+ add_options.push_back(AddOption("Multiply", "Scalar", "Operators", "VisualShaderNodeScalarOp", TTR("Multiplies scalar by scalar."), VisualShaderNodeScalarOp::OP_MUL, VisualShaderNode::PORT_TYPE_SCALAR));
+ add_options.push_back(AddOption("Remainder", "Scalar", "Operators", "VisualShaderNodeScalarOp", TTR("Returns the remainder of the two scalars."), VisualShaderNodeScalarOp::OP_MOD, VisualShaderNode::PORT_TYPE_SCALAR));
+ add_options.push_back(AddOption("Subtract", "Scalar", "Operators", "VisualShaderNodeScalarOp", TTR("Subtracts scalar from scalar."), VisualShaderNodeScalarOp::OP_SUB, VisualShaderNode::PORT_TYPE_SCALAR));
+
+ add_options.push_back(AddOption("ScalarConstant", "Scalar", "Variables", "VisualShaderNodeScalarConstant", TTR("Scalar constant."), -1, VisualShaderNode::PORT_TYPE_SCALAR));
+ add_options.push_back(AddOption("ScalarUniform", "Scalar", "Variables", "VisualShaderNodeScalarUniform", TTR("Scalar uniform."), -1, VisualShaderNode::PORT_TYPE_SCALAR));
+
+ // TEXTURES
+
+ add_options.push_back(AddOption("CubeMap", "Textures", "Functions", "VisualShaderNodeCubeMap", TTR("Perform the cubic texture lookup."), -1, VisualShaderNode::PORT_TYPE_COLOR));
+ add_options.push_back(AddOption("Texture", "Textures", "Functions", "VisualShaderNodeTexture", TTR("Perform the texture lookup."), -1, VisualShaderNode::PORT_TYPE_COLOR));
+
+ add_options.push_back(AddOption("CubeMapUniform", "Textures", "Variables", "VisualShaderNodeCubeMapUniform", TTR("Cubic texture uniform."), -1, VisualShaderNode::PORT_TYPE_COLOR));
+ add_options.push_back(AddOption("TextureUniform", "Textures", "Variables", "VisualShaderNodeTextureUniform", TTR("2D texture uniform."), -1, VisualShaderNode::PORT_TYPE_COLOR));
+
+ // TRANSFORM
+
+ add_options.push_back(AddOption("TransformFunc", "Transform", "Common", "VisualShaderNodeTransformFunc", TTR("Transform function."), -1, VisualShaderNode::PORT_TYPE_TRANSFORM));
+
+ add_options.push_back(AddOption("OuterProduct", "Transform", "Composition", "VisualShaderNodeOuterProduct", TTR("(GLES3 only) Calculate the outer product of a pair of vectors.\n\nOuterProduct treats the first parameter 'c' as a column vector (matrix with one column) and the second parameter 'r' as a row vector (matrix with one row) and does a linear algebraic matrix multiply 'c * r', yielding a matrix whose number of rows is the number of components in 'c' and whose number of columns is the number of components in 'r'."), -1, VisualShaderNode::PORT_TYPE_TRANSFORM));
+ add_options.push_back(AddOption("TransformCompose", "Transform", "Composition", "VisualShaderNodeTransformCompose", TTR("Composes transform from four vectors."), -1, VisualShaderNode::PORT_TYPE_TRANSFORM));
+ add_options.push_back(AddOption("TransformDecompose", "Transform", "Composition", "VisualShaderNodeTransformDecompose", TTR("Decomposes transform to four vectors.")));
+
+ add_options.push_back(AddOption("Determinant", "Transform", "Functions", "VisualShaderNodeDeterminant", TTR("(GLES3 only) Calculates the determinant of a transform."), -1, VisualShaderNode::PORT_TYPE_SCALAR));
+ add_options.push_back(AddOption("Inverse", "Transform", "Functions", "VisualShaderNodeTransformFunc", TTR("(GLES3 only) Calculates the inverse of a transform."), VisualShaderNodeTransformFunc::FUNC_INVERSE, VisualShaderNode::PORT_TYPE_TRANSFORM));
+ add_options.push_back(AddOption("Transpose", "Transform", "Functions", "VisualShaderNodeTransformFunc", TTR("(GLES3 only) Calculates the transpose of a transform."), VisualShaderNodeTransformFunc::FUNC_TRANSPOSE, VisualShaderNode::PORT_TYPE_TRANSFORM));
+
+ add_options.push_back(AddOption("TransformMult", "Transform", "Operators", "VisualShaderNodeTransformMult", TTR("Multiplies transform by transform."), -1, VisualShaderNode::PORT_TYPE_TRANSFORM));
+ add_options.push_back(AddOption("TransformVectorMult", "Transform", "Operators", "VisualShaderNodeTransformVecMult", TTR("Multiplies vector by transform."), -1, VisualShaderNode::PORT_TYPE_VECTOR));
+
+ add_options.push_back(AddOption("TransformConstant", "Transform", "Variables", "VisualShaderNodeTransformConstant", TTR("Transform constant."), -1, VisualShaderNode::PORT_TYPE_TRANSFORM));
+ add_options.push_back(AddOption("TransformUniform", "Transform", "Variables", "VisualShaderNodeTransformUniform", TTR("Transform uniform."), -1, VisualShaderNode::PORT_TYPE_TRANSFORM));
+
+ // VECTOR
+
+ add_options.push_back(AddOption("VectorFunc", "Vector", "Common", "VisualShaderNodeVectorFunc", TTR("Vector function."), -1, VisualShaderNode::PORT_TYPE_VECTOR));
+ add_options.push_back(AddOption("VectorOp", "Vector", "Common", "VisualShaderNodeVectorOp", TTR("Vector operator."), -1, VisualShaderNode::PORT_TYPE_VECTOR));
+
+ add_options.push_back(AddOption("VectorCompose", "Vector", "Composition", "VisualShaderNodeVectorCompose", TTR("Composes vector from three scalars."), -1, VisualShaderNode::PORT_TYPE_VECTOR));
+ add_options.push_back(AddOption("VectorDecompose", "Vector", "Composition", "VisualShaderNodeVectorDecompose", TTR("Decomposes vector to three scalars.")));
+
+ add_options.push_back(AddOption("Abs", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Returns the absolute value of the parameter."), VisualShaderNodeVectorFunc::FUNC_ABS, VisualShaderNode::PORT_TYPE_VECTOR));
+ add_options.push_back(AddOption("ACos", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Returns the arc-cosine of the parameter."), VisualShaderNodeVectorFunc::FUNC_ACOS, VisualShaderNode::PORT_TYPE_VECTOR));
+ add_options.push_back(AddOption("ACosH", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("(GLES3 only) Returns the inverse hyperbolic cosine of the parameter."), VisualShaderNodeVectorFunc::FUNC_ACOSH, VisualShaderNode::PORT_TYPE_VECTOR));
+ add_options.push_back(AddOption("ASin", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Returns the arc-sine of the parameter."), VisualShaderNodeVectorFunc::FUNC_ASIN, VisualShaderNode::PORT_TYPE_VECTOR));
+ add_options.push_back(AddOption("ASinH", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("(GLES3 only) Returns the inverse hyperbolic sine of the parameter."), VisualShaderNodeVectorFunc::FUNC_ASINH, VisualShaderNode::PORT_TYPE_VECTOR));
+ add_options.push_back(AddOption("ATan", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Returns the arc-tangent of the parameter."), VisualShaderNodeVectorFunc::FUNC_ATAN, VisualShaderNode::PORT_TYPE_VECTOR));
+ add_options.push_back(AddOption("ATan2", "Vector", "Functions", "VisualShaderNodeVectorOp", TTR("Returns the arc-tangent of the parameters."), VisualShaderNodeVectorOp::OP_ATAN2, VisualShaderNode::PORT_TYPE_VECTOR));
+ add_options.push_back(AddOption("ATanH", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("(GLES3 only) Returns the inverse hyperbolic tangent of the parameter."), VisualShaderNodeVectorFunc::FUNC_ATANH, VisualShaderNode::PORT_TYPE_VECTOR));
+ add_options.push_back(AddOption("Ceil", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Finds the nearest integer that is greater than or equal to the parameter."), VisualShaderNodeVectorFunc::FUNC_CEIL, VisualShaderNode::PORT_TYPE_VECTOR));
+ add_options.push_back(AddOption("Clamp", "Vector", "Functions", "VisualShaderNodeVectorClamp", TTR("Constrains a value to lie between two further values."), -1, VisualShaderNode::PORT_TYPE_VECTOR));
+ add_options.push_back(AddOption("Cos", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Returns the cosine of the parameter."), VisualShaderNodeVectorFunc::FUNC_COS, VisualShaderNode::PORT_TYPE_VECTOR));
+ add_options.push_back(AddOption("CosH", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("(GLES3 only) Returns the hyperbolic cosine of the parameter."), VisualShaderNodeVectorFunc::FUNC_COSH, VisualShaderNode::PORT_TYPE_VECTOR));
+ add_options.push_back(AddOption("Cross", "Vector", "Functions", "VisualShaderNodeVectorOp", TTR("Calculates the cross product of two vectors."), VisualShaderNodeVectorOp::OP_CROSS, VisualShaderNode::PORT_TYPE_VECTOR));
+ add_options.push_back(AddOption("Degrees", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Converts a quantity in radians to degrees."), VisualShaderNodeVectorFunc::FUNC_DEGREES, VisualShaderNode::PORT_TYPE_VECTOR));
+ add_options.push_back(AddOption("Distance", "Vector", "Functions", "VisualShaderNodeVectorDistance", TTR("Returns the distance between two points."), -1, VisualShaderNode::PORT_TYPE_SCALAR));
+ add_options.push_back(AddOption("Dot", "Vector", "Functions", "VisualShaderNodeDotProduct", TTR("Calculates the dot product of two vectors."), -1, VisualShaderNode::PORT_TYPE_SCALAR));
+ add_options.push_back(AddOption("Exp", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Base-e Exponential."), VisualShaderNodeVectorFunc::FUNC_EXP, VisualShaderNode::PORT_TYPE_VECTOR));
+ add_options.push_back(AddOption("Exp2", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Base-2 Exponential."), VisualShaderNodeVectorFunc::FUNC_EXP2, VisualShaderNode::PORT_TYPE_VECTOR));
+ add_options.push_back(AddOption("FaceForward", "Vector", "Functions", "VisualShaderNodeFaceForward", TTR("Returns a vector that points in the same direction as a reference vector. The function has three vector parameters : N, the vector to orient, I, the incident vector, and Nref, the reference vector. If the dot product of I and Nref is smaller than zero the return value is N. Otherwise -N is returned."), -1, VisualShaderNode::PORT_TYPE_VECTOR));
+ add_options.push_back(AddOption("Floor", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Finds the nearest integer less than or equal to the parameter."), VisualShaderNodeVectorFunc::FUNC_FLOOR, VisualShaderNode::PORT_TYPE_VECTOR));
+ add_options.push_back(AddOption("Fract", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Computes the fractional part of the argument."), VisualShaderNodeVectorFunc::FUNC_FRAC, VisualShaderNode::PORT_TYPE_VECTOR));
+ add_options.push_back(AddOption("InverseSqrt", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Returns the inverse of the square root of the parameter."), VisualShaderNodeVectorFunc::FUNC_INVERSE_SQRT, VisualShaderNode::PORT_TYPE_VECTOR));
+ add_options.push_back(AddOption("Length", "Vector", "Functions", "VisualShaderNodeVectorLen", TTR("Calculates the length of a vector."), -1, VisualShaderNode::PORT_TYPE_SCALAR));
+ add_options.push_back(AddOption("Log", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Natural logarithm."), VisualShaderNodeVectorFunc::FUNC_LOG, VisualShaderNode::PORT_TYPE_VECTOR));
+ add_options.push_back(AddOption("Log2", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Base-2 logarithm."), VisualShaderNodeVectorFunc::FUNC_LOG2, VisualShaderNode::PORT_TYPE_VECTOR));
+ add_options.push_back(AddOption("Max", "Vector", "Functions", "VisualShaderNodeVectorOp", TTR("Returns the greater of two values."), VisualShaderNodeVectorOp::OP_MAX, VisualShaderNode::PORT_TYPE_VECTOR));
+ add_options.push_back(AddOption("Min", "Vector", "Functions", "VisualShaderNodeVectorOp", TTR("Returns the lesser of two values."), VisualShaderNodeVectorOp::OP_MIN, VisualShaderNode::PORT_TYPE_VECTOR));
+ add_options.push_back(AddOption("Mix", "Vector", "Functions", "VisualShaderNodeVectorInterp", TTR("Linear interpolation between two vectors."), -1, VisualShaderNode::PORT_TYPE_VECTOR));
+ add_options.push_back(AddOption("Negate", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Returns the opposite value of the parameter."), VisualShaderNodeVectorFunc::FUNC_NEGATE, VisualShaderNode::PORT_TYPE_VECTOR));
+ add_options.push_back(AddOption("Normalize", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Calculates the normalize product of vector."), VisualShaderNodeVectorFunc::FUNC_NORMALIZE, VisualShaderNode::PORT_TYPE_VECTOR));
+ add_options.push_back(AddOption("Pow", "Vector", "Functions", "VisualShaderNodeVectorOp", TTR("Returns the value of the first parameter raised to the power of the second."), VisualShaderNodeVectorOp::OP_POW, VisualShaderNode::PORT_TYPE_VECTOR));
+ add_options.push_back(AddOption("Radians", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Converts a quantity in degrees to radians."), VisualShaderNodeVectorFunc::FUNC_RADIANS, VisualShaderNode::PORT_TYPE_VECTOR));
+ add_options.push_back(AddOption("Reciprocal", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("1.0 / vector"), VisualShaderNodeVectorFunc::FUNC_RECIPROCAL, VisualShaderNode::PORT_TYPE_VECTOR));
+ add_options.push_back(AddOption("Reflect", "Vector", "Functions", "VisualShaderNodeVectorOp", TTR("Returns a vector that points in the direction of reflection ( a : incident vector, b : normal vector )."), VisualShaderNodeVectorOp::OP_REFLECT, VisualShaderNode::PORT_TYPE_VECTOR));
+ add_options.push_back(AddOption("Refract", "Vector", "Functions", "VisualShaderNodeVectorRefract", TTR("Returns a vector that points in the direction of refraction."), -1, VisualShaderNode::PORT_TYPE_VECTOR));
+ add_options.push_back(AddOption("Round", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("(GLES3 only) Finds the nearest integer to the parameter."), VisualShaderNodeVectorFunc::FUNC_ROUND, VisualShaderNode::PORT_TYPE_VECTOR));
+ add_options.push_back(AddOption("RoundEven", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("(GLES3 only) Finds the nearest even integer to the parameter."), VisualShaderNodeVectorFunc::FUNC_ROUNDEVEN, VisualShaderNode::PORT_TYPE_VECTOR));
+ add_options.push_back(AddOption("Saturate", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Clamps the value between 0.0 and 1.0."), VisualShaderNodeVectorFunc::FUNC_SATURATE, VisualShaderNode::PORT_TYPE_VECTOR));
+ add_options.push_back(AddOption("Sign", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Extracts the sign of the parameter."), VisualShaderNodeVectorFunc::FUNC_SIGN, VisualShaderNode::PORT_TYPE_VECTOR));
+ add_options.push_back(AddOption("Sin", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Returns the sine of the parameter."), VisualShaderNodeVectorFunc::FUNC_SIN, VisualShaderNode::PORT_TYPE_VECTOR));
+ add_options.push_back(AddOption("SinH", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("(GLES3 only) Returns the hyperbolic sine of the parameter."), VisualShaderNodeVectorFunc::FUNC_SINH, VisualShaderNode::PORT_TYPE_VECTOR));
+ add_options.push_back(AddOption("Sqrt", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Returns the square root of the parameter."), VisualShaderNodeVectorFunc::FUNC_SQRT, VisualShaderNode::PORT_TYPE_VECTOR));
+ add_options.push_back(AddOption("SmoothStep", "Vector", "Functions", "VisualShaderNodeVectorSmoothStep", TTR("SmoothStep function( vector(edge0), vector(edge1), vector(x) ).\n\nReturns 0.0 if 'x' is smaller then 'edge0' and 1.0 if 'x' is larger than 'edge1'. Otherwise the return value is interpolated between 0.0 and 1.0 using Hermite polynomials."), -1, VisualShaderNode::PORT_TYPE_VECTOR));
+ add_options.push_back(AddOption("SmoothStepS", "Vector", "Functions", "VisualShaderNodeVectorScalarSmoothStep", TTR("SmoothStep function( scalar(edge0), scalar(edge1), vector(x) ).\n\nReturns 0.0 if 'x' is smaller then 'edge0' and 1.0 if 'x' is larger than 'edge1'. Otherwise the return value is interpolated between 0.0 and 1.0 using Hermite polynomials."), -1, VisualShaderNode::PORT_TYPE_VECTOR));
+ add_options.push_back(AddOption("Step", "Vector", "Functions", "VisualShaderNodeVectorOp", TTR("Step function( vector(edge), vector(x) ).\n\nReturns 0.0 if 'x' is smaller then 'edge' and otherwise 1.0."), VisualShaderNodeVectorOp::OP_STEP, VisualShaderNode::PORT_TYPE_VECTOR));
+ add_options.push_back(AddOption("StepS", "Vector", "Functions", "VisualShaderNodeVectorScalarStep", TTR("Step function( scalar(edge), vector(x) ).\n\nReturns 0.0 if 'x' is smaller then 'edge' and otherwise 1.0."), -1, VisualShaderNode::PORT_TYPE_VECTOR));
+ add_options.push_back(AddOption("Tan", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Returns the tangent of the parameter."), VisualShaderNodeVectorFunc::FUNC_TAN, VisualShaderNode::PORT_TYPE_VECTOR));
+ add_options.push_back(AddOption("TanH", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("(GLES3 only) Returns the hyperbolic tangent of the parameter."), VisualShaderNodeVectorFunc::FUNC_TANH, VisualShaderNode::PORT_TYPE_VECTOR));
+ add_options.push_back(AddOption("Trunc", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("(GLES3 only) Finds the truncated value of the parameter."), VisualShaderNodeVectorFunc::FUNC_TRUNC, VisualShaderNode::PORT_TYPE_VECTOR));
+
+ add_options.push_back(AddOption("Add", "Vector", "Operators", "VisualShaderNodeVectorOp", TTR("Adds vector to vector."), VisualShaderNodeVectorOp::OP_ADD, VisualShaderNode::PORT_TYPE_VECTOR));
+ add_options.push_back(AddOption("Divide", "Vector", "Operators", "VisualShaderNodeVectorOp", TTR("Divides vector by vector."), VisualShaderNodeVectorOp::OP_DIV, VisualShaderNode::PORT_TYPE_VECTOR));
+ add_options.push_back(AddOption("Multiply", "Vector", "Operators", "VisualShaderNodeVectorOp", TTR("Multiplies vector by vector."), VisualShaderNodeVectorOp::OP_MUL, VisualShaderNode::PORT_TYPE_VECTOR));
+ add_options.push_back(AddOption("Remainder", "Vector", "Operators", "VisualShaderNodeVectorOp", TTR("Returns the remainder of the two vectors."), VisualShaderNodeVectorOp::OP_MOD, VisualShaderNode::PORT_TYPE_VECTOR));
+ add_options.push_back(AddOption("Subtract", "Vector", "Operators", "VisualShaderNodeVectorOp", TTR("Subtracts vector from vector."), VisualShaderNodeVectorOp::OP_SUB, VisualShaderNode::PORT_TYPE_VECTOR));
+
+ add_options.push_back(AddOption("VectorConstant", "Vector", "Variables", "VisualShaderNodeVec3Constant", TTR("Vector constant."), -1, VisualShaderNode::PORT_TYPE_VECTOR));
+ add_options.push_back(AddOption("VectorUniform", "Vector", "Variables", "VisualShaderNodeVec3Uniform", TTR("Vector uniform."), -1, VisualShaderNode::PORT_TYPE_VECTOR));
+
+ // SPECIAL
+
+ add_options.push_back(AddOption("ScalarDerivativeFunc", "Special", "Common", "VisualShaderNodeScalarDerivativeFunc", TTR("(GLES3 only) (Fragment/Light mode only) Scalar derivative function."), -1, VisualShaderNode::PORT_TYPE_SCALAR, VisualShader::TYPE_FRAGMENT | VisualShader::TYPE_LIGHT));
+ add_options.push_back(AddOption("VectorDerivativeFunc", "Special", "Common", "VisualShaderNodeVectorDerivativeFunc", TTR("(GLES3 only) (Fragment/Light mode only) Vector derivative function."), -1, VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_FRAGMENT | VisualShader::TYPE_LIGHT));
+
+ add_options.push_back(AddOption("DdX", "Special", "Derivative", "VisualShaderNodeVectorDerivativeFunc", TTR("(GLES3 only) (Fragment/Light mode only) (Vector) Derivative in 'x' using local differencing."), VisualShaderNodeVectorDerivativeFunc::FUNC_X, VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_FRAGMENT | VisualShader::TYPE_LIGHT));
+ add_options.push_back(AddOption("DdXS", "Special", "Derivative", "VisualShaderNodeScalarDerivativeFunc", TTR("(GLES3 only) (Fragment/Light mode only) (Scalar) Derivative in 'x' using local differencing."), VisualShaderNodeScalarDerivativeFunc::FUNC_X, VisualShaderNode::PORT_TYPE_SCALAR, VisualShader::TYPE_FRAGMENT | VisualShader::TYPE_LIGHT));
+ add_options.push_back(AddOption("DdY", "Special", "Derivative", "VisualShaderNodeVectorDerivativeFunc", TTR("(GLES3 only) (Fragment/Light mode only) (Vector) Derivative in 'y' using local differencing."), VisualShaderNodeVectorDerivativeFunc::FUNC_Y, VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_FRAGMENT | VisualShader::TYPE_LIGHT));
+ add_options.push_back(AddOption("DdYS", "Special", "Derivative", "VisualShaderNodeScalarDerivativeFunc", TTR("(GLES3 only) (Fragment/Light mode only) (Scalar) Derivative in 'y' using local differencing."), VisualShaderNodeScalarDerivativeFunc::FUNC_Y, VisualShaderNode::PORT_TYPE_SCALAR, VisualShader::TYPE_FRAGMENT | VisualShader::TYPE_LIGHT));
+ add_options.push_back(AddOption("Sum", "Special", "Derivative", "VisualShaderNodeVectorDerivativeFunc", TTR("(GLES3 only) (Fragment/Light mode only) (Vector) Sum of absolute derivative in 'x' and 'y'."), VisualShaderNodeVectorDerivativeFunc::FUNC_SUM, VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_FRAGMENT | VisualShader::TYPE_LIGHT));
+ add_options.push_back(AddOption("SumS", "Special", "Derivative", "VisualShaderNodeScalarDerivativeFunc", TTR("(GLES3 only) (Fragment/Light mode only) (Scalar) Sum of absolute derivative in 'x' and 'y'."), VisualShaderNodeScalarDerivativeFunc::FUNC_SUM, VisualShaderNode::PORT_TYPE_SCALAR, VisualShader::TYPE_FRAGMENT | VisualShader::TYPE_LIGHT));
+
+ /////////////////////////////////////////////////////////////////////
_update_options_menu();
@@ -940,9 +1645,10 @@ public:
void setup(const Ref<VisualShaderNodeInput> &p_input) {
input = p_input;
- Ref<Texture> type_icon[3] = {
+ Ref<Texture> type_icon[4] = {
EditorNode::get_singleton()->get_gui_base()->get_icon("float", "EditorIcons"),
EditorNode::get_singleton()->get_gui_base()->get_icon("Vector3", "EditorIcons"),
+ EditorNode::get_singleton()->get_gui_base()->get_icon("bool", "EditorIcons"),
EditorNode::get_singleton()->get_gui_base()->get_icon("Transform", "EditorIcons"),
};
diff --git a/editor/plugins/visual_shader_editor_plugin.h b/editor/plugins/visual_shader_editor_plugin.h
index 2fb8a85d5b..2709d72931 100644
--- a/editor/plugins/visual_shader_editor_plugin.h
+++ b/editor/plugins/visual_shader_editor_plugin.h
@@ -60,7 +60,7 @@ class VisualShaderEditor : public VBoxContainer {
Ref<VisualShader> visual_shader;
GraphEdit *graph;
- MenuButton *add_node;
+ ToolButton *add_node;
OptionButton *edit_type;
@@ -68,18 +68,59 @@ class VisualShaderEditor : public VBoxContainer {
Label *error_label;
UndoRedo *undo_redo;
+ Point2 saved_node_pos;
+ bool saved_node_pos_dirty;
+
+ ConfirmationDialog *members_dialog;
+ MenuButton *tools;
+
+ enum ToolsMenuOptions {
+ EXPAND_ALL,
+ COLLAPSE_ALL
+ };
+
+ Tree *members;
+ AcceptDialog *alert;
+ LineEdit *node_filter;
+ RichTextLabel *node_desc;
+
+ void _tools_menu_option(int p_idx);
+ void _show_members_dialog();
void _update_graph();
struct AddOption {
String name;
String category;
+ String sub_category;
String type;
+ String description;
+ int sub_func;
+ String sub_func_str;
Ref<Script> script;
- AddOption(const String &p_name = String(), const String &p_category = String(), const String &p_type = String()) {
+ int mode;
+ int return_type;
+
+ AddOption(const String &p_name = String(), const String &p_category = String(), const String &p_sub_category = String(), const String &p_type = String(), const String &p_description = String(), int p_sub_func = -1, int p_return_type = -1, int p_mode = -1) {
+ name = p_name;
+ type = p_type;
+ category = p_category;
+ sub_category = p_sub_category;
+ description = p_description;
+ sub_func = p_sub_func;
+ return_type = p_return_type;
+ mode = p_mode;
+ }
+
+ AddOption(const String &p_name, const String &p_category, const String &p_sub_category, const String &p_type, const String &p_description, const String &p_sub_func, int p_return_type = -1, int p_mode = -1) {
name = p_name;
type = p_type;
category = p_category;
+ sub_category = p_sub_category;
+ description = p_description;
+ sub_func_str = p_sub_func;
+ return_type = p_return_type;
+ mode = p_mode;
}
};
@@ -87,7 +128,7 @@ class VisualShaderEditor : public VBoxContainer {
void _draw_color_over_button(Object *obj, Color p_color);
- void _add_node(int p_idx);
+ void _add_node(int p_idx, int p_op_idx = -1);
void _update_options_menu();
static VisualShaderEditor *singleton;
@@ -126,6 +167,18 @@ class VisualShaderEditor : public VBoxContainer {
void _preview_select_port(int p_node, int p_port);
void _input(const Ref<InputEvent> p_event);
+ void _member_gui_input(const Ref<InputEvent> p_event);
+ void _member_filter_changed(const String &p_text);
+ void _member_selected();
+ void _member_unselected();
+ void _member_create();
+
+ Variant get_drag_data_fw(const Point2 &p_point, Control *p_from);
+ 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);
+
+ bool _is_available(int p_flags);
+
protected:
void _notification(int p_what);
static void _bind_methods();