scene_import_settings.cpp 48 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466
  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_dialog.h"
  33. #include "editor/editor_file_system.h"
  34. #include "editor/editor_inspector.h"
  35. #include "editor/editor_node.h"
  36. #include "editor/editor_scale.h"
  37. #include "editor/editor_settings.h"
  38. #include "scene/3d/importer_mesh_instance_3d.h"
  39. #include "scene/animation/animation_player.h"
  40. #include "scene/resources/importer_mesh.h"
  41. #include "scene/resources/surface_tool.h"
  42. class SceneImportSettingsData : public Object {
  43. GDCLASS(SceneImportSettingsData, Object)
  44. friend class SceneImportSettings;
  45. HashMap<StringName, Variant> *settings = nullptr;
  46. HashMap<StringName, Variant> current;
  47. HashMap<StringName, Variant> defaults;
  48. List<ResourceImporter::ImportOption> options;
  49. bool hide_options = false;
  50. String path;
  51. ResourceImporterScene::InternalImportCategory category = ResourceImporterScene::INTERNAL_IMPORT_CATEGORY_MAX;
  52. bool _set(const StringName &p_name, const Variant &p_value) {
  53. if (settings) {
  54. if (defaults.has(p_name) && defaults[p_name] == p_value) {
  55. settings->erase(p_name);
  56. } else {
  57. (*settings)[p_name] = p_value;
  58. }
  59. current[p_name] = p_value;
  60. // SceneImportSettings must decide if a new collider should be generated or not
  61. if (category == ResourceImporterScene::INTERNAL_IMPORT_CATEGORY_MESH_3D_NODE) {
  62. SceneImportSettings::get_singleton()->request_generate_collider();
  63. }
  64. if (SceneImportSettings::get_singleton()->is_editing_animation()) {
  65. if (category == ResourceImporterScene::INTERNAL_IMPORT_CATEGORY_MAX) {
  66. if (ResourceImporterScene::get_animation_singleton()->get_option_visibility(path, p_name, current)) {
  67. SceneImportSettings::get_singleton()->update_view();
  68. }
  69. } else {
  70. if (ResourceImporterScene::get_animation_singleton()->get_internal_option_update_view_required(category, p_name, current)) {
  71. SceneImportSettings::get_singleton()->update_view();
  72. }
  73. }
  74. } else {
  75. if (category == ResourceImporterScene::INTERNAL_IMPORT_CATEGORY_MAX) {
  76. if (ResourceImporterScene::get_scene_singleton()->get_option_visibility(path, p_name, current)) {
  77. SceneImportSettings::get_singleton()->update_view();
  78. }
  79. } else {
  80. if (ResourceImporterScene::get_scene_singleton()->get_internal_option_update_view_required(category, p_name, current)) {
  81. SceneImportSettings::get_singleton()->update_view();
  82. }
  83. }
  84. }
  85. return true;
  86. }
  87. return false;
  88. }
  89. bool _get(const StringName &p_name, Variant &r_ret) const {
  90. if (settings) {
  91. if (settings->has(p_name)) {
  92. r_ret = (*settings)[p_name];
  93. return true;
  94. }
  95. }
  96. if (defaults.has(p_name)) {
  97. r_ret = defaults[p_name];
  98. return true;
  99. }
  100. return false;
  101. }
  102. void _get_property_list(List<PropertyInfo> *p_list) const {
  103. if (hide_options) {
  104. return;
  105. }
  106. for (const ResourceImporter::ImportOption &E : options) {
  107. if (SceneImportSettings::get_singleton()->is_editing_animation()) {
  108. if (category == ResourceImporterScene::INTERNAL_IMPORT_CATEGORY_MAX) {
  109. if (ResourceImporterScene::get_animation_singleton()->get_option_visibility(path, E.option.name, current)) {
  110. p_list->push_back(E.option);
  111. }
  112. } else {
  113. if (ResourceImporterScene::get_animation_singleton()->get_internal_option_visibility(category, E.option.name, current)) {
  114. p_list->push_back(E.option);
  115. }
  116. }
  117. } else {
  118. if (category == ResourceImporterScene::INTERNAL_IMPORT_CATEGORY_MAX) {
  119. if (ResourceImporterScene::get_scene_singleton()->get_option_visibility(path, E.option.name, current)) {
  120. p_list->push_back(E.option);
  121. }
  122. } else {
  123. if (ResourceImporterScene::get_scene_singleton()->get_internal_option_visibility(category, E.option.name, current)) {
  124. p_list->push_back(E.option);
  125. }
  126. }
  127. }
  128. }
  129. }
  130. };
  131. void SceneImportSettings::_fill_material(Tree *p_tree, const Ref<Material> &p_material, TreeItem *p_parent) {
  132. String import_id;
  133. bool has_import_id = false;
  134. if (p_material->has_meta("import_id")) {
  135. import_id = p_material->get_meta("import_id");
  136. has_import_id = true;
  137. } else if (!p_material->get_name().is_empty()) {
  138. import_id = p_material->get_name();
  139. has_import_id = true;
  140. } else if (unnamed_material_name_map.has(p_material)) {
  141. import_id = unnamed_material_name_map[p_material];
  142. } else {
  143. import_id = "@MATERIAL:" + itos(material_map.size());
  144. unnamed_material_name_map[p_material] = import_id;
  145. }
  146. bool created = false;
  147. if (!material_map.has(import_id)) {
  148. MaterialData md;
  149. created = true;
  150. md.has_import_id = has_import_id;
  151. md.material = p_material;
  152. _load_default_subresource_settings(md.settings, "materials", import_id, ResourceImporterScene::INTERNAL_IMPORT_CATEGORY_MATERIAL);
  153. material_map[import_id] = md;
  154. }
  155. MaterialData &material_data = material_map[import_id];
  156. ERR_FAIL_COND(p_material != material_data.material);
  157. Ref<Texture2D> icon = get_theme_icon(SNAME("StandardMaterial3D"), SNAME("EditorIcons"));
  158. TreeItem *item = p_tree->create_item(p_parent);
  159. if (p_material->get_name().is_empty()) {
  160. item->set_text(0, TTR("<Unnamed Material>"));
  161. } else {
  162. item->set_text(0, p_material->get_name());
  163. }
  164. item->set_icon(0, icon);
  165. item->set_meta("type", "Material");
  166. item->set_meta("import_id", import_id);
  167. item->set_tooltip_text(0, vformat(TTR("Import ID: %s"), import_id));
  168. item->set_selectable(0, true);
  169. if (p_tree == scene_tree) {
  170. material_data.scene_node = item;
  171. } else if (p_tree == mesh_tree) {
  172. material_data.mesh_node = item;
  173. } else {
  174. material_data.material_node = item;
  175. }
  176. if (created) {
  177. _fill_material(material_tree, p_material, material_tree->get_root());
  178. }
  179. }
  180. void SceneImportSettings::_fill_mesh(Tree *p_tree, const Ref<Mesh> &p_mesh, TreeItem *p_parent) {
  181. String import_id;
  182. bool has_import_id = false;
  183. if (p_mesh->has_meta("import_id")) {
  184. import_id = p_mesh->get_meta("import_id");
  185. has_import_id = true;
  186. } else if (!p_mesh->get_name().is_empty()) {
  187. import_id = p_mesh->get_name();
  188. has_import_id = true;
  189. } else {
  190. import_id = "@MESH:" + itos(mesh_set.size());
  191. }
  192. if (!mesh_map.has(import_id)) {
  193. MeshData md;
  194. md.has_import_id = has_import_id;
  195. md.mesh = p_mesh;
  196. _load_default_subresource_settings(md.settings, "meshes", import_id, ResourceImporterScene::INTERNAL_IMPORT_CATEGORY_MESH);
  197. mesh_map[import_id] = md;
  198. }
  199. MeshData &mesh_data = mesh_map[import_id];
  200. Ref<Texture2D> icon = get_theme_icon(SNAME("Mesh"), SNAME("EditorIcons"));
  201. TreeItem *item = p_tree->create_item(p_parent);
  202. item->set_text(0, p_mesh->get_name());
  203. item->set_icon(0, icon);
  204. bool created = false;
  205. if (!mesh_set.has(p_mesh)) {
  206. mesh_set.insert(p_mesh);
  207. created = true;
  208. }
  209. item->set_meta("type", "Mesh");
  210. item->set_meta("import_id", import_id);
  211. item->set_tooltip_text(0, vformat(TTR("Import ID: %s"), import_id));
  212. item->set_selectable(0, true);
  213. if (p_tree == scene_tree) {
  214. mesh_data.scene_node = item;
  215. } else {
  216. mesh_data.mesh_node = item;
  217. }
  218. item->set_collapsed(true);
  219. for (int i = 0; i < p_mesh->get_surface_count(); i++) {
  220. Ref<Material> mat = p_mesh->surface_get_material(i);
  221. if (mat.is_valid()) {
  222. _fill_material(p_tree, mat, item);
  223. }
  224. }
  225. if (created) {
  226. _fill_mesh(mesh_tree, p_mesh, mesh_tree->get_root());
  227. }
  228. }
  229. void SceneImportSettings::_fill_animation(Tree *p_tree, const Ref<Animation> &p_anim, const String &p_name, TreeItem *p_parent) {
  230. if (!animation_map.has(p_name)) {
  231. AnimationData ad;
  232. ad.animation = p_anim;
  233. _load_default_subresource_settings(ad.settings, "animations", p_name, ResourceImporterScene::INTERNAL_IMPORT_CATEGORY_ANIMATION);
  234. animation_map[p_name] = ad;
  235. }
  236. AnimationData &animation_data = animation_map[p_name];
  237. Ref<Texture2D> icon = get_theme_icon(SNAME("Animation"), SNAME("EditorIcons"));
  238. TreeItem *item = p_tree->create_item(p_parent);
  239. item->set_text(0, p_name);
  240. item->set_icon(0, icon);
  241. item->set_meta("type", "Animation");
  242. item->set_meta("import_id", p_name);
  243. item->set_selectable(0, true);
  244. animation_data.scene_node = item;
  245. }
  246. void SceneImportSettings::_fill_scene(Node *p_node, TreeItem *p_parent_item) {
  247. String import_id;
  248. if (p_node->has_meta("import_id")) {
  249. import_id = p_node->get_meta("import_id");
  250. } else {
  251. import_id = "PATH:" + String(scene->get_path_to(p_node));
  252. p_node->set_meta("import_id", import_id);
  253. }
  254. ImporterMeshInstance3D *src_mesh_node = Object::cast_to<ImporterMeshInstance3D>(p_node);
  255. if (src_mesh_node) {
  256. MeshInstance3D *mesh_node = memnew(MeshInstance3D);
  257. mesh_node->set_name(src_mesh_node->get_name());
  258. mesh_node->set_transform(src_mesh_node->get_transform());
  259. mesh_node->set_skin(src_mesh_node->get_skin());
  260. mesh_node->set_skeleton_path(src_mesh_node->get_skeleton_path());
  261. if (src_mesh_node->get_mesh().is_valid()) {
  262. Ref<ImporterMesh> editor_mesh = src_mesh_node->get_mesh();
  263. mesh_node->set_mesh(editor_mesh->get_mesh());
  264. }
  265. p_node->replace_by(mesh_node);
  266. memdelete(p_node);
  267. p_node = mesh_node;
  268. }
  269. String type = p_node->get_class();
  270. if (!has_theme_icon(type, SNAME("EditorIcons"))) {
  271. type = "Node3D";
  272. }
  273. Ref<Texture2D> icon = get_theme_icon(type, SNAME("EditorIcons"));
  274. TreeItem *item = scene_tree->create_item(p_parent_item);
  275. item->set_text(0, p_node->get_name());
  276. if (p_node == scene) {
  277. icon = get_theme_icon(SNAME("PackedScene"), SNAME("EditorIcons"));
  278. item->set_text(0, TTR("Scene"));
  279. }
  280. item->set_icon(0, icon);
  281. item->set_meta("type", "Node");
  282. item->set_meta("class", type);
  283. item->set_meta("import_id", import_id);
  284. item->set_tooltip_text(0, vformat(TTR("Type: %s\nImport ID: %s"), type, import_id));
  285. item->set_selectable(0, true);
  286. if (!node_map.has(import_id)) {
  287. NodeData nd;
  288. if (p_node != scene) {
  289. ResourceImporterScene::InternalImportCategory category;
  290. if (src_mesh_node) {
  291. category = ResourceImporterScene::INTERNAL_IMPORT_CATEGORY_MESH_3D_NODE;
  292. } else if (Object::cast_to<AnimationPlayer>(p_node)) {
  293. category = ResourceImporterScene::INTERNAL_IMPORT_CATEGORY_ANIMATION_NODE;
  294. } else if (Object::cast_to<Skeleton3D>(p_node)) {
  295. category = ResourceImporterScene::INTERNAL_IMPORT_CATEGORY_SKELETON_3D_NODE;
  296. } else {
  297. category = ResourceImporterScene::INTERNAL_IMPORT_CATEGORY_NODE;
  298. }
  299. _load_default_subresource_settings(nd.settings, "nodes", import_id, category);
  300. }
  301. node_map[import_id] = nd;
  302. }
  303. NodeData &node_data = node_map[import_id];
  304. node_data.node = p_node;
  305. node_data.scene_node = item;
  306. AnimationPlayer *anim_node = Object::cast_to<AnimationPlayer>(p_node);
  307. if (anim_node) {
  308. List<StringName> animations;
  309. anim_node->get_animation_list(&animations);
  310. for (const StringName &E : animations) {
  311. _fill_animation(scene_tree, anim_node->get_animation(E), E, item);
  312. }
  313. }
  314. for (int i = 0; i < p_node->get_child_count(); i++) {
  315. _fill_scene(p_node->get_child(i), item);
  316. }
  317. MeshInstance3D *mesh_node = Object::cast_to<MeshInstance3D>(p_node);
  318. if (mesh_node && mesh_node->get_mesh().is_valid()) {
  319. if (!editing_animation) {
  320. _fill_mesh(scene_tree, mesh_node->get_mesh(), item);
  321. }
  322. // Add the collider view.
  323. MeshInstance3D *collider_view = memnew(MeshInstance3D);
  324. collider_view->set_name("collider_view");
  325. collider_view->set_visible(false);
  326. mesh_node->add_child(collider_view, true);
  327. collider_view->set_owner(mesh_node);
  328. Transform3D accum_xform;
  329. Node3D *base = mesh_node;
  330. while (base) {
  331. accum_xform = base->get_transform() * accum_xform;
  332. base = Object::cast_to<Node3D>(base->get_parent());
  333. }
  334. AABB aabb = accum_xform.xform(mesh_node->get_mesh()->get_aabb());
  335. if (first_aabb) {
  336. contents_aabb = aabb;
  337. first_aabb = false;
  338. } else {
  339. contents_aabb.merge_with(aabb);
  340. }
  341. }
  342. }
  343. void SceneImportSettings::_update_scene() {
  344. scene_tree->clear();
  345. material_tree->clear();
  346. mesh_tree->clear();
  347. //hidden roots
  348. material_tree->create_item();
  349. mesh_tree->create_item();
  350. _fill_scene(scene, nullptr);
  351. }
  352. void SceneImportSettings::_update_view_gizmos() {
  353. if (!is_visible()) {
  354. return;
  355. }
  356. for (const KeyValue<String, NodeData> &e : node_map) {
  357. bool show_collider_view = false;
  358. if (e.value.settings.has(SNAME("generate/physics"))) {
  359. show_collider_view = e.value.settings[SNAME("generate/physics")];
  360. }
  361. MeshInstance3D *mesh_node = Object::cast_to<MeshInstance3D>(e.value.node);
  362. if (mesh_node == nullptr || mesh_node->get_mesh().is_null()) {
  363. // Nothing to do
  364. continue;
  365. }
  366. TypedArray<Node> descendants = mesh_node->find_children("collider_view", "MeshInstance3D");
  367. 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`.");
  368. MeshInstance3D *collider_view = static_cast<MeshInstance3D *>(descendants[0].operator Object *());
  369. collider_view->set_visible(show_collider_view);
  370. if (generate_collider) {
  371. // This collider_view doesn't have a mesh so we need to generate a new one.
  372. Ref<ImporterMesh> mesh;
  373. mesh.instantiate();
  374. // ResourceImporterScene::get_collision_shapes() expects ImporterMesh, not Mesh.
  375. // TODO: Duplicate code with EditorSceneFormatImporterESCN::import_scene()
  376. // Consider making a utility function to convert from Mesh to ImporterMesh.
  377. Ref<Mesh> mesh_3d_mesh = mesh_node->get_mesh();
  378. Ref<ArrayMesh> array_mesh_3d_mesh = mesh_3d_mesh;
  379. if (array_mesh_3d_mesh.is_valid()) {
  380. // For the MeshInstance3D nodes, we need to convert the ArrayMesh to an ImporterMesh specially.
  381. mesh->set_name(array_mesh_3d_mesh->get_name());
  382. for (int32_t blend_i = 0; blend_i < array_mesh_3d_mesh->get_blend_shape_count(); blend_i++) {
  383. mesh->add_blend_shape(array_mesh_3d_mesh->get_blend_shape_name(blend_i));
  384. }
  385. for (int32_t surface_i = 0; surface_i < array_mesh_3d_mesh->get_surface_count(); surface_i++) {
  386. mesh->add_surface(array_mesh_3d_mesh->surface_get_primitive_type(surface_i),
  387. array_mesh_3d_mesh->surface_get_arrays(surface_i),
  388. array_mesh_3d_mesh->surface_get_blend_shape_arrays(surface_i),
  389. array_mesh_3d_mesh->surface_get_lods(surface_i),
  390. array_mesh_3d_mesh->surface_get_material(surface_i),
  391. array_mesh_3d_mesh->surface_get_name(surface_i),
  392. array_mesh_3d_mesh->surface_get_format(surface_i));
  393. }
  394. mesh->set_blend_shape_mode(array_mesh_3d_mesh->get_blend_shape_mode());
  395. } else if (mesh_3d_mesh.is_valid()) {
  396. // For the MeshInstance3D nodes, we need to convert the Mesh to an ImporterMesh specially.
  397. mesh->set_name(mesh_3d_mesh->get_name());
  398. for (int32_t surface_i = 0; surface_i < mesh_3d_mesh->get_surface_count(); surface_i++) {
  399. mesh->add_surface(mesh_3d_mesh->surface_get_primitive_type(surface_i),
  400. mesh_3d_mesh->surface_get_arrays(surface_i),
  401. Array(),
  402. mesh_3d_mesh->surface_get_lods(surface_i),
  403. mesh_3d_mesh->surface_get_material(surface_i),
  404. mesh_3d_mesh->surface_get_material(surface_i).is_valid() ? mesh_3d_mesh->surface_get_material(surface_i)->get_name() : String(),
  405. mesh_3d_mesh->surface_get_format(surface_i));
  406. }
  407. }
  408. // Generate the mesh collider.
  409. Vector<Ref<Shape3D>> shapes = ResourceImporterScene::get_collision_shapes(mesh, e.value.settings, 1.0);
  410. const Transform3D transform = ResourceImporterScene::get_collision_shapes_transform(e.value.settings);
  411. Ref<ArrayMesh> collider_view_mesh;
  412. collider_view_mesh.instantiate();
  413. for (Ref<Shape3D> shape : shapes) {
  414. Ref<ArrayMesh> debug_shape_mesh;
  415. if (shape.is_valid()) {
  416. debug_shape_mesh = shape->get_debug_mesh();
  417. }
  418. if (debug_shape_mesh.is_valid()) {
  419. collider_view_mesh->add_surface_from_arrays(
  420. debug_shape_mesh->surface_get_primitive_type(0),
  421. debug_shape_mesh->surface_get_arrays(0));
  422. collider_view_mesh->surface_set_material(
  423. collider_view_mesh->get_surface_count() - 1,
  424. collider_mat);
  425. }
  426. }
  427. collider_view->set_mesh(collider_view_mesh);
  428. collider_view->set_transform(transform);
  429. }
  430. }
  431. generate_collider = false;
  432. }
  433. void SceneImportSettings::_update_camera() {
  434. AABB camera_aabb;
  435. float rot_x = cam_rot_x;
  436. float rot_y = cam_rot_y;
  437. float zoom = cam_zoom;
  438. if (selected_type == "Node" || selected_type.is_empty()) {
  439. camera_aabb = contents_aabb;
  440. } else {
  441. if (mesh_preview->get_mesh().is_valid()) {
  442. camera_aabb = mesh_preview->get_transform().xform(mesh_preview->get_mesh()->get_aabb());
  443. } else {
  444. camera_aabb = AABB(Vector3(-1, -1, -1), Vector3(2, 2, 2));
  445. }
  446. if (selected_type == "Mesh" && mesh_map.has(selected_id)) {
  447. const MeshData &md = mesh_map[selected_id];
  448. rot_x = md.cam_rot_x;
  449. rot_y = md.cam_rot_y;
  450. zoom = md.cam_zoom;
  451. } else if (selected_type == "Material" && material_map.has(selected_id)) {
  452. const MaterialData &md = material_map[selected_id];
  453. rot_x = md.cam_rot_x;
  454. rot_y = md.cam_rot_y;
  455. zoom = md.cam_zoom;
  456. }
  457. }
  458. Vector3 center = camera_aabb.get_center();
  459. float camera_size = camera_aabb.get_longest_axis_size();
  460. camera->set_orthogonal(camera_size * zoom, 0.0001, camera_size * 2);
  461. Transform3D xf;
  462. xf.basis = Basis(Vector3(1, 0, 0), rot_x) * Basis(Vector3(0, 1, 0), rot_y);
  463. xf.origin = center;
  464. xf.translate_local(0, 0, camera_size);
  465. camera->set_transform(xf);
  466. }
  467. void SceneImportSettings::_load_default_subresource_settings(HashMap<StringName, Variant> &settings, const String &p_type, const String &p_import_id, ResourceImporterScene::InternalImportCategory p_category) {
  468. if (base_subresource_settings.has(p_type)) {
  469. Dictionary d = base_subresource_settings[p_type];
  470. if (d.has(p_import_id)) {
  471. d = d[p_import_id];
  472. List<ResourceImporterScene::ImportOption> options;
  473. if (editing_animation) {
  474. ResourceImporterScene::get_animation_singleton()->get_internal_import_options(p_category, &options);
  475. } else {
  476. ResourceImporterScene::get_scene_singleton()->get_internal_import_options(p_category, &options);
  477. }
  478. for (const ResourceImporterScene::ImportOption &E : options) {
  479. String key = E.option.name;
  480. if (d.has(key)) {
  481. settings[key] = d[key];
  482. }
  483. }
  484. }
  485. }
  486. }
  487. void SceneImportSettings::request_generate_collider() {
  488. generate_collider = true;
  489. }
  490. void SceneImportSettings::update_view() {
  491. update_view_timer->start();
  492. }
  493. void SceneImportSettings::open_settings(const String &p_path, bool p_for_animation) {
  494. if (scene) {
  495. memdelete(scene);
  496. scene = nullptr;
  497. }
  498. editing_animation = p_for_animation;
  499. scene_import_settings_data->settings = nullptr;
  500. scene_import_settings_data->path = p_path;
  501. // Visibility
  502. data_mode->set_tab_hidden(1, p_for_animation);
  503. data_mode->set_tab_hidden(2, p_for_animation);
  504. if (p_for_animation) {
  505. data_mode->set_current_tab(0);
  506. }
  507. action_menu->get_popup()->set_item_disabled(action_menu->get_popup()->get_item_id(ACTION_EXTRACT_MATERIALS), p_for_animation);
  508. action_menu->get_popup()->set_item_disabled(action_menu->get_popup()->get_item_id(ACTION_CHOOSE_MESH_SAVE_PATHS), p_for_animation);
  509. base_path = p_path;
  510. mesh_set.clear();
  511. animation_map.clear();
  512. material_map.clear();
  513. unnamed_material_name_map.clear();
  514. mesh_map.clear();
  515. node_map.clear();
  516. defaults.clear();
  517. mesh_preview->hide();
  518. selected_id = "";
  519. selected_type = "";
  520. cam_rot_x = -Math_PI / 4;
  521. cam_rot_y = -Math_PI / 4;
  522. cam_zoom = 1;
  523. {
  524. base_subresource_settings.clear();
  525. Ref<ConfigFile> config;
  526. config.instantiate();
  527. Error err = config->load(p_path + ".import");
  528. if (err == OK) {
  529. List<String> keys;
  530. config->get_section_keys("params", &keys);
  531. for (const String &E : keys) {
  532. Variant value = config->get_value("params", E);
  533. if (E == "_subresources") {
  534. base_subresource_settings = value;
  535. } else {
  536. defaults[E] = value;
  537. }
  538. }
  539. }
  540. }
  541. scene = ResourceImporterScene::get_scene_singleton()->pre_import(p_path, defaults); // Use the scene singleton here because we want to see the full thing.
  542. if (scene == nullptr) {
  543. EditorNode::get_singleton()->show_warning(TTR("Error opening scene"));
  544. return;
  545. }
  546. first_aabb = true;
  547. _update_scene();
  548. base_viewport->add_child(scene);
  549. inspector->edit(nullptr);
  550. if (first_aabb) {
  551. contents_aabb = AABB(Vector3(-1, -1, -1), Vector3(2, 2, 2));
  552. first_aabb = false;
  553. }
  554. popup_centered_ratio();
  555. _update_view_gizmos();
  556. _update_camera();
  557. // Start with the root item (Scene) selected.
  558. scene_tree->get_root()->select(0);
  559. if (p_for_animation) {
  560. set_title(vformat(TTR("Advanced Import Settings for AnimationLibrary '%s'"), base_path.get_file()));
  561. } else {
  562. set_title(vformat(TTR("Advanced Import Settings for Scene '%s'"), base_path.get_file()));
  563. }
  564. }
  565. SceneImportSettings *SceneImportSettings::singleton = nullptr;
  566. SceneImportSettings *SceneImportSettings::get_singleton() {
  567. return singleton;
  568. }
  569. Node *SceneImportSettings::get_selected_node() {
  570. if (selected_id == "") {
  571. return nullptr;
  572. }
  573. return node_map[selected_id].node;
  574. }
  575. void SceneImportSettings::_select(Tree *p_from, String p_type, String p_id) {
  576. selecting = true;
  577. scene_import_settings_data->hide_options = false;
  578. if (p_type == "Node") {
  579. node_selected->hide(); //always hide just in case
  580. mesh_preview->hide();
  581. if (Object::cast_to<Node3D>(scene)) {
  582. Object::cast_to<Node3D>(scene)->show();
  583. }
  584. //NodeData &nd=node_map[p_id];
  585. material_tree->deselect_all();
  586. mesh_tree->deselect_all();
  587. NodeData &nd = node_map[p_id];
  588. MeshInstance3D *mi = Object::cast_to<MeshInstance3D>(nd.node);
  589. if (mi) {
  590. Ref<Mesh> base_mesh = mi->get_mesh();
  591. if (base_mesh.is_valid()) {
  592. AABB aabb = base_mesh->get_aabb();
  593. Transform3D aabb_xf;
  594. aabb_xf.basis.scale(aabb.size);
  595. aabb_xf.origin = aabb.position;
  596. aabb_xf = mi->get_global_transform() * aabb_xf;
  597. node_selected->set_transform(aabb_xf);
  598. node_selected->show();
  599. }
  600. }
  601. if (nd.node == scene) {
  602. scene_import_settings_data->settings = &defaults;
  603. scene_import_settings_data->category = ResourceImporterScene::INTERNAL_IMPORT_CATEGORY_MAX;
  604. } else {
  605. scene_import_settings_data->settings = &nd.settings;
  606. if (mi) {
  607. scene_import_settings_data->category = ResourceImporterScene::INTERNAL_IMPORT_CATEGORY_MESH_3D_NODE;
  608. scene_import_settings_data->hide_options = editing_animation;
  609. } else if (Object::cast_to<AnimationPlayer>(nd.node)) {
  610. scene_import_settings_data->category = ResourceImporterScene::INTERNAL_IMPORT_CATEGORY_ANIMATION_NODE;
  611. } else if (Object::cast_to<Skeleton3D>(nd.node)) {
  612. scene_import_settings_data->category = ResourceImporterScene::INTERNAL_IMPORT_CATEGORY_SKELETON_3D_NODE;
  613. } else {
  614. scene_import_settings_data->category = ResourceImporterScene::INTERNAL_IMPORT_CATEGORY_NODE;
  615. scene_import_settings_data->hide_options = editing_animation;
  616. }
  617. }
  618. } else if (p_type == "Animation") {
  619. node_selected->hide(); //always hide just in case
  620. mesh_preview->hide();
  621. if (Object::cast_to<Node3D>(scene)) {
  622. Object::cast_to<Node3D>(scene)->show();
  623. }
  624. //NodeData &nd=node_map[p_id];
  625. material_tree->deselect_all();
  626. mesh_tree->deselect_all();
  627. AnimationData &ad = animation_map[p_id];
  628. scene_import_settings_data->settings = &ad.settings;
  629. scene_import_settings_data->category = ResourceImporterScene::INTERNAL_IMPORT_CATEGORY_ANIMATION;
  630. } else if (p_type == "Mesh") {
  631. node_selected->hide();
  632. if (Object::cast_to<Node3D>(scene)) {
  633. Object::cast_to<Node3D>(scene)->hide();
  634. }
  635. MeshData &md = mesh_map[p_id];
  636. if (md.mesh_node != nullptr) {
  637. if (p_from != mesh_tree) {
  638. md.mesh_node->uncollapse_tree();
  639. md.mesh_node->select(0);
  640. mesh_tree->ensure_cursor_is_visible();
  641. }
  642. if (p_from != scene_tree) {
  643. md.scene_node->uncollapse_tree();
  644. md.scene_node->select(0);
  645. scene_tree->ensure_cursor_is_visible();
  646. }
  647. }
  648. mesh_preview->set_mesh(md.mesh);
  649. mesh_preview->show();
  650. material_tree->deselect_all();
  651. scene_import_settings_data->settings = &md.settings;
  652. scene_import_settings_data->category = ResourceImporterScene::INTERNAL_IMPORT_CATEGORY_MESH;
  653. } else if (p_type == "Material") {
  654. node_selected->hide();
  655. if (Object::cast_to<Node3D>(scene)) {
  656. Object::cast_to<Node3D>(scene)->hide();
  657. }
  658. mesh_preview->show();
  659. MaterialData &md = material_map[p_id];
  660. material_preview->set_material(md.material);
  661. mesh_preview->set_mesh(material_preview);
  662. if (p_from != mesh_tree) {
  663. md.mesh_node->uncollapse_tree();
  664. md.mesh_node->select(0);
  665. mesh_tree->ensure_cursor_is_visible();
  666. }
  667. if (p_from != scene_tree) {
  668. md.scene_node->uncollapse_tree();
  669. md.scene_node->select(0);
  670. scene_tree->ensure_cursor_is_visible();
  671. }
  672. if (p_from != material_tree) {
  673. md.material_node->uncollapse_tree();
  674. md.material_node->select(0);
  675. material_tree->ensure_cursor_is_visible();
  676. }
  677. scene_import_settings_data->settings = &md.settings;
  678. scene_import_settings_data->category = ResourceImporterScene::INTERNAL_IMPORT_CATEGORY_MATERIAL;
  679. }
  680. selected_type = p_type;
  681. selected_id = p_id;
  682. selecting = false;
  683. _update_camera();
  684. List<ResourceImporter::ImportOption> options;
  685. if (editing_animation) {
  686. if (scene_import_settings_data->category == ResourceImporterScene::INTERNAL_IMPORT_CATEGORY_MAX) {
  687. ResourceImporterScene::get_animation_singleton()->get_import_options(base_path, &options);
  688. } else {
  689. ResourceImporterScene::get_animation_singleton()->get_internal_import_options(scene_import_settings_data->category, &options);
  690. }
  691. } else {
  692. if (scene_import_settings_data->category == ResourceImporterScene::INTERNAL_IMPORT_CATEGORY_MAX) {
  693. ResourceImporterScene::get_scene_singleton()->get_import_options(base_path, &options);
  694. } else {
  695. ResourceImporterScene::get_scene_singleton()->get_internal_import_options(scene_import_settings_data->category, &options);
  696. }
  697. }
  698. scene_import_settings_data->defaults.clear();
  699. scene_import_settings_data->current.clear();
  700. if (scene_import_settings_data->settings) {
  701. for (const ResourceImporter::ImportOption &E : options) {
  702. scene_import_settings_data->defaults[E.option.name] = E.default_value;
  703. //needed for visibility toggling (fails if something is missing)
  704. if (scene_import_settings_data->settings->has(E.option.name)) {
  705. scene_import_settings_data->current[E.option.name] = (*scene_import_settings_data->settings)[E.option.name];
  706. } else {
  707. scene_import_settings_data->current[E.option.name] = E.default_value;
  708. }
  709. }
  710. }
  711. scene_import_settings_data->options = options;
  712. inspector->edit(scene_import_settings_data);
  713. scene_import_settings_data->notify_property_list_changed();
  714. }
  715. void SceneImportSettings::_material_tree_selected() {
  716. if (selecting) {
  717. return;
  718. }
  719. TreeItem *item = material_tree->get_selected();
  720. String type = item->get_meta("type");
  721. String import_id = item->get_meta("import_id");
  722. _select(material_tree, type, import_id);
  723. }
  724. void SceneImportSettings::_mesh_tree_selected() {
  725. if (selecting) {
  726. return;
  727. }
  728. TreeItem *item = mesh_tree->get_selected();
  729. String type = item->get_meta("type");
  730. String import_id = item->get_meta("import_id");
  731. _select(mesh_tree, type, import_id);
  732. }
  733. void SceneImportSettings::_scene_tree_selected() {
  734. if (selecting) {
  735. return;
  736. }
  737. TreeItem *item = scene_tree->get_selected();
  738. String type = item->get_meta("type");
  739. String import_id = item->get_meta("import_id");
  740. _select(scene_tree, type, import_id);
  741. }
  742. void SceneImportSettings::_viewport_input(const Ref<InputEvent> &p_input) {
  743. float *rot_x = &cam_rot_x;
  744. float *rot_y = &cam_rot_y;
  745. float *zoom = &cam_zoom;
  746. if (selected_type == "Mesh" && mesh_map.has(selected_id)) {
  747. MeshData &md = mesh_map[selected_id];
  748. rot_x = &md.cam_rot_x;
  749. rot_y = &md.cam_rot_y;
  750. zoom = &md.cam_zoom;
  751. } else if (selected_type == "Material" && material_map.has(selected_id)) {
  752. MaterialData &md = material_map[selected_id];
  753. rot_x = &md.cam_rot_x;
  754. rot_y = &md.cam_rot_y;
  755. zoom = &md.cam_zoom;
  756. }
  757. Ref<InputEventMouseMotion> mm = p_input;
  758. if (mm.is_valid() && (mm->get_button_mask().has_flag(MouseButtonMask::LEFT))) {
  759. (*rot_x) -= mm->get_relative().y * 0.01 * EDSCALE;
  760. (*rot_y) -= mm->get_relative().x * 0.01 * EDSCALE;
  761. (*rot_x) = CLAMP((*rot_x), -Math_PI / 2, Math_PI / 2);
  762. _update_camera();
  763. }
  764. Ref<InputEventMouseButton> mb = p_input;
  765. if (mb.is_valid() && mb->get_button_index() == MouseButton::WHEEL_DOWN) {
  766. (*zoom) *= 1.1;
  767. if ((*zoom) > 10.0) {
  768. (*zoom) = 10.0;
  769. }
  770. _update_camera();
  771. }
  772. if (mb.is_valid() && mb->get_button_index() == MouseButton::WHEEL_UP) {
  773. (*zoom) /= 1.1;
  774. if ((*zoom) < 0.1) {
  775. (*zoom) = 0.1;
  776. }
  777. _update_camera();
  778. }
  779. }
  780. void SceneImportSettings::_re_import() {
  781. HashMap<StringName, Variant> main_settings;
  782. main_settings = defaults;
  783. main_settings.erase("_subresources");
  784. Dictionary nodes;
  785. Dictionary materials;
  786. Dictionary meshes;
  787. Dictionary animations;
  788. Dictionary subresources;
  789. for (KeyValue<String, NodeData> &E : node_map) {
  790. if (E.value.settings.size()) {
  791. Dictionary d;
  792. for (const KeyValue<StringName, Variant> &F : E.value.settings) {
  793. d[String(F.key)] = F.value;
  794. }
  795. nodes[E.key] = d;
  796. }
  797. }
  798. if (nodes.size()) {
  799. subresources["nodes"] = nodes;
  800. }
  801. for (KeyValue<String, MaterialData> &E : material_map) {
  802. if (E.value.settings.size()) {
  803. Dictionary d;
  804. for (const KeyValue<StringName, Variant> &F : E.value.settings) {
  805. d[String(F.key)] = F.value;
  806. }
  807. materials[E.key] = d;
  808. }
  809. }
  810. if (materials.size()) {
  811. subresources["materials"] = materials;
  812. }
  813. for (KeyValue<String, MeshData> &E : mesh_map) {
  814. if (E.value.settings.size()) {
  815. Dictionary d;
  816. for (const KeyValue<StringName, Variant> &F : E.value.settings) {
  817. d[String(F.key)] = F.value;
  818. }
  819. meshes[E.key] = d;
  820. }
  821. }
  822. if (meshes.size()) {
  823. subresources["meshes"] = meshes;
  824. }
  825. for (KeyValue<String, AnimationData> &E : animation_map) {
  826. if (E.value.settings.size()) {
  827. Dictionary d;
  828. for (const KeyValue<StringName, Variant> &F : E.value.settings) {
  829. d[String(F.key)] = F.value;
  830. }
  831. animations[E.key] = d;
  832. }
  833. }
  834. if (animations.size()) {
  835. subresources["animations"] = animations;
  836. }
  837. if (subresources.size()) {
  838. main_settings["_subresources"] = subresources;
  839. }
  840. EditorFileSystem::get_singleton()->reimport_file_with_custom_parameters(base_path, editing_animation ? "animation_library" : "scene", main_settings);
  841. }
  842. void SceneImportSettings::_notification(int p_what) {
  843. switch (p_what) {
  844. case NOTIFICATION_READY: {
  845. connect("confirmed", callable_mp(this, &SceneImportSettings::_re_import));
  846. } break;
  847. case EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED: {
  848. inspector->set_property_name_style(EditorPropertyNameProcessor::get_settings_style());
  849. } break;
  850. }
  851. }
  852. void SceneImportSettings::_menu_callback(int p_id) {
  853. switch (p_id) {
  854. case ACTION_EXTRACT_MATERIALS: {
  855. save_path->set_title(TTR("Select folder to extract material resources"));
  856. external_extension_type->select(0);
  857. } break;
  858. case ACTION_CHOOSE_MESH_SAVE_PATHS: {
  859. save_path->set_title(TTR("Select folder where mesh resources will save on import"));
  860. external_extension_type->select(1);
  861. } break;
  862. case ACTION_CHOOSE_ANIMATION_SAVE_PATHS: {
  863. save_path->set_title(TTR("Select folder where animations will save on import"));
  864. external_extension_type->select(1);
  865. } break;
  866. }
  867. save_path->set_current_dir(base_path.get_base_dir());
  868. current_action = p_id;
  869. save_path->popup_centered_ratio();
  870. }
  871. void SceneImportSettings::_save_path_changed(const String &p_path) {
  872. save_path_item->set_text(1, p_path);
  873. if (FileAccess::exists(p_path)) {
  874. save_path_item->set_text(2, TTR("Warning: File exists"));
  875. save_path_item->set_tooltip_text(2, TTR("Existing file with the same name will be replaced."));
  876. save_path_item->set_icon(2, get_theme_icon(SNAME("StatusWarning"), SNAME("EditorIcons")));
  877. } else {
  878. save_path_item->set_text(2, TTR("Will create new file"));
  879. save_path_item->set_icon(2, get_theme_icon(SNAME("StatusSuccess"), SNAME("EditorIcons")));
  880. }
  881. }
  882. void SceneImportSettings::_browse_save_callback(Object *p_item, int p_column, int p_id, MouseButton p_button) {
  883. if (p_button != MouseButton::LEFT) {
  884. return;
  885. }
  886. TreeItem *item = Object::cast_to<TreeItem>(p_item);
  887. String path = item->get_text(1);
  888. item_save_path->set_current_file(path);
  889. save_path_item = item;
  890. item_save_path->popup_centered_ratio();
  891. }
  892. void SceneImportSettings::_save_dir_callback(const String &p_path) {
  893. external_path_tree->clear();
  894. TreeItem *root = external_path_tree->create_item();
  895. save_path_items.clear();
  896. switch (current_action) {
  897. case ACTION_EXTRACT_MATERIALS: {
  898. for (const KeyValue<String, MaterialData> &E : material_map) {
  899. MaterialData &md = material_map[E.key];
  900. TreeItem *item = external_path_tree->create_item(root);
  901. String name = md.material_node->get_text(0);
  902. item->set_cell_mode(0, TreeItem::CELL_MODE_CHECK);
  903. item->set_icon(0, get_theme_icon(SNAME("StandardMaterial3D"), SNAME("EditorIcons")));
  904. item->set_text(0, name);
  905. if (md.has_import_id) {
  906. if (md.settings.has("use_external/enabled") && bool(md.settings["use_external/enabled"])) {
  907. item->set_text(2, TTR("Already External"));
  908. 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."));
  909. } else {
  910. item->set_metadata(0, E.key);
  911. item->set_editable(0, true);
  912. item->set_checked(0, true);
  913. String path = p_path.path_join(name);
  914. if (external_extension_type->get_selected() == 0) {
  915. path += ".tres";
  916. } else {
  917. path += ".res";
  918. }
  919. item->set_text(1, path);
  920. if (FileAccess::exists(path)) {
  921. item->set_text(2, TTR("Warning: File exists"));
  922. item->set_tooltip_text(2, TTR("Existing file with the same name will be replaced."));
  923. item->set_icon(2, get_theme_icon(SNAME("StatusWarning"), SNAME("EditorIcons")));
  924. } else {
  925. item->set_text(2, TTR("Will create new file"));
  926. item->set_icon(2, get_theme_icon(SNAME("StatusSuccess"), SNAME("EditorIcons")));
  927. }
  928. item->add_button(1, get_theme_icon(SNAME("Folder"), SNAME("EditorIcons")));
  929. }
  930. } else {
  931. item->set_text(2, TTR("No import ID"));
  932. 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."));
  933. item->set_icon(2, get_theme_icon(SNAME("StatusError"), SNAME("EditorIcons")));
  934. }
  935. save_path_items.push_back(item);
  936. }
  937. external_paths->set_title(TTR("Extract Materials to Resource Files"));
  938. external_paths->set_ok_button_text(TTR("Extract"));
  939. } break;
  940. case ACTION_CHOOSE_MESH_SAVE_PATHS: {
  941. for (const KeyValue<String, MeshData> &E : mesh_map) {
  942. MeshData &md = mesh_map[E.key];
  943. TreeItem *item = external_path_tree->create_item(root);
  944. String name = md.mesh_node->get_text(0);
  945. item->set_cell_mode(0, TreeItem::CELL_MODE_CHECK);
  946. item->set_icon(0, get_theme_icon(SNAME("Mesh"), SNAME("EditorIcons")));
  947. item->set_text(0, name);
  948. if (md.has_import_id) {
  949. if (md.settings.has("save_to_file/enabled") && bool(md.settings["save_to_file/enabled"])) {
  950. item->set_text(2, TTR("Already Saving"));
  951. item->set_tooltip_text(2, TTR("This mesh already saves to an external resource, no action will be taken."));
  952. } else {
  953. item->set_metadata(0, E.key);
  954. item->set_editable(0, true);
  955. item->set_checked(0, true);
  956. String path = p_path.path_join(name);
  957. if (external_extension_type->get_selected() == 0) {
  958. path += ".tres";
  959. } else {
  960. path += ".res";
  961. }
  962. item->set_text(1, path);
  963. if (FileAccess::exists(path)) {
  964. item->set_text(2, TTR("Warning: File exists"));
  965. item->set_tooltip_text(2, TTR("Existing file with the same name will be replaced on import."));
  966. item->set_icon(2, get_theme_icon(SNAME("StatusWarning"), SNAME("EditorIcons")));
  967. } else {
  968. item->set_text(2, TTR("Will save to new file"));
  969. item->set_icon(2, get_theme_icon(SNAME("StatusSuccess"), SNAME("EditorIcons")));
  970. }
  971. item->add_button(1, get_theme_icon(SNAME("Folder"), SNAME("EditorIcons")));
  972. }
  973. } else {
  974. item->set_text(2, TTR("No import ID"));
  975. 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."));
  976. item->set_icon(2, get_theme_icon(SNAME("StatusError"), SNAME("EditorIcons")));
  977. }
  978. save_path_items.push_back(item);
  979. }
  980. external_paths->set_title(TTR("Set paths to save meshes as resource files on Reimport"));
  981. external_paths->set_ok_button_text(TTR("Set Paths"));
  982. } break;
  983. case ACTION_CHOOSE_ANIMATION_SAVE_PATHS: {
  984. for (const KeyValue<String, AnimationData> &E : animation_map) {
  985. AnimationData &ad = animation_map[E.key];
  986. TreeItem *item = external_path_tree->create_item(root);
  987. String name = ad.scene_node->get_text(0);
  988. item->set_cell_mode(0, TreeItem::CELL_MODE_CHECK);
  989. item->set_icon(0, get_theme_icon(SNAME("Animation"), SNAME("EditorIcons")));
  990. item->set_text(0, name);
  991. if (ad.settings.has("save_to_file/enabled") && bool(ad.settings["save_to_file/enabled"])) {
  992. item->set_text(2, TTR("Already Saving"));
  993. item->set_tooltip_text(2, TTR("This animation already saves to an external resource, no action will be taken."));
  994. } else {
  995. item->set_metadata(0, E.key);
  996. item->set_editable(0, true);
  997. item->set_checked(0, true);
  998. String path = p_path.path_join(name);
  999. if (external_extension_type->get_selected() == 0) {
  1000. path += ".tres";
  1001. } else {
  1002. path += ".res";
  1003. }
  1004. item->set_text(1, path);
  1005. if (FileAccess::exists(path)) {
  1006. item->set_text(2, TTR("Warning: File exists"));
  1007. item->set_tooltip_text(2, TTR("Existing file with the same name will be replaced on import."));
  1008. item->set_icon(2, get_theme_icon(SNAME("StatusWarning"), SNAME("EditorIcons")));
  1009. } else {
  1010. item->set_text(2, TTR("Will save to new file"));
  1011. item->set_icon(2, get_theme_icon(SNAME("StatusSuccess"), SNAME("EditorIcons")));
  1012. }
  1013. item->add_button(1, get_theme_icon(SNAME("Folder"), SNAME("EditorIcons")));
  1014. }
  1015. save_path_items.push_back(item);
  1016. }
  1017. external_paths->set_title(TTR("Set paths to save animations as resource files on Reimport"));
  1018. external_paths->set_ok_button_text(TTR("Set Paths"));
  1019. } break;
  1020. }
  1021. external_paths->popup_centered_ratio();
  1022. }
  1023. void SceneImportSettings::_save_dir_confirm() {
  1024. for (int i = 0; i < save_path_items.size(); i++) {
  1025. TreeItem *item = save_path_items[i];
  1026. if (!item->is_checked(0)) {
  1027. continue; //ignore
  1028. }
  1029. String path = item->get_text(1);
  1030. if (!path.is_resource_file()) {
  1031. continue;
  1032. }
  1033. String id = item->get_metadata(0);
  1034. switch (current_action) {
  1035. case ACTION_EXTRACT_MATERIALS: {
  1036. ERR_CONTINUE(!material_map.has(id));
  1037. MaterialData &md = material_map[id];
  1038. Error err = ResourceSaver::save(md.material, path);
  1039. if (err != OK) {
  1040. EditorNode::get_singleton()->add_io_error(TTR("Can't make material external to file, write error:") + "\n\t" + path);
  1041. continue;
  1042. }
  1043. md.settings["use_external/enabled"] = true;
  1044. md.settings["use_external/path"] = path;
  1045. } break;
  1046. case ACTION_CHOOSE_MESH_SAVE_PATHS: {
  1047. ERR_CONTINUE(!mesh_map.has(id));
  1048. MeshData &md = mesh_map[id];
  1049. md.settings["save_to_file/enabled"] = true;
  1050. md.settings["save_to_file/path"] = path;
  1051. } break;
  1052. case ACTION_CHOOSE_ANIMATION_SAVE_PATHS: {
  1053. ERR_CONTINUE(!animation_map.has(id));
  1054. AnimationData &ad = animation_map[id];
  1055. ad.settings["save_to_file/enabled"] = true;
  1056. ad.settings["save_to_file/path"] = path;
  1057. } break;
  1058. }
  1059. }
  1060. if (current_action == ACTION_EXTRACT_MATERIALS) {
  1061. //as this happens right now, the scene needs to be saved and reimported.
  1062. _re_import();
  1063. open_settings(base_path);
  1064. } else {
  1065. scene_import_settings_data->notify_property_list_changed();
  1066. }
  1067. }
  1068. SceneImportSettings::SceneImportSettings() {
  1069. singleton = this;
  1070. VBoxContainer *main_vb = memnew(VBoxContainer);
  1071. add_child(main_vb);
  1072. HBoxContainer *menu_hb = memnew(HBoxContainer);
  1073. main_vb->add_child(menu_hb);
  1074. action_menu = memnew(MenuButton);
  1075. action_menu->set_text(TTR("Actions..."));
  1076. // Style the MenuButton like a regular Button to make it more noticeable.
  1077. action_menu->set_flat(false);
  1078. action_menu->add_theme_style_override("normal", get_theme_stylebox("normal", "Button"));
  1079. action_menu->add_theme_style_override("hover", get_theme_stylebox("hover", "Button"));
  1080. action_menu->add_theme_style_override("pressed", get_theme_stylebox("pressed", "Button"));
  1081. action_menu->set_focus_mode(Control::FOCUS_ALL);
  1082. menu_hb->add_child(action_menu);
  1083. action_menu->get_popup()->add_item(TTR("Extract Materials"), ACTION_EXTRACT_MATERIALS);
  1084. action_menu->get_popup()->add_separator();
  1085. action_menu->get_popup()->add_item(TTR("Set Animation Save Paths"), ACTION_CHOOSE_ANIMATION_SAVE_PATHS);
  1086. action_menu->get_popup()->add_item(TTR("Set Mesh Save Paths"), ACTION_CHOOSE_MESH_SAVE_PATHS);
  1087. action_menu->get_popup()->connect("id_pressed", callable_mp(this, &SceneImportSettings::_menu_callback));
  1088. tree_split = memnew(HSplitContainer);
  1089. main_vb->add_child(tree_split);
  1090. tree_split->set_v_size_flags(Control::SIZE_EXPAND_FILL);
  1091. data_mode = memnew(TabContainer);
  1092. tree_split->add_child(data_mode);
  1093. data_mode->set_custom_minimum_size(Size2(300 * EDSCALE, 0));
  1094. data_mode->set_theme_type_variation("TabContainerOdd");
  1095. property_split = memnew(HSplitContainer);
  1096. tree_split->add_child(property_split);
  1097. property_split->set_h_size_flags(Control::SIZE_EXPAND_FILL);
  1098. scene_tree = memnew(Tree);
  1099. scene_tree->set_name(TTR("Scene"));
  1100. data_mode->add_child(scene_tree);
  1101. scene_tree->connect("cell_selected", callable_mp(this, &SceneImportSettings::_scene_tree_selected));
  1102. mesh_tree = memnew(Tree);
  1103. mesh_tree->set_name(TTR("Meshes"));
  1104. data_mode->add_child(mesh_tree);
  1105. mesh_tree->set_hide_root(true);
  1106. mesh_tree->connect("cell_selected", callable_mp(this, &SceneImportSettings::_mesh_tree_selected));
  1107. material_tree = memnew(Tree);
  1108. material_tree->set_name(TTR("Materials"));
  1109. data_mode->add_child(material_tree);
  1110. material_tree->connect("cell_selected", callable_mp(this, &SceneImportSettings::_material_tree_selected));
  1111. material_tree->set_hide_root(true);
  1112. SubViewportContainer *vp_container = memnew(SubViewportContainer);
  1113. vp_container->set_h_size_flags(Control::SIZE_EXPAND_FILL);
  1114. vp_container->set_custom_minimum_size(Size2(10, 10));
  1115. vp_container->set_stretch(true);
  1116. vp_container->connect("gui_input", callable_mp(this, &SceneImportSettings::_viewport_input));
  1117. property_split->add_child(vp_container);
  1118. base_viewport = memnew(SubViewport);
  1119. vp_container->add_child(base_viewport);
  1120. base_viewport->set_use_own_world_3d(true);
  1121. camera = memnew(Camera3D);
  1122. base_viewport->add_child(camera);
  1123. camera->make_current();
  1124. if (GLOBAL_GET("rendering/lights_and_shadows/use_physical_light_units")) {
  1125. camera_attributes.instantiate();
  1126. camera->set_attributes(camera_attributes);
  1127. }
  1128. light = memnew(DirectionalLight3D);
  1129. light->set_transform(Transform3D().looking_at(Vector3(-1, -2, -0.6), Vector3(0, 1, 0)));
  1130. base_viewport->add_child(light);
  1131. light->set_shadow(true);
  1132. {
  1133. Ref<StandardMaterial3D> selection_mat;
  1134. selection_mat.instantiate();
  1135. selection_mat->set_shading_mode(StandardMaterial3D::SHADING_MODE_UNSHADED);
  1136. selection_mat->set_albedo(Color(1, 0.8, 1.0));
  1137. Ref<SurfaceTool> st;
  1138. st.instantiate();
  1139. st->begin(Mesh::PRIMITIVE_LINES);
  1140. AABB base_aabb;
  1141. base_aabb.size = Vector3(1, 1, 1);
  1142. for (int i = 0; i < 12; i++) {
  1143. Vector3 a, b;
  1144. base_aabb.get_edge(i, a, b);
  1145. st->add_vertex(a);
  1146. st->add_vertex(a.lerp(b, 0.2));
  1147. st->add_vertex(b);
  1148. st->add_vertex(b.lerp(a, 0.2));
  1149. }
  1150. selection_mesh.instantiate();
  1151. st->commit(selection_mesh);
  1152. selection_mesh->surface_set_material(0, selection_mat);
  1153. node_selected = memnew(MeshInstance3D);
  1154. node_selected->set_mesh(selection_mesh);
  1155. base_viewport->add_child(node_selected);
  1156. node_selected->hide();
  1157. }
  1158. {
  1159. mesh_preview = memnew(MeshInstance3D);
  1160. base_viewport->add_child(mesh_preview);
  1161. mesh_preview->hide();
  1162. material_preview.instantiate();
  1163. }
  1164. {
  1165. collider_mat.instantiate();
  1166. collider_mat->set_shading_mode(StandardMaterial3D::SHADING_MODE_UNSHADED);
  1167. collider_mat->set_albedo(Color(0.5, 0.5, 1.0));
  1168. }
  1169. inspector = memnew(EditorInspector);
  1170. inspector->set_custom_minimum_size(Size2(300 * EDSCALE, 0));
  1171. inspector->set_property_name_style(EditorPropertyNameProcessor::get_settings_style());
  1172. property_split->add_child(inspector);
  1173. scene_import_settings_data = memnew(SceneImportSettingsData);
  1174. set_ok_button_text(TTR("Reimport"));
  1175. set_cancel_button_text(TTR("Close"));
  1176. external_paths = memnew(ConfirmationDialog);
  1177. add_child(external_paths);
  1178. external_path_tree = memnew(Tree);
  1179. external_paths->add_child(external_path_tree);
  1180. external_path_tree->connect("button_clicked", callable_mp(this, &SceneImportSettings::_browse_save_callback));
  1181. external_paths->connect("confirmed", callable_mp(this, &SceneImportSettings::_save_dir_confirm));
  1182. external_path_tree->set_columns(3);
  1183. external_path_tree->set_column_titles_visible(true);
  1184. external_path_tree->set_column_expand(0, true);
  1185. external_path_tree->set_column_custom_minimum_width(0, 100 * EDSCALE);
  1186. external_path_tree->set_column_title(0, TTR("Resource"));
  1187. external_path_tree->set_column_expand(1, true);
  1188. external_path_tree->set_column_custom_minimum_width(1, 100 * EDSCALE);
  1189. external_path_tree->set_column_title(1, TTR("Path"));
  1190. external_path_tree->set_column_expand(2, false);
  1191. external_path_tree->set_column_custom_minimum_width(2, 200 * EDSCALE);
  1192. external_path_tree->set_column_title(2, TTR("Status"));
  1193. save_path = memnew(EditorFileDialog);
  1194. save_path->set_file_mode(EditorFileDialog::FILE_MODE_OPEN_DIR);
  1195. HBoxContainer *extension_hb = memnew(HBoxContainer);
  1196. save_path->get_vbox()->add_child(extension_hb);
  1197. extension_hb->add_spacer();
  1198. extension_hb->add_child(memnew(Label(TTR("Save Extension:"))));
  1199. external_extension_type = memnew(OptionButton);
  1200. extension_hb->add_child(external_extension_type);
  1201. external_extension_type->add_item(TTR("Text: *.tres"));
  1202. external_extension_type->add_item(TTR("Binary: *.res"));
  1203. external_path_tree->set_hide_root(true);
  1204. add_child(save_path);
  1205. item_save_path = memnew(EditorFileDialog);
  1206. item_save_path->set_file_mode(EditorFileDialog::FILE_MODE_SAVE_FILE);
  1207. item_save_path->add_filter("*.tres", TTR("Text Resource"));
  1208. item_save_path->add_filter("*.res", TTR("Binary Resource"));
  1209. add_child(item_save_path);
  1210. item_save_path->connect("file_selected", callable_mp(this, &SceneImportSettings::_save_path_changed));
  1211. save_path->connect("dir_selected", callable_mp(this, &SceneImportSettings::_save_dir_callback));
  1212. update_view_timer = memnew(Timer);
  1213. update_view_timer->set_wait_time(0.2);
  1214. update_view_timer->connect("timeout", callable_mp(this, &SceneImportSettings::_update_view_gizmos));
  1215. add_child(update_view_timer);
  1216. }
  1217. SceneImportSettings::~SceneImportSettings() {
  1218. memdelete(scene_import_settings_data);
  1219. }