Browse Source

Merge pull request #52802 from V-Sekai/gltf-extensions

Rémi Verschelde 3 years ago
parent
commit
2a09e11986
40 changed files with 802 additions and 317 deletions
  1. 5 5
      doc/classes/ImporterMesh.xml
  2. 2 2
      doc/classes/ImporterMeshInstance3D.xml
  3. 1 3
      editor/editor_node.cpp
  4. 14 13
      editor/import/editor_import_collada.cpp
  5. 2 2
      editor/import/editor_importer_bake_reset.cpp
  6. 4 4
      editor/import/resource_importer_obj.cpp
  7. 32 31
      editor/import/resource_importer_scene.cpp
  8. 3 3
      editor/import/resource_importer_scene.h
  9. 4 3
      editor/import/scene_import_settings.cpp
  10. 4 3
      modules/fbx/data/fbx_mesh_data.cpp
  11. 3 3
      modules/fbx/data/fbx_mesh_data.h
  12. 3 3
      modules/fbx/editor_scene_importer_fbx.cpp
  13. 3 1
      modules/gltf/config.py
  14. 4 0
      modules/gltf/doc_classes/GLTFDocument.xml
  15. 73 0
      modules/gltf/doc_classes/GLTFDocumentExtension.xml
  16. 9 0
      modules/gltf/doc_classes/GLTFDocumentExtensionConvertImporterMesh.xml
  17. 1 1
      modules/gltf/doc_classes/GLTFMesh.xml
  18. 3 0
      modules/gltf/editor_scene_exporter_gltf_plugin.cpp
  19. 3 1
      modules/gltf/editor_scene_exporter_gltf_plugin.h
  20. 3 0
      modules/gltf/editor_scene_importer_gltf.cpp
  21. 4 3
      modules/gltf/editor_scene_importer_gltf.h
  22. 2 0
      modules/gltf/gltf_accessor.cpp
  23. 2 0
      modules/gltf/gltf_accessor.h
  24. 2 0
      modules/gltf/gltf_buffer_view.cpp
  25. 199 122
      modules/gltf/gltf_document.cpp
  26. 15 9
      modules/gltf/gltf_document.h
  27. 88 0
      modules/gltf/gltf_document_extension.cpp
  28. 63 0
      modules/gltf/gltf_document_extension.h
  29. 79 0
      modules/gltf/gltf_document_extension_convert_importer_mesh.cpp
  30. 55 0
      modules/gltf/gltf_document_extension_convert_importer_mesh.h
  31. 3 3
      modules/gltf/gltf_mesh.cpp
  32. 5 4
      modules/gltf/gltf_mesh.h
  33. 1 0
      modules/gltf/gltf_state.h
  34. 4 0
      modules/gltf/register_types.cpp
  35. 20 18
      scene/3d/importer_mesh_instance_3d.cpp
  36. 10 10
      scene/3d/importer_mesh_instance_3d.h
  37. 4 0
      scene/register_scene_types.cpp
  38. 61 61
      scene/resources/importer_mesh.cpp
  39. 8 8
      scene/resources/importer_mesh.h
  40. 1 1
      servers/rendering_server.cpp

+ 5 - 5
doc/classes/EditorSceneImporterMesh.xml → doc/classes/ImporterMesh.xml

@@ -1,12 +1,12 @@
 <?xml version="1.0" encoding="UTF-8" ?>
-<class name="EditorSceneImporterMesh" inherits="Resource" version="4.0">
+<class name="ImporterMesh" inherits="Resource" version="4.0">
 	<brief_description>
 		A [Resource] that contains vertex array-based geometry during the import process.
 	</brief_description>
 	<description>
-		EditorSceneImporterMesh is a type of [Resource] analogous to [ArrayMesh]. It contains vertex array-based geometry, divided in [i]surfaces[/i]. Each surface contains a completely separate array and a material used to draw it. Design wise, a mesh with multiple surfaces is preferred to a single surface, because objects created in 3D editing software commonly contain multiple materials.
+		ImporterMesh is a type of [Resource] analogous to [ArrayMesh]. It contains vertex array-based geometry, divided in [i]surfaces[/i]. Each surface contains a completely separate array and a material used to draw it. Design wise, a mesh with multiple surfaces is preferred to a single surface, because objects created in 3D editing software commonly contain multiple materials.
 
-		Unlike its runtime counterpart, [EditorSceneImporterMesh] contains mesh data before various import steps, such as lod and shadow mesh generation, have taken place. Modify surface data by calling [method clear], followed by [method add_surface] for each surface.
+		Unlike its runtime counterpart, [ImporterMesh] contains mesh data before various import steps, such as lod and shadow mesh generation, have taken place. Modify surface data by calling [method clear], followed by [method add_surface] for each surface.
 	</description>
 	<tutorials>
 	</tutorials>
@@ -37,7 +37,7 @@
 		<method name="clear">
 			<return type="void" />
 			<description>
-				Removes all surfaces and blend shapes from this [EditorSceneImporterMesh].
+				Removes all surfaces and blend shapes from this [ImporterMesh].
 			</description>
 		</method>
 		<method name="get_blend_shape_count" qualifiers="const">
@@ -69,7 +69,7 @@
 			<return type="ArrayMesh" />
 			<argument index="0" name="base_mesh" type="ArrayMesh" default="null" />
 			<description>
-				Returns the mesh data represented by this [EditorSceneImporterMesh] as a usable [ArrayMesh].
+				Returns the mesh data represented by this [ImporterMesh] as a usable [ArrayMesh].
 				This method caches the returned mesh, and subsequent calls will return the cached data until [method clear] is called.
 				If not yet cached and [code]base_mesh[/code] is provided, [code]base_mesh[/code] will be used and mutated.
 			</description>

+ 2 - 2
doc/classes/EditorSceneImporterMeshNode3D.xml → doc/classes/ImporterMeshInstance3D.xml

@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="UTF-8" ?>
-<class name="EditorSceneImporterMeshNode3D" inherits="Node3D" version="4.0">
+<class name="ImporterMeshInstance3D" inherits="Node3D" version="4.0">
 	<brief_description>
 	</brief_description>
 	<description>
@@ -7,7 +7,7 @@
 	<tutorials>
 	</tutorials>
 	<members>
-		<member name="mesh" type="EditorSceneImporterMesh" setter="set_mesh" getter="get_mesh">
+		<member name="mesh" type="ImporterMesh" setter="set_mesh" getter="get_mesh">
 		</member>
 		<member name="skeleton_path" type="NodePath" setter="set_skeleton_path" getter="get_skeleton_path" default="NodePath(&quot;&quot;)">
 		</member>

+ 1 - 3
editor/editor_node.cpp

@@ -49,6 +49,7 @@
 #include "core/version.h"
 #include "core/version_hash.gen.h"
 #include "main/main.h"
+#include "scene/3d/importer_mesh_instance_3d.h"
 #include "scene/gui/center_container.h"
 #include "scene/gui/control.h"
 #include "scene/gui/dialogs.h"
@@ -113,7 +114,6 @@
 #include "editor/import/resource_importer_texture_atlas.h"
 #include "editor/import/resource_importer_wav.h"
 #include "editor/import/scene_import_settings.h"
-#include "editor/import/scene_importer_mesh_node_3d.h"
 #include "editor/import_dock.h"
 #include "editor/multi_node_edit.h"
 #include "editor/node_dock.h"
