Path: blob/master/modules/gridmap/editor/grid_map_editor_plugin.cpp
10278 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.begin;165paste_indicator.current = selection.begin;166paste_indicator.begin = selection.begin;167paste_indicator.end = selection.end;168paste_indicator.orientation = 0;169_update_paste_indicator();170} break;171case MENU_OPTION_SELECTION_CLEAR: {172if (!selection.active) {173break;174}175176_delete_selection();177178} break;179case MENU_OPTION_SELECTION_FILL: {180if (!selection.active) {181return;182}183184_fill_selection();185186} break;187case MENU_OPTION_GRIDMAP_SETTINGS: {188settings_dialog->popup_centered(settings_vbc->get_combined_minimum_size() + Size2(50, 50) * EDSCALE);189} break;190}191}192193void GridMapEditor::_update_cursor_transform() {194cursor_transform = Transform3D();195cursor_transform.origin = cursor_origin;196cursor_transform.basis *= node->get_cell_scale();197cursor_transform = node->get_global_transform() * cursor_transform;198199if (mode_buttons_group->get_pressed_button() == paint_mode_button) {200// Auto-deselect the selection when painting.201if (selection.active) {202_set_selection(false);203}204// Rotation is only applied in paint mode, we don't want the cursor box to rotate otherwise.205cursor_transform.basis = node->get_basis_with_orthogonal_index(cursor_rot);206if (selected_palette >= 0 && node && node->get_mesh_library().is_valid()) {207cursor_transform *= node->get_mesh_library()->get_item_mesh_transform(selected_palette);208}209} else {210Transform3D xf;211xf.scale(node->get_cell_size());212xf.origin.x = node->get_center_x() ? -node->get_cell_size().x / 2 : 0;213xf.origin.y = node->get_center_y() ? -node->get_cell_size().y / 2 : 0;214xf.origin.z = node->get_center_z() ? -node->get_cell_size().z / 2 : 0;215cursor_transform *= xf;216}217218if (cursor_instance.is_valid()) {219RenderingServer::get_singleton()->instance_set_transform(cursor_instance, cursor_transform);220RenderingServer::get_singleton()->instance_set_visible(cursor_instance, cursor_visible);221}222}223224void GridMapEditor::_update_selection_transform() {225Transform3D xf_zero;226xf_zero.basis.set_zero();227228if (!selection.active) {229RenderingServer::get_singleton()->instance_set_transform(selection_instance, xf_zero);230for (int i = 0; i < 3; i++) {231RenderingServer::get_singleton()->instance_set_transform(selection_level_instance[i], xf_zero);232}233return;234}235236Transform3D xf;237xf.scale((Vector3(1, 1, 1) + (selection.end - selection.begin)) * node->get_cell_size());238xf.origin = selection.begin * node->get_cell_size();239240RenderingServer::get_singleton()->instance_set_transform(selection_instance, node->get_global_transform() * xf);241242for (int i = 0; i < 3; i++) {243if (i != edit_axis || (edit_floor[edit_axis] < selection.begin[edit_axis]) || (edit_floor[edit_axis] > selection.end[edit_axis] + 1)) {244RenderingServer::get_singleton()->instance_set_transform(selection_level_instance[i], xf_zero);245} else {246Vector3 scale = (selection.end - selection.begin + Vector3(1, 1, 1));247scale[edit_axis] = 1.0;248Vector3 position = selection.begin;249position[edit_axis] = edit_floor[edit_axis];250251scale *= node->get_cell_size();252position *= node->get_cell_size();253254Transform3D xf2;255xf2.basis.scale(scale);256xf2.origin = position;257258RenderingServer::get_singleton()->instance_set_transform(selection_level_instance[i], node->get_global_transform() * xf2);259}260}261}262263void GridMapEditor::_validate_selection() {264if (!selection.active) {265return;266}267selection.begin = selection.click;268selection.end = selection.current;269270if (selection.begin.x > selection.end.x) {271SWAP(selection.begin.x, selection.end.x);272}273if (selection.begin.y > selection.end.y) {274SWAP(selection.begin.y, selection.end.y);275}276if (selection.begin.z > selection.end.z) {277SWAP(selection.begin.z, selection.end.z);278}279280_update_selection_transform();281}282283void GridMapEditor::_set_selection(bool p_active, const Vector3 &p_begin, const Vector3 &p_end) {284selection.active = p_active;285selection.begin = p_begin;286selection.end = p_end;287selection.click = p_begin;288selection.current = p_end;289290if (is_visible_in_tree()) {291_update_selection_transform();292}293}294295AABB GridMapEditor::_get_selection() const {296AABB ret;297if (selection.active) {298ret.position = selection.begin;299ret.size = selection.end - selection.begin;300} else {301ret.position.zero();302ret.size.zero();303}304return ret;305}306307bool GridMapEditor::_has_selection() const {308return node != nullptr && selection.active;309}310311Array GridMapEditor::_get_selected_cells() const {312Array ret;313if (node != nullptr && selection.active) {314for (int i = selection.begin.x; i <= selection.end.x; i++) {315for (int j = selection.begin.y; j <= selection.end.y; j++) {316for (int k = selection.begin.z; k <= selection.end.z; k++) {317Vector3i selected = Vector3i(i, j, k);318int itm = node->get_cell_item(selected);319if (itm == GridMap::INVALID_CELL_ITEM) {320continue;321}322ret.append(selected);323}324}325}326}327return ret;328}329330bool GridMapEditor::do_input_action(Camera3D *p_camera, const Point2 &p_point, bool p_click) {331if (!spatial_editor) {332return false;333}334if (input_action == INPUT_TRANSFORM) {335return false;336}337if (selected_palette < 0 && input_action != INPUT_NONE && input_action != INPUT_PICK && input_action != INPUT_SELECT && input_action != INPUT_PASTE) {338return false;339}340if (mesh_library.is_null()) {341return false;342}343if (input_action != INPUT_NONE && input_action != INPUT_PICK && input_action != INPUT_SELECT && input_action != INPUT_PASTE && !mesh_library->has_item(selected_palette)) {344return false;345}346347Camera3D *camera = p_camera;348Vector3 from = camera->project_ray_origin(p_point);349Vector3 normal = camera->project_ray_normal(p_point);350Transform3D local_xform = node->get_global_transform().affine_inverse();351Vector<Plane> planes = camera->get_frustum();352from = local_xform.xform(from);353normal = local_xform.basis.xform(normal).normalized();354355Plane p;356p.normal[edit_axis] = 1.0;357p.d = edit_floor[edit_axis] * node->get_cell_size()[edit_axis];358359Vector3 inters;360if (!p.intersects_segment(from, from + normal * settings_pick_distance->get_value(), &inters)) {361return false;362}363364// Make sure the intersection is inside the frustum planes, to avoid365// Painting on invisible regions.366for (int i = 0; i < planes.size(); i++) {367Plane fp = local_xform.xform(planes[i]);368if (fp.is_point_over(inters)) {369return false;370}371}372373int cell[3];374Vector3 cell_size = node->get_cell_size();375376for (int i = 0; i < 3; i++) {377if (i == edit_axis) {378cell[i] = edit_floor[i];379} else {380cell[i] = inters[i] / cell_size[i];381if (inters[i] < 0) {382cell[i] -= 1; // Compensate negative.383}384grid_ofs[i] = cell[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(cell[0], cell[1], cell[2]) + 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 = Vector3i(cell[0], cell[1], cell[2]);407_update_paste_indicator();408409} else if (input_action == INPUT_SELECT) {410selection.current = Vector3i(cell[0], cell[1], cell[2]);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(Vector3i(cell[0], cell[1], cell[2]));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 = Vector3i(cell[0], cell[1], cell[2]);440si.new_value = selected_palette;441si.new_orientation = cursor_rot;442si.old_value = node->get_cell_item(Vector3i(cell[0], cell[1], cell[2]));443si.old_orientation = node->get_cell_item_orientation(Vector3i(cell[0], cell[1], cell[2]));444set_items.push_back(si);445node->set_cell_item(Vector3i(cell[0], cell[1], cell[2]), selected_palette, cursor_rot);446return true;447} else if (input_action == INPUT_ERASE) {448SetItem si;449si.position = Vector3i(cell[0], cell[1], cell[2]);450si.new_value = -1;451si.new_orientation = 0;452si.old_value = node->get_cell_item(Vector3i(cell[0], cell[1], cell[2]));453si.old_orientation = node->get_cell_item_orientation(Vector3i(cell[0], cell[1], cell[2]));454set_items.push_back(si);455node->set_cell_item(Vector3i(cell[0], cell[1], cell[2]), -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(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.begin + (paste_indicator.current - paste_indicator.click) + 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.begin + (paste_indicator.current - paste_indicator.click) + 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);591592Vector3 ofs = paste_indicator.current - paste_indicator.click;593EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();594undo_redo->create_action(TTR("GridMap Paste Selection"));595596for (const ClipboardItem &item : clipboard_items) {597Vector3 position = rot.xform(item.grid_offset) + paste_indicator.begin + ofs;598599Basis orm;600orm = node->get_basis_with_orthogonal_index(item.orientation);601orm = rot * orm;602603undo_redo->add_do_method(node, "set_cell_item", position, item.cell_item, node->get_orthogonal_index_from_basis(orm));604undo_redo->add_undo_method(node, "set_cell_item", position, node->get_cell_item(position), node->get_cell_item_orientation(position));605}606607if (reselect) {608// We need to rotate the paste_indicator to find the selection begin and end:609Vector3 temp_end = rot.xform(paste_indicator.end - paste_indicator.begin) + paste_indicator.begin + ofs;610Vector3 temp_begin = paste_indicator.begin + ofs;611// _set_selection expects that selection_begin is the corner closer to the origin:612for (int i = 0; i < 3; ++i) {613if (temp_begin[i] > temp_end[i]) {614float p = temp_begin[i];615temp_begin[i] = temp_end[i];616temp_end[i] = p;617}618}619undo_redo->add_do_method(this, "_set_selection", true, temp_begin, temp_end);620undo_redo->add_undo_method(this, "_set_selection", selection.active, selection.begin, selection.end);621}622623undo_redo->commit_action();624625_clear_clipboard_data();626}627628void GridMapEditor::_show_viewports_transform_gizmo(bool p_value) {629Dictionary new_state;630new_state["transform_gizmo"] = p_value;631for (uint32_t i = 0; i < Node3DEditor::VIEWPORTS_COUNT; i++) {632Node3DEditorViewport *viewport = Node3DEditor::get_singleton()->get_editor_viewport(i);633viewport->set_state(new_state);634}635}636637EditorPlugin::AfterGUIInput GridMapEditor::forward_spatial_input_event(Camera3D *p_camera, const Ref<InputEvent> &p_event) {638// If the mouse is currently captured, we are most likely in freelook mode.639// In this case, disable shortcuts to avoid conflicts with freelook navigation.640if (!node || Input::get_singleton()->get_mouse_mode() == Input::MOUSE_MODE_CAPTURED) {641return EditorPlugin::AFTER_GUI_INPUT_PASS;642}643644Ref<InputEventKey> k = p_event;645if (k.is_valid() && k->is_pressed() && !k->is_echo()) {646// Transform mode (toggle button):647// If we are in Transform mode we pass the events to the 3D editor,648// but if the Transform mode shortcut is pressed again, we go back to Selection mode.649if (mode_buttons_group->get_pressed_button() == transform_mode_button) {650if (transform_mode_button->get_shortcut().is_valid() && transform_mode_button->get_shortcut()->matches_event(p_event)) {651select_mode_button->set_pressed(true);652accept_event();653return EditorPlugin::AFTER_GUI_INPUT_STOP;654}655return EditorPlugin::AFTER_GUI_INPUT_PASS;656}657// Tool modes and tool actions:658for (BaseButton *b : viewport_shortcut_buttons) {659if (b->is_disabled()) {660continue;661}662663if (b->get_shortcut().is_valid() && b->get_shortcut()->matches_event(p_event)) {664if (b->is_toggle_mode()) {665b->set_pressed(b->get_button_group().is_valid() || !b->is_pressed());666} else {667// Can't press a button without toggle mode, so just emit the signal directly.668b->emit_signal(SceneStringName(pressed));669}670accept_event();671return EditorPlugin::AFTER_GUI_INPUT_STOP;672}673}674// Hard key actions:675if (k->get_keycode() == Key::ESCAPE) {676if (input_action == INPUT_PASTE) {677_clear_clipboard_data();678input_action = INPUT_NONE;679_update_paste_indicator();680return EditorPlugin::AFTER_GUI_INPUT_STOP;681} else if (selection.active) {682_set_selection(false);683return EditorPlugin::AFTER_GUI_INPUT_STOP;684} else {685input_action = INPUT_NONE;686update_palette();687_update_cursor_instance();688return EditorPlugin::AFTER_GUI_INPUT_STOP;689}690}691// Options menu shortcuts:692Ref<Shortcut> ed_shortcut = ED_GET_SHORTCUT("grid_map/previous_floor");693if (ed_shortcut.is_valid() && ed_shortcut->matches_event(p_event)) {694accept_event();695_menu_option(MENU_OPTION_PREV_LEVEL);696return EditorPlugin::AFTER_GUI_INPUT_STOP;697}698ed_shortcut = ED_GET_SHORTCUT("grid_map/next_floor");699if (ed_shortcut.is_valid() && ed_shortcut->matches_event(p_event)) {700accept_event();701_menu_option(MENU_OPTION_NEXT_LEVEL);702return EditorPlugin::AFTER_GUI_INPUT_STOP;703}704for (int i = 0; i < options->get_popup()->get_item_count(); ++i) {705const Ref<Shortcut> &shortcut = options->get_popup()->get_item_shortcut(i);706if (shortcut.is_valid() && shortcut->matches_event(p_event)) {707// Consume input to avoid conflicts with other plugins.708accept_event();709_menu_option(options->get_popup()->get_item_id(i));710return EditorPlugin::AFTER_GUI_INPUT_STOP;711}712}713}714715Ref<InputEventMouseButton> mb = p_event;716if (mb.is_valid()) {717if (mb->get_button_index() == MouseButton::WHEEL_UP && (mb->is_command_or_control_pressed())) {718if (mb->is_pressed()) {719floor->set_value(floor->get_value() + mb->get_factor());720}721722return EditorPlugin::AFTER_GUI_INPUT_STOP; // Eaten.723} else if (mb->get_button_index() == MouseButton::WHEEL_DOWN && (mb->is_command_or_control_pressed())) {724if (mb->is_pressed()) {725floor->set_value(floor->get_value() - mb->get_factor());726}727return EditorPlugin::AFTER_GUI_INPUT_STOP;728}729730if (mb->is_pressed()) {731Node3DEditorViewport::NavigationScheme nav_scheme = (Node3DEditorViewport::NavigationScheme)EDITOR_GET("editors/3d/navigation/navigation_scheme").operator int();732if ((nav_scheme == Node3DEditorViewport::NAVIGATION_MAYA || nav_scheme == Node3DEditorViewport::NAVIGATION_MODO) && mb->is_alt_pressed()) {733input_action = INPUT_NONE;734} else if (mb->get_button_index() == MouseButton::LEFT) {735bool can_edit = (node && node->get_mesh_library().is_valid());736if (input_action == INPUT_PASTE) {737_do_paste();738input_action = INPUT_NONE;739_update_paste_indicator();740return EditorPlugin::AFTER_GUI_INPUT_STOP;741} else if (mode_buttons_group->get_pressed_button() == select_mode_button && can_edit) {742input_action = INPUT_SELECT;743last_selection = selection;744} else if (mode_buttons_group->get_pressed_button() == pick_mode_button && can_edit) {745input_action = INPUT_PICK;746} else if (mode_buttons_group->get_pressed_button() == paint_mode_button && can_edit) {747input_action = INPUT_PAINT;748set_items.clear();749} else if (mode_buttons_group->get_pressed_button() == erase_mode_button && can_edit) {750input_action = INPUT_ERASE;751set_items.clear();752}753} else if (mb->get_button_index() == MouseButton::RIGHT) {754if (input_action == INPUT_PASTE) {755_clear_clipboard_data();756input_action = INPUT_NONE;757_update_paste_indicator();758return EditorPlugin::AFTER_GUI_INPUT_STOP;759} else if (selection.active) {760_set_selection(false);761return EditorPlugin::AFTER_GUI_INPUT_STOP;762}763} else {764return EditorPlugin::AFTER_GUI_INPUT_PASS;765}766767if (do_input_action(p_camera, Point2(mb->get_position().x, mb->get_position().y), true)) {768return EditorPlugin::AFTER_GUI_INPUT_STOP;769}770return EditorPlugin::AFTER_GUI_INPUT_PASS;771} else {772if ((mb->get_button_index() == MouseButton::LEFT && input_action == INPUT_ERASE) || (mb->get_button_index() == MouseButton::LEFT && input_action == INPUT_PAINT)) {773if (set_items.size()) {774EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();775undo_redo->create_action(TTR("GridMap Paint"));776for (const SetItem &si : set_items) {777undo_redo->add_do_method(node, "set_cell_item", si.position, si.new_value, si.new_orientation);778}779for (uint32_t i = set_items.size(); i > 0; i--) {780const SetItem &si = set_items[i - 1];781undo_redo->add_undo_method(node, "set_cell_item", si.position, si.old_value, si.old_orientation);782}783784undo_redo->commit_action();785}786set_items.clear();787input_action = INPUT_NONE;788789if (set_items.size() > 0) {790return EditorPlugin::AFTER_GUI_INPUT_STOP;791}792return EditorPlugin::AFTER_GUI_INPUT_PASS;793}794795if (mb->get_button_index() == MouseButton::LEFT && input_action == INPUT_SELECT) {796EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();797undo_redo->create_action(TTR("GridMap Selection"));798undo_redo->add_do_method(this, "_set_selection", selection.active, selection.begin, selection.end);799undo_redo->add_undo_method(this, "_set_selection", last_selection.active, last_selection.begin, last_selection.end);800undo_redo->commit_action();801}802803if (mb->get_button_index() == MouseButton::LEFT && input_action != INPUT_NONE) {804set_items.clear();805input_action = INPUT_NONE;806return EditorPlugin::AFTER_GUI_INPUT_STOP;807}808if (mb->get_button_index() == MouseButton::RIGHT && (input_action == INPUT_ERASE || input_action == INPUT_PASTE)) {809input_action = INPUT_NONE;810return EditorPlugin::AFTER_GUI_INPUT_STOP;811}812}813}814815Ref<InputEventMouseMotion> mm = p_event;816817if (mm.is_valid()) {818// Update the grid, to check if the grid needs to be moved to a tile cursor.819update_grid();820821if (do_input_action(p_camera, mm->get_position(), false)) {822return EditorPlugin::AFTER_GUI_INPUT_STOP;823}824return EditorPlugin::AFTER_GUI_INPUT_PASS;825}826827Ref<InputEventPanGesture> pan_gesture = p_event;828if (pan_gesture.is_valid()) {829if (pan_gesture->is_alt_pressed() && pan_gesture->is_command_or_control_pressed()) {830const real_t delta = pan_gesture->get_delta().y * 0.5;831accumulated_floor_delta += delta;832int step = 0;833if (Math::abs(accumulated_floor_delta) > 1.0) {834step = SIGN(accumulated_floor_delta);835accumulated_floor_delta -= step;836}837if (step) {838floor->set_value(floor->get_value() + step);839}840return EditorPlugin::AFTER_GUI_INPUT_STOP;841}842}843accumulated_floor_delta = 0.0;844845return EditorPlugin::AFTER_GUI_INPUT_PASS;846}847848struct _CGMEItemSort {849String name;850int id = 0;851_FORCE_INLINE_ bool operator<(const _CGMEItemSort &r_it) const { return name < r_it.name; }852};853854void GridMapEditor::_set_display_mode(int p_mode) {855if (display_mode == p_mode) {856return;857}858859if (p_mode == DISPLAY_LIST) {860mode_list->set_pressed(true);861mode_thumbnail->set_pressed(false);862} else if (p_mode == DISPLAY_THUMBNAIL) {863mode_list->set_pressed(false);864mode_thumbnail->set_pressed(true);865}866867display_mode = p_mode;868869update_palette();870}871872void GridMapEditor::_text_changed(const String &p_text) {873update_palette();874}875876void GridMapEditor::_sbox_input(const Ref<InputEvent> &p_event) {877// Redirect navigational key events to the item list.878Ref<InputEventKey> key = p_event;879if (key.is_valid()) {880if (key->is_action("ui_up", true) || key->is_action("ui_down", true) || key->is_action("ui_page_up") || key->is_action("ui_page_down")) {881mesh_library_palette->gui_input(key);882search_box->accept_event();883}884}885}886887void GridMapEditor::_mesh_library_palette_input(const Ref<InputEvent> &p_ie) {888const Ref<InputEventMouseButton> mb = p_ie;889890// Zoom in/out using Ctrl + mouse wheel891if (mb.is_valid() && mb->is_pressed() && mb->is_command_or_control_pressed()) {892if (mb->is_pressed() && mb->get_button_index() == MouseButton::WHEEL_UP) {893zoom_widget->set_zoom(zoom_widget->get_zoom() + 0.2);894zoom_widget->emit_signal(SNAME("zoom_changed"), zoom_widget->get_zoom());895}896897if (mb->is_pressed() && mb->get_button_index() == MouseButton::WHEEL_DOWN) {898zoom_widget->set_zoom(zoom_widget->get_zoom() - 0.2);899zoom_widget->emit_signal(SNAME("zoom_changed"), zoom_widget->get_zoom());900}901}902}903904void GridMapEditor::_icon_size_changed(float p_value) {905mesh_library_palette->set_icon_scale(p_value);906update_palette();907}908909void GridMapEditor::update_palette() {910float min_size = EDITOR_GET("editors/grid_map/preview_size");911min_size *= EDSCALE;912913mesh_library_palette->clear();914if (display_mode == DISPLAY_THUMBNAIL) {915mesh_library_palette->set_max_columns(0);916mesh_library_palette->set_icon_mode(ItemList::ICON_MODE_TOP);917mesh_library_palette->set_fixed_column_width(min_size * MAX(zoom_widget->get_zoom(), 1.5));918} else if (display_mode == DISPLAY_LIST) {919mesh_library_palette->set_max_columns(0);920mesh_library_palette->set_icon_mode(ItemList::ICON_MODE_LEFT);921mesh_library_palette->set_fixed_column_width(0);922}923924mesh_library_palette->set_fixed_icon_size(Size2(min_size, min_size));925mesh_library_palette->set_max_text_lines(2);926927if (mesh_library.is_null()) {928search_box->set_text("");929search_box->set_editable(false);930info_message->show();931return;932}933934search_box->set_editable(true);935info_message->hide();936937Vector<int> ids;938ids = mesh_library->get_item_list();939940List<_CGMEItemSort> il;941for (int i = 0; i < ids.size(); i++) {942_CGMEItemSort is;943is.id = ids[i];944is.name = mesh_library->get_item_name(ids[i]);945il.push_back(is);946}947il.sort();948949String filter = search_box->get_text().strip_edges();950951int item = 0;952953for (_CGMEItemSort &E : il) {954int id = E.id;955String name = mesh_library->get_item_name(id);956Ref<Texture2D> preview = mesh_library->get_item_preview(id);957958if (name.is_empty()) {959name = "#" + itos(id);960}961962if (!filter.is_empty() && !filter.is_subsequence_ofn(name)) {963continue;964}965966mesh_library_palette->add_item("");967if (preview.is_valid()) {968mesh_library_palette->set_item_icon(item, preview);969mesh_library_palette->set_item_tooltip(item, name);970}971mesh_library_palette->set_item_text(item, name);972mesh_library_palette->set_item_metadata(item, id);973974if (selected_palette == id) {975mesh_library_palette->select(item);976}977978item++;979}980}981982void GridMapEditor::_update_mesh_library() {983ERR_FAIL_NULL(node);984985Ref<MeshLibrary> new_mesh_library = node->get_mesh_library();986if (new_mesh_library != mesh_library) {987if (mesh_library.is_valid()) {988mesh_library->disconnect_changed(callable_mp(this, &GridMapEditor::update_palette));989}990mesh_library = new_mesh_library;991} else {992return;993}994995if (mesh_library.is_valid()) {996mesh_library->connect_changed(callable_mp(this, &GridMapEditor::update_palette));997}998999update_palette();1000// Make sure we select the first tile as default possible.1001if (mesh_library_palette->get_current() == -1 && mesh_library_palette->get_item_count() > 0) {1002mesh_library_palette->set_current(0);1003selected_palette = mesh_library_palette->get_item_metadata(0);1004}1005// Update the cursor and grid in case the library is changed or removed.1006_update_cursor_instance();1007update_grid();1008}10091010void GridMapEditor::edit(GridMap *p_gridmap) {1011if (node) {1012node->disconnect(SNAME("cell_size_changed"), callable_mp(this, &GridMapEditor::_draw_grids));1013node->disconnect(CoreStringName(changed), callable_mp(this, &GridMapEditor::_update_mesh_library));1014if (mesh_library.is_valid()) {1015mesh_library->disconnect_changed(callable_mp(this, &GridMapEditor::update_palette));1016mesh_library = Ref<MeshLibrary>();1017}1018}10191020node = p_gridmap;10211022input_action = INPUT_NONE;1023selection.active = false;1024_update_selection_transform();1025_update_paste_indicator();10261027spatial_editor = Object::cast_to<Node3DEditorPlugin>(EditorNode::get_singleton()->get_editor_main_screen()->get_selected_plugin());10281029if (!node) {1030set_process(false);1031for (int i = 0; i < 3; i++) {1032RenderingServer::get_singleton()->instance_set_visible(grid_instance[i], false);1033}10341035if (cursor_instance.is_valid()) {1036RenderingServer::get_singleton()->instance_set_visible(cursor_instance, false);1037}10381039return;1040}10411042update_palette();1043_update_cursor_instance();10441045set_process(true);10461047_draw_grids(node->get_cell_size());1048update_grid();10491050node->connect(SNAME("cell_size_changed"), callable_mp(this, &GridMapEditor::_draw_grids));1051node->connect(CoreStringName(changed), callable_mp(this, &GridMapEditor::_update_mesh_library));1052_update_mesh_library();1053}10541055void GridMapEditor::update_grid() {1056grid_xform.origin.x -= 1; // Force update in hackish way.10571058grid_ofs[edit_axis] = edit_floor[edit_axis] * node->get_cell_size()[edit_axis];10591060// If there's a valid tile cursor, offset the grid, otherwise move it back to the node.1061edit_grid_xform.origin = cursor_instance.is_valid() ? grid_ofs : Vector3();1062edit_grid_xform.basis = Basis();10631064for (int i = 0; i < 3; i++) {1065RenderingServer::get_singleton()->instance_set_visible(grid_instance[i], i == edit_axis);1066}10671068updating = true;1069floor->set_value(edit_floor[edit_axis]);1070updating = false;1071}10721073void GridMapEditor::_draw_grids(const Vector3 &cell_size) {1074Vector3 edited_floor = node->get_meta("_editor_floor_", Vector3());10751076for (int i = 0; i < 3; i++) {1077RS::get_singleton()->mesh_clear(grid[i]);1078edit_floor[i] = edited_floor[i];1079}10801081Vector<Vector3> grid_points[3];1082Vector<Color> grid_colors[3];10831084for (int i = 0; i < 3; i++) {1085Vector3 axis;1086axis[i] = 1;1087Vector3 axis_n1;1088axis_n1[(i + 1) % 3] = cell_size[(i + 1) % 3];1089Vector3 axis_n2;1090axis_n2[(i + 2) % 3] = cell_size[(i + 2) % 3];10911092for (int j = -GRID_CURSOR_SIZE; j <= GRID_CURSOR_SIZE; j++) {1093for (int k = -GRID_CURSOR_SIZE; k <= GRID_CURSOR_SIZE; k++) {1094Vector3 p = axis_n1 * j + axis_n2 * k;1095float trans = Math::pow(MAX(0, 1.0 - (Vector2(j, k).length() / GRID_CURSOR_SIZE)), 2);10961097Vector3 pj = axis_n1 * (j + 1) + axis_n2 * k;1098float transj = Math::pow(MAX(0, 1.0 - (Vector2(j + 1, k).length() / GRID_CURSOR_SIZE)), 2);10991100Vector3 pk = axis_n1 * j + axis_n2 * (k + 1);1101float transk = Math::pow(MAX(0, 1.0 - (Vector2(j, k + 1).length() / GRID_CURSOR_SIZE)), 2);11021103grid_points[i].push_back(p);1104grid_points[i].push_back(pk);1105grid_colors[i].push_back(Color(1, 1, 1, trans));1106grid_colors[i].push_back(Color(1, 1, 1, transk));11071108grid_points[i].push_back(p);1109grid_points[i].push_back(pj);1110grid_colors[i].push_back(Color(1, 1, 1, trans));1111grid_colors[i].push_back(Color(1, 1, 1, transj));1112}1113}11141115Array d;1116d.resize(RS::ARRAY_MAX);1117d[RS::ARRAY_VERTEX] = grid_points[i];1118d[RS::ARRAY_COLOR] = grid_colors[i];1119RenderingServer::get_singleton()->mesh_add_surface_from_arrays(grid[i], RenderingServer::PRIMITIVE_LINES, d);1120RenderingServer::get_singleton()->mesh_surface_set_material(grid[i], 0, indicator_mat->get_rid());1121}1122}11231124void GridMapEditor::_update_theme() {1125transform_mode_button->set_button_icon(get_theme_icon(SNAME("ToolMove"), EditorStringName(EditorIcons)));1126select_mode_button->set_button_icon(get_theme_icon(SNAME("ToolSelect"), EditorStringName(EditorIcons)));1127erase_mode_button->set_button_icon(get_theme_icon(SNAME("Eraser"), EditorStringName(EditorIcons)));1128paint_mode_button->set_button_icon(get_theme_icon(SNAME("Paint"), EditorStringName(EditorIcons)));1129pick_mode_button->set_button_icon(get_theme_icon(SNAME("ColorPick"), EditorStringName(EditorIcons)));1130fill_action_button->set_button_icon(get_theme_icon(SNAME("Bucket"), EditorStringName(EditorIcons)));1131move_action_button->set_button_icon(get_theme_icon(SNAME("ActionCut"), EditorStringName(EditorIcons)));1132duplicate_action_button->set_button_icon(get_theme_icon(SNAME("ActionCopy"), EditorStringName(EditorIcons)));1133delete_action_button->set_button_icon(get_theme_icon(SNAME("Clear"), EditorStringName(EditorIcons)));1134rotate_x_button->set_button_icon(get_theme_icon(SNAME("RotateLeft"), EditorStringName(EditorIcons)));1135rotate_y_button->set_button_icon(get_theme_icon(SNAME("ToolRotate"), EditorStringName(EditorIcons)));1136rotate_z_button->set_button_icon(get_theme_icon(SNAME("RotateRight"), EditorStringName(EditorIcons)));1137search_box->set_right_icon(get_theme_icon(SNAME("Search"), EditorStringName(EditorIcons)));1138mode_thumbnail->set_button_icon(get_theme_icon(SNAME("FileThumbnail"), EditorStringName(EditorIcons)));1139mode_list->set_button_icon(get_theme_icon(SNAME("FileList"), EditorStringName(EditorIcons)));1140options->set_button_icon(get_theme_icon(SNAME("Tools"), EditorStringName(EditorIcons)));1141}11421143void GridMapEditor::_notification(int p_what) {1144switch (p_what) {1145case NOTIFICATION_ENTER_TREE: {1146mesh_library_palette->connect(SceneStringName(item_selected), callable_mp(this, &GridMapEditor::_item_selected_cbk));11471148const RID scenario = get_tree()->get_root()->get_world_3d()->get_scenario();11491150for (int i = 0; i < 3; i++) {1151grid[i] = RS::get_singleton()->mesh_create();1152grid_instance[i] = RS::get_singleton()->instance_create2(grid[i], scenario);1153RenderingServer::get_singleton()->instance_set_layer_mask(grid_instance[i], 1 << Node3DEditorViewport::MISC_TOOL_LAYER);1154selection_level_instance[i] = RenderingServer::get_singleton()->instance_create2(selection_level_mesh[i], scenario);1155RenderingServer::get_singleton()->instance_set_layer_mask(selection_level_instance[i], 1 << Node3DEditorViewport::MISC_TOOL_LAYER);1156}11571158cursor_instance = RenderingServer::get_singleton()->instance_create2(cursor_mesh, scenario);1159RenderingServer::get_singleton()->instance_set_layer_mask(cursor_instance, 1 << Node3DEditorViewport::MISC_TOOL_LAYER);1160RenderingServer::get_singleton()->instance_set_visible(cursor_instance, false);1161selection_instance = RenderingServer::get_singleton()->instance_create2(selection_mesh, scenario);1162RenderingServer::get_singleton()->instance_set_layer_mask(selection_instance, 1 << Node3DEditorViewport::MISC_TOOL_LAYER);1163paste_instance = RenderingServer::get_singleton()->instance_create2(paste_mesh, scenario);1164RenderingServer::get_singleton()->instance_set_layer_mask(paste_instance, 1 << Node3DEditorViewport::MISC_TOOL_LAYER);11651166_update_selection_transform();1167_update_paste_indicator();1168_update_theme();1169} break;11701171case NOTIFICATION_EXIT_TREE: {1172_clear_clipboard_data();11731174for (int i = 0; i < 3; i++) {1175RS::get_singleton()->free(grid_instance[i]);1176RS::get_singleton()->free(grid[i]);1177grid_instance[i] = RID();1178grid[i] = RID();1179RenderingServer::get_singleton()->free(selection_level_instance[i]);1180}11811182RenderingServer::get_singleton()->free(cursor_instance);1183RenderingServer::get_singleton()->free(selection_instance);1184RenderingServer::get_singleton()->free(paste_instance);1185cursor_instance = RID();1186selection_instance = RID();1187paste_instance = RID();1188} break;11891190case NOTIFICATION_PROCESS: {1191if (!node) {1192return;1193}11941195Transform3D xf = node->get_global_transform();11961197if (xf != grid_xform) {1198for (int i = 0; i < 3; i++) {1199RS::get_singleton()->instance_set_transform(grid_instance[i], xf * edit_grid_xform);1200}1201grid_xform = xf;1202_update_cursor_transform();1203_update_selection_transform();1204}1205} break;12061207case NOTIFICATION_THEME_CHANGED: {1208_update_theme();1209} break;12101211case NOTIFICATION_APPLICATION_FOCUS_OUT: {1212if (input_action == INPUT_PAINT) {1213// Simulate mouse released event to stop drawing when editor focus exists.1214Ref<InputEventMouseButton> release;1215release.instantiate();1216release->set_button_index(MouseButton::LEFT);1217forward_spatial_input_event(nullptr, release);1218}1219} break;12201221case EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED: {1222indicator_mat->set_albedo(EDITOR_GET("editors/3d_gizmos/gizmo_colors/gridmap_grid"));12231224// Take Preview Size changes into account.1225update_palette();1226} break;1227}1228}12291230void GridMapEditor::_update_cursor_instance() {1231if (!node) {1232return;1233}12341235if (cursor_instance.is_valid()) {1236RenderingServer::get_singleton()->free(cursor_instance);1237}1238cursor_instance = RID();12391240const RID scenario = get_tree()->get_root()->get_world_3d()->get_scenario();12411242if (mode_buttons_group->get_pressed_button() == paint_mode_button) {1243if (selected_palette >= 0 && node && node->get_mesh_library().is_valid()) {1244Ref<Mesh> mesh = node->get_mesh_library()->get_item_mesh(selected_palette);1245if (mesh.is_valid() && mesh->get_rid().is_valid()) {1246cursor_instance = RenderingServer::get_singleton()->instance_create2(mesh->get_rid(), scenario);1247RS::ShadowCastingSetting cast_shadows = (RS::ShadowCastingSetting)node->get_mesh_library()->get_item_mesh_cast_shadow(selected_palette);1248RS::get_singleton()->instance_geometry_set_cast_shadows_setting(cursor_instance, cast_shadows);1249}1250}1251} else if (mode_buttons_group->get_pressed_button() == select_mode_button) {1252cursor_inner_mat->set_albedo(Color(default_color, 0.2));1253cursor_outer_mat->set_albedo(Color(default_color, 0.8));1254cursor_instance = RenderingServer::get_singleton()->instance_create2(cursor_mesh, scenario);1255} else if (mode_buttons_group->get_pressed_button() == erase_mode_button) {1256cursor_inner_mat->set_albedo(Color(erase_color, 0.2));1257cursor_outer_mat->set_albedo(Color(erase_color, 0.8));1258cursor_instance = RenderingServer::get_singleton()->instance_create2(cursor_mesh, scenario);1259} else if (mode_buttons_group->get_pressed_button() == pick_mode_button) {1260cursor_inner_mat->set_albedo(Color(pick_color, 0.2));1261cursor_outer_mat->set_albedo(Color(pick_color, 0.8));1262cursor_instance = RenderingServer::get_singleton()->instance_create2(cursor_mesh, scenario);1263}12641265// Make the cursor translucent so that it can be distinguished from already-placed tiles.1266RenderingServer::get_singleton()->instance_geometry_set_transparency(cursor_instance, 0.5);12671268_update_cursor_transform();1269}12701271void GridMapEditor::_on_tool_mode_changed() {1272_show_viewports_transform_gizmo(mode_buttons_group->get_pressed_button() == transform_mode_button);1273_update_cursor_instance();1274}12751276void GridMapEditor::_item_selected_cbk(int idx) {1277selected_palette = mesh_library_palette->get_item_metadata(idx);12781279_update_cursor_instance();1280}12811282void GridMapEditor::_floor_changed(float p_value) {1283if (updating) {1284return;1285}12861287edit_floor[edit_axis] = p_value;1288node->set_meta("_editor_floor_", Vector3(edit_floor[0], edit_floor[1], edit_floor[2]));1289update_grid();1290_update_selection_transform();1291}12921293void GridMapEditor::_floor_mouse_exited() {1294floor->get_line_edit()->release_focus();1295}12961297void GridMapEditor::_bind_methods() {1298ClassDB::bind_method("_configure", &GridMapEditor::_configure);1299ClassDB::bind_method("_set_selection", &GridMapEditor::_set_selection);1300}13011302GridMapEditor::GridMapEditor() {1303ED_SHORTCUT("grid_map/previous_floor", TTRC("Previous Floor"), Key::KEY_1, true);1304ED_SHORTCUT("grid_map/next_floor", TTRC("Next Floor"), Key::KEY_3, true);1305ED_SHORTCUT("grid_map/edit_x_axis", TTRC("Edit X Axis"), KeyModifierMask::SHIFT + Key::Z, true);1306ED_SHORTCUT("grid_map/edit_y_axis", TTRC("Edit Y Axis"), KeyModifierMask::SHIFT + Key::X, true);1307ED_SHORTCUT("grid_map/edit_z_axis", TTRC("Edit Z Axis"), KeyModifierMask::SHIFT + Key::C, true);1308ED_SHORTCUT("grid_map/keep_selected", TTRC("Keep Selection"));1309ED_SHORTCUT("grid_map/clear_rotation", TTRC("Clear Rotation"));13101311options = memnew(MenuButton);1312options->set_theme_type_variation(SceneStringName(FlatButton));1313options->get_popup()->add_separator();1314options->get_popup()->add_radio_check_shortcut(ED_GET_SHORTCUT("grid_map/edit_x_axis"), MENU_OPTION_X_AXIS);1315options->get_popup()->add_radio_check_shortcut(ED_GET_SHORTCUT("grid_map/edit_y_axis"), MENU_OPTION_Y_AXIS);1316options->get_popup()->add_radio_check_shortcut(ED_GET_SHORTCUT("grid_map/edit_z_axis"), MENU_OPTION_Z_AXIS);1317options->get_popup()->set_item_checked(options->get_popup()->get_item_index(MENU_OPTION_Y_AXIS), true);1318options->get_popup()->add_separator();1319// TRANSLATORS: This is a toggle to select after pasting the new content.1320options->get_popup()->add_shortcut(ED_GET_SHORTCUT("grid_map/clear_rotation"), MENU_OPTION_CURSOR_CLEAR_ROTATION);1321options->get_popup()->add_check_shortcut(ED_GET_SHORTCUT("grid_map/keep_selected"), MENU_OPTION_PASTE_SELECTS);1322options->get_popup()->set_item_checked(options->get_popup()->get_item_index(MENU_OPTION_PASTE_SELECTS), true);1323options->get_popup()->add_separator();1324options->get_popup()->add_item(TTR("Settings..."), MENU_OPTION_GRIDMAP_SETTINGS);13251326settings_dialog = memnew(ConfirmationDialog);1327settings_dialog->set_title(TTR("GridMap Settings"));1328add_child(settings_dialog);1329settings_vbc = memnew(VBoxContainer);1330settings_vbc->set_custom_minimum_size(Size2(200, 0) * EDSCALE);1331settings_dialog->add_child(settings_vbc);13321333settings_pick_distance = memnew(SpinBox);1334settings_pick_distance->set_max(10000.0f);1335settings_pick_distance->set_min(500.0f);1336settings_pick_distance->set_step(1.0f);1337settings_pick_distance->set_value(EDITOR_GET("editors/grid_map/pick_distance"));1338settings_pick_distance->set_accessibility_name(TTRC("Pick Distance:"));1339settings_vbc->add_margin_child(TTR("Pick Distance:"), settings_pick_distance);13401341options->get_popup()->connect(SceneStringName(id_pressed), callable_mp(this, &GridMapEditor::_menu_option));13421343toolbar = memnew(HBoxContainer);1344add_child(toolbar);1345toolbar->set_h_size_flags(SIZE_EXPAND_FILL);13461347HBoxContainer *mode_buttons = memnew(HBoxContainer);1348toolbar->add_child(mode_buttons);1349mode_buttons_group.instantiate();13501351viewport_shortcut_buttons.reserve(12);13521353transform_mode_button = memnew(Button);1354transform_mode_button->set_theme_type_variation(SceneStringName(FlatButton));1355transform_mode_button->set_toggle_mode(true);1356transform_mode_button->set_button_group(mode_buttons_group);1357transform_mode_button->set_shortcut(ED_SHORTCUT("grid_map/transform_tool", TTRC("Transform"), Key::T, true));1358transform_mode_button->set_accessibility_name(TTRC("Transform"));1359transform_mode_button->connect(SceneStringName(toggled),1360callable_mp(this, &GridMapEditor::_on_tool_mode_changed).unbind(1));1361mode_buttons->add_child(transform_mode_button);1362viewport_shortcut_buttons.push_back(transform_mode_button);1363VSeparator *vsep = memnew(VSeparator);1364mode_buttons->add_child(vsep);13651366select_mode_button = memnew(Button);1367select_mode_button->set_theme_type_variation(SceneStringName(FlatButton));1368select_mode_button->set_toggle_mode(true);1369select_mode_button->set_button_group(mode_buttons_group);1370select_mode_button->set_shortcut(ED_SHORTCUT("grid_map/selection_tool", TTRC("Selection"), Key::Q, true));1371select_mode_button->set_accessibility_name(TTRC("Selection"));1372select_mode_button->connect(SceneStringName(toggled),1373callable_mp(this, &GridMapEditor::_on_tool_mode_changed).unbind(1));1374mode_buttons->add_child(select_mode_button);1375viewport_shortcut_buttons.push_back(select_mode_button);13761377erase_mode_button = memnew(Button);1378erase_mode_button->set_theme_type_variation(SceneStringName(FlatButton));1379erase_mode_button->set_toggle_mode(true);1380erase_mode_button->set_button_group(mode_buttons_group);1381erase_mode_button->set_shortcut(ED_SHORTCUT("grid_map/erase_tool", TTRC("Erase"), Key::W, true));1382erase_mode_button->set_accessibility_name(TTRC("Erase"));1383mode_buttons->add_child(erase_mode_button);1384erase_mode_button->connect(SceneStringName(toggled),1385callable_mp(this, &GridMapEditor::_on_tool_mode_changed).unbind(1));1386viewport_shortcut_buttons.push_back(erase_mode_button);13871388paint_mode_button = memnew(Button);1389paint_mode_button->set_theme_type_variation(SceneStringName(FlatButton));1390paint_mode_button->set_toggle_mode(true);1391paint_mode_button->set_button_group(mode_buttons_group);1392paint_mode_button->set_shortcut(ED_SHORTCUT("grid_map/paint_tool", TTRC("Paint"), Key::E, true));1393paint_mode_button->set_accessibility_name(TTRC("Paint"));1394paint_mode_button->connect(SceneStringName(toggled),1395callable_mp(this, &GridMapEditor::_on_tool_mode_changed).unbind(1));1396mode_buttons->add_child(paint_mode_button);1397viewport_shortcut_buttons.push_back(paint_mode_button);13981399pick_mode_button = memnew(Button);1400pick_mode_button->set_theme_type_variation(SceneStringName(FlatButton));1401pick_mode_button->set_toggle_mode(true);1402pick_mode_button->set_button_group(mode_buttons_group);1403pick_mode_button->set_shortcut(ED_SHORTCUT("grid_map/pick_tool", TTRC("Pick"), Key::R, true));1404pick_mode_button->set_accessibility_name(TTRC("Pick"));1405pick_mode_button->connect(SceneStringName(toggled),1406callable_mp(this, &GridMapEditor::_on_tool_mode_changed).unbind(1));1407mode_buttons->add_child(pick_mode_button);1408viewport_shortcut_buttons.push_back(pick_mode_button);14091410vsep = memnew(VSeparator);1411toolbar->add_child(vsep);14121413HBoxContainer *action_buttons = memnew(HBoxContainer);1414toolbar->add_child(action_buttons);14151416fill_action_button = memnew(Button);1417fill_action_button->set_theme_type_variation(SceneStringName(FlatButton));1418fill_action_button->set_shortcut(ED_SHORTCUT("grid_map/fill_tool", TTRC("Fill"), Key::Z, true));1419fill_action_button->set_accessibility_name(TTRC("Fill"));1420fill_action_button->connect(SceneStringName(pressed),1421callable_mp(this, &GridMapEditor::_menu_option).bind(MENU_OPTION_SELECTION_FILL));1422action_buttons->add_child(fill_action_button);1423viewport_shortcut_buttons.push_back(fill_action_button);14241425move_action_button = memnew(Button);1426move_action_button->set_theme_type_variation(SceneStringName(FlatButton));1427move_action_button->set_shortcut(ED_SHORTCUT("grid_map/move_tool", TTRC("Move"), Key::X, true));1428fill_action_button->set_accessibility_name(TTRC("Move"));1429move_action_button->connect(SceneStringName(pressed),1430callable_mp(this, &GridMapEditor::_menu_option).bind(MENU_OPTION_SELECTION_CUT));1431action_buttons->add_child(move_action_button);1432viewport_shortcut_buttons.push_back(move_action_button);14331434duplicate_action_button = memnew(Button);1435duplicate_action_button->set_theme_type_variation(SceneStringName(FlatButton));1436duplicate_action_button->set_shortcut(ED_SHORTCUT("grid_map/duplicate_tool", TTRC("Duplicate"), Key::C, true));1437duplicate_action_button->set_accessibility_name(TTRC("Duplicate"));1438duplicate_action_button->connect(SceneStringName(pressed),1439callable_mp(this, &GridMapEditor::_menu_option).bind(MENU_OPTION_SELECTION_DUPLICATE));1440action_buttons->add_child(duplicate_action_button);1441viewport_shortcut_buttons.push_back(duplicate_action_button);14421443delete_action_button = memnew(Button);1444delete_action_button->set_theme_type_variation(SceneStringName(FlatButton));1445delete_action_button->set_shortcut(ED_SHORTCUT("grid_map/delete_tool", TTRC("Delete"), Key::V, true));1446delete_action_button->set_accessibility_name(TTRC("Delete"));1447delete_action_button->connect(SceneStringName(pressed),1448callable_mp(this, &GridMapEditor::_menu_option).bind(MENU_OPTION_SELECTION_CLEAR));1449action_buttons->add_child(delete_action_button);1450viewport_shortcut_buttons.push_back(delete_action_button);14511452vsep = memnew(VSeparator);1453toolbar->add_child(vsep);14541455HBoxContainer *rotation_buttons = memnew(HBoxContainer);1456toolbar->add_child(rotation_buttons);14571458rotate_x_button = memnew(Button);1459rotate_x_button->set_theme_type_variation(SceneStringName(FlatButton));1460rotate_x_button->set_shortcut(ED_SHORTCUT("grid_map/cursor_rotate_x", TTRC("Cursor Rotate X"), Key::A, true));1461rotate_x_button->set_accessibility_name(TTRC("Cursor Rotate X"));1462rotate_x_button->connect(SceneStringName(pressed),1463callable_mp(this, &GridMapEditor::_menu_option).bind(MENU_OPTION_CURSOR_ROTATE_X));1464rotation_buttons->add_child(rotate_x_button);1465viewport_shortcut_buttons.push_back(rotate_x_button);14661467rotate_y_button = memnew(Button);1468rotate_y_button->set_theme_type_variation(SceneStringName(FlatButton));1469rotate_y_button->set_shortcut(ED_SHORTCUT("grid_map/cursor_rotate_y", TTRC("Cursor Rotate Y"), Key::S, true));1470rotate_y_button->set_accessibility_name(TTRC("Cursor Rotate Y"));1471rotate_y_button->connect(SceneStringName(pressed),1472callable_mp(this, &GridMapEditor::_menu_option).bind(MENU_OPTION_CURSOR_ROTATE_Y));1473rotation_buttons->add_child(rotate_y_button);1474viewport_shortcut_buttons.push_back(rotate_y_button);14751476rotate_z_button = memnew(Button);1477rotate_z_button->set_theme_type_variation(SceneStringName(FlatButton));1478rotate_z_button->set_shortcut(ED_SHORTCUT("grid_map/cursor_rotate_z", TTRC("Cursor Rotate Z"), Key::D, true));1479rotate_z_button->set_accessibility_name(TTRC("Cursor Rotate Z"));1480rotate_z_button->connect(SceneStringName(pressed),1481callable_mp(this, &GridMapEditor::_menu_option).bind(MENU_OPTION_CURSOR_ROTATE_Z));1482rotation_buttons->add_child(rotate_z_button);1483viewport_shortcut_buttons.push_back(rotate_z_button);14841485// Wide empty separation control. (like BoxContainer::add_spacer())1486Control *c = memnew(Control);1487c->set_mouse_filter(MOUSE_FILTER_PASS);1488c->set_h_size_flags(SIZE_EXPAND_FILL);1489toolbar->add_child(c);14901491floor = memnew(SpinBox);1492floor->set_min(-32767);1493floor->set_max(32767);1494floor->set_step(1);1495floor->set_accessibility_name(TTRC("Change Grid Floor:"));1496floor->set_tooltip_text(1497vformat(TTR("Change Grid Floor:\nPrevious Plane (%s)\nNext Plane (%s)"),1498ED_GET_SHORTCUT("grid_map/previous_floor")->get_as_text(),1499ED_GET_SHORTCUT("grid_map/next_floor")->get_as_text()));1500toolbar->add_child(floor);1501floor->get_line_edit()->add_theme_constant_override("minimum_character_width", 2);1502floor->get_line_edit()->set_context_menu_enabled(false);1503floor->connect(SceneStringName(value_changed), callable_mp(this, &GridMapEditor::_floor_changed));1504floor->connect(SceneStringName(mouse_exited), callable_mp(this, &GridMapEditor::_floor_mouse_exited));1505floor->get_line_edit()->connect(SceneStringName(mouse_exited), callable_mp(this, &GridMapEditor::_floor_mouse_exited));15061507search_box = memnew(LineEdit);1508search_box->add_theme_constant_override("minimum_character_width", 10);1509search_box->set_placeholder(TTR("Filter Meshes"));1510search_box->set_accessibility_name(TTRC("Filter Meshes"));1511search_box->set_clear_button_enabled(true);1512toolbar->add_child(search_box);1513search_box->connect(SceneStringName(text_changed), callable_mp(this, &GridMapEditor::_text_changed));1514search_box->connect(SceneStringName(gui_input), callable_mp(this, &GridMapEditor::_sbox_input));15151516zoom_widget = memnew(EditorZoomWidget);1517toolbar->add_child(zoom_widget);1518zoom_widget->setup_zoom_limits(0.2, 4);1519zoom_widget->set_zoom(1.0);1520zoom_widget->set_anchors_and_offsets_preset(Control::PRESET_TOP_LEFT, Control::PRESET_MODE_MINSIZE, 2 * EDSCALE);1521zoom_widget->connect("zoom_changed", callable_mp(this, &GridMapEditor::_icon_size_changed));1522zoom_widget->set_shortcut_context(this);15231524mode_thumbnail = memnew(Button);1525mode_thumbnail->set_theme_type_variation(SceneStringName(FlatButton));1526mode_thumbnail->set_toggle_mode(true);1527mode_thumbnail->set_accessibility_name(TTRC("View as Thumbnails"));1528mode_thumbnail->set_pressed(true);1529toolbar->add_child(mode_thumbnail);1530mode_thumbnail->connect(SceneStringName(pressed), callable_mp(this, &GridMapEditor::_set_display_mode).bind(DISPLAY_THUMBNAIL));15311532mode_list = memnew(Button);1533mode_list->set_theme_type_variation(SceneStringName(FlatButton));1534mode_list->set_toggle_mode(true);1535mode_list->set_accessibility_name(TTRC("View as List"));1536mode_list->set_pressed(false);1537toolbar->add_child(mode_list);1538mode_list->connect(SceneStringName(pressed), callable_mp(this, &GridMapEditor::_set_display_mode).bind(DISPLAY_LIST));15391540toolbar->add_child(options);15411542mesh_library_palette = memnew(ItemList);1543mesh_library_palette->set_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED);1544add_child(mesh_library_palette);1545mesh_library_palette->set_v_size_flags(SIZE_EXPAND_FILL);1546mesh_library_palette->connect(SceneStringName(gui_input), callable_mp(this, &GridMapEditor::_mesh_library_palette_input));15471548info_message = memnew(Label);1549info_message->set_focus_mode(FOCUS_ACCESSIBILITY);1550info_message->set_text(TTR("Give a MeshLibrary resource to this GridMap to use its meshes."));1551info_message->set_vertical_alignment(VERTICAL_ALIGNMENT_CENTER);1552info_message->set_horizontal_alignment(HORIZONTAL_ALIGNMENT_CENTER);1553info_message->set_autowrap_mode(TextServer::AUTOWRAP_WORD_SMART);1554info_message->set_custom_minimum_size(Size2(100 * EDSCALE, 0));1555info_message->set_anchors_and_offsets_preset(PRESET_FULL_RECT, PRESET_MODE_KEEP_SIZE, 8 * EDSCALE);1556mesh_library_palette->add_child(info_message);15571558edit_axis = Vector3::AXIS_Y;1559edit_floor[0] = -1;1560edit_floor[1] = -1;1561edit_floor[2] = -1;15621563cursor_mesh = RenderingServer::get_singleton()->mesh_create();1564selection_mesh = RenderingServer::get_singleton()->mesh_create();1565paste_mesh = RenderingServer::get_singleton()->mesh_create();15661567{1568// Selection mesh create.15691570Vector<Vector3> lines;1571Vector<Vector3> triangles;1572Vector<Vector3> square[3];15731574for (int i = 0; i < 6; i++) {1575Vector3 face_points[4];15761577for (int j = 0; j < 4; j++) {1578float v[3];1579v[0] = 1.0;1580v[1] = 1 - 2 * ((j >> 1) & 1);1581v[2] = v[1] * (1 - 2 * (j & 1));15821583for (int k = 0; k < 3; k++) {1584if (i < 3) {1585face_points[j][(i + k) % 3] = v[k];1586} else {1587face_points[3 - j][(i + k) % 3] = -v[k];1588}1589}1590}15911592triangles.push_back(face_points[0] * 0.5 + Vector3(0.5, 0.5, 0.5));1593triangles.push_back(face_points[1] * 0.5 + Vector3(0.5, 0.5, 0.5));1594triangles.push_back(face_points[2] * 0.5 + Vector3(0.5, 0.5, 0.5));15951596triangles.push_back(face_points[2] * 0.5 + Vector3(0.5, 0.5, 0.5));1597triangles.push_back(face_points[3] * 0.5 + Vector3(0.5, 0.5, 0.5));1598triangles.push_back(face_points[0] * 0.5 + Vector3(0.5, 0.5, 0.5));1599}16001601for (int i = 0; i < 12; i++) {1602AABB base(Vector3(0, 0, 0), Vector3(1, 1, 1));1603Vector3 a, b;1604base.get_edge(i, a, b);1605lines.push_back(a);1606lines.push_back(b);1607}16081609for (int i = 0; i < 3; i++) {1610Vector3 points[4];1611for (int j = 0; j < 4; j++) {1612static const bool orderx[4] = { false, true, true, false };1613static const bool ordery[4] = { false, false, true, true };16141615Vector3 sp;1616if (orderx[j]) {1617sp[(i + 1) % 3] = 1.0;1618}1619if (ordery[j]) {1620sp[(i + 2) % 3] = 1.0;1621}16221623points[j] = sp;1624}16251626for (int j = 0; j < 4; j++) {1627Vector3 ofs;1628ofs[i] += 0.01;1629square[i].push_back(points[j] - ofs);1630square[i].push_back(points[(j + 1) % 4] - ofs);1631square[i].push_back(points[j] + ofs);1632square[i].push_back(points[(j + 1) % 4] + ofs);1633}1634}16351636Array d;1637d.resize(RS::ARRAY_MAX);16381639default_color = Color(0.0, 0.565, 1.0); // blue 0.7, 0.7, 1.01640erase_color = Color(1.0, 0.2, 0.2); // red1641pick_color = Color(1, 0.7, 0); // orange/yellow16421643cursor_inner_mat.instantiate();1644cursor_inner_mat->set_albedo(Color(default_color, 0.2));1645cursor_inner_mat->set_shading_mode(StandardMaterial3D::SHADING_MODE_UNSHADED);1646cursor_inner_mat->set_flag(StandardMaterial3D::FLAG_DISABLE_FOG, true);1647cursor_inner_mat->set_transparency(StandardMaterial3D::TRANSPARENCY_ALPHA);16481649cursor_outer_mat.instantiate();1650cursor_outer_mat->set_albedo(Color(default_color, 0.8));1651cursor_outer_mat->set_on_top_of_alpha();1652cursor_outer_mat->set_shading_mode(StandardMaterial3D::SHADING_MODE_UNSHADED);1653cursor_outer_mat->set_transparency(StandardMaterial3D::TRANSPARENCY_ALPHA);1654cursor_outer_mat->set_flag(StandardMaterial3D::FLAG_DISABLE_FOG, true);16551656inner_mat.instantiate();1657inner_mat->set_albedo(Color(default_color, 0.2));1658inner_mat->set_shading_mode(StandardMaterial3D::SHADING_MODE_UNSHADED);1659inner_mat->set_flag(StandardMaterial3D::FLAG_DISABLE_FOG, true);1660inner_mat->set_transparency(StandardMaterial3D::TRANSPARENCY_ALPHA);16611662outer_mat.instantiate();1663outer_mat->set_albedo(Color(default_color, 0.8));1664outer_mat->set_on_top_of_alpha();1665outer_mat->set_shading_mode(StandardMaterial3D::SHADING_MODE_UNSHADED);1666outer_mat->set_transparency(StandardMaterial3D::TRANSPARENCY_ALPHA);1667outer_mat->set_flag(StandardMaterial3D::FLAG_DISABLE_FOG, true);16681669selection_floor_mat.instantiate();1670selection_floor_mat->set_albedo(Color(0.80, 0.80, 1.0, 1));1671selection_floor_mat->set_on_top_of_alpha();1672selection_floor_mat->set_shading_mode(StandardMaterial3D::SHADING_MODE_UNSHADED);1673selection_floor_mat->set_flag(StandardMaterial3D::FLAG_DISABLE_FOG, true);16741675d[RS::ARRAY_VERTEX] = triangles;1676RenderingServer::get_singleton()->mesh_add_surface_from_arrays(cursor_mesh, RS::PRIMITIVE_TRIANGLES, d);1677RenderingServer::get_singleton()->mesh_surface_set_material(cursor_mesh, 0, cursor_inner_mat->get_rid());16781679d[RS::ARRAY_VERTEX] = lines;1680RenderingServer::get_singleton()->mesh_add_surface_from_arrays(cursor_mesh, RS::PRIMITIVE_LINES, d);1681RenderingServer::get_singleton()->mesh_surface_set_material(cursor_mesh, 1, cursor_outer_mat->get_rid());16821683d[RS::ARRAY_VERTEX] = triangles;1684RenderingServer::get_singleton()->mesh_add_surface_from_arrays(selection_mesh, RS::PRIMITIVE_TRIANGLES, d);1685RenderingServer::get_singleton()->mesh_surface_set_material(selection_mesh, 0, inner_mat->get_rid());16861687d[RS::ARRAY_VERTEX] = lines;1688RenderingServer::get_singleton()->mesh_add_surface_from_arrays(selection_mesh, RS::PRIMITIVE_LINES, d);1689RenderingServer::get_singleton()->mesh_surface_set_material(selection_mesh, 1, outer_mat->get_rid());16901691d[RS::ARRAY_VERTEX] = triangles;1692RenderingServer::get_singleton()->mesh_add_surface_from_arrays(paste_mesh, RS::PRIMITIVE_TRIANGLES, d);1693RenderingServer::get_singleton()->mesh_surface_set_material(paste_mesh, 0, inner_mat->get_rid());16941695d[RS::ARRAY_VERTEX] = lines;1696RenderingServer::get_singleton()->mesh_add_surface_from_arrays(paste_mesh, RS::PRIMITIVE_LINES, d);1697RenderingServer::get_singleton()->mesh_surface_set_material(paste_mesh, 1, outer_mat->get_rid());16981699for (int i = 0; i < 3; i++) {1700d[RS::ARRAY_VERTEX] = square[i];1701selection_level_mesh[i] = RS::get_singleton()->mesh_create();1702RenderingServer::get_singleton()->mesh_add_surface_from_arrays(selection_level_mesh[i], RS::PRIMITIVE_LINES, d);1703RenderingServer::get_singleton()->mesh_surface_set_material(selection_level_mesh[i], 0, selection_floor_mat->get_rid());1704}1705}17061707_set_selection(false);17081709indicator_mat.instantiate();1710indicator_mat->set_shading_mode(StandardMaterial3D::SHADING_MODE_UNSHADED);1711indicator_mat->set_transparency(StandardMaterial3D::TRANSPARENCY_ALPHA);1712indicator_mat->set_flag(StandardMaterial3D::FLAG_SRGB_VERTEX_COLOR, true);1713indicator_mat->set_flag(StandardMaterial3D::FLAG_ALBEDO_FROM_VERTEX_COLOR, true);1714indicator_mat->set_flag(StandardMaterial3D::FLAG_DISABLE_FOG, true);1715indicator_mat->set_albedo(EDITOR_GET("editors/3d_gizmos/gizmo_colors/gridmap_grid"));1716}17171718GridMapEditor::~GridMapEditor() {1719ERR_FAIL_NULL(RenderingServer::get_singleton());1720_clear_clipboard_data();17211722for (int i = 0; i < 3; i++) {1723if (grid[i].is_valid()) {1724RenderingServer::get_singleton()->free(grid[i]);1725}1726if (grid_instance[i].is_valid()) {1727RenderingServer::get_singleton()->free(grid_instance[i]);1728}1729if (selection_level_instance[i].is_valid()) {1730RenderingServer::get_singleton()->free(selection_level_instance[i]);1731}1732if (selection_level_mesh[i].is_valid()) {1733RenderingServer::get_singleton()->free(selection_level_mesh[i]);1734}1735}17361737RenderingServer::get_singleton()->free(cursor_mesh);1738if (cursor_instance.is_valid()) {1739RenderingServer::get_singleton()->free(cursor_instance);1740}17411742RenderingServer::get_singleton()->free(selection_mesh);1743if (selection_instance.is_valid()) {1744RenderingServer::get_singleton()->free(selection_instance);1745}17461747RenderingServer::get_singleton()->free(paste_mesh);1748if (paste_instance.is_valid()) {1749RenderingServer::get_singleton()->free(paste_instance);1750}1751}17521753void GridMapEditorPlugin::_notification(int p_what) {1754switch (p_what) {1755case NOTIFICATION_ENTER_TREE: {1756grid_map_editor = memnew(GridMapEditor);1757grid_map_editor->set_h_size_flags(Control::SIZE_EXPAND_FILL);1758grid_map_editor->set_v_size_flags(Control::SIZE_EXPAND_FILL);1759grid_map_editor->set_custom_minimum_size(Size2(0, 200) * EDSCALE);1760grid_map_editor->hide();17611762panel_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")));1763panel_button->hide();1764} break;1765case NOTIFICATION_EXIT_TREE: {1766EditorNode::get_bottom_panel()->remove_item(grid_map_editor);1767memdelete_notnull(grid_map_editor);1768grid_map_editor = nullptr;1769panel_button = nullptr;1770} break;1771}1772}17731774void GridMapEditorPlugin::_bind_methods() {1775ClassDB::bind_method(D_METHOD("get_current_grid_map"), &GridMapEditorPlugin::get_current_grid_map);1776ClassDB::bind_method(D_METHOD("set_selection", "begin", "end"), &GridMapEditorPlugin::set_selection);1777ClassDB::bind_method(D_METHOD("clear_selection"), &GridMapEditorPlugin::clear_selection);1778ClassDB::bind_method(D_METHOD("get_selection"), &GridMapEditorPlugin::get_selection);1779ClassDB::bind_method(D_METHOD("has_selection"), &GridMapEditorPlugin::has_selection);1780ClassDB::bind_method(D_METHOD("get_selected_cells"), &GridMapEditorPlugin::get_selected_cells);1781ClassDB::bind_method(D_METHOD("set_selected_palette_item", "item"), &GridMapEditorPlugin::set_selected_palette_item);1782ClassDB::bind_method(D_METHOD("get_selected_palette_item"), &GridMapEditorPlugin::get_selected_palette_item);1783}17841785void GridMapEditorPlugin::edit(Object *p_object) {1786ERR_FAIL_NULL(grid_map_editor);1787grid_map_editor->edit(Object::cast_to<GridMap>(p_object));1788}17891790bool GridMapEditorPlugin::handles(Object *p_object) const {1791return p_object->is_class("GridMap");1792}17931794void GridMapEditorPlugin::make_visible(bool p_visible) {1795ERR_FAIL_NULL(grid_map_editor);1796if (p_visible) {1797BaseButton *button = grid_map_editor->mode_buttons_group->get_pressed_button();1798if (button == nullptr) {1799grid_map_editor->select_mode_button->set_pressed(true);1800}1801grid_map_editor->_on_tool_mode_changed();1802panel_button->show();1803EditorNode::get_bottom_panel()->make_item_visible(grid_map_editor);1804grid_map_editor->set_process(true);1805} else {1806grid_map_editor->_show_viewports_transform_gizmo(true);1807panel_button->hide();1808if (grid_map_editor->is_visible_in_tree()) {1809EditorNode::get_bottom_panel()->hide_bottom_panel();1810}1811grid_map_editor->set_process(false);1812}1813}18141815GridMap *GridMapEditorPlugin::get_current_grid_map() const {1816ERR_FAIL_NULL_V(grid_map_editor, nullptr);1817return grid_map_editor->node;1818}18191820void GridMapEditorPlugin::set_selection(const Vector3i &p_begin, const Vector3i &p_end) {1821ERR_FAIL_NULL(grid_map_editor);1822grid_map_editor->_set_selection(true, p_begin, p_end);1823}18241825void GridMapEditorPlugin::clear_selection() {1826ERR_FAIL_NULL(grid_map_editor);1827grid_map_editor->_set_selection(false);1828}18291830AABB GridMapEditorPlugin::get_selection() const {1831ERR_FAIL_NULL_V(grid_map_editor, AABB());1832return grid_map_editor->_get_selection();1833}18341835bool GridMapEditorPlugin::has_selection() const {1836ERR_FAIL_NULL_V(grid_map_editor, false);1837return grid_map_editor->_has_selection();1838}18391840Array GridMapEditorPlugin::get_selected_cells() const {1841ERR_FAIL_NULL_V(grid_map_editor, Array());1842return grid_map_editor->_get_selected_cells();1843}18441845void GridMapEditorPlugin::set_selected_palette_item(int p_item) const {1846ERR_FAIL_NULL(grid_map_editor);1847if (grid_map_editor->node && grid_map_editor->node->get_mesh_library().is_valid()) {1848if (p_item < -1) {1849p_item = -1;1850} else if (p_item >= grid_map_editor->node->get_mesh_library()->get_item_list().size()) {1851p_item = grid_map_editor->node->get_mesh_library()->get_item_list().size() - 1;1852}1853if (p_item != grid_map_editor->selected_palette) {1854grid_map_editor->selected_palette = p_item;1855grid_map_editor->_update_cursor_instance();1856grid_map_editor->update_palette();1857}1858}1859}18601861int GridMapEditorPlugin::get_selected_palette_item() const {1862ERR_FAIL_NULL_V(grid_map_editor, 0);1863if (grid_map_editor->selected_palette >= 0 && grid_map_editor->node && grid_map_editor->node->get_mesh_library().is_valid()) {1864return grid_map_editor->selected_palette;1865} else {1866return -1;1867}1868}186918701871