2017-03-05 14:47:28 +00:00
|
|
|
/*************************************************************************/
|
|
|
|
/* resource_importer_scene.cpp */
|
|
|
|
/*************************************************************************/
|
|
|
|
/* This file is part of: */
|
|
|
|
/* GODOT ENGINE */
|
2017-08-27 12:16:55 +00:00
|
|
|
/* https://godotengine.org */
|
2017-03-05 14:47:28 +00:00
|
|
|
/*************************************************************************/
|
2020-01-01 10:16:22 +00:00
|
|
|
/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
|
|
|
|
/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
|
2017-03-05 14:47:28 +00:00
|
|
|
/* */
|
|
|
|
/* 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. */
|
|
|
|
/*************************************************************************/
|
2018-01-04 23:50:27 +00:00
|
|
|
|
2017-02-04 12:48:04 +00:00
|
|
|
#include "resource_importer_scene.h"
|
|
|
|
|
2018-09-11 16:13:45 +00:00
|
|
|
#include "core/io/resource_saver.h"
|
2017-03-05 13:21:25 +00:00
|
|
|
#include "editor/editor_node.h"
|
2020-03-26 21:49:16 +00:00
|
|
|
#include "scene/3d/collision_shape_3d.h"
|
|
|
|
#include "scene/3d/mesh_instance_3d.h"
|
|
|
|
#include "scene/3d/navigation_3d.h"
|
|
|
|
#include "scene/3d/physics_body_3d.h"
|
2020-03-27 07:44:44 +00:00
|
|
|
#include "scene/3d/vehicle_body_3d.h"
|
2017-09-08 11:06:09 +00:00
|
|
|
#include "scene/animation/animation_player.h"
|
|
|
|
#include "scene/resources/animation.h"
|
2020-03-26 21:49:16 +00:00
|
|
|
#include "scene/resources/box_shape_3d.h"
|
2020-01-21 20:32:27 +00:00
|
|
|
#include "scene/resources/packed_scene.h"
|
2020-03-27 07:44:44 +00:00
|
|
|
#include "scene/resources/ray_shape_3d.h"
|
2019-02-12 16:18:13 +00:00
|
|
|
#include "scene/resources/resource_format_text.h"
|
2020-03-26 21:49:16 +00:00
|
|
|
#include "scene/resources/sphere_shape_3d.h"
|
|
|
|
#include "scene/resources/world_margin_shape_3d.h"
|
2017-02-04 12:48:04 +00:00
|
|
|
|
2017-12-07 18:44:20 +00:00
|
|
|
uint32_t EditorSceneImporter::get_import_flags() const {
|
|
|
|
if (get_script_instance()) {
|
|
|
|
return get_script_instance()->call("_get_import_flags");
|
|
|
|
}
|
|
|
|
|
|
|
|
ERR_FAIL_V(0);
|
|
|
|
}
|
2020-05-14 12:29:06 +00:00
|
|
|
|
2017-12-07 18:44:20 +00:00
|
|
|
void EditorSceneImporter::get_extensions(List<String> *r_extensions) const {
|
|
|
|
if (get_script_instance()) {
|
2017-12-09 17:11:26 +00:00
|
|
|
Array arr = get_script_instance()->call("_get_extensions");
|
|
|
|
for (int i = 0; i < arr.size(); i++) {
|
2017-12-07 18:44:20 +00:00
|
|
|
r_extensions->push_back(arr[i]);
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
ERR_FAIL();
|
|
|
|
}
|
2020-05-14 12:29:06 +00:00
|
|
|
|
2017-12-07 18:44:20 +00:00
|
|
|
Node *EditorSceneImporter::import_scene(const String &p_path, uint32_t p_flags, int p_bake_fps, List<String> *r_missing_deps, Error *r_err) {
|
|
|
|
if (get_script_instance()) {
|
2017-12-09 17:11:26 +00:00
|
|
|
return get_script_instance()->call("_import_scene", p_path, p_flags, p_bake_fps);
|
2017-12-07 18:44:20 +00:00
|
|
|
}
|
|
|
|
|
2020-04-01 23:20:12 +00:00
|
|
|
ERR_FAIL_V(nullptr);
|
2017-12-07 18:44:20 +00:00
|
|
|
}
|
|
|
|
|
2017-12-09 17:11:26 +00:00
|
|
|
Ref<Animation> EditorSceneImporter::import_animation(const String &p_path, uint32_t p_flags, int p_bake_fps) {
|
2017-12-07 18:44:20 +00:00
|
|
|
if (get_script_instance()) {
|
2017-12-09 17:11:26 +00:00
|
|
|
return get_script_instance()->call("_import_animation", p_path, p_flags);
|
2017-12-07 18:44:20 +00:00
|
|
|
}
|
|
|
|
|
2020-04-01 23:20:12 +00:00
|
|
|
ERR_FAIL_V(nullptr);
|
2017-12-07 18:44:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//for documenters, these functions are useful when an importer calls an external conversion helper (like, fbx2gltf),
|
|
|
|
//and you want to load the resulting file
|
|
|
|
|
2017-12-09 17:11:26 +00:00
|
|
|
Node *EditorSceneImporter::import_scene_from_other_importer(const String &p_path, uint32_t p_flags, int p_bake_fps) {
|
|
|
|
return ResourceImporterScene::get_singleton()->import_scene_from_other_importer(this, p_path, p_flags, p_bake_fps);
|
2017-12-07 18:44:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
Ref<Animation> EditorSceneImporter::import_animation_from_other_importer(const String &p_path, uint32_t p_flags, int p_bake_fps) {
|
2017-12-09 17:11:26 +00:00
|
|
|
return ResourceImporterScene::get_singleton()->import_animation_from_other_importer(this, p_path, p_flags, p_bake_fps);
|
2017-12-07 18:44:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void EditorSceneImporter::_bind_methods() {
|
2017-12-09 17:11:26 +00:00
|
|
|
ClassDB::bind_method(D_METHOD("import_scene_from_other_importer", "path", "flags", "bake_fps"), &EditorSceneImporter::import_scene_from_other_importer);
|
|
|
|
ClassDB::bind_method(D_METHOD("import_animation_from_other_importer", "path", "flags", "bake_fps"), &EditorSceneImporter::import_animation_from_other_importer);
|
2017-12-07 18:44:20 +00:00
|
|
|
|
|
|
|
BIND_VMETHOD(MethodInfo(Variant::INT, "_get_import_flags"));
|
|
|
|
BIND_VMETHOD(MethodInfo(Variant::ARRAY, "_get_extensions"));
|
|
|
|
|
2017-12-09 17:11:26 +00:00
|
|
|
MethodInfo mi = MethodInfo(Variant::OBJECT, "_import_scene", PropertyInfo(Variant::STRING, "path"), PropertyInfo(Variant::INT, "flags"), PropertyInfo(Variant::INT, "bake_fps"));
|
|
|
|
mi.return_val.class_name = "Node";
|
2017-12-07 18:44:20 +00:00
|
|
|
BIND_VMETHOD(mi);
|
2017-12-09 17:11:26 +00:00
|
|
|
mi = MethodInfo(Variant::OBJECT, "_import_animation", PropertyInfo(Variant::STRING, "path"), PropertyInfo(Variant::INT, "flags"), PropertyInfo(Variant::INT, "bake_fps"));
|
|
|
|
mi.return_val.class_name = "Animation";
|
2017-12-07 18:44:20 +00:00
|
|
|
BIND_VMETHOD(mi);
|
|
|
|
|
2017-12-09 17:11:26 +00:00
|
|
|
BIND_CONSTANT(IMPORT_SCENE);
|
|
|
|
BIND_CONSTANT(IMPORT_ANIMATION);
|
|
|
|
BIND_CONSTANT(IMPORT_ANIMATION_DETECT_LOOP);
|
|
|
|
BIND_CONSTANT(IMPORT_ANIMATION_OPTIMIZE);
|
|
|
|
BIND_CONSTANT(IMPORT_ANIMATION_FORCE_ALL_TRACKS_IN_ALL_CLIPS);
|
|
|
|
BIND_CONSTANT(IMPORT_ANIMATION_KEEP_VALUE_TRACKS);
|
|
|
|
BIND_CONSTANT(IMPORT_GENERATE_TANGENT_ARRAYS);
|
|
|
|
BIND_CONSTANT(IMPORT_FAIL_ON_MISSING_DEPENDENCIES);
|
|
|
|
BIND_CONSTANT(IMPORT_MATERIALS_IN_INSTANCES);
|
|
|
|
BIND_CONSTANT(IMPORT_USE_COMPRESSION);
|
2017-12-07 18:44:20 +00:00
|
|
|
}
|
|
|
|
|
2020-12-12 12:06:59 +00:00
|
|
|
////////////////////////////////////////////////
|
|
|
|
|
|
|
|
void EditorSceneImporterMesh::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 {
|
|
|
|
return blend_shapes.size();
|
|
|
|
}
|
|
|
|
|
|
|
|
String EditorSceneImporterMesh::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) {
|
|
|
|
blend_shape_mode = p_blend_shape_mode;
|
|
|
|
}
|
|
|
|
Mesh::BlendShapeMode EditorSceneImporterMesh::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) {
|
|
|
|
ERR_FAIL_COND(p_blend_shapes.size() != blend_shapes.size());
|
|
|
|
ERR_FAIL_COND(p_arrays.size() != Mesh::ARRAY_MAX);
|
|
|
|
Surface s;
|
|
|
|
s.primitive = p_primitive;
|
|
|
|
s.arrays = p_arrays;
|
|
|
|
s.name = p_name;
|
|
|
|
|
|
|
|
for (int i = 0; i < blend_shapes.size(); i++) {
|
|
|
|
Array bsdata = p_blend_shapes[i];
|
|
|
|
ERR_FAIL_COND(bsdata.size() != Mesh::ARRAY_MAX);
|
|
|
|
Surface::BlendShape bs;
|
|
|
|
bs.arrays = bsdata;
|
|
|
|
s.blend_shape_data.push_back(bs);
|
|
|
|
}
|
|
|
|
|
|
|
|
List<Variant> lods;
|
|
|
|
p_lods.get_key_list(&lods);
|
|
|
|
for (List<Variant>::Element *E = lods.front(); E; E = E->next()) {
|
|
|
|
ERR_CONTINUE(!E->get().is_num());
|
|
|
|
Surface::LOD lod;
|
|
|
|
lod.distance = E->get();
|
|
|
|
lod.indices = p_lods[E->get()];
|
|
|
|
ERR_CONTINUE(lod.indices.size() == 0);
|
|
|
|
s.lods.push_back(lod);
|
|
|
|
}
|
|
|
|
|
|
|
|
s.material = p_material;
|
|
|
|
|
|
|
|
surfaces.push_back(s);
|
|
|
|
mesh.unref();
|
|
|
|
}
|
|
|
|
int EditorSceneImporterMesh::get_surface_count() const {
|
|
|
|
return surfaces.size();
|
|
|
|
}
|
|
|
|
|
|
|
|
Mesh::PrimitiveType EditorSceneImporterMesh::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 {
|
|
|
|
ERR_FAIL_INDEX_V(p_surface, surfaces.size(), Array());
|
|
|
|
return surfaces[p_surface].arrays;
|
|
|
|
}
|
|
|
|
String EditorSceneImporterMesh::get_surface_name(int p_surface) const {
|
|
|
|
ERR_FAIL_INDEX_V(p_surface, surfaces.size(), String());
|
|
|
|
return surfaces[p_surface].name;
|
|
|
|
}
|
|
|
|
Array EditorSceneImporterMesh::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 {
|
|
|
|
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 {
|
|
|
|
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 {
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
Ref<Material> EditorSceneImporterMesh::get_surface_material(int p_surface) const {
|
|
|
|
ERR_FAIL_INDEX_V(p_surface, surfaces.size(), Ref<Material>());
|
|
|
|
return surfaces[p_surface].material;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool EditorSceneImporterMesh::has_mesh() const {
|
|
|
|
return mesh.is_valid();
|
|
|
|
}
|
|
|
|
|
|
|
|
Ref<ArrayMesh> EditorSceneImporterMesh::get_mesh() {
|
|
|
|
ERR_FAIL_COND_V(surfaces.size() == 0, Ref<ArrayMesh>());
|
|
|
|
|
|
|
|
if (mesh.is_null()) {
|
|
|
|
mesh.instance();
|
|
|
|
for (int i = 0; i < blend_shapes.size(); i++) {
|
|
|
|
mesh->add_blend_shape(blend_shapes[i]);
|
|
|
|
}
|
|
|
|
mesh->set_blend_shape_mode(blend_shape_mode);
|
|
|
|
for (int i = 0; i < surfaces.size(); i++) {
|
|
|
|
Array bs_data;
|
|
|
|
if (surfaces[i].blend_shape_data.size()) {
|
|
|
|
for (int j = 0; j < surfaces[i].blend_shape_data.size(); j++) {
|
|
|
|
bs_data.push_back(surfaces[i].blend_shape_data[j].arrays);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Dictionary lods;
|
|
|
|
if (surfaces[i].lods.size()) {
|
|
|
|
for (int j = 0; j < surfaces[i].lods.size(); j++) {
|
|
|
|
lods[surfaces[i].lods[j].distance] = surfaces[i].lods[j].indices;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
mesh->add_surface_from_arrays(surfaces[i].primitive, surfaces[i].arrays, bs_data, lods);
|
|
|
|
if (surfaces[i].material.is_valid()) {
|
|
|
|
mesh->surface_set_material(mesh->get_surface_count() - 1, surfaces[i].material);
|
|
|
|
}
|
|
|
|
if (surfaces[i].name != String()) {
|
|
|
|
mesh->surface_set_name(mesh->get_surface_count() - 1, surfaces[i].name);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return mesh;
|
|
|
|
}
|
|
|
|
|
|
|
|
void EditorSceneImporterMesh::clear() {
|
|
|
|
surfaces.clear();
|
|
|
|
blend_shapes.clear();
|
|
|
|
mesh.unref();
|
|
|
|
}
|
|
|
|
|
|
|
|
void EditorSceneImporterMesh::_set_data(const Dictionary &p_data) {
|
|
|
|
clear();
|
|
|
|
if (p_data.has("blend_shape_names")) {
|
|
|
|
blend_shapes = p_data["blend_shape_names"];
|
|
|
|
}
|
|
|
|
if (p_data.has("surfaces")) {
|
|
|
|
Array surface_arr = p_data["surfaces"];
|
|
|
|
for (int i = 0; i < surface_arr.size(); i++) {
|
|
|
|
Dictionary s = surface_arr[i];
|
|
|
|
ERR_CONTINUE(!s.has("primitive"));
|
|
|
|
ERR_CONTINUE(!s.has("arrays"));
|
|
|
|
Mesh::PrimitiveType prim = Mesh::PrimitiveType(int(s["primitive"]));
|
|
|
|
ERR_CONTINUE(prim >= Mesh::PRIMITIVE_MAX);
|
|
|
|
Array arr = s["arrays"];
|
|
|
|
Dictionary lods;
|
|
|
|
String name;
|
|
|
|
if (s.has("name")) {
|
|
|
|
name = s["name"];
|
|
|
|
}
|
|
|
|
if (s.has("lods")) {
|
|
|
|
lods = s["lods"];
|
|
|
|
}
|
|
|
|
Array blend_shapes;
|
|
|
|
if (s.has("blend_shapes")) {
|
|
|
|
blend_shapes = s["blend_shapes"];
|
|
|
|
}
|
|
|
|
Ref<Material> material;
|
|
|
|
if (s.has("material")) {
|
|
|
|
material = s["material"];
|
|
|
|
}
|
|
|
|
add_surface(prim, arr, blend_shapes, lods, material, name);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Dictionary EditorSceneImporterMesh::_get_data() const {
|
|
|
|
Dictionary data;
|
|
|
|
if (blend_shapes.size()) {
|
|
|
|
data["blend_shape_names"] = blend_shapes;
|
|
|
|
}
|
|
|
|
Array surface_arr;
|
|
|
|
for (int i = 0; i < surfaces.size(); i++) {
|
|
|
|
Dictionary d;
|
|
|
|
d["primitive"] = surfaces[i].primitive;
|
|
|
|
d["arrays"] = surfaces[i].arrays;
|
|
|
|
if (surfaces[i].blend_shape_data.size()) {
|
|
|
|
Array bs_data;
|
|
|
|
for (int j = 0; j < surfaces[i].blend_shape_data.size(); j++) {
|
|
|
|
bs_data.push_back(surfaces[i].blend_shape_data[j].arrays);
|
|
|
|
}
|
|
|
|
d["blend_shapes"] = bs_data;
|
|
|
|
}
|
|
|
|
if (surfaces[i].lods.size()) {
|
|
|
|
Dictionary lods;
|
|
|
|
for (int j = 0; j < surfaces[i].lods.size(); j++) {
|
|
|
|
lods[surfaces[i].lods[j].distance] = surfaces[i].lods[j].indices;
|
|
|
|
}
|
|
|
|
d["lods"] = lods;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (surfaces[i].material.is_valid()) {
|
|
|
|
d["material"] = surfaces[i].material;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (surfaces[i].name != String()) {
|
|
|
|
d["name"] = surfaces[i].name;
|
|
|
|
}
|
|
|
|
|
|
|
|
surface_arr.push_back(d);
|
|
|
|
}
|
|
|
|
data["surfaces"] = surface_arr;
|
|
|
|
return data;
|
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
|
|
|
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("add_surface", "primitive", "arrays", "blend_shapes", "lods", "material"), &EditorSceneImporterMesh::add_surface, DEFVAL(Array()), DEFVAL(Dictionary()), DEFVAL(Ref<Material>()), DEFVAL(String()));
|
|
|
|
|
|
|
|
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_mesh"), &EditorSceneImporterMesh::get_mesh);
|
|
|
|
ClassDB::bind_method(D_METHOD("clear"), &EditorSceneImporterMesh::clear);
|
|
|
|
|
|
|
|
ClassDB::bind_method(D_METHOD("_set_data", "data"), &EditorSceneImporterMesh::_set_data);
|
|
|
|
ClassDB::bind_method(D_METHOD("_get_data"), &EditorSceneImporterMesh::_get_data);
|
|
|
|
|
|
|
|
ADD_PROPERTY(PropertyInfo(Variant::DICTIONARY, "_data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "_set_data", "_get_data");
|
|
|
|
}
|
|
|
|
|
|
|
|
void EditorSceneImporterMeshNode::set_mesh(const Ref<EditorSceneImporterMesh> &p_mesh) {
|
|
|
|
mesh = p_mesh;
|
|
|
|
}
|
|
|
|
Ref<EditorSceneImporterMesh> EditorSceneImporterMeshNode::get_mesh() const {
|
|
|
|
return mesh;
|
|
|
|
}
|
|
|
|
|
|
|
|
void EditorSceneImporterMeshNode::set_skin(const Ref<Skin> &p_skin) {
|
|
|
|
skin = p_skin;
|
|
|
|
}
|
|
|
|
Ref<Skin> EditorSceneImporterMeshNode::get_skin() const {
|
|
|
|
return skin;
|
|
|
|
}
|
|
|
|
|
|
|
|
void EditorSceneImporterMeshNode::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);
|
|
|
|
}
|
|
|
|
|
|
|
|
surface_materials.write[p_idx] = p_material;
|
|
|
|
}
|
|
|
|
Ref<Material> EditorSceneImporterMeshNode::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>();
|
|
|
|
}
|
|
|
|
return surface_materials[p_idx];
|
|
|
|
}
|
|
|
|
|
|
|
|
void EditorSceneImporterMeshNode::set_skeleton_path(const NodePath &p_path) {
|
|
|
|
skeleton_path = p_path;
|
|
|
|
}
|
|
|
|
NodePath EditorSceneImporterMeshNode::get_skeleton_path() const {
|
|
|
|
return skeleton_path;
|
|
|
|
}
|
|
|
|
|
|
|
|
void EditorSceneImporterMeshNode::_bind_methods() {
|
|
|
|
ClassDB::bind_method(D_METHOD("set_mesh", "mesh"), &EditorSceneImporterMeshNode::set_mesh);
|
|
|
|
ClassDB::bind_method(D_METHOD("get_mesh"), &EditorSceneImporterMeshNode::get_mesh);
|
|
|
|
|
|
|
|
ClassDB::bind_method(D_METHOD("set_skin", "skin"), &EditorSceneImporterMeshNode::set_skin);
|
|
|
|
ClassDB::bind_method(D_METHOD("get_skin"), &EditorSceneImporterMeshNode::get_skin);
|
|
|
|
|
|
|
|
ClassDB::bind_method(D_METHOD("set_skeleton_path", "skeleton_path"), &EditorSceneImporterMeshNode::set_skeleton_path);
|
|
|
|
ClassDB::bind_method(D_METHOD("get_skeleton_path"), &EditorSceneImporterMeshNode::get_skeleton_path);
|
|
|
|
|
|
|
|
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "mesh", PROPERTY_HINT_RESOURCE_TYPE, "EditorSceneImporterMesh"), "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");
|
|
|
|
}
|
|
|
|
|
2017-12-07 18:44:20 +00:00
|
|
|
/////////////////////////////////
|
2017-02-04 12:48:04 +00:00
|
|
|
void EditorScenePostImport::_bind_methods() {
|
2018-01-19 23:48:44 +00:00
|
|
|
BIND_VMETHOD(MethodInfo(Variant::OBJECT, "post_import", PropertyInfo(Variant::OBJECT, "scene")));
|
|
|
|
ClassDB::bind_method(D_METHOD("get_source_folder"), &EditorScenePostImport::get_source_folder);
|
|
|
|
ClassDB::bind_method(D_METHOD("get_source_file"), &EditorScenePostImport::get_source_file);
|
2017-02-04 12:48:04 +00:00
|
|
|
}
|
|
|
|
|
2017-03-05 15:44:50 +00:00
|
|
|
Node *EditorScenePostImport::post_import(Node *p_scene) {
|
2020-05-14 14:41:43 +00:00
|
|
|
if (get_script_instance()) {
|
2017-03-05 15:44:50 +00:00
|
|
|
return get_script_instance()->call("post_import", p_scene);
|
2020-05-14 14:41:43 +00:00
|
|
|
}
|
2017-02-04 12:48:04 +00:00
|
|
|
|
|
|
|
return p_scene;
|
|
|
|
}
|
|
|
|
|
2018-01-19 23:48:44 +00:00
|
|
|
String EditorScenePostImport::get_source_folder() const {
|
|
|
|
return source_folder;
|
|
|
|
}
|
|
|
|
|
|
|
|
String EditorScenePostImport::get_source_file() const {
|
|
|
|
return source_file;
|
|
|
|
}
|
|
|
|
|
|
|
|
void EditorScenePostImport::init(const String &p_source_folder, const String &p_source_file) {
|
|
|
|
source_folder = p_source_folder;
|
|
|
|
source_file = p_source_file;
|
|
|
|
}
|
|
|
|
|
2017-02-04 12:48:04 +00:00
|
|
|
EditorScenePostImport::EditorScenePostImport() {
|
|
|
|
}
|
|
|
|
|
|
|
|
String ResourceImporterScene::get_importer_name() const {
|
|
|
|
return "scene";
|
|
|
|
}
|
|
|
|
|
2017-03-05 15:44:50 +00:00
|
|
|
String ResourceImporterScene::get_visible_name() const {
|
2017-02-04 12:48:04 +00:00
|
|
|
return "Scene";
|
|
|
|
}
|
|
|
|
|
2017-03-05 15:44:50 +00:00
|
|
|
void ResourceImporterScene::get_recognized_extensions(List<String> *p_extensions) const {
|
2020-03-17 06:33:00 +00:00
|
|
|
for (Set<Ref<EditorSceneImporter>>::Element *E = importers.front(); E; E = E->next()) {
|
2017-02-04 12:48:04 +00:00
|
|
|
E->get()->get_extensions(p_extensions);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
String ResourceImporterScene::get_save_extension() const {
|
|
|
|
return "scn";
|
|
|
|
}
|
|
|
|
|
2017-03-05 15:44:50 +00:00
|
|
|
String ResourceImporterScene::get_resource_type() const {
|
2017-02-04 12:48:04 +00:00
|
|
|
return "PackedScene";
|
|
|
|
}
|
|
|
|
|
2020-12-02 01:40:47 +00:00
|
|
|
int ResourceImporterScene::get_format_version() const {
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2017-03-05 15:44:50 +00:00
|
|
|
bool ResourceImporterScene::get_option_visibility(const String &p_option, const Map<StringName, Variant> &p_options) const {
|
2017-02-04 12:48:04 +00:00
|
|
|
if (p_option.begins_with("animation/")) {
|
2020-05-14 14:41:43 +00:00
|
|
|
if (p_option != "animation/import" && !bool(p_options["animation/import"])) {
|
2017-02-04 12:48:04 +00:00
|
|
|
return false;
|
2020-05-14 14:41:43 +00:00
|
|
|
}
|
2017-02-04 12:48:04 +00:00
|
|
|
|
2020-05-14 14:41:43 +00:00
|
|
|
if (p_option == "animation/keep_custom_tracks" && int(p_options["animation/storage"]) == 0) {
|
2017-12-07 13:18:55 +00:00
|
|
|
return false;
|
2020-05-14 14:41:43 +00:00
|
|
|
}
|
2017-12-07 13:18:55 +00:00
|
|
|
|
2020-05-14 14:41:43 +00:00
|
|
|
if (p_option.begins_with("animation/optimizer/") && p_option != "animation/optimizer/enabled" && !bool(p_options["animation/optimizer/enabled"])) {
|
2017-02-04 12:48:04 +00:00
|
|
|
return false;
|
2020-05-14 14:41:43 +00:00
|
|
|
}
|
2017-02-04 12:48:04 +00:00
|
|
|
|
|
|
|
if (p_option.begins_with("animation/clip_")) {
|
|
|
|
int max_clip = p_options["animation/clips/amount"];
|
2017-03-05 15:44:50 +00:00
|
|
|
int clip = p_option.get_slice("/", 1).get_slice("_", 1).to_int() - 1;
|
2020-05-14 14:41:43 +00:00
|
|
|
if (clip >= max_clip) {
|
2017-02-04 12:48:04 +00:00
|
|
|
return false;
|
2020-05-14 14:41:43 +00:00
|
|
|
}
|
2017-02-04 12:48:04 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-08-17 20:02:43 +00:00
|
|
|
if (p_option == "materials/keep_on_reimport" && int(p_options["materials/storage"]) == 0) {
|
2017-07-23 21:48:05 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2017-12-09 17:11:26 +00:00
|
|
|
if (p_option == "meshes/lightmap_texel_size" && int(p_options["meshes/light_baking"]) < 2) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2017-02-04 12:48:04 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
int ResourceImporterScene::get_preset_count() const {
|
2017-09-20 23:59:19 +00:00
|
|
|
return PRESET_MAX;
|
2017-02-04 12:48:04 +00:00
|
|
|
}
|
2020-05-14 12:29:06 +00:00
|
|
|
|
2017-02-04 12:48:04 +00:00
|
|
|
String ResourceImporterScene::get_preset_name(int p_idx) const {
|
2017-07-23 21:48:05 +00:00
|
|
|
switch (p_idx) {
|
2020-05-10 11:00:47 +00:00
|
|
|
case PRESET_SINGLE_SCENE:
|
|
|
|
return TTR("Import as Single Scene");
|
|
|
|
case PRESET_SEPARATE_ANIMATIONS:
|
|
|
|
return TTR("Import with Separate Animations");
|
|
|
|
case PRESET_SEPARATE_MATERIALS:
|
|
|
|
return TTR("Import with Separate Materials");
|
|
|
|
case PRESET_SEPARATE_MESHES:
|
|
|
|
return TTR("Import with Separate Objects");
|
|
|
|
case PRESET_SEPARATE_MESHES_AND_MATERIALS:
|
|
|
|
return TTR("Import with Separate Objects+Materials");
|
|
|
|
case PRESET_SEPARATE_MESHES_AND_ANIMATIONS:
|
|
|
|
return TTR("Import with Separate Objects+Animations");
|
|
|
|
case PRESET_SEPARATE_MATERIALS_AND_ANIMATIONS:
|
|
|
|
return TTR("Import with Separate Materials+Animations");
|
|
|
|
case PRESET_SEPARATE_MESHES_MATERIALS_AND_ANIMATIONS:
|
|
|
|
return TTR("Import with Separate Objects+Materials+Animations");
|
|
|
|
case PRESET_MULTIPLE_SCENES:
|
|
|
|
return TTR("Import as Multiple Scenes");
|
|
|
|
case PRESET_MULTIPLE_SCENES_AND_MATERIALS:
|
|
|
|
return TTR("Import as Multiple Scenes+Materials");
|
2017-07-23 21:48:05 +00:00
|
|
|
}
|
|
|
|
|
2017-02-04 12:48:04 +00:00
|
|
|
return "";
|
|
|
|
}
|
|
|
|
|
2017-03-05 15:44:50 +00:00
|
|
|
static bool _teststr(const String &p_what, const String &p_str) {
|
2018-07-02 08:54:14 +00:00
|
|
|
String what = p_what;
|
2018-07-02 05:02:32 +00:00
|
|
|
|
|
|
|
//remove trailing spaces and numbers, some apps like blender add ".number" to duplicates so also compensate for this
|
2018-07-02 08:54:14 +00:00
|
|
|
while (what.length() && ((what[what.length() - 1] >= '0' && what[what.length() - 1] <= '9') || what[what.length() - 1] <= 32 || what[what.length() - 1] == '.')) {
|
|
|
|
what = what.substr(0, what.length() - 1);
|
2018-07-02 05:02:32 +00:00
|
|
|
}
|
|
|
|
|
2020-05-14 14:41:43 +00:00
|
|
|
if (what.findn("$" + p_str) != -1) { //blender and other stuff
|
2017-02-04 12:48:04 +00:00
|
|
|
return true;
|
2020-05-14 14:41:43 +00:00
|
|
|
}
|
|
|
|
if (what.to_lower().ends_with("-" + p_str)) { //collada only supports "_" and "-" besides letters
|
2017-02-04 12:48:04 +00:00
|
|
|
return true;
|
2020-05-14 14:41:43 +00:00
|
|
|
}
|
|
|
|
if (what.to_lower().ends_with("_" + p_str)) { //collada only supports "_" and "-" besides letters
|
2017-02-04 12:48:04 +00:00
|
|
|
return true;
|
2020-05-14 14:41:43 +00:00
|
|
|
}
|
2017-02-04 12:48:04 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2017-03-05 15:44:50 +00:00
|
|
|
static String _fixstr(const String &p_what, const String &p_str) {
|
2018-07-02 08:54:14 +00:00
|
|
|
String what = p_what;
|
|
|
|
|
|
|
|
//remove trailing spaces and numbers, some apps like blender add ".number" to duplicates so also compensate for this
|
|
|
|
while (what.length() && ((what[what.length() - 1] >= '0' && what[what.length() - 1] <= '9') || what[what.length() - 1] <= 32 || what[what.length() - 1] == '.')) {
|
|
|
|
what = what.substr(0, what.length() - 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
String end = p_what.substr(what.length(), p_what.length() - what.length());
|
|
|
|
|
2020-05-14 14:41:43 +00:00
|
|
|
if (what.findn("$" + p_str) != -1) { //blender and other stuff
|
2018-07-02 08:54:14 +00:00
|
|
|
return what.replace("$" + p_str, "") + end;
|
2020-05-14 14:41:43 +00:00
|
|
|
}
|
|
|
|
if (what.to_lower().ends_with("-" + p_str)) { //collada only supports "_" and "-" besides letters
|
2018-07-02 08:54:14 +00:00
|
|
|
return what.substr(0, what.length() - (p_str.length() + 1)) + end;
|
2020-05-14 14:41:43 +00:00
|
|
|
}
|
|
|
|
if (what.to_lower().ends_with("_" + p_str)) { //collada only supports "_" and "-" besides letters
|
2018-07-02 08:54:14 +00:00
|
|
|
return what.substr(0, what.length() - (p_str.length() + 1)) + end;
|
2020-05-14 14:41:43 +00:00
|
|
|
}
|
2018-07-02 08:54:14 +00:00
|
|
|
return what;
|
2017-02-04 12:48:04 +00:00
|
|
|
}
|
|
|
|
|
2020-03-26 21:49:16 +00:00
|
|
|
static void _gen_shape_list(const Ref<Mesh> &mesh, List<Ref<Shape3D>> &r_shape_list, bool p_convex) {
|
2019-04-10 20:46:04 +00:00
|
|
|
if (!p_convex) {
|
2020-03-26 21:49:16 +00:00
|
|
|
Ref<Shape3D> shape = mesh->create_trimesh_shape();
|
2019-04-10 20:46:04 +00:00
|
|
|
r_shape_list.push_back(shape);
|
|
|
|
} else {
|
2020-03-26 21:49:16 +00:00
|
|
|
Vector<Ref<Shape3D>> cd = mesh->convex_decompose();
|
2019-04-10 20:46:04 +00:00
|
|
|
if (cd.size()) {
|
|
|
|
for (int i = 0; i < cd.size(); i++) {
|
|
|
|
r_shape_list.push_back(cd[i]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-03-26 21:49:16 +00:00
|
|
|
Node *ResourceImporterScene::_fix_node(Node *p_node, Node *p_root, Map<Ref<Mesh>, List<Ref<Shape3D>>> &collision_map, LightBakeMode p_light_bake_mode) {
|
2018-08-24 07:35:07 +00:00
|
|
|
// children first
|
2017-03-05 15:44:50 +00:00
|
|
|
for (int i = 0; i < p_node->get_child_count(); i++) {
|
2017-11-25 04:29:15 +00:00
|
|
|
Node *r = _fix_node(p_node->get_child(i), p_root, collision_map, p_light_bake_mode);
|
2017-02-04 12:48:04 +00:00
|
|
|
if (!r) {
|
|
|
|
i--; //was erased
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
String name = p_node->get_name();
|
|
|
|
|
2017-03-05 15:44:50 +00:00
|
|
|
bool isroot = p_node == p_root;
|
2017-02-04 12:48:04 +00:00
|
|
|
|
2017-03-05 15:44:50 +00:00
|
|
|
if (!isroot && _teststr(name, "noimp")) {
|
2017-02-04 12:48:04 +00:00
|
|
|
memdelete(p_node);
|
2020-04-01 23:20:12 +00:00
|
|
|
return nullptr;
|
2017-02-04 12:48:04 +00:00
|
|
|
}
|
|
|
|
|
2020-03-26 21:49:16 +00:00
|
|
|
if (Object::cast_to<MeshInstance3D>(p_node)) {
|
|
|
|
MeshInstance3D *mi = Object::cast_to<MeshInstance3D>(p_node);
|
2017-02-04 12:48:04 +00:00
|
|
|
|
2017-06-07 21:18:55 +00:00
|
|
|
Ref<ArrayMesh> m = mi->get_mesh();
|
2017-02-04 12:48:04 +00:00
|
|
|
|
|
|
|
if (m.is_valid()) {
|
2017-03-05 15:44:50 +00:00
|
|
|
for (int i = 0; i < m->get_surface_count(); i++) {
|
2019-09-15 04:01:52 +00:00
|
|
|
Ref<StandardMaterial3D> mat = m->surface_get_material(i);
|
2020-05-14 14:41:43 +00:00
|
|
|
if (!mat.is_valid()) {
|
2017-02-04 12:48:04 +00:00
|
|
|
continue;
|
2020-05-14 14:41:43 +00:00
|
|
|
}
|
2017-02-04 12:48:04 +00:00
|
|
|
|
2017-03-05 15:44:50 +00:00
|
|
|
if (_teststr(mat->get_name(), "alpha")) {
|
2019-09-15 04:01:52 +00:00
|
|
|
mat->set_transparency(StandardMaterial3D::TRANSPARENCY_ALPHA);
|
2017-03-05 15:44:50 +00:00
|
|
|
mat->set_name(_fixstr(mat->get_name(), "alpha"));
|
2017-02-04 12:48:04 +00:00
|
|
|
}
|
2017-03-05 15:44:50 +00:00
|
|
|
if (_teststr(mat->get_name(), "vcol")) {
|
2019-09-15 04:01:52 +00:00
|
|
|
mat->set_flag(StandardMaterial3D::FLAG_ALBEDO_FROM_VERTEX_COLOR, true);
|
|
|
|
mat->set_flag(StandardMaterial3D::FLAG_SRGB_VERTEX_COLOR, true);
|
2017-03-05 15:44:50 +00:00
|
|
|
mat->set_name(_fixstr(mat->get_name(), "vcol"));
|
2017-02-04 12:48:04 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2017-11-25 04:29:15 +00:00
|
|
|
|
|
|
|
if (p_light_bake_mode != LIGHT_BAKE_DISABLED) {
|
2020-05-01 12:34:23 +00:00
|
|
|
mi->set_gi_mode(GeometryInstance3D::GI_MODE_BAKED);
|
2017-11-25 04:29:15 +00:00
|
|
|
}
|
2017-02-04 12:48:04 +00:00
|
|
|
}
|
|
|
|
|
2017-08-24 20:58:51 +00:00
|
|
|
if (Object::cast_to<AnimationPlayer>(p_node)) {
|
2017-02-04 12:48:04 +00:00
|
|
|
//remove animations referencing non-importable nodes
|
2017-08-24 20:58:51 +00:00
|
|
|
AnimationPlayer *ap = Object::cast_to<AnimationPlayer>(p_node);
|
2017-02-04 12:48:04 +00:00
|
|
|
|
|
|
|
List<StringName> anims;
|
|
|
|
ap->get_animation_list(&anims);
|
2017-03-05 15:44:50 +00:00
|
|
|
for (List<StringName>::Element *E = anims.front(); E; E = E->next()) {
|
|
|
|
Ref<Animation> anim = ap->get_animation(E->get());
|
2017-02-04 12:48:04 +00:00
|
|
|
ERR_CONTINUE(anim.is_null());
|
2017-03-05 15:44:50 +00:00
|
|
|
for (int i = 0; i < anim->get_track_count(); i++) {
|
2017-02-04 12:48:04 +00:00
|
|
|
NodePath path = anim->track_get_path(i);
|
|
|
|
|
2017-03-05 15:44:50 +00:00
|
|
|
for (int j = 0; j < path.get_name_count(); j++) {
|
2017-02-04 12:48:04 +00:00
|
|
|
String node = path.get_name(j);
|
2017-03-05 15:44:50 +00:00
|
|
|
if (_teststr(node, "noimp")) {
|
2017-02-04 12:48:04 +00:00
|
|
|
anim->remove_track(i);
|
|
|
|
i--;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-11-16 13:06:30 +00:00
|
|
|
if (_teststr(name, "colonly") || _teststr(name, "convcolonly")) {
|
2020-05-14 14:41:43 +00:00
|
|
|
if (isroot) {
|
2017-02-04 12:48:04 +00:00
|
|
|
return p_node;
|
2020-05-14 14:41:43 +00:00
|
|
|
}
|
2020-03-26 21:49:16 +00:00
|
|
|
MeshInstance3D *mi = Object::cast_to<MeshInstance3D>(p_node);
|
2017-09-06 21:50:18 +00:00
|
|
|
if (mi) {
|
2019-04-10 20:46:04 +00:00
|
|
|
Ref<Mesh> mesh = mi->get_mesh();
|
|
|
|
|
|
|
|
if (mesh.is_valid()) {
|
2020-03-26 21:49:16 +00:00
|
|
|
List<Ref<Shape3D>> shapes;
|
2019-04-10 20:46:04 +00:00
|
|
|
String fixed_name;
|
|
|
|
if (collision_map.has(mesh)) {
|
|
|
|
shapes = collision_map[mesh];
|
|
|
|
} else if (_teststr(name, "colonly")) {
|
|
|
|
_gen_shape_list(mesh, shapes, false);
|
|
|
|
collision_map[mesh] = shapes;
|
|
|
|
} else if (_teststr(name, "convcolonly")) {
|
|
|
|
_gen_shape_list(mesh, shapes, true);
|
|
|
|
collision_map[mesh] = shapes;
|
2018-10-07 14:18:27 +00:00
|
|
|
}
|
2017-11-16 13:06:30 +00:00
|
|
|
|
2019-04-10 20:46:04 +00:00
|
|
|
if (_teststr(name, "colonly")) {
|
|
|
|
fixed_name = _fixstr(name, "colonly");
|
|
|
|
} else if (_teststr(name, "convcolonly")) {
|
|
|
|
fixed_name = _fixstr(name, "convcolonly");
|
2018-10-07 14:18:27 +00:00
|
|
|
}
|
2017-02-04 12:48:04 +00:00
|
|
|
|
2020-04-01 23:20:12 +00:00
|
|
|
ERR_FAIL_COND_V(fixed_name == String(), nullptr);
|
2019-04-10 20:46:04 +00:00
|
|
|
|
|
|
|
if (shapes.size()) {
|
2020-03-26 21:49:16 +00:00
|
|
|
StaticBody3D *col = memnew(StaticBody3D);
|
2019-04-10 20:46:04 +00:00
|
|
|
col->set_transform(mi->get_transform());
|
|
|
|
col->set_name(fixed_name);
|
|
|
|
p_node->replace_by(col);
|
|
|
|
memdelete(p_node);
|
|
|
|
p_node = col;
|
|
|
|
|
|
|
|
int idx = 0;
|
2020-03-26 21:49:16 +00:00
|
|
|
for (List<Ref<Shape3D>>::Element *E = shapes.front(); E; E = E->next()) {
|
|
|
|
CollisionShape3D *cshape = memnew(CollisionShape3D);
|
2019-04-10 20:46:04 +00:00
|
|
|
cshape->set_shape(E->get());
|
|
|
|
col->add_child(cshape);
|
2017-02-04 12:48:04 +00:00
|
|
|
|
2019-04-10 20:46:04 +00:00
|
|
|
cshape->set_name("shape" + itos(idx));
|
|
|
|
cshape->set_owner(col->get_owner());
|
|
|
|
idx++;
|
|
|
|
}
|
|
|
|
}
|
2018-10-07 14:18:27 +00:00
|
|
|
}
|
2019-04-10 20:46:04 +00:00
|
|
|
|
2017-02-04 12:48:04 +00:00
|
|
|
} else if (p_node->has_meta("empty_draw_type")) {
|
|
|
|
String empty_draw_type = String(p_node->get_meta("empty_draw_type"));
|
2020-03-26 21:49:16 +00:00
|
|
|
StaticBody3D *sb = memnew(StaticBody3D);
|
2017-03-05 15:44:50 +00:00
|
|
|
sb->set_name(_fixstr(name, "colonly"));
|
2020-03-26 21:49:16 +00:00
|
|
|
Object::cast_to<Node3D>(sb)->set_transform(Object::cast_to<Node3D>(p_node)->get_transform());
|
2017-02-04 12:48:04 +00:00
|
|
|
p_node->replace_by(sb);
|
|
|
|
memdelete(p_node);
|
2020-04-01 23:20:12 +00:00
|
|
|
p_node = nullptr;
|
2020-03-26 21:49:16 +00:00
|
|
|
CollisionShape3D *colshape = memnew(CollisionShape3D);
|
2017-02-04 12:48:04 +00:00
|
|
|
if (empty_draw_type == "CUBE") {
|
2020-03-26 21:49:16 +00:00
|
|
|
BoxShape3D *boxShape = memnew(BoxShape3D);
|
2017-02-04 12:48:04 +00:00
|
|
|
boxShape->set_extents(Vector3(1, 1, 1));
|
|
|
|
colshape->set_shape(boxShape);
|
2020-03-26 21:49:16 +00:00
|
|
|
colshape->set_name("BoxShape3D");
|
2017-02-04 12:48:04 +00:00
|
|
|
} else if (empty_draw_type == "SINGLE_ARROW") {
|
2020-03-26 21:49:16 +00:00
|
|
|
RayShape3D *rayShape = memnew(RayShape3D);
|
2017-02-04 12:48:04 +00:00
|
|
|
rayShape->set_length(1);
|
|
|
|
colshape->set_shape(rayShape);
|
2020-03-26 21:49:16 +00:00
|
|
|
colshape->set_name("RayShape3D");
|
|
|
|
Object::cast_to<Node3D>(sb)->rotate_x(Math_PI / 2);
|
2017-02-04 12:48:04 +00:00
|
|
|
} else if (empty_draw_type == "IMAGE") {
|
2020-03-26 21:49:16 +00:00
|
|
|
WorldMarginShape3D *world_margin_shape = memnew(WorldMarginShape3D);
|
2020-02-21 11:19:24 +00:00
|
|
|
colshape->set_shape(world_margin_shape);
|
2020-03-30 16:22:57 +00:00
|
|
|
colshape->set_name("WorldMarginShape3D");
|
2017-02-04 12:48:04 +00:00
|
|
|
} else {
|
2020-03-26 21:49:16 +00:00
|
|
|
SphereShape3D *sphereShape = memnew(SphereShape3D);
|
2017-02-04 12:48:04 +00:00
|
|
|
sphereShape->set_radius(1);
|
|
|
|
colshape->set_shape(sphereShape);
|
2020-03-26 21:49:16 +00:00
|
|
|
colshape->set_name("SphereShape3D");
|
2017-02-04 12:48:04 +00:00
|
|
|
}
|
|
|
|
sb->add_child(colshape);
|
|
|
|
colshape->set_owner(sb->get_owner());
|
|
|
|
}
|
|
|
|
|
2020-03-26 21:49:16 +00:00
|
|
|
} else if (_teststr(name, "rigid") && Object::cast_to<MeshInstance3D>(p_node)) {
|
2020-05-14 14:41:43 +00:00
|
|
|
if (isroot) {
|
2017-02-04 12:48:04 +00:00
|
|
|
return p_node;
|
2020-05-14 14:41:43 +00:00
|
|
|
}
|
2017-02-04 12:48:04 +00:00
|
|
|
|
2020-03-26 21:49:16 +00:00
|
|
|
MeshInstance3D *mi = Object::cast_to<MeshInstance3D>(p_node);
|
2019-04-10 20:46:04 +00:00
|
|
|
Ref<Mesh> mesh = mi->get_mesh();
|
|
|
|
|
|
|
|
if (mesh.is_valid()) {
|
2020-03-26 21:49:16 +00:00
|
|
|
List<Ref<Shape3D>> shapes;
|
2019-04-10 20:46:04 +00:00
|
|
|
if (collision_map.has(mesh)) {
|
|
|
|
shapes = collision_map[mesh];
|
|
|
|
} else {
|
|
|
|
_gen_shape_list(mesh, shapes, true);
|
|
|
|
}
|
|
|
|
|
2020-03-26 21:49:16 +00:00
|
|
|
RigidBody3D *rigid_body = memnew(RigidBody3D);
|
2019-04-10 20:46:04 +00:00
|
|
|
rigid_body->set_name(_fixstr(name, "rigid"));
|
|
|
|
p_node->replace_by(rigid_body);
|
|
|
|
rigid_body->set_transform(mi->get_transform());
|
|
|
|
p_node = rigid_body;
|
|
|
|
mi->set_name("mesh");
|
|
|
|
mi->set_transform(Transform());
|
|
|
|
rigid_body->add_child(mi);
|
|
|
|
mi->set_owner(rigid_body->get_owner());
|
|
|
|
|
|
|
|
int idx = 0;
|
2020-03-26 21:49:16 +00:00
|
|
|
for (List<Ref<Shape3D>>::Element *E = shapes.front(); E; E = E->next()) {
|
|
|
|
CollisionShape3D *cshape = memnew(CollisionShape3D);
|
2019-04-10 20:46:04 +00:00
|
|
|
cshape->set_shape(E->get());
|
|
|
|
rigid_body->add_child(cshape);
|
|
|
|
|
|
|
|
cshape->set_name("shape" + itos(idx));
|
|
|
|
cshape->set_owner(p_node->get_owner());
|
|
|
|
idx++;
|
|
|
|
}
|
|
|
|
}
|
2017-02-04 12:48:04 +00:00
|
|
|
|
2020-03-26 21:49:16 +00:00
|
|
|
} else if ((_teststr(name, "col") || (_teststr(name, "convcol"))) && Object::cast_to<MeshInstance3D>(p_node)) {
|
|
|
|
MeshInstance3D *mi = Object::cast_to<MeshInstance3D>(p_node);
|
2017-02-04 12:48:04 +00:00
|
|
|
|
2019-04-10 20:46:04 +00:00
|
|
|
Ref<Mesh> mesh = mi->get_mesh();
|
|
|
|
|
|
|
|
if (mesh.is_valid()) {
|
2020-03-26 21:49:16 +00:00
|
|
|
List<Ref<Shape3D>> shapes;
|
2019-04-10 20:46:04 +00:00
|
|
|
String fixed_name;
|
|
|
|
if (collision_map.has(mesh)) {
|
|
|
|
shapes = collision_map[mesh];
|
|
|
|
} else if (_teststr(name, "col")) {
|
|
|
|
_gen_shape_list(mesh, shapes, false);
|
|
|
|
collision_map[mesh] = shapes;
|
|
|
|
} else if (_teststr(name, "convcol")) {
|
|
|
|
_gen_shape_list(mesh, shapes, true);
|
|
|
|
collision_map[mesh] = shapes;
|
2018-07-02 08:54:14 +00:00
|
|
|
}
|
2017-11-16 13:06:30 +00:00
|
|
|
|
2019-04-10 20:46:04 +00:00
|
|
|
if (_teststr(name, "col")) {
|
|
|
|
fixed_name = _fixstr(name, "col");
|
|
|
|
} else if (_teststr(name, "convcol")) {
|
|
|
|
fixed_name = _fixstr(name, "convcol");
|
2018-07-02 08:54:14 +00:00
|
|
|
}
|
2017-11-16 13:06:30 +00:00
|
|
|
|
2019-04-10 20:46:04 +00:00
|
|
|
if (fixed_name != String()) {
|
|
|
|
if (mi->get_parent() && !mi->get_parent()->has_node(fixed_name)) {
|
|
|
|
mi->set_name(fixed_name);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (shapes.size()) {
|
2020-03-26 21:49:16 +00:00
|
|
|
StaticBody3D *col = memnew(StaticBody3D);
|
2019-04-10 20:46:04 +00:00
|
|
|
col->set_name("static_collision");
|
|
|
|
mi->add_child(col);
|
|
|
|
col->set_owner(mi->get_owner());
|
2017-02-04 12:48:04 +00:00
|
|
|
|
2019-04-10 20:46:04 +00:00
|
|
|
int idx = 0;
|
2020-03-26 21:49:16 +00:00
|
|
|
for (List<Ref<Shape3D>>::Element *E = shapes.front(); E; E = E->next()) {
|
|
|
|
CollisionShape3D *cshape = memnew(CollisionShape3D);
|
2019-04-10 20:46:04 +00:00
|
|
|
cshape->set_shape(E->get());
|
|
|
|
col->add_child(cshape);
|
|
|
|
|
|
|
|
cshape->set_name("shape" + itos(idx));
|
|
|
|
cshape->set_owner(p_node->get_owner());
|
|
|
|
|
|
|
|
idx++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2017-02-04 12:48:04 +00:00
|
|
|
|
2020-03-26 21:49:16 +00:00
|
|
|
} else if (_teststr(name, "navmesh") && Object::cast_to<MeshInstance3D>(p_node)) {
|
2020-05-14 14:41:43 +00:00
|
|
|
if (isroot) {
|
2017-02-04 12:48:04 +00:00
|
|
|
return p_node;
|
2020-05-14 14:41:43 +00:00
|
|
|
}
|
2017-02-04 12:48:04 +00:00
|
|
|
|
2020-03-26 21:49:16 +00:00
|
|
|
MeshInstance3D *mi = Object::cast_to<MeshInstance3D>(p_node);
|
2017-02-04 12:48:04 +00:00
|
|
|
|
2017-06-07 21:18:55 +00:00
|
|
|
Ref<ArrayMesh> mesh = mi->get_mesh();
|
2020-04-01 23:20:12 +00:00
|
|
|
ERR_FAIL_COND_V(mesh.is_null(), nullptr);
|
2020-03-26 21:49:16 +00:00
|
|
|
NavigationRegion3D *nmi = memnew(NavigationRegion3D);
|
2017-02-04 12:48:04 +00:00
|
|
|
|
2017-03-05 15:44:50 +00:00
|
|
|
nmi->set_name(_fixstr(name, "navmesh"));
|
|
|
|
Ref<NavigationMesh> nmesh = memnew(NavigationMesh);
|
2017-02-04 12:48:04 +00:00
|
|
|
nmesh->create_from_mesh(mesh);
|
|
|
|
nmi->set_navigation_mesh(nmesh);
|
2020-03-26 21:49:16 +00:00
|
|
|
Object::cast_to<Node3D>(nmi)->set_transform(mi->get_transform());
|
2017-02-04 12:48:04 +00:00
|
|
|
p_node->replace_by(nmi);
|
|
|
|
memdelete(p_node);
|
2017-03-05 15:44:50 +00:00
|
|
|
p_node = nmi;
|
|
|
|
} else if (_teststr(name, "vehicle")) {
|
2020-05-14 14:41:43 +00:00
|
|
|
if (isroot) {
|
2017-02-04 12:48:04 +00:00
|
|
|
return p_node;
|
2020-05-14 14:41:43 +00:00
|
|
|
}
|
2017-02-04 12:48:04 +00:00
|
|
|
|
|
|
|
Node *owner = p_node->get_owner();
|
2020-03-26 21:49:16 +00:00
|
|
|
Node3D *s = Object::cast_to<Node3D>(p_node);
|
2020-03-27 07:44:44 +00:00
|
|
|
VehicleBody3D *bv = memnew(VehicleBody3D);
|
2017-03-05 15:44:50 +00:00
|
|
|
String n = _fixstr(p_node->get_name(), "vehicle");
|
2017-02-04 12:48:04 +00:00
|
|
|
bv->set_name(n);
|
|
|
|
p_node->replace_by(bv);
|
|
|
|
p_node->set_name(n);
|
|
|
|
bv->add_child(p_node);
|
|
|
|
bv->set_owner(owner);
|
|
|
|
p_node->set_owner(owner);
|
|
|
|
bv->set_transform(s->get_transform());
|
|
|
|
s->set_transform(Transform());
|
|
|
|
|
2017-03-05 15:44:50 +00:00
|
|
|
p_node = bv;
|
2017-02-04 12:48:04 +00:00
|
|
|
|
2017-03-05 15:44:50 +00:00
|
|
|
} else if (_teststr(name, "wheel")) {
|
2020-05-14 14:41:43 +00:00
|
|
|
if (isroot) {
|
2017-02-04 12:48:04 +00:00
|
|
|
return p_node;
|
2020-05-14 14:41:43 +00:00
|
|
|
}
|
2017-02-04 12:48:04 +00:00
|
|
|
|
|
|
|
Node *owner = p_node->get_owner();
|
2020-03-26 21:49:16 +00:00
|
|
|
Node3D *s = Object::cast_to<Node3D>(p_node);
|
2020-03-27 07:44:44 +00:00
|
|
|
VehicleWheel3D *bv = memnew(VehicleWheel3D);
|
2017-03-05 15:44:50 +00:00
|
|
|
String n = _fixstr(p_node->get_name(), "wheel");
|
2017-02-04 12:48:04 +00:00
|
|
|
bv->set_name(n);
|
|
|
|
p_node->replace_by(bv);
|
|
|
|
p_node->set_name(n);
|
|
|
|
bv->add_child(p_node);
|
|
|
|
bv->set_owner(owner);
|
|
|
|
p_node->set_owner(owner);
|
|
|
|
bv->set_transform(s->get_transform());
|
|
|
|
s->set_transform(Transform());
|
|
|
|
|
2017-03-05 15:44:50 +00:00
|
|
|
p_node = bv;
|
2017-02-04 12:48:04 +00:00
|
|
|
|
2020-03-26 21:49:16 +00:00
|
|
|
} else if (Object::cast_to<MeshInstance3D>(p_node)) {
|
2017-11-16 13:06:30 +00:00
|
|
|
//last attempt, maybe collision inside the mesh data
|
2017-02-04 12:48:04 +00:00
|
|
|
|
2020-03-26 21:49:16 +00:00
|
|
|
MeshInstance3D *mi = Object::cast_to<MeshInstance3D>(p_node);
|
2017-02-04 12:48:04 +00:00
|
|
|
|
2017-06-07 21:18:55 +00:00
|
|
|
Ref<ArrayMesh> mesh = mi->get_mesh();
|
2017-02-04 12:48:04 +00:00
|
|
|
if (!mesh.is_null()) {
|
2020-03-26 21:49:16 +00:00
|
|
|
List<Ref<Shape3D>> shapes;
|
2019-04-10 20:46:04 +00:00
|
|
|
if (collision_map.has(mesh)) {
|
|
|
|
shapes = collision_map[mesh];
|
|
|
|
} else if (_teststr(mesh->get_name(), "col")) {
|
|
|
|
_gen_shape_list(mesh, shapes, false);
|
|
|
|
collision_map[mesh] = shapes;
|
|
|
|
mesh->set_name(_fixstr(mesh->get_name(), "col"));
|
|
|
|
} else if (_teststr(mesh->get_name(), "convcol")) {
|
|
|
|
_gen_shape_list(mesh, shapes, true);
|
|
|
|
collision_map[mesh] = shapes;
|
|
|
|
mesh->set_name(_fixstr(mesh->get_name(), "convcol"));
|
|
|
|
}
|
2017-11-16 13:06:30 +00:00
|
|
|
|
2019-04-10 20:46:04 +00:00
|
|
|
if (shapes.size()) {
|
2020-03-26 21:49:16 +00:00
|
|
|
StaticBody3D *col = memnew(StaticBody3D);
|
2019-04-10 20:46:04 +00:00
|
|
|
col->set_name("static_collision");
|
|
|
|
p_node->add_child(col);
|
|
|
|
col->set_owner(p_node->get_owner());
|
2017-11-16 13:06:30 +00:00
|
|
|
|
2019-04-10 20:46:04 +00:00
|
|
|
int idx = 0;
|
2020-03-26 21:49:16 +00:00
|
|
|
for (List<Ref<Shape3D>>::Element *E = shapes.front(); E; E = E->next()) {
|
|
|
|
CollisionShape3D *cshape = memnew(CollisionShape3D);
|
2019-04-10 20:46:04 +00:00
|
|
|
cshape->set_shape(E->get());
|
2017-11-16 13:06:30 +00:00
|
|
|
col->add_child(cshape);
|
2017-02-04 12:48:04 +00:00
|
|
|
|
2019-04-10 20:46:04 +00:00
|
|
|
cshape->set_name("shape" + itos(idx));
|
2017-11-16 13:06:30 +00:00
|
|
|
cshape->set_owner(p_node->get_owner());
|
2019-04-10 20:46:04 +00:00
|
|
|
idx++;
|
2017-02-04 12:48:04 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return p_node;
|
|
|
|
}
|
|
|
|
|
2017-03-05 15:44:50 +00:00
|
|
|
void ResourceImporterScene::_create_clips(Node *scene, const Array &p_clips, bool p_bake_all) {
|
2020-05-14 14:41:43 +00:00
|
|
|
if (!scene->has_node(String("AnimationPlayer"))) {
|
2017-02-04 12:48:04 +00:00
|
|
|
return;
|
2020-05-14 14:41:43 +00:00
|
|
|
}
|
2017-02-04 12:48:04 +00:00
|
|
|
|
2017-03-05 15:44:50 +00:00
|
|
|
Node *n = scene->get_node(String("AnimationPlayer"));
|
2017-02-04 12:48:04 +00:00
|
|
|
ERR_FAIL_COND(!n);
|
2017-08-24 20:58:51 +00:00
|
|
|
AnimationPlayer *anim = Object::cast_to<AnimationPlayer>(n);
|
2017-02-04 12:48:04 +00:00
|
|
|
ERR_FAIL_COND(!anim);
|
|
|
|
|
2020-05-14 14:41:43 +00:00
|
|
|
if (!anim->has_animation("default")) {
|
2017-02-04 12:48:04 +00:00
|
|
|
return;
|
2020-05-14 14:41:43 +00:00
|
|
|
}
|
2017-02-04 12:48:04 +00:00
|
|
|
|
|
|
|
Ref<Animation> default_anim = anim->get_animation("default");
|
|
|
|
|
2017-03-05 15:44:50 +00:00
|
|
|
for (int i = 0; i < p_clips.size(); i += 4) {
|
2017-02-04 12:48:04 +00:00
|
|
|
String name = p_clips[i];
|
2017-03-05 15:44:50 +00:00
|
|
|
float from = p_clips[i + 1];
|
|
|
|
float to = p_clips[i + 2];
|
|
|
|
bool loop = p_clips[i + 3];
|
2020-05-14 14:41:43 +00:00
|
|
|
if (from >= to) {
|
2017-02-04 12:48:04 +00:00
|
|
|
continue;
|
2020-05-14 14:41:43 +00:00
|
|
|
}
|
2017-02-04 12:48:04 +00:00
|
|
|
|
2017-03-05 15:44:50 +00:00
|
|
|
Ref<Animation> new_anim = memnew(Animation);
|
2017-02-04 12:48:04 +00:00
|
|
|
|
2017-03-05 15:44:50 +00:00
|
|
|
for (int j = 0; j < default_anim->get_track_count(); j++) {
|
2017-02-04 12:48:04 +00:00
|
|
|
List<float> keys;
|
|
|
|
int kc = default_anim->track_get_key_count(j);
|
2017-03-05 15:44:50 +00:00
|
|
|
int dtrack = -1;
|
|
|
|
for (int k = 0; k < kc; k++) {
|
|
|
|
float kt = default_anim->track_get_key_time(j, k);
|
|
|
|
if (kt >= from && kt < to) {
|
2017-02-04 12:48:04 +00:00
|
|
|
//found a key within range, so create track
|
2017-03-05 15:44:50 +00:00
|
|
|
if (dtrack == -1) {
|
2017-02-04 12:48:04 +00:00
|
|
|
new_anim->add_track(default_anim->track_get_type(j));
|
2017-03-05 15:44:50 +00:00
|
|
|
dtrack = new_anim->get_track_count() - 1;
|
|
|
|
new_anim->track_set_path(dtrack, default_anim->track_get_path(j));
|
2017-02-04 12:48:04 +00:00
|
|
|
|
2017-03-05 15:44:50 +00:00
|
|
|
if (kt > (from + 0.01) && k > 0) {
|
|
|
|
if (default_anim->track_get_type(j) == Animation::TYPE_TRANSFORM) {
|
2017-02-04 12:48:04 +00:00
|
|
|
Quat q;
|
|
|
|
Vector3 p;
|
|
|
|
Vector3 s;
|
2017-03-05 15:44:50 +00:00
|
|
|
default_anim->transform_track_interpolate(j, from, &p, &q, &s);
|
|
|
|
new_anim->transform_track_insert_key(dtrack, 0, p, q, s);
|
2017-02-04 12:48:04 +00:00
|
|
|
}
|
2019-04-23 23:34:37 +00:00
|
|
|
if (default_anim->track_get_type(j) == Animation::TYPE_VALUE) {
|
|
|
|
Variant var = default_anim->value_track_interpolate(j, from);
|
|
|
|
new_anim->track_insert_key(dtrack, 0, var);
|
|
|
|
}
|
2017-02-04 12:48:04 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-03-05 15:44:50 +00:00
|
|
|
if (default_anim->track_get_type(j) == Animation::TYPE_TRANSFORM) {
|
2017-02-04 12:48:04 +00:00
|
|
|
Quat q;
|
|
|
|
Vector3 p;
|
|
|
|
Vector3 s;
|
2017-03-05 15:44:50 +00:00
|
|
|
default_anim->transform_track_get_key(j, k, &p, &q, &s);
|
|
|
|
new_anim->transform_track_insert_key(dtrack, kt - from, p, q, s);
|
2017-02-04 12:48:04 +00:00
|
|
|
}
|
2019-04-23 23:34:37 +00:00
|
|
|
if (default_anim->track_get_type(j) == Animation::TYPE_VALUE) {
|
|
|
|
Variant var = default_anim->track_get_key_value(j, k);
|
|
|
|
new_anim->track_insert_key(dtrack, kt - from, var);
|
|
|
|
}
|
2017-02-04 12:48:04 +00:00
|
|
|
}
|
|
|
|
|
2017-03-05 15:44:50 +00:00
|
|
|
if (dtrack != -1 && kt >= to) {
|
|
|
|
if (default_anim->track_get_type(j) == Animation::TYPE_TRANSFORM) {
|
2017-02-04 12:48:04 +00:00
|
|
|
Quat q;
|
|
|
|
Vector3 p;
|
|
|
|
Vector3 s;
|
2017-03-05 15:44:50 +00:00
|
|
|
default_anim->transform_track_interpolate(j, to, &p, &q, &s);
|
|
|
|
new_anim->transform_track_insert_key(dtrack, to - from, p, q, s);
|
2017-02-04 12:48:04 +00:00
|
|
|
}
|
2019-04-23 23:34:37 +00:00
|
|
|
if (default_anim->track_get_type(j) == Animation::TYPE_VALUE) {
|
|
|
|
Variant var = default_anim->value_track_interpolate(j, to);
|
|
|
|
new_anim->track_insert_key(dtrack, to - from, var);
|
|
|
|
}
|
2017-02-04 12:48:04 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-03-05 15:44:50 +00:00
|
|
|
if (dtrack == -1 && p_bake_all) {
|
2017-02-04 12:48:04 +00:00
|
|
|
new_anim->add_track(default_anim->track_get_type(j));
|
2017-03-05 15:44:50 +00:00
|
|
|
dtrack = new_anim->get_track_count() - 1;
|
|
|
|
new_anim->track_set_path(dtrack, default_anim->track_get_path(j));
|
|
|
|
if (default_anim->track_get_type(j) == Animation::TYPE_TRANSFORM) {
|
2017-02-04 12:48:04 +00:00
|
|
|
Quat q;
|
|
|
|
Vector3 p;
|
|
|
|
Vector3 s;
|
2017-03-05 15:44:50 +00:00
|
|
|
default_anim->transform_track_interpolate(j, from, &p, &q, &s);
|
|
|
|
new_anim->transform_track_insert_key(dtrack, 0, p, q, s);
|
|
|
|
default_anim->transform_track_interpolate(j, to, &p, &q, &s);
|
|
|
|
new_anim->transform_track_insert_key(dtrack, to - from, p, q, s);
|
2017-02-04 12:48:04 +00:00
|
|
|
}
|
2019-04-23 23:34:37 +00:00
|
|
|
if (default_anim->track_get_type(j) == Animation::TYPE_VALUE) {
|
|
|
|
Variant var = default_anim->value_track_interpolate(j, from);
|
|
|
|
new_anim->track_insert_key(dtrack, 0, var);
|
|
|
|
Variant to_var = default_anim->value_track_interpolate(j, to);
|
|
|
|
new_anim->track_insert_key(dtrack, to - from, to_var);
|
|
|
|
}
|
2017-02-04 12:48:04 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
new_anim->set_loop(loop);
|
2017-03-05 15:44:50 +00:00
|
|
|
new_anim->set_length(to - from);
|
|
|
|
anim->add_animation(name, new_anim);
|
2017-02-04 12:48:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
anim->remove_animation("default"); //remove default (no longer needed)
|
|
|
|
}
|
|
|
|
|
2017-03-05 15:44:50 +00:00
|
|
|
void ResourceImporterScene::_filter_anim_tracks(Ref<Animation> anim, Set<String> &keep) {
|
2017-02-04 12:48:04 +00:00
|
|
|
Ref<Animation> a = anim;
|
|
|
|
ERR_FAIL_COND(!a.is_valid());
|
|
|
|
|
2017-03-05 15:44:50 +00:00
|
|
|
for (int j = 0; j < a->get_track_count(); j++) {
|
2017-02-04 12:48:04 +00:00
|
|
|
String path = a->track_get_path(j);
|
|
|
|
|
|
|
|
if (!keep.has(path)) {
|
|
|
|
a->remove_track(j);
|
|
|
|
j--;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-03-05 15:44:50 +00:00
|
|
|
void ResourceImporterScene::_filter_tracks(Node *scene, const String &p_text) {
|
2020-05-14 14:41:43 +00:00
|
|
|
if (!scene->has_node(String("AnimationPlayer"))) {
|
2017-02-04 12:48:04 +00:00
|
|
|
return;
|
2020-05-14 14:41:43 +00:00
|
|
|
}
|
2017-03-05 15:44:50 +00:00
|
|
|
Node *n = scene->get_node(String("AnimationPlayer"));
|
2017-02-04 12:48:04 +00:00
|
|
|
ERR_FAIL_COND(!n);
|
2017-08-24 20:58:51 +00:00
|
|
|
AnimationPlayer *anim = Object::cast_to<AnimationPlayer>(n);
|
2017-02-04 12:48:04 +00:00
|
|
|
ERR_FAIL_COND(!anim);
|
|
|
|
|
|
|
|
Vector<String> strings = p_text.split("\n");
|
2017-03-05 15:44:50 +00:00
|
|
|
for (int i = 0; i < strings.size(); i++) {
|
2018-07-25 01:11:03 +00:00
|
|
|
strings.write[i] = strings[i].strip_edges();
|
2017-02-04 12:48:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
List<StringName> anim_names;
|
|
|
|
anim->get_animation_list(&anim_names);
|
2017-03-05 15:44:50 +00:00
|
|
|
for (List<StringName>::Element *E = anim_names.front(); E; E = E->next()) {
|
2017-02-04 12:48:04 +00:00
|
|
|
String name = E->get();
|
2017-03-05 15:44:50 +00:00
|
|
|
bool valid_for_this = false;
|
|
|
|
bool valid = false;
|
2017-02-04 12:48:04 +00:00
|
|
|
|
|
|
|
Set<String> keep;
|
|
|
|
Set<String> keep_local;
|
|
|
|
|
2017-03-05 15:44:50 +00:00
|
|
|
for (int i = 0; i < strings.size(); i++) {
|
2017-02-04 12:48:04 +00:00
|
|
|
if (strings[i].begins_with("@")) {
|
2017-03-05 15:44:50 +00:00
|
|
|
valid_for_this = false;
|
|
|
|
for (Set<String>::Element *F = keep_local.front(); F; F = F->next()) {
|
2017-02-04 12:48:04 +00:00
|
|
|
keep.insert(F->get());
|
|
|
|
}
|
|
|
|
keep_local.clear();
|
|
|
|
|
2017-03-05 15:44:50 +00:00
|
|
|
Vector<String> filters = strings[i].substr(1, strings[i].length()).split(",");
|
|
|
|
for (int j = 0; j < filters.size(); j++) {
|
2017-02-04 12:48:04 +00:00
|
|
|
String fname = filters[j].strip_edges();
|
2020-05-14 14:41:43 +00:00
|
|
|
if (fname == "") {
|
2017-02-04 12:48:04 +00:00
|
|
|
continue;
|
2020-05-14 14:41:43 +00:00
|
|
|
}
|
2017-02-04 12:48:04 +00:00
|
|
|
int fc = fname[0];
|
|
|
|
bool plus;
|
2020-05-14 14:41:43 +00:00
|
|
|
if (fc == '+') {
|
2017-03-05 15:44:50 +00:00
|
|
|
plus = true;
|
2020-05-14 14:41:43 +00:00
|
|
|
} else if (fc == '-') {
|
2017-03-05 15:44:50 +00:00
|
|
|
plus = false;
|
2020-05-14 14:41:43 +00:00
|
|
|
} else {
|
2017-02-04 12:48:04 +00:00
|
|
|
continue;
|
2020-05-14 14:41:43 +00:00
|
|
|
}
|
2017-02-04 12:48:04 +00:00
|
|
|
|
2017-03-05 15:44:50 +00:00
|
|
|
String filter = fname.substr(1, fname.length()).strip_edges();
|
2017-02-04 12:48:04 +00:00
|
|
|
|
2020-05-14 14:41:43 +00:00
|
|
|
if (!name.matchn(filter)) {
|
2017-02-04 12:48:04 +00:00
|
|
|
continue;
|
2020-05-14 14:41:43 +00:00
|
|
|
}
|
2017-03-05 15:44:50 +00:00
|
|
|
valid_for_this = plus;
|
2017-02-04 12:48:04 +00:00
|
|
|
}
|
|
|
|
|
2020-05-14 14:41:43 +00:00
|
|
|
if (valid_for_this) {
|
2017-03-05 15:44:50 +00:00
|
|
|
valid = true;
|
2020-05-14 14:41:43 +00:00
|
|
|
}
|
2017-02-04 12:48:04 +00:00
|
|
|
|
|
|
|
} else if (valid_for_this) {
|
|
|
|
Ref<Animation> a = anim->get_animation(name);
|
2020-05-14 14:41:43 +00:00
|
|
|
if (!a.is_valid()) {
|
2017-02-04 12:48:04 +00:00
|
|
|
continue;
|
2020-05-14 14:41:43 +00:00
|
|
|
}
|
2017-02-04 12:48:04 +00:00
|
|
|
|
2017-03-05 15:44:50 +00:00
|
|
|
for (int j = 0; j < a->get_track_count(); j++) {
|
2017-02-04 12:48:04 +00:00
|
|
|
String path = a->track_get_path(j);
|
|
|
|
|
|
|
|
String tname = strings[i];
|
2020-05-14 14:41:43 +00:00
|
|
|
if (tname == "") {
|
2017-02-04 12:48:04 +00:00
|
|
|
continue;
|
2020-05-14 14:41:43 +00:00
|
|
|
}
|
2017-02-04 12:48:04 +00:00
|
|
|
int fc = tname[0];
|
|
|
|
bool plus;
|
2020-05-14 14:41:43 +00:00
|
|
|
if (fc == '+') {
|
2017-03-05 15:44:50 +00:00
|
|
|
plus = true;
|
2020-05-14 14:41:43 +00:00
|
|
|
} else if (fc == '-') {
|
2017-03-05 15:44:50 +00:00
|
|
|
plus = false;
|
2020-05-14 14:41:43 +00:00
|
|
|
} else {
|
2017-02-04 12:48:04 +00:00
|
|
|
continue;
|
2020-05-14 14:41:43 +00:00
|
|
|
}
|
2017-02-04 12:48:04 +00:00
|
|
|
|
2017-03-05 15:44:50 +00:00
|
|
|
String filter = tname.substr(1, tname.length()).strip_edges();
|
2017-02-04 12:48:04 +00:00
|
|
|
|
2020-05-14 14:41:43 +00:00
|
|
|
if (!path.matchn(filter)) {
|
2017-02-04 12:48:04 +00:00
|
|
|
continue;
|
2020-05-14 14:41:43 +00:00
|
|
|
}
|
2017-02-04 12:48:04 +00:00
|
|
|
|
2020-05-14 14:41:43 +00:00
|
|
|
if (plus) {
|
2017-02-04 12:48:04 +00:00
|
|
|
keep_local.insert(path);
|
2020-05-14 14:41:43 +00:00
|
|
|
} else if (!keep.has(path)) {
|
2017-02-04 12:48:04 +00:00
|
|
|
keep_local.erase(path);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (valid) {
|
2017-03-05 15:44:50 +00:00
|
|
|
for (Set<String>::Element *F = keep_local.front(); F; F = F->next()) {
|
2017-02-04 12:48:04 +00:00
|
|
|
keep.insert(F->get());
|
|
|
|
}
|
2017-03-05 15:44:50 +00:00
|
|
|
_filter_anim_tracks(anim->get_animation(name), keep);
|
2017-02-04 12:48:04 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-03-05 15:44:50 +00:00
|
|
|
void ResourceImporterScene::_optimize_animations(Node *scene, float p_max_lin_error, float p_max_ang_error, float p_max_angle) {
|
2020-05-14 14:41:43 +00:00
|
|
|
if (!scene->has_node(String("AnimationPlayer"))) {
|
2017-02-04 12:48:04 +00:00
|
|
|
return;
|
2020-05-14 14:41:43 +00:00
|
|
|
}
|
2017-03-05 15:44:50 +00:00
|
|
|
Node *n = scene->get_node(String("AnimationPlayer"));
|
2017-02-04 12:48:04 +00:00
|
|
|
ERR_FAIL_COND(!n);
|
2017-08-24 20:58:51 +00:00
|
|
|
AnimationPlayer *anim = Object::cast_to<AnimationPlayer>(n);
|
2017-02-04 12:48:04 +00:00
|
|
|
ERR_FAIL_COND(!anim);
|
|
|
|
|
|
|
|
List<StringName> anim_names;
|
|
|
|
anim->get_animation_list(&anim_names);
|
2017-03-05 15:44:50 +00:00
|
|
|
for (List<StringName>::Element *E = anim_names.front(); E; E = E->next()) {
|
2017-02-04 12:48:04 +00:00
|
|
|
Ref<Animation> a = anim->get_animation(E->get());
|
2017-03-05 15:44:50 +00:00
|
|
|
a->optimize(p_max_lin_error, p_max_ang_error, Math::deg2rad(p_max_angle));
|
2017-02-04 12:48:04 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-03-05 15:44:50 +00:00
|
|
|
static String _make_extname(const String &p_str) {
|
|
|
|
String ext_name = p_str.replace(".", "_");
|
|
|
|
ext_name = ext_name.replace(":", "_");
|
|
|
|
ext_name = ext_name.replace("\"", "_");
|
|
|
|
ext_name = ext_name.replace("<", "_");
|
|
|
|
ext_name = ext_name.replace(">", "_");
|
|
|
|
ext_name = ext_name.replace("/", "_");
|
|
|
|
ext_name = ext_name.replace("|", "_");
|
|
|
|
ext_name = ext_name.replace("\\", "_");
|
|
|
|
ext_name = ext_name.replace("?", "_");
|
|
|
|
ext_name = ext_name.replace("*", "_");
|
2017-02-04 23:31:15 +00:00
|
|
|
|
|
|
|
return ext_name;
|
|
|
|
}
|
|
|
|
|
2017-12-09 17:11:26 +00:00
|
|
|
void ResourceImporterScene::_find_meshes(Node *p_node, Map<Ref<ArrayMesh>, Transform> &meshes) {
|
|
|
|
List<PropertyInfo> pi;
|
|
|
|
p_node->get_property_list(&pi);
|
|
|
|
|
2020-03-26 21:49:16 +00:00
|
|
|
MeshInstance3D *mi = Object::cast_to<MeshInstance3D>(p_node);
|
2017-12-09 17:11:26 +00:00
|
|
|
|
|
|
|
if (mi) {
|
|
|
|
Ref<ArrayMesh> mesh = mi->get_mesh();
|
|
|
|
|
|
|
|
if (mesh.is_valid() && !meshes.has(mesh)) {
|
2020-03-26 21:49:16 +00:00
|
|
|
Node3D *s = mi;
|
2017-12-17 15:04:35 +00:00
|
|
|
Transform transform;
|
|
|
|
while (s) {
|
|
|
|
transform = transform * s->get_transform();
|
2020-05-01 12:34:23 +00:00
|
|
|
s = Object::cast_to<Node3D>(s->get_parent());
|
2017-12-09 17:11:26 +00:00
|
|
|
}
|
|
|
|
|
2017-12-17 15:04:35 +00:00
|
|
|
meshes[mesh] = transform;
|
2017-12-09 17:11:26 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
for (int i = 0; i < p_node->get_child_count(); i++) {
|
|
|
|
_find_meshes(p_node->get_child(i), meshes);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-03-17 06:33:00 +00:00
|
|
|
void ResourceImporterScene::_make_external_resources(Node *p_node, const String &p_base_path, bool p_make_animations, bool p_animations_as_text, bool p_keep_animations, bool p_make_materials, bool p_materials_as_text, bool p_keep_materials, bool p_make_meshes, bool p_meshes_as_text, Map<Ref<Animation>, Ref<Animation>> &p_animations, Map<Ref<Material>, Ref<Material>> &p_materials, Map<Ref<ArrayMesh>, Ref<ArrayMesh>> &p_meshes) {
|
2017-02-04 23:31:15 +00:00
|
|
|
List<PropertyInfo> pi;
|
|
|
|
|
2017-09-08 11:06:09 +00:00
|
|
|
if (p_make_animations) {
|
|
|
|
if (Object::cast_to<AnimationPlayer>(p_node)) {
|
|
|
|
AnimationPlayer *ap = Object::cast_to<AnimationPlayer>(p_node);
|
|
|
|
|
|
|
|
List<StringName> anims;
|
|
|
|
ap->get_animation_list(&anims);
|
|
|
|
for (List<StringName>::Element *E = anims.front(); E; E = E->next()) {
|
|
|
|
Ref<Animation> anim = ap->get_animation(E->get());
|
|
|
|
ERR_CONTINUE(anim.is_null());
|
|
|
|
|
|
|
|
if (!p_animations.has(anim)) {
|
2020-06-30 02:10:18 +00:00
|
|
|
// Tracks from source file should be set as imported, anything else is a custom track.
|
2017-12-07 13:18:55 +00:00
|
|
|
for (int i = 0; i < anim->get_track_count(); i++) {
|
2020-06-30 02:10:18 +00:00
|
|
|
anim->track_set_imported(i, true);
|
2017-12-07 13:18:55 +00:00
|
|
|
}
|
|
|
|
|
2019-04-08 08:48:52 +00:00
|
|
|
String ext_name;
|
|
|
|
|
|
|
|
if (p_animations_as_text) {
|
|
|
|
ext_name = p_base_path.plus_file(_make_extname(E->get()) + ".tres");
|
|
|
|
} else {
|
|
|
|
ext_name = p_base_path.plus_file(_make_extname(E->get()) + ".anim");
|
|
|
|
}
|
|
|
|
|
2017-12-07 13:18:55 +00:00
|
|
|
if (FileAccess::exists(ext_name) && p_keep_animations) {
|
2020-06-30 02:10:18 +00:00
|
|
|
// Copy custom animation tracks from previously imported files.
|
2017-12-07 13:18:55 +00:00
|
|
|
Ref<Animation> old_anim = ResourceLoader::load(ext_name, "Animation", true);
|
|
|
|
if (old_anim.is_valid()) {
|
|
|
|
for (int i = 0; i < old_anim->get_track_count(); i++) {
|
|
|
|
if (!old_anim->track_is_imported(i)) {
|
|
|
|
old_anim->copy_track(i, anim);
|
|
|
|
}
|
|
|
|
}
|
2019-03-25 23:02:11 +00:00
|
|
|
anim->set_loop(old_anim->has_loop());
|
2017-12-07 13:18:55 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-06-30 02:10:18 +00:00
|
|
|
anim->set_path(ext_name, true); // Set path to save externally.
|
2017-09-08 11:06:09 +00:00
|
|
|
ResourceSaver::save(ext_name, anim, ResourceSaver::FLAG_CHANGE_PATH);
|
|
|
|
p_animations[anim] = anim;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-02-04 23:31:15 +00:00
|
|
|
p_node->get_property_list(&pi);
|
|
|
|
|
2017-03-05 15:44:50 +00:00
|
|
|
for (List<PropertyInfo>::Element *E = pi.front(); E; E = E->next()) {
|
|
|
|
if (E->get().type == Variant::OBJECT) {
|
2017-02-04 23:31:15 +00:00
|
|
|
Ref<Material> mat = p_node->get(E->get().name);
|
2017-08-18 11:25:04 +00:00
|
|
|
|
2017-03-05 15:44:50 +00:00
|
|
|
if (p_make_materials && mat.is_valid() && mat->get_name() != "") {
|
2017-02-04 23:31:15 +00:00
|
|
|
if (!p_materials.has(mat)) {
|
2019-04-08 08:48:52 +00:00
|
|
|
String ext_name;
|
|
|
|
|
|
|
|
if (p_materials_as_text) {
|
|
|
|
ext_name = p_base_path.plus_file(_make_extname(mat->get_name()) + ".tres");
|
|
|
|
} else {
|
|
|
|
ext_name = p_base_path.plus_file(_make_extname(mat->get_name()) + ".material");
|
|
|
|
}
|
|
|
|
|
2017-07-23 21:48:05 +00:00
|
|
|
if (p_keep_materials && FileAccess::exists(ext_name)) {
|
2017-02-04 23:31:15 +00:00
|
|
|
//if exists, use it
|
2017-11-07 04:22:37 +00:00
|
|
|
p_materials[mat] = ResourceLoader::load(ext_name);
|
2017-02-04 23:31:15 +00:00
|
|
|
} else {
|
2017-03-05 15:44:50 +00:00
|
|
|
ResourceSaver::save(ext_name, mat, ResourceSaver::FLAG_CHANGE_PATH);
|
2018-12-11 13:56:36 +00:00
|
|
|
p_materials[mat] = ResourceLoader::load(ext_name, "", true); // disable loading from the cache.
|
2017-02-04 23:31:15 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-03-05 15:44:50 +00:00
|
|
|
if (p_materials[mat] != mat) {
|
|
|
|
p_node->set(E->get().name, p_materials[mat]);
|
2017-02-04 23:31:15 +00:00
|
|
|
}
|
|
|
|
} else {
|
2017-06-07 21:18:55 +00:00
|
|
|
Ref<ArrayMesh> mesh = p_node->get(E->get().name);
|
2017-02-04 23:31:15 +00:00
|
|
|
|
|
|
|
if (mesh.is_valid()) {
|
2017-03-05 15:44:50 +00:00
|
|
|
bool mesh_just_added = false;
|
2017-02-04 23:31:15 +00:00
|
|
|
|
|
|
|
if (p_make_meshes) {
|
|
|
|
if (!p_meshes.has(mesh)) {
|
2017-07-23 21:48:05 +00:00
|
|
|
//meshes are always overwritten, keeping them is not practical
|
2019-04-08 08:48:52 +00:00
|
|
|
String ext_name;
|
|
|
|
|
|
|
|
if (p_meshes_as_text) {
|
|
|
|
ext_name = p_base_path.plus_file(_make_extname(mesh->get_name()) + ".tres");
|
|
|
|
} else {
|
|
|
|
ext_name = p_base_path.plus_file(_make_extname(mesh->get_name()) + ".mesh");
|
|
|
|
}
|
2017-02-04 23:31:15 +00:00
|
|
|
|
2017-07-23 21:48:05 +00:00
|
|
|
ResourceSaver::save(ext_name, mesh, ResourceSaver::FLAG_CHANGE_PATH);
|
2017-11-07 04:22:37 +00:00
|
|
|
p_meshes[mesh] = ResourceLoader::load(ext_name);
|
|
|
|
p_node->set(E->get().name, p_meshes[mesh]);
|
2017-07-23 21:48:05 +00:00
|
|
|
mesh_just_added = true;
|
2017-02-04 23:31:15 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-03-05 15:44:50 +00:00
|
|
|
if (p_make_materials) {
|
2017-02-04 23:31:15 +00:00
|
|
|
if (mesh_just_added || !p_meshes.has(mesh)) {
|
2017-03-05 15:44:50 +00:00
|
|
|
for (int i = 0; i < mesh->get_surface_count(); i++) {
|
|
|
|
mat = mesh->surface_get_material(i);
|
2017-11-25 15:32:02 +00:00
|
|
|
|
2020-05-14 14:41:43 +00:00
|
|
|
if (!mat.is_valid()) {
|
2017-11-25 15:32:02 +00:00
|
|
|
continue;
|
2020-05-14 14:41:43 +00:00
|
|
|
}
|
|
|
|
if (mat->get_name() == "") {
|
2017-02-04 23:31:15 +00:00
|
|
|
continue;
|
2020-05-14 14:41:43 +00:00
|
|
|
}
|
2017-02-04 23:31:15 +00:00
|
|
|
|
|
|
|
if (!p_materials.has(mat)) {
|
2019-04-08 08:48:52 +00:00
|
|
|
String ext_name;
|
|
|
|
|
|
|
|
if (p_materials_as_text) {
|
|
|
|
ext_name = p_base_path.plus_file(_make_extname(mat->get_name()) + ".tres");
|
|
|
|
} else {
|
|
|
|
ext_name = p_base_path.plus_file(_make_extname(mat->get_name()) + ".material");
|
|
|
|
}
|
2017-02-04 23:31:15 +00:00
|
|
|
|
2018-12-11 13:56:36 +00:00
|
|
|
if (p_keep_materials && FileAccess::exists(ext_name)) {
|
2017-02-04 23:31:15 +00:00
|
|
|
//if exists, use it
|
2017-11-07 04:22:37 +00:00
|
|
|
p_materials[mat] = ResourceLoader::load(ext_name);
|
2017-02-04 23:31:15 +00:00
|
|
|
} else {
|
2017-03-05 15:44:50 +00:00
|
|
|
ResourceSaver::save(ext_name, mat, ResourceSaver::FLAG_CHANGE_PATH);
|
2018-12-11 13:56:36 +00:00
|
|
|
p_materials[mat] = ResourceLoader::load(ext_name, "", true); // disable loading from the cache.
|
2017-02-04 23:31:15 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-03-05 15:44:50 +00:00
|
|
|
if (p_materials[mat] != mat) {
|
|
|
|
mesh->surface_set_material(i, p_materials[mat]);
|
2017-11-07 04:22:37 +00:00
|
|
|
|
|
|
|
//re-save the mesh since a material is now assigned
|
|
|
|
if (p_make_meshes) {
|
2019-04-08 08:48:52 +00:00
|
|
|
String ext_name;
|
|
|
|
|
|
|
|
if (p_meshes_as_text) {
|
|
|
|
ext_name = p_base_path.plus_file(_make_extname(mesh->get_name()) + ".tres");
|
|
|
|
} else {
|
|
|
|
ext_name = p_base_path.plus_file(_make_extname(mesh->get_name()) + ".mesh");
|
|
|
|
}
|
|
|
|
|
2017-11-07 04:22:37 +00:00
|
|
|
ResourceSaver::save(ext_name, mesh, ResourceSaver::FLAG_CHANGE_PATH);
|
|
|
|
p_meshes[mesh] = ResourceLoader::load(ext_name);
|
|
|
|
}
|
2017-02-04 23:31:15 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-03-05 15:44:50 +00:00
|
|
|
if (!p_make_meshes) {
|
2017-06-07 21:18:55 +00:00
|
|
|
p_meshes[mesh] = Ref<ArrayMesh>(); //save it anyway, so it won't be checked again
|
2017-02-04 23:31:15 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-03-05 15:44:50 +00:00
|
|
|
for (int i = 0; i < p_node->get_child_count(); i++) {
|
2019-04-08 08:48:52 +00:00
|
|
|
_make_external_resources(p_node->get_child(i), p_base_path, p_make_animations, p_animations_as_text, p_keep_animations, p_make_materials, p_materials_as_text, p_keep_materials, p_make_meshes, p_meshes_as_text, p_animations, p_materials, p_meshes);
|
2017-02-04 23:31:15 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-03-05 15:44:50 +00:00
|
|
|
void ResourceImporterScene::get_import_options(List<ImportOption> *r_options, int p_preset) const {
|
2020-03-26 21:49:16 +00:00
|
|
|
r_options->push_back(ImportOption(PropertyInfo(Variant::STRING, "nodes/root_type", PROPERTY_HINT_TYPE_STRING, "Node"), "Node3D"));
|
2017-03-05 15:44:50 +00:00
|
|
|
r_options->push_back(ImportOption(PropertyInfo(Variant::STRING, "nodes/root_name"), "Scene Root"));
|
2017-02-04 12:48:04 +00:00
|
|
|
|
|
|
|
List<String> script_extentions;
|
2017-03-05 15:44:50 +00:00
|
|
|
ResourceLoader::get_recognized_extensions_for_type("Script", &script_extentions);
|
2017-02-04 12:48:04 +00:00
|
|
|
|
|
|
|
String script_ext_hint;
|
|
|
|
|
2017-03-05 15:44:50 +00:00
|
|
|
for (List<String>::Element *E = script_extentions.front(); E; E = E->next()) {
|
2020-05-14 14:41:43 +00:00
|
|
|
if (script_ext_hint != "") {
|
2017-03-05 15:44:50 +00:00
|
|
|
script_ext_hint += ",";
|
2020-05-14 14:41:43 +00:00
|
|
|
}
|
2017-03-05 15:44:50 +00:00
|
|
|
script_ext_hint += "*." + E->get();
|
2017-02-04 12:48:04 +00:00
|
|
|
}
|
|
|
|
|
2017-09-21 01:29:26 +00:00
|
|
|
bool materials_out = p_preset == PRESET_SEPARATE_MATERIALS || p_preset == PRESET_SEPARATE_MESHES_AND_MATERIALS || p_preset == PRESET_MULTIPLE_SCENES_AND_MATERIALS || p_preset == PRESET_SEPARATE_MATERIALS_AND_ANIMATIONS || p_preset == PRESET_SEPARATE_MESHES_MATERIALS_AND_ANIMATIONS;
|
|
|
|
bool meshes_out = p_preset == PRESET_SEPARATE_MESHES || p_preset == PRESET_SEPARATE_MESHES_AND_MATERIALS || p_preset == PRESET_SEPARATE_MESHES_AND_ANIMATIONS || p_preset == PRESET_SEPARATE_MESHES_MATERIALS_AND_ANIMATIONS;
|
2017-07-23 21:48:05 +00:00
|
|
|
bool scenes_out = p_preset == PRESET_MULTIPLE_SCENES || p_preset == PRESET_MULTIPLE_SCENES_AND_MATERIALS;
|
2017-09-21 01:29:26 +00:00
|
|
|
bool animations_out = p_preset == PRESET_SEPARATE_ANIMATIONS || p_preset == PRESET_SEPARATE_MESHES_AND_ANIMATIONS || p_preset == PRESET_SEPARATE_MATERIALS_AND_ANIMATIONS || p_preset == PRESET_SEPARATE_MESHES_MATERIALS_AND_ANIMATIONS;
|
2017-07-23 21:48:05 +00:00
|
|
|
|
Variant: Added 64-bit packed arrays, renamed Variant::REAL to FLOAT.
- Renames PackedIntArray to PackedInt32Array.
- Renames PackedFloatArray to PackedFloat32Array.
- Adds PackedInt64Array and PackedFloat64Array.
- Renames Variant::REAL to Variant::FLOAT for consistency.
Packed arrays are for storing large amount of data and creating stuff like
meshes, buffers. textures, etc. Forcing them to be 64 is a huge waste of
memory. That said, many users requested the ability to have 64 bits packed
arrays for their games, so this is just an optional added type.
For Variant, the float datatype is always 64 bits, and exposed as `float`.
We still have `real_t` which is the datatype that can change from 32 to 64
bits depending on a compile flag (not entirely working right now, but that's
the idea). It affects math related datatypes and code only.
Neither Variant nor PackedArray make use of real_t, which is only intended
for math precision, so the term is removed from there to keep only float.
2020-02-24 18:20:53 +00:00
|
|
|
r_options->push_back(ImportOption(PropertyInfo(Variant::FLOAT, "nodes/root_scale", PROPERTY_HINT_RANGE, "0.001,1000,0.001"), 1.0));
|
2017-03-05 15:44:50 +00:00
|
|
|
r_options->push_back(ImportOption(PropertyInfo(Variant::STRING, "nodes/custom_script", PROPERTY_HINT_FILE, script_ext_hint), ""));
|
2017-07-23 21:48:05 +00:00
|
|
|
r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "nodes/storage", PROPERTY_HINT_ENUM, "Single Scene,Instanced Sub-Scenes"), scenes_out ? 1 : 0));
|
2017-08-30 00:54:26 +00:00
|
|
|
r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "materials/location", PROPERTY_HINT_ENUM, "Node,Mesh"), (meshes_out || materials_out) ? 1 : 0));
|
2019-04-08 08:48:52 +00:00
|
|
|
r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "materials/storage", PROPERTY_HINT_ENUM, "Built-In,Files (.material),Files (.tres)", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), materials_out ? 1 : 0));
|
2019-06-26 13:08:25 +00:00
|
|
|
r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "materials/keep_on_reimport"), materials_out));
|
2017-08-18 11:25:04 +00:00
|
|
|
r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "meshes/compress"), true));
|
|
|
|
r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "meshes/ensure_tangents"), true));
|
2019-04-08 08:48:52 +00:00
|
|
|
r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "meshes/storage", PROPERTY_HINT_ENUM, "Built-In,Files (.mesh),Files (.tres)"), meshes_out ? 1 : 0));
|
2017-12-14 11:59:46 +00:00
|
|
|
r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "meshes/light_baking", PROPERTY_HINT_ENUM, "Disabled,Enable,Gen Lightmaps", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), 0));
|
Variant: Added 64-bit packed arrays, renamed Variant::REAL to FLOAT.
- Renames PackedIntArray to PackedInt32Array.
- Renames PackedFloatArray to PackedFloat32Array.
- Adds PackedInt64Array and PackedFloat64Array.
- Renames Variant::REAL to Variant::FLOAT for consistency.
Packed arrays are for storing large amount of data and creating stuff like
meshes, buffers. textures, etc. Forcing them to be 64 is a huge waste of
memory. That said, many users requested the ability to have 64 bits packed
arrays for their games, so this is just an optional added type.
For Variant, the float datatype is always 64 bits, and exposed as `float`.
We still have `real_t` which is the datatype that can change from 32 to 64
bits depending on a compile flag (not entirely working right now, but that's
the idea). It affects math related datatypes and code only.
Neither Variant nor PackedArray make use of real_t, which is only intended
for math precision, so the term is removed from there to keep only float.
2020-02-24 18:20:53 +00:00
|
|
|
r_options->push_back(ImportOption(PropertyInfo(Variant::FLOAT, "meshes/lightmap_texel_size", PROPERTY_HINT_RANGE, "0.001,100,0.001"), 0.1));
|
2020-02-21 10:27:48 +00:00
|
|
|
r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "skins/use_named_skins"), true));
|
2017-08-30 00:54:26 +00:00
|
|
|
r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "external_files/store_in_subdir"), false));
|
2017-03-05 15:44:50 +00:00
|
|
|
r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "animation/import", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), true));
|
Variant: Added 64-bit packed arrays, renamed Variant::REAL to FLOAT.
- Renames PackedIntArray to PackedInt32Array.
- Renames PackedFloatArray to PackedFloat32Array.
- Adds PackedInt64Array and PackedFloat64Array.
- Renames Variant::REAL to Variant::FLOAT for consistency.
Packed arrays are for storing large amount of data and creating stuff like
meshes, buffers. textures, etc. Forcing them to be 64 is a huge waste of
memory. That said, many users requested the ability to have 64 bits packed
arrays for their games, so this is just an optional added type.
For Variant, the float datatype is always 64 bits, and exposed as `float`.
We still have `real_t` which is the datatype that can change from 32 to 64
bits depending on a compile flag (not entirely working right now, but that's
the idea). It affects math related datatypes and code only.
Neither Variant nor PackedArray make use of real_t, which is only intended
for math precision, so the term is removed from there to keep only float.
2020-02-24 18:20:53 +00:00
|
|
|
r_options->push_back(ImportOption(PropertyInfo(Variant::FLOAT, "animation/fps", PROPERTY_HINT_RANGE, "1,120,1"), 15));
|
2017-03-05 15:44:50 +00:00
|
|
|
r_options->push_back(ImportOption(PropertyInfo(Variant::STRING, "animation/filter_script", PROPERTY_HINT_MULTILINE_TEXT), ""));
|
2019-09-28 02:33:00 +00:00
|
|
|
r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "animation/storage", PROPERTY_HINT_ENUM, "Built-In,Files (.anim),Files (.tres)", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), animations_out));
|
2019-06-26 13:08:25 +00:00
|
|
|
r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "animation/keep_custom_tracks"), animations_out));
|
2017-03-05 15:44:50 +00:00
|
|
|
r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "animation/optimizer/enabled", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), true));
|
Variant: Added 64-bit packed arrays, renamed Variant::REAL to FLOAT.
- Renames PackedIntArray to PackedInt32Array.
- Renames PackedFloatArray to PackedFloat32Array.
- Adds PackedInt64Array and PackedFloat64Array.
- Renames Variant::REAL to Variant::FLOAT for consistency.
Packed arrays are for storing large amount of data and creating stuff like
meshes, buffers. textures, etc. Forcing them to be 64 is a huge waste of
memory. That said, many users requested the ability to have 64 bits packed
arrays for their games, so this is just an optional added type.
For Variant, the float datatype is always 64 bits, and exposed as `float`.
We still have `real_t` which is the datatype that can change from 32 to 64
bits depending on a compile flag (not entirely working right now, but that's
the idea). It affects math related datatypes and code only.
Neither Variant nor PackedArray make use of real_t, which is only intended
for math precision, so the term is removed from there to keep only float.
2020-02-24 18:20:53 +00:00
|
|
|
r_options->push_back(ImportOption(PropertyInfo(Variant::FLOAT, "animation/optimizer/max_linear_error"), 0.05));
|
|
|
|
r_options->push_back(ImportOption(PropertyInfo(Variant::FLOAT, "animation/optimizer/max_angular_error"), 0.01));
|
|
|
|
r_options->push_back(ImportOption(PropertyInfo(Variant::FLOAT, "animation/optimizer/max_angle"), 22));
|
2017-03-05 15:44:50 +00:00
|
|
|
r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "animation/optimizer/remove_unused_tracks"), true));
|
|
|
|
r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "animation/clips/amount", PROPERTY_HINT_RANGE, "0,256,1", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), 0));
|
|
|
|
for (int i = 0; i < 256; i++) {
|
|
|
|
r_options->push_back(ImportOption(PropertyInfo(Variant::STRING, "animation/clip_" + itos(i + 1) + "/name"), ""));
|
|
|
|
r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "animation/clip_" + itos(i + 1) + "/start_frame"), 0));
|
|
|
|
r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "animation/clip_" + itos(i + 1) + "/end_frame"), 0));
|
|
|
|
r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "animation/clip_" + itos(i + 1) + "/loops"), false));
|
2017-02-04 12:48:04 +00:00
|
|
|
}
|
|
|
|
}
|
2017-02-04 23:31:15 +00:00
|
|
|
|
2017-07-23 21:48:05 +00:00
|
|
|
void ResourceImporterScene::_replace_owner(Node *p_node, Node *p_scene, Node *p_new_owner) {
|
|
|
|
if (p_node != p_new_owner && p_node->get_owner() == p_scene) {
|
|
|
|
p_node->set_owner(p_new_owner);
|
|
|
|
}
|
|
|
|
|
|
|
|
for (int i = 0; i < p_node->get_child_count(); i++) {
|
|
|
|
Node *n = p_node->get_child(i);
|
|
|
|
_replace_owner(n, p_scene, p_new_owner);
|
|
|
|
}
|
2017-12-07 18:44:20 +00:00
|
|
|
}
|
|
|
|
|
2017-12-09 17:11:26 +00:00
|
|
|
Node *ResourceImporterScene::import_scene_from_other_importer(EditorSceneImporter *p_exception, const String &p_path, uint32_t p_flags, int p_bake_fps) {
|
2017-12-07 18:44:20 +00:00
|
|
|
Ref<EditorSceneImporter> importer;
|
|
|
|
String ext = p_path.get_extension().to_lower();
|
|
|
|
|
2020-03-17 06:33:00 +00:00
|
|
|
for (Set<Ref<EditorSceneImporter>>::Element *E = importers.front(); E; E = E->next()) {
|
2020-05-14 14:41:43 +00:00
|
|
|
if (E->get().ptr() == p_exception) {
|
2017-12-07 18:44:20 +00:00
|
|
|
continue;
|
2020-05-14 14:41:43 +00:00
|
|
|
}
|
2017-12-07 18:44:20 +00:00
|
|
|
List<String> extensions;
|
|
|
|
E->get()->get_extensions(&extensions);
|
|
|
|
|
|
|
|
for (List<String>::Element *F = extensions.front(); F; F = F->next()) {
|
|
|
|
if (F->get().to_lower() == ext) {
|
|
|
|
importer = E->get();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-05-14 14:41:43 +00:00
|
|
|
if (importer.is_valid()) {
|
2017-12-07 18:44:20 +00:00
|
|
|
break;
|
2020-05-14 14:41:43 +00:00
|
|
|
}
|
2017-12-07 18:44:20 +00:00
|
|
|
}
|
|
|
|
|
2020-04-01 23:20:12 +00:00
|
|
|
ERR_FAIL_COND_V(!importer.is_valid(), nullptr);
|
2017-12-07 18:44:20 +00:00
|
|
|
|
|
|
|
List<String> missing;
|
|
|
|
Error err;
|
2017-12-09 17:11:26 +00:00
|
|
|
return importer->import_scene(p_path, p_flags, p_bake_fps, &missing, &err);
|
2017-12-07 18:44:20 +00:00
|
|
|
}
|
|
|
|
|
2017-12-09 17:11:26 +00:00
|
|
|
Ref<Animation> ResourceImporterScene::import_animation_from_other_importer(EditorSceneImporter *p_exception, const String &p_path, uint32_t p_flags, int p_bake_fps) {
|
|
|
|
Ref<EditorSceneImporter> importer;
|
|
|
|
String ext = p_path.get_extension().to_lower();
|
2017-12-07 18:44:20 +00:00
|
|
|
|
2020-03-17 06:33:00 +00:00
|
|
|
for (Set<Ref<EditorSceneImporter>>::Element *E = importers.front(); E; E = E->next()) {
|
2020-05-14 14:41:43 +00:00
|
|
|
if (E->get().ptr() == p_exception) {
|
2017-12-09 17:11:26 +00:00
|
|
|
continue;
|
2020-05-14 14:41:43 +00:00
|
|
|
}
|
2017-12-09 17:11:26 +00:00
|
|
|
List<String> extensions;
|
|
|
|
E->get()->get_extensions(&extensions);
|
2017-12-07 18:44:20 +00:00
|
|
|
|
2017-12-09 17:11:26 +00:00
|
|
|
for (List<String>::Element *F = extensions.front(); F; F = F->next()) {
|
|
|
|
if (F->get().to_lower() == ext) {
|
|
|
|
importer = E->get();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2017-12-07 18:44:20 +00:00
|
|
|
|
2020-05-14 14:41:43 +00:00
|
|
|
if (importer.is_valid()) {
|
2017-12-09 17:11:26 +00:00
|
|
|
break;
|
2020-05-14 14:41:43 +00:00
|
|
|
}
|
2017-12-09 17:11:26 +00:00
|
|
|
}
|
2017-12-07 18:44:20 +00:00
|
|
|
|
2020-04-01 23:20:12 +00:00
|
|
|
ERR_FAIL_COND_V(!importer.is_valid(), nullptr);
|
2017-12-07 18:44:20 +00:00
|
|
|
|
2017-12-09 17:11:26 +00:00
|
|
|
return importer->import_animation(p_path, p_flags, p_bake_fps);
|
2017-07-23 21:48:05 +00:00
|
|
|
}
|
|
|
|
|
2020-12-12 12:06:59 +00:00
|
|
|
void ResourceImporterScene::_generate_meshes(Node *p_node) {
|
|
|
|
EditorSceneImporterMeshNode *src_mesh = Object::cast_to<EditorSceneImporterMeshNode>(p_node);
|
|
|
|
if (src_mesh != nullptr) {
|
|
|
|
//is mesh
|
|
|
|
MeshInstance3D *mesh_node = memnew(MeshInstance3D);
|
|
|
|
mesh_node->set_transform(src_mesh->get_transform());
|
|
|
|
mesh_node->set_skin(src_mesh->get_skin());
|
|
|
|
mesh_node->set_skeleton_path(src_mesh->get_skeleton_path());
|
|
|
|
|
|
|
|
Ref<ArrayMesh> mesh;
|
|
|
|
if (!src_mesh->get_mesh()->has_mesh()) {
|
|
|
|
//do mesh processing
|
|
|
|
}
|
|
|
|
mesh = src_mesh->get_mesh()->get_mesh();
|
|
|
|
mesh_node->set_mesh(mesh);
|
|
|
|
for (int i = 0; i < mesh->get_surface_count(); i++) {
|
|
|
|
mesh_node->set_surface_material(i, src_mesh->get_surface_material(i));
|
|
|
|
}
|
|
|
|
|
|
|
|
p_node->replace_by(mesh_node);
|
|
|
|
memdelete(p_node);
|
|
|
|
p_node = mesh_node;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (int i = 0; i < p_node->get_child_count(); i++) {
|
|
|
|
_generate_meshes(p_node->get_child(i));
|
|
|
|
}
|
|
|
|
}
|
2019-02-26 21:43:37 +00:00
|
|
|
Error ResourceImporterScene::import(const String &p_source_file, const String &p_save_path, const Map<StringName, Variant> &p_options, List<String> *r_platform_variants, List<String> *r_gen_files, Variant *r_metadata) {
|
2019-06-26 13:08:25 +00:00
|
|
|
const String &src_path = p_source_file;
|
2017-02-04 12:48:04 +00:00
|
|
|
|
|
|
|
Ref<EditorSceneImporter> importer;
|
2017-03-05 15:44:50 +00:00
|
|
|
String ext = src_path.get_extension().to_lower();
|
2017-02-04 12:48:04 +00:00
|
|
|
|
2017-03-05 15:44:50 +00:00
|
|
|
EditorProgress progress("import", TTR("Import Scene"), 104);
|
2018-04-22 17:36:01 +00:00
|
|
|
progress.step(TTR("Importing Scene..."), 0);
|
2017-02-04 12:48:04 +00:00
|
|
|
|
2020-03-17 06:33:00 +00:00
|
|
|
for (Set<Ref<EditorSceneImporter>>::Element *E = importers.front(); E; E = E->next()) {
|
2017-02-04 12:48:04 +00:00
|
|
|
List<String> extensions;
|
|
|
|
E->get()->get_extensions(&extensions);
|
|
|
|
|
2017-03-05 15:44:50 +00:00
|
|
|
for (List<String>::Element *F = extensions.front(); F; F = F->next()) {
|
|
|
|
if (F->get().to_lower() == ext) {
|
2017-02-04 12:48:04 +00:00
|
|
|
importer = E->get();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-05-14 14:41:43 +00:00
|
|
|
if (importer.is_valid()) {
|
2017-02-04 12:48:04 +00:00
|
|
|
break;
|
2020-05-14 14:41:43 +00:00
|
|
|
}
|
2017-02-04 12:48:04 +00:00
|
|
|
}
|
|
|
|
|
2017-03-05 15:44:50 +00:00
|
|
|
ERR_FAIL_COND_V(!importer.is_valid(), ERR_FILE_UNRECOGNIZED);
|
2017-02-04 12:48:04 +00:00
|
|
|
|
2017-03-05 15:44:50 +00:00
|
|
|
float fps = p_options["animation/fps"];
|
2017-02-04 12:48:04 +00:00
|
|
|
|
2017-03-05 15:44:50 +00:00
|
|
|
int import_flags = EditorSceneImporter::IMPORT_ANIMATION_DETECT_LOOP;
|
2020-05-14 14:41:43 +00:00
|
|
|
if (!bool(p_options["animation/optimizer/remove_unused_tracks"])) {
|
2017-03-05 15:44:50 +00:00
|
|
|
import_flags |= EditorSceneImporter::IMPORT_ANIMATION_FORCE_ALL_TRACKS_IN_ALL_CLIPS;
|
2020-05-14 14:41:43 +00:00
|
|
|
}
|
2017-02-04 12:48:04 +00:00
|
|
|
|
2020-05-14 14:41:43 +00:00
|
|
|
if (bool(p_options["animation/import"])) {
|
2017-03-05 15:44:50 +00:00
|
|
|
import_flags |= EditorSceneImporter::IMPORT_ANIMATION;
|
2020-05-14 14:41:43 +00:00
|
|
|
}
|
2017-02-04 12:48:04 +00:00
|
|
|
|
2020-05-14 14:41:43 +00:00
|
|
|
if (int(p_options["meshes/compress"])) {
|
2017-11-01 00:01:24 +00:00
|
|
|
import_flags |= EditorSceneImporter::IMPORT_USE_COMPRESSION;
|
2020-05-14 14:41:43 +00:00
|
|
|
}
|
2017-11-01 00:01:24 +00:00
|
|
|
|
2020-05-14 14:41:43 +00:00
|
|
|
if (bool(p_options["meshes/ensure_tangents"])) {
|
2017-03-05 15:44:50 +00:00
|
|
|
import_flags |= EditorSceneImporter::IMPORT_GENERATE_TANGENT_ARRAYS;
|
2020-05-14 14:41:43 +00:00
|
|
|
}
|
2017-02-04 12:48:04 +00:00
|
|
|
|
2020-05-14 14:41:43 +00:00
|
|
|
if (int(p_options["materials/location"]) == 0) {
|
2017-03-05 15:44:50 +00:00
|
|
|
import_flags |= EditorSceneImporter::IMPORT_MATERIALS_IN_INSTANCES;
|
2020-05-14 14:41:43 +00:00
|
|
|
}
|
2017-02-04 12:48:04 +00:00
|
|
|
|
2020-05-14 14:41:43 +00:00
|
|
|
if (bool(p_options["skins/use_named_skins"])) {
|
2020-02-21 10:27:48 +00:00
|
|
|
import_flags |= EditorSceneImporter::IMPORT_USE_NAMED_SKIN_BINDS;
|
2020-05-14 14:41:43 +00:00
|
|
|
}
|
2020-02-21 10:27:48 +00:00
|
|
|
|
2017-03-05 15:44:50 +00:00
|
|
|
Error err = OK;
|
2017-02-04 12:48:04 +00:00
|
|
|
List<String> missing_deps; // for now, not much will be done with this
|
2017-03-05 15:44:50 +00:00
|
|
|
Node *scene = importer->import_scene(src_path, import_flags, fps, &missing_deps, &err);
|
|
|
|
if (!scene || err != OK) {
|
2017-02-04 12:48:04 +00:00
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
String root_type = p_options["nodes/root_type"];
|
2019-01-30 04:07:56 +00:00
|
|
|
root_type = root_type.split(" ")[0]; // full root_type is "ClassName (filename.gd)" for a script global class.
|
|
|
|
|
2020-04-01 23:20:12 +00:00
|
|
|
Ref<Script> root_script = nullptr;
|
2019-01-30 04:07:56 +00:00
|
|
|
if (ScriptServer::is_global_class(root_type)) {
|
|
|
|
root_script = ResourceLoader::load(ScriptServer::get_global_class_path(root_type));
|
|
|
|
root_type = ScriptServer::get_global_class_base(root_type);
|
|
|
|
}
|
2017-02-04 12:48:04 +00:00
|
|
|
|
2020-03-26 21:49:16 +00:00
|
|
|
if (root_type != "Node3D") {
|
2017-09-07 19:48:50 +00:00
|
|
|
Node *base_node = Object::cast_to<Node>(ClassDB::instance(root_type));
|
2017-02-04 12:48:04 +00:00
|
|
|
|
|
|
|
if (base_node) {
|
|
|
|
scene->replace_by(base_node);
|
|
|
|
memdelete(scene);
|
2017-03-05 15:44:50 +00:00
|
|
|
scene = base_node;
|
2017-02-04 12:48:04 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-01-30 04:07:56 +00:00
|
|
|
if (root_script.is_valid()) {
|
|
|
|
scene->set_script(Variant(root_script));
|
|
|
|
}
|
|
|
|
|
2020-05-01 12:34:23 +00:00
|
|
|
float root_scale = 1.0;
|
2020-03-26 21:49:16 +00:00
|
|
|
if (Object::cast_to<Node3D>(scene)) {
|
2020-05-01 12:34:23 +00:00
|
|
|
root_scale = p_options["nodes/root_scale"];
|
2020-03-26 21:49:16 +00:00
|
|
|
Object::cast_to<Node3D>(scene)->scale(Vector3(root_scale, root_scale, root_scale));
|
2017-12-17 18:47:50 +00:00
|
|
|
}
|
|
|
|
|
2020-05-14 14:41:43 +00:00
|
|
|
if (p_options["nodes/root_name"] != "Scene Root") {
|
2019-04-08 16:43:55 +00:00
|
|
|
scene->set_name(p_options["nodes/root_name"]);
|
2020-05-14 14:41:43 +00:00
|
|
|
} else {
|
2019-04-08 16:43:55 +00:00
|
|
|
scene->set_name(p_save_path.get_file().get_basename());
|
2020-05-14 14:41:43 +00:00
|
|
|
}
|
2017-02-04 12:48:04 +00:00
|
|
|
|
2020-12-12 12:06:59 +00:00
|
|
|
_generate_meshes(scene);
|
|
|
|
|
2017-03-05 15:44:50 +00:00
|
|
|
err = OK;
|
2017-02-04 12:48:04 +00:00
|
|
|
|
|
|
|
String animation_filter = String(p_options["animation/filter_script"]).strip_edges();
|
|
|
|
|
|
|
|
bool use_optimizer = p_options["animation/optimizer/enabled"];
|
2017-03-05 15:44:50 +00:00
|
|
|
float anim_optimizer_linerr = p_options["animation/optimizer/max_linear_error"];
|
|
|
|
float anim_optimizer_angerr = p_options["animation/optimizer/max_angular_error"];
|
|
|
|
float anim_optimizer_maxang = p_options["animation/optimizer/max_angle"];
|
2017-11-25 04:29:15 +00:00
|
|
|
int light_bake_mode = p_options["meshes/light_baking"];
|
2017-02-04 12:48:04 +00:00
|
|
|
|
2020-03-26 21:49:16 +00:00
|
|
|
Map<Ref<Mesh>, List<Ref<Shape3D>>> collision_map;
|
2017-02-04 12:48:04 +00:00
|
|
|
|
2017-11-25 04:29:15 +00:00
|
|
|
scene = _fix_node(scene, scene, collision_map, LightBakeMode(light_bake_mode));
|
2017-02-04 12:48:04 +00:00
|
|
|
|
|
|
|
if (use_optimizer) {
|
2017-03-05 15:44:50 +00:00
|
|
|
_optimize_animations(scene, anim_optimizer_linerr, anim_optimizer_angerr, anim_optimizer_maxang);
|
2017-02-04 12:48:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
Array animation_clips;
|
|
|
|
{
|
|
|
|
int clip_count = p_options["animation/clips/amount"];
|
|
|
|
|
2017-03-05 15:44:50 +00:00
|
|
|
for (int i = 0; i < clip_count; i++) {
|
|
|
|
String name = p_options["animation/clip_" + itos(i + 1) + "/name"];
|
|
|
|
int from_frame = p_options["animation/clip_" + itos(i + 1) + "/start_frame"];
|
|
|
|
int end_frame = p_options["animation/clip_" + itos(i + 1) + "/end_frame"];
|
|
|
|
bool loop = p_options["animation/clip_" + itos(i + 1) + "/loops"];
|
2017-02-04 12:48:04 +00:00
|
|
|
|
|
|
|
animation_clips.push_back(name);
|
2017-03-05 15:44:50 +00:00
|
|
|
animation_clips.push_back(from_frame / fps);
|
|
|
|
animation_clips.push_back(end_frame / fps);
|
2017-02-04 12:48:04 +00:00
|
|
|
animation_clips.push_back(loop);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (animation_clips.size()) {
|
2017-03-05 15:44:50 +00:00
|
|
|
_create_clips(scene, animation_clips, !bool(p_options["animation/optimizer/remove_unused_tracks"]));
|
2017-02-04 12:48:04 +00:00
|
|
|
}
|
|
|
|
|
2017-03-05 15:44:50 +00:00
|
|
|
if (animation_filter != "") {
|
|
|
|
_filter_tracks(scene, animation_filter);
|
2017-02-04 12:48:04 +00:00
|
|
|
}
|
|
|
|
|
2019-04-08 08:48:52 +00:00
|
|
|
bool external_animations = int(p_options["animation/storage"]) == 1 || int(p_options["animation/storage"]) == 2;
|
|
|
|
bool external_animations_as_text = int(p_options["animation/storage"]) == 2;
|
2017-12-07 13:18:55 +00:00
|
|
|
bool keep_custom_tracks = p_options["animation/keep_custom_tracks"];
|
2019-04-08 08:48:52 +00:00
|
|
|
bool external_materials = int(p_options["materials/storage"]) == 1 || int(p_options["materials/storage"]) == 2;
|
|
|
|
bool external_materials_as_text = int(p_options["materials/storage"]) == 2;
|
|
|
|
bool external_meshes = int(p_options["meshes/storage"]) == 1 || int(p_options["meshes/storage"]) == 2;
|
|
|
|
bool external_meshes_as_text = int(p_options["meshes/storage"]) == 2;
|
2017-07-23 21:48:05 +00:00
|
|
|
bool external_scenes = int(p_options["nodes/storage"]) == 1;
|
|
|
|
|
|
|
|
String base_path = p_source_file.get_base_dir();
|
|
|
|
|
2017-09-08 11:06:09 +00:00
|
|
|
if (external_animations || external_materials || external_meshes || external_scenes) {
|
2017-07-23 21:48:05 +00:00
|
|
|
if (bool(p_options["external_files/store_in_subdir"])) {
|
|
|
|
String subdir_name = p_source_file.get_file().get_basename();
|
|
|
|
DirAccess *da = DirAccess::open(base_path);
|
2019-02-12 20:10:08 +00:00
|
|
|
Error err2 = da->make_dir(subdir_name);
|
2017-07-23 21:48:05 +00:00
|
|
|
memdelete(da);
|
2019-09-25 08:28:50 +00:00
|
|
|
ERR_FAIL_COND_V_MSG(err2 != OK && err2 != ERR_ALREADY_EXISTS, err2, "Cannot make directory '" + subdir_name + "'.");
|
2017-07-23 21:48:05 +00:00
|
|
|
base_path = base_path.plus_file(subdir_name);
|
|
|
|
}
|
|
|
|
}
|
2017-02-04 23:31:15 +00:00
|
|
|
|
2017-12-09 17:11:26 +00:00
|
|
|
if (light_bake_mode == 2 /* || generate LOD */) {
|
|
|
|
Map<Ref<ArrayMesh>, Transform> meshes;
|
|
|
|
_find_meshes(scene, meshes);
|
|
|
|
|
2020-04-22 13:34:00 +00:00
|
|
|
String file_id = src_path.get_file();
|
|
|
|
String cache_file_path = base_path.plus_file(file_id + ".unwrap_cache");
|
2017-12-09 17:11:26 +00:00
|
|
|
|
2020-04-22 13:34:00 +00:00
|
|
|
Vector<unsigned char> cache_data;
|
2017-12-09 17:11:26 +00:00
|
|
|
|
2020-04-22 13:34:00 +00:00
|
|
|
if (FileAccess::exists(cache_file_path)) {
|
|
|
|
Error err2;
|
|
|
|
FileAccess *file = FileAccess::open(cache_file_path, FileAccess::READ, &err2);
|
2017-12-09 17:11:26 +00:00
|
|
|
|
2020-04-22 13:34:00 +00:00
|
|
|
if (err2) {
|
2020-05-14 14:41:43 +00:00
|
|
|
if (file) {
|
2020-04-22 13:34:00 +00:00
|
|
|
memdelete(file);
|
2020-05-14 14:41:43 +00:00
|
|
|
}
|
2020-04-22 13:34:00 +00:00
|
|
|
} else {
|
|
|
|
int cache_size = file->get_len();
|
|
|
|
cache_data.resize(cache_size);
|
|
|
|
file->get_buffer(cache_data.ptrw(), cache_size);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
float texel_size = p_options["meshes/lightmap_texel_size"];
|
|
|
|
texel_size = MAX(0.001, texel_size);
|
|
|
|
|
|
|
|
Map<String, unsigned int> used_unwraps;
|
2017-12-09 17:11:26 +00:00
|
|
|
|
2020-04-22 13:34:00 +00:00
|
|
|
EditorProgress progress2("gen_lightmaps", TTR("Generating Lightmaps"), meshes.size());
|
|
|
|
int step = 0;
|
|
|
|
for (Map<Ref<ArrayMesh>, Transform>::Element *E = meshes.front(); E; E = E->next()) {
|
|
|
|
Ref<ArrayMesh> mesh = E->key();
|
|
|
|
String name = mesh->get_name();
|
|
|
|
if (name == "") { //should not happen but..
|
|
|
|
name = "Mesh " + itos(step);
|
|
|
|
}
|
|
|
|
|
|
|
|
progress2.step(TTR("Generating for Mesh: ") + name + " (" + itos(step) + "/" + itos(meshes.size()) + ")", step);
|
|
|
|
|
|
|
|
int *ret_cache_data = (int *)cache_data.ptrw();
|
|
|
|
unsigned int ret_cache_size = cache_data.size();
|
|
|
|
bool ret_used_cache = true; // Tell the unwrapper to use the cache
|
|
|
|
Error err2 = mesh->lightmap_unwrap_cached(ret_cache_data, ret_cache_size, ret_used_cache, E->get(), texel_size);
|
|
|
|
|
|
|
|
if (err2 != OK) {
|
|
|
|
EditorNode::add_io_error("Mesh '" + name + "' failed lightmap generation. Please fix geometry.");
|
|
|
|
} else {
|
|
|
|
String hash = String::md5((unsigned char *)ret_cache_data);
|
|
|
|
used_unwraps.insert(hash, ret_cache_size);
|
|
|
|
|
|
|
|
if (!ret_used_cache) {
|
|
|
|
// Cache was not used, add the generated entry to the current cache
|
|
|
|
if (cache_data.empty()) {
|
|
|
|
cache_data.resize(4 + ret_cache_size);
|
|
|
|
int *data = (int *)cache_data.ptrw();
|
|
|
|
data[0] = 1;
|
|
|
|
memcpy(&data[1], ret_cache_data, ret_cache_size);
|
|
|
|
} else {
|
|
|
|
int current_size = cache_data.size();
|
|
|
|
cache_data.resize(cache_data.size() + ret_cache_size);
|
|
|
|
unsigned char *ptrw = cache_data.ptrw();
|
|
|
|
memcpy(&ptrw[current_size], ret_cache_data, ret_cache_size);
|
|
|
|
int *data = (int *)ptrw;
|
|
|
|
data[0] += 1;
|
|
|
|
}
|
2017-12-09 17:11:26 +00:00
|
|
|
}
|
|
|
|
}
|
2020-04-22 13:34:00 +00:00
|
|
|
step++;
|
|
|
|
}
|
|
|
|
|
|
|
|
Error err2;
|
|
|
|
FileAccess *file = FileAccess::open(cache_file_path, FileAccess::WRITE, &err2);
|
|
|
|
|
|
|
|
if (err2) {
|
2020-05-14 14:41:43 +00:00
|
|
|
if (file) {
|
2020-04-22 13:34:00 +00:00
|
|
|
memdelete(file);
|
2020-05-14 14:41:43 +00:00
|
|
|
}
|
2020-04-22 13:34:00 +00:00
|
|
|
} else {
|
|
|
|
// Store number of entries
|
|
|
|
file->store_32(used_unwraps.size());
|
|
|
|
|
|
|
|
// Store cache entries
|
|
|
|
const int *cache = (int *)cache_data.ptr();
|
|
|
|
unsigned int r_idx = 1;
|
|
|
|
for (int i = 0; i < cache[0]; ++i) {
|
|
|
|
unsigned char *entry_start = (unsigned char *)&cache[r_idx];
|
|
|
|
String entry_hash = String::md5(entry_start);
|
|
|
|
if (used_unwraps.has(entry_hash)) {
|
|
|
|
unsigned int entry_size = used_unwraps[entry_hash];
|
|
|
|
file->store_buffer(entry_start, entry_size);
|
|
|
|
}
|
|
|
|
|
|
|
|
r_idx += 4; // hash
|
|
|
|
r_idx += 2; // size hint
|
|
|
|
|
|
|
|
int vertex_count = cache[r_idx];
|
|
|
|
r_idx += 1; // vertex count
|
|
|
|
r_idx += vertex_count; // vertex
|
|
|
|
r_idx += vertex_count * 2; // uvs
|
|
|
|
|
|
|
|
int index_count = cache[r_idx];
|
|
|
|
r_idx += 1; // index count
|
|
|
|
r_idx += index_count; // indices
|
|
|
|
}
|
|
|
|
|
|
|
|
file->close();
|
2017-12-09 17:11:26 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-09-08 11:06:09 +00:00
|
|
|
if (external_animations || external_materials || external_meshes) {
|
2020-03-17 06:33:00 +00:00
|
|
|
Map<Ref<Animation>, Ref<Animation>> anim_map;
|
|
|
|
Map<Ref<Material>, Ref<Material>> mat_map;
|
|
|
|
Map<Ref<ArrayMesh>, Ref<ArrayMesh>> mesh_map;
|
2017-07-23 21:48:05 +00:00
|
|
|
|
2017-08-17 20:02:43 +00:00
|
|
|
bool keep_materials = bool(p_options["materials/keep_on_reimport"]);
|
2017-07-23 21:48:05 +00:00
|
|
|
|
2019-04-08 08:48:52 +00:00
|
|
|
_make_external_resources(scene, base_path, external_animations, external_animations_as_text, keep_custom_tracks, external_materials, external_materials_as_text, keep_materials, external_meshes, external_meshes_as_text, anim_map, mat_map, mesh_map);
|
2017-02-04 23:31:15 +00:00
|
|
|
}
|
|
|
|
|
2018-04-22 17:36:01 +00:00
|
|
|
progress.step(TTR("Running Custom Script..."), 2);
|
2017-02-04 12:48:04 +00:00
|
|
|
|
|
|
|
String post_import_script_path = p_options["nodes/custom_script"];
|
2017-03-05 15:44:50 +00:00
|
|
|
Ref<EditorScenePostImport> post_import_script;
|
2017-02-04 12:48:04 +00:00
|
|
|
|
2017-03-05 15:44:50 +00:00
|
|
|
if (post_import_script_path != "") {
|
2017-02-04 12:48:04 +00:00
|
|
|
Ref<Script> scr = ResourceLoader::load(post_import_script_path);
|
|
|
|
if (!scr.is_valid()) {
|
2017-03-05 15:44:50 +00:00
|
|
|
EditorNode::add_io_error(TTR("Couldn't load post-import script:") + " " + post_import_script_path);
|
2017-02-04 12:48:04 +00:00
|
|
|
} else {
|
2017-03-05 15:44:50 +00:00
|
|
|
post_import_script = Ref<EditorScenePostImport>(memnew(EditorScenePostImport));
|
2020-02-13 19:03:10 +00:00
|
|
|
post_import_script->set_script(scr);
|
2017-02-04 12:48:04 +00:00
|
|
|
if (!post_import_script->get_script_instance()) {
|
2017-03-05 15:44:50 +00:00
|
|
|
EditorNode::add_io_error(TTR("Invalid/broken script for post-import (check console):") + " " + post_import_script_path);
|
2017-02-04 12:48:04 +00:00
|
|
|
post_import_script.unref();
|
|
|
|
return ERR_CANT_CREATE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (post_import_script.is_valid()) {
|
2018-01-19 23:48:44 +00:00
|
|
|
post_import_script->init(base_path, p_source_file);
|
2017-02-04 12:48:04 +00:00
|
|
|
scene = post_import_script->post_import(scene);
|
|
|
|
if (!scene) {
|
2020-05-11 19:09:36 +00:00
|
|
|
EditorNode::add_io_error(
|
|
|
|
TTR("Error running post-import script:") + " " + post_import_script_path + "\n" +
|
|
|
|
TTR("Did you return a Node-derived object in the `post_import()` method?"));
|
2017-02-04 12:48:04 +00:00
|
|
|
return err;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-04-22 17:36:01 +00:00
|
|
|
progress.step(TTR("Saving..."), 104);
|
2017-02-04 12:48:04 +00:00
|
|
|
|
2017-07-23 21:48:05 +00:00
|
|
|
if (external_scenes) {
|
|
|
|
//save sub-scenes as instances!
|
|
|
|
for (int i = 0; i < scene->get_child_count(); i++) {
|
|
|
|
Node *child = scene->get_child(i);
|
2020-05-14 14:41:43 +00:00
|
|
|
if (child->get_owner() != scene) {
|
2017-07-23 21:48:05 +00:00
|
|
|
continue; //not a real child probably created by scene type (ig, a scrollbar)
|
2020-05-14 14:41:43 +00:00
|
|
|
}
|
2017-07-23 21:48:05 +00:00
|
|
|
_replace_owner(child, scene, child);
|
|
|
|
|
|
|
|
String cn = String(child->get_name()).strip_edges().replace(".", "_").replace(":", "_");
|
|
|
|
if (cn == String()) {
|
|
|
|
cn = "ChildNode" + itos(i);
|
|
|
|
}
|
|
|
|
String path = base_path.plus_file(cn + ".scn");
|
|
|
|
child->set_filename(path);
|
|
|
|
|
|
|
|
Ref<PackedScene> packer = memnew(PackedScene);
|
|
|
|
packer->pack(child);
|
|
|
|
err = ResourceSaver::save(path, packer); //do not take over, let the changed files reload themselves
|
2019-09-25 08:28:50 +00:00
|
|
|
ERR_FAIL_COND_V_MSG(err != OK, err, "Cannot save scene to file '" + path + "'.");
|
2017-07-23 21:48:05 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-03-05 15:44:50 +00:00
|
|
|
Ref<PackedScene> packer = memnew(PackedScene);
|
2017-02-04 12:48:04 +00:00
|
|
|
packer->pack(scene);
|
2018-08-24 07:35:07 +00:00
|
|
|
print_verbose("Saving scene to: " + p_save_path + ".scn");
|
2017-03-05 15:44:50 +00:00
|
|
|
err = ResourceSaver::save(p_save_path + ".scn", packer); //do not take over, let the changed files reload themselves
|
2019-09-25 08:28:50 +00:00
|
|
|
ERR_FAIL_COND_V_MSG(err != OK, err, "Cannot save scene to file '" + p_save_path + ".scn'.");
|
2017-02-04 12:48:04 +00:00
|
|
|
|
|
|
|
memdelete(scene);
|
|
|
|
|
2017-08-31 21:57:03 +00:00
|
|
|
//this is not the time to reimport, wait until import process is done, import file is saved, etc.
|
|
|
|
//EditorNode::get_singleton()->reload_scene(p_source_file);
|
2017-02-04 12:48:04 +00:00
|
|
|
|
|
|
|
return OK;
|
|
|
|
}
|
|
|
|
|
2020-04-01 23:20:12 +00:00
|
|
|
ResourceImporterScene *ResourceImporterScene::singleton = nullptr;
|
2017-02-04 12:48:04 +00:00
|
|
|
|
2017-03-05 15:44:50 +00:00
|
|
|
ResourceImporterScene::ResourceImporterScene() {
|
|
|
|
singleton = this;
|
2017-02-04 12:48:04 +00:00
|
|
|
}
|
2020-05-14 12:29:06 +00:00
|
|
|
|
2018-01-30 14:03:46 +00:00
|
|
|
///////////////////////////////////////
|
|
|
|
|
|
|
|
uint32_t EditorSceneImporterESCN::get_import_flags() const {
|
|
|
|
return IMPORT_SCENE;
|
|
|
|
}
|
2020-05-14 12:29:06 +00:00
|
|
|
|
2018-01-30 14:03:46 +00:00
|
|
|
void EditorSceneImporterESCN::get_extensions(List<String> *r_extensions) const {
|
|
|
|
r_extensions->push_back("escn");
|
|
|
|
}
|
2020-05-14 12:29:06 +00:00
|
|
|
|
2018-01-30 14:03:46 +00:00
|
|
|
Node *EditorSceneImporterESCN::import_scene(const String &p_path, uint32_t p_flags, int p_bake_fps, List<String> *r_missing_deps, Error *r_err) {
|
|
|
|
Error error;
|
|
|
|
Ref<PackedScene> ps = ResourceFormatLoaderText::singleton->load(p_path, p_path, &error);
|
2020-04-01 23:20:12 +00:00
|
|
|
ERR_FAIL_COND_V_MSG(!ps.is_valid(), nullptr, "Cannot load scene as text resource from path '" + p_path + "'.");
|
2018-01-30 14:03:46 +00:00
|
|
|
|
|
|
|
Node *scene = ps->instance();
|
2020-04-01 23:20:12 +00:00
|
|
|
ERR_FAIL_COND_V(!scene, nullptr);
|
2018-01-30 14:03:46 +00:00
|
|
|
|
|
|
|
return scene;
|
|
|
|
}
|
2020-05-14 12:29:06 +00:00
|
|
|
|
2018-01-30 14:03:46 +00:00
|
|
|
Ref<Animation> EditorSceneImporterESCN::import_animation(const String &p_path, uint32_t p_flags, int p_bake_fps) {
|
|
|
|
ERR_FAIL_V(Ref<Animation>());
|
|
|
|
}
|