scene_import_settings.cpp 63 KB

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