Path: blob/master/modules/gridmap/editor/grid_map_editor_plugin.cpp
11353 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/os/keyboard.h"33#include "editor/editor_main_screen.h"34#include "editor/editor_node.h"35#include "editor/editor_string_names.h"36#include "editor/editor_undo_redo_manager.h"37#include "editor/gui/editor_bottom_panel.h"38#include "editor/gui/editor_zoom_widget.h"39#include "editor/scene/3d/node_3d_editor_plugin.h"40#include "editor/settings/editor_command_palette.h"41#include "editor/settings/editor_settings.h"42#include "editor/themes/editor_scale.h"43#include "scene/3d/camera_3d.h"44#include "scene/gui/dialogs.h"45#include "scene/gui/label.h"46#include "scene/gui/menu_button.h"47#include "scene/gui/separator.h"48#include "scene/main/window.h"4950void GridMapEditor::_configure() {51if (!node) {52return;53}5455update_grid();56}5758void GridMapEditor::_menu_option(int p_option) {59switch (p_option) {60case MENU_OPTION_PREV_LEVEL: {61floor->set_value(floor->get_value() - 1);62if (selection.active && input_action == INPUT_SELECT) {63selection.current[edit_axis]--;64_validate_selection();65}66} break;6768case MENU_OPTION_NEXT_LEVEL: {69floor->set_value(floor->get_value() + 1);70if (selection.active && input_action == INPUT_SELECT) {71selection.current[edit_axis]++;72_validate_selection();73}74} break;7576case MENU_OPTION_X_AXIS:77case MENU_OPTION_Y_AXIS:78case MENU_OPTION_Z_AXIS: {79int new_axis = p_option - MENU_OPTION_X_AXIS;80for (int i = 0; i < 3; i++) {81int idx = options->get_popup()->get_item_index(MENU_OPTION_X_AXIS + i);82options->get_popup()->set_item_checked(idx, i == new_axis);83}8485if (edit_axis != new_axis) {86if (edit_axis == Vector3::AXIS_Y) {87floor->set_tooltip_text("Change Grid Plane");88} else if (new_axis == Vector3::AXIS_Y) {89floor->set_tooltip_text("Change Grid Floor");90}91}92edit_axis = Vector3::Axis(new_axis);93update_grid();9495} break;9697case MENU_OPTION_CURSOR_ROTATE_X:98case MENU_OPTION_CURSOR_ROTATE_Y:99case MENU_OPTION_CURSOR_ROTATE_Z:100case MENU_OPTION_CURSOR_BACK_ROTATE_X:101case MENU_OPTION_CURSOR_BACK_ROTATE_Y:102case MENU_OPTION_CURSOR_BACK_ROTATE_Z: {103Vector3 rotation_axis;104float rotation_angle = -Math::PI / 2.0;105if (p_option == MENU_OPTION_CURSOR_ROTATE_X || p_option == MENU_OPTION_CURSOR_BACK_ROTATE_X) {106rotation_axis.x = (p_option == MENU_OPTION_CURSOR_ROTATE_X) ? 1 : -1;107} else if (p_option == MENU_OPTION_CURSOR_ROTATE_Y || p_option == MENU_OPTION_CURSOR_BACK_ROTATE_Y) {108rotation_axis.y = (p_option == MENU_OPTION_CURSOR_ROTATE_Y) ? 1 : -1;109} else if (p_option == MENU_OPTION_CURSOR_ROTATE_Z || p_option == MENU_OPTION_CURSOR_BACK_ROTATE_Z) {110rotation_axis.z = (p_option == MENU_OPTION_CURSOR_ROTATE_Z) ? 1 : -1;111}112113Basis r;114if (input_action == INPUT_PASTE) {115r = node->get_basis_with_orthogonal_index(paste_indicator.orientation);116r.rotate(rotation_axis, rotation_angle);117paste_indicator.orientation = node->get_orthogonal_index_from_basis(r);118_update_paste_indicator();119} else if (_has_selection()) {120Array cells = _get_selected_cells();121for (int i = 0; i < cells.size(); i++) {122Vector3i cell = cells[i];123r = node->get_basis_with_orthogonal_index(node->get_cell_item_orientation(cell));124r.rotate(rotation_axis, rotation_angle);125node->set_cell_item(cell, node->get_cell_item(cell), node->get_orthogonal_index_from_basis(r));126}127} else {128r = node->get_basis_with_orthogonal_index(cursor_rot);129r.rotate(rotation_axis, rotation_angle);130cursor_rot = node->get_orthogonal_index_from_basis(r);131_update_cursor_transform();132}133} break;134135case MENU_OPTION_CURSOR_CLEAR_ROTATION: {136if (input_action == INPUT_PASTE) {137paste_indicator.orientation = 0;138_update_paste_indicator();139break;140}141142cursor_rot = 0;143_update_cursor_transform();144} break;145146case MENU_OPTION_PASTE_SELECTS: {147int idx = options->get_popup()->get_item_index(MENU_OPTION_PASTE_SELECTS);148options->get_popup()->set_item_checked(idx, !options->get_popup()->is_item_checked(idx));149} break;150151case MENU_OPTION_SELECTION_DUPLICATE:152case MENU_OPTION_SELECTION_CUT: {153if (!(selection.active && input_action == INPUT_NONE)) {154break;155}156157_set_clipboard_data();158159if (p_option == MENU_OPTION_SELECTION_CUT) {160_delete_selection();161}162163input_action = INPUT_PASTE;164paste_indicator.click = selection.click;165paste_indicator.current = cursor_gridpos;166paste_indicator.begin = selection.begin;167paste_indicator.end = selection.end;168paste_indicator.distance_from_cursor = cursor_gridpos - paste_indicator.begin;169paste_indicator.orientation = 0;170_update_paste_indicator();171} break;172case MENU_OPTION_SELECTION_CLEAR: {173if (!selection.active) {174break;175}176177_delete_selection();178179} break;180case MENU_OPTION_SELECTION_FILL: {181if (!selection.active) {182return;183}184185_fill_selection();186187} break;188case MENU_OPTION_GRIDMAP_SETTINGS: {189settings_dialog->popup_centered(settings_vbc->get_combined_minimum_size() + Size2(50, 50) * EDSCALE);190} break;191}192}193194void GridMapEditor::_update_cursor_transform() {195cursor_transform = Transform3D();196cursor_transform.origin = cursor_origin;197cursor_transform.basis *= node->get_cell_scale();198cursor_transform = node->get_global_transform() * cursor_transform;199200if (mode_buttons_group->get_pressed_button() == paint_mode_button) {201// Auto-deselect the selection when painting.202if (selection.active) {203_set_selection(false);204}205// Rotation is only applied in paint mode, we don't want the cursor box to rotate otherwise.206cursor_transform.basis *= node->get_basis_with_orthogonal_index(cursor_rot);207if (selected_palette >= 0 && node && node->get_mesh_library().is_valid()) {208cursor_transform *= node->get_mesh_library()->get_item_mesh_transform(selected_palette);209}210} else {211Transform3D xf;212xf.scale(node->get_cell_size());213xf.origin.x = node->get_center_x() ? -node->get_cell_size().x / 2 : 0;214xf.origin.y = node->get_center_y() ? -node->get_cell_size().y / 2 : 0;215xf.origin.z = node->get_center_z() ? -node->get_cell_size().z / 2 : 0;216cursor_transform *= xf;217}218219if (cursor_instance.is_valid()) {220RenderingServer::get_singleton()->instance_set_transform(cursor_instance, cursor_transform);221RenderingServer::get_singleton()->instance_set_visible(cursor_instance, cursor_visible);222}223}224225void GridMapEditor::_update_selection_transform() {226Transform3D xf_zero;227xf_zero.basis.set_zero();228229if (!selection.active) {230RenderingServer::get_singleton()->instance_set_transform(selection_instance, xf_zero);231for (int i = 0; i < 3; i++) {232RenderingServer::get_singleton()->instance_set_transform(selection_level_instance[i], xf_zero);233}234return;235}236237Transform3D xf;238xf.scale((Vector3(1, 1, 1) + (selection.end - selection.begin)) * node->get_cell_size());239xf.origin = selection.begin * node->get_cell_size();240241RenderingServer::get_singleton()->instance_set_transform(selection_instance, node->get_global_transform() * xf);242243for (int i = 0; i < 3; i++) {244if (i != edit_axis || (edit_floor[edit_axis] < selection.begin[edit_axis]) || (edit_floor[edit_axis] > selection.end[edit_axis] + 1)) {245RenderingServer::get_singleton()->instance_set_transform(selection_level_instance[i], xf_zero);246} else {247Vector3 scale = (selection.end - selection.begin + Vector3(1, 1, 1));248scale[edit_axis] = 1.0;249Vector3 position = selection.begin;250position[edit_axis] = edit_floor[edit_axis];251252scale *= node->get_cell_size();253position *= node->get_cell_size();254255Transform3D xf2;256xf2.basis.scale(scale);257xf2.origin = position;258259RenderingServer::get_singleton()->instance_set_transform(selection_level_instance[i], node->get_global_transform() * xf2);260}261}262}263264void GridMapEditor::_validate_selection() {265if (!selection.active) {266return;267}268selection.begin = selection.click;269selection.end = selection.current;270271if (selection.begin.x > selection.end.x) {272SWAP(selection.begin.x, selection.end.x);273}274if (selection.begin.y > selection.end.y) {275SWAP(selection.begin.y, selection.end.y);276}277if (selection.begin.z > selection.end.z) {278SWAP(selection.begin.z, selection.end.z);279}280281_update_selection_transform();282}283284void GridMapEditor::_set_selection(bool p_active, const Vector3 &p_begin, const Vector3 &p_end) {285selection.active = p_active;286selection.begin = p_begin;287selection.end = p_end;288selection.click = p_begin;289selection.current = p_end;290291if (is_visible_in_tree()) {292_update_selection_transform();293}294}295296AABB GridMapEditor::_get_selection() const {297AABB ret;298if (selection.active) {299ret.position = selection.begin;300ret.size = selection.end - selection.begin;301} else {302ret.position.zero();303ret.size.zero();304}305return ret;306}307308bool GridMapEditor::_has_selection() const {309return node != nullptr && selection.active;310}311312Array GridMapEditor::_get_selected_cells() const {313Array ret;314if (node != nullptr && selection.active) {315for (int i = selection.begin.x; i <= selection.end.x; i++) {316for (int j = selection.begin.y; j <= selection.end.y; j++) {317for (int k = selection.begin.z; k <= selection.end.z; k++) {318Vector3i selected = Vector3i(i, j, k);319int itm = node->get_cell_item(selected);320if (itm == GridMap::INVALID_CELL_ITEM) {321continue;322}323ret.append(selected);324}325}326}327}328return ret;329}330331bool GridMapEditor::do_input_action(Camera3D *p_camera, const Point2 &p_point, bool p_click) {332if (!spatial_editor) {333return false;334}335if (input_action == INPUT_TRANSFORM) {336return false;337}338if (selected_palette < 0 && input_action != INPUT_NONE && input_action != INPUT_PICK && input_action != INPUT_SELECT && input_action != INPUT_PASTE) {339return false;340}341if (mesh_library.is_null()) {342return false;343}344if (input_action != INPUT_NONE && input_action != INPUT_PICK && input_action != INPUT_SELECT && input_action != INPUT_PASTE && !mesh_library->has_item(selected_palette)) {345return false;346}347348Camera3D *camera = p_camera;349Vector3 from = camera->project_ray_origin(p_point);350Vector3 normal = camera->project_ray_normal(p_point);351Transform3D local_xform = node->get_global_transform().affine_inverse();352Vector<Plane> planes = camera->get_frustum();353from = local_xform.xform(from);354normal = local_xform.basis.xform(normal).normalized();355356Plane p;357p.normal[edit_axis] = 1.0;358p.d = edit_floor[edit_axis] * node->get_cell_size()[edit_axis];359360Vector3 inters;361if (!p.intersects_segment(from, from + normal * settings_pick_distance->get_value(), &inters)) {362return false;363}364365// Make sure the intersection is inside the frustum planes, to avoid366// Painting on invisible regions.367for (int i = 0; i < planes.size(); i++) {368Plane fp = local_xform.xform(planes[i]);369if (fp.is_point_over(inters)) {370return false;371}372}373374Vector3 cell_size = node->get_cell_size();375376for (int i = 0; i < 3; i++) {377if (i == edit_axis) {378cursor_gridpos[i] = edit_floor[i];379} else {380cursor_gridpos[i] = inters[i] / cell_size[i];381if (inters[i] < 0) {382cursor_gridpos[i] -= 1; // Compensate negative.383}384grid_ofs[i] = cursor_gridpos[i] * cell_size[i];385}386}387388RS::get_singleton()->instance_set_transform(grid_instance[edit_axis], node->get_global_transform() * edit_grid_xform);389390if (cursor_instance.is_valid()) {391cursor_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();392cursor_visible = true;393394if (input_action == INPUT_PASTE) {395cursor_visible = false;396}397398_update_cursor_transform();399}400401if (input_action == INPUT_NONE) {402return false;403}404405if (input_action == INPUT_PASTE) {406paste_indicator.current = cursor_gridpos;407_update_paste_indicator();408409} else if (input_action == INPUT_SELECT) {410selection.current = cursor_gridpos;411if (p_click) {412selection.click = selection.current;413}414selection.active = true;415_validate_selection();416417return true;418} else if (input_action == INPUT_PICK) {419int item = node->get_cell_item(cursor_gridpos);420if (item >= 0) {421selected_palette = item;422423// Clear the filter if picked an item that's filtered out.424int index = mesh_library_palette->find_metadata(item);425if (index == -1) {426search_box->clear();427}428429// This will select `selected_palette` in the ItemList when possible.430update_palette();431432_update_cursor_instance();433}434return true;435}436437if (input_action == INPUT_PAINT) {438SetItem si;439si.position = cursor_gridpos;440si.new_value = selected_palette;441si.new_orientation = cursor_rot;442si.old_value = node->get_cell_item(cursor_gridpos);443si.old_orientation = node->get_cell_item_orientation(cursor_gridpos);444set_items.push_back(si);445node->set_cell_item(cursor_gridpos, selected_palette, cursor_rot);446return true;447} else if (input_action == INPUT_ERASE) {448SetItem si;449si.position = cursor_gridpos;450si.new_value = -1;451si.new_orientation = 0;452si.old_value = node->get_cell_item(cursor_gridpos);453si.old_orientation = node->get_cell_item_orientation(cursor_gridpos);454set_items.push_back(si);455node->set_cell_item(cursor_gridpos, -1);456return true;457}458459return false;460}461462void GridMapEditor::_delete_selection() {463if (!selection.active) {464return;465}466467EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();468undo_redo->create_action(TTR("GridMap Delete Selection"));469for (int i = selection.begin.x; i <= selection.end.x; i++) {470for (int j = selection.begin.y; j <= selection.end.y; j++) {471for (int k = selection.begin.z; k <= selection.end.z; k++) {472Vector3i selected = Vector3i(i, j, k);473undo_redo->add_do_method(node, "set_cell_item", selected, GridMap::INVALID_CELL_ITEM);474undo_redo->add_undo_method(node, "set_cell_item", selected, node->get_cell_item(selected), node->get_cell_item_orientation(selected));475}476}477}478undo_redo->add_do_method(this, "_set_selection", !selection.active, selection.begin, selection.end);479undo_redo->add_undo_method(this, "_set_selection", selection.active, selection.begin, selection.end);480undo_redo->commit_action();481}482483void GridMapEditor::_fill_selection() {484if (!selection.active) {485return;486}487488EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();489undo_redo->create_action(TTR("GridMap Fill Selection"));490for (int i = selection.begin.x; i <= selection.end.x; i++) {491for (int j = selection.begin.y; j <= selection.end.y; j++) {492for (int k = selection.begin.z; k <= selection.end.z; k++) {493Vector3i selected = Vector3i(i, j, k);494undo_redo->add_do_method(node, "set_cell_item", selected, selected_palette, cursor_rot);495undo_redo->add_undo_method(node, "set_cell_item", selected, node->get_cell_item(selected), node->get_cell_item_orientation(selected));496}497}498}499undo_redo->add_do_method(this, "_set_selection", !selection.active, selection.begin, selection.end);500undo_redo->add_undo_method(this, "_set_selection", selection.active, selection.begin, selection.end);501undo_redo->commit_action();502}503504void GridMapEditor::_clear_clipboard_data() {505for (const ClipboardItem &E : clipboard_items) {506if (E.instance.is_null()) {507continue;508}509RenderingServer::get_singleton()->free_rid(E.instance);510}511512clipboard_items.clear();513}514515void GridMapEditor::_set_clipboard_data() {516_clear_clipboard_data();517518Ref<MeshLibrary> meshLibrary = node->get_mesh_library();519520const RID scenario = get_tree()->get_root()->get_world_3d()->get_scenario();521522for (int i = selection.begin.x; i <= selection.end.x; i++) {523for (int j = selection.begin.y; j <= selection.end.y; j++) {524for (int k = selection.begin.z; k <= selection.end.z; k++) {525Vector3i selected = Vector3i(i, j, k);526int itm = node->get_cell_item(selected);527if (itm == GridMap::INVALID_CELL_ITEM) {528continue;529}530531Ref<Mesh> mesh = meshLibrary->get_item_mesh(itm);532533ClipboardItem item;534item.cell_item = itm;535item.grid_offset = Vector3(selected) - selection.begin;536item.orientation = node->get_cell_item_orientation(selected);537538if (mesh.is_valid()) {539item.instance = RenderingServer::get_singleton()->instance_create2(mesh->get_rid(), scenario);540}541542clipboard_items.push_back(item);543}544}545}546}547548void GridMapEditor::_update_paste_indicator() {549if (input_action != INPUT_PASTE) {550Transform3D xf;551xf.basis.set_zero();552RenderingServer::get_singleton()->instance_set_transform(paste_instance, xf);553return;554}555556Vector3 center = 0.5 * Vector3(real_t(node->get_center_x()), real_t(node->get_center_y()), real_t(node->get_center_z()));557Vector3 scale = (Vector3(1, 1, 1) + (paste_indicator.end - paste_indicator.begin)) * node->get_cell_size();558Transform3D xf;559xf.scale(scale);560xf.origin = (paste_indicator.current - paste_indicator.distance_from_cursor + center) * node->get_cell_size();561Basis rot;562rot = node->get_basis_with_orthogonal_index(paste_indicator.orientation);563xf.basis = rot * xf.basis;564xf.translate_local((-center * node->get_cell_size()) / scale);565566RenderingServer::get_singleton()->instance_set_transform(paste_instance, node->get_global_transform() * xf);567568for (const ClipboardItem &item : clipboard_items) {569if (item.instance.is_null()) {570continue;571}572xf = Transform3D();573xf.origin = (paste_indicator.current - paste_indicator.distance_from_cursor + center) * node->get_cell_size();574xf.basis = rot * xf.basis;575xf.translate_local(item.grid_offset * node->get_cell_size());576577Basis item_rot;578item_rot = node->get_basis_with_orthogonal_index(item.orientation);579xf.basis = item_rot * xf.basis * node->get_cell_scale();580581RenderingServer::get_singleton()->instance_set_transform(item.instance, node->get_global_transform() * xf);582}583}584585void GridMapEditor::_do_paste() {586int idx = options->get_popup()->get_item_index(MENU_OPTION_PASTE_SELECTS);587bool reselect = options->get_popup()->is_item_checked(idx);588589Basis rot;590rot = node->get_basis_with_orthogonal_index(paste_indicator.orientation);591592EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();593undo_redo->create_action(TTR("GridMap Paste Selection"));594595for (const ClipboardItem &item : clipboard_items) {596Vector3 position = rot.xform(item.grid_offset) + paste_indicator.current - paste_indicator.distance_from_cursor;597598Basis orm;599orm = node->get_basis_with_orthogonal_index(item.orientation);600orm = rot * orm;601602undo_redo->add_do_method(node, "set_cell_item", position, item.cell_item, node->get_orthogonal_index_from_basis(orm));603undo_redo->add_undo_method(node, "set_cell_item", position, node->get_cell_item(position), node->get_cell_item_orientation(position));604}605606if (reselect) {607// We need to rotate the paste_indicator to find the selection begin and end:608Vector3 temp_end = rot.xform(paste_indicator.end - paste_indicator.begin) + paste_indicator.current - paste_indicator.distance_from_cursor;609Vector3 temp_begin = paste_indicator.current - paste_indicator.distance_from_cursor;610// _set_selection expects that selection_begin is the corner closer to the origin:611for (int i = 0; i < 3; ++i) {612if (temp_begin[i] > temp_end[i]) {613float p = temp_begin[i];614temp_begin[i] = temp_end[i];615temp_end[i] = p;616}617}618undo_redo->add_do_method(this, "_set_selection", true, temp_begin, temp_end);619undo_redo->add_undo_method(this, "_set_selection", selection.active, selection.begin, selection.end);620}621622undo_redo->commit_action();623624_clear_clipboard_data();625}626627void GridMapEditor::_show_viewports_transform_gizmo(bool p_value) {628Dictionary new_state;629new_state["transform_gizmo"] = p_value;630for (uint32_t i = 0; i < Node3DEditor::VIEWPORTS_COUNT; i++) {631Node3DEditorViewport *viewport = Node3DEditor::get_singleton()->get_editor_viewport(i);632viewport->set_state(new_state);633}634}635636EditorPlugin::AfterGUIInput GridMapEditor::forward_spatial_input_event(Camera3D *p_camera, const Ref<InputEvent> &p_event) {637// If the mouse is currently captured, we are most likely in freelook mode.638// In this case, disable shortcuts to avoid conflicts with freelook navigation.639if (!node || Input::get_singleton()->get_mouse_mode() == Input::MOUSE_MODE_CAPTURED) {640return EditorPlugin::AFTER_GUI_INPUT_PASS;641}642643Ref<InputEventKey> k = p_event;644if (k.is_valid() && k->is_pressed() && !k->is_echo()) {645// Transform mode (toggle button):646// If we are in Transform mode we pass the events to the 3D editor,647// but if the Transform mode shortcut is pressed again, we go back to Selection mode.648if (mode_buttons_group->get_pressed_button() == transform_mode_button) {649if (transform_mode_button->get_shortcut().is_valid() && transform_mode_button->get_shortcut()->matches_event(p_event)) {650select_mode_button->set_pressed(true);651accept_event();652return EditorPlugin::AFTER_GUI_INPUT_STOP;653}654return EditorPlugin::AFTER_GUI_INPUT_PASS;655}656// Tool modes and tool actions:657for (BaseButton *b : viewport_shortcut_buttons) {658if (b->is_disabled()) {659continue;660}661662if (b->get_shortcut().is_valid() && b->get_shortcut()->matches_event(p_event)) {663if (b->is_toggle_mode()) {664b->set_pressed(b->get_button_group().is_valid() || !b->is_pressed());665} else {666// Can't press a button without toggle mode, so just emit the signal directly.667b->emit_signal(SceneStringName(pressed));668}669accept_event();670return EditorPlugin::AFTER_GUI_INPUT_STOP;671}672}673// Hard key actions:674if (k->get_keycode() == Key::ESCAPE) {675if (input_action == INPUT_PASTE) {676_clear_clipboard_data();677input_action = INPUT_NONE;678_update_paste_indicator();679return EditorPlugin::AFTER_GUI_INPUT_STOP;680} else if (selection.active) {681_set_selection(false);682return EditorPlugin::AFTER_GUI_INPUT_STOP;683} else {684input_action = INPUT_NONE;685update_palette();686_update_cursor_instance();687return EditorPlugin::AFTER_GUI_INPUT_STOP;688}689}690// Options menu shortcuts:691Ref<Shortcut> ed_shortcut = ED_GET_SHORTCUT("grid_map/previous_floor");692if (ed_shortcut.is_valid() && ed_shortcut->matches_event(p_event)) {693accept_event();694_menu_option(MENU_OPTION_PREV_LEVEL);695return EditorPlugin::AFTER_GUI_INPUT_STOP;696}697ed_shortcut = ED_GET_SHORTCUT("grid_map/next_floor");698if (ed_shortcut.is_valid() && ed_shortcut->matches_event(p_event)) {699accept_event();700_menu_option(MENU_OPTION_NEXT_LEVEL);701return EditorPlugin::AFTER_GUI_INPUT_STOP;702}703for (int i = 0; i < options->get_popup()->get_item_count(); ++i) {704const Ref<Shortcut> &shortcut = options->get_popup()->get_item_shortcut(i);705if (shortcut.is_valid() && shortcut->matches_event(p_event)) {706// Consume input to avoid conflicts with other plugins.707accept_event();708_menu_option(options->get_popup()->get_item_id(i));709return EditorPlugin::AFTER_GUI_INPUT_STOP;710}711}712}713714Ref<InputEventMouseButton> mb = p_event;715if (mb.is_valid()) {716if (mb->get_button_index() == MouseButton::WHEEL_UP && (mb->is_command_or_control_pressed())) {717if (mb->is_pressed()) {718floor->set_value(floor->get_value() + mb->get_factor());719}720721return EditorPlugin::AFTER_GUI_INPUT_STOP; // Eaten.722} else if (mb->get_button_index() == MouseButton::WHEEL_DOWN && (mb->is_command_or_control_pressed())) {723if (mb->is_pressed()) {724floor->set_value(floor->get_value() - mb->get_factor());725}726return EditorPlugin::AFTER_GUI_INPUT_STOP;727}728729if (mb->is_pressed()) {730Node3DEditorViewport::NavigationScheme nav_scheme = (Node3DEditorViewport::NavigationScheme)EDITOR_GET("editors/3d/navigation/navigation_scheme").operator int();731if ((nav_scheme == Node3DEditorViewport::NAVIGATION_MAYA || nav_scheme == Node3DEditorViewport::NAVIGATION_MODO) && mb->is_alt_pressed()) {732input_action = INPUT_NONE;733} else if (mb->get_button_index() == MouseButton::LEFT) {734bool can_edit = (node && node->get_mesh_library().is_valid());735if (input_action == INPUT_PASTE) {736_do_paste();737input_action = INPUT_NONE;738_update_paste_indicator();739return EditorPlugin::AFTER_GUI_INPUT_STOP;740} else if (mode_buttons_group->get_pressed_button() == select_mode_button && can_edit) {741input_action = INPUT_SELECT;742last_selection = selection;743} else if (mode_buttons_group->get_pressed_button() == pick_mode_button && can_edit) {744input_action = INPUT_PICK;745} else if (mode_buttons_group->get_pressed_button() == paint_mode_button && can_edit) {746input_action = INPUT_PAINT;747set_items.clear();748} else if (mode_buttons_group->get_pressed_button() == erase_mode_button && can_edit) {749input_action = INPUT_ERASE;750set_items.clear();751}752} else if (mb->get_button_index() == MouseButton::RIGHT) {753if (input_action == INPUT_PASTE) {754_clear_clipboard_data();755input_action = INPUT_NONE;756_update_paste_indicator();757return EditorPlugin::AFTER_GUI_INPUT_STOP;758} else if (selection.active) {759_set_selection(false);760return EditorPlugin::AFTER_GUI_INPUT_STOP;761}762} else {763return EditorPlugin::AFTER_GUI_INPUT_PASS;764}765766if (do_input_action(p_camera, Point2(mb->get_position().x, mb->get_position().y), true)) {767return EditorPlugin::AFTER_GUI_INPUT_STOP;768}769return EditorPlugin::AFTER_GUI_INPUT_PASS;770} else {771if ((mb->get_button_index() == MouseButton::LEFT && input_action == INPUT_ERASE) || (mb->get_button_index() == MouseButton::LEFT && input_action == INPUT_PAINT)) {772if (set_items.size()) {773EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();774undo_redo->create_action(TTR("GridMap Paint"));775for (const SetItem &si : set_items) {776undo_redo->add_do_method(node, "set_cell_item", si.position, si.new_value, si.new_orientation);777}778for (uint32_t i = set_items.size(); i > 0; i--) {779const SetItem &si = set_items[i - 1];780undo_redo->add_undo_method(node, "set_cell_item", si.position, si.old_value, si.old_orientation);781}782783undo_redo->commit_action();784}785set_items.clear();786input_action = INPUT_NONE;787788if (set_items.size() > 0) {789return EditorPlugin::AFTER_GUI_INPUT_STOP;790}791return EditorPlugin::AFTER_GUI_INPUT_PASS;792}793794if (mb->get_button_index() == MouseButton::LEFT && input_action == INPUT_SELECT) {795EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();796undo_redo->create_action(TTR("GridMap Selection"));797undo_redo->add_do_method(this, "_set_selection", selection.active, selection.begin, selection.end);798undo_redo->add_undo_method(this, "_set_selection", last_selection.active, last_selection.begin, last_selection.end);799undo_redo->commit_action();800}801802if (mb->get_button_index() == MouseButton::LEFT && input_action != INPUT_NONE) {803set_items.clear();804input_action = INPUT_NONE;805return EditorPlugin::AFTER_GUI_INPUT_STOP;806}807if (mb->get_button_index() == MouseButton::RIGHT && (input_action == INPUT_ERASE || input_action == INPUT_PASTE)) {808input_action = INPUT_NONE;809return EditorPlugin::AFTER_GUI_INPUT_STOP;810}811}812}813814Ref<InputEventMouseMotion> mm = p_event;815816if (mm.is_valid()) {817// Update the grid, to check if the grid needs to be moved to a tile cursor.818update_grid();819820if (do_input_action(p_camera, mm->get_position(), false)) {821return EditorPlugin::AFTER_GUI_INPUT_STOP;822}823return EditorPlugin::AFTER_GUI_INPUT_PASS;824}825826Ref<InputEventPanGesture> pan_gesture = p_event;827if (pan_gesture.is_valid()) {828if (pan_gesture->is_alt_pressed() && pan_gesture->is_command_or_control_pressed()) {829const real_t delta = pan_gesture->get_delta().y * 0.5;830accumulated_floor_delta += delta;831int step = 0;832if (Math::abs(accumulated_floor_delta) > 1.0) {833step = SIGN(accumulated_floor_delta);834accumulated_floor_delta -= step;835}836if (step) {837floor->set_value(floor->get_value() + step);838}839return EditorPlugin::AFTER_GUI_INPUT_STOP;840}841}842accumulated_floor_delta = 0.0;843844return EditorPlugin::AFTER_GUI_INPUT_PASS;845}846847struct _CGMEItemSort {848String name;849int id = 0;850_FORCE_INLINE_ bool operator<(const _CGMEItemSort &r_it) const { return name < r_it.name; }851};852853void GridMapEditor::_set_display_mode(int p_mode) {854if (display_mode == p_mode) {855return;856}857858if (p_mode == DISPLAY_LIST) {859mode_list->set_pressed(true);860mode_thumbnail->set_pressed(false);861} else if (p_mode == DISPLAY_THUMBNAIL) {862mode_list->set_pressed(false);863mode_thumbnail->set_pressed(true);864}865866display_mode = p_mode;867868update_palette();869}870871void GridMapEditor::_text_changed(const String &p_text) {872update_palette();873}874875void GridMapEditor::_sbox_input(const Ref<InputEvent> &p_event) {876// Redirect navigational key events to the item list.877Ref<InputEventKey> key = p_event;878if (key.is_valid()) {879if (key->is_action("ui_up", true) || key->is_action("ui_down", true) || key->is_action("ui_page_up") || key->is_action("ui_page_down")) {880mesh_library_palette->gui_input(key);881search_box->accept_event();882}883}884}885886void GridMapEditor::_mesh_library_palette_input(const Ref<InputEvent> &p_ie) {887const Ref<InputEventMouseButton> mb = p_ie;888889// Zoom in/out using Ctrl + mouse wheel890if (mb.is_valid() && mb->is_pressed() && mb->is_command_or_control_pressed()) {891if (mb->is_pressed() && mb->get_button_index() == MouseButton::WHEEL_UP) {892zoom_widget->set_zoom(zoom_widget->get_zoom() + 0.2);893zoom_widget->emit_signal(SNAME("zoom_changed"), zoom_widget->get_zoom());894}895896if (mb->is_pressed() && mb->get_button_index() == MouseButton::WHEEL_DOWN) {897zoom_widget->set_zoom(zoom_widget->get_zoom() - 0.2);898zoom_widget->emit_signal(SNAME("zoom_changed"), zoom_widget->get_zoom());899}900}901}902903void GridMapEditor::_icon_size_changed(float p_value) {904mesh_library_palette->set_icon_scale(p_value);905update_palette();906}907908void GridMapEditor::update_palette() {909float min_size = EDITOR_GET("editors/grid_map/preview_size");910min_size *= EDSCALE;911912mesh_library_palette->clear();913if (display_mode == DISPLAY_THUMBNAIL) {914mesh_library_palette->set_max_columns(0);915mesh_library_palette->set_icon_mode(ItemList::ICON_MODE_TOP);916mesh_library_palette->set_fixed_column_width(min_size * MAX(zoom_widget->get_zoom(), 1.5));917} else if (display_mode == DISPLAY_LIST) {918mesh_library_palette->set_max_columns(0);919mesh_library_palette->set_icon_mode(ItemList::ICON_MODE_LEFT);920mesh_library_palette->set_fixed_column_width(0);921}922923mesh_library_palette->set_fixed_icon_size(Size2(min_size, min_size));924mesh_library_palette->set_max_text_lines(2);925926if (mesh_library.is_null()) {927search_box->set_text("");928search_box->set_editable(false);929info_message->show();930return;931}932933search_box->set_editable(true);934info_message->hide();935936Vector<int> ids;937ids = mesh_library->get_item_list();938939List<_CGMEItemSort> il;940for (int i = 0; i < ids.size(); i++) {941_CGMEItemSort is;942is.id = ids[i];943is.name = mesh_library->get_item_name(ids[i]);944il.push_back(is);945}946il.sort();947948String filter = search_box->get_text().strip_edges();949950int item = 0;951952for (_CGMEItemSort &E : il) {953int id = E.id;954String name = mesh_library->get_item_name(id);955Ref<Texture2D> preview = mesh_library->get_item_preview(id);956957if (name.is_empty()) {958name = "#" + itos(id);959}960961if (!filter.is_empty() && !filter.is_subsequence_ofn(name)) {962continue;963}964965mesh_library_palette->add_item("");966if (preview.is_valid()) {967mesh_library_palette->set_item_icon(item, preview);968mesh_library_palette->set_item_tooltip(item, name);969}970mesh_library_palette->set_item_text(item, name);971mesh_library_palette->set_item_metadata(item, id);972973if (selected_palette == id) {974mesh_library_palette->select(item);975}976977item++;978}979}980981void GridMapEditor::_update_mesh_library() {982ERR_FAIL_NULL(node);983984Ref<MeshLibrary> new_mesh_library = node->get_mesh_library();985if (new_mesh_library != mesh_library) {986if (mesh_library.is_valid()) {987mesh_library->disconnect_changed(callable_mp(this, &GridMapEditor::update_palette));988}989mesh_library = new_mesh_library;990} else {991return;992}993994if (mesh_library.is_valid()) {995mesh_library->connect_changed(callable_mp(this, &GridMapEditor::update_palette));996}997998update_palette();999// Make sure we select the first tile as default possible.1000if (mesh_library_palette->get_current() == -1 && mesh_library_palette->get_item_count() > 0) {1001mesh_library_palette->set_current(0);1002selected_palette = mesh_library_palette->get_item_metadata(0);1003}1004// Update the cursor and grid in case the library is changed or removed.1005_update_cursor_instance();1006update_grid();1007}10081009void GridMapEditor::edit(GridMap *p_gridmap) {1010if (node) {1011node->disconnect(SNAME("cell_size_changed"), callable_mp(this, &GridMapEditor::_draw_grids));1012node->disconnect(CoreStringName(changed), callable_mp(this, &GridMapEditor::_update_mesh_library));1013if (mesh_library.is_valid()) {1014mesh_library->disconnect_changed(callable_mp(this, &GridMapEditor::update_palette));1015mesh_library = Ref<MeshLibrary>();1016}1017}10181019node = p_gridmap;10201021input_action = INPUT_NONE;1022selection.active = false;1023_update_selection_transform();1024_update_paste_indicator();10251026spatial_editor = Object::cast_to<Node3DEditorPlugin>(EditorNode::get_singleton()->get_editor_main_screen()->get_selected_plugin());10271028if (!node) {1029set_process(false);1030for (int i = 0; i < 3; i++) {1031RenderingServer::get_singleton()->instance_set_visible(grid_instance[i], false);1032}10331034if (cursor_instance.is_valid()) {1035RenderingServer::get_singleton()->instance_set_visible(cursor_instance, false);1036}10371038return;1039}10401041update_palette();1042_update_cursor_instance();10431044set_process(true);10451046_draw_grids(node->get_cell_size());1047update_grid();10481049node->connect(SNAME("cell_size_changed"), callable_mp(this, &GridMapEditor::_draw_grids));1050node->connect(CoreStringName(changed), callable_mp(this, &GridMapEditor::_update_mesh_library));1051_update_mesh_library();1052}10531054void GridMapEditor::update_grid() {1055grid_xform.origin.x -= 1; // Force update in hackish way.10561057grid_ofs[edit_axis] = edit_floor[edit_axis] * node->get_cell_size()[edit_axis];10581059// If there's a valid tile cursor, offset the grid, otherwise move it back to the node.1060edit_grid_xform.origin = cursor_instance.is_valid() ? grid_ofs : Vector3();1061edit_grid_xform.basis = Basis();10621063for (int i = 0; i < 3; i++) {1064RenderingServer::get_singleton()->instance_set_visible(grid_instance[i], i == edit_axis);1065}10661067updating = true;1068floor->set_value(edit_floor[edit_axis]);1069updating = false;1070}10711072void GridMapEditor::_draw_grids(const Vector3 &cell_size) {1073Vector3 edited_floor = node->get_meta("_editor_floor_", Vector3());10741075for (int i = 0; i < 3; i++) {1076RS::get_singleton()->mesh_clear(grid[i]);1077edit_floor[i] = edited_floor[i];1078}10791080Vector<Vector3> grid_points[3];1081Vector<Color> grid_colors[3];10821083for (int i = 0; i < 3; i++) {1084Vector3 axis;1085axis[i] = 1;1086Vector3 axis_n1;1087axis_n1[(i + 1) % 3] = cell_size[(i + 1) % 3];1088Vector3 axis_n2;1089axis_n2[(i + 2) % 3] = cell_size[(i + 2) % 3];10901091for (int j = -GRID_CURSOR_SIZE; j <= GRID_CURSOR_SIZE; j++) {1092for (int k = -GRID_CURSOR_SIZE; k <= GRID_CURSOR_SIZE; k++) {1093Vector3 p = axis_n1 * j + axis_n2 * k;1094float trans = Math::pow(MAX(0, 1.0 - (Vector2(j, k).length() / GRID_CURSOR_SIZE)), 2);10951096Vector3 pj = axis_n1 * (j + 1) + axis_n2 * k;1097float transj = Math::pow(MAX(0, 1.0 - (Vector2(j + 1, k).length() / GRID_CURSOR_SIZE)), 2);10981099Vector3 pk = axis_n1 * j + axis_n2 * (k + 1);1100float transk = Math::pow(MAX(0, 1.0 - (Vector2(j, k + 1).length() / GRID_CURSOR_SIZE)), 2);11011102grid_points[i].push_back(p);1103grid_points[i].push_back(pk);1104grid_colors[i].push_back(Color(1, 1, 1, trans));1105grid_colors[i].push_back(Color(1, 1, 1, transk));11061107grid_points[i].push_back(p);1108grid_points[i].push_back(pj);1109grid_colors[i].push_back(Color(1, 1, 1, trans));1110grid_colors[i].push_back(Color(1, 1, 1, transj));1111}1112}11131114Array d;1115d.resize(RS::ARRAY_MAX);1116d[RS::ARRAY_VERTEX] = grid_points[i];1117d[RS::ARRAY_COLOR] = grid_colors[i];1118RenderingServer::get_singleton()->mesh_add_surface_from_arrays(grid[i], RenderingServer::PRIMITIVE_LINES, d);1119RenderingServer::get_singleton()->mesh_surface_set_material(grid[i], 0, indicator_mat->get_rid());1120}1121}11221123void GridMapEditor::_update_theme() {1124transform_mode_button->set_button_icon(get_theme_icon(SNAME("ToolMove"), EditorStringName(EditorIcons)));1125select_mode_button->set_button_icon(get_theme_icon(SNAME("ToolSelect"), EditorStringName(EditorIcons)));1126erase_mode_button->set_button_icon(get_theme_icon(SNAME("Eraser"), EditorStringName(EditorIcons)));1127paint_mode_button->set_button_icon(get_theme_icon(SNAME("Paint"), EditorStringName(EditorIcons)));1128pick_mode_button->set_button_icon(get_theme_icon(SNAME("ColorPick"), EditorStringName(EditorIcons)));1129fill_action_button->set_button_icon(get_theme_icon(SNAME("Bucket"), EditorStringName(EditorIcons)));1130move_action_button->set_button_icon(get_theme_icon(SNAME("ActionCut"), EditorStringName(EditorIcons)));1131duplicate_action_button->set_button_icon(get_theme_icon(SNAME("ActionCopy"), EditorStringName(EditorIcons)));1132delete_action_button->set_button_icon(get_theme_icon(SNAME("Clear"), EditorStringName(EditorIcons)));1133rotate_x_button->set_button_icon(get_theme_icon(SNAME("RotateLeft"), EditorStringName(EditorIcons)));1134rotate_y_button->set_button_icon(get_theme_icon(SNAME("ToolRotate"), EditorStringName(EditorIcons)));1135rotate_z_button->set_button_icon(get_theme_icon(SNAME("RotateRight"), EditorStringName(EditorIcons)));1136search_box->set_right_icon(get_theme_icon(SNAME("Search"), EditorStringName(EditorIcons)));1137mode_thumbnail->set_button_icon(get_theme_icon(SNAME("FileThumbnail"), EditorStringName(EditorIcons)));1138mode_list->set_button_icon(get_theme_icon(SNAME("FileList"), EditorStringName(EditorIcons)));1139options->set_button_icon(get_theme_icon(SNAME("Tools"), EditorStringName(EditorIcons)));1140}11411142void GridMapEditor::_notification(int p_what) {1143switch (p_what) {1144case NOTIFICATION_ENTER_TREE: {1145mesh_library_palette->connect(SceneStringName(item_selected), callable_mp(this, &GridMapEditor::_item_selected_cbk));11461147const RID scenario = get_tree()->get_root()->get_world_3d()->get_scenario();11481149for (int i = 0; i < 3; i++) {1150grid[i] = RS::get_singleton()->mesh_create();1151grid_instance[i] = RS::get_singleton()->instance_create2(grid[i], scenario);1152RenderingServer::get_singleton()->instance_set_layer_mask(grid_instance[i], 1 << Node3DEditorViewport::MISC_TOOL_LAYER);1153selection_level_instance[i] = RenderingServer::get_singleton()->instance_create2(selection_level_mesh[i], scenario);1154RenderingServer::get_singleton()->instance_set_layer_mask(selection_level_instance[i], 1 << Node3DEditorViewport::MISC_TOOL_LAYER);1155}11561157cursor_instance = RenderingServer::get_singleton()->instance_create2(cursor_mesh, scenario);1158RenderingServer::get_singleton()->instance_set_layer_mask(cursor_instance, 1 << Node3DEditorViewport::MISC_TOOL_LAYER);1159RenderingServer::get_singleton()->instance_set_visible(cursor_instance, false);1160selection_instance = RenderingServer::get_singleton()->instance_create2(selection_mesh, scenario);1161RenderingServer::get_singleton()->instance_set_layer_mask(selection_instance, 1 << Node3DEditorViewport::MISC_TOOL_LAYER);1162paste_instance = RenderingServer::get_singleton()->instance_create2(paste_mesh, scenario);1163RenderingServer::get_singleton()->instance_set_layer_mask(paste_instance, 1 << Node3DEditorViewport::MISC_TOOL_LAYER);11641165_update_selection_transform();1166_update_paste_indicator();1167_update_theme();1168} break;11691170case NOTIFICATION_EXIT_TREE: {1171_clear_clipboard_data();11721173for (int i = 0; i < 3; i++) {1174RS::get_singleton()->free_rid(grid_instance[i]);1175RS::get_singleton()->free_rid(grid[i]);1176grid_instance[i] = RID();1177grid[i] = RID();1178RenderingServer::get_singleton()->free_rid(selection_level_instance[i]);1179}11801181RenderingServer::get_singleton()->free_rid(cursor_instance);1182RenderingServer::get_singleton()->free_rid(selection_instance);1183RenderingServer::get_singleton()->free_rid(paste_instance);1184cursor_instance = RID();1185selection_instance = RID();1186paste_instance = RID();1187} break;11881189case NOTIFICATION_PROCESS: {1190if (!node) {1191return;1192}11931194Transform3D xf = node->get_global_transform();11951196if (xf != grid_xform) {1197for (int i = 0; i < 3; i++) {1198RS::get_singleton()->instance_set_transform(grid_instance[i], xf * edit_grid_xform);1199}1200grid_xform = xf;1201_update_cursor_transform();1202_update_selection_transform();1203}1204} break;12051206case NOTIFICATION_THEME_CHANGED: {1207_update_theme();1208} break;12091210case NOTIFICATION_APPLICATION_FOCUS_OUT: {1211if (input_action == INPUT_PAINT) {1212// Simulate mouse released event to stop drawing when editor focus exists.1213Ref<InputEventMouseButton> release;1214release.instantiate();1215release->set_button_index(MouseButton::LEFT);1216forward_spatial_input_event(nullptr, release);1217}1218} break;12191220case EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED: {1221indicator_mat->set_albedo(EDITOR_GET("editors/3d_gizmos/gizmo_colors/gridmap_grid"));12221223// Take Preview Size changes into account.1224update_palette();1225} break;1226}1227}12281229void GridMapEditor::_update_cursor_instance() {1230if (!node) {1231return;1232}12331234if (cursor_instance.is_valid()) {1235RenderingServer::get_singleton()->free_rid(cursor_instance);1236}1237cursor_instance = RID();12381239const RID scenario = get_tree()->get_root()->get_world_3d()->get_scenario();12401241if (mode_buttons_group->get_pressed_button() == paint_mode_button) {1242if (selected_palette >= 0 && node && node->get_mesh_library().is_valid()) {1243Ref<Mesh> mesh = node->get_mesh_library()->get_item_mesh(selected_palette);1244if (mesh.is_valid() && mesh->get_rid().is_valid()) {1245cursor_instance = RenderingServer::get_singleton()->instance_create2(mesh->get_rid(), scenario);1246RS::ShadowCastingSetting cast_shadows = (RS::ShadowCastingSetting)node->get_mesh_library()->get_item_mesh_cast_shadow(selected_palette);1247RS::get_singleton()->instance_geometry_set_cast_shadows_setting(cursor_instance, cast_shadows);1248}1249}1250} else if (mode_buttons_group->get_pressed_button() == select_mode_button) {1251cursor_inner_mat->set_albedo(Color(default_color, 0.2));1252cursor_outer_mat->set_albedo(Color(default_color, 0.8));1253cursor_instance = RenderingServer::get_singleton()->instance_create2(cursor_mesh, scenario);1254} else if (mode_buttons_group->get_pressed_button() == erase_mode_button) {1255cursor_inner_mat->set_albedo(Color(erase_color, 0.2));1256cursor_outer_mat->set_albedo(Color(erase_color, 0.8));1257cursor_instance = RenderingServer::get_singleton()->instance_create2(cursor_mesh, scenario);1258} else if (mode_buttons_group->get_pressed_button() == pick_mode_button) {1259cursor_inner_mat->set_albedo(Color(pick_color, 0.2));1260cursor_outer_mat->set_albedo(Color(pick_color, 0.8));1261cursor_instance = RenderingServer::get_singleton()->instance_create2(cursor_mesh, scenario);1262}12631264// Make the cursor translucent so that it can be distinguished from already-placed tiles.1265RenderingServer::get_singleton()->instance_geometry_set_transparency(cursor_instance, 0.5);12661267_update_cursor_transform();1268}12691270void GridMapEditor::_on_tool_mode_changed() {1271_show_viewports_transform_gizmo(mode_buttons_group->get_pressed_button() == transform_mode_button);1272_update_cursor_instance();1273}12741275void GridMapEditor::_item_selected_cbk(int idx) {1276selected_palette = mesh_library_palette->get_item_metadata(idx);12771278_update_cursor_instance();1279}12801281void GridMapEditor::_floor_changed(float p_value) {1282if (updating) {1283return;1284}12851286edit_floor[edit_axis] = p_value;1287node->set_meta("_editor_floor_", Vector3(edit_floor[0], edit_floor[1], edit_floor[2]));1288update_grid();1289_update_selection_transform();1290}12911292void GridMapEditor::_floor_mouse_exited() {1293floor->get_line_edit()->release_focus();1294}12951296void GridMapEditor::_bind_methods() {1297ClassDB::bind_method("_configure", &GridMapEditor::_configure);1298ClassDB::bind_method("_set_selection", &GridMapEditor::_set_selection);1299}13001301GridMapEditor::GridMapEditor() {1302ED_SHORTCUT("grid_map/previous_floor", TTRC("Previous Floor"), Key::KEY_1, true);1303ED_SHORTCUT("grid_map/next_floor", TTRC("Next Floor"), Key::KEY_3, true);1304ED_SHORTCUT("grid_map/edit_x_axis", TTRC("Edit X Axis"), KeyModifierMask::SHIFT + Key::Z, true);1305ED_SHORTCUT("grid_map/edit_y_axis", TTRC("Edit Y Axis"), KeyModifierMask::SHIFT + Key::X, true);1306ED_SHORTCUT("grid_map/edit_z_axis", TTRC("Edit Z Axis"), KeyModifierMask::SHIFT + Key::C, true);1307ED_SHORTCUT("grid_map/keep_selected", TTRC("Keep Selection"));1308ED_SHORTCUT("grid_map/clear_rotation", TTRC("Clear Rotation"));13091310options = memnew(MenuButton);1311options->set_theme_type_variation(SceneStringName(FlatButton));1312options->get_popup()->add_separator();1313options->get_popup()->add_radio_check_shortcut(ED_GET_SHORTCUT("grid_map/edit_x_axis"), MENU_OPTION_X_AXIS);1314options->get_popup()->add_radio_check_shortcut(ED_GET_SHORTCUT("grid_map/edit_y_axis"), MENU_OPTION_Y_AXIS);1315options->get_popup()->add_radio_check_shortcut(ED_GET_SHORTCUT("grid_map/edit_z_axis"), MENU_OPTION_Z_AXIS);1316options->get_popup()->set_item_checked(options->get_popup()->get_item_index(MENU_OPTION_Y_AXIS), true);1317options->get_popup()->add_separator();1318// TRANSLATORS: This is a toggle to select after pasting the new content.1319options->get_popup()->add_shortcut(ED_GET_SHORTCUT("grid_map/clear_rotation"), MENU_OPTION_CURSOR_CLEAR_ROTATION);1320options->get_popup()->add_check_shortcut(ED_GET_SHORTCUT("grid_map/keep_selected"), MENU_OPTION_PASTE_SELECTS);1321options->get_popup()->set_item_checked(options->get_popup()->get_item_index(MENU_OPTION_PASTE_SELECTS), true);1322options->get_popup()->add_separator();1323options->get_popup()->add_item(TTR("Settings..."), MENU_OPTION_GRIDMAP_SETTINGS);13241325settings_dialog = memnew(ConfirmationDialog);1326settings_dialog->set_title(TTR("GridMap Settings"));1327add_child(settings_dialog);1328settings_vbc = memnew(VBoxContainer);1329settings_vbc->set_custom_minimum_size(Size2(200, 0) * EDSCALE);1330settings_dialog->add_child(settings_vbc);13311332settings_pick_distance = memnew(SpinBox);1333settings_pick_distance->set_max(10000.0f);1334settings_pick_distance->set_min(500.0f);1335settings_pick_distance->set_step(1.0f);1336settings_pick_distance->set_value(EDITOR_GET("editors/grid_map/pick_distance"));1337settings_pick_distance->set_accessibility_name(TTRC("Pick Distance:"));1338settings_vbc->add_margin_child(TTR("Pick Distance:"), settings_pick_distance);13391340options->get_popup()->connect(SceneStringName(id_pressed), callable_mp(this, &GridMapEditor::_menu_option));13411342toolbar = memnew(HBoxContainer);1343add_child(toolbar);1344toolbar->set_h_size_flags(SIZE_EXPAND_FILL);13451346HBoxContainer *mode_buttons = memnew(HBoxContainer);1347toolbar->add_child(mode_buttons);1348mode_buttons_group.instantiate();13491350viewport_shortcut_buttons.reserve(12);13511352transform_mode_button = memnew(Button);1353transform_mode_button->set_theme_type_variation(SceneStringName(FlatButton));1354transform_mode_button->set_toggle_mode(true);1355transform_mode_button->set_button_group(mode_buttons_group);1356transform_mode_button->set_shortcut(ED_SHORTCUT("grid_map/transform_tool", TTRC("Transform"), Key::T, true));1357transform_mode_button->set_accessibility_name(TTRC("Transform"));1358transform_mode_button->connect(SceneStringName(toggled),1359callable_mp(this, &GridMapEditor::_on_tool_mode_changed).unbind(1));1360mode_buttons->add_child(transform_mode_button);1361viewport_shortcut_buttons.push_back(transform_mode_button);1362VSeparator *vsep = memnew(VSeparator);1363mode_buttons->add_child(vsep);13641365select_mode_button = memnew(Button);1366select_mode_button->set_theme_type_variation(SceneStringName(FlatButton));1367select_mode_button->set_toggle_mode(true);1368select_mode_button->set_button_group(mode_buttons_group);1369select_mode_button->set_shortcut(ED_SHORTCUT("grid_map/selection_tool", TTRC("Selection"), Key::Q, true));1370select_mode_button->set_accessibility_name(TTRC("Selection"));1371select_mode_button->connect(SceneStringName(toggled),1372callable_mp(this, &GridMapEditor::_on_tool_mode_changed).unbind(1));1373mode_buttons->add_child(select_mode_button);1374viewport_shortcut_buttons.push_back(select_mode_button);13751376erase_mode_button = memnew(Button);1377erase_mode_button->set_theme_type_variation(SceneStringName(FlatButton));1378erase_mode_button->set_toggle_mode(true);1379erase_mode_button->set_button_group(mode_buttons_group);1380erase_mode_button->set_shortcut(ED_SHORTCUT("grid_map/erase_tool", TTRC("Erase"), Key::W, true));1381erase_mode_button->set_accessibility_name(TTRC("Erase"));1382mode_buttons->add_child(erase_mode_button);1383erase_mode_button->connect(SceneStringName(toggled),1384callable_mp(this, &GridMapEditor::_on_tool_mode_changed).unbind(1));1385viewport_shortcut_buttons.push_back(erase_mode_button);13861387paint_mode_button = memnew(Button);1388paint_mode_button->set_theme_type_variation(SceneStringName(FlatButton));1389paint_mode_button->set_toggle_mode(true);1390paint_mode_button->set_button_group(mode_buttons_group);1391paint_mode_button->set_shortcut(ED_SHORTCUT("grid_map/paint_tool", TTRC("Paint"), Key::E, true));1392paint_mode_button->set_accessibility_name(TTRC("Paint"));1393paint_mode_button->connect(SceneStringName(toggled),1394callable_mp(this, &GridMapEditor::_on_tool_mode_changed).unbind(1));1395mode_buttons->add_child(paint_mode_button);1396viewport_shortcut_buttons.push_back(paint_mode_button);13971398pick_mode_button = memnew(Button);1399pick_mode_button->set_theme_type_variation(SceneStringName(FlatButton));1400pick_mode_button->set_toggle_mode(true);1401pick_mode_button->set_button_group(mode_buttons_group);1402pick_mode_button->set_shortcut(ED_SHORTCUT("grid_map/pick_tool", TTRC("Pick"), Key::R, true));1403pick_mode_button->set_accessibility_name(TTRC("Pick"));1404pick_mode_button->connect(SceneStringName(toggled),1405callable_mp(this, &GridMapEditor::_on_tool_mode_changed).unbind(1));1406mode_buttons->add_child(pick_mode_button);1407viewport_shortcut_buttons.push_back(pick_mode_button);14081409vsep = memnew(VSeparator);1410toolbar->add_child(vsep);14111412HBoxContainer *action_buttons = memnew(HBoxContainer);1413toolbar->add_child(action_buttons);14141415fill_action_button = memnew(Button);1416fill_action_button->set_theme_type_variation(SceneStringName(FlatButton));1417fill_action_button->set_shortcut(ED_SHORTCUT("grid_map/fill_tool", TTRC("Fill"), Key::Z, true));1418fill_action_button->set_accessibility_name(TTRC("Fill"));1419fill_action_button->connect(SceneStringName(pressed),1420callable_mp(this, &GridMapEditor::_menu_option).bind(MENU_OPTION_SELECTION_FILL));1421action_buttons->add_child(fill_action_button);1422viewport_shortcut_buttons.push_back(fill_action_button);14231424move_action_button = memnew(Button);1425move_action_button->set_theme_type_variation(SceneStringName(FlatButton));1426move_action_button->set_shortcut(ED_SHORTCUT("grid_map/move_tool", TTRC("Move"), Key::X, true));1427fill_action_button->set_accessibility_name(TTRC("Move"));1428move_action_button->connect(SceneStringName(pressed),1429callable_mp(this, &GridMapEditor::_menu_option).bind(MENU_OPTION_SELECTION_CUT));1430action_buttons->add_child(move_action_button);1431viewport_shortcut_buttons.push_back(move_action_button);14321433duplicate_action_button = memnew(Button);1434duplicate_action_button->set_theme_type_variation(SceneStringName(FlatButton));1435duplicate_action_button->set_shortcut(ED_SHORTCUT("grid_map/duplicate_tool", TTRC("Duplicate"), Key::C, true));1436duplicate_action_button->set_accessibility_name(TTRC("Duplicate"));1437duplicate_action_button->connect(SceneStringName(pressed),1438callable_mp(this, &GridMapEditor::_menu_option).bind(MENU_OPTION_SELECTION_DUPLICATE));1439action_buttons->add_child(duplicate_action_button);1440viewport_shortcut_buttons.push_back(duplicate_action_button);14411442delete_action_button = memnew(Button);1443delete_action_button->set_theme_type_variation(SceneStringName(FlatButton));1444delete_action_button->set_shortcut(ED_SHORTCUT("grid_map/delete_tool", TTRC("Delete"), Key::V, true));1445delete_action_button->set_accessibility_name(TTRC("Delete"));1446delete_action_button->connect(SceneStringName(pressed),1447callable_mp(this, &GridMapEditor::_menu_option).bind(MENU_OPTION_SELECTION_CLEAR));1448action_buttons->add_child(delete_action_button);1449viewport_shortcut_buttons.push_back(delete_action_button);14501451vsep = memnew(VSeparator);1452toolbar->add_child(vsep);14531454HBoxContainer *rotation_buttons = memnew(HBoxContainer);1455toolbar->add_child(rotation_buttons);14561457rotate_x_button = memnew(Button);1458rotate_x_button->set_theme_type_variation(SceneStringName(FlatButton));1459rotate_x_button->set_shortcut(ED_SHORTCUT("grid_map/cursor_rotate_x", TTRC("Cursor Rotate X"), Key::A, true));1460rotate_x_button->set_accessibility_name(TTRC("Cursor Rotate X"));1461rotate_x_button->connect(SceneStringName(pressed),1462callable_mp(this, &GridMapEditor::_menu_option).bind(MENU_OPTION_CURSOR_ROTATE_X));1463rotation_buttons->add_child(rotate_x_button);1464viewport_shortcut_buttons.push_back(rotate_x_button);14651466rotate_y_button = memnew(Button);1467rotate_y_button->set_theme_type_variation(SceneStringName(FlatButton));1468rotate_y_button->set_shortcut(ED_SHORTCUT("grid_map/cursor_rotate_y", TTRC("Cursor Rotate Y"), Key::S, true));1469rotate_y_button->set_accessibility_name(TTRC("Cursor Rotate Y"));1470rotate_y_button->connect(SceneStringName(pressed),1471callable_mp(this, &GridMapEditor::_menu_option).bind(MENU_OPTION_CURSOR_ROTATE_Y));1472rotation_buttons->add_child(rotate_y_button);1473viewport_shortcut_buttons.push_back(rotate_y_button);14741475rotate_z_button = memnew(Button);1476rotate_z_button->set_theme_type_variation(SceneStringName(FlatButton));1477rotate_z_button->set_shortcut(ED_SHORTCUT("grid_map/cursor_rotate_z", TTRC("Cursor Rotate Z"), Key::D, true));1478rotate_z_button->set_accessibility_name(TTRC("Cursor Rotate Z"));1479rotate_z_button->connect(SceneStringName(pressed),1480callable_mp(this, &GridMapEditor::_menu_option).bind(MENU_OPTION_CURSOR_ROTATE_Z));1481rotation_buttons->add_child(rotate_z_button);1482viewport_shortcut_buttons.push_back(rotate_z_button);14831484// Wide empty separation control. (like BoxContainer::add_spacer())1485Control *c = memnew(Control);1486c->set_mouse_filter(MOUSE_FILTER_PASS);1487c->set_h_size_flags(SIZE_EXPAND_FILL);1488toolbar->add_child(c);14891490floor = memnew(SpinBox);1491floor->set_min(-32767);1492floor->set_max(32767);1493floor->set_step(1);1494floor->set_accessibility_name(TTRC("Change Grid Floor:"));1495floor->set_tooltip_text(1496vformat(TTR("Change Grid Floor:\nPrevious Plane (%s)\nNext Plane (%s)"),1497ED_GET_SHORTCUT("grid_map/previous_floor")->get_as_text(),1498ED_GET_SHORTCUT("grid_map/next_floor")->get_as_text()));1499toolbar->add_child(floor);1500floor->get_line_edit()->add_theme_constant_override("minimum_character_width", 2);1501floor->get_line_edit()->set_context_menu_enabled(false);1502floor->connect(SceneStringName(value_changed), callable_mp(this, &GridMapEditor::_floor_changed));1503floor->connect(SceneStringName(mouse_exited), callable_mp(this, &GridMapEditor::_floor_mouse_exited));1504floor->get_line_edit()->connect(SceneStringName(mouse_exited), callable_mp(this, &GridMapEditor::_floor_mouse_exited));15051506search_box = memnew(LineEdit);1507search_box->add_theme_constant_override("minimum_character_width", 10);1508search_box->set_placeholder(TTR("Filter Meshes"));1509search_box->set_accessibility_name(TTRC("Filter Meshes"));1510search_box->set_clear_button_enabled(true);1511toolbar->add_child(search_box);1512search_box->connect(SceneStringName(text_changed), callable_mp(this, &GridMapEditor::_text_changed));1513search_box->connect(SceneStringName(gui_input), callable_mp(this, &GridMapEditor::_sbox_input));15141515zoom_widget = memnew(EditorZoomWidget);1516toolbar->add_child(zoom_widget);1517zoom_widget->setup_zoom_limits(0.2, 4);1518zoom_widget->set_zoom(1.0);1519zoom_widget->set_anchors_and_offsets_preset(Control::PRESET_TOP_LEFT, Control::PRESET_MODE_MINSIZE, 2 * EDSCALE);1520zoom_widget->connect("zoom_changed", callable_mp(this, &GridMapEditor::_icon_size_changed));1521zoom_widget->set_shortcut_context(this);15221523mode_thumbnail = memnew(Button);1524mode_thumbnail->set_theme_type_variation(SceneStringName(FlatButton));1525mode_thumbnail->set_toggle_mode(true);1526mode_thumbnail->set_accessibility_name(TTRC("View as Thumbnails"));1527mode_thumbnail->set_pressed(true);1528toolbar->add_child(mode_thumbnail);1529mode_thumbnail->connect(SceneStringName(pressed), callable_mp(this, &GridMapEditor::_set_display_mode).bind(DISPLAY_THUMBNAIL));15301531mode_list = memnew(Button);1532mode_list->set_theme_type_variation(SceneStringName(FlatButton));1533mode_list->set_toggle_mode(true);1534mode_list->set_accessibility_name(TTRC("View as List"));1535mode_list->set_pressed(false);1536toolbar->add_child(mode_list);1537mode_list->connect(SceneStringName(pressed), callable_mp(this, &GridMapEditor::_set_display_mode).bind(DISPLAY_LIST));15381539toolbar->add_child(options);15401541mesh_library_palette = memnew(ItemList);1542mesh_library_palette->set_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED);1543add_child(mesh_library_palette);1544mesh_library_palette->set_v_size_flags(SIZE_EXPAND_FILL);1545mesh_library_palette->connect(SceneStringName(gui_input), callable_mp(this, &GridMapEditor::_mesh_library_palette_input));15461547info_message = memnew(Label);1548info_message->set_focus_mode(FOCUS_ACCESSIBILITY);1549info_message->set_text(TTR("Give a MeshLibrary resource to this GridMap to use its meshes."));1550info_message->set_vertical_alignment(VERTICAL_ALIGNMENT_CENTER);1551info_message->set_horizontal_alignment(HORIZONTAL_ALIGNMENT_CENTER);1552info_message->set_autowrap_mode(TextServer::AUTOWRAP_WORD_SMART);1553info_message->set_custom_minimum_size(Size2(100 * EDSCALE, 0));1554info_message->set_anchors_and_offsets_preset(PRESET_FULL_RECT, PRESET_MODE_KEEP_SIZE, 8 * EDSCALE);1555mesh_library_palette->add_child(info_message);15561557edit_axis = Vector3::AXIS_Y;1558edit_floor[0] = -1;1559edit_floor[1] = -1;1560edit_floor[2] = -1;15611562cursor_mesh = RenderingServer::get_singleton()->mesh_create();1563selection_mesh = RenderingServer::get_singleton()->mesh_create();1564paste_mesh = RenderingServer::get_singleton()->mesh_create();15651566{1567// Selection mesh create.15681569Vector<Vector3> lines;1570Vector<Vector3> triangles;1571Vector<Vector3> square[3];15721573for (int i = 0; i < 6; i++) {1574Vector3 face_points[4];15751576for (int j = 0; j < 4; j++) {1577float v[3];1578v[0] = 1.0;1579v[1] = 1 - 2 * ((j >> 1) & 1);1580v[2] = v[1] * (1 - 2 * (j & 1));15811582for (int k = 0; k < 3; k++) {1583if (i < 3) {1584face_points[j][(i + k) % 3] = v[k];1585} else {1586face_points[3 - j][(i + k) % 3] = -v[k];1587}1588}1589}15901591triangles.push_back(face_points[0] * 0.5 + Vector3(0.5, 0.5, 0.5));1592triangles.push_back(face_points[1] * 0.5 + Vector3(0.5, 0.5, 0.5));1593triangles.push_back(face_points[2] * 0.5 + Vector3(0.5, 0.5, 0.5));15941595triangles.push_back(face_points[2] * 0.5 + Vector3(0.5, 0.5, 0.5));1596triangles.push_back(face_points[3] * 0.5 + Vector3(0.5, 0.5, 0.5));1597triangles.push_back(face_points[0] * 0.5 + Vector3(0.5, 0.5, 0.5));1598}15991600for (int i = 0; i < 12; i++) {1601AABB base(Vector3(0, 0, 0), Vector3(1, 1, 1));1602Vector3 a, b;1603base.get_edge(i, a, b);1604lines.push_back(a);1605lines.push_back(b);1606}16071608for (int i = 0; i < 3; i++) {1609Vector3 points[4];1610for (int j = 0; j < 4; j++) {1611static const bool orderx[4] = { false, true, true, false };1612static const bool ordery[4] = { false, false, true, true };16131614Vector3 sp;1615if (orderx[j]) {1616sp[(i + 1) % 3] = 1.0;1617}1618if (ordery[j]) {1619sp[(i + 2) % 3] = 1.0;1620}16211622points[j] = sp;1623}16241625for (int j = 0; j < 4; j++) {1626Vector3 ofs;1627ofs[i] += 0.01;1628square[i].push_back(points[j] - ofs);1629square[i].push_back(points[(j + 1) % 4] - ofs);1630square[i].push_back(points[j] + ofs);1631square[i].push_back(points[(j + 1) % 4] + ofs);1632}1633}16341635Array d;1636d.resize(RS::ARRAY_MAX);16371638default_color = Color(0.0, 0.565, 1.0); // blue 0.7, 0.7, 1.01639erase_color = Color(1.0, 0.2, 0.2); // red1640pick_color = Color(1, 0.7, 0); // orange/yellow16411642cursor_inner_mat.instantiate();1643cursor_inner_mat->set_albedo(Color(default_color, 0.2));1644cursor_inner_mat->set_shading_mode(StandardMaterial3D::SHADING_MODE_UNSHADED);1645cursor_inner_mat->set_flag(StandardMaterial3D::FLAG_DISABLE_FOG, true);1646cursor_inner_mat->set_transparency(StandardMaterial3D::TRANSPARENCY_ALPHA);16471648cursor_outer_mat.instantiate();1649cursor_outer_mat->set_albedo(Color(default_color, 0.8));1650cursor_outer_mat->set_on_top_of_alpha();1651cursor_outer_mat->set_shading_mode(StandardMaterial3D::SHADING_MODE_UNSHADED);1652cursor_outer_mat->set_transparency(StandardMaterial3D::TRANSPARENCY_ALPHA);1653cursor_outer_mat->set_flag(StandardMaterial3D::FLAG_DISABLE_FOG, true);16541655inner_mat.instantiate();1656inner_mat->set_albedo(Color(default_color, 0.2));1657inner_mat->set_shading_mode(StandardMaterial3D::SHADING_MODE_UNSHADED);1658inner_mat->set_flag(StandardMaterial3D::FLAG_DISABLE_FOG, true);1659inner_mat->set_transparency(StandardMaterial3D::TRANSPARENCY_ALPHA);16601661outer_mat.instantiate();1662outer_mat->set_albedo(Color(default_color, 0.8));1663outer_mat->set_on_top_of_alpha();1664outer_mat->set_shading_mode(StandardMaterial3D::SHADING_MODE_UNSHADED);1665outer_mat->set_transparency(StandardMaterial3D::TRANSPARENCY_ALPHA);1666outer_mat->set_flag(StandardMaterial3D::FLAG_DISABLE_FOG, true);16671668selection_floor_mat.instantiate();1669selection_floor_mat->set_albedo(Color(0.80, 0.80, 1.0, 1));1670selection_floor_mat->set_on_top_of_alpha();1671selection_floor_mat->set_shading_mode(StandardMaterial3D::SHADING_MODE_UNSHADED);1672selection_floor_mat->set_flag(StandardMaterial3D::FLAG_DISABLE_FOG, true);16731674d[RS::ARRAY_VERTEX] = triangles;1675RenderingServer::get_singleton()->mesh_add_surface_from_arrays(cursor_mesh, RS::PRIMITIVE_TRIANGLES, d);1676RenderingServer::get_singleton()->mesh_surface_set_material(cursor_mesh, 0, cursor_inner_mat->get_rid());16771678d[RS::ARRAY_VERTEX] = lines;1679RenderingServer::get_singleton()->mesh_add_surface_from_arrays(cursor_mesh, RS::PRIMITIVE_LINES, d);1680RenderingServer::get_singleton()->mesh_surface_set_material(cursor_mesh, 1, cursor_outer_mat->get_rid());16811682d[RS::ARRAY_VERTEX] = triangles;1683RenderingServer::get_singleton()->mesh_add_surface_from_arrays(selection_mesh, RS::PRIMITIVE_TRIANGLES, d);1684RenderingServer::get_singleton()->mesh_surface_set_material(selection_mesh, 0, inner_mat->get_rid());16851686d[RS::ARRAY_VERTEX] = lines;1687RenderingServer::get_singleton()->mesh_add_surface_from_arrays(selection_mesh, RS::PRIMITIVE_LINES, d);1688RenderingServer::get_singleton()->mesh_surface_set_material(selection_mesh, 1, outer_mat->get_rid());16891690d[RS::ARRAY_VERTEX] = triangles;1691RenderingServer::get_singleton()->mesh_add_surface_from_arrays(paste_mesh, RS::PRIMITIVE_TRIANGLES, d);1692RenderingServer::get_singleton()->mesh_surface_set_material(paste_mesh, 0, inner_mat->get_rid());16931694d[RS::ARRAY_VERTEX] = lines;1695RenderingServer::get_singleton()->mesh_add_surface_from_arrays(paste_mesh, RS::PRIMITIVE_LINES, d);1696RenderingServer::get_singleton()->mesh_surface_set_material(paste_mesh, 1, outer_mat->get_rid());16971698for (int i = 0; i < 3; i++) {1699d[RS::ARRAY_VERTEX] = square[i];1700selection_level_mesh[i] = RS::get_singleton()->mesh_create();1701RenderingServer::get_singleton()->mesh_add_surface_from_arrays(selection_level_mesh[i], RS::PRIMITIVE_LINES, d);1702RenderingServer::get_singleton()->mesh_surface_set_material(selection_level_mesh[i], 0, selection_floor_mat->get_rid());1703}1704}17051706_set_selection(false);17071708indicator_mat.instantiate();1709indicator_mat->set_shading_mode(StandardMaterial3D::SHADING_MODE_UNSHADED);1710indicator_mat->set_transparency(StandardMaterial3D::TRANSPARENCY_ALPHA);1711indicator_mat->set_flag(StandardMaterial3D::FLAG_SRGB_VERTEX_COLOR, true);1712indicator_mat->set_flag(StandardMaterial3D::FLAG_ALBEDO_FROM_VERTEX_COLOR, true);1713indicator_mat->set_flag(StandardMaterial3D::FLAG_DISABLE_FOG, true);1714indicator_mat->set_albedo(EDITOR_GET("editors/3d_gizmos/gizmo_colors/gridmap_grid"));1715}17161717GridMapEditor::~GridMapEditor() {1718ERR_FAIL_NULL(RenderingServer::get_singleton());1719_clear_clipboard_data();17201721for (int i = 0; i < 3; i++) {1722if (grid[i].is_valid()) {1723RenderingServer::get_singleton()->free_rid(grid[i]);1724}1725if (grid_instance[i].is_valid()) {1726RenderingServer::get_singleton()->free_rid(grid_instance[i]);1727}1728if (selection_level_instance[i].is_valid()) {1729RenderingServer::get_singleton()->free_rid(selection_level_instance[i]);1730}1731if (selection_level_mesh[i].is_valid()) {1732RenderingServer::get_singleton()->free_rid(selection_level_mesh[i]);1733}1734}17351736RenderingServer::get_singleton()->free_rid(cursor_mesh);1737if (cursor_instance.is_valid()) {1738RenderingServer::get_singleton()->free_rid(cursor_instance);1739}17401741RenderingServer::get_singleton()->free_rid(selection_mesh);1742if (selection_instance.is_valid()) {1743RenderingServer::get_singleton()->free_rid(selection_instance);1744}17451746RenderingServer::get_singleton()->free_rid(paste_mesh);1747if (paste_instance.is_valid()) {1748RenderingServer::get_singleton()->free_rid(paste_instance);1749}1750}17511752void GridMapEditorPlugin::_notification(int p_what) {1753switch (p_what) {1754case NOTIFICATION_ENTER_TREE: {1755grid_map_editor = memnew(GridMapEditor);1756grid_map_editor->set_h_size_flags(Control::SIZE_EXPAND_FILL);1757grid_map_editor->set_v_size_flags(Control::SIZE_EXPAND_FILL);1758grid_map_editor->set_custom_minimum_size(Size2(0, 200) * EDSCALE);1759grid_map_editor->hide();17601761panel_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")));1762panel_button->hide();1763} break;1764case NOTIFICATION_EXIT_TREE: {1765EditorNode::get_bottom_panel()->remove_item(grid_map_editor);1766memdelete_notnull(grid_map_editor);1767grid_map_editor = nullptr;1768panel_button = nullptr;1769} break;1770}1771}17721773void GridMapEditorPlugin::_bind_methods() {1774ClassDB::bind_method(D_METHOD("get_current_grid_map"), &GridMapEditorPlugin::get_current_grid_map);1775ClassDB::bind_method(D_METHOD("set_selection", "begin", "end"), &GridMapEditorPlugin::set_selection);1776ClassDB::bind_method(D_METHOD("clear_selection"), &GridMapEditorPlugin::clear_selection);1777ClassDB::bind_method(D_METHOD("get_selection"), &GridMapEditorPlugin::get_selection);1778ClassDB::bind_method(D_METHOD("has_selection"), &GridMapEditorPlugin::has_selection);1779ClassDB::bind_method(D_METHOD("get_selected_cells"), &GridMapEditorPlugin::get_selected_cells);1780ClassDB::bind_method(D_METHOD("set_selected_palette_item", "item"), &GridMapEditorPlugin::set_selected_palette_item);1781ClassDB::bind_method(D_METHOD("get_selected_palette_item"), &GridMapEditorPlugin::get_selected_palette_item);1782}17831784void GridMapEditorPlugin::edit(Object *p_object) {1785ERR_FAIL_NULL(grid_map_editor);1786grid_map_editor->edit(Object::cast_to<GridMap>(p_object));1787}17881789bool GridMapEditorPlugin::handles(Object *p_object) const {1790return p_object->is_class("GridMap");1791}17921793void GridMapEditorPlugin::make_visible(bool p_visible) {1794ERR_FAIL_NULL(grid_map_editor);1795if (p_visible) {1796BaseButton *button = grid_map_editor->mode_buttons_group->get_pressed_button();1797if (button == nullptr) {1798grid_map_editor->select_mode_button->set_pressed(true);1799}1800grid_map_editor->_on_tool_mode_changed();1801panel_button->show();1802EditorNode::get_bottom_panel()->make_item_visible(grid_map_editor);1803grid_map_editor->set_process(true);1804} else {1805grid_map_editor->_show_viewports_transform_gizmo(true);1806panel_button->hide();1807if (grid_map_editor->is_visible_in_tree()) {1808EditorNode::get_bottom_panel()->hide_bottom_panel();1809}1810grid_map_editor->set_process(false);1811}1812}18131814GridMap *GridMapEditorPlugin::get_current_grid_map() const {1815ERR_FAIL_NULL_V(grid_map_editor, nullptr);1816return grid_map_editor->node;1817}18181819void GridMapEditorPlugin::set_selection(const Vector3i &p_begin, const Vector3i &p_end) {1820ERR_FAIL_NULL(grid_map_editor);1821grid_map_editor->_set_selection(true, p_begin, p_end);1822}18231824void GridMapEditorPlugin::clear_selection() {1825ERR_FAIL_NULL(grid_map_editor);1826grid_map_editor->_set_selection(false);1827}18281829AABB GridMapEditorPlugin::get_selection() const {1830ERR_FAIL_NULL_V(grid_map_editor, AABB());1831return grid_map_editor->_get_selection();1832}18331834bool GridMapEditorPlugin::has_selection() const {1835ERR_FAIL_NULL_V(grid_map_editor, false);1836return grid_map_editor->_has_selection();1837}18381839Array GridMapEditorPlugin::get_selected_cells() const {1840ERR_FAIL_NULL_V(grid_map_editor, Array());1841return grid_map_editor->_get_selected_cells();1842}18431844void GridMapEditorPlugin::set_selected_palette_item(int p_item) const {1845ERR_FAIL_NULL(grid_map_editor);1846if (grid_map_editor->node && grid_map_editor->node->get_mesh_library().is_valid()) {1847if (p_item < -1) {1848p_item = -1;1849} else if (p_item >= grid_map_editor->node->get_mesh_library()->get_item_list().size()) {1850p_item = grid_map_editor->node->get_mesh_library()->get_item_list().size() - 1;1851}1852if (p_item != grid_map_editor->selected_palette) {1853grid_map_editor->selected_palette = p_item;1854grid_map_editor->_update_cursor_instance();1855grid_map_editor->update_palette();1856}1857}1858}18591860int GridMapEditorPlugin::get_selected_palette_item() const {1861ERR_FAIL_NULL_V(grid_map_editor, 0);1862if (grid_map_editor->selected_palette >= 0 && grid_map_editor->node && grid_map_editor->node->get_mesh_library().is_valid()) {1863return grid_map_editor->selected_palette;1864} else {1865return -1;1866}1867}186818691870