Path: blob/master/modules/gridmap/editor/grid_map_editor_plugin.cpp
20870 views
/**************************************************************************/1/* grid_map_editor_plugin.cpp */2/**************************************************************************/3/* This file is part of: */4/* GODOT ENGINE */5/* https://godotengine.org */6/**************************************************************************/7/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */8/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */9/* */10/* Permission is hereby granted, free of charge, to any person obtaining */11/* a copy of this software and associated documentation files (the */12/* "Software"), to deal in the Software without restriction, including */13/* without limitation the rights to use, copy, modify, merge, publish, */14/* distribute, sublicense, and/or sell copies of the Software, and to */15/* permit persons to whom the Software is furnished to do so, subject to */16/* the following conditions: */17/* */18/* The above copyright notice and this permission notice shall be */19/* included in all copies or substantial portions of the Software. */20/* */21/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */22/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */23/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */24/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */25/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */26/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */27/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */28/**************************************************************************/2930#include "grid_map_editor_plugin.h"3132#include "core/input/input.h"33#include "core/math/geometry_2d.h"34#include "core/os/keyboard.h"35#include "editor/editor_main_screen.h"36#include "editor/editor_node.h"37#include "editor/editor_string_names.h"38#include "editor/editor_undo_redo_manager.h"39#include "editor/gui/editor_bottom_panel.h"40#include "editor/gui/editor_zoom_widget.h"41#include "editor/gui/filter_line_edit.h"42#include "editor/scene/3d/node_3d_editor_plugin.h"43#include "editor/settings/editor_command_palette.h"44#include "editor/settings/editor_settings.h"45#include "editor/themes/editor_scale.h"46#include "scene/3d/camera_3d.h"47#include "scene/gui/dialogs.h"48#include "scene/gui/item_list.h"49#include "scene/gui/label.h"50#include "scene/gui/margin_container.h"51#include "scene/gui/menu_button.h"52#include "scene/gui/separator.h"53#include "scene/gui/slider.h"54#include "scene/gui/spin_box.h"55#include "scene/main/window.h"5657void GridMapEditor::_configure() {58if (!node) {59return;60}6162update_grid();63}6465void GridMapEditor::_menu_option(int p_option) {66switch (p_option) {67case MENU_OPTION_PREV_LEVEL: {68floor->set_value(floor->get_value() - 1);69if (selection.active && input_action == INPUT_SELECT) {70selection.current[edit_axis]--;71_validate_selection();72}73} break;7475case MENU_OPTION_NEXT_LEVEL: {76floor->set_value(floor->get_value() + 1);77if (selection.active && input_action == INPUT_SELECT) {78selection.current[edit_axis]++;79_validate_selection();80}81} break;8283case MENU_OPTION_X_AXIS:84case MENU_OPTION_Y_AXIS:85case MENU_OPTION_Z_AXIS: {86int new_axis = p_option - MENU_OPTION_X_AXIS;87for (int i = 0; i < 3; i++) {88int idx = options->get_popup()->get_item_index(MENU_OPTION_X_AXIS + i);89options->get_popup()->set_item_checked(idx, i == new_axis);90}9192if (edit_axis != new_axis) {93if (edit_axis == Vector3::AXIS_Y) {94floor->set_tooltip_text("Change Grid Plane");95} else if (new_axis == Vector3::AXIS_Y) {96floor->set_tooltip_text("Change Grid Floor");97}98}99edit_axis = Vector3::Axis(new_axis);100update_grid();101102} break;103104case MENU_OPTION_CURSOR_ROTATE_X:105case MENU_OPTION_CURSOR_ROTATE_Y:106case MENU_OPTION_CURSOR_ROTATE_Z:107case MENU_OPTION_CURSOR_BACK_ROTATE_X:108case MENU_OPTION_CURSOR_BACK_ROTATE_Y:109case MENU_OPTION_CURSOR_BACK_ROTATE_Z: {110Vector3 rotation_axis;111float rotation_angle = -Math::PI / 2.0;112if (p_option == MENU_OPTION_CURSOR_ROTATE_X || p_option == MENU_OPTION_CURSOR_BACK_ROTATE_X) {113rotation_axis.x = (p_option == MENU_OPTION_CURSOR_ROTATE_X) ? 1 : -1;114} else if (p_option == MENU_OPTION_CURSOR_ROTATE_Y || p_option == MENU_OPTION_CURSOR_BACK_ROTATE_Y) {115rotation_axis.y = (p_option == MENU_OPTION_CURSOR_ROTATE_Y) ? 1 : -1;116} else if (p_option == MENU_OPTION_CURSOR_ROTATE_Z || p_option == MENU_OPTION_CURSOR_BACK_ROTATE_Z) {117rotation_axis.z = (p_option == MENU_OPTION_CURSOR_ROTATE_Z) ? 1 : -1;118}119120Basis r;121if (input_action == INPUT_PASTE) {122r = node->get_basis_with_orthogonal_index(paste_indicator.orientation);123r.rotate(rotation_axis, rotation_angle);124paste_indicator.orientation = node->get_orthogonal_index_from_basis(r);125_update_paste_indicator();126} else if (_has_selection()) {127Array cells = _get_selected_cells();128for (int i = 0; i < cells.size(); i++) {129Vector3i cell = cells[i];130r = node->get_basis_with_orthogonal_index(node->get_cell_item_orientation(cell));131r.rotate(rotation_axis, rotation_angle);132node->set_cell_item(cell, node->get_cell_item(cell), node->get_orthogonal_index_from_basis(r));133}134} else {135r = node->get_basis_with_orthogonal_index(cursor_rot);136r.rotate(rotation_axis, rotation_angle);137cursor_rot = node->get_orthogonal_index_from_basis(r);138_update_cursor_transform();139}140} break;141142case MENU_OPTION_CURSOR_CLEAR_ROTATION: {143if (input_action == INPUT_PASTE) {144paste_indicator.orientation = 0;145_update_paste_indicator();146break;147}148149cursor_rot = 0;150_update_cursor_transform();151} break;152153case MENU_OPTION_PASTE_SELECTS: {154int idx = options->get_popup()->get_item_index(MENU_OPTION_PASTE_SELECTS);155options->get_popup()->set_item_checked(idx, !options->get_popup()->is_item_checked(idx));156} break;157158case MENU_OPTION_SELECTION_DUPLICATE: {159if (!(selection.active && input_action == INPUT_NONE)) {160break;161}162163_set_clipboard_data();164clipboard_is_move = false;165166if (!clipboard_items.is_empty()) {167_setup_paste_mode();168}169} break;170171case MENU_OPTION_SELECTION_MOVE: {172if (!(selection.active && input_action == INPUT_NONE)) {173break;174}175176_set_clipboard_data();177clipboard_is_move = true;178179if (!clipboard_items.is_empty()) {180_delete_selection();181_setup_paste_mode();182}183} break;184case MENU_OPTION_SELECTION_CLEAR: {185if (!selection.active) {186break;187}188189_delete_selection_with_undo();190191} break;192case MENU_OPTION_SELECTION_FILL: {193if (!selection.active) {194return;195}196197_fill_selection();198199} break;200case MENU_OPTION_GRIDMAP_SETTINGS: {201settings_dialog->popup_centered(settings_vbc->get_combined_minimum_size() + Size2(50, 50) * EDSCALE);202} break;203}204}205206void GridMapEditor::_update_cursor_transform() {207cursor_transform = Transform3D();208cursor_transform.origin = cursor_origin;209cursor_transform.basis *= node->get_cell_scale();210cursor_transform = node->get_global_transform() * cursor_transform;211212if (mode_buttons_group->get_pressed_button() == paint_mode_button) {213// Auto-deselect the selection when painting.214if (selection.active) {215_set_selection(false);216}217// Rotation is only applied in paint mode, we don't want the cursor box to rotate otherwise.218cursor_transform.basis *= node->get_basis_with_orthogonal_index(cursor_rot);219if (selected_palette >= 0 && node && node->get_mesh_library().is_valid()) {220cursor_transform *= node->get_mesh_library()->get_item_mesh_transform(selected_palette);221}222} else {223Transform3D xf;224xf.scale(node->get_cell_size());225xf.origin.x = node->get_center_x() ? -node->get_cell_size().x / 2 : 0;226xf.origin.y = node->get_center_y() ? -node->get_cell_size().y / 2 : 0;227xf.origin.z = node->get_center_z() ? -node->get_cell_size().z / 2 : 0;228cursor_transform *= xf;229}230231if (cursor_instance.is_valid()) {232RenderingServer::get_singleton()->instance_set_transform(cursor_instance, cursor_transform);233RenderingServer::get_singleton()->instance_set_visible(cursor_instance, cursor_visible);234}235}236237void GridMapEditor::_update_selection_transform() {238Transform3D xf_zero;239xf_zero.basis.set_zero();240241if (!selection.active) {242RenderingServer::get_singleton()->instance_set_transform(selection_instance, xf_zero);243for (int i = 0; i < 3; i++) {244RenderingServer::get_singleton()->instance_set_transform(selection_level_instance[i], xf_zero);245}246return;247}248249Transform3D xf;250xf.scale((Vector3(1, 1, 1) + (selection.end - selection.begin)) * node->get_cell_size());251xf.origin = selection.begin * node->get_cell_size();252253RenderingServer::get_singleton()->instance_set_transform(selection_instance, node->get_global_transform() * xf);254255for (int i = 0; i < 3; i++) {256if (i != edit_axis || (edit_floor[edit_axis] < selection.begin[edit_axis]) || (edit_floor[edit_axis] > selection.end[edit_axis] + 1)) {257RenderingServer::get_singleton()->instance_set_transform(selection_level_instance[i], xf_zero);258} else {259Vector3 scale = (selection.end - selection.begin + Vector3(1, 1, 1));260scale[edit_axis] = 1.0;261Vector3 position = selection.begin;262position[edit_axis] = edit_floor[edit_axis];263264scale *= node->get_cell_size();265position *= node->get_cell_size();266267Transform3D xf2;268xf2.basis.scale(scale);269xf2.origin = position;270271RenderingServer::get_singleton()->instance_set_transform(selection_level_instance[i], node->get_global_transform() * xf2);272}273}274}275276void GridMapEditor::_validate_selection() {277if (!selection.active) {278return;279}280selection.begin = selection.click;281selection.end = selection.current;282283if (selection.begin.x > selection.end.x) {284SWAP(selection.begin.x, selection.end.x);285}286if (selection.begin.y > selection.end.y) {287SWAP(selection.begin.y, selection.end.y);288}289if (selection.begin.z > selection.end.z) {290SWAP(selection.begin.z, selection.end.z);291}292293_update_selection_transform();294}295296void GridMapEditor::_set_selection(bool p_active, const Vector3 &p_begin, const Vector3 &p_end) {297selection.active = p_active;298selection.begin = p_begin;299selection.end = p_end;300selection.click = p_begin;301selection.current = p_end;302303if (is_visible_in_tree()) {304_update_selection_transform();305}306}307308AABB GridMapEditor::_get_selection() const {309AABB ret;310if (selection.active) {311ret.position = selection.begin;312ret.size = selection.end - selection.begin;313} else {314ret.position.zero();315ret.size.zero();316}317return ret;318}319320bool GridMapEditor::_has_selection() const {321return node != nullptr && selection.active;322}323324Array GridMapEditor::_get_selected_cells() const {325Array ret;326if (node != nullptr && selection.active) {327for (int i = selection.begin.x; i <= selection.end.x; i++) {328for (int j = selection.begin.y; j <= selection.end.y; j++) {329for (int k = selection.begin.z; k <= selection.end.z; k++) {330Vector3i selected = Vector3i(i, j, k);331int itm = node->get_cell_item(selected);332if (itm == GridMap::INVALID_CELL_ITEM) {333continue;334}335ret.append(selected);336}337}338}339}340return ret;341}342343bool GridMapEditor::do_input_action(Camera3D *p_camera, const Point2 &p_point, bool p_click) {344if (!spatial_editor) {345return false;346}347if (input_action == INPUT_TRANSFORM) {348return false;349}350if (selected_palette < 0 && input_action != INPUT_NONE && input_action != INPUT_PICK && input_action != INPUT_SELECT && input_action != INPUT_PASTE) {351return false;352}353if (mesh_library.is_null()) {354return false;355}356if (input_action != INPUT_NONE && input_action != INPUT_PICK && input_action != INPUT_SELECT && input_action != INPUT_PASTE && !mesh_library->has_item(selected_palette)) {357return false;358}359360Camera3D *camera = p_camera;361Vector3 from = camera->project_ray_origin(p_point);362Vector3 normal = camera->project_ray_normal(p_point);363Transform3D local_xform = node->get_global_transform().affine_inverse();364Vector<Plane> planes = camera->get_frustum();365from = local_xform.xform(from);366normal = local_xform.basis.xform(normal).normalized();367368Plane p;369p.normal[edit_axis] = 1.0;370p.d = edit_floor[edit_axis] * node->get_cell_size()[edit_axis];371372Vector3 inters;373if (!p.intersects_segment(from, from + normal * settings_pick_distance->get_value(), &inters)) {374return false;375}376377// Make sure the intersection is inside the frustum planes, to avoid378// Painting on invisible regions.379for (int i = 0; i < planes.size(); i++) {380Plane fp = local_xform.xform(planes[i]);381if (fp.is_point_over(inters)) {382return false;383}384}385386Vector3 cell_size = node->get_cell_size();387388for (int i = 0; i < 3; i++) {389if (i == edit_axis) {390cursor_gridpos[i] = edit_floor[i];391} else {392cursor_gridpos[i] = inters[i] / cell_size[i];393if (inters[i] < 0) {394cursor_gridpos[i] -= 1; // Compensate negative.395}396grid_ofs[i] = cursor_gridpos[i] * cell_size[i];397}398}399400RS::get_singleton()->instance_set_transform(grid_instance[edit_axis], node->get_global_transform() * edit_grid_xform);401402if (cursor_instance.is_valid()) {403cursor_origin = (Vector3(cursor_gridpos) + Vector3(0.5 * node->get_center_x(), 0.5 * node->get_center_y(), 0.5 * node->get_center_z())) * node->get_cell_size();404cursor_visible = true;405406if (input_action == INPUT_PASTE) {407cursor_visible = false;408}409410_update_cursor_transform();411}412413if (input_action == INPUT_NONE) {414return false;415}416417if (input_action == INPUT_PASTE) {418paste_indicator.current = cursor_gridpos;419_update_paste_indicator();420421} else if (input_action == INPUT_SELECT) {422selection.current = cursor_gridpos;423if (p_click) {424selection.click = selection.current;425}426selection.active = true;427_validate_selection();428429return true;430} else if (input_action == INPUT_PICK) {431int item = node->get_cell_item(cursor_gridpos);432if (item >= 0) {433selected_palette = item;434435// Clear the filter if picked an item that's filtered out.436int index = mesh_library_palette->find_metadata(item);437if (index == -1) {438search_box->clear();439}440441// This will select `selected_palette` in the ItemList when possible.442update_palette();443444_update_cursor_instance();445}446return true;447}448449if (input_action == INPUT_PAINT || input_action == INPUT_ERASE) {450LocalVector<Vector3i> cells;451if (!set_items.is_empty()) {452Vector3i last_si = (--set_items.end())->position;453// Manipulate Vector3i into Point2i by ignoring the edit_axis.454int i = edit_axis == 0 ? 1 : 0;455int j = edit_axis == 2 ? 1 : 2;456Point2i from_cell = Point2i(last_si[i], last_si[j]);457Point2i to_cell = Point2i(cursor_gridpos[i], cursor_gridpos[j]);458459Vector<Point2i> cells_2d = Geometry2D::bresenham_line(from_cell, to_cell);460461switch (edit_axis) {462case 0:463for (const Point2i &cell_2d : cells_2d) {464cells.push_back(Vector3i(edit_floor[0], cell_2d[0], cell_2d[1]));465}466break;467case 1:468for (const Point2i &cell_2d : cells_2d) {469cells.push_back(Vector3i(cell_2d[0], edit_floor[1], cell_2d[1]));470}471break;472case 2:473for (const Point2i &cell_2d : cells_2d) {474cells.push_back(Vector3i(cell_2d[0], cell_2d[1], edit_floor[2]));475}476break;477default:478break;479}480} else {481cells.push_back(cursor_gridpos);482}483484if (input_action == INPUT_PAINT) {485for (const Vector3i &cell_v : cells) {486SetItem si;487si.position = cell_v;488si.new_value = selected_palette;489si.new_orientation = cursor_rot;490si.old_value = node->get_cell_item(cell_v);491si.old_orientation = node->get_cell_item_orientation(cell_v);492set_items.push_back(si);493node->set_cell_item(cell_v, selected_palette, cursor_rot);494}495return true;496} else if (input_action == INPUT_ERASE) {497for (const Vector3i &cell_v : cells) {498SetItem si;499si.position = cell_v;500si.new_value = -1;501si.new_orientation = 0;502si.old_value = node->get_cell_item(cell_v);503si.old_orientation = node->get_cell_item_orientation(cell_v);504set_items.push_back(si);505node->set_cell_item(cell_v, -1);506}507return true;508}509}510511return false;512}513514void GridMapEditor::_delete_selection() {515if (!selection.active) {516return;517}518519for (int i = selection.begin.x; i <= selection.end.x; i++) {520for (int j = selection.begin.y; j <= selection.end.y; j++) {521for (int k = selection.begin.z; k <= selection.end.z; k++) {522Vector3i selected = Vector3i(i, j, k);523node->set_cell_item(selected, GridMap::INVALID_CELL_ITEM);524}525}526}527}528529void GridMapEditor::_delete_selection_with_undo() {530if (!selection.active) {531return;532}533534EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();535undo_redo->create_action(TTR("GridMap Delete Selection"));536for (int i = selection.begin.x; i <= selection.end.x; i++) {537for (int j = selection.begin.y; j <= selection.end.y; j++) {538for (int k = selection.begin.z; k <= selection.end.z; k++) {539Vector3i selected = Vector3i(i, j, k);540undo_redo->add_do_method(node, "set_cell_item", selected, GridMap::INVALID_CELL_ITEM);541undo_redo->add_undo_method(node, "set_cell_item", selected, node->get_cell_item(selected), node->get_cell_item_orientation(selected));542}543}544}545undo_redo->add_do_method(this, "_set_selection", !selection.active, selection.begin, selection.end);546undo_redo->add_undo_method(this, "_set_selection", selection.active, selection.begin, selection.end);547undo_redo->commit_action();548}549550void GridMapEditor::_setup_paste_mode() {551input_action = INPUT_PASTE;552paste_indicator.click = selection.click;553paste_indicator.current = cursor_gridpos;554paste_indicator.begin = selection.begin;555paste_indicator.end = selection.end;556paste_indicator.distance_from_cursor = cursor_gridpos - paste_indicator.begin;557paste_indicator.orientation = 0;558_update_paste_indicator();559}560561void GridMapEditor::_fill_selection() {562if (!selection.active) {563return;564}565566EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();567undo_redo->create_action(TTR("GridMap Fill Selection"));568for (int i = selection.begin.x; i <= selection.end.x; i++) {569for (int j = selection.begin.y; j <= selection.end.y; j++) {570for (int k = selection.begin.z; k <= selection.end.z; k++) {571Vector3i selected = Vector3i(i, j, k);572undo_redo->add_do_method(node, "set_cell_item", selected, selected_palette, cursor_rot);573undo_redo->add_undo_method(node, "set_cell_item", selected, node->get_cell_item(selected), node->get_cell_item_orientation(selected));574}575}576}577undo_redo->add_do_method(this, "_set_selection", !selection.active, selection.begin, selection.end);578undo_redo->add_undo_method(this, "_set_selection", selection.active, selection.begin, selection.end);579undo_redo->commit_action();580}581582void GridMapEditor::_clear_clipboard_data() {583for (const ClipboardItem &E : clipboard_items) {584if (E.instance.is_null()) {585continue;586}587RenderingServer::get_singleton()->free_rid(E.instance);588}589590clipboard_items.clear();591clipboard_is_move = false;592}593594void GridMapEditor::_set_clipboard_data() {595_clear_clipboard_data();596597Ref<MeshLibrary> meshLibrary = node->get_mesh_library();598599const RID scenario = get_tree()->get_root()->get_world_3d()->get_scenario();600601for (int i = selection.begin.x; i <= selection.end.x; i++) {602for (int j = selection.begin.y; j <= selection.end.y; j++) {603for (int k = selection.begin.z; k <= selection.end.z; k++) {604Vector3i selected = Vector3i(i, j, k);605int itm = node->get_cell_item(selected);606if (itm == GridMap::INVALID_CELL_ITEM) {607continue;608}609610Ref<Mesh> mesh = meshLibrary->get_item_mesh(itm);611612ClipboardItem item;613item.cell_item = itm;614item.grid_offset = Vector3(selected) - selection.begin;615item.orientation = node->get_cell_item_orientation(selected);616617if (mesh.is_valid()) {618item.instance = RenderingServer::get_singleton()->instance_create2(mesh->get_rid(), scenario);619}620621clipboard_items.push_back(item);622}623}624}625}626627void GridMapEditor::_update_paste_indicator() {628if (input_action != INPUT_PASTE) {629Transform3D xf;630xf.basis.set_zero();631RenderingServer::get_singleton()->instance_set_transform(paste_instance, xf);632return;633}634635Vector3 center = 0.5 * Vector3(real_t(node->get_center_x()), real_t(node->get_center_y()), real_t(node->get_center_z()));636Vector3 scale = (Vector3(1, 1, 1) + (paste_indicator.end - paste_indicator.begin)) * node->get_cell_size();637Transform3D xf;638xf.scale(scale);639xf.origin = (paste_indicator.current - paste_indicator.distance_from_cursor + center) * node->get_cell_size();640Basis rot;641rot = node->get_basis_with_orthogonal_index(paste_indicator.orientation);642xf.basis = rot * xf.basis;643xf.translate_local((-center * node->get_cell_size()) / scale);644645RenderingServer::get_singleton()->instance_set_transform(paste_instance, node->get_global_transform() * xf);646647for (const ClipboardItem &item : clipboard_items) {648if (item.instance.is_null()) {649continue;650}651xf = Transform3D();652xf.origin = (paste_indicator.current - paste_indicator.distance_from_cursor + center) * node->get_cell_size();653xf.basis = rot * xf.basis;654xf.translate_local(item.grid_offset * node->get_cell_size());655656Basis item_rot;657item_rot = node->get_basis_with_orthogonal_index(item.orientation);658xf.basis = item_rot * xf.basis * node->get_cell_scale();659660RenderingServer::get_singleton()->instance_set_transform(item.instance, node->get_global_transform() * xf);661}662}663664void GridMapEditor::_cancel_pending_move() {665if (input_action == INPUT_PASTE) {666if (clipboard_is_move) {667for (const ClipboardItem &item : clipboard_items) {668Vector3 original_position = paste_indicator.begin + item.grid_offset;669node->set_cell_item(Vector3i(original_position), item.cell_item, item.orientation);670}671}672_clear_clipboard_data();673input_action = INPUT_NONE;674_update_paste_indicator();675}676}677678void GridMapEditor::_do_paste() {679int idx = options->get_popup()->get_item_index(MENU_OPTION_PASTE_SELECTS);680bool reselect = options->get_popup()->is_item_checked(idx);681682Basis rot;683rot = node->get_basis_with_orthogonal_index(paste_indicator.orientation);684685EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();686687if (clipboard_is_move) {688undo_redo->create_action(TTR("GridMap Move Selection"));689690for (const ClipboardItem &item : clipboard_items) {691Vector3 original_position = paste_indicator.begin + item.grid_offset;692undo_redo->add_undo_method(node, "set_cell_item", original_position, item.cell_item, item.orientation);693undo_redo->add_do_method(node, "set_cell_item", original_position, GridMap::INVALID_CELL_ITEM);694}695} else {696undo_redo->create_action(TTR("GridMap Paste Selection"));697}698699for (const ClipboardItem &item : clipboard_items) {700Vector3 position = rot.xform(item.grid_offset) + paste_indicator.current - paste_indicator.distance_from_cursor;701702Basis orm;703orm = node->get_basis_with_orthogonal_index(item.orientation);704orm = rot * orm;705706undo_redo->add_do_method(node, "set_cell_item", position, item.cell_item, node->get_orthogonal_index_from_basis(orm));707undo_redo->add_undo_method(node, "set_cell_item", position, node->get_cell_item(position), node->get_cell_item_orientation(position));708}709710if (reselect) {711// We need to rotate the paste_indicator to find the selection begin and end:712Vector3 temp_end = rot.xform(paste_indicator.end - paste_indicator.begin) + paste_indicator.current - paste_indicator.distance_from_cursor;713Vector3 temp_begin = paste_indicator.current - paste_indicator.distance_from_cursor;714// _set_selection expects that selection_begin is the corner closer to the origin:715for (int i = 0; i < 3; ++i) {716if (temp_begin[i] > temp_end[i]) {717float p = temp_begin[i];718temp_begin[i] = temp_end[i];719temp_end[i] = p;720}721}722undo_redo->add_do_method(this, "_set_selection", true, temp_begin, temp_end);723undo_redo->add_undo_method(this, "_set_selection", selection.active, selection.begin, selection.end);724}725726undo_redo->commit_action();727728_clear_clipboard_data();729}730731void GridMapEditor::_show_viewports_transform_gizmo(bool p_value) {732Dictionary new_state;733new_state["transform_gizmo"] = p_value;734for (uint32_t i = 0; i < Node3DEditor::VIEWPORTS_COUNT; i++) {735Node3DEditorViewport *viewport = Node3DEditor::get_singleton()->get_editor_viewport(i);736viewport->set_state(new_state);737}738}739740EditorPlugin::AfterGUIInput GridMapEditor::forward_spatial_input_event(Camera3D *p_camera, const Ref<InputEvent> &p_event) {741// If the mouse is currently captured, we are most likely in freelook mode.742// In this case, disable shortcuts to avoid conflicts with freelook navigation.743if (!node || Input::get_singleton()->get_mouse_mode() == Input::MouseMode::MOUSE_MODE_CAPTURED) {744return EditorPlugin::AFTER_GUI_INPUT_PASS;745}746747Ref<InputEventKey> k = p_event;748if (k.is_valid() && k->is_pressed() && !k->is_echo()) {749// Transform mode (toggle button):750// If we are in Transform mode we pass the events to the 3D editor,751// but if the Transform mode shortcut is pressed again, we go back to Selection mode.752if (mode_buttons_group->get_pressed_button() == transform_mode_button) {753if (transform_mode_button->get_shortcut().is_valid() && transform_mode_button->get_shortcut()->matches_event(p_event)) {754select_mode_button->set_pressed(true);755accept_event();756return EditorPlugin::AFTER_GUI_INPUT_STOP;757}758return EditorPlugin::AFTER_GUI_INPUT_PASS;759}760// Tool modes and tool actions:761for (BaseButton *b : viewport_shortcut_buttons) {762if (b->is_disabled()) {763continue;764}765766if (b->get_shortcut().is_valid() && b->get_shortcut()->matches_event(p_event)) {767if (b->is_toggle_mode()) {768b->set_pressed(b->get_button_group().is_valid() || !b->is_pressed());769} else {770// Can't press a button without toggle mode, so just emit the signal directly.771b->emit_signal(SceneStringName(pressed));772}773accept_event();774return EditorPlugin::AFTER_GUI_INPUT_STOP;775}776}777// Hard key actions:778if (k->get_keycode() == Key::ESCAPE) {779if (input_action == INPUT_PASTE) {780_cancel_pending_move();781return EditorPlugin::AFTER_GUI_INPUT_STOP;782} else if (selection.active) {783_set_selection(false);784return EditorPlugin::AFTER_GUI_INPUT_STOP;785} else {786input_action = INPUT_NONE;787update_palette();788_update_cursor_instance();789return EditorPlugin::AFTER_GUI_INPUT_STOP;790}791}792// Options menu shortcuts:793Ref<Shortcut> ed_shortcut = ED_GET_SHORTCUT("grid_map/previous_floor");794if (ed_shortcut.is_valid() && ed_shortcut->matches_event(p_event)) {795accept_event();796_menu_option(MENU_OPTION_PREV_LEVEL);797return EditorPlugin::AFTER_GUI_INPUT_STOP;798}799ed_shortcut = ED_GET_SHORTCUT("grid_map/next_floor");800if (ed_shortcut.is_valid() && ed_shortcut->matches_event(p_event)) {801accept_event();802_menu_option(MENU_OPTION_NEXT_LEVEL);803return EditorPlugin::AFTER_GUI_INPUT_STOP;804}805for (int i = 0; i < options->get_popup()->get_item_count(); ++i) {806const Ref<Shortcut> &shortcut = options->get_popup()->get_item_shortcut(i);807if (shortcut.is_valid() && shortcut->matches_event(p_event)) {808// Consume input to avoid conflicts with other plugins.809accept_event();810_menu_option(options->get_popup()->get_item_id(i));811return EditorPlugin::AFTER_GUI_INPUT_STOP;812}813}814}815816Ref<InputEventMouseButton> mb = p_event;817if (mb.is_valid()) {818if (mb->get_button_index() == MouseButton::WHEEL_UP && (mb->is_command_or_control_pressed())) {819if (mb->is_pressed()) {820floor->set_value(floor->get_value() + mb->get_factor());821}822823return EditorPlugin::AFTER_GUI_INPUT_STOP; // Eaten.824} else if (mb->get_button_index() == MouseButton::WHEEL_DOWN && (mb->is_command_or_control_pressed())) {825if (mb->is_pressed()) {826floor->set_value(floor->get_value() - mb->get_factor());827}828return EditorPlugin::AFTER_GUI_INPUT_STOP;829}830831if (mb->is_pressed()) {832Node3DEditorViewport::NavigationScheme nav_scheme = (Node3DEditorViewport::NavigationScheme)EDITOR_GET("editors/3d/navigation/navigation_scheme").operator int();833if ((nav_scheme == Node3DEditorViewport::NAVIGATION_MAYA || nav_scheme == Node3DEditorViewport::NAVIGATION_MODO) && mb->is_alt_pressed()) {834input_action = INPUT_NONE;835} else if (mb->get_button_index() == MouseButton::LEFT) {836bool can_edit = (node && node->get_mesh_library().is_valid());837if (input_action == INPUT_PASTE) {838_do_paste();839input_action = INPUT_NONE;840_update_paste_indicator();841return EditorPlugin::AFTER_GUI_INPUT_STOP;842} else if (mode_buttons_group->get_pressed_button() == select_mode_button && can_edit) {843input_action = INPUT_SELECT;844last_selection = selection;845} else if (mode_buttons_group->get_pressed_button() == pick_mode_button && can_edit) {846input_action = INPUT_PICK;847} else if (mode_buttons_group->get_pressed_button() == paint_mode_button && can_edit) {848input_action = INPUT_PAINT;849set_items.clear();850} else if (mode_buttons_group->get_pressed_button() == erase_mode_button && can_edit) {851input_action = INPUT_ERASE;852set_items.clear();853}854} else if (mb->get_button_index() == MouseButton::RIGHT) {855if (input_action == INPUT_PASTE) {856_clear_clipboard_data();857input_action = INPUT_NONE;858_update_paste_indicator();859return EditorPlugin::AFTER_GUI_INPUT_STOP;860} else if (selection.active) {861_set_selection(false);862return EditorPlugin::AFTER_GUI_INPUT_STOP;863}864} else {865return EditorPlugin::AFTER_GUI_INPUT_PASS;866}867868if (do_input_action(p_camera, Point2(mb->get_position().x, mb->get_position().y), true)) {869return EditorPlugin::AFTER_GUI_INPUT_STOP;870}871return EditorPlugin::AFTER_GUI_INPUT_PASS;872} else {873if ((mb->get_button_index() == MouseButton::LEFT && input_action == INPUT_ERASE) || (mb->get_button_index() == MouseButton::LEFT && input_action == INPUT_PAINT)) {874if (set_items.size()) {875EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();876undo_redo->create_action(TTR("GridMap Paint"));877for (const SetItem &si : set_items) {878undo_redo->add_do_method(node, "set_cell_item", si.position, si.new_value, si.new_orientation);879}880for (uint32_t i = set_items.size(); i > 0; i--) {881const SetItem &si = set_items[i - 1];882undo_redo->add_undo_method(node, "set_cell_item", si.position, si.old_value, si.old_orientation);883}884885undo_redo->commit_action();886}887set_items.clear();888input_action = INPUT_NONE;889890if (set_items.size() > 0) {891return EditorPlugin::AFTER_GUI_INPUT_STOP;892}893return EditorPlugin::AFTER_GUI_INPUT_PASS;894}895896if (mb->get_button_index() == MouseButton::LEFT && input_action == INPUT_SELECT) {897EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();898undo_redo->create_action(TTR("GridMap Selection"));899undo_redo->add_do_method(this, "_set_selection", selection.active, selection.begin, selection.end);900undo_redo->add_undo_method(this, "_set_selection", last_selection.active, last_selection.begin, last_selection.end);901undo_redo->commit_action();902}903904if (mb->get_button_index() == MouseButton::LEFT && input_action != INPUT_NONE) {905set_items.clear();906input_action = INPUT_NONE;907return EditorPlugin::AFTER_GUI_INPUT_STOP;908}909if (mb->get_button_index() == MouseButton::RIGHT && (input_action == INPUT_ERASE || input_action == INPUT_PASTE)) {910input_action = INPUT_NONE;911return EditorPlugin::AFTER_GUI_INPUT_STOP;912}913}914}915916Ref<InputEventMouseMotion> mm = p_event;917918if (mm.is_valid()) {919// Update the grid, to check if the grid needs to be moved to a tile cursor.920update_grid();921922if (do_input_action(p_camera, mm->get_position(), false)) {923return EditorPlugin::AFTER_GUI_INPUT_STOP;924}925return EditorPlugin::AFTER_GUI_INPUT_PASS;926}927928Ref<InputEventPanGesture> pan_gesture = p_event;929if (pan_gesture.is_valid()) {930if (pan_gesture->is_alt_pressed() && pan_gesture->is_command_or_control_pressed()) {931const real_t delta = pan_gesture->get_delta().y * 0.5;932accumulated_floor_delta += delta;933int step = 0;934if (Math::abs(accumulated_floor_delta) > 1.0) {935step = SIGN(accumulated_floor_delta);936accumulated_floor_delta -= step;937}938if (step) {939floor->set_value(floor->get_value() + step);940}941return EditorPlugin::AFTER_GUI_INPUT_STOP;942}943}944accumulated_floor_delta = 0.0;945946return EditorPlugin::AFTER_GUI_INPUT_PASS;947}948949struct _CGMEItemSort {950String name;951int id = 0;952_FORCE_INLINE_ bool operator<(const _CGMEItemSort &r_it) const { return name < r_it.name; }953};954955void GridMapEditor::_set_display_mode(int p_mode) {956if (display_mode == p_mode) {957return;958}959960if (p_mode == DISPLAY_LIST) {961mode_list->set_pressed(true);962mode_thumbnail->set_pressed(false);963} else if (p_mode == DISPLAY_THUMBNAIL) {964mode_list->set_pressed(false);965mode_thumbnail->set_pressed(true);966}967968display_mode = p_mode;969970update_palette();971}972973void GridMapEditor::_text_changed(const String &p_text) {974update_palette();975}976977void GridMapEditor::_mesh_library_palette_input(const Ref<InputEvent> &p_ie) {978const Ref<InputEventMouseButton> mb = p_ie;979980// Zoom in/out using Ctrl + mouse wheel981if (mb.is_valid() && mb->is_pressed() && mb->is_command_or_control_pressed()) {982if (mb->is_pressed() && mb->get_button_index() == MouseButton::WHEEL_UP) {983zoom_widget->set_zoom(zoom_widget->get_zoom() + 0.2);984zoom_widget->emit_signal(SNAME("zoom_changed"), zoom_widget->get_zoom());985}986987if (mb->is_pressed() && mb->get_button_index() == MouseButton::WHEEL_DOWN) {988zoom_widget->set_zoom(zoom_widget->get_zoom() - 0.2);989zoom_widget->emit_signal(SNAME("zoom_changed"), zoom_widget->get_zoom());990}991}992}993994void GridMapEditor::_icon_size_changed(float p_value) {995mesh_library_palette->set_icon_scale(p_value);996update_palette();997}998999void GridMapEditor::update_palette() {1000float min_size = EDITOR_GET("editors/grid_map/preview_size");1001min_size *= EDSCALE;10021003mesh_library_palette->clear();1004if (display_mode == DISPLAY_THUMBNAIL) {1005mesh_library_palette->set_max_columns(0);1006mesh_library_palette->set_icon_mode(ItemList::ICON_MODE_TOP);1007mesh_library_palette->set_fixed_column_width(min_size * MAX(zoom_widget->get_zoom(), 1.5));1008} else if (display_mode == DISPLAY_LIST) {1009mesh_library_palette->set_max_columns(0);1010mesh_library_palette->set_icon_mode(ItemList::ICON_MODE_LEFT);1011mesh_library_palette->set_fixed_column_width(0);1012}10131014mesh_library_palette->set_fixed_icon_size(Size2(min_size, min_size));1015mesh_library_palette->set_max_text_lines(2);10161017if (mesh_library.is_null()) {1018search_box->set_text("");1019search_box->set_editable(false);1020info_message->show();1021return;1022}10231024search_box->set_editable(true);1025info_message->hide();10261027Vector<int> ids;1028ids = mesh_library->get_item_list();10291030List<_CGMEItemSort> il;1031for (int i = 0; i < ids.size(); i++) {1032_CGMEItemSort is;1033is.id = ids[i];1034is.name = mesh_library->get_item_name(ids[i]);1035il.push_back(is);1036}1037il.sort();10381039String filter = search_box->get_text().strip_edges();10401041int item = 0;10421043for (_CGMEItemSort &E : il) {1044int id = E.id;1045String name = mesh_library->get_item_name(id);1046Ref<Texture2D> preview = mesh_library->get_item_preview(id);10471048if (name.is_empty()) {1049name = "#" + itos(id);1050}10511052if (!filter.is_empty() && !filter.is_subsequence_ofn(name)) {1053continue;1054}10551056mesh_library_palette->add_item("");1057if (preview.is_valid()) {1058mesh_library_palette->set_item_icon(item, preview);1059mesh_library_palette->set_item_tooltip(item, name);1060}1061mesh_library_palette->set_item_text(item, name);1062mesh_library_palette->set_item_metadata(item, id);10631064if (selected_palette == id) {1065mesh_library_palette->select(item);1066}10671068item++;1069}1070}10711072void GridMapEditor::_update_mesh_library() {1073ERR_FAIL_NULL(node);10741075Ref<MeshLibrary> new_mesh_library = node->get_mesh_library();1076if (new_mesh_library != mesh_library) {1077if (mesh_library.is_valid()) {1078mesh_library->disconnect_changed(callable_mp(this, &GridMapEditor::update_palette));1079}1080mesh_library = new_mesh_library;1081} else {1082return;1083}10841085if (mesh_library.is_valid()) {1086mesh_library->connect_changed(callable_mp(this, &GridMapEditor::update_palette));1087}10881089update_palette();1090// Make sure we select the first tile as default possible.1091if (mesh_library_palette->get_current() == -1 && mesh_library_palette->get_item_count() > 0) {1092mesh_library_palette->set_current(0);1093selected_palette = mesh_library_palette->get_item_metadata(0);1094}1095// Update the cursor and grid in case the library is changed or removed.1096_update_cursor_instance();1097update_grid();1098}10991100void GridMapEditor::edit(GridMap *p_gridmap) {1101if (node) {1102node->disconnect(SNAME("cell_size_changed"), callable_mp(this, &GridMapEditor::_draw_grids));1103node->disconnect(CoreStringName(changed), callable_mp(this, &GridMapEditor::_update_mesh_library));1104if (mesh_library.is_valid()) {1105mesh_library->disconnect_changed(callable_mp(this, &GridMapEditor::update_palette));1106mesh_library = Ref<MeshLibrary>();1107}1108}11091110_cancel_pending_move();11111112node = p_gridmap;11131114input_action = INPUT_NONE;1115selection.active = false;1116_update_selection_transform();1117_update_paste_indicator();11181119spatial_editor = Object::cast_to<Node3DEditorPlugin>(EditorNode::get_singleton()->get_editor_main_screen()->get_selected_plugin());11201121if (!node) {1122set_process(false);1123for (int i = 0; i < 3; i++) {1124RenderingServer::get_singleton()->instance_set_visible(grid_instance[i], false);1125}11261127if (cursor_instance.is_valid()) {1128RenderingServer::get_singleton()->instance_set_visible(cursor_instance, false);1129}11301131return;1132}11331134update_palette();1135_update_cursor_instance();11361137set_process(true);11381139_draw_grids(node->get_cell_size());1140update_grid();11411142node->connect(SNAME("cell_size_changed"), callable_mp(this, &GridMapEditor::_draw_grids));1143node->connect(CoreStringName(changed), callable_mp(this, &GridMapEditor::_update_mesh_library));1144_update_mesh_library();1145}11461147void GridMapEditor::update_grid() {1148grid_xform.origin.x -= 1; // Force update in hackish way.11491150grid_ofs[edit_axis] = edit_floor[edit_axis] * node->get_cell_size()[edit_axis];11511152// If there's a valid tile cursor, offset the grid, otherwise move it back to the node.1153edit_grid_xform.origin = cursor_instance.is_valid() ? grid_ofs : Vector3();1154edit_grid_xform.basis = Basis();11551156for (int i = 0; i < 3; i++) {1157RenderingServer::get_singleton()->instance_set_visible(grid_instance[i], i == edit_axis);1158}11591160updating = true;1161floor->set_value(edit_floor[edit_axis]);1162updating = false;1163}11641165void GridMapEditor::_draw_grids(const Vector3 &cell_size) {1166Vector3 edited_floor = node->get_meta("_editor_floor_", Vector3());11671168for (int i = 0; i < 3; i++) {1169RS::get_singleton()->mesh_clear(grid[i]);1170edit_floor[i] = edited_floor[i];1171}11721173Vector<Vector3> grid_points[3];1174Vector<Color> grid_colors[3];11751176for (int i = 0; i < 3; i++) {1177Vector3 axis;1178axis[i] = 1;1179Vector3 axis_n1;1180axis_n1[(i + 1) % 3] = cell_size[(i + 1) % 3];1181Vector3 axis_n2;1182axis_n2[(i + 2) % 3] = cell_size[(i + 2) % 3];11831184for (int j = -GRID_CURSOR_SIZE; j <= GRID_CURSOR_SIZE; j++) {1185for (int k = -GRID_CURSOR_SIZE; k <= GRID_CURSOR_SIZE; k++) {1186Vector3 p = axis_n1 * j + axis_n2 * k;1187float trans = Math::pow(MAX(0, 1.0 - (Vector2(j, k).length() / GRID_CURSOR_SIZE)), 2);11881189Vector3 pj = axis_n1 * (j + 1) + axis_n2 * k;1190float transj = Math::pow(MAX(0, 1.0 - (Vector2(j + 1, k).length() / GRID_CURSOR_SIZE)), 2);11911192Vector3 pk = axis_n1 * j + axis_n2 * (k + 1);1193float transk = Math::pow(MAX(0, 1.0 - (Vector2(j, k + 1).length() / GRID_CURSOR_SIZE)), 2);11941195grid_points[i].push_back(p);1196grid_points[i].push_back(pk);1197grid_colors[i].push_back(Color(1, 1, 1, trans));1198grid_colors[i].push_back(Color(1, 1, 1, transk));11991200grid_points[i].push_back(p);1201grid_points[i].push_back(pj);1202grid_colors[i].push_back(Color(1, 1, 1, trans));1203grid_colors[i].push_back(Color(1, 1, 1, transj));1204}1205}12061207Array d;1208d.resize(RS::ARRAY_MAX);1209d[RS::ARRAY_VERTEX] = grid_points[i];1210d[RS::ARRAY_COLOR] = grid_colors[i];1211RenderingServer::get_singleton()->mesh_add_surface_from_arrays(grid[i], RenderingServer::PRIMITIVE_LINES, d);1212RenderingServer::get_singleton()->mesh_surface_set_material(grid[i], 0, indicator_mat->get_rid());1213}1214}12151216void GridMapEditor::_update_theme() {1217transform_mode_button->set_button_icon(get_theme_icon(SNAME("ToolMove"), EditorStringName(EditorIcons)));1218select_mode_button->set_button_icon(get_theme_icon(SNAME("ToolSelect"), EditorStringName(EditorIcons)));1219erase_mode_button->set_button_icon(get_theme_icon(SNAME("Eraser"), EditorStringName(EditorIcons)));1220paint_mode_button->set_button_icon(get_theme_icon(SNAME("Paint"), EditorStringName(EditorIcons)));1221pick_mode_button->set_button_icon(get_theme_icon(SNAME("ColorPick"), EditorStringName(EditorIcons)));1222fill_action_button->set_button_icon(get_theme_icon(SNAME("Bucket"), EditorStringName(EditorIcons)));1223move_action_button->set_button_icon(get_theme_icon(SNAME("ActionCut"), EditorStringName(EditorIcons)));1224duplicate_action_button->set_button_icon(get_theme_icon(SNAME("ActionCopy"), EditorStringName(EditorIcons)));1225delete_action_button->set_button_icon(get_theme_icon(SNAME("Clear"), EditorStringName(EditorIcons)));1226rotate_x_button->set_button_icon(get_theme_icon(SNAME("RotateLeft"), EditorStringName(EditorIcons)));1227rotate_y_button->set_button_icon(get_theme_icon(SNAME("ToolRotate"), EditorStringName(EditorIcons)));1228rotate_z_button->set_button_icon(get_theme_icon(SNAME("RotateRight"), EditorStringName(EditorIcons)));1229mode_thumbnail->set_button_icon(get_theme_icon(SNAME("FileThumbnail"), EditorStringName(EditorIcons)));1230mode_list->set_button_icon(get_theme_icon(SNAME("FileList"), EditorStringName(EditorIcons)));1231options->set_button_icon(get_theme_icon(SNAME("Tools"), EditorStringName(EditorIcons)));1232}12331234void GridMapEditor::_notification(int p_what) {1235switch (p_what) {1236case NOTIFICATION_ENTER_TREE: {1237const RID scenario = get_tree()->get_root()->get_world_3d()->get_scenario();12381239for (int i = 0; i < 3; i++) {1240grid[i] = RS::get_singleton()->mesh_create();1241grid_instance[i] = RS::get_singleton()->instance_create2(grid[i], scenario);1242RenderingServer::get_singleton()->instance_set_layer_mask(grid_instance[i], 1 << Node3DEditorViewport::MISC_TOOL_LAYER);1243selection_level_instance[i] = RenderingServer::get_singleton()->instance_create2(selection_level_mesh[i], scenario);1244RenderingServer::get_singleton()->instance_set_layer_mask(selection_level_instance[i], 1 << Node3DEditorViewport::MISC_TOOL_LAYER);1245}12461247cursor_instance = RenderingServer::get_singleton()->instance_create2(cursor_mesh, scenario);1248RenderingServer::get_singleton()->instance_set_layer_mask(cursor_instance, 1 << Node3DEditorViewport::MISC_TOOL_LAYER);1249RenderingServer::get_singleton()->instance_set_visible(cursor_instance, false);1250selection_instance = RenderingServer::get_singleton()->instance_create2(selection_mesh, scenario);1251RenderingServer::get_singleton()->instance_set_layer_mask(selection_instance, 1 << Node3DEditorViewport::MISC_TOOL_LAYER);1252paste_instance = RenderingServer::get_singleton()->instance_create2(paste_mesh, scenario);1253RenderingServer::get_singleton()->instance_set_layer_mask(paste_instance, 1 << Node3DEditorViewport::MISC_TOOL_LAYER);12541255_update_selection_transform();1256_update_paste_indicator();1257_update_theme();1258} break;12591260case NOTIFICATION_EXIT_TREE: {1261_cancel_pending_move();1262_clear_clipboard_data();12631264for (int i = 0; i < 3; i++) {1265RS::get_singleton()->free_rid(grid_instance[i]);1266RS::get_singleton()->free_rid(grid[i]);1267grid_instance[i] = RID();1268grid[i] = RID();1269RenderingServer::get_singleton()->free_rid(selection_level_instance[i]);1270}12711272RenderingServer::get_singleton()->free_rid(cursor_instance);1273RenderingServer::get_singleton()->free_rid(selection_instance);1274RenderingServer::get_singleton()->free_rid(paste_instance);1275cursor_instance = RID();1276selection_instance = RID();1277paste_instance = RID();1278} break;12791280case NOTIFICATION_PROCESS: {1281if (!node) {1282return;1283}12841285Transform3D xf = node->get_global_transform();12861287if (xf != grid_xform) {1288for (int i = 0; i < 3; i++) {1289RS::get_singleton()->instance_set_transform(grid_instance[i], xf * edit_grid_xform);1290}1291grid_xform = xf;1292_update_cursor_transform();1293_update_selection_transform();1294}1295} break;12961297case NOTIFICATION_THEME_CHANGED: {1298_update_theme();1299} break;13001301case NOTIFICATION_APPLICATION_FOCUS_OUT: {1302if (input_action == INPUT_PAINT) {1303// Simulate mouse released event to stop drawing when editor focus exists.1304Ref<InputEventMouseButton> release;1305release.instantiate();1306release->set_button_index(MouseButton::LEFT);1307forward_spatial_input_event(nullptr, release);1308}1309} break;13101311case EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED: {1312indicator_mat->set_albedo(EDITOR_GET("editors/3d_gizmos/gizmo_colors/gridmap_grid"));13131314// Take Preview Size changes into account.1315update_palette();1316} break;1317}1318}13191320void GridMapEditor::_update_cursor_instance() {1321if (!node) {1322return;1323}13241325if (cursor_instance.is_valid()) {1326RenderingServer::get_singleton()->free_rid(cursor_instance);1327}1328cursor_instance = RID();13291330const RID scenario = get_tree()->get_root()->get_world_3d()->get_scenario();13311332if (mode_buttons_group->get_pressed_button() == paint_mode_button) {1333if (selected_palette >= 0 && node && node->get_mesh_library().is_valid()) {1334Ref<Mesh> mesh = node->get_mesh_library()->get_item_mesh(selected_palette);1335if (mesh.is_valid() && mesh->get_rid().is_valid()) {1336cursor_instance = RenderingServer::get_singleton()->instance_create2(mesh->get_rid(), scenario);1337RS::ShadowCastingSetting cast_shadows = (RS::ShadowCastingSetting)node->get_mesh_library()->get_item_mesh_cast_shadow(selected_palette);1338RS::get_singleton()->instance_geometry_set_cast_shadows_setting(cursor_instance, cast_shadows);1339}1340}1341} else if (mode_buttons_group->get_pressed_button() == select_mode_button) {1342cursor_inner_mat->set_albedo(Color(default_color, 0.2));1343cursor_outer_mat->set_albedo(Color(default_color, 0.8));1344cursor_instance = RenderingServer::get_singleton()->instance_create2(cursor_mesh, scenario);1345} else if (mode_buttons_group->get_pressed_button() == erase_mode_button) {1346cursor_inner_mat->set_albedo(Color(erase_color, 0.2));1347cursor_outer_mat->set_albedo(Color(erase_color, 0.8));1348cursor_instance = RenderingServer::get_singleton()->instance_create2(cursor_mesh, scenario);1349} else if (mode_buttons_group->get_pressed_button() == pick_mode_button) {1350cursor_inner_mat->set_albedo(Color(pick_color, 0.2));1351cursor_outer_mat->set_albedo(Color(pick_color, 0.8));1352cursor_instance = RenderingServer::get_singleton()->instance_create2(cursor_mesh, scenario);1353}13541355if (cursor_instance.is_valid()) {1356// Make the cursor translucent so that it can be distinguished from already-placed tiles.1357RenderingServer::get_singleton()->instance_geometry_set_transparency(cursor_instance, 0.5);1358}1359_update_cursor_transform();1360}13611362void GridMapEditor::_on_tool_mode_changed() {1363_show_viewports_transform_gizmo(mode_buttons_group->get_pressed_button() == transform_mode_button);1364_update_cursor_instance();1365}13661367void GridMapEditor::_item_selected_cbk(int idx) {1368selected_palette = mesh_library_palette->get_item_metadata(idx);13691370_update_cursor_instance();1371}13721373void GridMapEditor::_floor_changed(float p_value) {1374if (updating) {1375return;1376}13771378edit_floor[edit_axis] = p_value;1379node->set_meta("_editor_floor_", Vector3(edit_floor[0], edit_floor[1], edit_floor[2]));1380update_grid();1381_update_selection_transform();1382}13831384void GridMapEditor::_floor_mouse_exited() {1385floor->get_line_edit()->release_focus();1386}13871388void GridMapEditor::_bind_methods() {1389ClassDB::bind_method("_configure", &GridMapEditor::_configure);1390ClassDB::bind_method("_set_selection", &GridMapEditor::_set_selection);1391}13921393GridMapEditor::GridMapEditor() {1394ED_SHORTCUT("grid_map/previous_floor", TTRC("Previous Floor"), Key::KEY_1, true);1395ED_SHORTCUT("grid_map/next_floor", TTRC("Next Floor"), Key::KEY_3, true);1396ED_SHORTCUT("grid_map/edit_x_axis", TTRC("Edit X Axis"), KeyModifierMask::SHIFT + Key::Z, true);1397ED_SHORTCUT("grid_map/edit_y_axis", TTRC("Edit Y Axis"), KeyModifierMask::SHIFT + Key::X, true);1398ED_SHORTCUT("grid_map/edit_z_axis", TTRC("Edit Z Axis"), KeyModifierMask::SHIFT + Key::C, true);1399ED_SHORTCUT("grid_map/keep_selected", TTRC("Keep Selection"));1400ED_SHORTCUT("grid_map/clear_rotation", TTRC("Clear Rotation"));14011402options = memnew(MenuButton);1403options->set_theme_type_variation(SceneStringName(FlatButton));1404options->get_popup()->add_separator();1405options->get_popup()->add_radio_check_shortcut(ED_GET_SHORTCUT("grid_map/edit_x_axis"), MENU_OPTION_X_AXIS);1406options->get_popup()->add_radio_check_shortcut(ED_GET_SHORTCUT("grid_map/edit_y_axis"), MENU_OPTION_Y_AXIS);1407options->get_popup()->add_radio_check_shortcut(ED_GET_SHORTCUT("grid_map/edit_z_axis"), MENU_OPTION_Z_AXIS);1408options->get_popup()->set_item_checked(options->get_popup()->get_item_index(MENU_OPTION_Y_AXIS), true);1409options->get_popup()->add_separator();1410// TRANSLATORS: This is a toggle to select after pasting the new content.1411options->get_popup()->add_shortcut(ED_GET_SHORTCUT("grid_map/clear_rotation"), MENU_OPTION_CURSOR_CLEAR_ROTATION);1412options->get_popup()->add_check_shortcut(ED_GET_SHORTCUT("grid_map/keep_selected"), MENU_OPTION_PASTE_SELECTS);1413options->get_popup()->set_item_checked(options->get_popup()->get_item_index(MENU_OPTION_PASTE_SELECTS), true);1414options->get_popup()->add_separator();1415options->get_popup()->add_item(TTR("Settings..."), MENU_OPTION_GRIDMAP_SETTINGS);14161417settings_dialog = memnew(ConfirmationDialog);1418settings_dialog->set_title(TTR("GridMap Settings"));1419add_child(settings_dialog);1420settings_vbc = memnew(VBoxContainer);1421settings_vbc->set_custom_minimum_size(Size2(200, 0) * EDSCALE);1422settings_dialog->add_child(settings_vbc);14231424settings_pick_distance = memnew(SpinBox);1425settings_pick_distance->set_max(10000.0f);1426settings_pick_distance->set_min(500.0f);1427settings_pick_distance->set_step(1.0f);1428settings_pick_distance->set_value(EDITOR_GET("editors/grid_map/pick_distance"));1429settings_pick_distance->set_accessibility_name(TTRC("Pick Distance:"));1430settings_vbc->add_margin_child(TTR("Pick Distance:"), settings_pick_distance);14311432options->get_popup()->connect(SceneStringName(id_pressed), callable_mp(this, &GridMapEditor::_menu_option));14331434toolbar = memnew(HBoxContainer);1435add_child(toolbar);1436toolbar->set_h_size_flags(SIZE_EXPAND_FILL);14371438HBoxContainer *mode_buttons = memnew(HBoxContainer);1439toolbar->add_child(mode_buttons);1440mode_buttons_group.instantiate();14411442viewport_shortcut_buttons.reserve(12);14431444transform_mode_button = memnew(Button);1445transform_mode_button->set_theme_type_variation(SceneStringName(FlatButton));1446transform_mode_button->set_toggle_mode(true);1447transform_mode_button->set_button_group(mode_buttons_group);1448transform_mode_button->set_shortcut(ED_SHORTCUT("grid_map/transform_tool", TTRC("Transform"), Key::T, true));1449transform_mode_button->set_accessibility_name(TTRC("Transform"));1450transform_mode_button->connect(SceneStringName(toggled),1451callable_mp(this, &GridMapEditor::_on_tool_mode_changed).unbind(1));1452mode_buttons->add_child(transform_mode_button);1453viewport_shortcut_buttons.push_back(transform_mode_button);1454VSeparator *vsep = memnew(VSeparator);1455mode_buttons->add_child(vsep);14561457select_mode_button = memnew(Button);1458select_mode_button->set_theme_type_variation(SceneStringName(FlatButton));1459select_mode_button->set_toggle_mode(true);1460select_mode_button->set_button_group(mode_buttons_group);1461select_mode_button->set_shortcut(ED_SHORTCUT("grid_map/selection_tool", TTRC("Selection"), Key::Q, true));1462select_mode_button->set_accessibility_name(TTRC("Selection"));1463select_mode_button->connect(SceneStringName(toggled),1464callable_mp(this, &GridMapEditor::_on_tool_mode_changed).unbind(1));1465mode_buttons->add_child(select_mode_button);1466viewport_shortcut_buttons.push_back(select_mode_button);14671468erase_mode_button = memnew(Button);1469erase_mode_button->set_theme_type_variation(SceneStringName(FlatButton));1470erase_mode_button->set_toggle_mode(true);1471erase_mode_button->set_button_group(mode_buttons_group);1472erase_mode_button->set_shortcut(ED_SHORTCUT("grid_map/erase_tool", TTRC("Erase"), Key::W, true));1473erase_mode_button->set_accessibility_name(TTRC("Erase"));1474mode_buttons->add_child(erase_mode_button);1475erase_mode_button->connect(SceneStringName(toggled),1476callable_mp(this, &GridMapEditor::_on_tool_mode_changed).unbind(1));1477viewport_shortcut_buttons.push_back(erase_mode_button);14781479paint_mode_button = memnew(Button);1480paint_mode_button->set_theme_type_variation(SceneStringName(FlatButton));1481paint_mode_button->set_toggle_mode(true);1482paint_mode_button->set_button_group(mode_buttons_group);1483paint_mode_button->set_shortcut(ED_SHORTCUT("grid_map/paint_tool", TTRC("Paint"), Key::E, true));1484paint_mode_button->set_accessibility_name(TTRC("Paint"));1485paint_mode_button->connect(SceneStringName(toggled),1486callable_mp(this, &GridMapEditor::_on_tool_mode_changed).unbind(1));1487mode_buttons->add_child(paint_mode_button);1488viewport_shortcut_buttons.push_back(paint_mode_button);14891490pick_mode_button = memnew(Button);1491pick_mode_button->set_theme_type_variation(SceneStringName(FlatButton));1492pick_mode_button->set_toggle_mode(true);1493pick_mode_button->set_button_group(mode_buttons_group);1494pick_mode_button->set_shortcut(ED_SHORTCUT("grid_map/pick_tool", TTRC("Pick"), Key::R, true));1495pick_mode_button->set_accessibility_name(TTRC("Pick"));1496pick_mode_button->connect(SceneStringName(toggled),1497callable_mp(this, &GridMapEditor::_on_tool_mode_changed).unbind(1));1498mode_buttons->add_child(pick_mode_button);1499viewport_shortcut_buttons.push_back(pick_mode_button);15001501vsep = memnew(VSeparator);1502toolbar->add_child(vsep);15031504HBoxContainer *action_buttons = memnew(HBoxContainer);1505toolbar->add_child(action_buttons);15061507fill_action_button = memnew(Button);1508fill_action_button->set_theme_type_variation(SceneStringName(FlatButton));1509fill_action_button->set_shortcut(ED_SHORTCUT("grid_map/fill_tool", TTRC("Fill"), Key::Z, true));1510fill_action_button->set_accessibility_name(TTRC("Fill"));1511fill_action_button->connect(SceneStringName(pressed),1512callable_mp(this, &GridMapEditor::_menu_option).bind(MENU_OPTION_SELECTION_FILL));1513action_buttons->add_child(fill_action_button);1514viewport_shortcut_buttons.push_back(fill_action_button);15151516move_action_button = memnew(Button);1517move_action_button->set_theme_type_variation(SceneStringName(FlatButton));1518move_action_button->set_shortcut(ED_SHORTCUT("grid_map/move_tool", TTRC("Move"), Key::X, true));1519fill_action_button->set_accessibility_name(TTRC("Move"));1520move_action_button->connect(SceneStringName(pressed),1521callable_mp(this, &GridMapEditor::_menu_option).bind(MENU_OPTION_SELECTION_MOVE));1522action_buttons->add_child(move_action_button);1523viewport_shortcut_buttons.push_back(move_action_button);15241525duplicate_action_button = memnew(Button);1526duplicate_action_button->set_theme_type_variation(SceneStringName(FlatButton));1527duplicate_action_button->set_shortcut(ED_SHORTCUT("grid_map/duplicate_tool", TTRC("Duplicate"), Key::C, true));1528duplicate_action_button->set_accessibility_name(TTRC("Duplicate"));1529duplicate_action_button->connect(SceneStringName(pressed),1530callable_mp(this, &GridMapEditor::_menu_option).bind(MENU_OPTION_SELECTION_DUPLICATE));1531action_buttons->add_child(duplicate_action_button);1532viewport_shortcut_buttons.push_back(duplicate_action_button);15331534delete_action_button = memnew(Button);1535delete_action_button->set_theme_type_variation(SceneStringName(FlatButton));1536delete_action_button->set_shortcut(ED_SHORTCUT("grid_map/delete_tool", TTRC("Delete"), Key::V, true));1537delete_action_button->set_accessibility_name(TTRC("Delete"));1538delete_action_button->connect(SceneStringName(pressed),1539callable_mp(this, &GridMapEditor::_menu_option).bind(MENU_OPTION_SELECTION_CLEAR));1540action_buttons->add_child(delete_action_button);1541viewport_shortcut_buttons.push_back(delete_action_button);15421543vsep = memnew(VSeparator);1544toolbar->add_child(vsep);15451546HBoxContainer *rotation_buttons = memnew(HBoxContainer);1547toolbar->add_child(rotation_buttons);15481549rotate_x_button = memnew(Button);1550rotate_x_button->set_theme_type_variation(SceneStringName(FlatButton));1551rotate_x_button->set_shortcut(ED_SHORTCUT("grid_map/cursor_rotate_x", TTRC("Cursor Rotate X"), Key::A, true));1552rotate_x_button->set_accessibility_name(TTRC("Cursor Rotate X"));1553rotate_x_button->connect(SceneStringName(pressed),1554callable_mp(this, &GridMapEditor::_menu_option).bind(MENU_OPTION_CURSOR_ROTATE_X));1555rotation_buttons->add_child(rotate_x_button);1556viewport_shortcut_buttons.push_back(rotate_x_button);15571558rotate_y_button = memnew(Button);1559rotate_y_button->set_theme_type_variation(SceneStringName(FlatButton));1560rotate_y_button->set_shortcut(ED_SHORTCUT("grid_map/cursor_rotate_y", TTRC("Cursor Rotate Y"), Key::S, true));1561rotate_y_button->set_accessibility_name(TTRC("Cursor Rotate Y"));1562rotate_y_button->connect(SceneStringName(pressed),1563callable_mp(this, &GridMapEditor::_menu_option).bind(MENU_OPTION_CURSOR_ROTATE_Y));1564rotation_buttons->add_child(rotate_y_button);1565viewport_shortcut_buttons.push_back(rotate_y_button);15661567rotate_z_button = memnew(Button);1568rotate_z_button->set_theme_type_variation(SceneStringName(FlatButton));1569rotate_z_button->set_shortcut(ED_SHORTCUT("grid_map/cursor_rotate_z", TTRC("Cursor Rotate Z"), Key::D, true));1570rotate_z_button->set_accessibility_name(TTRC("Cursor Rotate Z"));1571rotate_z_button->connect(SceneStringName(pressed),1572callable_mp(this, &GridMapEditor::_menu_option).bind(MENU_OPTION_CURSOR_ROTATE_Z));1573rotation_buttons->add_child(rotate_z_button);1574viewport_shortcut_buttons.push_back(rotate_z_button);15751576// Wide empty separation control. (like BoxContainer::add_spacer())1577Control *c = memnew(Control);1578c->set_mouse_filter(MOUSE_FILTER_PASS);1579c->set_h_size_flags(SIZE_EXPAND_FILL);1580toolbar->add_child(c);15811582floor = memnew(SpinBox);1583floor->set_min(-32767);1584floor->set_max(32767);1585floor->set_step(1);1586floor->set_accessibility_name(TTRC("Change Grid Floor:"));1587floor->set_tooltip_text(1588vformat(TTR("Change Grid Floor:\nPrevious Plane (%s)\nNext Plane (%s)"),1589ED_GET_SHORTCUT("grid_map/previous_floor")->get_as_text(),1590ED_GET_SHORTCUT("grid_map/next_floor")->get_as_text()));1591toolbar->add_child(floor);1592floor->get_line_edit()->add_theme_constant_override("minimum_character_width", 2);1593floor->get_line_edit()->set_context_menu_enabled(false);1594floor->connect(SceneStringName(value_changed), callable_mp(this, &GridMapEditor::_floor_changed));1595floor->connect(SceneStringName(mouse_exited), callable_mp(this, &GridMapEditor::_floor_mouse_exited));1596floor->get_line_edit()->connect(SceneStringName(mouse_exited), callable_mp(this, &GridMapEditor::_floor_mouse_exited));15971598search_box = memnew(FilterLineEdit);1599search_box->add_theme_constant_override("minimum_character_width", 10);1600search_box->set_h_size_flags(SIZE_EXPAND_FILL);1601search_box->set_placeholder(TTR("Filter Meshes"));1602search_box->set_accessibility_name(TTRC("Filter Meshes"));1603toolbar->add_child(search_box);1604search_box->connect(SceneStringName(text_changed), callable_mp(this, &GridMapEditor::_text_changed));16051606zoom_widget = memnew(EditorZoomWidget);1607toolbar->add_child(zoom_widget);1608zoom_widget->setup_zoom_limits(0.2, 4);1609zoom_widget->set_zoom(1.0);1610zoom_widget->set_anchors_and_offsets_preset(Control::PRESET_TOP_LEFT, Control::PRESET_MODE_MINSIZE, 2 * EDSCALE);1611zoom_widget->connect("zoom_changed", callable_mp(this, &GridMapEditor::_icon_size_changed));1612zoom_widget->set_shortcut_context(this);16131614mode_thumbnail = memnew(Button);1615mode_thumbnail->set_theme_type_variation(SceneStringName(FlatButton));1616mode_thumbnail->set_toggle_mode(true);1617mode_thumbnail->set_accessibility_name(TTRC("View as Thumbnails"));1618mode_thumbnail->set_pressed(true);1619toolbar->add_child(mode_thumbnail);1620mode_thumbnail->connect(SceneStringName(pressed), callable_mp(this, &GridMapEditor::_set_display_mode).bind(DISPLAY_THUMBNAIL));16211622mode_list = memnew(Button);1623mode_list->set_theme_type_variation(SceneStringName(FlatButton));1624mode_list->set_toggle_mode(true);1625mode_list->set_accessibility_name(TTRC("View as List"));1626mode_list->set_pressed(false);1627toolbar->add_child(mode_list);1628mode_list->connect(SceneStringName(pressed), callable_mp(this, &GridMapEditor::_set_display_mode).bind(DISPLAY_LIST));16291630toolbar->add_child(options);16311632MarginContainer *mc = memnew(MarginContainer);1633mc->set_theme_type_variation("NoBorderBottomPanel");1634mc->set_v_size_flags(SIZE_EXPAND_FILL);1635add_child(mc);16361637mesh_library_palette = memnew(ItemList);1638search_box->set_forward_control(mesh_library_palette);1639mesh_library_palette->set_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED);1640mesh_library_palette->set_scroll_hint_mode(ItemList::SCROLL_HINT_MODE_BOTH);1641mc->add_child(mesh_library_palette);1642mesh_library_palette->connect(SceneStringName(gui_input), callable_mp(this, &GridMapEditor::_mesh_library_palette_input));1643mesh_library_palette->connect(SceneStringName(item_selected), callable_mp(this, &GridMapEditor::_item_selected_cbk));16441645info_message = memnew(Label);1646info_message->set_focus_mode(FOCUS_ACCESSIBILITY);1647info_message->set_text(TTR("Give a MeshLibrary resource to this GridMap to use its meshes."));1648info_message->set_vertical_alignment(VERTICAL_ALIGNMENT_CENTER);1649info_message->set_horizontal_alignment(HORIZONTAL_ALIGNMENT_CENTER);1650info_message->set_autowrap_mode(TextServer::AUTOWRAP_WORD_SMART);1651info_message->set_custom_minimum_size(Size2(100 * EDSCALE, 0));1652info_message->set_anchors_and_offsets_preset(PRESET_FULL_RECT, PRESET_MODE_KEEP_SIZE, 8 * EDSCALE);1653mesh_library_palette->add_child(info_message);16541655edit_axis = Vector3::AXIS_Y;1656edit_floor[0] = -1;1657edit_floor[1] = -1;1658edit_floor[2] = -1;16591660cursor_mesh = RenderingServer::get_singleton()->mesh_create();1661selection_mesh = RenderingServer::get_singleton()->mesh_create();1662paste_mesh = RenderingServer::get_singleton()->mesh_create();16631664{1665// Selection mesh create.16661667Vector<Vector3> lines;1668Vector<Vector3> triangles;1669Vector<Vector3> square[3];16701671for (int i = 0; i < 6; i++) {1672Vector3 face_points[4];16731674for (int j = 0; j < 4; j++) {1675float v[3];1676v[0] = 1.0;1677v[1] = 1 - 2 * ((j >> 1) & 1);1678v[2] = v[1] * (1 - 2 * (j & 1));16791680for (int k = 0; k < 3; k++) {1681if (i < 3) {1682face_points[j][(i + k) % 3] = v[k];1683} else {1684face_points[3 - j][(i + k) % 3] = -v[k];1685}1686}1687}16881689triangles.push_back(face_points[0] * 0.5 + Vector3(0.5, 0.5, 0.5));1690triangles.push_back(face_points[1] * 0.5 + Vector3(0.5, 0.5, 0.5));1691triangles.push_back(face_points[2] * 0.5 + Vector3(0.5, 0.5, 0.5));16921693triangles.push_back(face_points[2] * 0.5 + Vector3(0.5, 0.5, 0.5));1694triangles.push_back(face_points[3] * 0.5 + Vector3(0.5, 0.5, 0.5));1695triangles.push_back(face_points[0] * 0.5 + Vector3(0.5, 0.5, 0.5));1696}16971698for (int i = 0; i < 12; i++) {1699AABB base(Vector3(0, 0, 0), Vector3(1, 1, 1));1700Vector3 a, b;1701base.get_edge(i, a, b);1702lines.push_back(a);1703lines.push_back(b);1704}17051706for (int i = 0; i < 3; i++) {1707Vector3 points[4];1708for (int j = 0; j < 4; j++) {1709static const bool orderx[4] = { false, true, true, false };1710static const bool ordery[4] = { false, false, true, true };17111712Vector3 sp;1713if (orderx[j]) {1714sp[(i + 1) % 3] = 1.0;1715}1716if (ordery[j]) {1717sp[(i + 2) % 3] = 1.0;1718}17191720points[j] = sp;1721}17221723for (int j = 0; j < 4; j++) {1724Vector3 ofs;1725ofs[i] += 0.01;1726square[i].push_back(points[j] - ofs);1727square[i].push_back(points[(j + 1) % 4] - ofs);1728square[i].push_back(points[j] + ofs);1729square[i].push_back(points[(j + 1) % 4] + ofs);1730}1731}17321733Array d;1734d.resize(RS::ARRAY_MAX);17351736default_color = Color(0.0, 0.565, 1.0); // blue 0.7, 0.7, 1.01737erase_color = Color(1.0, 0.2, 0.2); // red1738pick_color = Color(1, 0.7, 0); // orange/yellow17391740cursor_inner_mat.instantiate();1741cursor_inner_mat->set_albedo(Color(default_color, 0.2));1742cursor_inner_mat->set_shading_mode(StandardMaterial3D::SHADING_MODE_UNSHADED);1743cursor_inner_mat->set_flag(StandardMaterial3D::FLAG_DISABLE_FOG, true);1744cursor_inner_mat->set_transparency(StandardMaterial3D::TRANSPARENCY_ALPHA);17451746cursor_outer_mat.instantiate();1747cursor_outer_mat->set_albedo(Color(default_color, 0.8));1748cursor_outer_mat->set_on_top_of_alpha();1749cursor_outer_mat->set_shading_mode(StandardMaterial3D::SHADING_MODE_UNSHADED);1750cursor_outer_mat->set_transparency(StandardMaterial3D::TRANSPARENCY_ALPHA);1751cursor_outer_mat->set_flag(StandardMaterial3D::FLAG_DISABLE_FOG, true);17521753inner_mat.instantiate();1754inner_mat->set_albedo(Color(default_color, 0.2));1755inner_mat->set_shading_mode(StandardMaterial3D::SHADING_MODE_UNSHADED);1756inner_mat->set_flag(StandardMaterial3D::FLAG_DISABLE_FOG, true);1757inner_mat->set_transparency(StandardMaterial3D::TRANSPARENCY_ALPHA);17581759outer_mat.instantiate();1760outer_mat->set_albedo(Color(default_color, 0.8));1761outer_mat->set_on_top_of_alpha();1762outer_mat->set_shading_mode(StandardMaterial3D::SHADING_MODE_UNSHADED);1763outer_mat->set_transparency(StandardMaterial3D::TRANSPARENCY_ALPHA);1764outer_mat->set_flag(StandardMaterial3D::FLAG_DISABLE_FOG, true);17651766selection_floor_mat.instantiate();1767selection_floor_mat->set_albedo(Color(0.80, 0.80, 1.0, 1));1768selection_floor_mat->set_on_top_of_alpha();1769selection_floor_mat->set_shading_mode(StandardMaterial3D::SHADING_MODE_UNSHADED);1770selection_floor_mat->set_flag(StandardMaterial3D::FLAG_DISABLE_FOG, true);17711772d[RS::ARRAY_VERTEX] = triangles;1773RenderingServer::get_singleton()->mesh_add_surface_from_arrays(cursor_mesh, RS::PRIMITIVE_TRIANGLES, d);1774RenderingServer::get_singleton()->mesh_surface_set_material(cursor_mesh, 0, cursor_inner_mat->get_rid());17751776d[RS::ARRAY_VERTEX] = lines;1777RenderingServer::get_singleton()->mesh_add_surface_from_arrays(cursor_mesh, RS::PRIMITIVE_LINES, d);1778RenderingServer::get_singleton()->mesh_surface_set_material(cursor_mesh, 1, cursor_outer_mat->get_rid());17791780d[RS::ARRAY_VERTEX] = triangles;1781RenderingServer::get_singleton()->mesh_add_surface_from_arrays(selection_mesh, RS::PRIMITIVE_TRIANGLES, d);1782RenderingServer::get_singleton()->mesh_surface_set_material(selection_mesh, 0, inner_mat->get_rid());17831784d[RS::ARRAY_VERTEX] = lines;1785RenderingServer::get_singleton()->mesh_add_surface_from_arrays(selection_mesh, RS::PRIMITIVE_LINES, d);1786RenderingServer::get_singleton()->mesh_surface_set_material(selection_mesh, 1, outer_mat->get_rid());17871788d[RS::ARRAY_VERTEX] = triangles;1789RenderingServer::get_singleton()->mesh_add_surface_from_arrays(paste_mesh, RS::PRIMITIVE_TRIANGLES, d);1790RenderingServer::get_singleton()->mesh_surface_set_material(paste_mesh, 0, inner_mat->get_rid());17911792d[RS::ARRAY_VERTEX] = lines;1793RenderingServer::get_singleton()->mesh_add_surface_from_arrays(paste_mesh, RS::PRIMITIVE_LINES, d);1794RenderingServer::get_singleton()->mesh_surface_set_material(paste_mesh, 1, outer_mat->get_rid());17951796for (int i = 0; i < 3; i++) {1797d[RS::ARRAY_VERTEX] = square[i];1798selection_level_mesh[i] = RS::get_singleton()->mesh_create();1799RenderingServer::get_singleton()->mesh_add_surface_from_arrays(selection_level_mesh[i], RS::PRIMITIVE_LINES, d);1800RenderingServer::get_singleton()->mesh_surface_set_material(selection_level_mesh[i], 0, selection_floor_mat->get_rid());1801}1802}18031804_set_selection(false);18051806indicator_mat.instantiate();1807indicator_mat->set_shading_mode(StandardMaterial3D::SHADING_MODE_UNSHADED);1808indicator_mat->set_transparency(StandardMaterial3D::TRANSPARENCY_ALPHA);1809indicator_mat->set_flag(StandardMaterial3D::FLAG_SRGB_VERTEX_COLOR, true);1810indicator_mat->set_flag(StandardMaterial3D::FLAG_ALBEDO_FROM_VERTEX_COLOR, true);1811indicator_mat->set_flag(StandardMaterial3D::FLAG_DISABLE_FOG, true);1812indicator_mat->set_albedo(EDITOR_GET("editors/3d_gizmos/gizmo_colors/gridmap_grid"));1813}18141815GridMapEditor::~GridMapEditor() {1816ERR_FAIL_NULL(RenderingServer::get_singleton());1817_clear_clipboard_data();18181819for (int i = 0; i < 3; i++) {1820if (grid[i].is_valid()) {1821RenderingServer::get_singleton()->free_rid(grid[i]);1822}1823if (grid_instance[i].is_valid()) {1824RenderingServer::get_singleton()->free_rid(grid_instance[i]);1825}1826if (selection_level_instance[i].is_valid()) {1827RenderingServer::get_singleton()->free_rid(selection_level_instance[i]);1828}1829if (selection_level_mesh[i].is_valid()) {1830RenderingServer::get_singleton()->free_rid(selection_level_mesh[i]);1831}1832}18331834RenderingServer::get_singleton()->free_rid(cursor_mesh);1835if (cursor_instance.is_valid()) {1836RenderingServer::get_singleton()->free_rid(cursor_instance);1837}18381839RenderingServer::get_singleton()->free_rid(selection_mesh);1840if (selection_instance.is_valid()) {1841RenderingServer::get_singleton()->free_rid(selection_instance);1842}18431844RenderingServer::get_singleton()->free_rid(paste_mesh);1845if (paste_instance.is_valid()) {1846RenderingServer::get_singleton()->free_rid(paste_instance);1847}1848}18491850void GridMapEditorPlugin::_notification(int p_what) {1851switch (p_what) {1852case NOTIFICATION_ENTER_TREE: {1853grid_map_editor = memnew(GridMapEditor);1854grid_map_editor->set_h_size_flags(Control::SIZE_EXPAND_FILL);1855grid_map_editor->set_v_size_flags(Control::SIZE_EXPAND_FILL);1856grid_map_editor->set_custom_minimum_size(Size2(0, 200) * EDSCALE);1857grid_map_editor->hide();18581859panel_button = EditorNode::get_bottom_panel()->add_item(TTRC("GridMap"), grid_map_editor, ED_SHORTCUT_AND_COMMAND("bottom_panels/toggle_grid_map_bottom_panel", TTRC("Toggle GridMap Bottom Panel")));1860panel_button->hide();1861} break;1862case NOTIFICATION_EXIT_TREE: {1863EditorNode::get_bottom_panel()->remove_item(grid_map_editor);1864memdelete_notnull(grid_map_editor);1865grid_map_editor = nullptr;1866panel_button = nullptr;1867} break;1868}1869}18701871void GridMapEditorPlugin::_bind_methods() {1872ClassDB::bind_method(D_METHOD("get_current_grid_map"), &GridMapEditorPlugin::get_current_grid_map);1873ClassDB::bind_method(D_METHOD("set_selection", "begin", "end"), &GridMapEditorPlugin::set_selection);1874ClassDB::bind_method(D_METHOD("clear_selection"), &GridMapEditorPlugin::clear_selection);1875ClassDB::bind_method(D_METHOD("get_selection"), &GridMapEditorPlugin::get_selection);1876ClassDB::bind_method(D_METHOD("has_selection"), &GridMapEditorPlugin::has_selection);1877ClassDB::bind_method(D_METHOD("get_selected_cells"), &GridMapEditorPlugin::get_selected_cells);1878ClassDB::bind_method(D_METHOD("set_selected_palette_item", "item"), &GridMapEditorPlugin::set_selected_palette_item);1879ClassDB::bind_method(D_METHOD("get_selected_palette_item"), &GridMapEditorPlugin::get_selected_palette_item);1880}18811882void GridMapEditorPlugin::edit(Object *p_object) {1883ERR_FAIL_NULL(grid_map_editor);1884grid_map_editor->edit(Object::cast_to<GridMap>(p_object));1885}18861887bool GridMapEditorPlugin::handles(Object *p_object) const {1888return p_object->is_class("GridMap");1889}18901891void GridMapEditorPlugin::make_visible(bool p_visible) {1892ERR_FAIL_NULL(grid_map_editor);1893if (p_visible) {1894BaseButton *button = grid_map_editor->mode_buttons_group->get_pressed_button();1895if (button == nullptr) {1896grid_map_editor->select_mode_button->set_pressed(true);1897}1898grid_map_editor->_on_tool_mode_changed();1899panel_button->show();1900EditorNode::get_bottom_panel()->make_item_visible(grid_map_editor);1901grid_map_editor->set_process(true);1902} else {1903grid_map_editor->_cancel_pending_move();1904grid_map_editor->_show_viewports_transform_gizmo(true);1905panel_button->hide();1906if (grid_map_editor->is_visible_in_tree()) {1907EditorNode::get_bottom_panel()->hide_bottom_panel();1908}1909grid_map_editor->set_process(false);1910}1911}19121913GridMap *GridMapEditorPlugin::get_current_grid_map() const {1914ERR_FAIL_NULL_V(grid_map_editor, nullptr);1915return grid_map_editor->node;1916}19171918void GridMapEditorPlugin::set_selection(const Vector3i &p_begin, const Vector3i &p_end) {1919ERR_FAIL_NULL(grid_map_editor);1920grid_map_editor->_set_selection(true, p_begin, p_end);1921}19221923void GridMapEditorPlugin::clear_selection() {1924ERR_FAIL_NULL(grid_map_editor);1925grid_map_editor->_set_selection(false);1926}19271928AABB GridMapEditorPlugin::get_selection() const {1929ERR_FAIL_NULL_V(grid_map_editor, AABB());1930return grid_map_editor->_get_selection();1931}19321933bool GridMapEditorPlugin::has_selection() const {1934ERR_FAIL_NULL_V(grid_map_editor, false);1935return grid_map_editor->_has_selection();1936}19371938Array GridMapEditorPlugin::get_selected_cells() const {1939ERR_FAIL_NULL_V(grid_map_editor, Array());1940return grid_map_editor->_get_selected_cells();1941}19421943void GridMapEditorPlugin::set_selected_palette_item(int p_item) const {1944ERR_FAIL_NULL(grid_map_editor);1945if (grid_map_editor->node && grid_map_editor->node->get_mesh_library().is_valid()) {1946if (p_item < -1) {1947p_item = -1;1948} else if (p_item >= grid_map_editor->node->get_mesh_library()->get_item_list().size()) {1949p_item = grid_map_editor->node->get_mesh_library()->get_item_list().size() - 1;1950}1951if (p_item != grid_map_editor->selected_palette) {1952grid_map_editor->selected_palette = p_item;1953grid_map_editor->_update_cursor_instance();1954grid_map_editor->update_palette();1955}1956}1957}19581959int GridMapEditorPlugin::get_selected_palette_item() const {1960ERR_FAIL_NULL_V(grid_map_editor, 0);1961if (grid_map_editor->selected_palette >= 0 && grid_map_editor->node && grid_map_editor->node->get_mesh_library().is_valid()) {1962return grid_map_editor->selected_palette;1963} else {1964return -1;1965}1966}196719681969