@@ -3852,8 +3852,6 @@ void EditorNode::register_editor_types() {
 	GDREGISTER_CLASS(EditorSpinSlider);
 	GDREGISTER_CLASS(EditorResourcePicker);
 	GDREGISTER_CLASS(EditorScriptPicker);
-	GDREGISTER_CLASS(EditorSceneImporterMesh);
-	GDREGISTER_CLASS(EditorSceneImporterMeshNode3D);
 
 	GDREGISTER_VIRTUAL_CLASS(FileSystemDock);
 

+ 14 - 13
editor/import/editor_import_collada.cpp

@@ -33,8 +33,8 @@
 #include "core/os/os.h"
 #include "editor/editor_node.h"
 #include "editor/import/collada.h"
-#include "editor/import/scene_importer_mesh_node_3d.h"
 #include "scene/3d/camera_3d.h"
+#include "scene/3d/importer_mesh_instance_3d.h"
 #include "scene/3d/light_3d.h"
 #include "scene/3d/mesh_instance_3d.h"
 #include "scene/3d/node_3d.h"
@@ -42,6 +42,7 @@
 #include "scene/3d/skeleton_3d.h"
 #include "scene/animation/animation_player.h"
 #include "scene/resources/animation.h"
+#include "scene/resources/importer_mesh.h"
 #include "scene/resources/packed_scene.h"
 #include "scene/resources/surface_tool.h"
 
@@ -68,7 +69,7 @@ struct ColladaImport {
 
 	Map<String, NodeMap> node_map; //map from collada node to engine node
 	Map<String, String> node_name_map; //map from collada node to engine node
-	Map<String, Ref<EditorSceneImporterMesh>> mesh_cache;
+	Map<String, Ref<ImporterMesh>> mesh_cache;
 	Map<String, Ref<Curve3D>> curve_cache;
 	Map<String, Ref<Material>> material_cache;
 	Map<Collada::Node *, Skeleton3D *> skeleton_map;
@@ -87,7 +88,7 @@ struct ColladaImport {
 	Error _create_scene(Collada::Node *p_node, Node3D *p_parent);
 	Error _create_resources(Collada::Node *p_node, bool p_use_compression);
 	Error _create_material(const String &p_target);
-	Error _create_mesh_surfaces(bool p_optimize, Ref<EditorSceneImporterMesh> &p_mesh, const Map<String, Collada::NodeGeometry::Material> &p_material_map, const Collada::MeshData &meshdata, const Transform3D &p_local_xform, const Vector<int> &bone_remap, const Collada::SkinControllerData *p_skin_controller, const Collada::MorphControllerData *p_morph_data, Vector<Ref<EditorSceneImporterMesh>> p_morph_meshes = Vector<Ref<EditorSceneImporterMesh>>(), bool p_use_compression = false, bool p_use_mesh_material = false);
+	Error _create_mesh_surfaces(bool p_optimize, Ref<ImporterMesh> &p_mesh, const Map<String, Collada::NodeGeometry::Material> &p_material_map, const Collada::MeshData &meshdata, const Transform3D &p_local_xform, const Vector<int> &bone_remap, const Collada::SkinControllerData *p_skin_controller, const Collada::MorphControllerData *p_morph_data, Vector<Ref<ImporterMesh>> p_morph_meshes = Vector<Ref<ImporterMesh>>(), bool p_use_compression = false, bool p_use_mesh_material = false);
 	Error load(const String &p_path, int p_flags, bool p_force_make_tangents = false, bool p_use_compression = false);
 	void _fix_param_animation_tracks();
 	void create_animation(int p_clip, bool p_make_tracks_in_all_bones, bool p_import_value_tracks);
@@ -282,8 +283,8 @@ Error ColladaImport::_create_scene(Collada::Node *p_node, Node3D *p_parent) {
 				node = memnew(Path3D);
 			} else {
 				//mesh since nothing else
-				node = memnew(EditorSceneImporterMeshNode3D);
-				//Object::cast_to<EditorSceneImporterMeshNode3D>(node)->set_flag(GeometryInstance3D::FLAG_USE_BAKED_LIGHT, true);
+				node = memnew(ImporterMeshInstance3D);
+				//Object::cast_to<ImporterMeshInstance3D>(node)->set_flag(GeometryInstance3D::FLAG_USE_BAKED_LIGHT, true);
 			}
 		} break;
 		case Collada::Node::TYPE_SKELETON: {
@@ -457,7 +458,7 @@ Error ColladaImport::_create_material(const String &p_target) {
 	return OK;
 }
 
-Error ColladaImport::_create_mesh_surfaces(bool p_optimize, Ref<EditorSceneImporterMesh> &p_mesh, const Map<String, Collada::NodeGeometry::Material> &p_material_map, const Collada::MeshData &meshdata, const Transform3D &p_local_xform, const Vector<int> &bone_remap, const Collada::SkinControllerData *p_skin_controller, const Collada::MorphControllerData *p_morph_data, Vector<Ref<EditorSceneImporterMesh>> p_morph_meshes, bool p_use_compression, bool p_use_mesh_material) {
+Error ColladaImport::_create_mesh_surfaces(bool p_optimize, Ref<ImporterMesh> &p_mesh, const Map<String, Collada::NodeGeometry::Material> &p_material_map, const Collada::MeshData &meshdata, const Transform3D &p_local_xform, const Vector<int> &bone_remap, const Collada::SkinControllerData *p_skin_controller, const Collada::MorphControllerData *p_morph_data, Vector<Ref<ImporterMesh>> p_morph_meshes, bool p_use_compression, bool p_use_mesh_material) {
 	bool local_xform_mirror = p_local_xform.basis.determinant() < 0;
 
 	if (p_morph_data) {
@@ -1087,10 +1088,10 @@ Error ColladaImport::_create_resources(Collada::Node *p_node, bool p_use_compres
 			}
 		}
 
-		if (Object::cast_to<EditorSceneImporterMeshNode3D>(node)) {
+		if (Object::cast_to<ImporterMeshInstance3D>(node)) {
 			Collada::NodeGeometry *ng2 = static_cast<Collada::NodeGeometry *>(p_node);
 
-			EditorSceneImporterMeshNode3D *mi = Object::cast_to<EditorSceneImporterMeshNode3D>(node);
+			ImporterMeshInstance3D *mi = Object::cast_to<ImporterMeshInstance3D>(node);
 
 			ERR_FAIL_COND_V(!mi, ERR_BUG);
 
@@ -1099,7 +1100,7 @@ Error ColladaImport::_create_resources(Collada::Node *p_node, bool p_use_compres
 			String meshid;
 			Transform3D apply_xform;
 			Vector<int> bone_remap;
-			Vector<Ref<EditorSceneImporterMesh>> morphs;
+			Vector<Ref<ImporterMesh>> morphs;
 
 			if (ng2->controller) {
 				String ngsource = ng2->source;
@@ -1168,10 +1169,10 @@ Error ColladaImport::_create_resources(Collada::Node *p_node, bool p_use_compres
 							for (int i = 0; i < names.size(); i++) {
 								String meshid2 = names[i];
 								if (collada.state.mesh_data_map.has(meshid2)) {
-									Ref<EditorSceneImporterMesh> mesh = Ref<EditorSceneImporterMesh>(memnew(EditorSceneImporterMesh));
+									Ref<ImporterMesh> mesh = Ref<ImporterMesh>(memnew(ImporterMesh));
 									const Collada::MeshData &meshdata = collada.state.mesh_data_map[meshid2];
 									mesh->set_name(meshdata.name);
-									Error err = _create_mesh_surfaces(false, mesh, ng2->material_map, meshdata, apply_xform, bone_remap, skin, nullptr, Vector<Ref<EditorSceneImporterMesh>>(), false);
+									Error err = _create_mesh_surfaces(false, mesh, ng2->material_map, meshdata, apply_xform, bone_remap, skin, nullptr, Vector<Ref<ImporterMesh>>(), false);
 									ERR_FAIL_COND_V(err, err);
 
 									morphs.push_back(mesh);
@@ -1194,7 +1195,7 @@ Error ColladaImport::_create_resources(Collada::Node *p_node, bool p_use_compres
 				meshid = ng2->source;
 			}
 
-			Ref<EditorSceneImporterMesh> mesh;
+			Ref<ImporterMesh> mesh;
 			if (mesh_cache.has(meshid)) {
 				mesh = mesh_cache[meshid];
 			} else {
@@ -1202,7 +1203,7 @@ Error ColladaImport::_create_resources(Collada::Node *p_node, bool p_use_compres
 					//bleh, must ignore invalid
 
 					ERR_FAIL_COND_V(!collada.state.mesh_data_map.has(meshid), ERR_INVALID_DATA);
-					mesh = Ref<EditorSceneImporterMesh>(memnew(EditorSceneImporterMesh));
+					mesh = Ref<ImporterMesh>(memnew(ImporterMesh));
 					const Collada::MeshData &meshdata = collada.state.mesh_data_map[meshid];
 					String name = meshdata.name;
 					if (name == "") {

+ 2 - 2
editor/import/editor_importer_bake_reset.cpp

@@ -33,8 +33,8 @@
 #include "core/error/error_list.h"
 #include "core/error/error_macros.h"
 #include "core/math/transform_3d.h"
-#include "editor/import/scene_importer_mesh_node_3d.h"
 #include "resource_importer_scene.h"
+#include "scene/3d/importer_mesh_instance_3d.h"
 #include "scene/3d/mesh_instance_3d.h"
 #include "scene/3d/node_3d.h"
 #include "scene/3d/skeleton_3d.h"
@@ -71,7 +71,7 @@ void BakeReset::_bake_animation_pose(Node *scene, const String &p_bake_anim) {
 	while (!queue.is_empty()) {
 		List<Node *>::Element *E = queue.front();
 		Node *node = E->get();
-		EditorSceneImporterMeshNode3D *editor_mesh_3d = scene->cast_to<EditorSceneImporterMeshNode3D>(node);
+		ImporterMeshInstance3D *editor_mesh_3d = scene->cast_to<ImporterMeshInstance3D>(node);
 		MeshInstance3D *mesh_3d = scene->cast_to<MeshInstance3D>(node);
 		if (scene->cast_to<Skeleton3D>(node)) {
 			Skeleton3D *skeleton = Object::cast_to<Skeleton3D>(node);

+ 4 - 4
editor/import/resource_importer_obj.cpp

@@ -32,10 +32,10 @@
 
 #include "core/io/file_access.h"
 #include "core/io/resource_saver.h"
-#include "editor/import/scene_importer_mesh.h"
-#include "editor/import/scene_importer_mesh_node_3d.h"
+#include "scene/3d/importer_mesh_instance_3d.h"
 #include "scene/3d/mesh_instance_3d.h"
 #include "scene/3d/node_3d.h"
+#include "scene/resources/importer_mesh.h"
 #include "scene/resources/mesh.h"
 #include "scene/resources/surface_tool.h"
 
@@ -439,13 +439,13 @@ Node *EditorOBJImporter::import_scene(const String &p_path, uint32_t p_flags, in
 	Node3D *scene = memnew(Node3D);
 
 	for (const Ref<Mesh> &m : meshes) {
-		Ref<EditorSceneImporterMesh> mesh;
+		Ref<ImporterMesh> mesh;
 		mesh.instantiate();
 		for (int i = 0; i < m->get_surface_count(); i++) {
 			mesh->add_surface(m->surface_get_primitive_type(i), m->surface_get_arrays(i), Array(), Dictionary(), m->surface_get_material(i));
 		}
 
-		EditorSceneImporterMeshNode3D *mi = memnew(EditorSceneImporterMeshNode3D);
+		ImporterMeshInstance3D *mi = memnew(ImporterMeshInstance3D);
 		mi->set_mesh(mesh);
 		mi->set_name(m->get_name());
 		scene->add_child(mi);

+ 32 - 31
editor/import/resource_importer_scene.cpp

@@ -34,9 +34,9 @@
 #include "editor/editor_node.h"
 #include "editor/import/editor_importer_bake_reset.h"
 #include "editor/import/scene_import_settings.h"
-#include "editor/import/scene_importer_mesh_node_3d.h"
 #include "scene/3d/area_3d.h"
 #include "scene/3d/collision_shape_3d.h"
+#include "scene/3d/importer_mesh_instance_3d.h"
 #include "scene/3d/mesh_instance_3d.h"
 #include "scene/3d/navigation_region_3d.h"
 #include "scene/3d/physics_body_3d.h"
@@ -44,6 +44,7 @@
 #include "scene/animation/animation_player.h"
 #include "scene/resources/animation.h"
 #include "scene/resources/box_shape_3d.h"
+#include "scene/resources/importer_mesh.h"
 #include "scene/resources/packed_scene.h"
 #include "scene/resources/resource_format_text.h"
 #include "scene/resources/separation_ray_shape_3d.h"
@@ -233,7 +234,7 @@ static String _fixstr(const String &p_what, const String &p_str) {
 	return what;
 }
 
-static void _pre_gen_shape_list(Ref<EditorSceneImporterMesh> &mesh, Vector<Ref<Shape3D>> &r_shape_list, bool p_convex) {
+static void _pre_gen_shape_list(Ref<ImporterMesh> &mesh, Vector<Ref<Shape3D>> &r_shape_list, bool p_convex) {
 	ERR_FAIL_NULL_MSG(mesh, "Cannot generate shape list with null mesh value");
 	if (!p_convex) {
 		Ref<Shape3D> shape = mesh->create_trimesh_shape();
@@ -249,7 +250,7 @@ static void _pre_gen_shape_list(Ref<EditorSceneImporterMesh> &mesh, Vector<Ref<S
 	}
 }
 
-Node *ResourceImporterScene::_pre_fix_node(Node *p_node, Node *p_root, Map<Ref<EditorSceneImporterMesh>, Vector<Ref<Shape3D>>> &collision_map) {
+Node *ResourceImporterScene::_pre_fix_node(Node *p_node, Node *p_root, Map<Ref<ImporterMesh>, Vector<Ref<Shape3D>>> &collision_map) {
 	// children first
 	for (int i = 0; i < p_node->get_child_count(); i++) {
 		Node *r = _pre_fix_node(p_node->get_child(i), p_root, collision_map);
@@ -267,10 +268,10 @@ Node *ResourceImporterScene::_pre_fix_node(Node *p_node, Node *p_root, Map<Ref<E
 		return nullptr;
 	}
 
-	if (Object::cast_to<EditorSceneImporterMeshNode3D>(p_node)) {
-		EditorSceneImporterMeshNode3D *mi = Object::cast_to<EditorSceneImporterMeshNode3D>(p_node);
+	if (Object::cast_to<ImporterMeshInstance3D>(p_node)) {
+		ImporterMeshInstance3D *mi = Object::cast_to<ImporterMeshInstance3D>(p_node);
 
-		Ref<EditorSceneImporterMesh> m = mi->get_mesh();
+		Ref<ImporterMesh> m = mi->get_mesh();
 
 		if (m.is_valid()) {
 			for (int i = 0; i < m->get_surface_count(); i++) {
@@ -331,9 +332,9 @@ Node *ResourceImporterScene::_pre_fix_node(Node *p_node, Node *p_root, Map<Ref<E
 		if (isroot) {
 			return p_node;
 		}
-		EditorSceneImporterMeshNode3D *mi = Object::cast_to<EditorSceneImporterMeshNode3D>(p_node);
+		ImporterMeshInstance3D *mi = Object::cast_to<ImporterMeshInstance3D>(p_node);
 		if (mi) {
-			Ref<EditorSceneImporterMesh> mesh = mi->get_mesh();
+			Ref<ImporterMesh> mesh = mi->get_mesh();
 
 			if (mesh.is_valid()) {
 				Vector<Ref<Shape3D>> shapes;
@@ -398,13 +399,13 @@ Node *ResourceImporterScene::_pre_fix_node(Node *p_node, Node *p_root, Map<Ref<E
 			colshape->set_owner(sb->get_owner());
 		}
 
-	} else if (_teststr(name, "rigid") && Object::cast_to<EditorSceneImporterMeshNode3D>(p_node)) {
+	} else if (_teststr(name, "rigid") && Object::cast_to<ImporterMeshInstance3D>(p_node)) {
 		if (isroot) {
 			return p_node;
 		}
 
-		EditorSceneImporterMeshNode3D *mi = Object::cast_to<EditorSceneImporterMeshNode3D>(p_node);
-		Ref<EditorSceneImporterMesh> mesh = mi->get_mesh();
+		ImporterMeshInstance3D *mi = Object::cast_to<ImporterMeshInstance3D>(p_node);
+		Ref<ImporterMesh> mesh = mi->get_mesh();
 
 		if (mesh.is_valid()) {
 			Vector<Ref<Shape3D>> shapes;
@@ -426,10 +427,10 @@ Node *ResourceImporterScene::_pre_fix_node(Node *p_node, Node *p_root, Map<Ref<E
 			_add_shapes(rigid_body, shapes);
 		}
 
-	} else if ((_teststr(name, "col") || (_teststr(name, "convcol"))) && Object::cast_to<EditorSceneImporterMeshNode3D>(p_node)) {
-		EditorSceneImporterMeshNode3D *mi = Object::cast_to<EditorSceneImporterMeshNode3D>(p_node);
+	} else if ((_teststr(name, "col") || (_teststr(name, "convcol"))) && Object::cast_to<ImporterMeshInstance3D>(p_node)) {
+		ImporterMeshInstance3D *mi = Object::cast_to<ImporterMeshInstance3D>(p_node);
 
-		Ref<EditorSceneImporterMesh> mesh = mi->get_mesh();
+		Ref<ImporterMesh> mesh = mi->get_mesh();
 
 		if (mesh.is_valid()) {
 			Vector<Ref<Shape3D>> shapes;
@@ -465,14 +466,14 @@ Node *ResourceImporterScene::_pre_fix_node(Node *p_node, Node *p_root, Map<Ref<E
 			}
 		}
 
-	} else if (_teststr(name, "navmesh") && Object::cast_to<EditorSceneImporterMeshNode3D>(p_node)) {
+	} else if (_teststr(name, "navmesh") && Object::cast_to<ImporterMeshInstance3D>(p_node)) {
 		if (isroot) {
 			return p_node;
 		}
 
-		EditorSceneImporterMeshNode3D *mi = Object::cast_to<EditorSceneImporterMeshNode3D>(p_node);
+		ImporterMeshInstance3D *mi = Object::cast_to<ImporterMeshInstance3D>(p_node);
 
-		Ref<EditorSceneImporterMesh> mesh = mi->get_mesh();
+		Ref<ImporterMesh> mesh = mi->get_mesh();
 		ERR_FAIL_COND_V(mesh.is_null(), nullptr);
 		NavigationRegion3D *nmi = memnew(NavigationRegion3D);
 
@@ -484,12 +485,12 @@ Node *ResourceImporterScene::_pre_fix_node(Node *p_node, Node *p_root, Map<Ref<E
 		memdelete(p_node);
 		p_node = nmi;
 
-	} else if (Object::cast_to<EditorSceneImporterMeshNode3D>(p_node)) {
+	} else if (Object::cast_to<ImporterMeshInstance3D>(p_node)) {
 		//last attempt, maybe collision inside the mesh data
 
-		EditorSceneImporterMeshNode3D *mi = Object::cast_to<EditorSceneImporterMeshNode3D>(p_node);
+		ImporterMeshInstance3D *mi = Object::cast_to<ImporterMeshInstance3D>(p_node);
 
-		Ref<EditorSceneImporterMesh> mesh = mi->get_mesh();
+		Ref<ImporterMesh> mesh = mi->get_mesh();
 		if (!mesh.is_null()) {
 			Vector<Ref<Shape3D>> shapes;
 			if (collision_map.has(mesh)) {
@@ -517,7 +518,7 @@ Node *ResourceImporterScene::_pre_fix_node(Node *p_node, Node *p_root, Map<Ref<E
 	return p_node;
 }
 
-Node *ResourceImporterScene::_post_fix_node(Node *p_node, Node *p_root, Map<Ref<EditorSceneImporterMesh>, Vector<Ref<Shape3D>>> &collision_map, Set<Ref<EditorSceneImporterMesh>> &r_scanned_meshes, const Dictionary &p_node_data, const Dictionary &p_material_data, const Dictionary &p_animation_data, float p_animation_fps) {
+Node *ResourceImporterScene::_post_fix_node(Node *p_node, Node *p_root, Map<Ref<ImporterMesh>, Vector<Ref<Shape3D>>> &collision_map, Set<Ref<ImporterMesh>> &r_scanned_meshes, const Dictionary &p_node_data, const Dictionary &p_material_data, const Dictionary &p_animation_data, float p_animation_fps) {
 	// children first
 	for (int i = 0; i < p_node->get_child_count(); i++) {
 		Node *r = _post_fix_node(p_node->get_child(i), p_root, collision_map, r_scanned_meshes, p_node_data, p_material_data, p_animation_data, p_animation_fps);
@@ -546,10 +547,10 @@ Node *ResourceImporterScene::_post_fix_node(Node *p_node, Node *p_root, Map<Ref<
 		return nullptr;
 	}
 
-	if (Object::cast_to<EditorSceneImporterMeshNode3D>(p_node)) {
-		EditorSceneImporterMeshNode3D *mi = Object::cast_to<EditorSceneImporterMeshNode3D>(p_node);
+	if (Object::cast_to<ImporterMeshInstance3D>(p_node)) {
+		ImporterMeshInstance3D *mi = Object::cast_to<ImporterMeshInstance3D>(p_node);
 
-		Ref<EditorSceneImporterMesh> m = mi->get_mesh();
+		Ref<ImporterMesh> m = mi->get_mesh();
 
 		if (m.is_valid()) {
 			if (!r_scanned_meshes.has(m)) {
@@ -669,10 +670,10 @@ Node *ResourceImporterScene::_post_fix_node(Node *p_node, Node *p_root, Map<Ref<
 	}
 
 	//navmesh (node may have changed type above)
-	if (Object::cast_to<EditorSceneImporterMeshNode3D>(p_node)) {
-		EditorSceneImporterMeshNode3D *mi = Object::cast_to<EditorSceneImporterMeshNode3D>(p_node);
+	if (Object::cast_to<ImporterMeshInstance3D>(p_node)) {
+		ImporterMeshInstance3D *mi = Object::cast_to<ImporterMeshInstance3D>(p_node);
 
-		Ref<EditorSceneImporterMesh> m = mi->get_mesh();
+		Ref<ImporterMesh> m = mi->get_mesh();
 
 		if (m.is_valid()) {
 			if (node_settings.has("generate/navmesh")) {
@@ -1247,7 +1248,7 @@ Ref<Animation> ResourceImporterScene::import_animation_from_other_importer(Edito
 }
 
 void ResourceImporterScene::_generate_meshes(Node *p_node, const Dictionary &p_mesh_data, bool p_generate_lods, bool p_create_shadow_meshes, LightBakeMode p_light_bake_mode, float p_lightmap_texel_size, const Vector<uint8_t> &p_src_lightmap_cache, Vector<Vector<uint8_t>> &r_lightmap_caches) {
-	EditorSceneImporterMeshNode3D *src_mesh_node = Object::cast_to<EditorSceneImporterMeshNode3D>(p_node);
+	ImporterMeshInstance3D *src_mesh_node = Object::cast_to<ImporterMeshInstance3D>(p_node);
 	if (src_mesh_node) {
 		//is mesh
 		MeshInstance3D *mesh_node = memnew(MeshInstance3D);
@@ -1452,7 +1453,7 @@ Node *ResourceImporterScene::pre_import(const String &p_source_file) {
 		return nullptr;
 	}
 
-	Map<Ref<EditorSceneImporterMesh>, Vector<Ref<Shape3D>>> collision_map;
+	Map<Ref<ImporterMesh>, Vector<Ref<Shape3D>>> collision_map;
 
 	_pre_fix_node(scene, scene, collision_map);
 
@@ -1527,8 +1528,8 @@ Error ResourceImporterScene::import(const String &p_source_file, const String &p
 		animation_data = subresources["animations"];
 	}
 
-	Set<Ref<EditorSceneImporterMesh>> scanned_meshes;
-	Map<Ref<EditorSceneImporterMesh>, Vector<Ref<Shape3D>>> collision_map;
+	Set<Ref<ImporterMesh>> scanned_meshes;
+	Map<Ref<ImporterMesh>, Vector<Ref<Shape3D>>> collision_map;
 
 	_pre_fix_node(scene, scene, collision_map);
 	_post_fix_node(scene, scene, collision_map, scanned_meshes, node_data, material_data, animation_data, fps);

+ 3 - 3
editor/import/resource_importer_scene.h

@@ -41,7 +41,7 @@
 class Material;
 class AnimationPlayer;
 
-class EditorSceneImporterMesh;
+class ImporterMesh;
 class EditorSceneImporter : public RefCounted {
 	GDCLASS(EditorSceneImporter, RefCounted);
 
@@ -181,8 +181,8 @@ public:
 	// Import scenes *after* everything else (such as textures).
 	virtual int get_import_order() const override { return ResourceImporter::IMPORT_ORDER_SCENE; }
 
-	Node *_pre_fix_node(Node *p_node, Node *p_root, Map<Ref<EditorSceneImporterMesh>, Vector<Ref<Shape3D>>> &collision_map);
-	Node *_post_fix_node(Node *p_node, Node *p_root, Map<Ref<EditorSceneImporterMesh>, Vector<Ref<Shape3D>>> &collision_map, Set<Ref<EditorSceneImporterMesh>> &r_scanned_meshes, const Dictionary &p_node_data, const Dictionary &p_material_data, const Dictionary &p_animation_data, float p_animation_fps);
+	Node *_pre_fix_node(Node *p_node, Node *p_root, Map<Ref<ImporterMesh>, Vector<Ref<Shape3D>>> &collision_map);
+	Node *_post_fix_node(Node *p_node, Node *p_root, Map<Ref<ImporterMesh>, Vector<Ref<Shape3D>>> &collision_map, Set<Ref<ImporterMesh>> &r_scanned_meshes, const Dictionary &p_node_data, const Dictionary &p_material_data, const Dictionary &p_animation_data, float p_animation_fps);
 
 	Ref<Animation> _save_animation_to_file(Ref<Animation> anim, bool p_save_to_file, String p_save_to_path, bool p_keep_custom_tracks);
 	void _create_clips(AnimationPlayer *anim, const Array &p_clips, bool p_bake_all);

+ 4 - 3
editor/import/scene_import_settings.cpp

@@ -31,7 +31,8 @@
 #include "scene_import_settings.h"
 #include "editor/editor_node.h"
 #include "editor/editor_scale.h"
-#include "editor/import/scene_importer_mesh_node_3d.h"
+#include "scene/3d/importer_mesh_instance_3d.h"
+#include "scene/resources/importer_mesh.h"
 #include "scene/resources/surface_tool.h"
 
 class SceneImportSettingsData : public Object {
@@ -240,7 +241,7 @@ void SceneImportSettings::_fill_scene(Node *p_node, TreeItem *p_parent_item) {
 		p_node->set_meta("import_id", import_id);
 	}
 
-	EditorSceneImporterMeshNode3D *src_mesh_node = Object::cast_to<EditorSceneImporterMeshNode3D>(p_node);
+	ImporterMeshInstance3D *src_mesh_node = Object::cast_to<ImporterMeshInstance3D>(p_node);
 
 	if (src_mesh_node) {
 		MeshInstance3D *mesh_node = memnew(MeshInstance3D);
@@ -249,7 +250,7 @@ void SceneImportSettings::_fill_scene(Node *p_node, TreeItem *p_parent_item) {
 		mesh_node->set_skin(src_mesh_node->get_skin());
 		mesh_node->set_skeleton_path(src_mesh_node->get_skeleton_path());
 		if (src_mesh_node->get_mesh().is_valid()) {
-			Ref<EditorSceneImporterMesh> editor_mesh = src_mesh_node->get_mesh();
+			Ref<ImporterMesh> editor_mesh = src_mesh_node->get_mesh();
 			mesh_node->set_mesh(editor_mesh->get_mesh());
 		}
 

+ 4 - 3
modules/fbx/data/fbx_mesh_data.cpp

@@ -31,6 +31,7 @@
 #include "fbx_mesh_data.h"
 
 #include "core/templates/local_vector.h"
+#include "scene/resources/importer_mesh.h"
 #include "scene/resources/mesh.h"
 #include "scene/resources/surface_tool.h"
 
@@ -101,7 +102,7 @@ HashMap<int, Vector2> collect_uv(const Vector<VertexData<Vector2>> *p_data, Hash
 	return collection;
 }
 
-EditorSceneImporterMeshNode3D *FBXMeshData::create_fbx_mesh(const ImportState &state, const FBXDocParser::MeshGeometry *p_mesh_geometry, const FBXDocParser::Model *model, bool use_compression) {
+ImporterMeshInstance3D *FBXMeshData::create_fbx_mesh(const ImportState &state, const FBXDocParser::MeshGeometry *p_mesh_geometry, const FBXDocParser::Model *model, bool use_compression) {
 	mesh_geometry = p_mesh_geometry;
 	// todo: make this just use a uint64_t FBX ID this is a copy of our original materials unfortunately.
 	const std::vector<const FBXDocParser::Material *> &material_lookup = model->GetMaterials();
@@ -344,7 +345,7 @@ EditorSceneImporterMeshNode3D *FBXMeshData::create_fbx_mesh(const ImportState &s
 	}
 
 	// Phase 6. Compose the mesh and return it.
-	Ref<EditorSceneImporterMesh> mesh;
+	Ref<ImporterMesh> mesh;
 	mesh.instantiate();
 
 	// Add blend shape info.
@@ -380,7 +381,7 @@ EditorSceneImporterMeshNode3D *FBXMeshData::create_fbx_mesh(const ImportState &s
 		in_mesh_surface_id += 1;
 	}
 
-	EditorSceneImporterMeshNode3D *godot_mesh = memnew(EditorSceneImporterMeshNode3D);
+	ImporterMeshInstance3D *godot_mesh = memnew(ImporterMeshInstance3D);
 	godot_mesh->set_mesh(mesh);
 	const String name = ImportUtils::FBXNodeToName(model->Name());
 	godot_mesh->set_name(name); // hurry up compiling >.<

+ 3 - 3
modules/fbx/data/fbx_mesh_data.h

@@ -35,7 +35,7 @@
 #include "core/templates/local_vector.h"
 #include "core/templates/ordered_hash_map.h"
 #include "editor/import/resource_importer_scene.h"
-#include "editor/import/scene_importer_mesh_node_3d.h"
+#include "scene/3d/importer_mesh_instance_3d.h"
 #include "scene/3d/mesh_instance_3d.h"
 #include "scene/resources/surface_tool.h"
 
@@ -98,7 +98,7 @@ struct FBXMeshData : RefCounted {
 	// translate fbx mesh data from document context to FBX Mesh Geometry Context
 	bool valid_weight_indexes = false;
 
-	EditorSceneImporterMeshNode3D *create_fbx_mesh(const ImportState &state, const FBXDocParser::MeshGeometry *p_mesh_geometry, const FBXDocParser::Model *model, bool use_compression);
+	ImporterMeshInstance3D *create_fbx_mesh(const ImportState &state, const FBXDocParser::MeshGeometry *p_mesh_geometry, const FBXDocParser::Model *model, bool use_compression);
 
 	void gen_weight_info(Ref<SurfaceTool> st, int vertex_id) const;
 
@@ -107,7 +107,7 @@ struct FBXMeshData : RefCounted {
 	int max_weight_count = 0;
 	uint64_t armature_id = 0;
 	bool valid_armature_id = false;
-	EditorSceneImporterMeshNode3D *godot_mesh_instance = nullptr;
+	ImporterMeshInstance3D *godot_mesh_instance = nullptr;
 
 private:
 	void sanitize_vertex_weights(const ImportState &state);

+ 3 - 3
modules/fbx/editor_scene_importer_fbx.cpp

@@ -40,9 +40,9 @@
 #include "editor/editor_log.h"
 #include "editor/editor_node.h"
 #include "editor/import/resource_importer_scene.h"
-#include "editor/import/scene_importer_mesh_node_3d.h"
 #include "scene/3d/bone_attachment_3d.h"
 #include "scene/3d/camera_3d.h"
+#include "scene/3d/importer_mesh_instance_3d.h"
 #include "scene/3d/light_3d.h"
 #include "scene/main/node.h"
 #include "scene/resources/material.h"
@@ -627,7 +627,7 @@ Node3D *EditorSceneImporterFBX::_generate_scene(
 				node_element;
 				node_element = node_element->next()) {
 			Ref<FBXNode> fbx_node = node_element->get();
-			EditorSceneImporterMeshNode3D *mesh_node = nullptr;
+			ImporterMeshInstance3D *mesh_node = nullptr;
 			Ref<FBXMeshData> mesh_data_precached;
 
 			// check for valid geometry
@@ -768,7 +768,7 @@ Node3D *EditorSceneImporterFBX::_generate_scene(
 	for (KeyValue<uint64_t, Ref<FBXMeshData>> &mesh_data : state.renderer_mesh_data) {
 		Ref<FBXMeshData> mesh = mesh_data.value;
 		const uint64_t mesh_id = mesh_data.key;
-		EditorSceneImporterMeshNode3D *mesh_instance = mesh->godot_mesh_instance;
+		ImporterMeshInstance3D *mesh_instance = mesh->godot_mesh_instance;
 		const int mesh_weights = mesh->max_weight_count;
 		Ref<FBXSkeleton> skeleton;
 		const bool valid_armature = mesh->valid_armature_id;

+ 3 - 1
modules/gltf/config.py

@@ -1,5 +1,5 @@
 def can_build(env, platform):
-    return env["tools"] and not env["disable_3d"]
+    return not env["disable_3d"]
 
 
 def configure(env):
@@ -22,6 +22,8 @@ def get_doc_classes():
         "GLTFSpecGloss",
         "GLTFState",
         "GLTFTexture",
+        "GLTFDocumentExtension",
+        "GLTFDocumentExtensionConvertImporterMesh",
     ]
 
 

+ 4 - 0
modules/gltf/doc_classes/GLTFDocument.xml

@@ -30,4 +30,8 @@
 			</description>
 		</method>
 	</methods>
+	<members>
+		<member name="extensions" type="GLTFDocumentExtension[]" setter="set_extensions" getter="get_extensions" default="[Object(GLTFDocumentExtensionConvertImporterMesh,&quot;resource_local_to_scene&quot;:false,&quot;resource_name&quot;:&quot;&quot;,&quot;script&quot;:null)]">
+		</member>
+	</members>
 </class>

+ 73 - 0
modules/gltf/doc_classes/GLTFDocumentExtension.xml

@@ -0,0 +1,73 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="GLTFDocumentExtension" inherits="Resource" version="4.0">
+	<brief_description>
+	</brief_description>
+	<description>
+	</description>
+	<tutorials>
+	</tutorials>
+	<methods>
+		<method name="export_post">
+			<return type="int" enum="Error" />
+			<argument index="0" name="document" type="GLTFDocument" />
+			<description>
+			</description>
+		</method>
+		<method name="export_preflight">
+			<return type="int" enum="Error" />
+			<argument index="0" name="document" type="GLTFDocument" />
+			<argument index="1" name="node" type="Node" />
+			<description>
+			</description>
+		</method>
+		<method name="get_export_setting" qualifiers="const">
+			<return type="Variant" />
+			<argument index="0" name="key" type="StringName" />
+			<description>
+			</description>
+		</method>
+		<method name="get_export_setting_keys" qualifiers="const">
+			<return type="Array" />
+			<description>
+			</description>
+		</method>
+		<method name="get_import_setting" qualifiers="const">
+			<return type="Variant" />
+			<argument index="0" name="key" type="StringName" />
+			<description>
+			</description>
+		</method>
+		<method name="get_import_setting_keys" qualifiers="const">
+			<return type="Array" />
+			<description>
+			</description>
+		</method>
+		<method name="import_post">
+			<return type="int" enum="Error" />
+			<argument index="0" name="document" type="GLTFDocument" />
+			<argument index="1" name="node" type="Node" />
+			<description>
+			</description>
+		</method>
+		<method name="import_preflight">
+			<return type="int" enum="Error" />
+			<argument index="0" name="document" type="GLTFDocument" />
+			<description>
+			</description>
+		</method>
+		<method name="set_export_setting">
+			<return type="void" />
+			<argument index="0" name="key" type="StringName" />
+			<argument index="1" name="value" type="Variant" />
+			<description>
+			</description>
+		</method>
+		<method name="set_import_setting">
+			<return type="void" />
+			<argument index="0" name="key" type="StringName" />
+			<argument index="1" name="value" type="Variant" />
+			<description>
+			</description>
+		</method>
+	</methods>
+</class>

+ 9 - 0
modules/gltf/doc_classes/GLTFDocumentExtensionConvertImporterMesh.xml

@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="GLTFDocumentExtensionConvertImporterMesh" inherits="GLTFDocumentExtension" version="4.0">
+	<brief_description>
+	</brief_description>
+	<description>
+	</description>
+	<tutorials>
+	</tutorials>
+</class>

+ 1 - 1
modules/gltf/doc_classes/GLTFMesh.xml

@@ -9,7 +9,7 @@
 	<members>
 		<member name="blend_weights" type="PackedFloat32Array" setter="set_blend_weights" getter="get_blend_weights" default="PackedFloat32Array()">
 		</member>
-		<member name="mesh" type="EditorSceneImporterMesh" setter="set_mesh" getter="get_mesh">
+		<member name="mesh" type="ImporterMesh" setter="set_mesh" getter="get_mesh">
 		</member>
 	</members>
 </class>

+ 3 - 0
modules/gltf/editor_scene_exporter_gltf_plugin.cpp

@@ -28,6 +28,7 @@
 /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
 /*************************************************************************/
 
+#if TOOLS_ENABLED
 #include "editor_scene_exporter_gltf_plugin.h"
 #include "core/config/project_settings.h"
 #include "core/error/error_list.h"
@@ -93,3 +94,5 @@ void SceneExporterGLTFPlugin::convert_scene_to_gltf2() {
 	file_export_lib->set_current_file(filename + String(".gltf"));
 	file_export_lib->popup_centered_ratio();
 }
+
+#endif // TOOLS_ENABLED

+ 3 - 1
modules/gltf/editor_scene_exporter_gltf_plugin.h

@@ -31,7 +31,9 @@
 #ifndef EDITOR_SCENE_EXPORTER_GLTF_PLUGIN_H
 #define EDITOR_SCENE_EXPORTER_GLTF_PLUGIN_H
 
+#if TOOLS_ENABLED
 #include "editor/editor_plugin.h"
+
 #include "editor_scene_importer_gltf.h"
 
 class SceneExporterGLTFPlugin : public EditorPlugin {
@@ -47,5 +49,5 @@ public:
 	bool has_main_screen() const override;
 	SceneExporterGLTFPlugin(class EditorNode *p_node);
 };
-
+#endif // TOOLS_ENABLED
 #endif // EDITOR_SCENE_EXPORTER_GLTF_PLUGIN_H

+ 3 - 0
modules/gltf/editor_scene_importer_gltf.cpp

@@ -28,6 +28,7 @@
 /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
 /*************************************************************************/
 
+#if TOOLS_ENABLED
 #include "editor_scene_importer_gltf.h"
 
 #include "gltf_document.h"
@@ -60,3 +61,5 @@ Ref<Animation> EditorSceneImporterGLTF::import_animation(const String &p_path,
 		int p_bake_fps) {
 	return Ref<Animation>();
 }
+
+#endif // TOOLS_ENABLED

+ 4 - 3
modules/gltf/editor_scene_importer_gltf.h

@@ -30,16 +30,17 @@
 
 #ifndef EDITOR_SCENE_IMPORTER_GLTF_H
 #define EDITOR_SCENE_IMPORTER_GLTF_H
-
+#ifdef TOOLS_ENABLED
 #include "gltf_state.h"
 
+#include "gltf_document_extension.h"
+
 #include "editor/import/resource_importer_scene.h"
 #include "scene/main/node.h"
 #include "scene/resources/packed_scene.h"
 
 class Animation;
 
-#ifdef TOOLS_ENABLED
 class EditorSceneImporterGLTF : public EditorSceneImporter {
 	GDCLASS(EditorSceneImporterGLTF, EditorSceneImporter);
 
@@ -50,5 +51,5 @@ public:
 	virtual Ref<Animation> import_animation(const String &p_path,
 			uint32_t p_flags, int p_bake_fps) override;
 };
-#endif
+#endif // TOOLS_ENABLED
 #endif // EDITOR_SCENE_IMPORTER_GLTF_H

+ 2 - 0
modules/gltf/gltf_accessor.cpp

@@ -30,6 +30,8 @@
 
 #include "gltf_accessor.h"
 
+#include "gltf_document_extension.h"
+
 void GLTFAccessor::_bind_methods() {
 	ClassDB::bind_method(D_METHOD("get_buffer_view"), &GLTFAccessor::get_buffer_view);
 	ClassDB::bind_method(D_METHOD("set_buffer_view", "buffer_view"), &GLTFAccessor::set_buffer_view);

+ 2 - 0
modules/gltf/gltf_accessor.h

@@ -32,7 +32,9 @@
 #define GLTF_ACCESSOR_H
 
 #include "core/io/resource.h"
+
 #include "gltf_document.h"
+#include "gltf_document_extension.h"
 
 struct GLTFAccessor : public Resource {
 	GDCLASS(GLTFAccessor, Resource);

+ 2 - 0
modules/gltf/gltf_buffer_view.cpp

@@ -30,6 +30,8 @@
 
 #include "gltf_buffer_view.h"
 
+#include "gltf_document_extension.h"
+
 void GLTFBufferView::_bind_methods() {
 	ClassDB::bind_method(D_METHOD("get_buffer"), &GLTFBufferView::get_buffer);
 	ClassDB::bind_method(D_METHOD("set_buffer", "buffer"), &GLTFBufferView::set_buffer);

+ 199 - 122
modules/gltf/gltf_document.cpp

@@ -33,6 +33,8 @@
 #include "gltf_accessor.h"
 #include "gltf_animation.h"
 #include "gltf_camera.h"
+#include "gltf_document_extension.h"
+#include "gltf_document_extension_convert_importer_mesh.h"
 #include "gltf_light.h"
 #include "gltf_mesh.h"
 #include "gltf_node.h"
@@ -49,6 +51,7 @@
 #include "core/io/json.h"
 #include "core/math/disjoint_set.h"
 #include "core/math/vector2.h"
+#include "core/variant/dictionary.h"
 #include "core/variant/typed_array.h"
 #include "core/variant/variant.h"
 #include "core/version.h"
@@ -57,8 +60,12 @@
 #include "editor/import/resource_importer_scene.h"
 #include "scene/2d/node_2d.h"
 #include "scene/3d/camera_3d.h"
+#include "scene/3d/mesh_instance_3d.h"
 #include "scene/3d/multimesh_instance_3d.h"
 #include "scene/animation/animation_player.h"
+#include "scene/resources/importer_mesh.h"
+#include "scene/resources/mesh.h"
+#include "scene/resources/multimesh.h"
 #include "scene/resources/surface_tool.h"
 
 #include "modules/modules_enabled.gen.h"
@@ -2101,7 +2108,7 @@ Error GLTFDocument::_serialize_meshes(Ref<GLTFState> state) {
 	Array meshes;
 	for (GLTFMeshIndex gltf_mesh_i = 0; gltf_mesh_i < state->meshes.size(); gltf_mesh_i++) {
 		print_verbose("glTF: Serializing mesh: " + itos(gltf_mesh_i));
-		Ref<EditorSceneImporterMesh> import_mesh = state->meshes.write[gltf_mesh_i]->get_mesh();
+		Ref<ImporterMesh> import_mesh = state->meshes.write[gltf_mesh_i]->get_mesh();
 		if (import_mesh.is_null()) {
 			continue;
 		}
@@ -2493,7 +2500,7 @@ Error GLTFDocument::_parse_meshes(Ref<GLTFState> state) {
 		Array primitives = d["primitives"];
 		const Dictionary &extras = d.has("extras") ? (Dictionary)d["extras"] :
 													   Dictionary();
-		Ref<EditorSceneImporterMesh> import_mesh;
+		Ref<ImporterMesh> import_mesh;
 		import_mesh.instantiate();
 		String mesh_name = "mesh";
 		if (d.has("name") && !String(d["name"]).is_empty()) {
@@ -2732,17 +2739,18 @@ Error GLTFDocument::_parse_meshes(Ref<GLTFState> state) {
 
 			bool generate_tangents = (primitive == Mesh::PRIMITIVE_TRIANGLES && !a.has("TANGENT") && a.has("TEXCOORD_0") && a.has("NORMAL"));
 
+			Ref<SurfaceTool> mesh_surface_tool;
+			mesh_surface_tool.instantiate();
+			mesh_surface_tool->create_from_triangle_arrays(array);
+			if (a.has("JOINTS_0") && a.has("JOINTS_1")) {
+				mesh_surface_tool->set_skin_weight_count(SurfaceTool::SKIN_8_WEIGHTS);
+			}
+			mesh_surface_tool->index();
 			if (generate_tangents) {
 				//must generate mikktspace tangents.. ergh..
-				Ref<SurfaceTool> st;
-				st.instantiate();
-				st->create_from_triangle_arrays(array);
-				if (a.has("JOINTS_0") && a.has("JOINTS_1")) {
-					st->set_skin_weight_count(SurfaceTool::SKIN_8_WEIGHTS);
-				}
-				st->generate_tangents();
-				array = st->commit_to_arrays();
+				mesh_surface_tool->generate_tangents();
 			}
+			array = mesh_surface_tool->commit_to_arrays();
 
 			Array morphs;
 			//blend shapes
@@ -2772,8 +2780,6 @@ Error GLTFDocument::_parse_meshes(Ref<GLTFState> state) {
 						array_copy[l] = array[l];
 					}
 
-					array_copy[Mesh::ARRAY_INDEX] = Variant();
-
 					if (t.has("POSITION")) {
 						Vector<Vector3> varr = _decode_accessor_as_vec3(state, t["POSITION"], true);
 						const Vector<Vector3> src_varr = array[Mesh::ARRAY_VERTEX];
@@ -2852,17 +2858,17 @@ Error GLTFDocument::_parse_meshes(Ref<GLTFState> state) {
 						array_copy[Mesh::ARRAY_TANGENT] = tangents_v4;
 					}
 
+					Ref<SurfaceTool> blend_surface_tool;
+					blend_surface_tool.instantiate();
+					blend_surface_tool->create_from_triangle_arrays(array_copy);
+					if (a.has("JOINTS_0") && a.has("JOINTS_1")) {
+						blend_surface_tool->set_skin_weight_count(SurfaceTool::SKIN_8_WEIGHTS);
+					}
+					blend_surface_tool->index();
 					if (generate_tangents) {
-						Ref<SurfaceTool> st;
-						st.instantiate();
-						st->create_from_triangle_arrays(array_copy);
-						if (a.has("JOINTS_0") && a.has("JOINTS_1")) {
-							st->set_skin_weight_count(SurfaceTool::SKIN_8_WEIGHTS);
-						}
-						st->deindex();
-						st->generate_tangents();
-						array_copy = st->commit_to_arrays();
+						blend_surface_tool->generate_tangents();
 					}
+					array_copy = blend_surface_tool->commit_to_arrays();
 
 					morphs.push_back(array_copy);
 				}
@@ -2875,19 +2881,23 @@ Error GLTFDocument::_parse_meshes(Ref<GLTFState> state) {
 				const int material = p["material"];
 				ERR_FAIL_INDEX_V(material, state->materials.size(), ERR_FILE_CORRUPT);
 				Ref<BaseMaterial3D> mat3d = state->materials[material];
+				ERR_FAIL_NULL_V(mat3d, ERR_FILE_CORRUPT);
 				if (has_vertex_color) {
 					mat3d->set_flag(BaseMaterial3D::FLAG_ALBEDO_FROM_VERTEX_COLOR, true);
 				}
 				mat = mat3d;
 
-			} else if (has_vertex_color) {
+			} else {
 				Ref<StandardMaterial3D> mat3d;
 				mat3d.instantiate();
-				mat3d->set_flag(BaseMaterial3D::FLAG_ALBEDO_FROM_VERTEX_COLOR, true);
+				if (has_vertex_color) {
+					mat3d->set_flag(BaseMaterial3D::FLAG_ALBEDO_FROM_VERTEX_COLOR, true);
+				}
 				mat = mat3d;
 			}
-
-			import_mesh->add_surface(primitive, array, morphs, Dictionary(), mat, mat.is_valid() ? mat->get_name() : String(), flags);
+			ERR_FAIL_NULL_V(mat, ERR_FILE_CORRUPT);
+			import_mesh->add_surface(primitive, array, morphs,
+					Dictionary(), mat, mat->get_name(), flags);
 		}
 
 		Vector<float> blend_weights;
@@ -3610,7 +3620,6 @@ Error GLTFDocument::_parse_materials(Ref<GLTFState> state) {
 				material->set_cull_mode(BaseMaterial3D::CULL_DISABLED);
 			}
 		}
-
 		if (d.has("alphaMode")) {
 			const String &am = d["alphaMode"];
 			if (am == "BLEND") {
@@ -5007,72 +5016,65 @@ GLTFMeshIndex GLTFDocument::_convert_mesh_to_gltf(Ref<GLTFState> state, MeshInst
 	if (p_mesh_instance->get_mesh().is_null()) {
 		return -1;
 	}
-	Ref<EditorSceneImporterMesh> import_mesh;
-	import_mesh.instantiate();
-	Ref<Mesh> godot_mesh = p_mesh_instance->get_mesh();
-	if (godot_mesh.is_null()) {
-		return -1;
-	}
+	Ref<ImporterMesh> current_mesh;
+	current_mesh.instantiate();
 	Vector<float> blend_weights;
-	Vector<String> blend_names;
-	int32_t blend_count = godot_mesh->get_blend_shape_count();
-	blend_names.resize(blend_count);
-	blend_weights.resize(blend_count);
-	for (int32_t blend_i = 0; blend_i < godot_mesh->get_blend_shape_count(); blend_i++) {
-		String blend_name = godot_mesh->get_blend_shape_name(blend_i);
-		blend_names.write[blend_i] = blend_name;
-		import_mesh->add_blend_shape(blend_name);
-	}
-	for (int32_t surface_i = 0; surface_i < godot_mesh->get_surface_count(); surface_i++) {
-		Mesh::PrimitiveType primitive_type = godot_mesh->surface_get_primitive_type(surface_i);
-		Array arrays = godot_mesh->surface_get_arrays(surface_i);
-		Array blend_shape_arrays = godot_mesh->surface_get_blend_shape_arrays(surface_i);
-		Ref<Material> mat = godot_mesh->surface_get_material(surface_i);
-		Ref<ArrayMesh> godot_array_mesh = godot_mesh;
-		String surface_name;
-		if (godot_array_mesh.is_valid()) {
-			surface_name = godot_array_mesh->surface_get_name(surface_i);
-		}
-		if (p_mesh_instance->get_surface_override_material(surface_i).is_valid()) {
-			mat = p_mesh_instance->get_surface_override_material(surface_i);
-		}
-		if (p_mesh_instance->get_material_override().is_valid()) {
-			mat = p_mesh_instance->get_material_override();
-		}
-		import_mesh->add_surface(primitive_type, arrays, blend_shape_arrays, Dictionary(), mat, surface_name, godot_mesh->surface_get_format(surface_i));
-	}
-	for (int32_t blend_i = 0; blend_i < blend_count; blend_i++) {
-		blend_weights.write[blend_i] = 0.0f;
+	{
+		Ref<Mesh> import_mesh = p_mesh_instance->get_mesh();
+		Ref<ArrayMesh> import_array_mesh = p_mesh_instance->get_mesh();
+		if (import_mesh->get_blend_shape_count()) {
+			ArrayMesh::BlendShapeMode shape_mode = ArrayMesh::BLEND_SHAPE_MODE_NORMALIZED;
+			if (import_array_mesh.is_valid()) {
+				shape_mode = import_array_mesh->get_blend_shape_mode();
+			}
+			current_mesh->set_blend_shape_mode(shape_mode);
+			for (int morph_i = 0; morph_i < import_mesh->get_blend_shape_count(); morph_i++) {
+				current_mesh->add_blend_shape(import_mesh->get_blend_shape_name(morph_i));
+			}
+		}
+		for (int32_t surface_i = 0; surface_i < import_mesh->get_surface_count(); surface_i++) {
+			Array array = import_mesh->surface_get_arrays(surface_i);
+			Ref<Material> mat = import_mesh->surface_get_material(surface_i);
+			String mat_name;
+			if (mat.is_valid()) {
+				mat_name = mat->get_name();
+			}
+			current_mesh->add_surface(import_mesh->surface_get_primitive_type(surface_i),
+					array, import_mesh->surface_get_blend_shape_arrays(surface_i), import_mesh->surface_get_lods(surface_i), mat,
+					mat_name, import_mesh->surface_get_format(surface_i));
+		}
+		int32_t blend_count = import_mesh->get_blend_shape_count();
+		blend_weights.resize(blend_count);
+		for (int32_t blend_i = 0; blend_i < blend_count; blend_i++) {
+			blend_weights.write[blend_i] = 0.0f;
+		}
 	}
 	Ref<GLTFMesh> gltf_mesh;
 	gltf_mesh.instantiate();
-	gltf_mesh->set_mesh(import_mesh);
+	gltf_mesh->set_mesh(current_mesh);
 	gltf_mesh->set_blend_weights(blend_weights);
 	GLTFMeshIndex mesh_i = state->meshes.size();
 	state->meshes.push_back(gltf_mesh);
 	return mesh_i;
 }
 
-EditorSceneImporterMeshNode3D *GLTFDocument::_generate_mesh_instance(Ref<GLTFState> state, Node *scene_parent, const GLTFNodeIndex node_index) {
+ImporterMeshInstance3D *GLTFDocument::_generate_mesh_instance(Ref<GLTFState> state, Node *parent_node, const GLTFNodeIndex node_index) {
 	Ref<GLTFNode> gltf_node = state->nodes[node_index];
 
 	ERR_FAIL_INDEX_V(gltf_node->mesh, state->meshes.size(), nullptr);
 
-	EditorSceneImporterMeshNode3D *mi = memnew(EditorSceneImporterMeshNode3D);
+	ImporterMeshInstance3D *mi = memnew(ImporterMeshInstance3D);
 	print_verbose("glTF: Creating mesh for: " + gltf_node->get_name());
 
 	Ref<GLTFMesh> mesh = state->meshes.write[gltf_node->mesh];
 	if (mesh.is_null()) {
 		return mi;
 	}
-	Ref<EditorSceneImporterMesh> import_mesh = mesh->get_mesh();
+	Ref<ImporterMesh> import_mesh = mesh->get_mesh();
 	if (import_mesh.is_null()) {
 		return mi;
 	}
 	mi->set_mesh(import_mesh);
-	for (int i = 0; i < mesh->get_blend_weights().size(); i++) {
-		mi->set("blend_shapes/" + mesh->get_mesh()->get_blend_shape_name(i), mesh->get_blend_weights()[i]);
-	}
 	return mi;
 }
 
@@ -5241,7 +5243,7 @@ void GLTFDocument::_convert_scene_node(Ref<GLTFState> state, Node *p_current, co
 		return;
 	} else if (cast_to<MultiMeshInstance3D>(p_current)) {
 		MultiMeshInstance3D *multi = cast_to<MultiMeshInstance3D>(p_current);
-		_convert_mult_mesh_instance_to_gltf(multi, p_gltf_parent, p_gltf_root, gltf_node, state);
+		_convert_multi_mesh_instance_to_gltf(multi, p_gltf_parent, p_gltf_root, gltf_node, state);
 #ifdef MODULE_CSG_ENABLED
 	} else if (cast_to<CSGShape3D>(p_current)) {
 		CSGShape3D *shape = cast_to<CSGShape3D>(p_current);
@@ -5292,13 +5294,8 @@ void GLTFDocument::_convert_csg_shape_to_gltf(CSGShape3D *p_current, GLTFNodeInd
 	}
 	Ref<GLTFMesh> gltf_mesh;
 	gltf_mesh.instantiate();
-	Ref<EditorSceneImporterMesh> import_mesh;
-	import_mesh.instantiate();
-	Ref<ArrayMesh> array_mesh = csg->get_meshes()[1];
-	for (int32_t surface_i = 0; surface_i < array_mesh->get_surface_count(); surface_i++) {
-		import_mesh->add_surface(Mesh::PrimitiveType::PRIMITIVE_TRIANGLES, array_mesh->surface_get_arrays(surface_i), Array(), Dictionary(), mat, array_mesh->surface_get_name(surface_i));
-	}
-	gltf_mesh->set_mesh(import_mesh);
+	Ref<ImporterMesh> array_mesh = csg->get_meshes()[1];
+	gltf_mesh->set_mesh(array_mesh);
 	GLTFMeshIndex mesh_i = state->meshes.size();
 	state->meshes.push_back(gltf_mesh);
 	gltf_node->mesh = mesh_i;
@@ -5364,7 +5361,7 @@ void GLTFDocument::_convert_grid_map_to_gltf(GridMap *p_grid_map, GLTFNodeIndex
 		Vector3 cell_location = cells[k];
 		int32_t cell = p_grid_map->get_cell_item(
 				Vector3(cell_location.x, cell_location.y, cell_location.z));
-		EditorSceneImporterMeshNode3D *import_mesh_node = memnew(EditorSceneImporterMeshNode3D);
+		ImporterMeshInstance3D *import_mesh_node = memnew(ImporterMeshInstance3D);
 		import_mesh_node->set_mesh(p_grid_map->get_mesh_library()->get_item_mesh(cell));
 		Transform3D cell_xform;
 		cell_xform.basis.set_orthogonal_index(
@@ -5386,49 +5383,72 @@ void GLTFDocument::_convert_grid_map_to_gltf(GridMap *p_grid_map, GLTFNodeIndex
 }
 #endif // MODULE_GRIDMAP_ENABLED
 
-void GLTFDocument::_convert_mult_mesh_instance_to_gltf(MultiMeshInstance3D *p_multi_mesh_instance, GLTFNodeIndex p_parent_node_index, GLTFNodeIndex p_root_node_index, Ref<GLTFNode> gltf_node, Ref<GLTFState> state) {
+void GLTFDocument::_convert_multi_mesh_instance_to_gltf(
+		MultiMeshInstance3D *p_multi_mesh_instance,
+		GLTFNodeIndex p_parent_node_index,
+		GLTFNodeIndex p_root_node_index,
+		Ref<GLTFNode> gltf_node, Ref<GLTFState> state) {
+	ERR_FAIL_COND(!p_multi_mesh_instance);
 	Ref<MultiMesh> multi_mesh = p_multi_mesh_instance->get_multimesh();
-	if (multi_mesh.is_valid()) {
-		for (int32_t instance_i = 0; instance_i < multi_mesh->get_instance_count();
-				instance_i++) {
-			GLTFNode *new_gltf_node = memnew(GLTFNode);
-			Transform3D transform;
-			if (multi_mesh->get_transform_format() == MultiMesh::TRANSFORM_2D) {
-				Transform2D xform_2d = multi_mesh->get_instance_transform_2d(instance_i);
-				transform.origin =
-						Vector3(xform_2d.get_origin().x, 0, xform_2d.get_origin().y);
-				real_t rotation = xform_2d.get_rotation();
-				Quaternion quaternion(Vector3(0, 1, 0), rotation);
-				Size2 scale = xform_2d.get_scale();
-				transform.basis.set_quaternion_scale(quaternion,
-						Vector3(scale.x, 0, scale.y));
-				transform =
-						p_multi_mesh_instance->get_transform() * transform;
-			} else if (multi_mesh->get_transform_format() == MultiMesh::TRANSFORM_3D) {
-				transform = p_multi_mesh_instance->get_transform() *
-							multi_mesh->get_instance_transform(instance_i);
-			}
-			Ref<ArrayMesh> mm = multi_mesh->get_mesh();
-			if (mm.is_valid()) {
-				Ref<EditorSceneImporterMesh> mesh;
-				mesh.instantiate();
-				for (int32_t surface_i = 0; surface_i < mm->get_surface_count(); surface_i++) {
-					Array surface = mm->surface_get_arrays(surface_i);
-					mesh->add_surface(mm->surface_get_primitive_type(surface_i), surface, Array(), Dictionary(),
-							mm->surface_get_material(surface_i), mm->get_name());
-				}
-				Ref<GLTFMesh> gltf_mesh;
-				gltf_mesh.instantiate();
-				gltf_mesh->set_name(multi_mesh->get_name());
-				gltf_mesh->set_mesh(mesh);
-				new_gltf_node->mesh = state->meshes.size();
-				state->meshes.push_back(gltf_mesh);
-			}
-			new_gltf_node->xform = transform;
-			new_gltf_node->set_name(_gen_unique_name(state, p_multi_mesh_instance->get_name()));
-			gltf_node->children.push_back(state->nodes.size());
-			state->nodes.push_back(new_gltf_node);
+	if (multi_mesh.is_null()) {
+		return;
+	}
+	Ref<GLTFMesh> gltf_mesh;
+	gltf_mesh.instantiate();
+	Ref<Mesh> mesh = multi_mesh->get_mesh();
+	if (mesh.is_null()) {
+		return;
+	}
+	gltf_mesh->set_name(multi_mesh->get_name());
+	Ref<ImporterMesh> importer_mesh;
+	importer_mesh.instantiate();
+	Ref<ArrayMesh> array_mesh = multi_mesh->get_mesh();
+	if (array_mesh.is_valid()) {
+		importer_mesh->set_blend_shape_mode(array_mesh->get_blend_shape_mode());
+		for (int32_t blend_i = 0; blend_i < array_mesh->get_blend_shape_count(); blend_i++) {
+			importer_mesh->add_blend_shape(array_mesh->get_blend_shape_name(blend_i));
+		}
+	}
+	for (int32_t surface_i = 0; surface_i < mesh->get_surface_count(); surface_i++) {
+		Ref<Material> mat = mesh->surface_get_material(surface_i);
+		String material_name;
+		if (mat.is_valid()) {
+			material_name = mat->get_name();
 		}
+		Array blend_arrays;
+		if (array_mesh.is_valid()) {
+			blend_arrays = array_mesh->surface_get_blend_shape_arrays(surface_i);
+		}
+		importer_mesh->add_surface(mesh->surface_get_primitive_type(surface_i), mesh->surface_get_arrays(surface_i),
+				blend_arrays, mesh->surface_get_lods(surface_i), mat, material_name, mesh->surface_get_format(surface_i));
+	}
+	gltf_mesh->set_mesh(importer_mesh);
+	GLTFMeshIndex mesh_index = state->meshes.size();
+	state->meshes.push_back(gltf_mesh);
+	for (int32_t instance_i = 0; instance_i < multi_mesh->get_instance_count();
+			instance_i++) {
+		Transform3D transform;
+		if (multi_mesh->get_transform_format() == MultiMesh::TRANSFORM_2D) {
+			Transform2D xform_2d = multi_mesh->get_instance_transform_2d(instance_i);
+			transform.origin =
+					Vector3(xform_2d.get_origin().x, 0, xform_2d.get_origin().y);
+			real_t rotation = xform_2d.get_rotation();
+			Quaternion quaternion(Vector3(0, 1, 0), rotation);
+			Size2 scale = xform_2d.get_scale();
+			transform.basis.set_quaternion_scale(quaternion,
+					Vector3(scale.x, 0, scale.y));
+			transform = p_multi_mesh_instance->get_transform() * transform;
+		} else if (multi_mesh->get_transform_format() == MultiMesh::TRANSFORM_3D) {
+			transform = p_multi_mesh_instance->get_transform() *
+						multi_mesh->get_instance_transform(instance_i);
+		}
+		Ref<GLTFNode> new_gltf_node;
+		new_gltf_node.instantiate();
+		new_gltf_node->mesh = mesh_index;
+		new_gltf_node->xform = transform;
+		new_gltf_node->set_name(_gen_unique_name(state, p_multi_mesh_instance->get_name()));
+		gltf_node->children.push_back(state->nodes.size());
+		state->nodes.push_back(new_gltf_node);
 	}
 }
 
@@ -6106,8 +6126,8 @@ void GLTFDocument::_process_mesh_instances(Ref<GLTFState> state, Node *scene_roo
 			Map<GLTFNodeIndex, Node *>::Element *mi_element = state->scene_nodes.find(node_i);
 			ERR_CONTINUE_MSG(mi_element == nullptr, vformat("Unable to find node %d", node_i));
 
-			EditorSceneImporterMeshNode3D *mi = Object::cast_to<EditorSceneImporterMeshNode3D>(mi_element->get());
-			ERR_CONTINUE_MSG(mi == nullptr, vformat("Unable to cast node %d of type %s to EditorSceneImporterMeshNode3D", node_i, mi_element->get()->get_class_name()));
+			ImporterMeshInstance3D *mi = Object::cast_to<ImporterMeshInstance3D>(mi_element->get());
+			ERR_CONTINUE_MSG(mi == nullptr, vformat("Unable to cast node %d of type %s to ImporterMeshInstance3D", node_i, mi_element->get()->get_class_name()));
 
 			const GLTFSkeletonIndex skel_i = state->skins.write[node->skin]->skeleton;
 			Ref<GLTFSkeleton> gltf_skeleton = state->skeletons.write[skel_i];
@@ -6748,10 +6768,25 @@ Error GLTFDocument::save_scene(Node *p_node, const String &p_path,
 
 	Ref<GLTFDocument> gltf_document;
 	gltf_document.instantiate();
+	for (int32_t ext_i = 0; ext_i < document_extensions.size(); ext_i++) {
+		Ref<GLTFDocumentExtension> ext = document_extensions[ext_i];
+		ERR_CONTINUE(ext.is_null());
+		Error err = ext->export_preflight(this, p_node);
+		ERR_FAIL_COND_V(err != OK, err);
+	}
+
 	if (r_state == Ref<GLTFState>()) {
 		r_state.instantiate();
 	}
-	return gltf_document->serialize(r_state, p_node, p_path);
+	Error err = gltf_document->serialize(r_state, p_node, p_path);
+	ERR_FAIL_COND_V(err != OK, err);
+	for (int32_t ext_i = 0; ext_i < document_extensions.size(); ext_i++) {
+		Ref<GLTFDocumentExtension> ext = document_extensions[ext_i];
+		ERR_CONTINUE(ext.is_null());
+		err = ext->export_post(this);
+		ERR_FAIL_COND_V(err != OK, err);
+	}
+	return OK;
 }
 
 Node *GLTFDocument::import_scene_gltf(const String &p_path, uint32_t p_flags, int32_t p_bake_fps, Ref<GLTFState> r_state, List<String> *r_missing_deps, Error *r_err) {
@@ -6764,6 +6799,15 @@ Node *GLTFDocument::import_scene_gltf(const String &p_path, uint32_t p_flags, in
 
 	Ref<GLTFDocument> gltf_document;
 	gltf_document.instantiate();
+	for (int32_t ext_i = 0; ext_i < document_extensions.size(); ext_i++) {
+		Ref<GLTFDocumentExtension> ext = document_extensions[ext_i];
+		ERR_CONTINUE(ext.is_null());
+		Error err = ext->import_preflight(this);
+		if (r_err) {
+			*r_err = err;
+		}
+		ERR_FAIL_COND_V(err != OK, nullptr);
+	}
 	Error err = gltf_document->parse(r_state, p_path);
 	if (r_err) {
 		*r_err = err;
@@ -6783,7 +6827,15 @@ Node *GLTFDocument::import_scene_gltf(const String &p_path, uint32_t p_flags, in
 			gltf_document->_import_animation(r_state, ap, i, p_bake_fps);
 		}
 	}
-
+	for (int32_t ext_i = 0; ext_i < document_extensions.size(); ext_i++) {
+		Ref<GLTFDocumentExtension> ext = document_extensions[ext_i];
+		ERR_CONTINUE(ext.is_null());
+		err = ext->import_post(this, root);
+		if (r_err) {
+			*r_err = err;
+		}
+		ERR_FAIL_COND_V(err != OK, nullptr);
+	}
 	return root;
 }
 
@@ -6792,6 +6844,14 @@ void GLTFDocument::_bind_methods() {
 			&GLTFDocument::save_scene, DEFVAL(0), DEFVAL(30), DEFVAL(Ref<GLTFState>()));
 	ClassDB::bind_method(D_METHOD("import_scene", "path", "flags", "bake_fps", "state"),
 			&GLTFDocument::import_scene, DEFVAL(0), DEFVAL(30), DEFVAL(Ref<GLTFState>()));
+	ClassDB::bind_method(D_METHOD("set_extensions", "extensions"),
+			&GLTFDocument::set_extensions);
+	ClassDB::bind_method(D_METHOD("get_extensions"),
+			&GLTFDocument::get_extensions);
+	ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "extensions", PROPERTY_HINT_ARRAY_TYPE,
+						 vformat("%s/%s:%s", Variant::OBJECT, PROPERTY_HINT_RESOURCE_TYPE, "GLTFDocumentExtension"),
+						 PROPERTY_USAGE_DEFAULT),
+			"set_extensions", "get_extensions");
 }
 
 void GLTFDocument::_build_parent_hierachy(Ref<GLTFState> state) {
@@ -6817,3 +6877,20 @@ Node *GLTFDocument::import_scene(const String &p_path, uint32_t p_flags, int32_t
 	}
 	return node;
 }
+
+void GLTFDocument::set_extensions(TypedArray<GLTFDocumentExtension> p_extensions) {
+	document_extensions = p_extensions;
+}
+
+TypedArray<GLTFDocumentExtension> GLTFDocument::get_extensions() const {
+	return document_extensions;
+}
+
+GLTFDocument::GLTFDocument() {
+	if (!::Engine::get_singleton()->is_editor_hint()) {
+		return;
+	}
+	Ref<GLTFDocumentExtensionConvertImporterMesh> extension_editor;
+	extension_editor.instantiate();
+	document_extensions.push_back(extension_editor);
+}

+ 15 - 9
modules/gltf/gltf_document.h

@@ -33,8 +33,11 @@
 
 #include "gltf_animation.h"
 
-#include "editor/import/scene_importer_mesh_node_3d.h"
+#include "core/variant/dictionary.h"
+#include "core/variant/variant.h"
+#include "gltf_document_extension_convert_importer_mesh.h"
 #include "scene/3d/bone_attachment_3d.h"
+#include "scene/3d/importer_mesh_instance_3d.h"
 #include "scene/3d/light_3d.h"
 #include "scene/3d/mesh_instance_3d.h"
 #include "scene/3d/node_3d.h"
@@ -54,6 +57,7 @@ class GLTFSkeleton;
 class CSGShape3D;
 class GridMap;
 class MultiMeshInstance3D;
+class GLTFDocumentExtension;
 
 using GLTFAccessorIndex = int;
 using GLTFAnimationIndex = int;
@@ -74,11 +78,13 @@ class GLTFDocument : public Resource {
 	friend class GLTFState;
 	friend class GLTFSkin;
 	friend class GLTFSkeleton;
+	TypedArray<GLTFDocumentExtension> document_extensions;
 
 private:
 	const float BAKE_FPS = 30.0f;
 
 public:
+	GLTFDocument();
 	const int32_t JOINT_GROUP_SIZE = 4;
 	enum GLTFType {
 		TYPE_SCALAR,
@@ -118,6 +124,8 @@ public:
 	Error save_scene(Node *p_node, const String &p_path,
 			const String &p_src_path, uint32_t p_flags,
 			float p_bake_fps, Ref<GLTFState> r_state);
+	void set_extensions(TypedArray<GLTFDocumentExtension> p_extensions);
+	TypedArray<GLTFDocumentExtension> get_extensions() const;
 
 private:
 	template <class T>
@@ -280,12 +288,10 @@ private:
 			Skeleton3D *skeleton,
 			const GLTFNodeIndex node_index,
 			const GLTFNodeIndex bone_index);
-	EditorSceneImporterMeshNode3D *_generate_mesh_instance(Ref<GLTFState> state, Node *scene_parent, const GLTFNodeIndex node_index);
-	Camera3D *_generate_camera(Ref<GLTFState> state, Node *scene_parent,
-			const GLTFNodeIndex node_index);
-	Node3D *_generate_light(Ref<GLTFState> state, Node *scene_parent, const GLTFNodeIndex node_index);
-	Node3D *_generate_spatial(Ref<GLTFState> state, Node *scene_parent,
-			const GLTFNodeIndex node_index);
+	ImporterMeshInstance3D *_generate_mesh_instance(Ref<GLTFState> state, Node *parent_node, const GLTFNodeIndex node_index);
+	Camera3D *_generate_camera(Ref<GLTFState> state, Node *parent_node, const GLTFNodeIndex node_index);
+	Node3D *_generate_light(Ref<GLTFState> state, Node *parent_node, const GLTFNodeIndex node_index);
+	Node3D *_generate_spatial(Ref<GLTFState> state, Node *parent_node, const GLTFNodeIndex node_index);
 	void _assign_scene_names(Ref<GLTFState> state);
 	template <class T>
 	T _interpolate_track(const Vector<float> &p_times, const Vector<T> &p_values,
@@ -420,8 +426,8 @@ public:
 			GLTFNodeIndex p_root_node_index,
 			Ref<GLTFNode> gltf_node, Ref<GLTFState> state);
 #endif // MODULE_GRIDMAP_ENABLED
-	void _convert_mult_mesh_instance_to_gltf(
-			MultiMeshInstance3D *p_scene_parent,
+	void _convert_multi_mesh_instance_to_gltf(
+			MultiMeshInstance3D *p_multi_mesh_instance,
 			GLTFNodeIndex p_parent_node_index,
 			GLTFNodeIndex p_root_node_index,
 			Ref<GLTFNode> gltf_node, Ref<GLTFState> state);

+ 88 - 0
modules/gltf/gltf_document_extension.cpp

@@ -0,0 +1,88 @@
+/*************************************************************************/
+/*  gltf_document_extension.cpp                                          */
+/*************************************************************************/
+/*                       This file is part of:                           */
+/*                           GODOT ENGINE                                */
+/*                      https://godotengine.org                          */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur.                 */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md).   */
+/*                                                                       */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the       */
+/* "Software"), to deal in the Software without restriction, including   */
+/* without limitation the rights to use, copy, modify, merge, publish,   */
+/* distribute, sublicense, and/or sell copies of the Software, and to    */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions:                                             */
+/*                                                                       */
+/* The above copyright notice and this permission notice shall be        */
+/* included in all copies or substantial portions of the Software.       */
+/*                                                                       */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
+/*************************************************************************/
+
+#include "gltf_document_extension.h"
+
+#include "gltf_document.h"
+
+void GLTFDocumentExtension::_bind_methods() {
+	// Import
+	ClassDB::bind_method(D_METHOD("get_import_setting_keys"),
+			&GLTFDocumentExtension::get_import_setting_keys);
+	ClassDB::bind_method(D_METHOD("import_preflight", "document"),
+			&GLTFDocumentExtension::import_preflight);
+	ClassDB::bind_method(D_METHOD("get_import_setting", "key"),
+			&GLTFDocumentExtension::get_import_setting);
+	ClassDB::bind_method(D_METHOD("set_import_setting", "key", "value"),
+			&GLTFDocumentExtension::set_import_setting);
+	ClassDB::bind_method(D_METHOD("import_post", "document", "node"),
+			&GLTFDocumentExtension::import_post);
+	// Export
+	ClassDB::bind_method(D_METHOD("get_export_setting_keys"),
+			&GLTFDocumentExtension::get_export_setting_keys);
+	ClassDB::bind_method(D_METHOD("get_export_setting", "key"),
+			&GLTFDocumentExtension::get_export_setting);
+	ClassDB::bind_method(D_METHOD("set_export_setting", "key", "value"),
+			&GLTFDocumentExtension::set_export_setting);
+	ClassDB::bind_method(D_METHOD("export_preflight", "document", "node"),
+			&GLTFDocumentExtension::export_preflight);
+	ClassDB::bind_method(D_METHOD("export_post", "document"),
+			&GLTFDocumentExtension::export_post);
+}
+
+Array GLTFDocumentExtension::get_import_setting_keys() const {
+	return import_settings.keys();
+}
+
+Variant GLTFDocumentExtension::get_import_setting(const StringName &p_key) const {
+	if (!import_settings.has(p_key)) {
+		return Variant();
+	}
+	return import_settings[p_key];
+}
+
+void GLTFDocumentExtension::set_import_setting(const StringName &p_key, Variant p_var) {
+	import_settings[p_key] = p_var;
+}
+
+Array GLTFDocumentExtension::get_export_setting_keys() const {
+	return import_settings.keys();
+}
+
+Variant GLTFDocumentExtension::get_export_setting(const StringName &p_key) const {
+	if (!import_settings.has(p_key)) {
+		return Variant();
+	}
+	return import_settings[p_key];
+}
+
+void GLTFDocumentExtension::set_export_setting(const StringName &p_key, Variant p_var) {
+	import_settings[p_key] = p_var;
+}

+ 63 - 0
modules/gltf/gltf_document_extension.h

@@ -0,0 +1,63 @@
+/*************************************************************************/
+/*  gltf_document_extension.h                                            */
+/*************************************************************************/
+/*                       This file is part of:                           */
+/*                           GODOT ENGINE                                */
+/*                      https://godotengine.org                          */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur.                 */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md).   */
+/*                                                                       */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the       */
+/* "Software"), to deal in the Software without restriction, including   */
+/* without limitation the rights to use, copy, modify, merge, publish,   */
+/* distribute, sublicense, and/or sell copies of the Software, and to    */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions:                                             */
+/*                                                                       */
+/* The above copyright notice and this permission notice shall be        */
+/* included in all copies or substantial portions of the Software.       */
+/*                                                                       */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
+/*************************************************************************/
+
+#ifndef GLTF_DOCUMENT_EXTENSION_H
+#define GLTF_DOCUMENT_EXTENSION_H
+
+#include "core/io/resource.h"
+#include "core/variant/dictionary.h"
+#include "core/variant/typed_array.h"
+#include "core/variant/variant.h"
+class GLTFDocument;
+class GLTFDocumentExtension : public Resource {
+	GDCLASS(GLTFDocumentExtension, Resource);
+
+	Dictionary import_settings;
+	Dictionary export_settings;
+
+protected:
+	static void _bind_methods();
+
+public:
+	virtual Array get_import_setting_keys() const;
+	virtual Variant get_import_setting(const StringName &p_key) const;
+	virtual void set_import_setting(const StringName &p_key, Variant p_var);
+	virtual Error import_preflight(Ref<GLTFDocument> p_document) { return OK; }
+	virtual Error import_post(Ref<GLTFDocument> p_document, Node *p_node) { return OK; }
+
+public:
+	virtual Array get_export_setting_keys() const;
+	virtual Variant get_export_setting(const StringName &p_key) const;
+	virtual void set_export_setting(const StringName &p_key, Variant p_var);
+	virtual Error export_preflight(Ref<GLTFDocument> p_document, Node *p_node) { return OK; }
+	virtual Error export_post(Ref<GLTFDocument> p_document) { return OK; }
+};
+
+#endif // GLTF_DOCUMENT_EXTENSION_H

+ 79 - 0
modules/gltf/gltf_document_extension_convert_importer_mesh.cpp

@@ -0,0 +1,79 @@
+/*************************************************************************/
+/*  gltf_document_extension_convert_importer_mesh.cpp                    */
+/*************************************************************************/
+/*                       This file is part of:                           */
+/*                           GODOT ENGINE                                */
+/*                      https://godotengine.org                          */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur.                 */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md).   */
+/*                                                                       */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the       */
+/* "Software"), to deal in the Software without restriction, including   */
+/* without limitation the rights to use, copy, modify, merge, publish,   */
+/* distribute, sublicense, and/or sell copies of the Software, and to    */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions:                                             */
+/*                                                                       */
+/* The above copyright notice and this permission notice shall be        */
+/* included in all copies or substantial portions of the Software.       */
+/*                                                                       */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
+/*************************************************************************/
+
+#include "gltf_document_extension_convert_importer_mesh.h"
+#include "scene/3d/mesh_instance_3d.h"
+#include "scene/resources/importer_mesh.h"
+
+#include <cstddef>
+
+void GLTFDocumentExtensionConvertImporterMesh::_bind_methods() {
+}
+
+Error GLTFDocumentExtensionConvertImporterMesh::import_post(Ref<GLTFDocument> p_document, Node *p_node) {
+	List<Node *> queue;
+	queue.push_back(p_node);
+	List<Node *> delete_queue;
+	while (!queue.is_empty()) {
+		List<Node *>::Element *E = queue.front();
+		Node *node = E->get();
+		{
+			ImporterMeshInstance3D *mesh_3d = cast_to<ImporterMeshInstance3D>(node);
+			if (mesh_3d) {
+				MeshInstance3D *mesh_instance_node_3d = memnew(MeshInstance3D);
+				Ref<ImporterMesh> mesh = mesh_3d->get_mesh();
+				if (mesh.is_valid()) {
+					Ref<ArrayMesh> array_mesh = mesh->get_mesh();
+					mesh_instance_node_3d->set_name(node->get_name());
+					mesh_instance_node_3d->set_transform(mesh_3d->get_transform());
+					mesh_instance_node_3d->set_mesh(array_mesh);
+					mesh_instance_node_3d->set_skin(mesh_3d->get_skin());
+					mesh_instance_node_3d->set_skeleton_path(mesh_3d->get_skeleton_path());
+					node->replace_by(mesh_instance_node_3d);
+					delete_queue.push_back(node);
+				} else {
+					memdelete(mesh_instance_node_3d);
+				}
+			}
+		}
+		int child_count = node->get_child_count();
+		for (int i = 0; i < child_count; i++) {
+			queue.push_back(node->get_child(i));
+		}
+		queue.pop_front();
+	}
+	while (!queue.is_empty()) {
+		List<Node *>::Element *E = delete_queue.front();
+		Node *node = E->get();
+		memdelete(node);
+		delete_queue.pop_front();
+	}
+	return OK;
+}

+ 55 - 0
modules/gltf/gltf_document_extension_convert_importer_mesh.h

@@ -0,0 +1,55 @@
+/*************************************************************************/
+/*  gltf_document_extension_convert_importer_mesh.h                      */
+/*************************************************************************/
+/*                       This file is part of:                           */
+/*                           GODOT ENGINE                                */
+/*                      https://godotengine.org                          */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur.                 */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md).   */
+/*                                                                       */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the       */
+/* "Software"), to deal in the Software without restriction, including   */
+/* without limitation the rights to use, copy, modify, merge, publish,   */
+/* distribute, sublicense, and/or sell copies of the Software, and to    */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions:                                             */
+/*                                                                       */
+/* The above copyright notice and this permission notice shall be        */
+/* included in all copies or substantial portions of the Software.       */
+/*                                                                       */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
+/*************************************************************************/
+
+#ifndef GLTF_EXTENSION_EDITOR_H
+#define GLTF_EXTENSION_EDITOR_H
+
+#include "core/io/resource.h"
+#include "core/variant/dictionary.h"
+
+#include "gltf_document.h"
+#include "gltf_document_extension.h"
+#include "scene/3d/importer_mesh_instance_3d.h"
+#include "scene/3d/mesh_instance_3d.h"
+#include "scene/main/node.h"
+#include "scene/resources/importer_mesh.h"
+
+class GLTFDocumentExtension;
+class GLTFDocument;
+class GLTFDocumentExtensionConvertImporterMesh : public GLTFDocumentExtension {
+	GDCLASS(GLTFDocumentExtensionConvertImporterMesh, GLTFDocumentExtension);
+
+protected:
+	static void _bind_methods();
+
+public:
+	Error import_post(Ref<GLTFDocument> p_document, Node *p_node) override;
+};
+#endif // GLTF_EXTENSION_EDITOR_H

+ 3 - 3
modules/gltf/gltf_mesh.cpp

@@ -29,7 +29,7 @@
 /*************************************************************************/
 
 #include "gltf_mesh.h"
-#include "editor/import/scene_importer_mesh.h"
+#include "scene/resources/importer_mesh.h"
 
 void GLTFMesh::_bind_methods() {
 	ClassDB::bind_method(D_METHOD("get_mesh"), &GLTFMesh::get_mesh);
@@ -41,11 +41,11 @@ void GLTFMesh::_bind_methods() {
 	ADD_PROPERTY(PropertyInfo(Variant::PACKED_FLOAT32_ARRAY, "blend_weights"), "set_blend_weights", "get_blend_weights"); // Vector<float>
 }
 
-Ref<EditorSceneImporterMesh> GLTFMesh::get_mesh() {
+Ref<ImporterMesh> GLTFMesh::get_mesh() {
 	return mesh;
 }
 
-void GLTFMesh::set_mesh(Ref<EditorSceneImporterMesh> p_mesh) {
+void GLTFMesh::set_mesh(Ref<ImporterMesh> p_mesh) {
 	mesh = p_mesh;
 }
 

+ 5 - 4
modules/gltf/gltf_mesh.h

@@ -33,22 +33,23 @@
 
 #include "core/io/resource.h"
 #include "editor/import/resource_importer_scene.h"
-#include "editor/import/scene_importer_mesh.h"
+#include "scene/3d/importer_mesh_instance_3d.h"
+#include "scene/resources/importer_mesh.h"
 #include "scene/resources/mesh.h"
 
 class GLTFMesh : public Resource {
 	GDCLASS(GLTFMesh, Resource);
 
 private:
-	Ref<EditorSceneImporterMesh> mesh;
+	Ref<ImporterMesh> mesh;
 	Vector<float> blend_weights;
 
 protected:
 	static void _bind_methods();
 
 public:
-	Ref<EditorSceneImporterMesh> get_mesh();
-	void set_mesh(Ref<EditorSceneImporterMesh> p_mesh);
+	Ref<ImporterMesh> get_mesh();
+	void set_mesh(Ref<ImporterMesh> p_mesh);
 	Vector<float> get_blend_weights();
 	void set_blend_weights(Vector<float> p_blend_weights);
 };

+ 1 - 0
modules/gltf/gltf_state.h

@@ -36,6 +36,7 @@
 #include "gltf_buffer_view.h"
 #include "gltf_camera.h"
 #include "gltf_document.h"
+#include "gltf_document_extension.h"
 #include "gltf_light.h"
 #include "gltf_mesh.h"
 #include "gltf_node.h"

+ 4 - 0
modules/gltf/register_types.cpp

@@ -38,6 +38,8 @@
 #include "gltf_buffer_view.h"
 #include "gltf_camera.h"
 #include "gltf_document.h"
+#include "gltf_document_extension.h"
+#include "gltf_document_extension_convert_importer_mesh.h"
 #include "gltf_light.h"
 #include "gltf_mesh.h"
 #include "gltf_node.h"
@@ -79,6 +81,8 @@ void register_gltf_types() {
 	GDREGISTER_CLASS(GLTFCamera);
 	GDREGISTER_CLASS(GLTFLight);
 	GDREGISTER_CLASS(GLTFState);
+	GDREGISTER_CLASS(GLTFDocumentExtensionConvertImporterMesh);
+	GDREGISTER_CLASS(GLTFDocumentExtension);
 	GDREGISTER_CLASS(GLTFDocument);
 #endif
 }

+ 20 - 18
editor/import/scene_importer_mesh_node_3d.cpp → scene/3d/importer_mesh_instance_3d.cpp

@@ -1,5 +1,5 @@
 /*************************************************************************/
-/*  scene_importer_mesh_node_3d.cpp                                      */
+/*  importer_mesh_instance_3d.cpp                                        */
 /*************************************************************************/
 /*                       This file is part of:                           */
 /*                           GODOT ENGINE                                */
@@ -28,23 +28,25 @@
 /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
 /*************************************************************************/
 
-#include "scene_importer_mesh_node_3d.h"
+#include "importer_mesh_instance_3d.h"
 
-void EditorSceneImporterMeshNode3D::set_mesh(const Ref<EditorSceneImporterMesh> &p_mesh) {
+#include "scene/resources/importer_mesh.h"
+
+void ImporterMeshInstance3D::set_mesh(const Ref<ImporterMesh> &p_mesh) {
 	mesh = p_mesh;
 }
-Ref<EditorSceneImporterMesh> EditorSceneImporterMeshNode3D::get_mesh() const {
+Ref<ImporterMesh> ImporterMeshInstance3D::get_mesh() const {
 	return mesh;
 }
 
-void EditorSceneImporterMeshNode3D::set_skin(const Ref<Skin> &p_skin) {
+void ImporterMeshInstance3D::set_skin(const Ref<Skin> &p_skin) {
 	skin = p_skin;
 }
-Ref<Skin> EditorSceneImporterMeshNode3D::get_skin() const {
+Ref<Skin> ImporterMeshInstance3D::get_skin() const {
 	return skin;
 }
 
-void EditorSceneImporterMeshNode3D::set_surface_material(int p_idx, const Ref<Material> &p_material) {
+void ImporterMeshInstance3D::set_surface_material(int p_idx, const Ref<Material> &p_material) {
 	ERR_FAIL_COND(p_idx < 0);
 	if (p_idx >= surface_materials.size()) {
 		surface_materials.resize(p_idx + 1);
@@ -52,7 +54,7 @@ void EditorSceneImporterMeshNode3D::set_surface_material(int p_idx, const Ref<Ma
 
 	surface_materials.write[p_idx] = p_material;
 }
-Ref<Material> EditorSceneImporterMeshNode3D::get_surface_material(int p_idx) const {
+Ref<Material> ImporterMeshInstance3D::get_surface_material(int p_idx) const {
 	ERR_FAIL_COND_V(p_idx < 0, Ref<Material>());
 	if (p_idx >= surface_materials.size()) {
 		return Ref<Material>();
@@ -60,24 +62,24 @@ Ref<Material> EditorSceneImporterMeshNode3D::get_surface_material(int p_idx) con
 	return surface_materials[p_idx];
 }
 
-void EditorSceneImporterMeshNode3D::set_skeleton_path(const NodePath &p_path) {
+void ImporterMeshInstance3D::set_skeleton_path(const NodePath &p_path) {
 	skeleton_path = p_path;
 }
-NodePath EditorSceneImporterMeshNode3D::get_skeleton_path() const {
+NodePath ImporterMeshInstance3D::get_skeleton_path() const {
 	return skeleton_path;
 }
 
-void EditorSceneImporterMeshNode3D::_bind_methods() {
-	ClassDB::bind_method(D_METHOD("set_mesh", "mesh"), &EditorSceneImporterMeshNode3D::set_mesh);
-	ClassDB::bind_method(D_METHOD("get_mesh"), &EditorSceneImporterMeshNode3D::get_mesh);
+void ImporterMeshInstance3D::_bind_methods() {
+	ClassDB::bind_method(D_METHOD("set_mesh", "mesh"), &ImporterMeshInstance3D::set_mesh);
+	ClassDB::bind_method(D_METHOD("get_mesh"), &ImporterMeshInstance3D::get_mesh);
 
-	ClassDB::bind_method(D_METHOD("set_skin", "skin"), &EditorSceneImporterMeshNode3D::set_skin);
-	ClassDB::bind_method(D_METHOD("get_skin"), &EditorSceneImporterMeshNode3D::get_skin);
+	ClassDB::bind_method(D_METHOD("set_skin", "skin"), &ImporterMeshInstance3D::set_skin);
+	ClassDB::bind_method(D_METHOD("get_skin"), &ImporterMeshInstance3D::get_skin);
 
-	ClassDB::bind_method(D_METHOD("set_skeleton_path", "skeleton_path"), &EditorSceneImporterMeshNode3D::set_skeleton_path);
-	ClassDB::bind_method(D_METHOD("get_skeleton_path"), &EditorSceneImporterMeshNode3D::get_skeleton_path);
+	ClassDB::bind_method(D_METHOD("set_skeleton_path", "skeleton_path"), &ImporterMeshInstance3D::set_skeleton_path);
+	ClassDB::bind_method(D_METHOD("get_skeleton_path"), &ImporterMeshInstance3D::get_skeleton_path);
 
-	ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "mesh", PROPERTY_HINT_RESOURCE_TYPE, "EditorSceneImporterMesh"), "set_mesh", "get_mesh");
+	ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "mesh", PROPERTY_HINT_RESOURCE_TYPE, "ImporterMesh"), "set_mesh", "get_mesh");
 	ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "skin", PROPERTY_HINT_RESOURCE_TYPE, "Skin"), "set_skin", "get_skin");
 	ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "skeleton_path", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Skeleton"), "set_skeleton_path", "get_skeleton_path");
 }

+ 10 - 10
editor/import/scene_importer_mesh_node_3d.h → scene/3d/importer_mesh_instance_3d.h

@@ -1,5 +1,5 @@
 /*************************************************************************/
-/*  scene_importer_mesh_node_3d.h                                        */
+/*  importer_mesh_instance_3d.h                                          */
 /*************************************************************************/
 /*                       This file is part of:                           */
 /*                           GODOT ENGINE                                */
@@ -28,19 +28,19 @@
 /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
 /*************************************************************************/
 
-#ifndef EDITOR_SCENE_IMPORTER_MESH_NODE_3D_H
-#define EDITOR_SCENE_IMPORTER_MESH_NODE_3D_H
+#ifndef SCENE_IMPORTER_MESH_INSTANCE_3D_H
+#define SCENE_IMPORTER_MESH_INSTANCE_3D_H
 
-#include "editor/import/scene_importer_mesh.h"
 #include "scene/3d/node_3d.h"
+#include "scene/resources/immediate_mesh.h"
 #include "scene/resources/skin.h"
 
-class EditorSceneImporterMesh;
+class ImporterMesh;
 
-class EditorSceneImporterMeshNode3D : public Node3D {
-	GDCLASS(EditorSceneImporterMeshNode3D, Node3D)
+class ImporterMeshInstance3D : public Node3D {
+	GDCLASS(ImporterMeshInstance3D, Node3D)
 
-	Ref<EditorSceneImporterMesh> mesh;
+	Ref<ImporterMesh> mesh;
 	Ref<Skin> skin;
 	NodePath skeleton_path;
 	Vector<Ref<Material>> surface_materials;
@@ -49,8 +49,8 @@ protected:
 	static void _bind_methods();
 
 public:
-	void set_mesh(const Ref<EditorSceneImporterMesh> &p_mesh);
-	Ref<EditorSceneImporterMesh> get_mesh() const;
+	void set_mesh(const Ref<ImporterMesh> &p_mesh);
+	Ref<ImporterMesh> get_mesh() const;
 
 	void set_skin(const Ref<Skin> &p_skin);
 	Ref<Skin> get_skin() const;

+ 4 - 0
scene/register_scene_types.cpp

@@ -215,6 +215,7 @@
 #include "scene/3d/decal.h"
 #include "scene/3d/gpu_particles_3d.h"
 #include "scene/3d/gpu_particles_collision_3d.h"
+#include "scene/3d/importer_mesh_instance_3d.h"
 #include "scene/3d/joint_3d.h"
 #include "scene/3d/light_3d.h"
 #include "scene/3d/lightmap_gi.h"
@@ -244,6 +245,7 @@
 #include "scene/3d/world_environment.h"
 #include "scene/3d/xr_nodes.h"
 #include "scene/resources/environment.h"
+#include "scene/resources/importer_mesh.h"
 #include "scene/resources/mesh_library.h"
 #endif
 
@@ -441,6 +443,8 @@ void register_scene_types() {
 	GDREGISTER_CLASS(Skin);
 	GDREGISTER_VIRTUAL_CLASS(SkinReference);
 	GDREGISTER_CLASS(Skeleton3D);
+	GDREGISTER_CLASS(ImporterMesh);
+	GDREGISTER_CLASS(ImporterMeshInstance3D);
 	GDREGISTER_VIRTUAL_CLASS(VisualInstance3D);
 	GDREGISTER_VIRTUAL_CLASS(GeometryInstance3D);
 	GDREGISTER_CLASS(Camera3D);

+ 61 - 61
editor/import/scene_importer_mesh.cpp → scene/resources/importer_mesh.cpp

@@ -1,5 +1,5 @@
 /*************************************************************************/
-/*  scene_importer_mesh.cpp                                              */
+/*  importer_mesh.cpp                                                    */
 /*************************************************************************/
 /*                       This file is part of:                           */
 /*                           GODOT ENGINE                                */
@@ -28,7 +28,7 @@
 /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
 /*************************************************************************/
 
-#include "scene_importer_mesh.h"
+#include "importer_mesh.h"
 
 #include "core/math/random_pcg.h"
 #include "core/math/static_raycaster.h"
@@ -36,7 +36,7 @@
 
 #include <cstdint>
 
-void EditorSceneImporterMesh::Surface::split_normals(const LocalVector<int> &p_indices, const LocalVector<Vector3> &p_normals) {
+void ImporterMesh::Surface::split_normals(const LocalVector<int> &p_indices, const LocalVector<Vector3> &p_normals) {
 	ERR_FAIL_COND(arrays.size() != RS::ARRAY_MAX);
 
 	const PackedVector3Array &vertices = arrays[RS::ARRAY_VERTEX];
@@ -124,29 +124,29 @@ void EditorSceneImporterMesh::Surface::split_normals(const LocalVector<int> &p_i
 	}
 }
 
-void EditorSceneImporterMesh::add_blend_shape(const String &p_name) {
+void ImporterMesh::add_blend_shape(const String &p_name) {
 	ERR_FAIL_COND(surfaces.size() > 0);
 	blend_shapes.push_back(p_name);
 }
 
-int EditorSceneImporterMesh::get_blend_shape_count() const {
+int ImporterMesh::get_blend_shape_count() const {
 	return blend_shapes.size();
 }
 
-String EditorSceneImporterMesh::get_blend_shape_name(int p_blend_shape) const {
+String ImporterMesh::get_blend_shape_name(int p_blend_shape) const {
 	ERR_FAIL_INDEX_V(p_blend_shape, blend_shapes.size(), String());
 	return blend_shapes[p_blend_shape];
 }
 
-void EditorSceneImporterMesh::set_blend_shape_mode(Mesh::BlendShapeMode p_blend_shape_mode) {
+void ImporterMesh::set_blend_shape_mode(Mesh::BlendShapeMode p_blend_shape_mode) {
 	blend_shape_mode = p_blend_shape_mode;
 }
 
-Mesh::BlendShapeMode EditorSceneImporterMesh::get_blend_shape_mode() const {
+Mesh::BlendShapeMode ImporterMesh::get_blend_shape_mode() const {
 	return blend_shape_mode;
 }
 
-void EditorSceneImporterMesh::add_surface(Mesh::PrimitiveType p_primitive, const Array &p_arrays, const Array &p_blend_shapes, const Dictionary &p_lods, const Ref<Material> &p_material, const String &p_name, const uint32_t p_flags) {
+void ImporterMesh::add_surface(Mesh::PrimitiveType p_primitive, const Array &p_arrays, const Array &p_blend_shapes, const Dictionary &p_lods, const Ref<Material> &p_material, const String &p_name, const uint32_t p_flags) {
 	ERR_FAIL_COND(p_blend_shapes.size() != blend_shapes.size());
 	ERR_FAIL_COND(p_arrays.size() != Mesh::ARRAY_MAX);
 	Surface s;
@@ -186,67 +186,67 @@ void EditorSceneImporterMesh::add_surface(Mesh::PrimitiveType p_primitive, const
 	mesh.unref();
 }
 
-int EditorSceneImporterMesh::get_surface_count() const {
+int ImporterMesh::get_surface_count() const {
 	return surfaces.size();
 }
 
-Mesh::PrimitiveType EditorSceneImporterMesh::get_surface_primitive_type(int p_surface) {
+Mesh::PrimitiveType ImporterMesh::get_surface_primitive_type(int p_surface) {
 	ERR_FAIL_INDEX_V(p_surface, surfaces.size(), Mesh::PRIMITIVE_MAX);
 	return surfaces[p_surface].primitive;
 }
-Array EditorSceneImporterMesh::get_surface_arrays(int p_surface) const {
+Array ImporterMesh::get_surface_arrays(int p_surface) const {
 	ERR_FAIL_INDEX_V(p_surface, surfaces.size(), Array());
 	return surfaces[p_surface].arrays;
 }
-String EditorSceneImporterMesh::get_surface_name(int p_surface) const {
+String ImporterMesh::get_surface_name(int p_surface) const {
 	ERR_FAIL_INDEX_V(p_surface, surfaces.size(), String());
 	return surfaces[p_surface].name;
 }
-void EditorSceneImporterMesh::set_surface_name(int p_surface, const String &p_name) {
+void ImporterMesh::set_surface_name(int p_surface, const String &p_name) {
 	ERR_FAIL_INDEX(p_surface, surfaces.size());
 	surfaces.write[p_surface].name = p_name;
 	mesh.unref();
 }
 
-Array EditorSceneImporterMesh::get_surface_blend_shape_arrays(int p_surface, int p_blend_shape) const {
+Array ImporterMesh::get_surface_blend_shape_arrays(int p_surface, int p_blend_shape) const {
 	ERR_FAIL_INDEX_V(p_surface, surfaces.size(), Array());
 	ERR_FAIL_INDEX_V(p_blend_shape, surfaces[p_surface].blend_shape_data.size(), Array());
 	return surfaces[p_surface].blend_shape_data[p_blend_shape].arrays;
 }
-int EditorSceneImporterMesh::get_surface_lod_count(int p_surface) const {
+int ImporterMesh::get_surface_lod_count(int p_surface) const {
 	ERR_FAIL_INDEX_V(p_surface, surfaces.size(), 0);
 	return surfaces[p_surface].lods.size();
 }
-Vector<int> EditorSceneImporterMesh::get_surface_lod_indices(int p_surface, int p_lod) const {
+Vector<int> ImporterMesh::get_surface_lod_indices(int p_surface, int p_lod) const {
 	ERR_FAIL_INDEX_V(p_surface, surfaces.size(), Vector<int>());
 	ERR_FAIL_INDEX_V(p_lod, surfaces[p_surface].lods.size(), Vector<int>());
 
 	return surfaces[p_surface].lods[p_lod].indices;
 }
 
-float EditorSceneImporterMesh::get_surface_lod_size(int p_surface, int p_lod) const {
+float ImporterMesh::get_surface_lod_size(int p_surface, int p_lod) const {
 	ERR_FAIL_INDEX_V(p_surface, surfaces.size(), 0);
 	ERR_FAIL_INDEX_V(p_lod, surfaces[p_surface].lods.size(), 0);
 	return surfaces[p_surface].lods[p_lod].distance;
 }
 
-uint32_t EditorSceneImporterMesh::get_surface_format(int p_surface) const {
+uint32_t ImporterMesh::get_surface_format(int p_surface) const {
 	ERR_FAIL_INDEX_V(p_surface, surfaces.size(), 0);
 	return surfaces[p_surface].flags;
 }
 
-Ref<Material> EditorSceneImporterMesh::get_surface_material(int p_surface) const {
+Ref<Material> ImporterMesh::get_surface_material(int p_surface) const {
 	ERR_FAIL_INDEX_V(p_surface, surfaces.size(), Ref<Material>());
 	return surfaces[p_surface].material;
 }
 
-void EditorSceneImporterMesh::set_surface_material(int p_surface, const Ref<Material> &p_material) {
+void ImporterMesh::set_surface_material(int p_surface, const Ref<Material> &p_material) {
 	ERR_FAIL_INDEX(p_surface, surfaces.size());
 	surfaces.write[p_surface].material = p_material;
 	mesh.unref();
 }
 
-void EditorSceneImporterMesh::generate_lods(float p_normal_merge_angle, float p_normal_split_angle) {
+void ImporterMesh::generate_lods(float p_normal_merge_angle, float p_normal_split_angle) {
 	if (!SurfaceTool::simplify_scale_func) {
 		return;
 	}
@@ -608,11 +608,11 @@ void EditorSceneImporterMesh::generate_lods(float p_normal_merge_angle, float p_
 	}
 }
 
-bool EditorSceneImporterMesh::has_mesh() const {
+bool ImporterMesh::has_mesh() const {
 	return mesh.is_valid();
 }
 
-Ref<ArrayMesh> EditorSceneImporterMesh::get_mesh(const Ref<ArrayMesh> &p_base) {
+Ref<ArrayMesh> ImporterMesh::get_mesh(const Ref<ArrayMesh> &p_base) {
 	ERR_FAIL_COND_V(surfaces.size() == 0, Ref<ArrayMesh>());
 
 	if (mesh.is_null()) {
@@ -664,13 +664,13 @@ Ref<ArrayMesh> EditorSceneImporterMesh::get_mesh(const Ref<ArrayMesh> &p_base) {
 	return mesh;
 }
 
-void EditorSceneImporterMesh::clear() {
+void ImporterMesh::clear() {
 	surfaces.clear();
 	blend_shapes.clear();
 	mesh.unref();
 }
 
-void EditorSceneImporterMesh::create_shadow_mesh() {
+void ImporterMesh::create_shadow_mesh() {
 	if (shadow_mesh.is_valid()) {
 		shadow_mesh.unref();
 	}
@@ -763,11 +763,11 @@ void EditorSceneImporterMesh::create_shadow_mesh() {
 	}
 }
 
-Ref<EditorSceneImporterMesh> EditorSceneImporterMesh::get_shadow_mesh() const {
+Ref<ImporterMesh> ImporterMesh::get_shadow_mesh() const {
 	return shadow_mesh;
 }
 
-void EditorSceneImporterMesh::_set_data(const Dictionary &p_data) {
+void ImporterMesh::_set_data(const Dictionary &p_data) {
 	clear();
 	if (p_data.has("blend_shape_names")) {
 		blend_shapes = p_data["blend_shape_names"];
@@ -805,7 +805,7 @@ void EditorSceneImporterMesh::_set_data(const Dictionary &p_data) {
 		}
 	}
 }
-Dictionary EditorSceneImporterMesh::_get_data() const {
+Dictionary ImporterMesh::_get_data() const {
 	Dictionary data;
 	if (blend_shapes.size()) {
 		data["blend_shape_names"] = blend_shapes;
@@ -848,7 +848,7 @@ Dictionary EditorSceneImporterMesh::_get_data() const {
 	return data;
 }
 
-Vector<Face3> EditorSceneImporterMesh::get_faces() const {
+Vector<Face3> ImporterMesh::get_faces() const {
 	Vector<Face3> faces;
 	for (int i = 0; i < surfaces.size(); i++) {
 		if (surfaces[i].primitive == Mesh::PRIMITIVE_TRIANGLES) {
@@ -877,7 +877,7 @@ Vector<Face3> EditorSceneImporterMesh::get_faces() const {
 	return faces;
 }
 
-Vector<Ref<Shape3D>> EditorSceneImporterMesh::convex_decompose(const Mesh::ConvexDecompositionSettings &p_settings) const {
+Vector<Ref<Shape3D>> ImporterMesh::convex_decompose(const Mesh::ConvexDecompositionSettings &p_settings) const {
 	ERR_FAIL_COND_V(!Mesh::convex_decomposition_function, Vector<Ref<Shape3D>>());
 
 	const Vector<Face3> faces = get_faces();
@@ -924,7 +924,7 @@ Vector<Ref<Shape3D>> EditorSceneImporterMesh::convex_decompose(const Mesh::Conve
 	return ret;
 }
 
-Ref<Shape3D> EditorSceneImporterMesh::create_trimesh_shape() const {
+Ref<Shape3D> ImporterMesh::create_trimesh_shape() const {
 	Vector<Face3> faces = get_faces();
 	if (faces.size() == 0) {
 		return Ref<Shape3D>();
@@ -945,7 +945,7 @@ Ref<Shape3D> EditorSceneImporterMesh::create_trimesh_shape() const {
 	return shape;
 }
 
-Ref<NavigationMesh> EditorSceneImporterMesh::create_navigation_mesh() {
+Ref<NavigationMesh> ImporterMesh::create_navigation_mesh() {
 	Vector<Face3> faces = get_faces();
 	if (faces.size() == 0) {
 		return Ref<NavigationMesh>();
@@ -1000,7 +1000,7 @@ struct EditorSceneImporterMeshLightmapSurface {
 	String name;
 };
 
-Error EditorSceneImporterMesh::lightmap_unwrap_cached(const Transform3D &p_base_transform, float p_texel_size, const Vector<uint8_t> &p_src_cache, Vector<uint8_t> &r_dst_cache) {
+Error ImporterMesh::lightmap_unwrap_cached(const Transform3D &p_base_transform, float p_texel_size, const Vector<uint8_t> &p_src_cache, Vector<uint8_t> &r_dst_cache) {
 	ERR_FAIL_COND_V(!array_mesh_lightmap_unwrap_callback, ERR_UNCONFIGURED);
 	ERR_FAIL_COND_V_MSG(blend_shapes.size() != 0, ERR_UNAVAILABLE, "Can't unwrap mesh with blend shapes.");
 
@@ -1197,46 +1197,46 @@ Error EditorSceneImporterMesh::lightmap_unwrap_cached(const Transform3D &p_base_
 	return OK;
 }
 
-void EditorSceneImporterMesh::set_lightmap_size_hint(const Size2i &p_size) {
+void ImporterMesh::set_lightmap_size_hint(const Size2i &p_size) {
 	lightmap_size_hint = p_size;
 }
 
-Size2i EditorSceneImporterMesh::get_lightmap_size_hint() const {
+Size2i ImporterMesh::get_lightmap_size_hint() const {
 	return lightmap_size_hint;
 }
 
-void EditorSceneImporterMesh::_bind_methods() {
-	ClassDB::bind_method(D_METHOD("add_blend_shape", "name"), &EditorSceneImporterMesh::add_blend_shape);
-	ClassDB::bind_method(D_METHOD("get_blend_shape_count"), &EditorSceneImporterMesh::get_blend_shape_count);
-	ClassDB::bind_method(D_METHOD("get_blend_shape_name", "blend_shape_idx"), &EditorSceneImporterMesh::get_blend_shape_name);
+void ImporterMesh::_bind_methods() {
+	ClassDB::bind_method(D_METHOD("add_blend_shape", "name"), &ImporterMesh::add_blend_shape);
+	ClassDB::bind_method(D_METHOD("get_blend_shape_count"), &ImporterMesh::get_blend_shape_count);
+	ClassDB::bind_method(D_METHOD("get_blend_shape_name", "blend_shape_idx"), &ImporterMesh::get_blend_shape_name);
 
-	ClassDB::bind_method(D_METHOD("set_blend_shape_mode", "mode"), &EditorSceneImporterMesh::set_blend_shape_mode);
-	ClassDB::bind_method(D_METHOD("get_blend_shape_mode"), &EditorSceneImporterMesh::get_blend_shape_mode);
+	ClassDB::bind_method(D_METHOD("set_blend_shape_mode", "mode"), &ImporterMesh::set_blend_shape_mode);
+	ClassDB::bind_method(D_METHOD("get_blend_shape_mode"), &ImporterMesh::get_blend_shape_mode);
 
-	ClassDB::bind_method(D_METHOD("add_surface", "primitive", "arrays", "blend_shapes", "lods", "material", "name", "flags"), &EditorSceneImporterMesh::add_surface, DEFVAL(Array()), DEFVAL(Dictionary()), DEFVAL(Ref<Material>()), DEFVAL(String()), DEFVAL(0));
+	ClassDB::bind_method(D_METHOD("add_surface", "primitive", "arrays", "blend_shapes", "lods", "material", "name", "flags"), &ImporterMesh::add_surface, DEFVAL(Array()), DEFVAL(Dictionary()), DEFVAL(Ref<Material>()), DEFVAL(String()), DEFVAL(0));
 
-	ClassDB::bind_method(D_METHOD("get_surface_count"), &EditorSceneImporterMesh::get_surface_count);
-	ClassDB::bind_method(D_METHOD("get_surface_primitive_type", "surface_idx"), &EditorSceneImporterMesh::get_surface_primitive_type);
-	ClassDB::bind_method(D_METHOD("get_surface_name", "surface_idx"), &EditorSceneImporterMesh::get_surface_name);
-	ClassDB::bind_method(D_METHOD("get_surface_arrays", "surface_idx"), &EditorSceneImporterMesh::get_surface_arrays);
-	ClassDB::bind_method(D_METHOD("get_surface_blend_shape_arrays", "surface_idx", "blend_shape_idx"), &EditorSceneImporterMesh::get_surface_blend_shape_arrays);
-	ClassDB::bind_method(D_METHOD("get_surface_lod_count", "surface_idx"), &EditorSceneImporterMesh::get_surface_lod_count);
-	ClassDB::bind_method(D_METHOD("get_surface_lod_size", "surface_idx", "lod_idx"), &EditorSceneImporterMesh::get_surface_lod_size);
-	ClassDB::bind_method(D_METHOD("get_surface_lod_indices", "surface_idx", "lod_idx"), &EditorSceneImporterMesh::get_surface_lod_indices);
-	ClassDB::bind_method(D_METHOD("get_surface_material", "surface_idx"), &EditorSceneImporterMesh::get_surface_material);
-	ClassDB::bind_method(D_METHOD("get_surface_format", "surface_idx"), &EditorSceneImporterMesh::get_surface_format);
+	ClassDB::bind_method(D_METHOD("get_surface_count"), &ImporterMesh::get_surface_count);
+	ClassDB::bind_method(D_METHOD("get_surface_primitive_type", "surface_idx"), &ImporterMesh::get_surface_primitive_type);
+	ClassDB::bind_method(D_METHOD("get_surface_name", "surface_idx"), &ImporterMesh::get_surface_name);
+	ClassDB::bind_method(D_METHOD("get_surface_arrays", "surface_idx"), &ImporterMesh::get_surface_arrays);
+	ClassDB::bind_method(D_METHOD("get_surface_blend_shape_arrays", "surface_idx", "blend_shape_idx"), &ImporterMesh::get_surface_blend_shape_arrays);
+	ClassDB::bind_method(D_METHOD("get_surface_lod_count", "surface_idx"), &ImporterMesh::get_surface_lod_count);
+	ClassDB::bind_method(D_METHOD("get_surface_lod_size", "surface_idx", "lod_idx"), &ImporterMesh::get_surface_lod_size);
+	ClassDB::bind_method(D_METHOD("get_surface_lod_indices", "surface_idx", "lod_idx"), &ImporterMesh::get_surface_lod_indices);
+	ClassDB::bind_method(D_METHOD("get_surface_material", "surface_idx"), &ImporterMesh::get_surface_material);
+	ClassDB::bind_method(D_METHOD("get_surface_format", "surface_idx"), &ImporterMesh::get_surface_format);
 
-	ClassDB::bind_method(D_METHOD("set_surface_name", "surface_idx", "name"), &EditorSceneImporterMesh::set_surface_name);
-	ClassDB::bind_method(D_METHOD("set_surface_material", "surface_idx", "material"), &EditorSceneImporterMesh::set_surface_material);
+	ClassDB::bind_method(D_METHOD("set_surface_name", "surface_idx", "name"), &ImporterMesh::set_surface_name);
+	ClassDB::bind_method(D_METHOD("set_surface_material", "surface_idx", "material"), &ImporterMesh::set_surface_material);
 
-	ClassDB::bind_method(D_METHOD("get_mesh", "base_mesh"), &EditorSceneImporterMesh::get_mesh, DEFVAL(Ref<ArrayMesh>()));
-	ClassDB::bind_method(D_METHOD("clear"), &EditorSceneImporterMesh::clear);
+	ClassDB::bind_method(D_METHOD("get_mesh", "base_mesh"), &ImporterMesh::get_mesh, DEFVAL(Ref<ArrayMesh>()));
+	ClassDB::bind_method(D_METHOD("clear"), &ImporterMesh::clear);
 
-	ClassDB::bind_method(D_METHOD("_set_data", "data"), &EditorSceneImporterMesh::_set_data);
-	ClassDB::bind_method(D_METHOD("_get_data"), &EditorSceneImporterMesh::_get_data);
+	ClassDB::bind_method(D_METHOD("_set_data", "data"), &ImporterMesh::_set_data);
+	ClassDB::bind_method(D_METHOD("_get_data"), &ImporterMesh::_get_data);
 
-	ClassDB::bind_method(D_METHOD("set_lightmap_size_hint", "size"), &EditorSceneImporterMesh::set_lightmap_size_hint);
-	ClassDB::bind_method(D_METHOD("get_lightmap_size_hint"), &EditorSceneImporterMesh::get_lightmap_size_hint);
+	ClassDB::bind_method(D_METHOD("set_lightmap_size_hint", "size"), &ImporterMesh::set_lightmap_size_hint);
+	ClassDB::bind_method(D_METHOD("get_lightmap_size_hint"), &ImporterMesh::get_lightmap_size_hint);
 
 	ADD_PROPERTY(PropertyInfo(Variant::DICTIONARY, "_data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "_set_data", "_get_data");
 }

+ 8 - 8
editor/import/scene_importer_mesh.h → scene/resources/importer_mesh.h

@@ -1,5 +1,5 @@
 /*************************************************************************/
-/*  scene_importer_mesh.h                                                */
+/*  importer_mesh.h                                                      */
 /*************************************************************************/
 /*                       This file is part of:                           */
 /*                           GODOT ENGINE                                */
@@ -28,8 +28,8 @@
 /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
 /*************************************************************************/
 
-#ifndef EDITOR_SCENE_IMPORTER_MESH_H
-#define EDITOR_SCENE_IMPORTER_MESH_H
+#ifndef SCENE_IMPORTER_MESH_H
+#define SCENE_IMPORTER_MESH_H
 
 #include "core/io/resource.h"
 #include "core/templates/local_vector.h"
@@ -44,8 +44,8 @@
 // so the data is not registered (hence, quality loss), importing happens faster and
 // its easier to modify before saving
 
-class EditorSceneImporterMesh : public Resource {
-	GDCLASS(EditorSceneImporterMesh, Resource)
+class ImporterMesh : public Resource {
+	GDCLASS(ImporterMesh, Resource)
 
 	struct Surface {
 		Mesh::PrimitiveType primitive;
@@ -77,7 +77,7 @@ class EditorSceneImporterMesh : public Resource {
 
 	Ref<ArrayMesh> mesh;
 
-	Ref<EditorSceneImporterMesh> shadow_mesh;
+	Ref<ImporterMesh> shadow_mesh;
 
 	Size2i lightmap_size_hint;
 
@@ -114,7 +114,7 @@ public:
 	void generate_lods(float p_normal_merge_angle, float p_normal_split_angle);
 
 	void create_shadow_mesh();
-	Ref<EditorSceneImporterMesh> get_shadow_mesh() const;
+	Ref<ImporterMesh> get_shadow_mesh() const;
 
 	Vector<Face3> get_faces() const;
 	Vector<Ref<Shape3D>> convex_decompose(const Mesh::ConvexDecompositionSettings &p_settings) const;
@@ -129,4 +129,4 @@ public:
 	Ref<ArrayMesh> get_mesh(const Ref<ArrayMesh> &p_base = Ref<ArrayMesh>());
 	void clear();
 };
-#endif // EDITOR_SCENE_IMPORTER_MESH_H
+#endif // SCENE_IMPORTER_MESH_H

+ 1 - 1
servers/rendering_server.cpp

@@ -934,7 +934,7 @@ Error RenderingServer::mesh_create_surface_data_from_arrays(SurfaceData *r_surfa
 				}
 			}
 
-			ERR_FAIL_COND_V((bsformat) != (format & (RS::ARRAY_FORMAT_INDEX - 1)), ERR_INVALID_PARAMETER);
+			ERR_FAIL_COND_V_MSG((bsformat) != (format & (ARRAY_FORMAT_VERTEX | ARRAY_FORMAT_NORMAL | ARRAY_FORMAT_TANGENT)), ERR_INVALID_PARAMETER, "Blend shape format must match the main array format for Vertex, Normal and Tangent arrays.");
 		}
 	}