scene_import_settings.cpp 66 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926
  1. /**************************************************************************/
  2. /* scene_import_settings.cpp */
  3. /**************************************************************************/
  4. /* This file is part of: */
  5. /* GODOT ENGINE */
  6. /* https://godotengine.org */
  7. /**************************************************************************/
  8. /* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
  9. /* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
  10. /* */
  11. /* Permission is hereby granted, free of charge, to any person obtaining */
  12. /* a copy of this software and associated documentation files (the */
  13. /* "Software"), to deal in the Software without restriction, including */
  14. /* without limitation the rights to use, copy, modify, merge, publish, */
  15. /* distribute, sublicense, and/or sell copies of the Software, and to */
  16. /* permit persons to whom the Software is furnished to do so, subject to */
  17. /* the following conditions: */
  18. /* */
  19. /* The above copyright notice and this permission notice shall be */
  20. /* included in all copies or substantial portions of the Software. */
  21. /* */
  22. /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
  23. /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
  24. /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
  25. /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
  26. /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
  27. /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
  28. /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
  29. /**************************************************************************/
  30. #include "scene_import_settings.h"
  31. #include "core/config/project_settings.h"
  32. #include "editor/editor_file_system.h"
  33. #include "editor/editor_inspector.h"
  34. #include "editor/editor_node.h"
  35. #include "editor/editor_settings.h"
  36. #include "editor/editor_string_names.h"
  37. #include "editor/gui/editor_file_dialog.h"
  38. #include "editor/plugins/skeleton_3d_editor_plugin.h"
  39. #include "editor/themes/editor_scale.h"
  40. #include "scene/3d/importer_mesh_instance_3d.h"
  41. #include "scene/animation/animation_player.h"
  42. #include "scene/resources/3d/importer_mesh.h"
  43. #include "scene/resources/surface_tool.h"
  44. class SceneImportSettingsData : public Object {
  45. GDCLASS(SceneImportSettingsData, Object)
  46. friend class SceneImportSettingsDialog;
  47. HashMap<StringName, Variant> *settings = nullptr;
  48. HashMap<StringName, Variant> current;
  49. HashMap<StringName, Variant> defaults;
  50. List<ResourceImporter::ImportOption> options;
  51. Vector<String> animation_list;
  52. bool hide_options = false;
  53. String path;
  54. ResourceImporterScene::InternalImportCategory category = ResourceImporterScene::INTERNAL_IMPORT_CATEGORY_MAX;
  55. bool _set(const StringName &p_name, const Variant &p_value) {
  56. if (settings) {
  57. if (defaults.has(p_name) && defaults[p_name] == p_value) {
  58. settings->erase(p_name);
  59. } else {
  60. (*settings)[p_name] = p_value;
  61. }
  62. current[p_name] = p_value;
  63. // SceneImportSettings must decide if a new collider should be generated or not.
  64. if (category == ResourceImporterScene::INTERNAL_IMPORT_CATEGORY_MESH_3D_NODE) {
  65. SceneImportSettingsDialog::get_singleton()->request_generate_collider();
  66. }
  67. if (SceneImportSettingsDialog::get_singleton()->is_editing_animation()) {
  68. if (category == ResourceImporterScene::INTERNAL_IMPORT_CATEGORY_MAX) {
  69. if (ResourceImporterScene::get_animation_singleton()->get_option_visibility(path, p_name, current)) {
  70. SceneImportSettingsDialog::get_singleton()->update_view();
  71. }
  72. } else {
  73. if (ResourceImporterScene::get_animation_singleton()->get_internal_option_update_view_required(category, p_name, current)) {
  74. SceneImportSettingsDialog::get_singleton()->update_view();
  75. }
  76. }
  77. } else {
  78. if (category == ResourceImporterScene::INTERNAL_IMPORT_CATEGORY_MAX) {
  79. if (ResourceImporterScene::get_scene_singleton()->get_option_visibility(path, p_name, current)) {
  80. SceneImportSettingsDialog::get_singleton()->update_view();
  81. }
  82. } else {
  83. if (ResourceImporterScene::get_scene_singleton()->get_internal_option_update_view_required(category, p_name, current)) {
  84. SceneImportSettingsDialog::get_singleton()->update_view();
  85. }
  86. }
  87. }
  88. return true;
  89. }
  90. return false;
  91. }
  92. bool _get(const StringName &p_name, Variant &r_ret) const {
  93. if (settings) {
  94. if (settings->has(p_name)) {
  95. r_ret = (*settings)[p_name];
  96. return true;
  97. }
  98. }
  99. if (defaults.has(p_name)) {
  100. r_ret = defaults[p_name];
  101. return true;
  102. }
  103. return false;
  104. }
  105. void handle_special_properties(PropertyInfo &r_option) const {
  106. ERR_FAIL_NULL(settings);
  107. if (r_option.name == "rest_pose/load_pose") {
  108. if (!settings->has("rest_pose/load_pose") || int((*settings)["rest_pose/load_pose"]) != 2) {
  109. if (settings->has("rest_pose/external_animation_library")) {
  110. (*settings)["rest_pose/external_animation_library"] = Variant();
  111. }
  112. }
  113. }
  114. if (r_option.name == "rest_pose/selected_animation") {
  115. if (!settings->has("rest_pose/load_pose")) {
  116. return;
  117. }
  118. String hint_string;
  119. switch (int((*settings)["rest_pose/load_pose"])) {
  120. case 1: {
  121. hint_string = String(",").join(animation_list);
  122. if (animation_list.size() == 1) {
  123. (*settings)["rest_pose/selected_animation"] = animation_list[0];
  124. }
  125. } break;
  126. case 2: {
  127. Object *res = nullptr;
  128. if (settings->has("rest_pose/external_animation_library")) {
  129. res = (*settings)["rest_pose/external_animation_library"];
  130. }
  131. Ref<Animation> anim(res);
  132. Ref<AnimationLibrary> library(res);
  133. if (anim.is_valid()) {
  134. hint_string = anim->get_name();
  135. }
  136. if (library.is_valid()) {
  137. List<StringName> anim_names;
  138. library->get_animation_list(&anim_names);
  139. if (anim_names.size() == 1) {
  140. (*settings)["rest_pose/selected_animation"] = String(anim_names.front()->get());
  141. }
  142. for (StringName anim_name : anim_names) {
  143. hint_string += "," + anim_name; // Include preceding, as a catch-all.
  144. }
  145. }
  146. } break;
  147. default:
  148. break;
  149. }
  150. r_option.hint = PROPERTY_HINT_ENUM;
  151. r_option.hint_string = hint_string;
  152. }
  153. }
  154. void _get_property_list(List<PropertyInfo> *r_list) const {
  155. if (hide_options) {
  156. return;
  157. }
  158. for (const ResourceImporter::ImportOption &E : options) {
  159. PropertyInfo option = E.option;
  160. if (SceneImportSettingsDialog::get_singleton()->is_editing_animation()) {
  161. if (category == ResourceImporterScene::INTERNAL_IMPORT_CATEGORY_MAX) {
  162. if (ResourceImporterScene::get_animation_singleton()->get_option_visibility(path, E.option.name, current)) {
  163. handle_special_properties(option);
  164. r_list->push_back(option);
  165. }
  166. } else {
  167. if (ResourceImporterScene::get_animation_singleton()->get_internal_option_visibility(category, E.option.name, current)) {
  168. handle_special_properties(option);
  169. r_list->push_back(option);
  170. }
  171. }
  172. } else {
  173. if (category == ResourceImporterScene::INTERNAL_IMPORT_CATEGORY_MAX) {
  174. if (ResourceImporterScene::get_scene_singleton()->get_option_visibility(path, E.option.name, current)) {
  175. handle_special_properties(option);
  176. r_list->push_back(option);
  177. }
  178. } else {
  179. if (ResourceImporterScene::get_scene_singleton()->get_internal_option_visibility(category, E.option.name, current)) {
  180. handle_special_properties(option);
  181. r_list->push_back(option);
  182. }
  183. }
  184. }
  185. }
  186. }
  187. };
  188. void SceneImportSettingsDialog::_fill_material(Tree *p_tree, const Ref<Material> &p_material, TreeItem *p_parent) {
  189. String import_id;
  190. bool has_import_id = false;
  191. if (p_material->has_meta("import_id")) {
  192. import_id = p_material->get_meta("import_id");
  193. has_import_id = true;
  194. } else if (!p_material->get_name().is_empty()) {
  195. import_id = p_material->get_name();
  196. has_import_id = true;
  197. } else if (unnamed_material_name_map.has(p_material)) {
  198. import_id = unnamed_material_name_map[p_material];
  199. } else {
  200. import_id = "@MATERIAL:" + itos(material_map.size());
  201. unnamed_material_name_map[p_material] = import_id;
  202. }
  203. bool created = false;
  204. if (!material_map.has(import_id)) {
  205. MaterialData md;
  206. created = true;
  207. md.has_import_id = has_import_id;
  208. md.material = p_material;
  209. _load_default_subresource_settings(md.settings, "materials", import_id, ResourceImporterScene::INTERNAL_IMPORT_CATEGORY_MATERIAL);
  210. material_map[import_id] = md;
  211. }
  212. MaterialData &material_data = material_map[import_id];
  213. ERR_FAIL_COND(p_material != material_data.material);
  214. Ref<Texture2D> icon = get_editor_theme_icon(SNAME("StandardMaterial3D"));
  215. TreeItem *item = p_tree->create_item(p_parent);
  216. if (p_material->get_name().is_empty()) {
  217. item->set_text(0, TTR("<Unnamed Material>"));
  218. } else {
  219. item->set_text(0, p_material->get_name());
  220. }
  221. item->set_icon(0, icon);
  222. item->set_meta("type", "Material");
  223. item->set_meta("import_id", import_id);
  224. item->set_tooltip_text(0, vformat(TTR("Import ID: %s"), import_id));
  225. item->set_selectable(0, true);
  226. if (p_tree == scene_tree) {
  227. material_data.scene_node = item;
  228. } else if (p_tree == mesh_tree) {
  229. material_data.mesh_node = item;
  230. } else {
  231. material_data.material_node = item;
  232. }
  233. if (created) {
  234. _fill_material(material_tree, p_material, material_tree->get_root());
  235. }
  236. }
  237. void SceneImportSettingsDialog::_fill_mesh(Tree *p_tree, const Ref<Mesh> &p_mesh, TreeItem *p_parent) {
  238. String import_id;
  239. bool has_import_id = false;
  240. if (p_mesh->has_meta("import_id")) {
  241. import_id = p_mesh->get_meta("import_id");
  242. has_import_id = true;
  243. } else if (!p_mesh->get_name().is_empty()) {
  244. import_id = p_mesh->get_name();
  245. has_import_id = true;
  246. } else {
  247. import_id = "@MESH:" + itos(mesh_set.size());
  248. }
  249. if (!mesh_map.has(import_id)) {
  250. MeshData md;
  251. md.has_import_id = has_import_id;
  252. md.mesh = p_mesh;
  253. _load_default_subresource_settings(md.settings, "meshes", import_id, ResourceImporterScene::INTERNAL_IMPORT_CATEGORY_MESH);
  254. mesh_map[import_id] = md;
  255. }
  256. MeshData &mesh_data = mesh_map[import_id];
  257. Ref<Texture2D> icon = get_editor_theme_icon(SNAME("MeshItem"));
  258. TreeItem *item = p_tree->create_item(p_parent);
  259. item->set_text(0, p_mesh->get_name());
  260. item->set_icon(0, icon);
  261. bool created = false;
  262. if (!mesh_set.has(p_mesh)) {
  263. mesh_set.insert(p_mesh);
  264. created = true;
  265. }
  266. item->set_meta("type", "Mesh");
  267. item->set_meta("import_id", import_id);
  268. item->set_tooltip_text(0, vformat(TTR("Import ID: %s"), import_id));
  269. item->set_selectable(0, true);
  270. if (p_tree == scene_tree) {
  271. mesh_data.scene_node = item;
  272. } else {
  273. mesh_data.mesh_node = item;
  274. }
  275. item->set_collapsed(true);
  276. for (int i = 0; i < p_mesh->get_surface_count(); i++) {
  277. Ref<Material> mat = p_mesh->surface_get_material(i);
  278. if (mat.is_valid()) {
  279. _fill_material(p_tree, mat, item);
  280. }
  281. }
  282. if (created) {
  283. _fill_mesh(mesh_tree, p_mesh, mesh_tree->get_root());
  284. }
  285. }
  286. void SceneImportSettingsDialog::_fill_animation(Tree *p_tree, const Ref<Animation> &p_anim, const String &p_name, TreeItem *p_parent) {
  287. if (!animation_map.has(p_name)) {
  288. AnimationData ad;
  289. ad.animation = p_anim;
  290. _load_default_subresource_settings(ad.settings, "animations", p_name, ResourceImporterScene::INTERNAL_IMPORT_CATEGORY_ANIMATION);
  291. animation_map[p_name] = ad;
  292. }
  293. AnimationData &animation_data = animation_map[p_name];
  294. Ref<Texture2D> icon = get_editor_theme_icon(SNAME("Animation"));
  295. TreeItem *item = p_tree->create_item(p_parent);
  296. item->set_text(0, p_name);
  297. item->set_icon(0, icon);
  298. item->set_meta("type", "Animation");
  299. item->set_meta("import_id", p_name);
  300. item->set_selectable(0, true);
  301. animation_data.scene_node = item;
  302. }
  303. void SceneImportSettingsDialog::_fill_scene(Node *p_node, TreeItem *p_parent_item) {
  304. String import_id;
  305. if (p_node->has_meta("import_id")) {
  306. import_id = p_node->get_meta("import_id");
  307. } else {
  308. import_id = "PATH:" + String(scene->get_path_to(p_node));
  309. p_node->set_meta("import_id", import_id);
  310. }
  311. ImporterMeshInstance3D *src_mesh_node = Object::cast_to<ImporterMeshInstance3D>(p_node);
  312. if (src_mesh_node) {
  313. MeshInstance3D *mesh_node = memnew(MeshInstance3D);
  314. mesh_node->set_name(src_mesh_node->get_name());
  315. mesh_node->set_transform(src_mesh_node->get_transform());
  316. mesh_node->set_skin(src_mesh_node->get_skin());
  317. mesh_node->set_skeleton_path(src_mesh_node->get_skeleton_path());
  318. if (src_mesh_node->get_mesh().is_valid()) {
  319. Ref<ImporterMesh> editor_mesh = src_mesh_node->get_mesh();
  320. mesh_node->set_mesh(editor_mesh->get_mesh());
  321. }
  322. // Replace the original mesh node in the scene tree with the new one.
  323. if (unlikely(p_node == scene)) {
  324. scene = mesh_node;
  325. }
  326. p_node->replace_by(mesh_node);
  327. memdelete(p_node);
  328. p_node = mesh_node;
  329. }
  330. String type = p_node->get_class();
  331. if (!has_theme_icon(type, EditorStringName(EditorIcons))) {
  332. type = "Node3D";
  333. }
  334. Ref<Texture2D> icon = get_editor_theme_icon(type);
  335. TreeItem *item = scene_tree->create_item(p_parent_item);
  336. item->set_text(0, p_node->get_name());
  337. if (p_node == scene) {
  338. icon = get_editor_theme_icon(SNAME("PackedScene"));
  339. item->set_text(0, TTR("Scene"));
  340. }
  341. item->set_icon(0, icon);
  342. item->set_meta("type", "Node");
  343. item->set_meta("class", type);
  344. item->set_meta("import_id", import_id);
  345. item->set_tooltip_text(0, vformat(TTR("Type: %s\nImport ID: %s"), type, import_id));
  346. item->set_selectable(0, true);
  347. if (!node_map.has(import_id)) {
  348. NodeData nd;
  349. if (p_node != scene) {
  350. ResourceImporterScene::InternalImportCategory category;
  351. if (src_mesh_node) {
  352. category = ResourceImporterScene::INTERNAL_IMPORT_CATEGORY_MESH_3D_NODE;
  353. } else if (Object::cast_to<AnimationPlayer>(p_node)) {
  354. category = ResourceImporterScene::INTERNAL_IMPORT_CATEGORY_ANIMATION_NODE;
  355. animation_player = Object::cast_to<AnimationPlayer>(p_node);
  356. animation_player->connect(SceneStringName(animation_finished), callable_mp(this, &SceneImportSettingsDialog::_animation_finished));
  357. } else if (Object::cast_to<Skeleton3D>(p_node)) {
  358. category = ResourceImporterScene::INTERNAL_IMPORT_CATEGORY_SKELETON_3D_NODE;
  359. Skeleton3D *skeleton = Object::cast_to<Skeleton3D>(p_node);
  360. skeleton->connect(SceneStringName(tree_entered), callable_mp(this, &SceneImportSettingsDialog::_skeleton_tree_entered).bind(skeleton));
  361. skeletons.push_back(skeleton);
  362. } else {
  363. category = ResourceImporterScene::INTERNAL_IMPORT_CATEGORY_NODE;
  364. }
  365. _load_default_subresource_settings(nd.settings, "nodes", import_id, category);
  366. }
  367. node_map[import_id] = nd;
  368. }
  369. NodeData &node_data = node_map[import_id];
  370. node_data.node = p_node;
  371. node_data.scene_node = item;
  372. AnimationPlayer *anim_node = Object::cast_to<AnimationPlayer>(p_node);
  373. if (anim_node) {
  374. Vector<String> animation_list;
  375. List<StringName> animations;
  376. anim_node->get_animation_list(&animations);
  377. for (const StringName &E : animations) {
  378. _fill_animation(scene_tree, anim_node->get_animation(E), E, item);
  379. animation_list.append(E);
  380. }
  381. if (scene_import_settings_data != nullptr) {
  382. scene_import_settings_data->animation_list = animation_list;
  383. }
  384. }
  385. for (int i = 0; i < p_node->get_child_count(); i++) {
  386. _fill_scene(p_node->get_child(i), item);
  387. }
  388. MeshInstance3D *mesh_node = Object::cast_to<MeshInstance3D>(p_node);
  389. if (mesh_node && mesh_node->get_mesh().is_valid()) {
  390. if (!editing_animation) {
  391. _fill_mesh(scene_tree, mesh_node->get_mesh(), item);
  392. }
  393. // Add the collider view.
  394. MeshInstance3D *collider_view = memnew(MeshInstance3D);
  395. collider_view->set_name("collider_view");
  396. collider_view->set_visible(false);
  397. mesh_node->add_child(collider_view, true);
  398. collider_view->set_owner(mesh_node);
  399. Transform3D accum_xform;
  400. Node3D *base = mesh_node;
  401. while (base) {
  402. accum_xform = base->get_transform() * accum_xform;
  403. base = Object::cast_to<Node3D>(base->get_parent());
  404. }
  405. AABB aabb = accum_xform.xform(mesh_node->get_mesh()->get_aabb());
  406. if (first_aabb) {
  407. contents_aabb = aabb;
  408. first_aabb = false;
  409. } else {
  410. contents_aabb.merge_with(aabb);
  411. }
  412. }
  413. Skeleton3D *skeleton = Object::cast_to<Skeleton3D>(p_node);
  414. if (skeleton) {
  415. Ref<ArrayMesh> bones_mesh = Skeleton3DGizmoPlugin::get_bones_mesh(skeleton, -1, true);
  416. bones_mesh_preview->set_mesh(bones_mesh);
  417. Transform3D accum_xform;
  418. Node3D *base = skeleton;
  419. while (base) {
  420. accum_xform = base->get_transform() * accum_xform;
  421. base = Object::cast_to<Node3D>(base->get_parent());
  422. }
  423. bones_mesh_preview->set_transform(accum_xform * skeleton->get_transform());
  424. AABB aabb = accum_xform.xform(bones_mesh->get_aabb());
  425. if (first_aabb) {
  426. contents_aabb = aabb;
  427. first_aabb = false;
  428. } else {
  429. contents_aabb.merge_with(aabb);
  430. }
  431. }
  432. }
  433. void SceneImportSettingsDialog::_update_scene() {
  434. scene_tree->clear();
  435. material_tree->clear();
  436. mesh_tree->clear();
  437. // Hidden roots.
  438. material_tree->create_item();
  439. mesh_tree->create_item();
  440. _fill_scene(scene, nullptr);
  441. }
  442. void SceneImportSettingsDialog::_update_view_gizmos() {
  443. if (!is_visible()) {
  444. return;
  445. }
  446. const HashMap<StringName, Variant> &main_settings = scene_import_settings_data->current;
  447. bool reshow_settings = false;
  448. if (main_settings.has("nodes/import_as_skeleton_bones")) {
  449. bool new_import_as_skeleton = main_settings["nodes/import_as_skeleton_bones"];
  450. reshow_settings = reshow_settings || (new_import_as_skeleton != previous_import_as_skeleton);
  451. previous_import_as_skeleton = new_import_as_skeleton;
  452. }
  453. if (main_settings.has("animation/import_rest_as_RESET")) {
  454. bool new_rest_as_reset = main_settings["animation/import_rest_as_RESET"];
  455. reshow_settings = reshow_settings || (new_rest_as_reset != previous_rest_as_reset);
  456. previous_rest_as_reset = new_rest_as_reset;
  457. }
  458. if (reshow_settings) {
  459. _re_import();
  460. open_settings(base_path);
  461. return;
  462. }
  463. for (const KeyValue<String, NodeData> &e : node_map) {
  464. // Skip import nodes that aren't MeshInstance3D.
  465. const MeshInstance3D *mesh_node = Object::cast_to<MeshInstance3D>(e.value.node);
  466. if (mesh_node == nullptr || mesh_node->get_mesh().is_null()) {
  467. continue;
  468. }
  469. // Determine if the mesh collider should be visible.
  470. bool show_collider_view = false;
  471. if (e.value.settings.has(SNAME("generate/physics"))) {
  472. show_collider_view = e.value.settings[SNAME("generate/physics")];
  473. }
  474. // Get the collider_view MeshInstance3D.
  475. TypedArray<Node> descendants = mesh_node->find_children("collider_view", "MeshInstance3D");
  476. CRASH_COND_MSG(descendants.is_empty(), "This is unreachable, since the collider view is always created even when the collision is not used! If this is triggered there is a bug on the function `_fill_scene`.");
  477. MeshInstance3D *collider_view = Object::cast_to<MeshInstance3D>(descendants[0].operator Object *());
  478. // Regenerate the physics collider for this MeshInstance3D if either:
  479. // - A regeneration is requested for the selected import node.
  480. // - The collider is being made visible.
  481. if ((generate_collider && e.key == selected_id) || (show_collider_view && !collider_view->is_visible())) {
  482. // This collider_view doesn't have a mesh so we need to generate a new one.
  483. Ref<ImporterMesh> mesh;
  484. mesh.instantiate();
  485. // ResourceImporterScene::get_collision_shapes() expects ImporterMesh, not Mesh.
  486. // TODO: Duplicate code with EditorSceneFormatImporterESCN::import_scene()
  487. // Consider making a utility function to convert from Mesh to ImporterMesh.
  488. Ref<Mesh> mesh_3d_mesh = mesh_node->get_mesh();
  489. Ref<ArrayMesh> array_mesh_3d_mesh = mesh_3d_mesh;
  490. if (array_mesh_3d_mesh.is_valid()) {
  491. // For the MeshInstance3D nodes, we need to convert the ArrayMesh to an ImporterMesh specially.
  492. mesh->set_name(array_mesh_3d_mesh->get_name());
  493. for (int32_t blend_i = 0; blend_i < array_mesh_3d_mesh->get_blend_shape_count(); blend_i++) {
  494. mesh->add_blend_shape(array_mesh_3d_mesh->get_blend_shape_name(blend_i));
  495. }
  496. for (int32_t surface_i = 0; surface_i < array_mesh_3d_mesh->get_surface_count(); surface_i++) {
  497. mesh->add_surface(array_mesh_3d_mesh->surface_get_primitive_type(surface_i),
  498. array_mesh_3d_mesh->surface_get_arrays(surface_i),
  499. array_mesh_3d_mesh->surface_get_blend_shape_arrays(surface_i),
  500. array_mesh_3d_mesh->surface_get_lods(surface_i),
  501. array_mesh_3d_mesh->surface_get_material(surface_i),
  502. array_mesh_3d_mesh->surface_get_name(surface_i),
  503. array_mesh_3d_mesh->surface_get_format(surface_i));
  504. }
  505. mesh->set_blend_shape_mode(array_mesh_3d_mesh->get_blend_shape_mode());
  506. } else if (mesh_3d_mesh.is_valid()) {
  507. // For the MeshInstance3D nodes, we need to convert the Mesh to an ImporterMesh specially.
  508. mesh->set_name(mesh_3d_mesh->get_name());
  509. for (int32_t surface_i = 0; surface_i < mesh_3d_mesh->get_surface_count(); surface_i++) {
  510. mesh->add_surface(mesh_3d_mesh->surface_get_primitive_type(surface_i),
  511. mesh_3d_mesh->surface_get_arrays(surface_i),
  512. Array(),
  513. mesh_3d_mesh->surface_get_lods(surface_i),
  514. mesh_3d_mesh->surface_get_material(surface_i),
  515. mesh_3d_mesh->surface_get_material(surface_i).is_valid() ? mesh_3d_mesh->surface_get_material(surface_i)->get_name() : String(),
  516. mesh_3d_mesh->surface_get_format(surface_i));
  517. }
  518. }
  519. // Generate the mesh collider.
  520. Vector<Ref<Shape3D>> shapes = ResourceImporterScene::get_collision_shapes(mesh, e.value.settings, 1.0);
  521. const Transform3D transform = ResourceImporterScene::get_collision_shapes_transform(e.value.settings);
  522. Ref<ArrayMesh> collider_view_mesh;
  523. collider_view_mesh.instantiate();
  524. for (Ref<Shape3D> shape : shapes) {
  525. Ref<ArrayMesh> debug_shape_mesh;
  526. if (shape.is_valid()) {
  527. debug_shape_mesh = shape->get_debug_mesh();
  528. }
  529. if (debug_shape_mesh.is_valid()) {
  530. collider_view_mesh->add_surface_from_arrays(
  531. debug_shape_mesh->surface_get_primitive_type(0),
  532. debug_shape_mesh->surface_get_arrays(0));
  533. collider_view_mesh->surface_set_material(
  534. collider_view_mesh->get_surface_count() - 1,
  535. collider_mat);
  536. }
  537. }
  538. collider_view->set_mesh(collider_view_mesh);
  539. collider_view->set_transform(transform);
  540. }
  541. // Set the collider visibility.
  542. collider_view->set_visible(show_collider_view);
  543. }
  544. generate_collider = false;
  545. }
  546. void SceneImportSettingsDialog::_update_camera() {
  547. AABB camera_aabb;
  548. float rot_x = cam_rot_x;
  549. float rot_y = cam_rot_y;
  550. float zoom = cam_zoom;
  551. if (selected_type == "Node" || selected_type == "Animation" || selected_type.is_empty()) {
  552. camera_aabb = contents_aabb;
  553. } else {
  554. if (mesh_preview->get_mesh().is_valid()) {
  555. camera_aabb = mesh_preview->get_transform().xform(mesh_preview->get_mesh()->get_aabb());
  556. } else {
  557. camera_aabb = AABB(Vector3(-1, -1, -1), Vector3(2, 2, 2));
  558. }
  559. if (selected_type == "Mesh" && mesh_map.has(selected_id)) {
  560. const MeshData &md = mesh_map[selected_id];
  561. rot_x = md.cam_rot_x;
  562. rot_y = md.cam_rot_y;
  563. zoom = md.cam_zoom;
  564. } else if (selected_type == "Material" && material_map.has(selected_id)) {
  565. const MaterialData &md = material_map[selected_id];
  566. rot_x = md.cam_rot_x;
  567. rot_y = md.cam_rot_y;
  568. zoom = md.cam_zoom;
  569. }
  570. }
  571. Vector3 center = camera_aabb.get_center();
  572. float camera_size = camera_aabb.get_longest_axis_size();
  573. camera->set_orthogonal(camera_size * zoom, 0.0001, camera_size * 2);
  574. Transform3D xf;
  575. xf.basis = Basis(Vector3(0, 1, 0), rot_y) * Basis(Vector3(1, 0, 0), rot_x);
  576. xf.origin = center;
  577. xf.translate_local(0, 0, camera_size);
  578. camera->set_transform(xf);
  579. }
  580. void SceneImportSettingsDialog::_load_default_subresource_settings(HashMap<StringName, Variant> &settings, const String &p_type, const String &p_import_id, ResourceImporterScene::InternalImportCategory p_category) {
  581. if (base_subresource_settings.has(p_type)) {
  582. Dictionary d = base_subresource_settings[p_type];
  583. if (d.has(p_import_id)) {
  584. d = d[p_import_id];
  585. List<ResourceImporterScene::ImportOption> options;
  586. if (editing_animation) {
  587. ResourceImporterScene::get_animation_singleton()->get_internal_import_options(p_category, &options);
  588. } else {
  589. ResourceImporterScene::get_scene_singleton()->get_internal_import_options(p_category, &options);
  590. }
  591. for (const ResourceImporterScene::ImportOption &E : options) {
  592. String key = E.option.name;
  593. if (d.has(key)) {
  594. settings[key] = d[key];
  595. }
  596. }
  597. }
  598. }
  599. }
  600. void SceneImportSettingsDialog::request_generate_collider() {
  601. generate_collider = true;
  602. }
  603. void SceneImportSettingsDialog::update_view() {
  604. update_view_timer->start();
  605. }
  606. void SceneImportSettingsDialog::open_settings(const String &p_path, const String &p_scene_import_type) {
  607. if (scene) {
  608. _cleanup();
  609. memdelete(scene);
  610. scene = nullptr;
  611. }
  612. editing_animation = p_scene_import_type == "AnimationLibrary";
  613. scene_import_settings_data->settings = nullptr;
  614. scene_import_settings_data->path = p_path;
  615. // Visibility.
  616. data_mode->set_tab_hidden(1, editing_animation);
  617. data_mode->set_tab_hidden(2, editing_animation);
  618. if (editing_animation) {
  619. data_mode->set_current_tab(0);
  620. }
  621. action_menu->get_popup()->set_item_disabled(action_menu->get_popup()->get_item_id(ACTION_EXTRACT_MATERIALS), editing_animation);
  622. action_menu->get_popup()->set_item_disabled(action_menu->get_popup()->get_item_id(ACTION_CHOOSE_MESH_SAVE_PATHS), editing_animation);
  623. base_path = p_path;
  624. mesh_set.clear();
  625. animation_map.clear();
  626. material_map.clear();
  627. unnamed_material_name_map.clear();
  628. mesh_map.clear();
  629. node_map.clear();
  630. defaults.clear();
  631. mesh_preview->hide();
  632. selected_id = "";
  633. selected_type = "";
  634. cam_rot_x = -Math_PI / 4;
  635. cam_rot_y = -Math_PI / 4;
  636. cam_zoom = 1;
  637. {
  638. base_subresource_settings.clear();
  639. Ref<ConfigFile> config;
  640. config.instantiate();
  641. Error err = config->load(p_path + ".import");
  642. if (err == OK) {
  643. List<String> keys;
  644. config->get_section_keys("params", &keys);
  645. for (const String &E : keys) {
  646. Variant value = config->get_value("params", E);
  647. if (E == "_subresources") {
  648. base_subresource_settings = value;
  649. } else {
  650. defaults[E] = value;
  651. }
  652. }
  653. }
  654. }
  655. scene = ResourceImporterScene::get_scene_singleton()->pre_import(p_path, defaults); // Use the scene singleton here because we want to see the full thing.
  656. if (scene == nullptr) {
  657. EditorNode::get_singleton()->show_warning(TTR("Error opening scene"));
  658. return;
  659. }
  660. first_aabb = true;
  661. _update_scene();
  662. base_viewport->add_child(scene);
  663. inspector->edit(nullptr);
  664. if (first_aabb) {
  665. contents_aabb = AABB(Vector3(-1, -1, -1), Vector3(2, 2, 2));
  666. first_aabb = false;
  667. }
  668. const HashMap<StringName, Variant> &main_settings = scene_import_settings_data->current;
  669. if (main_settings.has("nodes/import_as_skeleton_bones")) {
  670. previous_import_as_skeleton = main_settings["nodes/import_as_skeleton_bones"];
  671. }
  672. if (main_settings.has("animation/import_rest_as_RESET")) {
  673. previous_rest_as_reset = main_settings["animation/import_rest_as_RESET"];
  674. }
  675. popup_centered_ratio();
  676. _update_view_gizmos();
  677. _update_camera();
  678. // Start with the root item (Scene) selected.
  679. scene_tree->get_root()->select(0);
  680. if (editing_animation) {
  681. set_title(vformat(TTR("Advanced Import Settings for AnimationLibrary '%s'"), base_path.get_file()));
  682. } else {
  683. set_title(vformat(TTR("Advanced Import Settings for Scene '%s'"), base_path.get_file()));
  684. }
  685. }
  686. SceneImportSettingsDialog *SceneImportSettingsDialog::singleton = nullptr;
  687. SceneImportSettingsDialog *SceneImportSettingsDialog::get_singleton() {
  688. return singleton;
  689. }
  690. Node *SceneImportSettingsDialog::get_selected_node() {
  691. if (selected_id == "") {
  692. return nullptr;
  693. }
  694. return node_map[selected_id].node;
  695. }
  696. void SceneImportSettingsDialog::_select(Tree *p_from, const String &p_type, const String &p_id) {
  697. selecting = true;
  698. scene_import_settings_data->hide_options = false;
  699. bones_mesh_preview->hide();
  700. if (p_type == "Node") {
  701. node_selected->hide(); // Always hide just in case.
  702. mesh_preview->hide();
  703. _reset_animation();
  704. if (Object::cast_to<Node3D>(scene)) {
  705. Object::cast_to<Node3D>(scene)->show();
  706. }
  707. material_tree->deselect_all();
  708. mesh_tree->deselect_all();
  709. NodeData &nd = node_map[p_id];
  710. MeshInstance3D *mi = Object::cast_to<MeshInstance3D>(nd.node);
  711. if (mi) {
  712. Ref<Mesh> base_mesh = mi->get_mesh();
  713. if (base_mesh.is_valid()) {
  714. AABB aabb = base_mesh->get_aabb();
  715. Transform3D aabb_xf;
  716. aabb_xf.basis.scale(aabb.size);
  717. aabb_xf.origin = aabb.position;
  718. aabb_xf = mi->get_global_transform() * aabb_xf;
  719. node_selected->set_transform(aabb_xf);
  720. node_selected->show();
  721. }
  722. }
  723. if (nd.node == scene) {
  724. scene_import_settings_data->settings = &defaults;
  725. scene_import_settings_data->category = ResourceImporterScene::INTERNAL_IMPORT_CATEGORY_MAX;
  726. } else {
  727. scene_import_settings_data->settings = &nd.settings;
  728. if (mi) {
  729. scene_import_settings_data->category = ResourceImporterScene::INTERNAL_IMPORT_CATEGORY_MESH_3D_NODE;
  730. scene_import_settings_data->hide_options = editing_animation;
  731. } else if (Object::cast_to<AnimationPlayer>(nd.node)) {
  732. scene_import_settings_data->category = ResourceImporterScene::INTERNAL_IMPORT_CATEGORY_ANIMATION_NODE;
  733. } else if (Object::cast_to<Skeleton3D>(nd.node)) {
  734. scene_import_settings_data->category = ResourceImporterScene::INTERNAL_IMPORT_CATEGORY_SKELETON_3D_NODE;
  735. bones_mesh_preview->show();
  736. } else {
  737. scene_import_settings_data->category = ResourceImporterScene::INTERNAL_IMPORT_CATEGORY_NODE;
  738. scene_import_settings_data->hide_options = editing_animation;
  739. }
  740. }
  741. } else if (p_type == "Animation") {
  742. node_selected->hide(); // Always hide just in case.
  743. mesh_preview->hide();
  744. _reset_animation(p_id);
  745. if (Object::cast_to<Node3D>(scene)) {
  746. Object::cast_to<Node3D>(scene)->show();
  747. }
  748. material_tree->deselect_all();
  749. mesh_tree->deselect_all();
  750. AnimationData &ad = animation_map[p_id];
  751. scene_import_settings_data->settings = &ad.settings;
  752. scene_import_settings_data->category = ResourceImporterScene::INTERNAL_IMPORT_CATEGORY_ANIMATION;
  753. _animation_update_skeleton_visibility();
  754. } else if (p_type == "Mesh") {
  755. node_selected->hide();
  756. if (Object::cast_to<Node3D>(scene)) {
  757. Object::cast_to<Node3D>(scene)->hide();
  758. }
  759. MeshData &md = mesh_map[p_id];
  760. if (md.mesh_node != nullptr) {
  761. if (p_from != mesh_tree) {
  762. md.mesh_node->uncollapse_tree();
  763. md.mesh_node->select(0);
  764. mesh_tree->ensure_cursor_is_visible();
  765. }
  766. if (p_from != scene_tree) {
  767. md.scene_node->uncollapse_tree();
  768. md.scene_node->select(0);
  769. scene_tree->ensure_cursor_is_visible();
  770. }
  771. }
  772. mesh_preview->set_mesh(md.mesh);
  773. mesh_preview->show();
  774. _reset_animation();
  775. material_tree->deselect_all();
  776. scene_import_settings_data->settings = &md.settings;
  777. scene_import_settings_data->category = ResourceImporterScene::INTERNAL_IMPORT_CATEGORY_MESH;
  778. } else if (p_type == "Material") {
  779. node_selected->hide();
  780. if (Object::cast_to<Node3D>(scene)) {
  781. Object::cast_to<Node3D>(scene)->hide();
  782. }
  783. mesh_preview->show();
  784. _reset_animation();
  785. MaterialData &md = material_map[p_id];
  786. material_preview->set_material(md.material);
  787. mesh_preview->set_mesh(material_preview);
  788. if (p_from != mesh_tree) {
  789. md.mesh_node->uncollapse_tree();
  790. md.mesh_node->select(0);
  791. mesh_tree->ensure_cursor_is_visible();
  792. }
  793. if (p_from != scene_tree) {
  794. md.scene_node->uncollapse_tree();
  795. md.scene_node->select(0);
  796. scene_tree->ensure_cursor_is_visible();
  797. }
  798. if (p_from != material_tree) {
  799. md.material_node->uncollapse_tree();
  800. md.material_node->select(0);
  801. material_tree->ensure_cursor_is_visible();
  802. }
  803. scene_import_settings_data->settings = &md.settings;
  804. scene_import_settings_data->category = ResourceImporterScene::INTERNAL_IMPORT_CATEGORY_MATERIAL;
  805. }
  806. selected_type = p_type;
  807. selected_id = p_id;
  808. selecting = false;
  809. _update_camera();
  810. List<ResourceImporter::ImportOption> options;
  811. if (editing_animation) {
  812. if (scene_import_settings_data->category == ResourceImporterScene::INTERNAL_IMPORT_CATEGORY_MAX) {
  813. ResourceImporterScene::get_animation_singleton()->get_import_options(base_path, &options);
  814. } else {
  815. ResourceImporterScene::get_animation_singleton()->get_internal_import_options(scene_import_settings_data->category, &options);
  816. }
  817. } else {
  818. if (scene_import_settings_data->category == ResourceImporterScene::INTERNAL_IMPORT_CATEGORY_MAX) {
  819. ResourceImporterScene::get_scene_singleton()->get_import_options(base_path, &options);
  820. } else {
  821. ResourceImporterScene::get_scene_singleton()->get_internal_import_options(scene_import_settings_data->category, &options);
  822. }
  823. }
  824. scene_import_settings_data->defaults.clear();
  825. scene_import_settings_data->current.clear();
  826. if (scene_import_settings_data->settings) {
  827. for (const ResourceImporter::ImportOption &E : options) {
  828. scene_import_settings_data->defaults[E.option.name] = E.default_value;
  829. // Needed for visibility toggling (fails if something is missing).
  830. if (scene_import_settings_data->settings->has(E.option.name)) {
  831. scene_import_settings_data->current[E.option.name] = (*scene_import_settings_data->settings)[E.option.name];
  832. } else {
  833. scene_import_settings_data->current[E.option.name] = E.default_value;
  834. }
  835. }
  836. }
  837. scene_import_settings_data->options = options;
  838. inspector->edit(scene_import_settings_data);
  839. scene_import_settings_data->notify_property_list_changed();
  840. }
  841. void SceneImportSettingsDialog::_inspector_property_edited(const String &p_name) {
  842. if (p_name == "settings/loop_mode") {
  843. if (!animation_map.has(selected_id)) {
  844. return;
  845. }
  846. HashMap<StringName, Variant> settings = animation_map[selected_id].settings;
  847. if (settings.has(p_name)) {
  848. animation_loop_mode = static_cast<Animation::LoopMode>((int)settings[p_name]);
  849. } else {
  850. animation_loop_mode = Animation::LoopMode::LOOP_NONE;
  851. }
  852. }
  853. }
  854. void SceneImportSettingsDialog::_reset_bone_transforms() {
  855. for (Skeleton3D *skeleton : skeletons) {
  856. skeleton->reset_bone_poses();
  857. }
  858. }
  859. void SceneImportSettingsDialog::_play_animation() {
  860. if (animation_player == nullptr) {
  861. return;
  862. }
  863. StringName id = StringName(selected_id);
  864. if (animation_player->has_animation(id)) {
  865. if (animation_player->is_playing()) {
  866. animation_player->pause();
  867. animation_play_button->set_button_icon(get_editor_theme_icon(SNAME("MainPlay")));
  868. set_process(false);
  869. } else {
  870. animation_player->play(id);
  871. animation_play_button->set_button_icon(get_editor_theme_icon(SNAME("Pause")));
  872. set_process(true);
  873. }
  874. }
  875. }
  876. void SceneImportSettingsDialog::_stop_current_animation() {
  877. animation_pingpong = false;
  878. animation_player->stop();
  879. animation_play_button->set_button_icon(get_editor_theme_icon(SNAME("MainPlay")));
  880. animation_slider->set_value_no_signal(0.0);
  881. set_process(false);
  882. }
  883. void SceneImportSettingsDialog::_reset_animation(const String &p_animation_name) {
  884. if (p_animation_name.is_empty()) {
  885. animation_preview->hide();
  886. if (animation_player != nullptr && animation_player->is_playing()) {
  887. animation_player->stop();
  888. }
  889. animation_play_button->set_button_icon(get_editor_theme_icon(SNAME("MainPlay")));
  890. _reset_bone_transforms();
  891. set_process(false);
  892. } else {
  893. _reset_bone_transforms();
  894. animation_preview->show();
  895. animation_loop_mode = Animation::LoopMode::LOOP_NONE;
  896. animation_pingpong = false;
  897. if (animation_map.has(p_animation_name)) {
  898. HashMap<StringName, Variant> settings = animation_map[p_animation_name].settings;
  899. if (settings.has("settings/loop_mode")) {
  900. animation_loop_mode = static_cast<Animation::LoopMode>((int)settings["settings/loop_mode"]);
  901. }
  902. }
  903. if (animation_player->is_playing() && animation_loop_mode != Animation::LoopMode::LOOP_NONE) {
  904. animation_player->play(p_animation_name);
  905. } else {
  906. animation_player->stop(true);
  907. animation_play_button->set_button_icon(get_editor_theme_icon(SNAME("MainPlay")));
  908. animation_player->set_assigned_animation(p_animation_name);
  909. animation_player->seek(0.0, true);
  910. animation_slider->set_value_no_signal(0.0);
  911. set_process(false);
  912. }
  913. }
  914. }
  915. void SceneImportSettingsDialog::_animation_slider_value_changed(double p_value) {
  916. if (animation_player == nullptr || !animation_map.has(selected_id) || animation_map[selected_id].animation.is_null()) {
  917. return;
  918. }
  919. if (animation_player->is_playing()) {
  920. animation_player->stop();
  921. animation_play_button->set_button_icon(get_editor_theme_icon(SNAME("MainPlay")));
  922. set_process(false);
  923. }
  924. animation_player->seek(p_value * animation_map[selected_id].animation->get_length(), true);
  925. }
  926. void SceneImportSettingsDialog::_skeleton_tree_entered(Skeleton3D *p_skeleton) {
  927. bones_mesh_preview->set_skeleton_path(p_skeleton->get_path());
  928. bones_mesh_preview->set_skin(p_skeleton->register_skin(p_skeleton->create_skin_from_rest_transforms()));
  929. }
  930. void SceneImportSettingsDialog::_animation_finished(const StringName &p_name) {
  931. Animation::LoopMode loop_mode = animation_loop_mode;
  932. switch (loop_mode) {
  933. case Animation::LOOP_NONE: {
  934. animation_play_button->set_button_icon(get_editor_theme_icon(SNAME("MainPlay")));
  935. animation_slider->set_value_no_signal(1.0);
  936. set_process(false);
  937. } break;
  938. case Animation::LOOP_LINEAR: {
  939. animation_player->play(p_name);
  940. } break;
  941. case Animation::LOOP_PINGPONG: {
  942. if (animation_pingpong) {
  943. animation_player->play(p_name);
  944. } else {
  945. animation_player->play_backwards(p_name);
  946. }
  947. animation_pingpong = !animation_pingpong;
  948. } break;
  949. default: {
  950. } break;
  951. }
  952. }
  953. void SceneImportSettingsDialog::_animation_update_skeleton_visibility() {
  954. if (animation_toggle_skeleton_visibility->is_pressed()) {
  955. bones_mesh_preview->show();
  956. } else {
  957. bones_mesh_preview->hide();
  958. }
  959. }
  960. void SceneImportSettingsDialog::_material_tree_selected() {
  961. if (selecting) {
  962. return;
  963. }
  964. TreeItem *item = material_tree->get_selected();
  965. String type = item->get_meta("type");
  966. String import_id = item->get_meta("import_id");
  967. _select(material_tree, type, import_id);
  968. }
  969. void SceneImportSettingsDialog::_mesh_tree_selected() {
  970. if (selecting) {
  971. return;
  972. }
  973. TreeItem *item = mesh_tree->get_selected();
  974. String type = item->get_meta("type");
  975. String import_id = item->get_meta("import_id");
  976. _select(mesh_tree, type, import_id);
  977. }
  978. void SceneImportSettingsDialog::_scene_tree_selected() {
  979. if (selecting) {
  980. return;
  981. }
  982. TreeItem *item = scene_tree->get_selected();
  983. String type = item->get_meta("type");
  984. String import_id = item->get_meta("import_id");
  985. _select(scene_tree, type, import_id);
  986. }
  987. void SceneImportSettingsDialog::_cleanup() {
  988. skeletons.clear();
  989. if (animation_player != nullptr) {
  990. animation_player->disconnect(SceneStringName(animation_finished), callable_mp(this, &SceneImportSettingsDialog::_animation_finished));
  991. animation_player = nullptr;
  992. }
  993. set_process(false);
  994. }
  995. void SceneImportSettingsDialog::_on_light_1_switch_pressed() {
  996. light1->set_visible(light_1_switch->is_pressed());
  997. }
  998. void SceneImportSettingsDialog::_on_light_2_switch_pressed() {
  999. light2->set_visible(light_2_switch->is_pressed());
  1000. }
  1001. void SceneImportSettingsDialog::_on_light_rotate_switch_pressed() {
  1002. bool light_top_level = !light_rotate_switch->is_pressed();
  1003. light1->set_as_top_level_keep_local(light_top_level);
  1004. light2->set_as_top_level_keep_local(light_top_level);
  1005. }
  1006. void SceneImportSettingsDialog::_viewport_input(const Ref<InputEvent> &p_input) {
  1007. float *rot_x = &cam_rot_x;
  1008. float *rot_y = &cam_rot_y;
  1009. float *zoom = &cam_zoom;
  1010. if (selected_type == "Mesh" && mesh_map.has(selected_id)) {
  1011. MeshData &md = mesh_map[selected_id];
  1012. rot_x = &md.cam_rot_x;
  1013. rot_y = &md.cam_rot_y;
  1014. zoom = &md.cam_zoom;
  1015. } else if (selected_type == "Material" && material_map.has(selected_id)) {
  1016. MaterialData &md = material_map[selected_id];
  1017. rot_x = &md.cam_rot_x;
  1018. rot_y = &md.cam_rot_y;
  1019. zoom = &md.cam_zoom;
  1020. }
  1021. Ref<InputEventMouseMotion> mm = p_input;
  1022. if (mm.is_valid() && (mm->get_button_mask().has_flag(MouseButtonMask::LEFT))) {
  1023. (*rot_x) -= mm->get_relative().y * 0.01 * EDSCALE;
  1024. (*rot_y) -= mm->get_relative().x * 0.01 * EDSCALE;
  1025. (*rot_x) = CLAMP((*rot_x), -Math_PI / 2, Math_PI / 2);
  1026. _update_camera();
  1027. }
  1028. if (mm.is_valid() && DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_CURSOR_SHAPE)) {
  1029. DisplayServer::get_singleton()->cursor_set_shape(DisplayServer::CursorShape::CURSOR_ARROW);
  1030. }
  1031. Ref<InputEventMouseButton> mb = p_input;
  1032. if (mb.is_valid() && mb->get_button_index() == MouseButton::WHEEL_DOWN) {
  1033. (*zoom) *= 1.1;
  1034. if ((*zoom) > 10.0) {
  1035. (*zoom) = 10.0;
  1036. }
  1037. _update_camera();
  1038. }
  1039. if (mb.is_valid() && mb->get_button_index() == MouseButton::WHEEL_UP) {
  1040. (*zoom) /= 1.1;
  1041. if ((*zoom) < 0.1) {
  1042. (*zoom) = 0.1;
  1043. }
  1044. _update_camera();
  1045. }
  1046. }
  1047. void SceneImportSettingsDialog::_re_import() {
  1048. HashMap<StringName, Variant> main_settings;
  1049. main_settings = scene_import_settings_data->current;
  1050. main_settings.erase("_subresources");
  1051. Dictionary nodes;
  1052. Dictionary materials;
  1053. Dictionary meshes;
  1054. Dictionary animations;
  1055. Dictionary subresources;
  1056. for (KeyValue<String, NodeData> &E : node_map) {
  1057. if (E.value.settings.size()) {
  1058. Dictionary d;
  1059. for (const KeyValue<StringName, Variant> &F : E.value.settings) {
  1060. d[String(F.key)] = F.value;
  1061. }
  1062. nodes[E.key] = d;
  1063. }
  1064. }
  1065. if (nodes.size()) {
  1066. subresources["nodes"] = nodes;
  1067. }
  1068. for (KeyValue<String, MaterialData> &E : material_map) {
  1069. if (E.value.settings.size()) {
  1070. Dictionary d;
  1071. for (const KeyValue<StringName, Variant> &F : E.value.settings) {
  1072. d[String(F.key)] = F.value;
  1073. }
  1074. materials[E.key] = d;
  1075. }
  1076. }
  1077. if (materials.size()) {
  1078. subresources["materials"] = materials;
  1079. }
  1080. for (KeyValue<String, MeshData> &E : mesh_map) {
  1081. if (E.value.settings.size()) {
  1082. Dictionary d;
  1083. for (const KeyValue<StringName, Variant> &F : E.value.settings) {
  1084. d[String(F.key)] = F.value;
  1085. }
  1086. meshes[E.key] = d;
  1087. }
  1088. }
  1089. if (meshes.size()) {
  1090. subresources["meshes"] = meshes;
  1091. }
  1092. for (KeyValue<String, AnimationData> &E : animation_map) {
  1093. if (E.value.settings.size()) {
  1094. Dictionary d;
  1095. for (const KeyValue<StringName, Variant> &F : E.value.settings) {
  1096. d[String(F.key)] = F.value;
  1097. }
  1098. animations[E.key] = d;
  1099. }
  1100. }
  1101. if (animations.size()) {
  1102. subresources["animations"] = animations;
  1103. }
  1104. if (subresources.size()) {
  1105. main_settings["_subresources"] = subresources;
  1106. }
  1107. _cleanup(); // Prevent skeletons and other pointers from pointing to dangling references.
  1108. EditorFileSystem::get_singleton()->reimport_file_with_custom_parameters(base_path, editing_animation ? "animation_library" : "scene", main_settings);
  1109. }
  1110. void SceneImportSettingsDialog::_update_theme_item_cache() {
  1111. ConfirmationDialog::_update_theme_item_cache();
  1112. theme_cache.light_1_icon = get_editor_theme_icon(SNAME("MaterialPreviewLight1"));
  1113. theme_cache.light_2_icon = get_editor_theme_icon(SNAME("MaterialPreviewLight2"));
  1114. theme_cache.rotate_icon = get_editor_theme_icon(SNAME("PreviewRotate"));
  1115. }
  1116. void SceneImportSettingsDialog::_notification(int p_what) {
  1117. switch (p_what) {
  1118. case NOTIFICATION_READY: {
  1119. connect(SceneStringName(confirmed), callable_mp(this, &SceneImportSettingsDialog::_re_import));
  1120. } break;
  1121. case NOTIFICATION_THEME_CHANGED: {
  1122. action_menu->begin_bulk_theme_override();
  1123. action_menu->add_theme_style_override(CoreStringName(normal), get_theme_stylebox(CoreStringName(normal), "Button"));
  1124. action_menu->add_theme_style_override("hover", get_theme_stylebox("hover", "Button"));
  1125. action_menu->add_theme_style_override(SceneStringName(pressed), get_theme_stylebox(SceneStringName(pressed), "Button"));
  1126. action_menu->end_bulk_theme_override();
  1127. if (animation_player != nullptr && animation_player->is_playing()) {
  1128. animation_play_button->set_button_icon(get_editor_theme_icon(SNAME("Pause")));
  1129. } else {
  1130. animation_play_button->set_button_icon(get_editor_theme_icon(SNAME("MainPlay")));
  1131. }
  1132. animation_stop_button->set_button_icon(get_editor_theme_icon(SNAME("Stop")));
  1133. light_1_switch->set_button_icon(theme_cache.light_1_icon);
  1134. light_2_switch->set_button_icon(theme_cache.light_2_icon);
  1135. light_rotate_switch->set_button_icon(theme_cache.rotate_icon);
  1136. animation_toggle_skeleton_visibility->set_button_icon(get_editor_theme_icon(SNAME("Skeleton3D")));
  1137. } break;
  1138. case NOTIFICATION_PROCESS: {
  1139. if (animation_player != nullptr) {
  1140. animation_slider->set_value_no_signal(animation_player->get_current_animation_position() / animation_player->get_current_animation_length());
  1141. }
  1142. } break;
  1143. case NOTIFICATION_VISIBILITY_CHANGED: {
  1144. if (!is_visible()) {
  1145. _cleanup();
  1146. }
  1147. } break;
  1148. }
  1149. }
  1150. void SceneImportSettingsDialog::_menu_callback(int p_id) {
  1151. switch (p_id) {
  1152. case ACTION_EXTRACT_MATERIALS: {
  1153. save_path->set_title(TTR("Select folder to extract material resources"));
  1154. external_extension_type->select(0);
  1155. } break;
  1156. case ACTION_CHOOSE_MESH_SAVE_PATHS: {
  1157. save_path->set_title(TTR("Select folder where mesh resources will save on import"));
  1158. external_extension_type->select(1);
  1159. } break;
  1160. case ACTION_CHOOSE_ANIMATION_SAVE_PATHS: {
  1161. save_path->set_title(TTR("Select folder where animations will save on import"));
  1162. external_extension_type->select(1);
  1163. } break;
  1164. }
  1165. save_path->set_current_dir(base_path.get_base_dir());
  1166. current_action = p_id;
  1167. save_path->popup_centered_ratio();
  1168. }
  1169. void SceneImportSettingsDialog::_save_path_changed(const String &p_path) {
  1170. save_path_item->set_text(1, p_path);
  1171. if (FileAccess::exists(p_path)) {
  1172. save_path_item->set_text(2, TTR("Warning: File exists"));
  1173. save_path_item->set_tooltip_text(2, TTR("Existing file with the same name will be replaced."));
  1174. save_path_item->set_icon(2, get_editor_theme_icon(SNAME("StatusWarning")));
  1175. } else {
  1176. save_path_item->set_text(2, TTR("Will create new file"));
  1177. save_path_item->set_icon(2, get_editor_theme_icon(SNAME("StatusSuccess")));
  1178. }
  1179. }
  1180. void SceneImportSettingsDialog::_browse_save_callback(Object *p_item, int p_column, int p_id, MouseButton p_button) {
  1181. if (p_button != MouseButton::LEFT) {
  1182. return;
  1183. }
  1184. TreeItem *item = Object::cast_to<TreeItem>(p_item);
  1185. String path = item->get_text(1);
  1186. item_save_path->set_current_file(path);
  1187. save_path_item = item;
  1188. item_save_path->popup_centered_ratio();
  1189. }
  1190. void SceneImportSettingsDialog::_save_dir_callback(const String &p_path) {
  1191. external_path_tree->clear();
  1192. TreeItem *root = external_path_tree->create_item();
  1193. save_path_items.clear();
  1194. switch (current_action) {
  1195. case ACTION_EXTRACT_MATERIALS: {
  1196. for (const KeyValue<String, MaterialData> &E : material_map) {
  1197. MaterialData &md = material_map[E.key];
  1198. TreeItem *item = external_path_tree->create_item(root);
  1199. String name = md.material_node->get_text(0);
  1200. item->set_cell_mode(0, TreeItem::CELL_MODE_CHECK);
  1201. item->set_icon(0, get_editor_theme_icon(SNAME("StandardMaterial3D")));
  1202. item->set_text(0, name);
  1203. if (md.has_import_id) {
  1204. if (md.settings.has("use_external/enabled") && bool(md.settings["use_external/enabled"])) {
  1205. item->set_text(2, TTR("Already External"));
  1206. item->set_tooltip_text(2, TTR("This material already references an external file, no action will be taken.\nDisable the external property for it to be extracted again."));
  1207. } else {
  1208. item->set_metadata(0, E.key);
  1209. item->set_editable(0, true);
  1210. item->set_checked(0, true);
  1211. name = name.validate_filename();
  1212. String path = p_path.path_join(name);
  1213. if (external_extension_type->get_selected() == 0) {
  1214. path += ".tres";
  1215. } else {
  1216. path += ".res";
  1217. }
  1218. item->set_text(1, path);
  1219. if (FileAccess::exists(path)) {
  1220. item->set_text(2, TTR("Warning: File exists"));
  1221. item->set_tooltip_text(2, TTR("Existing file with the same name will be replaced."));
  1222. item->set_icon(2, get_editor_theme_icon(SNAME("StatusWarning")));
  1223. } else {
  1224. item->set_text(2, TTR("Will create new file"));
  1225. item->set_icon(2, get_editor_theme_icon(SNAME("StatusSuccess")));
  1226. }
  1227. item->add_button(1, get_editor_theme_icon(SNAME("Folder")));
  1228. }
  1229. } else {
  1230. item->set_text(2, TTR("No import ID"));
  1231. item->set_tooltip_text(2, TTR("Material has no name nor any other way to identify on re-import.\nPlease name it or ensure it is exported with an unique ID."));
  1232. item->set_icon(2, get_editor_theme_icon(SNAME("StatusError")));
  1233. }
  1234. save_path_items.push_back(item);
  1235. }
  1236. external_paths->set_title(TTR("Extract Materials to Resource Files"));
  1237. external_paths->set_ok_button_text(TTR("Extract"));
  1238. } break;
  1239. case ACTION_CHOOSE_MESH_SAVE_PATHS: {
  1240. for (const KeyValue<String, MeshData> &E : mesh_map) {
  1241. MeshData &md = mesh_map[E.key];
  1242. TreeItem *item = external_path_tree->create_item(root);
  1243. String name = md.mesh_node->get_text(0);
  1244. item->set_cell_mode(0, TreeItem::CELL_MODE_CHECK);
  1245. item->set_icon(0, get_editor_theme_icon(SNAME("MeshItem")));
  1246. item->set_text(0, name);
  1247. if (md.has_import_id) {
  1248. if (md.settings.has("save_to_file/enabled") && bool(md.settings["save_to_file/enabled"])) {
  1249. item->set_text(2, TTR("Already Saving"));
  1250. item->set_tooltip_text(2, TTR("This mesh already saves to an external resource, no action will be taken."));
  1251. } else {
  1252. item->set_metadata(0, E.key);
  1253. item->set_editable(0, true);
  1254. item->set_checked(0, true);
  1255. name = name.validate_filename();
  1256. String path = p_path.path_join(name);
  1257. if (external_extension_type->get_selected() == 0) {
  1258. path += ".tres";
  1259. } else {
  1260. path += ".res";
  1261. }
  1262. item->set_text(1, path);
  1263. if (FileAccess::exists(path)) {
  1264. item->set_text(2, TTR("Warning: File exists"));
  1265. item->set_tooltip_text(2, TTR("Existing file with the same name will be replaced on import."));
  1266. item->set_icon(2, get_editor_theme_icon(SNAME("StatusWarning")));
  1267. } else {
  1268. item->set_text(2, TTR("Will save to new file"));
  1269. item->set_icon(2, get_editor_theme_icon(SNAME("StatusSuccess")));
  1270. }
  1271. item->add_button(1, get_editor_theme_icon(SNAME("Folder")));
  1272. }
  1273. } else {
  1274. item->set_text(2, TTR("No import ID"));
  1275. item->set_tooltip_text(2, TTR("Mesh has no name nor any other way to identify on re-import.\nPlease name it or ensure it is exported with an unique ID."));
  1276. item->set_icon(2, get_editor_theme_icon(SNAME("StatusError")));
  1277. }
  1278. save_path_items.push_back(item);
  1279. }
  1280. external_paths->set_title(TTR("Set paths to save meshes as resource files on Reimport"));
  1281. external_paths->set_ok_button_text(TTR("Set Paths"));
  1282. } break;
  1283. case ACTION_CHOOSE_ANIMATION_SAVE_PATHS: {
  1284. for (const KeyValue<String, AnimationData> &E : animation_map) {
  1285. AnimationData &ad = animation_map[E.key];
  1286. TreeItem *item = external_path_tree->create_item(root);
  1287. String name = ad.scene_node->get_text(0);
  1288. item->set_cell_mode(0, TreeItem::CELL_MODE_CHECK);
  1289. item->set_icon(0, get_editor_theme_icon(SNAME("Animation")));
  1290. item->set_text(0, name);
  1291. if (ad.settings.has("save_to_file/enabled") && bool(ad.settings["save_to_file/enabled"])) {
  1292. item->set_text(2, TTR("Already Saving"));
  1293. item->set_tooltip_text(2, TTR("This animation already saves to an external resource, no action will be taken."));
  1294. } else {
  1295. item->set_metadata(0, E.key);
  1296. item->set_editable(0, true);
  1297. item->set_checked(0, true);
  1298. name = name.validate_filename();
  1299. String path = p_path.path_join(name);
  1300. if (external_extension_type->get_selected() == 0) {
  1301. path += ".tres";
  1302. } else {
  1303. path += ".res";
  1304. }
  1305. item->set_text(1, path);
  1306. if (FileAccess::exists(path)) {
  1307. item->set_text(2, TTR("Warning: File exists"));
  1308. item->set_tooltip_text(2, TTR("Existing file with the same name will be replaced on import."));
  1309. item->set_icon(2, get_editor_theme_icon(SNAME("StatusWarning")));
  1310. } else {
  1311. item->set_text(2, TTR("Will save to new file"));
  1312. item->set_icon(2, get_editor_theme_icon(SNAME("StatusSuccess")));
  1313. }
  1314. item->add_button(1, get_editor_theme_icon(SNAME("Folder")));
  1315. }
  1316. save_path_items.push_back(item);
  1317. }
  1318. external_paths->set_title(TTR("Set paths to save animations as resource files on Reimport"));
  1319. external_paths->set_ok_button_text(TTR("Set Paths"));
  1320. } break;
  1321. }
  1322. external_paths->popup_centered_ratio();
  1323. }
  1324. void SceneImportSettingsDialog::_save_dir_confirm() {
  1325. for (int i = 0; i < save_path_items.size(); i++) {
  1326. TreeItem *item = save_path_items[i];
  1327. if (!item->is_checked(0)) {
  1328. continue; //ignore
  1329. }
  1330. String path = item->get_text(1);
  1331. if (!path.is_resource_file()) {
  1332. continue;
  1333. }
  1334. String id = item->get_metadata(0);
  1335. switch (current_action) {
  1336. case ACTION_EXTRACT_MATERIALS: {
  1337. ERR_CONTINUE(!material_map.has(id));
  1338. MaterialData &md = material_map[id];
  1339. Error err = ResourceSaver::save(md.material, path);
  1340. if (err != OK) {
  1341. EditorNode::get_singleton()->add_io_error(TTR("Can't make material external to file, write error:") + "\n\t" + path);
  1342. continue;
  1343. }
  1344. md.settings["use_external/enabled"] = true;
  1345. md.settings["use_external/path"] = path;
  1346. } break;
  1347. case ACTION_CHOOSE_MESH_SAVE_PATHS: {
  1348. ERR_CONTINUE(!mesh_map.has(id));
  1349. MeshData &md = mesh_map[id];
  1350. md.settings["save_to_file/enabled"] = true;
  1351. md.settings["save_to_file/path"] = path;
  1352. } break;
  1353. case ACTION_CHOOSE_ANIMATION_SAVE_PATHS: {
  1354. ERR_CONTINUE(!animation_map.has(id));
  1355. AnimationData &ad = animation_map[id];
  1356. ad.settings["save_to_file/enabled"] = true;
  1357. ad.settings["save_to_file/path"] = path;
  1358. } break;
  1359. }
  1360. }
  1361. if (current_action == ACTION_EXTRACT_MATERIALS) {
  1362. //as this happens right now, the scene needs to be saved and reimported.
  1363. _re_import();
  1364. open_settings(base_path);
  1365. } else {
  1366. scene_import_settings_data->notify_property_list_changed();
  1367. }
  1368. }
  1369. SceneImportSettingsDialog::SceneImportSettingsDialog() {
  1370. singleton = this;
  1371. VBoxContainer *main_vb = memnew(VBoxContainer);
  1372. add_child(main_vb);
  1373. HBoxContainer *menu_hb = memnew(HBoxContainer);
  1374. main_vb->add_child(menu_hb);
  1375. action_menu = memnew(MenuButton);
  1376. action_menu->set_text(TTR("Actions..."));
  1377. // Style the MenuButton like a regular Button to make it more noticeable.
  1378. action_menu->set_flat(false);
  1379. action_menu->set_focus_mode(Control::FOCUS_ALL);
  1380. menu_hb->add_child(action_menu);
  1381. action_menu->get_popup()->add_item(TTR("Extract Materials"), ACTION_EXTRACT_MATERIALS);
  1382. action_menu->get_popup()->add_separator();
  1383. action_menu->get_popup()->add_item(TTR("Set Animation Save Paths"), ACTION_CHOOSE_ANIMATION_SAVE_PATHS);
  1384. action_menu->get_popup()->add_item(TTR("Set Mesh Save Paths"), ACTION_CHOOSE_MESH_SAVE_PATHS);
  1385. action_menu->get_popup()->connect(SceneStringName(id_pressed), callable_mp(this, &SceneImportSettingsDialog::_menu_callback));
  1386. tree_split = memnew(HSplitContainer);
  1387. main_vb->add_child(tree_split);
  1388. tree_split->set_v_size_flags(Control::SIZE_EXPAND_FILL);
  1389. data_mode = memnew(TabContainer);
  1390. tree_split->add_child(data_mode);
  1391. data_mode->set_custom_minimum_size(Size2(300 * EDSCALE, 0));
  1392. data_mode->set_theme_type_variation("TabContainerOdd");
  1393. property_split = memnew(HSplitContainer);
  1394. tree_split->add_child(property_split);
  1395. property_split->set_h_size_flags(Control::SIZE_EXPAND_FILL);
  1396. scene_tree = memnew(Tree);
  1397. scene_tree->set_name(TTR("Scene"));
  1398. scene_tree->set_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED);
  1399. data_mode->add_child(scene_tree);
  1400. scene_tree->connect("cell_selected", callable_mp(this, &SceneImportSettingsDialog::_scene_tree_selected));
  1401. mesh_tree = memnew(Tree);
  1402. mesh_tree->set_name(TTR("Meshes"));
  1403. mesh_tree->set_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED);
  1404. data_mode->add_child(mesh_tree);
  1405. mesh_tree->set_hide_root(true);
  1406. mesh_tree->connect("cell_selected", callable_mp(this, &SceneImportSettingsDialog::_mesh_tree_selected));
  1407. material_tree = memnew(Tree);
  1408. material_tree->set_name(TTR("Materials"));
  1409. material_tree->set_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED);
  1410. data_mode->add_child(material_tree);
  1411. material_tree->connect("cell_selected", callable_mp(this, &SceneImportSettingsDialog::_material_tree_selected));
  1412. material_tree->set_hide_root(true);
  1413. VBoxContainer *vp_vb = memnew(VBoxContainer);
  1414. vp_vb->set_h_size_flags(Control::SIZE_EXPAND_FILL);
  1415. vp_vb->set_v_size_flags(Control::SIZE_EXPAND_FILL);
  1416. vp_vb->set_anchors_and_offsets_preset(Control::LayoutPreset::PRESET_FULL_RECT);
  1417. property_split->add_child(vp_vb);
  1418. SubViewportContainer *vp_container = memnew(SubViewportContainer);
  1419. vp_container->set_v_size_flags(Control::SIZE_EXPAND_FILL);
  1420. vp_container->set_custom_minimum_size(Size2(10, 10));
  1421. vp_container->set_stretch(true);
  1422. vp_container->connect(SceneStringName(gui_input), callable_mp(this, &SceneImportSettingsDialog::_viewport_input));
  1423. vp_vb->add_child(vp_container);
  1424. base_viewport = memnew(SubViewport);
  1425. vp_container->add_child(base_viewport);
  1426. animation_preview = memnew(PanelContainer);
  1427. animation_preview->set_h_size_flags(Control::SIZE_EXPAND_FILL);
  1428. vp_vb->add_child(animation_preview);
  1429. animation_preview->hide();
  1430. HBoxContainer *animation_hbox = memnew(HBoxContainer);
  1431. animation_preview->add_child(animation_hbox);
  1432. animation_play_button = memnew(Button);
  1433. animation_hbox->add_child(animation_play_button);
  1434. animation_play_button->set_flat(true);
  1435. animation_play_button->set_focus_mode(Control::FOCUS_NONE);
  1436. animation_play_button->set_shortcut(ED_SHORTCUT("scene_import_settings/play_selected_animation", TTR("Selected Animation Play/Pause"), Key::SPACE));
  1437. animation_play_button->connect(SceneStringName(pressed), callable_mp(this, &SceneImportSettingsDialog::_play_animation));
  1438. animation_stop_button = memnew(Button);
  1439. animation_hbox->add_child(animation_stop_button);
  1440. animation_stop_button->set_flat(true);
  1441. animation_stop_button->set_focus_mode(Control::FOCUS_NONE);
  1442. animation_stop_button->set_tooltip_text(TTR("Selected Animation Stop"));
  1443. animation_stop_button->connect(SceneStringName(pressed), callable_mp(this, &SceneImportSettingsDialog::_stop_current_animation));
  1444. animation_slider = memnew(HSlider);
  1445. animation_hbox->add_child(animation_slider);
  1446. animation_slider->set_h_size_flags(Control::SIZE_EXPAND_FILL);
  1447. animation_slider->set_v_size_flags(Control::SIZE_EXPAND_FILL);
  1448. animation_slider->set_max(1.0);
  1449. animation_slider->set_step(1.0 / 100.0);
  1450. animation_slider->set_value_no_signal(0.0);
  1451. animation_slider->set_focus_mode(Control::FOCUS_NONE);
  1452. animation_slider->connect(SceneStringName(value_changed), callable_mp(this, &SceneImportSettingsDialog::_animation_slider_value_changed));
  1453. animation_toggle_skeleton_visibility = memnew(Button);
  1454. animation_hbox->add_child(animation_toggle_skeleton_visibility);
  1455. animation_toggle_skeleton_visibility->set_toggle_mode(true);
  1456. animation_toggle_skeleton_visibility->set_flat(true);
  1457. animation_toggle_skeleton_visibility->set_focus_mode(Control::FOCUS_NONE);
  1458. animation_toggle_skeleton_visibility->set_tooltip_text(TTR("Toggle Animation Skeleton Visibility"));
  1459. animation_toggle_skeleton_visibility->connect(SceneStringName(pressed), callable_mp(this, &SceneImportSettingsDialog::_animation_update_skeleton_visibility));
  1460. base_viewport->set_use_own_world_3d(true);
  1461. HBoxContainer *viewport_hbox = memnew(HBoxContainer);
  1462. vp_container->add_child(viewport_hbox);
  1463. viewport_hbox->set_anchors_and_offsets_preset(Control::PRESET_FULL_RECT, Control::PRESET_MODE_MINSIZE, 2);
  1464. viewport_hbox->add_spacer();
  1465. VBoxContainer *vb_light = memnew(VBoxContainer);
  1466. vb_light->set_v_size_flags(Control::SIZE_EXPAND_FILL);
  1467. viewport_hbox->add_child(vb_light);
  1468. light_rotate_switch = memnew(Button);
  1469. light_rotate_switch->set_theme_type_variation("PreviewLightButton");
  1470. light_rotate_switch->set_toggle_mode(true);
  1471. light_rotate_switch->set_pressed(true);
  1472. light_rotate_switch->set_tooltip_text(TTR("Rotate Lights With Model"));
  1473. light_rotate_switch->connect(SceneStringName(pressed), callable_mp(this, &SceneImportSettingsDialog::_on_light_rotate_switch_pressed));
  1474. vb_light->add_child(light_rotate_switch);
  1475. light_1_switch = memnew(Button);
  1476. light_1_switch->set_theme_type_variation("PreviewLightButton");
  1477. light_1_switch->set_toggle_mode(true);
  1478. light_1_switch->set_pressed(true);
  1479. light_1_switch->set_tooltip_text(TTR("Primary Light"));
  1480. light_1_switch->connect(SceneStringName(pressed), callable_mp(this, &SceneImportSettingsDialog::_on_light_1_switch_pressed));
  1481. vb_light->add_child(light_1_switch);
  1482. light_2_switch = memnew(Button);
  1483. light_2_switch->set_theme_type_variation("PreviewLightButton");
  1484. light_2_switch->set_toggle_mode(true);
  1485. light_2_switch->set_pressed(true);
  1486. light_2_switch->set_tooltip_text(TTR("Secondary Light"));
  1487. light_2_switch->connect(SceneStringName(pressed), callable_mp(this, &SceneImportSettingsDialog::_on_light_2_switch_pressed));
  1488. vb_light->add_child(light_2_switch);
  1489. camera = memnew(Camera3D);
  1490. base_viewport->add_child(camera);
  1491. camera->make_current();
  1492. if (GLOBAL_GET("rendering/lights_and_shadows/use_physical_light_units")) {
  1493. camera_attributes.instantiate();
  1494. camera->set_attributes(camera_attributes);
  1495. }
  1496. // Use a grayscale gradient sky to avoid skewing the preview towards a specific color,
  1497. // but still allow shaded areas to be easily distinguished (using the ambient and reflected light).
  1498. // This also helps the user orient themselves in the preview, since the bottom of the sky is black
  1499. // and the top of the sky is white.
  1500. procedural_sky_material.instantiate();
  1501. procedural_sky_material->set_sky_top_color(Color(1, 1, 1));
  1502. procedural_sky_material->set_sky_horizon_color(Color(0.5, 0.5, 0.5));
  1503. procedural_sky_material->set_ground_horizon_color(Color(0.5, 0.5, 0.5));
  1504. procedural_sky_material->set_ground_bottom_color(Color(0, 0, 0));
  1505. procedural_sky_material->set_sky_curve(2.0);
  1506. procedural_sky_material->set_ground_curve(0.5);
  1507. // Hide the sun from the sky.
  1508. procedural_sky_material->set_sun_angle_max(0.0);
  1509. sky.instantiate();
  1510. sky->set_material(procedural_sky_material);
  1511. environment.instantiate();
  1512. environment->set_background(Environment::BG_SKY);
  1513. environment->set_sky(sky);
  1514. // A custom FOV must be specified, as an orthogonal camera is used for the preview.
  1515. environment->set_sky_custom_fov(50.0);
  1516. camera->set_environment(environment);
  1517. light1 = memnew(DirectionalLight3D);
  1518. light1->set_transform(Transform3D(Basis::looking_at(Vector3(-1, -1, -1))));
  1519. light1->set_shadow(true);
  1520. camera->add_child(light1);
  1521. light2 = memnew(DirectionalLight3D);
  1522. light2->set_transform(Transform3D(Basis::looking_at(Vector3(0, 1, 0), Vector3(0, 0, 1))));
  1523. light2->set_color(Color(0.5f, 0.5f, 0.5f));
  1524. camera->add_child(light2);
  1525. {
  1526. Ref<StandardMaterial3D> selection_mat;
  1527. selection_mat.instantiate();
  1528. selection_mat->set_shading_mode(StandardMaterial3D::SHADING_MODE_UNSHADED);
  1529. selection_mat->set_flag(StandardMaterial3D::FLAG_DISABLE_FOG, true);
  1530. selection_mat->set_albedo(Color(1, 0.8, 1.0));
  1531. Ref<SurfaceTool> st;
  1532. st.instantiate();
  1533. st->begin(Mesh::PRIMITIVE_LINES);
  1534. AABB base_aabb;
  1535. base_aabb.size = Vector3(1, 1, 1);
  1536. for (int i = 0; i < 12; i++) {
  1537. Vector3 a, b;
  1538. base_aabb.get_edge(i, a, b);
  1539. st->add_vertex(a);
  1540. st->add_vertex(a.lerp(b, 0.2));
  1541. st->add_vertex(b);
  1542. st->add_vertex(b.lerp(a, 0.2));
  1543. }
  1544. selection_mesh.instantiate();
  1545. st->commit(selection_mesh);
  1546. selection_mesh->surface_set_material(0, selection_mat);
  1547. node_selected = memnew(MeshInstance3D);
  1548. node_selected->set_mesh(selection_mesh);
  1549. node_selected->set_cast_shadows_setting(GeometryInstance3D::SHADOW_CASTING_SETTING_OFF);
  1550. base_viewport->add_child(node_selected);
  1551. node_selected->hide();
  1552. }
  1553. {
  1554. mesh_preview = memnew(MeshInstance3D);
  1555. base_viewport->add_child(mesh_preview);
  1556. mesh_preview->hide();
  1557. material_preview.instantiate();
  1558. }
  1559. {
  1560. collider_mat.instantiate();
  1561. collider_mat->set_shading_mode(StandardMaterial3D::SHADING_MODE_UNSHADED);
  1562. collider_mat->set_flag(StandardMaterial3D::FLAG_DISABLE_FOG, true);
  1563. collider_mat->set_albedo(Color(0.5, 0.5, 1.0));
  1564. }
  1565. {
  1566. bones_mesh_preview = memnew(MeshInstance3D);
  1567. bones_mesh_preview->set_cast_shadows_setting(GeometryInstance3D::SHADOW_CASTING_SETTING_OFF);
  1568. bones_mesh_preview->set_skeleton_path(NodePath());
  1569. base_viewport->add_child(bones_mesh_preview);
  1570. }
  1571. inspector = memnew(EditorInspector);
  1572. inspector->set_custom_minimum_size(Size2(300 * EDSCALE, 0));
  1573. inspector->connect(SNAME("property_edited"), callable_mp(this, &SceneImportSettingsDialog::_inspector_property_edited));
  1574. property_split->add_child(inspector);
  1575. scene_import_settings_data = memnew(SceneImportSettingsData);
  1576. set_ok_button_text(TTR("Reimport"));
  1577. set_cancel_button_text(TTR("Close"));
  1578. external_paths = memnew(ConfirmationDialog);
  1579. add_child(external_paths);
  1580. external_path_tree = memnew(Tree);
  1581. external_paths->add_child(external_path_tree);
  1582. external_path_tree->connect("button_clicked", callable_mp(this, &SceneImportSettingsDialog::_browse_save_callback));
  1583. external_paths->connect(SceneStringName(confirmed), callable_mp(this, &SceneImportSettingsDialog::_save_dir_confirm));
  1584. external_path_tree->set_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED);
  1585. external_path_tree->set_columns(3);
  1586. external_path_tree->set_column_titles_visible(true);
  1587. external_path_tree->set_column_expand(0, true);
  1588. external_path_tree->set_column_custom_minimum_width(0, 100 * EDSCALE);
  1589. external_path_tree->set_column_title(0, TTR("Resource"));
  1590. external_path_tree->set_column_expand(1, true);
  1591. external_path_tree->set_column_custom_minimum_width(1, 100 * EDSCALE);
  1592. external_path_tree->set_column_title(1, TTR("Path"));
  1593. external_path_tree->set_column_expand(2, false);
  1594. external_path_tree->set_column_custom_minimum_width(2, 200 * EDSCALE);
  1595. external_path_tree->set_column_title(2, TTR("Status"));
  1596. save_path = memnew(EditorFileDialog);
  1597. save_path->set_file_mode(EditorFileDialog::FILE_MODE_OPEN_DIR);
  1598. HBoxContainer *extension_hb = memnew(HBoxContainer);
  1599. save_path->get_vbox()->add_child(extension_hb);
  1600. extension_hb->add_spacer();
  1601. extension_hb->add_child(memnew(Label(TTR("Save Extension:"))));
  1602. external_extension_type = memnew(OptionButton);
  1603. extension_hb->add_child(external_extension_type);
  1604. external_extension_type->add_item(TTR("Text: *.tres"));
  1605. external_extension_type->add_item(TTR("Binary: *.res"));
  1606. external_path_tree->set_hide_root(true);
  1607. add_child(save_path);
  1608. item_save_path = memnew(EditorFileDialog);
  1609. item_save_path->set_file_mode(EditorFileDialog::FILE_MODE_SAVE_FILE);
  1610. item_save_path->add_filter("*.tres", TTR("Text Resource"));
  1611. item_save_path->add_filter("*.res", TTR("Binary Resource"));
  1612. add_child(item_save_path);
  1613. item_save_path->connect("file_selected", callable_mp(this, &SceneImportSettingsDialog::_save_path_changed));
  1614. save_path->connect("dir_selected", callable_mp(this, &SceneImportSettingsDialog::_save_dir_callback));
  1615. update_view_timer = memnew(Timer);
  1616. update_view_timer->set_wait_time(0.2);
  1617. update_view_timer->connect("timeout", callable_mp(this, &SceneImportSettingsDialog::_update_view_gizmos));
  1618. add_child(update_view_timer);
  1619. }
  1620. SceneImportSettingsDialog::~SceneImportSettingsDialog() {
  1621. memdelete(scene_import_settings_data);
  1622. }