summaryrefslogtreecommitdiff
path: root/editor/import
diff options
context:
space:
mode:
Diffstat (limited to 'editor/import')
-rw-r--r--editor/import/SCsub2
-rw-r--r--editor/import/collada.cpp2407
-rw-r--r--editor/import/collada.h578
-rw-r--r--editor/import/editor_import_collada.cpp502
-rw-r--r--editor/import/editor_import_collada.h7
-rw-r--r--editor/import/editor_import_plugin.cpp9
-rw-r--r--editor/import/editor_import_plugin.h6
-rw-r--r--editor/import/editor_scene_importer_gltf.cpp636
-rw-r--r--editor/import/editor_scene_importer_gltf.h179
-rw-r--r--editor/import/resource_importer_bitmask.cpp22
-rw-r--r--editor/import/resource_importer_bitmask.h6
-rw-r--r--editor/import/resource_importer_csv.cpp12
-rw-r--r--editor/import/resource_importer_csv.h6
-rw-r--r--editor/import/resource_importer_csv_translation.cpp31
-rw-r--r--editor/import/resource_importer_csv_translation.h6
-rw-r--r--editor/import/resource_importer_image.cpp13
-rw-r--r--editor/import/resource_importer_image.h6
-rw-r--r--editor/import/resource_importer_layered_texture.cpp417
-rw-r--r--editor/import/resource_importer_layered_texture.h84
-rw-r--r--editor/import/resource_importer_obj.cpp109
-rw-r--r--editor/import/resource_importer_obj.h9
-rw-r--r--editor/import/resource_importer_scene.cpp625
-rw-r--r--editor/import/resource_importer_scene.h25
-rw-r--r--editor/import/resource_importer_shader_file.cpp118
-rw-r--r--editor/import/resource_importer_shader_file.h57
-rw-r--r--editor/import/resource_importer_texture.cpp552
-rw-r--r--editor/import/resource_importer_texture.h55
-rw-r--r--editor/import/resource_importer_texture_atlas.cpp69
-rw-r--r--editor/import/resource_importer_texture_atlas.h10
-rw-r--r--editor/import/resource_importer_wav.cpp57
-rw-r--r--editor/import/resource_importer_wav.h32
31 files changed, 4878 insertions, 1769 deletions
diff --git a/editor/import/SCsub b/editor/import/SCsub
index 2b1e889fb0..359d04e5df 100644
--- a/editor/import/SCsub
+++ b/editor/import/SCsub
@@ -1,5 +1,5 @@
#!/usr/bin/env python
-Import('env')
+Import("env")
env.add_source_files(env.editor_sources, "*.cpp")
diff --git a/editor/import/collada.cpp b/editor/import/collada.cpp
new file mode 100644
index 0000000000..41e71248a9
--- /dev/null
+++ b/editor/import/collada.cpp
@@ -0,0 +1,2407 @@
+/*************************************************************************/
+/* collada.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "collada.h"
+
+#include <stdio.h>
+
+//#define DEBUG_DEFAULT_ANIMATION
+//#define DEBUG_COLLADA
+#ifdef DEBUG_COLLADA
+#define COLLADA_PRINT(m_what) print_line(m_what)
+#else
+#define COLLADA_PRINT(m_what)
+#endif
+
+#define COLLADA_IMPORT_SCALE_SCENE
+
+/* HELPERS */
+
+String Collada::Effect::get_texture_path(const String &p_source, Collada &state) const {
+ const String &image = p_source;
+ ERR_FAIL_COND_V(!state.state.image_map.has(image), "");
+ return state.state.image_map[image].path;
+}
+
+Transform Collada::get_root_transform() const {
+ Transform unit_scale_transform;
+#ifndef COLLADA_IMPORT_SCALE_SCENE
+ unit_scale_transform.scale(Vector3(state.unit_scale, state.unit_scale, state.unit_scale));
+#endif
+ return unit_scale_transform;
+}
+
+void Collada::Vertex::fix_unit_scale(Collada &state) {
+#ifdef COLLADA_IMPORT_SCALE_SCENE
+ vertex *= state.state.unit_scale;
+#endif
+}
+
+static String _uri_to_id(const String &p_uri) {
+ if (p_uri.begins_with("#")) {
+ return p_uri.substr(1, p_uri.size() - 1);
+ } else {
+ return p_uri;
+ }
+}
+
+/** HELPER FUNCTIONS **/
+
+Transform Collada::fix_transform(const Transform &p_transform) {
+ Transform tr = p_transform;
+
+#ifndef NO_UP_AXIS_SWAP
+
+ if (state.up_axis != Vector3::AXIS_Y) {
+ for (int i = 0; i < 3; i++) {
+ SWAP(tr.basis[1][i], tr.basis[state.up_axis][i]);
+ }
+ for (int i = 0; i < 3; i++) {
+ SWAP(tr.basis[i][1], tr.basis[i][state.up_axis]);
+ }
+
+ SWAP(tr.origin[1], tr.origin[state.up_axis]);
+
+ tr.basis[state.up_axis][0] = -tr.basis[state.up_axis][0];
+ tr.basis[state.up_axis][1] = -tr.basis[state.up_axis][1];
+ tr.basis[0][state.up_axis] = -tr.basis[0][state.up_axis];
+ tr.basis[1][state.up_axis] = -tr.basis[1][state.up_axis];
+ tr.origin[state.up_axis] = -tr.origin[state.up_axis];
+ }
+#endif
+
+ //tr.scale(Vector3(state.unit_scale.unit_scale.unit_scale));
+ return tr;
+ //return state.matrix_fix * p_transform;
+}
+
+static Transform _read_transform_from_array(const Vector<float> &array, int ofs = 0) {
+ Transform tr;
+ // i wonder why collada matrices are transposed, given that's opposed to opengl..
+ tr.basis.elements[0][0] = array[0 + ofs];
+ tr.basis.elements[0][1] = array[1 + ofs];
+ tr.basis.elements[0][2] = array[2 + ofs];
+ tr.basis.elements[1][0] = array[4 + ofs];
+ tr.basis.elements[1][1] = array[5 + ofs];
+ tr.basis.elements[1][2] = array[6 + ofs];
+ tr.basis.elements[2][0] = array[8 + ofs];
+ tr.basis.elements[2][1] = array[9 + ofs];
+ tr.basis.elements[2][2] = array[10 + ofs];
+ tr.origin.x = array[3 + ofs];
+ tr.origin.y = array[7 + ofs];
+ tr.origin.z = array[11 + ofs];
+ return tr;
+}
+
+/* STRUCTURES */
+
+Transform Collada::Node::compute_transform(Collada &state) const {
+ Transform xform;
+
+ for (int i = 0; i < xform_list.size(); i++) {
+ Transform xform_step;
+ const XForm &xf = xform_list[i];
+ switch (xf.op) {
+ case XForm::OP_ROTATE: {
+ if (xf.data.size() >= 4) {
+ xform_step.rotate(Vector3(xf.data[0], xf.data[1], xf.data[2]), Math::deg2rad(xf.data[3]));
+ }
+ } break;
+ case XForm::OP_SCALE: {
+ if (xf.data.size() >= 3) {
+ xform_step.scale(Vector3(xf.data[0], xf.data[1], xf.data[2]));
+ }
+
+ } break;
+ case XForm::OP_TRANSLATE: {
+ if (xf.data.size() >= 3) {
+ xform_step.origin = Vector3(xf.data[0], xf.data[1], xf.data[2]);
+ }
+
+ } break;
+ case XForm::OP_MATRIX: {
+ if (xf.data.size() >= 16) {
+ xform_step = _read_transform_from_array(xf.data, 0);
+ }
+
+ } break;
+ default: {
+ }
+ }
+
+ xform = xform * xform_step;
+ }
+
+#ifdef COLLADA_IMPORT_SCALE_SCENE
+ xform.origin *= state.state.unit_scale;
+#endif
+ return xform;
+}
+
+Transform Collada::Node::get_transform() const {
+ return default_transform;
+}
+
+Transform Collada::Node::get_global_transform() const {
+ if (parent) {
+ return parent->get_global_transform() * default_transform;
+ } else {
+ return default_transform;
+ }
+}
+
+Vector<float> Collada::AnimationTrack::get_value_at_time(float p_time) const {
+ ERR_FAIL_COND_V(keys.size() == 0, Vector<float>());
+ int i = 0;
+
+ for (i = 0; i < keys.size(); i++) {
+ if (keys[i].time > p_time) {
+ break;
+ }
+ }
+
+ if (i == 0) {
+ return keys[0].data;
+ }
+ if (i == keys.size()) {
+ return keys[keys.size() - 1].data;
+ }
+
+ switch (keys[i].interp_type) {
+ case INTERP_BEZIER: //wait for bezier
+ case INTERP_LINEAR: {
+ float c = (p_time - keys[i - 1].time) / (keys[i].time - keys[i - 1].time);
+
+ if (keys[i].data.size() == 16) {
+ //interpolate a matrix
+ Transform src = _read_transform_from_array(keys[i - 1].data);
+ Transform dst = _read_transform_from_array(keys[i].data);
+
+ Transform interp = c < 0.001 ? src : src.interpolate_with(dst, c);
+
+ Vector<float> ret;
+ ret.resize(16);
+ Transform tr;
+ // i wonder why collada matrices are transposed, given that's opposed to opengl..
+ ret.write[0] = interp.basis.elements[0][0];
+ ret.write[1] = interp.basis.elements[0][1];
+ ret.write[2] = interp.basis.elements[0][2];
+ ret.write[4] = interp.basis.elements[1][0];
+ ret.write[5] = interp.basis.elements[1][1];
+ ret.write[6] = interp.basis.elements[1][2];
+ ret.write[8] = interp.basis.elements[2][0];
+ ret.write[9] = interp.basis.elements[2][1];
+ ret.write[10] = interp.basis.elements[2][2];
+ ret.write[3] = interp.origin.x;
+ ret.write[7] = interp.origin.y;
+ ret.write[11] = interp.origin.z;
+ ret.write[12] = 0;
+ ret.write[13] = 0;
+ ret.write[14] = 0;
+ ret.write[15] = 1;
+
+ return ret;
+ } else {
+ Vector<float> dest;
+ dest.resize(keys[i].data.size());
+ for (int j = 0; j < dest.size(); j++) {
+ dest.write[j] = keys[i].data[j] * c + keys[i - 1].data[j] * (1.0 - c);
+ }
+ return dest;
+ //interpolate one by one
+ }
+ } break;
+ }
+
+ ERR_FAIL_V(Vector<float>());
+}
+
+void Collada::_parse_asset(XMLParser &parser) {
+ while (parser.read() == OK) {
+ if (parser.get_node_type() == XMLParser::NODE_ELEMENT) {
+ String name = parser.get_node_name();
+
+ if (name == "up_axis") {
+ parser.read();
+ if (parser.get_node_data() == "X_UP") {
+ state.up_axis = Vector3::AXIS_X;
+ }
+ if (parser.get_node_data() == "Y_UP") {
+ state.up_axis = Vector3::AXIS_Y;
+ }
+ if (parser.get_node_data() == "Z_UP") {
+ state.up_axis = Vector3::AXIS_Z;
+ }
+
+ COLLADA_PRINT("up axis: " + parser.get_node_data());
+ } else if (name == "unit") {
+ state.unit_scale = parser.get_attribute_value("meter").to_double();
+ COLLADA_PRINT("unit scale: " + rtos(state.unit_scale));
+ }
+
+ } else if (parser.get_node_type() == XMLParser::NODE_ELEMENT_END && parser.get_node_name() == "asset") {
+ break; //end of <asset>
+ }
+ }
+}
+
+void Collada::_parse_image(XMLParser &parser) {
+ String id = parser.get_attribute_value("id");
+
+ if (!(state.import_flags & IMPORT_FLAG_SCENE)) {
+ if (!parser.is_empty()) {
+ parser.skip_section();
+ }
+ return;
+ }
+
+ Image image;
+
+ if (state.version < State::Version(1, 4, 0)) {
+ /* <1.4 */
+ String path = parser.get_attribute_value("source").strip_edges();
+ if (path.find("://") == -1 && path.is_rel_path()) {
+ // path is relative to file being loaded, so convert to a resource path
+ image.path = ProjectSettings::get_singleton()->localize_path(state.local_path.get_base_dir().plus_file(path.percent_decode()));
+ }
+ } else {
+ while (parser.read() == OK) {
+ if (parser.get_node_type() == XMLParser::NODE_ELEMENT) {
+ String name = parser.get_node_name();
+
+ if (name == "init_from") {
+ parser.read();
+ String path = parser.get_node_data().strip_edges().percent_decode();
+
+ if (path.find("://") == -1 && path.is_rel_path()) {
+ // path is relative to file being loaded, so convert to a resource path
+ path = ProjectSettings::get_singleton()->localize_path(state.local_path.get_base_dir().plus_file(path));
+
+ } else if (path.find("file:///") == 0) {
+ path = path.replace_first("file:///", "");
+ path = ProjectSettings::get_singleton()->localize_path(path);
+ }
+
+ image.path = path;
+
+ } else if (name == "data") {
+ ERR_PRINT("COLLADA Embedded image data not supported!");
+
+ } else if (name == "extra" && !parser.is_empty()) {
+ parser.skip_section();
+ }
+
+ } else if (parser.get_node_type() == XMLParser::NODE_ELEMENT_END && parser.get_node_name() == "image") {
+ break; //end of <asset>
+ }
+ }
+ }
+
+ state.image_map[id] = image;
+}
+
+void Collada::_parse_material(XMLParser &parser) {
+ if (!(state.import_flags & IMPORT_FLAG_SCENE)) {
+ if (!parser.is_empty()) {
+ parser.skip_section();
+ }
+ return;
+ }
+
+ Material material;
+
+ String id = parser.get_attribute_value("id");
+ if (parser.has_attribute("name")) {
+ material.name = parser.get_attribute_value("name");
+ }
+
+ if (state.version < State::Version(1, 4, 0)) {
+ /* <1.4 */
+ ERR_PRINT("Collada Materials < 1.4 are not supported (yet)");
+ } else {
+ while (parser.read() == OK) {
+ if (parser.get_node_type() == XMLParser::NODE_ELEMENT && parser.get_node_name() == "instance_effect") {
+ material.instance_effect = _uri_to_id(parser.get_attribute_value("url"));
+ } else if (parser.get_node_type() == XMLParser::NODE_ELEMENT_END && parser.get_node_name() == "material") {
+ break; //end of <asset>
+ }
+ }
+ }
+
+ state.material_map[id] = material;
+}
+
+//! reads floats from inside of xml element until end of xml element
+Vector<float> Collada::_read_float_array(XMLParser &parser) {
+ if (parser.is_empty()) {
+ return Vector<float>();
+ }
+
+ Vector<String> splitters;
+ splitters.push_back(" ");
+ splitters.push_back("\n");
+ splitters.push_back("\r");
+ splitters.push_back("\t");
+
+ Vector<float> array;
+ while (parser.read() == OK) {
+ // TODO: check for comments inside the element
+ // and ignore them.
+
+ if (parser.get_node_type() == XMLParser::NODE_TEXT) {
+ // parse float data
+ String str = parser.get_node_data();
+ array = str.split_floats_mk(splitters, false);
+ //array=str.split_floats(" ",false);
+ } else if (parser.get_node_type() == XMLParser::NODE_ELEMENT_END) {
+ break; // end parsing text
+ }
+ }
+
+ return array;
+}
+
+Vector<String> Collada::_read_string_array(XMLParser &parser) {
+ if (parser.is_empty()) {
+ return Vector<String>();
+ }
+
+ Vector<String> array;
+ while (parser.read() == OK) {
+ // TODO: check for comments inside the element
+ // and ignore them.
+
+ if (parser.get_node_type() == XMLParser::NODE_TEXT) {
+ // parse String data
+ String str = parser.get_node_data();
+ array = str.split_spaces();
+ } else if (parser.get_node_type() == XMLParser::NODE_ELEMENT_END) {
+ break; // end parsing text
+ }
+ }
+
+ return array;
+}
+
+Transform Collada::_read_transform(XMLParser &parser) {
+ if (parser.is_empty()) {
+ return Transform();
+ }
+
+ Vector<String> array;
+ while (parser.read() == OK) {
+ // TODO: check for comments inside the element
+ // and ignore them.
+
+ if (parser.get_node_type() == XMLParser::NODE_TEXT) {
+ // parse float data
+ String str = parser.get_node_data();
+ array = str.split_spaces();
+ } else if (parser.get_node_type() == XMLParser::NODE_ELEMENT_END) {
+ break; // end parsing text
+ }
+ }
+
+ ERR_FAIL_COND_V(array.size() != 16, Transform());
+ Vector<float> farr;
+ farr.resize(16);
+ for (int i = 0; i < 16; i++) {
+ farr.write[i] = array[i].to_double();
+ }
+
+ return _read_transform_from_array(farr);
+}
+
+String Collada::_read_empty_draw_type(XMLParser &parser) {
+ String empty_draw_type = "";
+
+ if (parser.is_empty()) {
+ return empty_draw_type;
+ }
+
+ while (parser.read() == OK) {
+ if (parser.get_node_type() == XMLParser::NODE_TEXT) {
+ empty_draw_type = parser.get_node_data();
+ } else if (parser.get_node_type() == XMLParser::NODE_ELEMENT_END) {
+ break; // end parsing text
+ }
+ }
+ return empty_draw_type;
+}
+
+Variant Collada::_parse_param(XMLParser &parser) {
+ if (parser.is_empty()) {
+ return Variant();
+ }
+
+ String from = parser.get_node_name();
+ Variant data;
+
+ while (parser.read() == OK) {
+ if (parser.get_node_type() == XMLParser::NODE_ELEMENT) {
+ if (parser.get_node_name() == "float") {
+ parser.read();
+ if (parser.get_node_type() == XMLParser::NODE_TEXT) {
+ data = parser.get_node_data().to_double();
+ }
+ } else if (parser.get_node_name() == "float2") {
+ Vector<float> v2 = _read_float_array(parser);
+
+ if (v2.size() >= 2) {
+ data = Vector2(v2[0], v2[1]);
+ }
+ } else if (parser.get_node_name() == "float3") {
+ Vector<float> v3 = _read_float_array(parser);
+
+ if (v3.size() >= 3) {
+ data = Vector3(v3[0], v3[1], v3[2]);
+ }
+ } else if (parser.get_node_name() == "float4") {
+ Vector<float> v4 = _read_float_array(parser);
+
+ if (v4.size() >= 4) {
+ data = Color(v4[0], v4[1], v4[2], v4[3]);
+ }
+ } else if (parser.get_node_name() == "sampler2D") {
+ while (parser.read() == OK) {
+ if (parser.get_node_type() == XMLParser::NODE_ELEMENT) {
+ if (parser.get_node_name() == "source") {
+ parser.read();
+
+ if (parser.get_node_type() == XMLParser::NODE_TEXT) {
+ data = parser.get_node_data();
+ }
+ }
+ } else if (parser.get_node_type() == XMLParser::NODE_ELEMENT_END && parser.get_node_name() == "sampler2D") {
+ break;
+ }
+ }
+ } else if (parser.get_node_name() == "surface") {
+ while (parser.read() == OK) {
+ if (parser.get_node_type() == XMLParser::NODE_ELEMENT) {
+ if (parser.get_node_name() == "init_from") {
+ parser.read();
+
+ if (parser.get_node_type() == XMLParser::NODE_TEXT) {
+ data = parser.get_node_data();
+ }
+ }
+ } else if (parser.get_node_type() == XMLParser::NODE_ELEMENT_END && parser.get_node_name() == "surface") {
+ break;
+ }
+ }
+ }
+
+ } else if (parser.get_node_type() == XMLParser::NODE_ELEMENT_END && parser.get_node_name() == from) {
+ break;
+ }
+ }
+
+ COLLADA_PRINT("newparam ending " + parser.get_node_name());
+ return data;
+}
+
+void Collada::_parse_effect_material(XMLParser &parser, Effect &effect, String &id) {
+ if (!(state.import_flags & IMPORT_FLAG_SCENE)) {
+ if (!parser.is_empty()) {
+ parser.skip_section();
+ }
+ return;
+ }
+
+ while (parser.read() == OK) {
+ if (parser.get_node_type() == XMLParser::NODE_ELEMENT) {
+ // first come the tags we descend, but ignore the top-levels
+
+ COLLADA_PRINT("node name: " + parser.get_node_name());
+
+ if (!parser.is_empty() && (parser.get_node_name() == "profile_COMMON" || parser.get_node_name() == "technique" || parser.get_node_name() == "extra")) {
+ _parse_effect_material(parser, effect, id); // try again
+
+ } else if (parser.get_node_name() == "newparam") {
+ String name = parser.get_attribute_value("sid");
+ Variant value = _parse_param(parser);
+ effect.params[name] = value;
+ COLLADA_PRINT("param: " + name + " value:" + String(value));
+
+ } else if (parser.get_node_name() == "constant" ||
+ parser.get_node_name() == "lambert" ||
+ parser.get_node_name() == "phong" ||
+ parser.get_node_name() == "blinn") {
+ COLLADA_PRINT("shade model: " + parser.get_node_name());
+ while (parser.read() == OK) {
+ if (parser.get_node_type() == XMLParser::NODE_ELEMENT) {
+ String what = parser.get_node_name();
+
+ if (what == "emission" ||
+ what == "diffuse" ||
+ what == "specular" ||
+ what == "reflective") {
+ // color or texture types
+ while (parser.read() == OK) {
+ if (parser.get_node_type() == XMLParser::NODE_ELEMENT) {
+ if (parser.get_node_name() == "color") {
+ Vector<float> colorarr = _read_float_array(parser);
+ COLLADA_PRINT("colorarr size: " + rtos(colorarr.size()));
+
+ if (colorarr.size() >= 3) {
+ // alpha strangely not alright? maybe it needs to be multiplied by value as a channel intensity
+ Color color(colorarr[0], colorarr[1], colorarr[2], 1.0);
+ if (what == "diffuse") {
+ effect.diffuse.color = color;
+ }
+ if (what == "specular") {
+ effect.specular.color = color;
+ }
+ if (what == "emission") {
+ effect.emission.color = color;
+ }
+
+ COLLADA_PRINT(what + " color: " + color);
+ }
+
+ } else if (parser.get_node_name() == "texture") {
+ String sampler = parser.get_attribute_value("texture");
+ if (!effect.params.has(sampler)) {
+ ERR_PRINT(String("Couldn't find sampler: " + sampler + " in material:" + id).utf8().get_data());
+ } else {
+ String surface = effect.params[sampler];
+
+ if (!effect.params.has(surface)) {
+ ERR_PRINT(String("Couldn't find surface: " + surface + " in material:" + id).utf8().get_data());
+ } else {
+ String uri = effect.params[surface];
+
+ if (what == "diffuse") {
+ effect.diffuse.texture = uri;
+ } else if (what == "specular") {
+ effect.specular.texture = uri;
+ } else if (what == "emission") {
+ effect.emission.texture = uri;
+ } else if (what == "bump") {
+ if (parser.has_attribute("bumptype") && parser.get_attribute_value("bumptype") != "NORMALMAP") {
+ WARN_PRINT("'bump' texture type is not NORMALMAP, only NORMALMAP is supported.");
+ }
+
+ effect.bump.texture = uri;
+ }
+
+ COLLADA_PRINT(what + " texture: " + uri);
+ }
+ }
+ } else if (!parser.is_empty()) {
+ parser.skip_section();
+ }
+
+ } else if (parser.get_node_type() == XMLParser::NODE_ELEMENT_END && parser.get_node_name() == what) {
+ break;
+ }
+ }
+
+ } else if (what == "shininess") {
+ effect.shininess = _parse_param(parser);
+ }
+ } else if (parser.get_node_type() == XMLParser::NODE_ELEMENT_END && (parser.get_node_name() == "constant" ||
+ parser.get_node_name() == "lambert" ||
+ parser.get_node_name() == "phong" ||
+ parser.get_node_name() == "blinn")) {
+ break;
+ }
+ }
+ } else if (parser.get_node_name() == "double_sided" || parser.get_node_name() == "show_double_sided") { // colladamax / google earth
+
+ // 3DS Max / Google Earth double sided extension
+ parser.read();
+ effect.found_double_sided = true;
+ effect.double_sided = parser.get_node_data().to_int();
+ COLLADA_PRINT("double sided: " + itos(parser.get_node_data().to_int()));
+ } else if (parser.get_node_name() == "unshaded") {
+ parser.read();
+ effect.unshaded = parser.get_node_data().to_int();
+ } else if (parser.get_node_name() == "bump") {
+ // color or texture types
+ while (parser.read() == OK) {
+ if (parser.get_node_type() == XMLParser::NODE_ELEMENT) {
+ if (parser.get_node_name() == "texture") {
+ String sampler = parser.get_attribute_value("texture");
+ if (!effect.params.has(sampler)) {
+ ERR_PRINT(String("Couldn't find sampler: " + sampler + " in material:" + id).utf8().get_data());
+ } else {
+ String surface = effect.params[sampler];
+
+ if (!effect.params.has(surface)) {
+ ERR_PRINT(String("Couldn't find surface: " + surface + " in material:" + id).utf8().get_data());
+ } else {
+ String uri = effect.params[surface];
+
+ if (parser.has_attribute("bumptype") && parser.get_attribute_value("bumptype") != "NORMALMAP") {
+ WARN_PRINT("'bump' texture type is not NORMALMAP, only NORMALMAP is supported.");
+ }
+
+ effect.bump.texture = uri;
+ COLLADA_PRINT(" bump: " + uri);
+ }
+ }
+ } else if (!parser.is_empty()) {
+ parser.skip_section();
+ }
+
+ } else if (parser.get_node_type() == XMLParser::NODE_ELEMENT_END && parser.get_node_name() == "bump") {
+ break;
+ }
+ }
+
+ } else if (!parser.is_empty()) {
+ parser.skip_section();
+ }
+ } else if (parser.get_node_type() == XMLParser::NODE_ELEMENT_END &&
+ (parser.get_node_name() == "effect" ||
+ parser.get_node_name() == "profile_COMMON" ||
+ parser.get_node_name() == "technique" ||
+ parser.get_node_name() == "extra")) {
+ break;
+ }
+ }
+}
+
+void Collada::_parse_effect(XMLParser &parser) {
+ if (!(state.import_flags & IMPORT_FLAG_SCENE)) {
+ if (!parser.is_empty()) {
+ parser.skip_section();
+ }
+ return;
+ }
+
+ String id = parser.get_attribute_value("id");
+
+ Effect effect;
+ if (parser.has_attribute("name")) {
+ effect.name = parser.get_attribute_value("name");
+ }
+ _parse_effect_material(parser, effect, id);
+
+ state.effect_map[id] = effect;
+
+ COLLADA_PRINT("Effect ID:" + id);
+}
+
+void Collada::_parse_camera(XMLParser &parser) {
+ if (!(state.import_flags & IMPORT_FLAG_SCENE)) {
+ if (!parser.is_empty()) {
+ parser.skip_section();
+ }
+ return;
+ }
+
+ String id = parser.get_attribute_value("id");
+
+ state.camera_data_map[id] = CameraData();
+ CameraData &camera = state.camera_data_map[id];
+
+ while (parser.read() == OK) {
+ if (parser.get_node_type() == XMLParser::NODE_ELEMENT) {
+ String name = parser.get_node_name();
+
+ if (name == "perspective") {
+ camera.mode = CameraData::MODE_PERSPECTIVE;
+ } else if (name == "orthographic") {
+ camera.mode = CameraData::MODE_ORTHOGONAL;
+ } else if (name == "xfov") {
+ parser.read();
+ camera.perspective.x_fov = parser.get_node_data().to_double();
+
+ } else if (name == "yfov") {
+ parser.read();
+ camera.perspective.y_fov = parser.get_node_data().to_double();
+ } else if (name == "xmag") {
+ parser.read();
+ camera.orthogonal.x_mag = parser.get_node_data().to_double();
+
+ } else if (name == "ymag") {
+ parser.read();
+ camera.orthogonal.y_mag = parser.get_node_data().to_double();
+ } else if (name == "aspect_ratio") {
+ parser.read();
+ camera.aspect = parser.get_node_data().to_double();
+
+ } else if (name == "znear") {
+ parser.read();
+ camera.z_near = parser.get_node_data().to_double();
+
+ } else if (name == "zfar") {
+ parser.read();
+ camera.z_far = parser.get_node_data().to_double();
+ }
+
+ } else if (parser.get_node_type() == XMLParser::NODE_ELEMENT_END && parser.get_node_name() == "camera") {
+ break; //end of <asset>
+ }
+ }
+
+ COLLADA_PRINT("Camera ID:" + id);
+}
+
+void Collada::_parse_light(XMLParser &parser) {
+ if (!(state.import_flags & IMPORT_FLAG_SCENE)) {
+ if (!parser.is_empty()) {
+ parser.skip_section();
+ }
+ return;
+ }
+
+ String id = parser.get_attribute_value("id");
+
+ state.light_data_map[id] = LightData();
+ LightData &light = state.light_data_map[id];
+
+ while (parser.read() == OK) {
+ if (parser.get_node_type() == XMLParser::NODE_ELEMENT) {
+ String name = parser.get_node_name();
+
+ if (name == "ambient") {
+ light.mode = LightData::MODE_AMBIENT;
+ } else if (name == "directional") {
+ light.mode = LightData::MODE_DIRECTIONAL;
+ } else if (name == "point") {
+ light.mode = LightData::MODE_OMNI;
+ } else if (name == "spot") {
+ light.mode = LightData::MODE_SPOT;
+ } else if (name == "color") {
+ parser.read();
+ Vector<float> colorarr = _read_float_array(parser);
+ COLLADA_PRINT("colorarr size: " + rtos(colorarr.size()));
+
+ if (colorarr.size() >= 4) {
+ // alpha strangely not alright? maybe it needs to be multiplied by value as a channel intensity
+ Color color(colorarr[0], colorarr[1], colorarr[2], 1.0);
+ light.color = color;
+ }
+
+ } else if (name == "constant_attenuation") {
+ parser.read();
+ light.constant_att = parser.get_node_data().to_double();
+ } else if (name == "linear_attenuation") {
+ parser.read();
+ light.linear_att = parser.get_node_data().to_double();
+ } else if (name == "quadratic_attenuation") {
+ parser.read();
+ light.quad_att = parser.get_node_data().to_double();
+ } else if (name == "falloff_angle") {
+ parser.read();
+ light.spot_angle = parser.get_node_data().to_double();
+
+ } else if (name == "falloff_exponent") {
+ parser.read();
+ light.spot_exp = parser.get_node_data().to_double();
+ }
+
+ } else if (parser.get_node_type() == XMLParser::NODE_ELEMENT_END && parser.get_node_name() == "light") {
+ break; //end of <asset>
+ }
+ }
+
+ COLLADA_PRINT("Light ID:" + id);
+}
+
+void Collada::_parse_curve_geometry(XMLParser &parser, String p_id, String p_name) {
+ if (!(state.import_flags & IMPORT_FLAG_SCENE)) {
+ if (!parser.is_empty()) {
+ parser.skip_section();
+ }
+ return;
+ }
+
+ //load everything into a pre dictionary
+
+ state.curve_data_map[p_id] = CurveData();
+
+ CurveData &curvedata = state.curve_data_map[p_id];
+ curvedata.name = p_name;
+
+ COLLADA_PRINT("curve name: " + p_name);
+
+ String current_source;
+ // handles geometry node and the curve children in this loop
+ // read sources with arrays and accessor for each curve
+ if (parser.is_empty()) {
+ return;
+ }
+
+ while (parser.read() == OK) {
+ if (parser.get_node_type() == XMLParser::NODE_ELEMENT) {
+ String section = parser.get_node_name();
+
+ if (section == "source") {
+ String id = parser.get_attribute_value("id");
+ curvedata.sources[id] = CurveData::Source();
+ current_source = id;
+ COLLADA_PRINT("source data: " + id);
+
+ } else if (section == "float_array" || section == "array") {
+ // create a new array and read it.
+ if (curvedata.sources.has(current_source)) {
+ curvedata.sources[current_source].array = _read_float_array(parser);
+ COLLADA_PRINT("section: " + current_source + " read " + itos(curvedata.sources[current_source].array.size()) + " values.");
+ }
+ } else if (section == "Name_array") {
+ // create a new array and read it.
+ if (curvedata.sources.has(current_source)) {
+ curvedata.sources[current_source].sarray = _read_string_array(parser);
+ COLLADA_PRINT("section: " + current_source + " read " + itos(curvedata.sources[current_source].array.size()) + " values.");
+ }
+
+ } else if (section == "technique_common") {
+ //skip it
+ } else if (section == "accessor") { // child of source (below a technique tag)
+
+ if (curvedata.sources.has(current_source)) {
+ curvedata.sources[current_source].stride = parser.get_attribute_value("stride").to_int();
+ COLLADA_PRINT("section: " + current_source + " stride " + itos(curvedata.sources[current_source].stride));
+ }
+ } else if (section == "control_vertices") {
+ while (parser.read() == OK) {
+ if (parser.get_node_type() == XMLParser::NODE_ELEMENT) {
+ if (parser.get_node_name() == "input") {
+ String semantic = parser.get_attribute_value("semantic");
+ String source = _uri_to_id(parser.get_attribute_value("source"));
+
+ curvedata.control_vertices[semantic] = source;
+
+ COLLADA_PRINT(section + " input semantic: " + semantic + " source: " + source);
+ }
+ } else if (parser.get_node_type() == XMLParser::NODE_ELEMENT_END && parser.get_node_name() == section) {
+ break;
+ }
+ }
+
+ } else if (!parser.is_empty()) {
+ parser.skip_section();
+ }
+ } else if (parser.get_node_type() == XMLParser::NODE_ELEMENT_END && parser.get_node_name() == "spline") {
+ break;
+ }
+ }
+}
+
+void Collada::_parse_mesh_geometry(XMLParser &parser, String p_id, String p_name) {
+ if (!(state.import_flags & IMPORT_FLAG_SCENE)) {
+ if (!parser.is_empty()) {
+ parser.skip_section();
+ }
+ return;
+ }
+
+ //load everything into a pre dictionary
+
+ state.mesh_data_map[p_id] = MeshData();
+
+ MeshData &meshdata = state.mesh_data_map[p_id];
+ meshdata.name = p_name;
+
+ COLLADA_PRINT("mesh name: " + p_name);
+
+ String current_source;
+ // handles geometry node and the mesh children in this loop
+ // read sources with arrays and accessor for each mesh
+ if (parser.is_empty()) {
+ return;
+ }
+
+ while (parser.read() == OK) {
+ if (parser.get_node_type() == XMLParser::NODE_ELEMENT) {
+ String section = parser.get_node_name();
+
+ if (section == "source") {
+ String id = parser.get_attribute_value("id");
+ meshdata.sources[id] = MeshData::Source();
+ current_source = id;
+ COLLADA_PRINT("source data: " + id);
+
+ } else if (section == "float_array" || section == "array") {
+ // create a new array and read it.
+ if (meshdata.sources.has(current_source)) {
+ meshdata.sources[current_source].array = _read_float_array(parser);
+ COLLADA_PRINT("section: " + current_source + " read " + itos(meshdata.sources[current_source].array.size()) + " values.");
+ }
+ } else if (section == "technique_common") {
+ //skip it
+ } else if (section == "accessor") { // child of source (below a technique tag)
+
+ if (meshdata.sources.has(current_source)) {
+ meshdata.sources[current_source].stride = parser.get_attribute_value("stride").to_int();
+ COLLADA_PRINT("section: " + current_source + " stride " + itos(meshdata.sources[current_source].stride));
+ }
+ } else if (section == "vertices") {
+ MeshData::Vertices vert;
+ String id = parser.get_attribute_value("id");
+
+ while (parser.read() == OK) {
+ if (parser.get_node_type() == XMLParser::NODE_ELEMENT) {
+ if (parser.get_node_name() == "input") {
+ String semantic = parser.get_attribute_value("semantic");
+ String source = _uri_to_id(parser.get_attribute_value("source"));
+
+ vert.sources[semantic] = source;
+
+ COLLADA_PRINT(section + " input semantic: " + semantic + " source: " + source);
+ }
+ } else if (parser.get_node_type() == XMLParser::NODE_ELEMENT_END && parser.get_node_name() == section) {
+ break;
+ }
+ }
+
+ meshdata.vertices[id] = vert;
+
+ } else if (section == "triangles" || section == "polylist" || section == "polygons") {
+ bool polygons = (section == "polygons");
+ if (polygons) {
+ WARN_PRINT("Primitive type \"polygons\" is not well supported (concave shapes may fail). To ensure that the geometry is properly imported, please re-export using \"triangles\" or \"polylist\".");
+ }
+ MeshData::Primitives prim;
+
+ if (parser.has_attribute("material")) {
+ prim.material = parser.get_attribute_value("material");
+ }
+ prim.count = parser.get_attribute_value("count").to_int();
+ prim.vertex_size = 0;
+ int last_ref = 0;
+
+ while (parser.read() == OK) {
+ if (parser.get_node_type() == XMLParser::NODE_ELEMENT) {
+ if (parser.get_node_name() == "input") {
+ String semantic = parser.get_attribute_value("semantic");
+ String source = _uri_to_id(parser.get_attribute_value("source"));
+
+ if (semantic == "TEXCOORD") {
+ /*
+ if (parser.has_attribute("set"))// a texcoord
+ semantic+=parser.get_attribute_value("set");
+ else
+ semantic="TEXCOORD0";*/
+ semantic = "TEXCOORD" + itos(last_ref++);
+ }
+ int offset = parser.get_attribute_value("offset").to_int();
+
+ MeshData::Primitives::SourceRef sref;
+ sref.source = source;
+ sref.offset = offset;
+ prim.sources[semantic] = sref;
+ prim.vertex_size = MAX(prim.vertex_size, offset + 1);
+
+ COLLADA_PRINT(section + " input semantic: " + semantic + " source: " + source + " offset: " + itos(offset));
+
+ } else if (parser.get_node_name() == "p") { //indices
+
+ Vector<float> values = _read_float_array(parser);
+ if (polygons) {
+ ERR_CONTINUE(prim.vertex_size == 0);
+ prim.polygons.push_back(values.size() / prim.vertex_size);
+ int from = prim.indices.size();
+ prim.indices.resize(from + values.size());
+ for (int i = 0; i < values.size(); i++) {
+ prim.indices.write[from + i] = values[i];
+ }
+
+ } else if (prim.vertex_size > 0) {
+ prim.indices = values;
+ }
+
+ COLLADA_PRINT("read " + itos(values.size()) + " index values");
+
+ } else if (parser.get_node_name() == "vcount") { // primitive
+
+ Vector<float> values = _read_float_array(parser);
+ prim.polygons = values;
+ COLLADA_PRINT("read " + itos(values.size()) + " polygon values");
+ }
+ } else if (parser.get_node_type() == XMLParser::NODE_ELEMENT_END && parser.get_node_name() == section) {
+ break;
+ }
+ }
+
+ meshdata.primitives.push_back(prim);
+
+ } else if (parser.get_node_name() == "double_sided") {
+ parser.read();
+ meshdata.found_double_sided = true;
+ meshdata.double_sided = parser.get_node_data().to_int();
+
+ } else if (parser.get_node_name() == "polygons") {
+ ERR_PRINT("Primitive type \"polygons\" not supported, re-export using \"polylist\" or \"triangles\".");
+ } else if (!parser.is_empty()) {
+ parser.skip_section();
+ }
+ } else if (parser.get_node_type() == XMLParser::NODE_ELEMENT_END && parser.get_node_name() == "mesh") {
+ break;
+ }
+ }
+}
+
+void Collada::_parse_skin_controller(XMLParser &parser, String p_id) {
+ state.skin_controller_data_map[p_id] = SkinControllerData();
+ SkinControllerData &skindata = state.skin_controller_data_map[p_id];
+
+ skindata.base = _uri_to_id(parser.get_attribute_value("source"));
+
+ String current_source;
+
+ while (parser.read() == OK) {
+ if (parser.get_node_type() == XMLParser::NODE_ELEMENT) {
+ String section = parser.get_node_name();
+
+ if (section == "bind_shape_matrix") {
+ skindata.bind_shape = _read_transform(parser);
+#ifdef COLLADA_IMPORT_SCALE_SCENE
+ skindata.bind_shape.origin *= state.unit_scale;
+
+#endif
+ COLLADA_PRINT("skeleton bind shape transform: " + skindata.bind_shape);
+
+ } else if (section == "source") {
+ String id = parser.get_attribute_value("id");
+ skindata.sources[id] = SkinControllerData::Source();
+ current_source = id;
+ COLLADA_PRINT("source data: " + id);
+
+ } else if (section == "float_array" || section == "array") {
+ // create a new array and read it.
+ if (skindata.sources.has(current_source)) {
+ skindata.sources[current_source].array = _read_float_array(parser);
+ COLLADA_PRINT("section: " + current_source + " read " + itos(skindata.sources[current_source].array.size()) + " values.");
+ }
+ } else if (section == "Name_array" || section == "IDREF_array") {
+ // create a new array and read it.
+
+ if (section == "IDREF_array") {
+ skindata.use_idrefs = true;
+ }
+ if (skindata.sources.has(current_source)) {
+ skindata.sources[current_source].sarray = _read_string_array(parser);
+ if (section == "IDREF_array") {
+ Vector<String> sa = skindata.sources[current_source].sarray;
+ for (int i = 0; i < sa.size(); i++) {
+ state.idref_joints.insert(sa[i]);
+ }
+ }
+ COLLADA_PRINT("section: " + current_source + " read " + itos(skindata.sources[current_source].array.size()) + " values.");
+ }
+ } else if (section == "technique_common") {
+ //skip it
+ } else if (section == "accessor") { // child of source (below a technique tag)
+
+ if (skindata.sources.has(current_source)) {
+ int stride = 1;
+ if (parser.has_attribute("stride")) {
+ stride = parser.get_attribute_value("stride").to_int();
+ }
+
+ skindata.sources[current_source].stride = stride;
+ COLLADA_PRINT("section: " + current_source + " stride " + itos(skindata.sources[current_source].stride));
+ }
+
+ } else if (section == "joints") {
+ SkinControllerData::Joints joint;
+
+ while (parser.read() == OK) {
+ if (parser.get_node_type() == XMLParser::NODE_ELEMENT) {
+ if (parser.get_node_name() == "input") {
+ String semantic = parser.get_attribute_value("semantic");
+ String source = _uri_to_id(parser.get_attribute_value("source"));
+
+ joint.sources[semantic] = source;
+
+ COLLADA_PRINT(section + " input semantic: " + semantic + " source: " + source);
+ }
+ } else if (parser.get_node_type() == XMLParser::NODE_ELEMENT_END && parser.get_node_name() == section) {
+ break;
+ }
+ }
+
+ skindata.joints = joint;
+
+ } else if (section == "vertex_weights") {
+ SkinControllerData::Weights weights;
+
+ weights.count = parser.get_attribute_value("count").to_int();
+
+ while (parser.read() == OK) {
+ if (parser.get_node_type() == XMLParser::NODE_ELEMENT) {
+ if (parser.get_node_name() == "input") {
+ String semantic = parser.get_attribute_value("semantic");
+ String source = _uri_to_id(parser.get_attribute_value("source"));
+
+ int offset = parser.get_attribute_value("offset").to_int();
+
+ SkinControllerData::Weights::SourceRef sref;
+ sref.source = source;
+ sref.offset = offset;
+ weights.sources[semantic] = sref;
+
+ COLLADA_PRINT(section + " input semantic: " + semantic + " source: " + source + " offset: " + itos(offset));
+
+ } else if (parser.get_node_name() == "v") { //indices
+
+ Vector<float> values = _read_float_array(parser);
+ weights.indices = values;
+ COLLADA_PRINT("read " + itos(values.size()) + " index values");
+
+ } else if (parser.get_node_name() == "vcount") { // weightsitive
+
+ Vector<float> values = _read_float_array(parser);
+ weights.sets = values;
+ COLLADA_PRINT("read " + itos(values.size()) + " polygon values");
+ }
+ } else if (parser.get_node_type() == XMLParser::NODE_ELEMENT_END && parser.get_node_name() == section) {
+ break;
+ }
+ }
+
+ skindata.weights = weights;
+ }
+ /*
+ else if (!parser.is_empty())
+ parser.skip_section();
+ */
+
+ } else if (parser.get_node_type() == XMLParser::NODE_ELEMENT_END && parser.get_node_name() == "skin") {
+ break;
+ }
+ }
+
+ /* STORE REST MATRICES */
+
+ Vector<Transform> rests;
+ ERR_FAIL_COND(!skindata.joints.sources.has("JOINT"));
+ ERR_FAIL_COND(!skindata.joints.sources.has("INV_BIND_MATRIX"));
+
+ String joint_arr = skindata.joints.sources["JOINT"];
+ String ibm = skindata.joints.sources["INV_BIND_MATRIX"];
+
+ ERR_FAIL_COND(!skindata.sources.has(joint_arr));
+ ERR_FAIL_COND(!skindata.sources.has(ibm));
+
+ SkinControllerData::Source &joint_source = skindata.sources[joint_arr];
+ SkinControllerData::Source &ibm_source = skindata.sources[ibm];
+
+ ERR_FAIL_COND(joint_source.sarray.size() != ibm_source.array.size() / 16);
+
+ for (int i = 0; i < joint_source.sarray.size(); i++) {
+ String name = joint_source.sarray[i];
+ Transform xform = _read_transform_from_array(ibm_source.array, i * 16); //<- this is a mistake, it must be applied to vertices
+ xform.affine_invert(); // inverse for rest, because it's an inverse
+#ifdef COLLADA_IMPORT_SCALE_SCENE
+ xform.origin *= state.unit_scale;
+#endif
+ skindata.bone_rest_map[name] = xform;
+ }
+}
+
+void Collada::_parse_morph_controller(XMLParser &parser, String p_id) {
+ state.morph_controller_data_map[p_id] = MorphControllerData();
+ MorphControllerData &morphdata = state.morph_controller_data_map[p_id];
+
+ morphdata.mesh = _uri_to_id(parser.get_attribute_value("source"));
+ morphdata.mode = parser.get_attribute_value("method");
+ String current_source;
+
+ while (parser.read() == OK) {
+ if (parser.get_node_type() == XMLParser::NODE_ELEMENT) {
+ String section = parser.get_node_name();
+
+ if (section == "source") {
+ String id = parser.get_attribute_value("id");
+ morphdata.sources[id] = MorphControllerData::Source();
+ current_source = id;
+ COLLADA_PRINT("source data: " + id);
+
+ } else if (section == "float_array" || section == "array") {
+ // create a new array and read it.
+ if (morphdata.sources.has(current_source)) {
+ morphdata.sources[current_source].array = _read_float_array(parser);
+ COLLADA_PRINT("section: " + current_source + " read " + itos(morphdata.sources[current_source].array.size()) + " values.");
+ }
+ } else if (section == "Name_array" || section == "IDREF_array") {
+ // create a new array and read it.
+
+ /*
+ if (section=="IDREF_array")
+ morphdata.use_idrefs=true;
+ */
+ if (morphdata.sources.has(current_source)) {
+ morphdata.sources[current_source].sarray = _read_string_array(parser);
+ /*
+ if (section=="IDREF_array") {
+ Vector<String> sa = morphdata.sources[current_source].sarray;
+ for(int i=0;i<sa.size();i++)
+ state.idref_joints.insert(sa[i]);
+ }*/
+ COLLADA_PRINT("section: " + current_source + " read " + itos(morphdata.sources[current_source].array.size()) + " values.");
+ }
+ } else if (section == "technique_common") {
+ //skip it
+ } else if (section == "accessor") { // child of source (below a technique tag)
+
+ if (morphdata.sources.has(current_source)) {
+ int stride = 1;
+ if (parser.has_attribute("stride")) {
+ stride = parser.get_attribute_value("stride").to_int();
+ }
+
+ morphdata.sources[current_source].stride = stride;
+ COLLADA_PRINT("section: " + current_source + " stride " + itos(morphdata.sources[current_source].stride));
+ }
+
+ } else if (section == "targets") {
+ while (parser.read() == OK) {
+ if (parser.get_node_type() == XMLParser::NODE_ELEMENT) {
+ if (parser.get_node_name() == "input") {
+ String semantic = parser.get_attribute_value("semantic");
+ String source = _uri_to_id(parser.get_attribute_value("source"));
+
+ morphdata.targets[semantic] = source;
+
+ COLLADA_PRINT(section + " input semantic: " + semantic + " source: " + source);
+ }
+ } else if (parser.get_node_type() == XMLParser::NODE_ELEMENT_END && parser.get_node_name() == section) {
+ break;
+ }
+ }
+ }
+ /*
+ else if (!parser.is_empty())
+ parser.skip_section();
+ */
+
+ } else if (parser.get_node_type() == XMLParser::NODE_ELEMENT_END && parser.get_node_name() == "morph") {
+ break;
+ }
+ }
+
+ if (morphdata.targets.has("MORPH_WEIGHT")) {
+ state.morph_name_map[morphdata.targets["MORPH_WEIGHT"]] = p_id;
+ }
+}
+
+void Collada::_parse_controller(XMLParser &parser) {
+ String id = parser.get_attribute_value("id");
+
+ if (parser.is_empty()) {
+ return;
+ }
+
+ while (parser.read() == OK) {
+ if (parser.get_node_type() == XMLParser::NODE_ELEMENT) {
+ String section = parser.get_node_name();
+
+ if (section == "skin") {
+ _parse_skin_controller(parser, id);
+ } else if (section == "morph") {
+ _parse_morph_controller(parser, id);
+ }
+ } else if (parser.get_node_type() == XMLParser::NODE_ELEMENT_END && parser.get_node_name() == "controller") {
+ break;
+ }
+ }
+}
+
+Collada::Node *Collada::_parse_visual_instance_geometry(XMLParser &parser) {
+ String type = parser.get_node_name();
+ NodeGeometry *geom = memnew(NodeGeometry);
+ geom->controller = type == "instance_controller";
+ geom->source = _uri_to_id(parser.get_attribute_value_safe("url"));
+
+ if (parser.is_empty()) { //nothing else to parse...
+ return geom;
+ }
+ // try to find also many materials and skeletons!
+ while (parser.read() == OK) {
+ if (parser.get_node_type() == XMLParser::NODE_ELEMENT) {
+ if (parser.get_node_name() == "instance_material") {
+ String symbol = parser.get_attribute_value("symbol");
+ String target = _uri_to_id(parser.get_attribute_value("target"));
+
+ NodeGeometry::Material mat;
+ mat.target = target;
+ geom->material_map[symbol] = mat;
+ COLLADA_PRINT("uses material: '" + target + "' on primitive'" + symbol + "'");
+ } else if (parser.get_node_name() == "skeleton") {
+ parser.read();
+ String uri = _uri_to_id(parser.get_node_data());
+ if (uri != "") {
+ geom->skeletons.push_back(uri);
+ }
+ }
+
+ } else if (parser.get_node_type() == XMLParser::NODE_ELEMENT_END && parser.get_node_name() == type) {
+ break;
+ }
+ }
+
+ if (geom->controller) {
+ if (geom->skeletons.empty()) {
+ //XSI style
+
+ if (state.skin_controller_data_map.has(geom->source)) {
+ SkinControllerData *skin = &state.skin_controller_data_map[geom->source];
+ //case where skeletons reference bones with IDREF (XSI)
+ ERR_FAIL_COND_V(!skin->joints.sources.has("JOINT"), geom);
+ String joint_arr = skin->joints.sources["JOINT"];
+ ERR_FAIL_COND_V(!skin->sources.has(joint_arr), geom);
+ Collada::SkinControllerData::Source &joint_source = skin->sources[joint_arr];
+ geom->skeletons = joint_source.sarray; //quite crazy, but should work.
+ }
+ }
+ }
+
+ return geom;
+}
+
+Collada::Node *Collada::_parse_visual_instance_camera(XMLParser &parser) {
+ NodeCamera *cam = memnew(NodeCamera);
+ cam->camera = _uri_to_id(parser.get_attribute_value_safe("url"));
+
+ if (state.up_axis == Vector3::AXIS_Z) { //collada weirdness
+ cam->post_transform.basis.rotate(Vector3(1, 0, 0), -Math_PI * 0.5);
+ }
+
+ if (parser.is_empty()) { //nothing else to parse...
+ return cam;
+ }
+
+ while (parser.read() == OK) {
+ if (parser.get_node_type() == XMLParser::NODE_ELEMENT_END && parser.get_node_name() == "instance_camera") {
+ break;
+ }
+ }
+
+ return cam;
+}
+
+Collada::Node *Collada::_parse_visual_instance_light(XMLParser &parser) {
+ NodeLight *cam = memnew(NodeLight);
+ cam->light = _uri_to_id(parser.get_attribute_value_safe("url"));
+
+ if (state.up_axis == Vector3::AXIS_Z) { //collada weirdness
+ cam->post_transform.basis.rotate(Vector3(1, 0, 0), -Math_PI * 0.5);
+ }
+
+ if (parser.is_empty()) { //nothing else to parse...
+ return cam;
+ }
+
+ while (parser.read() == OK) {
+ if (parser.get_node_type() == XMLParser::NODE_ELEMENT_END && parser.get_node_name() == "instance_light") {
+ break;
+ }
+ }
+
+ return cam;
+}
+
+Collada::Node *Collada::_parse_visual_node_instance_data(XMLParser &parser) {
+ String instance_type = parser.get_node_name();
+
+ if (instance_type == "instance_geometry" || instance_type == "instance_controller") {
+ return _parse_visual_instance_geometry(parser);
+ } else if (instance_type == "instance_camera") {
+ return _parse_visual_instance_camera(parser);
+ } else if (instance_type == "instance_light") {
+ return _parse_visual_instance_light(parser);
+ }
+
+ if (parser.is_empty()) { //nothing else to parse...
+ return nullptr;
+ }
+
+ while (parser.read() == OK) {
+ if (parser.get_node_type() == XMLParser::NODE_ELEMENT_END && parser.get_node_name() == instance_type) {
+ break;
+ }
+ }
+
+ return nullptr;
+}
+
+Collada::Node *Collada::_parse_visual_scene_node(XMLParser &parser) {
+ String name;
+
+ String id = parser.get_attribute_value_safe("id");
+
+ bool found_name = false;
+
+ if (id == "") {
+ id = "%NODEID%" + itos(Math::rand());
+
+ } else {
+ found_name = true;
+ }
+
+ Vector<Node::XForm> xform_list;
+ Vector<Node *> children;
+
+ String empty_draw_type = "";
+
+ Node *node = nullptr;
+
+ name = parser.has_attribute("name") ? parser.get_attribute_value_safe("name") : parser.get_attribute_value_safe("id");
+ if (name == "") {
+ name = id;
+ } else {
+ found_name = true;
+ }
+
+ if ((parser.has_attribute("type") && parser.get_attribute_value("type") == "JOINT") || state.idref_joints.has(name)) {
+ // handle a bone
+
+ NodeJoint *joint = memnew(NodeJoint);
+
+ if (parser.has_attribute("sid")) { //bones may not have sid
+ joint->sid = parser.get_attribute_value("sid");
+ //state.bone_map[joint->sid]=joint;
+ } else if (state.idref_joints.has(name)) {
+ joint->sid = name; //kind of a cheat but..
+ } else if (parser.has_attribute("name")) {
+ joint->sid = parser.get_attribute_value_safe("name");
+ }
+
+ if (joint->sid != "") {
+ state.sid_to_node_map[joint->sid] = id;
+ }
+
+ node = joint;
+ }
+
+ while (parser.read() == OK) {
+ if (parser.get_node_type() == XMLParser::NODE_ELEMENT) {
+ String section = parser.get_node_name();
+
+ if (section == "translate") {
+ Node::XForm xf;
+ if (parser.has_attribute("sid")) {
+ xf.id = parser.get_attribute_value("sid");
+ }
+ xf.op = Node::XForm::OP_TRANSLATE;
+
+ Vector<float> xlt = _read_float_array(parser);
+ xf.data = xlt;
+ xform_list.push_back(xf);
+
+ } else if (section == "rotate") {
+ Node::XForm xf;
+ if (parser.has_attribute("sid")) {
+ xf.id = parser.get_attribute_value("sid");
+ }
+ xf.op = Node::XForm::OP_ROTATE;
+
+ Vector<float> rot = _read_float_array(parser);
+ xf.data = rot;
+
+ xform_list.push_back(xf);
+
+ } else if (section == "scale") {
+ Node::XForm xf;
+ if (parser.has_attribute("sid")) {
+ xf.id = parser.get_attribute_value("sid");
+ }
+
+ xf.op = Node::XForm::OP_SCALE;
+
+ Vector<float> scale = _read_float_array(parser);
+
+ xf.data = scale;
+
+ xform_list.push_back(xf);
+
+ } else if (section == "matrix") {
+ Node::XForm xf;
+ if (parser.has_attribute("sid")) {
+ xf.id = parser.get_attribute_value("sid");
+ }
+ xf.op = Node::XForm::OP_MATRIX;
+
+ Vector<float> matrix = _read_float_array(parser);
+
+ xf.data = matrix;
+ String mtx;
+ for (int i = 0; i < matrix.size(); i++) {
+ mtx += " " + rtos(matrix[i]);
+ }
+
+ xform_list.push_back(xf);
+
+ } else if (section == "visibility") {
+ Node::XForm xf;
+ if (parser.has_attribute("sid")) {
+ xf.id = parser.get_attribute_value("sid");
+ }
+ xf.op = Node::XForm::OP_VISIBILITY;
+
+ Vector<float> visible = _read_float_array(parser);
+
+ xf.data = visible;
+
+ xform_list.push_back(xf);
+
+ } else if (section == "empty_draw_type") {
+ empty_draw_type = _read_empty_draw_type(parser);
+ } else if (section == "technique" || section == "extra") {
+ } else if (section != "node") {
+ //usually what defines the type of node
+ if (section.begins_with("instance_")) {
+ if (!node) {
+ node = _parse_visual_node_instance_data(parser);
+
+ } else {
+ ERR_PRINT("Multiple instance_* not supported.");
+ }
+ }
+
+ } else {
+ /* Found a child node!! what to do..*/
+
+ Node *child = _parse_visual_scene_node(parser);
+ children.push_back(child);
+ }
+
+ } else if (parser.get_node_type() == XMLParser::NODE_ELEMENT_END && parser.get_node_name() == "node") {
+ break;
+ }
+ }
+
+ if (!node) {
+ node = memnew(Node); //generic node, nothing of relevance found
+ }
+
+ node->noname = !found_name;
+ node->xform_list = xform_list;
+ node->children = children;
+ for (int i = 0; i < children.size(); i++) {
+ node->children[i]->parent = node;
+ }
+
+ node->name = name;
+ node->id = id;
+ node->empty_draw_type = empty_draw_type;
+
+ if (node->children.size() == 1) {
+ if (node->children[0]->noname && !node->noname) {
+ node->children[0]->name = node->name;
+ node->name = node->name + "-base";
+ }
+ }
+
+ node->default_transform = node->compute_transform(*this);
+ state.scene_map[id] = node;
+
+ return node;
+}
+
+void Collada::_parse_visual_scene(XMLParser &parser) {
+ String id = parser.get_attribute_value("id");
+
+ if (parser.is_empty()) {
+ return;
+ }
+
+ state.visual_scene_map[id] = VisualScene();
+ VisualScene &vscene = state.visual_scene_map[id];
+
+ if (parser.has_attribute("name")) {
+ vscene.name = parser.get_attribute_value("name");
+ }
+
+ while (parser.read() == OK) {
+ if (parser.get_node_type() == XMLParser::NODE_ELEMENT) {
+ String section = parser.get_node_name();
+
+ if (section == "node") {
+ vscene.root_nodes.push_back(_parse_visual_scene_node(parser));
+ }
+
+ } else if (parser.get_node_type() == XMLParser::NODE_ELEMENT_END && parser.get_node_name() == "visual_scene") {
+ break;
+ }
+ }
+
+ COLLADA_PRINT("Scene ID:" + id);
+}
+
+void Collada::_parse_animation(XMLParser &parser) {
+ if (!(state.import_flags & IMPORT_FLAG_ANIMATION)) {
+ if (!parser.is_empty()) {
+ parser.skip_section();
+ }
+
+ return;
+ }
+
+ Map<String, Vector<float>> float_sources;
+ Map<String, Vector<String>> string_sources;
+ Map<String, int> source_strides;
+ Map<String, Map<String, String>> samplers;
+ Map<String, Vector<String>> source_param_names;
+ Map<String, Vector<String>> source_param_types;
+
+ String id = "";
+ if (parser.has_attribute("id")) {
+ id = parser.get_attribute_value("id");
+ }
+
+ String current_source;
+ String current_sampler;
+ Vector<String> channel_sources;
+ Vector<String> channel_targets;
+
+ while (parser.read() == OK) {
+ if (parser.get_node_type() == XMLParser::NODE_ELEMENT) {
+ String name = parser.get_node_name();
+ if (name == "source") {
+ current_source = parser.get_attribute_value("id");
+ source_param_names[current_source] = Vector<String>();
+ source_param_types[current_source] = Vector<String>();
+
+ } else if (name == "float_array") {
+ if (current_source != "") {
+ float_sources[current_source] = _read_float_array(parser);
+ }
+
+ } else if (name == "Name_array") {
+ if (current_source != "") {
+ string_sources[current_source] = _read_string_array(parser);
+ }
+ } else if (name == "accessor") {
+ if (current_source != "" && parser.has_attribute("stride")) {
+ source_strides[current_source] = parser.get_attribute_value("stride").to_int();
+ }
+ } else if (name == "sampler") {
+ current_sampler = parser.get_attribute_value("id");
+ samplers[current_sampler] = Map<String, String>();
+ } else if (name == "param") {
+ if (parser.has_attribute("name")) {
+ source_param_names[current_source].push_back(parser.get_attribute_value("name"));
+ } else {
+ source_param_names[current_source].push_back("");
+ }
+
+ if (parser.has_attribute("type")) {
+ source_param_types[current_source].push_back(parser.get_attribute_value("type"));
+ } else {
+ source_param_types[current_source].push_back("");
+ }
+
+ } else if (name == "input") {
+ if (current_sampler != "") {
+ samplers[current_sampler][parser.get_attribute_value("semantic")] = parser.get_attribute_value("source");
+ }
+
+ } else if (name == "channel") {
+ channel_sources.push_back(parser.get_attribute_value("source"));
+ channel_targets.push_back(parser.get_attribute_value("target"));
+ }
+
+ } else if (parser.get_node_type() == XMLParser::NODE_ELEMENT_END && parser.get_node_name() == "animation") {
+ break; //end of <asset>
+ }
+ }
+
+ for (int i = 0; i < channel_sources.size(); i++) {
+ String source = _uri_to_id(channel_sources[i]);
+ String target = channel_targets[i];
+ ERR_CONTINUE(!samplers.has(source));
+ Map<String, String> &sampler = samplers[source];
+
+ ERR_CONTINUE(!sampler.has("INPUT")); //no input semantic? wtf?
+ String input_id = _uri_to_id(sampler["INPUT"]);
+ COLLADA_PRINT("input id is " + input_id);
+ ERR_CONTINUE(!float_sources.has(input_id));
+
+ ERR_CONTINUE(!sampler.has("OUTPUT"));
+ String output_id = _uri_to_id(sampler["OUTPUT"]);
+ ERR_CONTINUE(!float_sources.has(output_id));
+
+ ERR_CONTINUE(!source_param_names.has(output_id));
+
+ Vector<String> &names = source_param_names[output_id];
+
+ for (int l = 0; l < names.size(); l++) {
+ String name = names[l];
+
+ Vector<float> &time_keys = float_sources[input_id];
+ int key_count = time_keys.size();
+
+ AnimationTrack track; //begin crating track
+ track.id = id;
+
+ track.keys.resize(key_count);
+
+ for (int j = 0; j < key_count; j++) {
+ track.keys.write[j].time = time_keys[j];
+ state.animation_length = MAX(state.animation_length, time_keys[j]);
+ }
+
+ //now read actual values
+
+ int stride = 1;
+
+ if (source_strides.has(output_id)) {
+ stride = source_strides[output_id];
+ }
+ int output_len = stride / names.size();
+
+ ERR_CONTINUE(output_len == 0);
+ ERR_CONTINUE(!float_sources.has(output_id));
+
+ Vector<float> &output = float_sources[output_id];
+
+ ERR_CONTINUE_MSG((output.size() / stride) != key_count, "Wrong number of keys in output.");
+
+ for (int j = 0; j < key_count; j++) {
+ track.keys.write[j].data.resize(output_len);
+ for (int k = 0; k < output_len; k++) {
+ track.keys.write[j].data.write[k] = output[l + j * stride + k]; //super weird but should work:
+ }
+ }
+
+ if (sampler.has("INTERPOLATION")) {
+ String interp_id = _uri_to_id(sampler["INTERPOLATION"]);
+ ERR_CONTINUE(!string_sources.has(interp_id));
+ Vector<String> &interps = string_sources[interp_id];
+ ERR_CONTINUE(interps.size() != key_count);
+
+ for (int j = 0; j < key_count; j++) {
+ if (interps[j] == "BEZIER") {
+ track.keys.write[j].interp_type = AnimationTrack::INTERP_BEZIER;
+ } else {
+ track.keys.write[j].interp_type = AnimationTrack::INTERP_LINEAR;
+ }
+ }
+ }
+
+ if (sampler.has("IN_TANGENT") && sampler.has("OUT_TANGENT")) {
+ //bezier control points..
+ String intangent_id = _uri_to_id(sampler["IN_TANGENT"]);
+ ERR_CONTINUE(!float_sources.has(intangent_id));
+ Vector<float> &intangents = float_sources[intangent_id];
+
+ ERR_CONTINUE(intangents.size() != key_count * 2 * names.size());
+
+ String outangent_id = _uri_to_id(sampler["OUT_TANGENT"]);
+ ERR_CONTINUE(!float_sources.has(outangent_id));
+ Vector<float> &outangents = float_sources[outangent_id];
+ ERR_CONTINUE(outangents.size() != key_count * 2 * names.size());
+
+ for (int j = 0; j < key_count; j++) {
+ track.keys.write[j].in_tangent = Vector2(intangents[j * 2 * names.size() + 0 + l * 2], intangents[j * 2 * names.size() + 1 + l * 2]);
+ track.keys.write[j].out_tangent = Vector2(outangents[j * 2 * names.size() + 0 + l * 2], outangents[j * 2 * names.size() + 1 + l * 2]);
+ }
+ }
+
+ if (target.find("/") != -1) { //transform component
+ track.target = target.get_slicec('/', 0);
+ track.param = target.get_slicec('/', 1);
+ if (track.param.find(".") != -1) {
+ track.component = track.param.get_slice(".", 1).to_upper();
+ }
+ track.param = track.param.get_slice(".", 0);
+ if (names.size() > 1 && track.component == "") {
+ //this is a guess because the collada spec is ambiguous here...
+ //i suppose if you have many names (outputs) you can't use a component and i should abide to that.
+ track.component = name;
+ }
+ } else {
+ track.target = target;
+ }
+
+ state.animation_tracks.push_back(track);
+
+ if (!state.referenced_tracks.has(target)) {
+ state.referenced_tracks[target] = Vector<int>();
+ }
+
+ state.referenced_tracks[target].push_back(state.animation_tracks.size() - 1);
+
+ if (id != "") {
+ if (!state.by_id_tracks.has(id)) {
+ state.by_id_tracks[id] = Vector<int>();
+ }
+
+ state.by_id_tracks[id].push_back(state.animation_tracks.size() - 1);
+ }
+
+ COLLADA_PRINT("loaded animation with " + itos(key_count) + " keys");
+ }
+ }
+}
+
+void Collada::_parse_animation_clip(XMLParser &parser) {
+ if (!(state.import_flags & IMPORT_FLAG_ANIMATION)) {
+ if (!parser.is_empty()) {
+ parser.skip_section();
+ }
+
+ return;
+ }
+
+ AnimationClip clip;
+
+ if (parser.has_attribute("name")) {
+ clip.name = parser.get_attribute_value("name");
+ } else if (parser.has_attribute("id")) {
+ clip.name = parser.get_attribute_value("id");
+ }
+ if (parser.has_attribute("start")) {
+ clip.begin = parser.get_attribute_value("start").to_double();
+ }
+ if (parser.has_attribute("end")) {
+ clip.end = parser.get_attribute_value("end").to_double();
+ }
+
+ while (parser.read() == OK) {
+ if (parser.get_node_type() == XMLParser::NODE_ELEMENT) {
+ String name = parser.get_node_name();
+ if (name == "instance_animation") {
+ String url = _uri_to_id(parser.get_attribute_value("url"));
+ clip.tracks.push_back(url);
+ }
+
+ } else if (parser.get_node_type() == XMLParser::NODE_ELEMENT_END && parser.get_node_name() == "animation_clip") {
+ break; //end of <asset>
+ }
+ }
+
+ state.animation_clips.push_back(clip);
+}
+
+void Collada::_parse_scene(XMLParser &parser) {
+ if (parser.is_empty()) {
+ return;
+ }
+
+ while (parser.read() == OK) {
+ if (parser.get_node_type() == XMLParser::NODE_ELEMENT) {
+ String name = parser.get_node_name();
+
+ if (name == "instance_visual_scene") {
+ state.root_visual_scene = _uri_to_id(parser.get_attribute_value("url"));
+ } else if (name == "instance_physics_scene") {
+ state.root_physics_scene = _uri_to_id(parser.get_attribute_value("url"));
+ }
+
+ } else if (parser.get_node_type() == XMLParser::NODE_ELEMENT_END && parser.get_node_name() == "scene") {
+ break; //end of <asset>
+ }
+ }
+}
+
+void Collada::_parse_library(XMLParser &parser) {
+ if (parser.is_empty()) {
+ return;
+ }
+
+ while (parser.read() == OK) {
+ if (parser.get_node_type() == XMLParser::NODE_ELEMENT) {
+ String name = parser.get_node_name();
+ COLLADA_PRINT("library name is: " + name);
+ if (name == "image") {
+ _parse_image(parser);
+ } else if (name == "material") {
+ _parse_material(parser);
+ } else if (name == "effect") {
+ _parse_effect(parser);
+ } else if (name == "camera") {
+ _parse_camera(parser);
+ } else if (name == "light") {
+ _parse_light(parser);
+ } else if (name == "geometry") {
+ String id = parser.get_attribute_value("id");
+ String name2 = parser.get_attribute_value_safe("name");
+ while (parser.read() == OK) {
+ if (parser.get_node_type() == XMLParser::NODE_ELEMENT) {
+ if (parser.get_node_name() == "mesh") {
+ state.mesh_name_map[id] = (name2 != "") ? name2 : id;
+ _parse_mesh_geometry(parser, id, name2);
+ } else if (parser.get_node_name() == "spline") {
+ state.mesh_name_map[id] = (name2 != "") ? name2 : id;
+ _parse_curve_geometry(parser, id, name2);
+ } else if (!parser.is_empty()) {
+ parser.skip_section();
+ }
+ } else if (parser.get_node_type() == XMLParser::NODE_ELEMENT_END && parser.get_node_name() == "geometry") {
+ break;
+ }
+ }
+
+ } else if (name == "controller") {
+ _parse_controller(parser);
+ } else if (name == "animation") {
+ _parse_animation(parser);
+ } else if (name == "animation_clip") {
+ _parse_animation_clip(parser);
+ } else if (name == "visual_scene") {
+ COLLADA_PRINT("visual scene");
+ _parse_visual_scene(parser);
+ } else if (!parser.is_empty()) {
+ parser.skip_section();
+ }
+
+ } else if (parser.get_node_type() == XMLParser::NODE_ELEMENT_END && parser.get_node_name().begins_with("library_")) {
+ break; //end of <asset>
+ }
+ }
+}
+
+void Collada::_joint_set_owner(Collada::Node *p_node, NodeSkeleton *p_owner) {
+ if (p_node->type == Node::TYPE_JOINT) {
+ NodeJoint *nj = static_cast<NodeJoint *>(p_node);
+ nj->owner = p_owner;
+
+ for (int i = 0; i < nj->children.size(); i++) {
+ _joint_set_owner(nj->children.write[i], p_owner);
+ }
+ }
+}
+
+void Collada::_create_skeletons(Collada::Node **p_node, NodeSkeleton *p_skeleton) {
+ Node *node = *p_node;
+
+ if (node->type == Node::TYPE_JOINT) {
+ if (!p_skeleton) {
+ // ohohohoohoo it's a joint node, time to work!
+ NodeSkeleton *sk = memnew(NodeSkeleton);
+ *p_node = sk;
+ sk->children.push_back(node);
+ sk->parent = node->parent;
+ node->parent = sk;
+ p_skeleton = sk;
+ }
+
+ NodeJoint *nj = static_cast<NodeJoint *>(node);
+ nj->owner = p_skeleton;
+ } else {
+ p_skeleton = nullptr;
+ }
+
+ for (int i = 0; i < node->children.size(); i++) {
+ _create_skeletons(&node->children.write[i], p_skeleton);
+ }
+}
+
+bool Collada::_remove_node(Node *p_parent, Node *p_node) {
+ for (int i = 0; i < p_parent->children.size(); i++) {
+ if (p_parent->children[i] == p_node) {
+ p_parent->children.remove(i);
+ return true;
+ }
+ if (_remove_node(p_parent->children[i], p_node)) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+void Collada::_remove_node(VisualScene *p_vscene, Node *p_node) {
+ for (int i = 0; i < p_vscene->root_nodes.size(); i++) {
+ if (p_vscene->root_nodes[i] == p_node) {
+ p_vscene->root_nodes.remove(i);
+ return;
+ }
+ if (_remove_node(p_vscene->root_nodes[i], p_node)) {
+ return;
+ }
+ }
+
+ ERR_PRINT("ERROR: Not found node to remove?");
+}
+
+void Collada::_merge_skeletons(VisualScene *p_vscene, Node *p_node) {
+ if (p_node->type == Node::TYPE_GEOMETRY) {
+ NodeGeometry *gnode = static_cast<NodeGeometry *>(p_node);
+ if (gnode->controller) {
+ // recount skeletons used
+ Set<NodeSkeleton *> skeletons;
+
+ for (int i = 0; i < gnode->skeletons.size(); i++) {
+ String nodeid = gnode->skeletons[i];
+
+ ERR_CONTINUE(!state.scene_map.has(nodeid)); //weird, it should have it...
+
+#ifdef NO_SAFE_CAST
+ NodeJoint *nj = static_cast<NodeJoint *>(state.scene_map[nodeid]);
+#else
+ NodeJoint *nj = dynamic_cast<NodeJoint *>(state.scene_map[nodeid]);
+#endif
+ ERR_CONTINUE(!nj); //broken collada
+ ERR_CONTINUE(!nj->owner); //weird, node should have a skeleton owner
+
+ skeletons.insert(nj->owner);
+ }
+
+ if (skeletons.size() > 1) {
+ //do the merger!!
+ Set<NodeSkeleton *>::Element *E = skeletons.front();
+ NodeSkeleton *base = E->get();
+
+ for (E = E->next(); E; E = E->next()) {
+ NodeSkeleton *merged = E->get();
+ _remove_node(p_vscene, merged);
+ for (int i = 0; i < merged->children.size(); i++) {
+ _joint_set_owner(merged->children[i], base);
+ base->children.push_back(merged->children[i]);
+ merged->children[i]->parent = base;
+ }
+
+ merged->children.clear(); //take children from it
+ memdelete(merged);
+ }
+ }
+ }
+ }
+
+ for (int i = 0; i < p_node->children.size(); i++) {
+ _merge_skeletons(p_vscene, p_node->children[i]);
+ }
+}
+
+void Collada::_merge_skeletons2(VisualScene *p_vscene) {
+ for (Map<String, SkinControllerData>::Element *E = state.skin_controller_data_map.front(); E; E = E->next()) {
+ SkinControllerData &cd = E->get();
+
+ NodeSkeleton *skeleton = nullptr;
+
+ for (Map<String, Transform>::Element *F = cd.bone_rest_map.front(); F; F = F->next()) {
+ String name;
+
+ if (!state.sid_to_node_map.has(F->key())) {
+ continue;
+ }
+
+ name = state.sid_to_node_map[F->key()];
+
+ ERR_CONTINUE(!state.scene_map.has(name));
+
+ Node *node = state.scene_map[name];
+ ERR_CONTINUE(node->type != Node::TYPE_JOINT);
+
+ NodeSkeleton *sk = nullptr;
+
+ while (node && !sk) {
+ if (node->type == Node::TYPE_SKELETON) {
+ sk = static_cast<NodeSkeleton *>(node);
+ }
+ node = node->parent;
+ }
+
+ ERR_CONTINUE(!sk);
+
+ if (!skeleton) {
+ skeleton = sk;
+ continue;
+ }
+
+ if (skeleton != sk) {
+ //whoa.. wtf, merge.
+ _remove_node(p_vscene, sk);
+ for (int i = 0; i < sk->children.size(); i++) {
+ _joint_set_owner(sk->children[i], skeleton);
+ skeleton->children.push_back(sk->children[i]);
+ sk->children[i]->parent = skeleton;
+ }
+
+ sk->children.clear(); //take children from it
+ memdelete(sk);
+ }
+ }
+ }
+}
+
+bool Collada::_optimize_skeletons(VisualScene *p_vscene, Node *p_node) {
+ Node *node = p_node;
+
+ if (node->type == Node::TYPE_SKELETON && node->parent && node->parent->type == Node::TYPE_NODE && node->parent->children.size() == 1) {
+ //replace parent by this...
+ Node *parent = node->parent;
+
+ //i wonder if this is alright.. i think it is since created skeleton (first joint) is already animated by bone..
+ node->id = parent->id;
+ node->name = parent->name;
+ node->xform_list = parent->xform_list;
+ node->default_transform = parent->default_transform;
+
+ state.scene_map[node->id] = node;
+ node->parent = parent->parent;
+
+ if (parent->parent) {
+ Node *gp = parent->parent;
+ bool found = false;
+ for (int i = 0; i < gp->children.size(); i++) {
+ if (gp->children[i] == parent) {
+ gp->children.write[i] = node;
+ found = true;
+ break;
+ }
+ }
+ if (!found) {
+ ERR_PRINT("BUG");
+ }
+ } else {
+ bool found = false;
+
+ for (int i = 0; i < p_vscene->root_nodes.size(); i++) {
+ if (p_vscene->root_nodes[i] == parent) {
+ p_vscene->root_nodes.write[i] = node;
+ found = true;
+ break;
+ }
+ }
+ if (!found) {
+ ERR_PRINT("BUG");
+ }
+ }
+
+ parent->children.clear();
+ memdelete(parent);
+ return true;
+ }
+
+ for (int i = 0; i < node->children.size(); i++) {
+ if (_optimize_skeletons(p_vscene, node->children[i])) {
+ return false; //stop processing, go up
+ }
+ }
+
+ return false;
+}
+
+bool Collada::_move_geometry_to_skeletons(VisualScene *p_vscene, Node *p_node, List<Node *> *p_mgeom) {
+ // Bind Shape Matrix scales the bones and makes them gigantic, so the matrix then shrinks the model?
+ // Solution: apply the Bind Shape Matrix to the VERTICES, and if the object comes scaled, it seems to be left alone!
+
+ if (p_node->type == Node::TYPE_GEOMETRY) {
+ NodeGeometry *ng = static_cast<NodeGeometry *>(p_node);
+ if (ng->ignore_anim) {
+ return false; //already made child of skeleton and processeg
+ }
+
+ if (ng->controller && ng->skeletons.size()) {
+ String nodeid = ng->skeletons[0];
+
+ ERR_FAIL_COND_V(!state.scene_map.has(nodeid), false); //weird, it should have it...
+#ifdef NO_SAFE_CAST
+ NodeJoint *nj = static_cast<NodeJoint *>(state.scene_map[nodeid]);
+#else
+ NodeJoint *nj = dynamic_cast<NodeJoint *>(state.scene_map[nodeid]);
+#endif
+ ERR_FAIL_COND_V(!nj, false);
+ ERR_FAIL_COND_V(!nj->owner, false); //weird, node should have a skeleton owner
+
+ NodeSkeleton *sk = nj->owner;
+
+ Node *p = sk->parent;
+ bool node_is_parent_of_skeleton = false;
+
+ while (p) {
+ if (p == p_node) {
+ node_is_parent_of_skeleton = true;
+ break;
+ }
+ p = p->parent; // try again
+ }
+
+ ERR_FAIL_COND_V(node_is_parent_of_skeleton, false);
+
+ //this should be correct
+ ERR_FAIL_COND_V(!state.skin_controller_data_map.has(ng->source), false);
+ SkinControllerData &skin = state.skin_controller_data_map[ng->source];
+ Transform skel_inv = sk->get_global_transform().affine_inverse();
+ p_node->default_transform = skel_inv * (skin.bind_shape /* p_node->get_global_transform()*/); // i honestly have no idea what to do with a previous model xform.. most exporters ignore it
+
+ //make rests relative to the skeleton (they seem to be always relative to world)
+ for (Map<String, Transform>::Element *E = skin.bone_rest_map.front(); E; E = E->next()) {
+ E->get() = skel_inv * E->get(); //make the bone rest local to the skeleton
+ state.bone_rest_map[E->key()] = E->get(); // make it remember where the bone is globally, now that it's relative
+ }
+
+ //but most exporters seem to work only if i do this..
+ //p_node->default_transform = p_node->get_global_transform();
+
+ //p_node->default_transform=Transform(); //this seems to be correct, because bind shape makes the object local to the skeleton
+ p_node->ignore_anim = true; // collada may animate this later, if it does, then this is not supported (redo your original asset and don't animate the base mesh)
+ p_node->parent = sk;
+ //sk->children.push_back(0,p_node); //avoid INFINITE loop
+ p_mgeom->push_back(p_node);
+ return true;
+ }
+ }
+
+ for (int i = 0; i < p_node->children.size(); i++) {
+ if (_move_geometry_to_skeletons(p_vscene, p_node->children[i], p_mgeom)) {
+ p_node->children.remove(i);
+ i--;
+ }
+ }
+
+ return false;
+}
+
+void Collada::_find_morph_nodes(VisualScene *p_vscene, Node *p_node) {
+ if (p_node->type == Node::TYPE_GEOMETRY) {
+ NodeGeometry *nj = static_cast<NodeGeometry *>(p_node);
+
+ if (nj->controller) {
+ String base = nj->source;
+
+ while (base != "" && !state.mesh_data_map.has(base)) {
+ if (state.skin_controller_data_map.has(base)) {
+ SkinControllerData &sk = state.skin_controller_data_map[base];
+ base = sk.base;
+ } else if (state.morph_controller_data_map.has(base)) {
+ state.morph_ownership_map[base] = nj->id;
+ break;
+ } else {
+ ERR_FAIL_MSG("Invalid scene.");
+ }
+ }
+ }
+ }
+
+ for (int i = 0; i < p_node->children.size(); i++) {
+ _find_morph_nodes(p_vscene, p_node->children[i]);
+ }
+}
+
+void Collada::_optimize() {
+ for (Map<String, VisualScene>::Element *E = state.visual_scene_map.front(); E; E = E->next()) {
+ VisualScene &vs = E->get();
+ for (int i = 0; i < vs.root_nodes.size(); i++) {
+ _create_skeletons(&vs.root_nodes.write[i]);
+ }
+
+ for (int i = 0; i < vs.root_nodes.size(); i++) {
+ _merge_skeletons(&vs, vs.root_nodes[i]);
+ }
+
+ _merge_skeletons2(&vs);
+
+ for (int i = 0; i < vs.root_nodes.size(); i++) {
+ _optimize_skeletons(&vs, vs.root_nodes[i]);
+ }
+
+ for (int i = 0; i < vs.root_nodes.size(); i++) {
+ List<Node *> mgeom;
+ if (_move_geometry_to_skeletons(&vs, vs.root_nodes[i], &mgeom)) {
+ vs.root_nodes.remove(i);
+ i--;
+ }
+
+ while (!mgeom.empty()) {
+ Node *n = mgeom.front()->get();
+ n->parent->children.push_back(n);
+ mgeom.pop_front();
+ }
+ }
+
+ for (int i = 0; i < vs.root_nodes.size(); i++) {
+ _find_morph_nodes(&vs, vs.root_nodes[i]);
+ }
+ }
+}
+
+int Collada::get_uv_channel(String p_name) {
+ if (!channel_map.has(p_name)) {
+ ERR_FAIL_COND_V(channel_map.size() == 2, 0);
+
+ channel_map[p_name] = channel_map.size();
+ }
+
+ return channel_map[p_name];
+}
+
+Error Collada::load(const String &p_path, int p_flags) {
+ Ref<XMLParser> parserr = memnew(XMLParser);
+ XMLParser &parser = *parserr.ptr();
+ Error err = parser.open(p_path);
+ ERR_FAIL_COND_V_MSG(err, err, "Cannot open Collada file '" + p_path + "'.");
+
+ state.local_path = ProjectSettings::get_singleton()->localize_path(p_path);
+ state.import_flags = p_flags;
+ /* Skip headers */
+ while ((err = parser.read()) == OK) {
+ if (parser.get_node_type() == XMLParser::NODE_ELEMENT) {
+ if (parser.get_node_name() == "COLLADA") {
+ break;
+ } else if (!parser.is_empty()) {
+ parser.skip_section(); // unknown section, likely headers
+ }
+ }
+ }
+
+ ERR_FAIL_COND_V_MSG(err != OK, ERR_FILE_CORRUPT, "Corrupted Collada file '" + p_path + "'.");
+
+ /* Start loading Collada */
+
+ {
+ //version
+ String version = parser.get_attribute_value("version");
+ state.version.major = version.get_slice(".", 0).to_int();
+ state.version.minor = version.get_slice(".", 1).to_int();
+ state.version.rev = version.get_slice(".", 2).to_int();
+ COLLADA_PRINT("Collada VERSION: " + version);
+ }
+
+ while ((err = parser.read()) == OK) {
+ /* Read all the main sections.. */
+
+ if (parser.get_node_type() != XMLParser::NODE_ELEMENT) {
+ continue; //no idea what this may be, but skipping anyway
+ }
+
+ String section = parser.get_node_name();
+
+ COLLADA_PRINT("section: " + section);
+
+ if (section == "asset") {
+ _parse_asset(parser);
+
+ } else if (section.begins_with("library_")) {
+ _parse_library(parser);
+ } else if (section == "scene") {
+ _parse_scene(parser);
+ } else if (!parser.is_empty()) {
+ parser.skip_section(); // unknown section, likely headers
+ }
+ }
+
+ _optimize();
+ return OK;
+}
+
+Collada::Collada() {
+}
diff --git a/editor/import/collada.h b/editor/import/collada.h
new file mode 100644
index 0000000000..90c6c47e0b
--- /dev/null
+++ b/editor/import/collada.h
@@ -0,0 +1,578 @@
+/*************************************************************************/
+/* collada.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef COLLADA_H
+#define COLLADA_H
+
+#include "core/io/xml_parser.h"
+#include "core/map.h"
+#include "core/project_settings.h"
+#include "scene/resources/material.h"
+
+class Collada {
+public:
+ enum ImportFlags {
+ IMPORT_FLAG_SCENE = 1,
+ IMPORT_FLAG_ANIMATION = 2
+ };
+
+ struct Image {
+ String path;
+ };
+
+ struct Material {
+ String name;
+ String instance_effect;
+ };
+
+ struct Effect {
+ String name;
+ Map<String, Variant> params;
+
+ struct Channel {
+ int uv_idx = 0;
+ String texture;
+ Color color;
+ Channel() {}
+ };
+
+ Channel diffuse, specular, emission, bump;
+ float shininess = 40;
+ bool found_double_sided = false;
+ bool double_sided = true;
+ bool unshaded = false;
+
+ String get_texture_path(const String &p_source, Collada &state) const;
+
+ Effect() {
+ diffuse.color = Color(1, 1, 1, 1);
+ }
+ };
+
+ struct CameraData {
+ enum Mode {
+ MODE_PERSPECTIVE,
+ MODE_ORTHOGONAL
+ };
+
+ Mode mode = MODE_PERSPECTIVE;
+
+ union {
+ struct {
+ float x_fov = 0;
+ float y_fov = 0;
+ } perspective;
+ struct {
+ float x_mag = 0;
+ float y_mag = 0;
+ } orthogonal;
+ };
+
+ float aspect = 1;
+ float z_near = 0.1;
+ float z_far = 100;
+
+ CameraData() {}
+ };
+
+ struct LightData {
+ enum Mode {
+ MODE_AMBIENT,
+ MODE_DIRECTIONAL,
+ MODE_OMNI,
+ MODE_SPOT
+ };
+
+ Mode mode = MODE_AMBIENT;
+
+ Color color = Color(1, 1, 1, 1);
+
+ float constant_att = 0;
+ float linear_att = 0;
+ float quad_att = 0;
+
+ float spot_angle = 45;
+ float spot_exp = 1;
+
+ LightData() {}
+ };
+
+ struct MeshData {
+ String name;
+ struct Source {
+ Vector<float> array;
+ int stride;
+ };
+
+ Map<String, Source> sources;
+
+ struct Vertices {
+ Map<String, String> sources;
+ };
+
+ Map<String, Vertices> vertices;
+
+ struct Primitives {
+ struct SourceRef {
+ String source;
+ int offset;
+ };
+
+ String material;
+ Map<String, SourceRef> sources;
+ Vector<float> polygons;
+ Vector<float> indices;
+ int count;
+ int vertex_size;
+ };
+
+ Vector<Primitives> primitives;
+
+ bool found_double_sided = false;
+ bool double_sided = true;
+
+ MeshData() {}
+ };
+
+ struct CurveData {
+ String name;
+ bool closed = false;
+
+ struct Source {
+ Vector<String> sarray;
+ Vector<float> array;
+ int stride;
+ };
+
+ Map<String, Source> sources;
+
+ Map<String, String> control_vertices;
+
+ CurveData() {}
+ };
+
+ struct SkinControllerData {
+ String base;
+ bool use_idrefs = false;
+
+ Transform bind_shape;
+
+ struct Source {
+ Vector<String> sarray; //maybe for names
+ Vector<float> array;
+ int stride = 1;
+ Source() {}
+ };
+
+ Map<String, Source> sources;
+
+ struct Joints {
+ Map<String, String> sources;
+ } joints;
+
+ struct Weights {
+ struct SourceRef {
+ String source;
+ int offset;
+ };
+
+ String material;
+ Map<String, SourceRef> sources;
+ Vector<float> sets;
+ Vector<float> indices;
+ int count;
+ } weights;
+
+ Map<String, Transform> bone_rest_map;
+
+ SkinControllerData() {}
+ };
+
+ struct MorphControllerData {
+ String mesh;
+ String mode;
+
+ struct Source {
+ int stride = 1;
+ Vector<String> sarray; //maybe for names
+ Vector<float> array;
+ Source() {}
+ };
+
+ Map<String, Source> sources;
+
+ Map<String, String> targets;
+ MorphControllerData() {}
+ };
+
+ struct Vertex {
+ int idx = 0;
+ Vector3 vertex;
+ Vector3 normal;
+ Vector3 uv;
+ Vector3 uv2;
+ Plane tangent;
+ Color color;
+ int uid = 0;
+ struct Weight {
+ int bone_idx;
+ float weight;
+ bool operator<(const Weight w) const { return weight > w.weight; } //heaviest first
+ };
+
+ Vector<Weight> weights;
+
+ void fix_weights() {
+ weights.sort();
+ if (weights.size() > 4) {
+ //cap to 4 and make weights add up 1
+ weights.resize(4);
+ float total = 0;
+ for (int i = 0; i < 4; i++) {
+ total += weights[i].weight;
+ }
+ if (total) {
+ for (int i = 0; i < 4; i++) {
+ weights.write[i].weight /= total;
+ }
+ }
+ }
+ }
+
+ void fix_unit_scale(Collada &state);
+
+ bool operator<(const Vertex &p_vert) const {
+ if (uid == p_vert.uid) {
+ if (vertex == p_vert.vertex) {
+ if (normal == p_vert.normal) {
+ if (uv == p_vert.uv) {
+ if (uv2 == p_vert.uv2) {
+ if (!weights.empty() || !p_vert.weights.empty()) {
+ if (weights.size() == p_vert.weights.size()) {
+ for (int i = 0; i < weights.size(); i++) {
+ if (weights[i].bone_idx != p_vert.weights[i].bone_idx) {
+ return weights[i].bone_idx < p_vert.weights[i].bone_idx;
+ }
+
+ if (weights[i].weight != p_vert.weights[i].weight) {
+ return weights[i].weight < p_vert.weights[i].weight;
+ }
+ }
+ } else {
+ return weights.size() < p_vert.weights.size();
+ }
+ }
+
+ return (color < p_vert.color);
+ } else {
+ return (uv2 < p_vert.uv2);
+ }
+ } else {
+ return (uv < p_vert.uv);
+ }
+ } else {
+ return (normal < p_vert.normal);
+ }
+ } else {
+ return vertex < p_vert.vertex;
+ }
+ } else {
+ return uid < p_vert.uid;
+ }
+ }
+
+ Vertex() {}
+ };
+
+ struct Node {
+ enum Type {
+
+ TYPE_NODE,
+ TYPE_JOINT,
+ TYPE_SKELETON, //this bone is not collada, it's added afterwards as optimization
+ TYPE_LIGHT,
+ TYPE_CAMERA,
+ TYPE_GEOMETRY
+ };
+
+ struct XForm {
+ enum Op {
+ OP_ROTATE,
+ OP_SCALE,
+ OP_TRANSLATE,
+ OP_MATRIX,
+ OP_VISIBILITY
+ };
+
+ String id;
+ Op op;
+ Vector<float> data;
+ };
+
+ Type type = TYPE_NODE;
+
+ String name;
+ String id;
+ String empty_draw_type;
+ bool noname = false;
+ Vector<XForm> xform_list;
+ Transform default_transform;
+ Transform post_transform;
+ Vector<Node *> children;
+
+ Node *parent = nullptr;
+
+ Transform compute_transform(Collada &state) const;
+ Transform get_global_transform() const;
+ Transform get_transform() const;
+
+ bool ignore_anim = false;
+
+ Node() {}
+ virtual ~Node() {
+ for (int i = 0; i < children.size(); i++) {
+ memdelete(children[i]);
+ }
+ };
+ };
+
+ struct NodeSkeleton : public Node {
+ NodeSkeleton() { type = TYPE_SKELETON; }
+ };
+
+ struct NodeJoint : public Node {
+ NodeSkeleton *owner = nullptr;
+ String sid;
+ NodeJoint() {
+ type = TYPE_JOINT;
+ }
+ };
+
+ struct NodeGeometry : public Node {
+ bool controller;
+ String source;
+
+ struct Material {
+ String target;
+ };
+
+ Map<String, Material> material_map;
+ Vector<String> skeletons;
+
+ NodeGeometry() { type = TYPE_GEOMETRY; }
+ };
+
+ struct NodeCamera : public Node {
+ String camera;
+
+ NodeCamera() { type = TYPE_CAMERA; }
+ };
+
+ struct NodeLight : public Node {
+ String light;
+
+ NodeLight() { type = TYPE_LIGHT; }
+ };
+
+ struct VisualScene {
+ String name;
+ Vector<Node *> root_nodes;
+
+ ~VisualScene() {
+ for (int i = 0; i < root_nodes.size(); i++) {
+ memdelete(root_nodes[i]);
+ }
+ }
+ };
+
+ struct AnimationClip {
+ String name;
+ float begin = 0;
+ float end = 1;
+ Vector<String> tracks;
+
+ AnimationClip() {}
+ };
+
+ struct AnimationTrack {
+ String id;
+ String target;
+ String param;
+ String component;
+ bool property = false;
+
+ enum InterpolationType {
+ INTERP_LINEAR,
+ INTERP_BEZIER
+ };
+
+ struct Key {
+ enum Type {
+ TYPE_FLOAT,
+ TYPE_MATRIX
+ };
+
+ float time;
+ Vector<float> data;
+ Point2 in_tangent;
+ Point2 out_tangent;
+ InterpolationType interp_type = INTERP_LINEAR;
+
+ Key() {}
+ };
+
+ Vector<float> get_value_at_time(float p_time) const;
+
+ Vector<Key> keys;
+
+ AnimationTrack() {}
+ };
+
+ /****************/
+ /* IMPORT STATE */
+ /****************/
+
+ struct State {
+ int import_flags = 0;
+
+ float unit_scale = 1.0;
+ Vector3::Axis up_axis = Vector3::AXIS_Y;
+ bool z_up;
+
+ struct Version {
+ int major, minor, rev;
+
+ bool operator<(const Version &p_ver) const { return (major == p_ver.major) ? ((minor == p_ver.minor) ? (rev < p_ver.rev) : minor < p_ver.minor) : major < p_ver.major; }
+ Version(int p_major = 0, int p_minor = 0, int p_rev = 0) {
+ major = p_major;
+ minor = p_minor;
+ rev = p_rev;
+ }
+ } version;
+
+ Map<String, CameraData> camera_data_map;
+ Map<String, MeshData> mesh_data_map;
+ Map<String, LightData> light_data_map;
+ Map<String, CurveData> curve_data_map;
+
+ Map<String, String> mesh_name_map;
+ Map<String, String> morph_name_map;
+ Map<String, String> morph_ownership_map;
+ Map<String, SkinControllerData> skin_controller_data_map;
+ Map<String, MorphControllerData> morph_controller_data_map;
+
+ Map<String, Image> image_map;
+ Map<String, Material> material_map;
+ Map<String, Effect> effect_map;
+
+ Map<String, VisualScene> visual_scene_map;
+ Map<String, Node *> scene_map;
+ Set<String> idref_joints;
+ Map<String, String> sid_to_node_map;
+ //Map<String,NodeJoint*> bone_map;
+
+ Map<String, Transform> bone_rest_map;
+
+ String local_path;
+ String root_visual_scene;
+ String root_physics_scene;
+
+ Vector<AnimationClip> animation_clips;
+ Vector<AnimationTrack> animation_tracks;
+ Map<String, Vector<int>> referenced_tracks;
+ Map<String, Vector<int>> by_id_tracks;
+
+ float animation_length = 0;
+
+ State() {}
+ } state;
+
+ Error load(const String &p_path, int p_flags = 0);
+
+ Collada();
+
+ Transform fix_transform(const Transform &p_transform);
+
+ Transform get_root_transform() const;
+
+ int get_uv_channel(String p_name);
+
+private: // private stuff
+ Map<String, int> channel_map;
+
+ void _parse_asset(XMLParser &parser);
+ void _parse_image(XMLParser &parser);
+ void _parse_material(XMLParser &parser);
+ void _parse_effect_material(XMLParser &parser, Effect &effect, String &id);
+ void _parse_effect(XMLParser &parser);
+ void _parse_camera(XMLParser &parser);
+ void _parse_light(XMLParser &parser);
+ void _parse_animation_clip(XMLParser &parser);
+
+ void _parse_mesh_geometry(XMLParser &parser, String p_id, String p_name);
+ void _parse_curve_geometry(XMLParser &parser, String p_id, String p_name);
+
+ void _parse_skin_controller(XMLParser &parser, String p_id);
+ void _parse_morph_controller(XMLParser &parser, String p_id);
+ void _parse_controller(XMLParser &parser);
+
+ Node *_parse_visual_instance_geometry(XMLParser &parser);
+ Node *_parse_visual_instance_camera(XMLParser &parser);
+ Node *_parse_visual_instance_light(XMLParser &parser);
+
+ Node *_parse_visual_node_instance_data(XMLParser &parser);
+ Node *_parse_visual_scene_node(XMLParser &parser);
+ void _parse_visual_scene(XMLParser &parser);
+
+ void _parse_animation(XMLParser &parser);
+ void _parse_scene(XMLParser &parser);
+ void _parse_library(XMLParser &parser);
+
+ Variant _parse_param(XMLParser &parser);
+ Vector<float> _read_float_array(XMLParser &parser);
+ Vector<String> _read_string_array(XMLParser &parser);
+ Transform _read_transform(XMLParser &parser);
+ String _read_empty_draw_type(XMLParser &parser);
+
+ void _joint_set_owner(Collada::Node *p_node, NodeSkeleton *p_owner);
+ void _create_skeletons(Collada::Node **p_node, NodeSkeleton *p_skeleton = nullptr);
+ void _find_morph_nodes(VisualScene *p_vscene, Node *p_node);
+ bool _remove_node(Node *p_parent, Node *p_node);
+ void _remove_node(VisualScene *p_vscene, Node *p_node);
+ void _merge_skeletons2(VisualScene *p_vscene);
+ void _merge_skeletons(VisualScene *p_vscene, Node *p_node);
+ bool _optimize_skeletons(VisualScene *p_vscene, Node *p_node);
+
+ bool _move_geometry_to_skeletons(VisualScene *p_vscene, Node *p_node, List<Node *> *p_mgeom);
+
+ void _optimize();
+};
+
+#endif // COLLADA_H
diff --git a/editor/import/editor_import_collada.cpp b/editor/import/editor_import_collada.cpp
index d604a95320..12cbaaa885 100644
--- a/editor/import/editor_import_collada.cpp
+++ b/editor/import/editor_import_collada.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -31,34 +31,33 @@
#include "editor_import_collada.h"
#include "core/os/os.h"
-#include "editor/collada/collada.h"
#include "editor/editor_node.h"
-#include "scene/3d/camera.h"
-#include "scene/3d/light.h"
-#include "scene/3d/mesh_instance.h"
-#include "scene/3d/path.h"
-#include "scene/3d/skeleton.h"
-#include "scene/3d/spatial.h"
+#include "editor/import/collada.h"
+#include "scene/3d/camera_3d.h"
+#include "scene/3d/light_3d.h"
+#include "scene/3d/mesh_instance_3d.h"
+#include "scene/3d/node_3d.h"
+#include "scene/3d/path_3d.h"
+#include "scene/3d/skeleton_3d.h"
#include "scene/animation/animation_player.h"
#include "scene/resources/animation.h"
#include "scene/resources/packed_scene.h"
#include "scene/resources/surface_tool.h"
struct ColladaImport {
-
Collada collada;
- Spatial *scene;
+ Node3D *scene;
- Vector<Ref<Animation> > animations;
+ Vector<Ref<Animation>> animations;
struct NodeMap {
//String path;
- Spatial *node;
+ Node3D *node;
int bone;
List<int> anim_tracks;
NodeMap() {
- node = NULL;
+ node = nullptr;
bone = -1;
}
};
@@ -73,23 +72,23 @@ struct ColladaImport {
Map<String, NodeMap> node_map; //map from collada node to engine node
Map<String, String> node_name_map; //map from collada node to engine node
- Map<String, Ref<ArrayMesh> > mesh_cache;
- Map<String, Ref<Curve3D> > curve_cache;
- Map<String, Ref<Material> > material_cache;
- Map<Collada::Node *, Skeleton *> skeleton_map;
+ Map<String, Ref<ArrayMesh>> mesh_cache;
+ Map<String, Ref<Curve3D>> curve_cache;
+ Map<String, Ref<Material>> material_cache;
+ Map<Collada::Node *, Skeleton3D *> skeleton_map;
- Map<Skeleton *, Map<String, int> > skeleton_bone_map;
+ Map<Skeleton3D *, Map<String, int>> skeleton_bone_map;
Set<String> valid_animated_nodes;
Vector<int> valid_animated_properties;
Map<String, bool> bones_with_animation;
- Error _populate_skeleton(Skeleton *p_skeleton, Collada::Node *p_node, int &r_bone, int p_parent);
+ Error _populate_skeleton(Skeleton3D *p_skeleton, Collada::Node *p_node, int &r_bone, int p_parent);
Error _create_scene_skeletons(Collada::Node *p_node);
- Error _create_scene(Collada::Node *p_node, Spatial *p_parent);
+ Error _create_scene(Collada::Node *p_node, Node3D *p_parent);
Error _create_resources(Collada::Node *p_node, bool p_use_compression);
Error _create_material(const String &p_target);
- Error _create_mesh_surfaces(bool p_optimize, Ref<ArrayMesh> &p_mesh, const Map<String, Collada::NodeGeometry::Material> &p_material_map, const Collada::MeshData &meshdata, const Transform &p_local_xform, const Vector<int> &bone_remap, const Collada::SkinControllerData *p_skin_controller, const Collada::MorphControllerData *p_morph_data, Vector<Ref<ArrayMesh> > p_morph_meshes = Vector<Ref<ArrayMesh> >(), bool p_use_compression = false, bool p_use_mesh_material = false);
+ Error _create_mesh_surfaces(bool p_optimize, Ref<ArrayMesh> &p_mesh, const Map<String, Collada::NodeGeometry::Material> &p_material_map, const Collada::MeshData &meshdata, const Transform &p_local_xform, const Vector<int> &bone_remap, const Collada::SkinControllerData *p_skin_controller, const Collada::MorphControllerData *p_morph_data, Vector<Ref<ArrayMesh>> p_morph_meshes = Vector<Ref<ArrayMesh>>(), bool p_use_compression = false, bool p_use_mesh_material = false);
Error load(const String &p_path, int p_flags, bool p_force_make_tangents = false, bool p_use_compression = false);
void _fix_param_animation_tracks();
void create_animation(int p_clip, bool p_make_tracks_in_all_bones, bool p_import_value_tracks);
@@ -101,7 +100,6 @@ struct ColladaImport {
void _pre_process_lights(Collada::Node *p_node);
ColladaImport() {
-
found_ambient = false;
found_directional = false;
force_make_tangents = false;
@@ -110,16 +108,17 @@ struct ColladaImport {
}
};
-Error ColladaImport::_populate_skeleton(Skeleton *p_skeleton, Collada::Node *p_node, int &r_bone, int p_parent) {
-
- if (p_node->type != Collada::Node::TYPE_JOINT)
+Error ColladaImport::_populate_skeleton(Skeleton3D *p_skeleton, Collada::Node *p_node, int &r_bone, int p_parent) {
+ if (p_node->type != Collada::Node::TYPE_JOINT) {
return OK;
+ }
Collada::NodeJoint *joint = static_cast<Collada::NodeJoint *>(p_node);
p_skeleton->add_bone(p_node->name);
- if (p_parent >= 0)
+ if (p_parent >= 0) {
p_skeleton->set_bone_parent(r_bone, p_parent);
+ }
NodeMap nm;
nm.node = p_skeleton;
@@ -130,7 +129,6 @@ Error ColladaImport::_populate_skeleton(Skeleton *p_skeleton, Collada::Node *p_n
skeleton_bone_map[p_skeleton][joint->sid] = r_bone;
if (collada.state.bone_rest_map.has(joint->sid)) {
-
p_skeleton->set_bone_rest(r_bone, collada.fix_transform(collada.state.bone_rest_map[joint->sid]));
//should map this bone to something for animation?
} else {
@@ -139,22 +137,19 @@ Error ColladaImport::_populate_skeleton(Skeleton *p_skeleton, Collada::Node *p_n
int id = r_bone++;
for (int i = 0; i < p_node->children.size(); i++) {
-
Error err = _populate_skeleton(p_skeleton, p_node->children[i], r_bone, id);
- if (err)
+ if (err) {
return err;
+ }
}
return OK;
}
void ColladaImport::_pre_process_lights(Collada::Node *p_node) {
-
if (p_node->type == Collada::Node::TYPE_LIGHT) {
-
Collada::NodeLight *light = static_cast<Collada::NodeLight *>(p_node);
if (collada.state.light_data_map.has(light->light)) {
-
Collada::LightData &ld = collada.state.light_data_map[light->light];
if (ld.mode == Collada::LightData::MODE_AMBIENT) {
found_ambient = true;
@@ -166,18 +161,16 @@ void ColladaImport::_pre_process_lights(Collada::Node *p_node) {
}
}
- for (int i = 0; i < p_node->children.size(); i++)
+ for (int i = 0; i < p_node->children.size(); i++) {
_pre_process_lights(p_node->children[i]);
+ }
}
Error ColladaImport::_create_scene_skeletons(Collada::Node *p_node) {
-
if (p_node->type == Collada::Node::TYPE_SKELETON) {
-
- Skeleton *sk = memnew(Skeleton);
+ Skeleton3D *sk = memnew(Skeleton3D);
int bone = 0;
for (int i = 0; i < p_node->children.size(); i++) {
-
_populate_skeleton(sk, p_node->children[i], bone, -1);
}
sk->localize_rests(); //after creating skeleton, rests must be localized...!
@@ -185,54 +178,48 @@ Error ColladaImport::_create_scene_skeletons(Collada::Node *p_node) {
}
for (int i = 0; i < p_node->children.size(); i++) {
-
Error err = _create_scene_skeletons(p_node->children[i]);
- if (err)
+ if (err) {
return err;
+ }
}
return OK;
}
-Error ColladaImport::_create_scene(Collada::Node *p_node, Spatial *p_parent) {
-
- Spatial *node = NULL;
+Error ColladaImport::_create_scene(Collada::Node *p_node, Node3D *p_parent) {
+ Node3D *node = nullptr;
switch (p_node->type) {
-
case Collada::Node::TYPE_NODE: {
-
- node = memnew(Spatial);
+ node = memnew(Node3D);
} break;
case Collada::Node::TYPE_JOINT: {
-
return OK; // do nothing
} break;
case Collada::Node::TYPE_LIGHT: {
-
//node = memnew( Light)
Collada::NodeLight *light = static_cast<Collada::NodeLight *>(p_node);
if (collada.state.light_data_map.has(light->light)) {
-
Collada::LightData &ld = collada.state.light_data_map[light->light];
if (ld.mode == Collada::LightData::MODE_AMBIENT) {
-
- if (found_directional)
+ if (found_directional) {
return OK; //do nothing not needed
+ }
- if (!bool(GLOBAL_DEF("collada/use_ambient", false)))
+ if (!bool(GLOBAL_DEF("collada/use_ambient", false))) {
return OK;
+ }
//well, it's an ambient light..
- Light *l = memnew(DirectionalLight);
+ Light3D *l = memnew(DirectionalLight3D);
//l->set_color(Light::COLOR_AMBIENT,ld.color);
//l->set_color(Light::COLOR_DIFFUSE,Color(0,0,0));
//l->set_color(Light::COLOR_SPECULAR,Color(0,0,0));
node = l;
} else if (ld.mode == Collada::LightData::MODE_DIRECTIONAL) {
-
//well, it's an ambient light..
- Light *l = memnew(DirectionalLight);
+ Light3D *l = memnew(DirectionalLight3D);
/*
if (found_ambient) //use it here
l->set_color(Light::COLOR_AMBIENT,ambient);
@@ -242,13 +229,12 @@ Error ColladaImport::_create_scene(Collada::Node *p_node, Spatial *p_parent) {
*/
node = l;
} else {
+ Light3D *l;
- Light *l;
-
- if (ld.mode == Collada::LightData::MODE_OMNI)
- l = memnew(OmniLight);
- else {
- l = memnew(SpotLight);
+ if (ld.mode == Collada::LightData::MODE_OMNI) {
+ l = memnew(OmniLight3D);
+ } else {
+ l = memnew(SpotLight3D);
//l->set_parameter(Light::PARAM_SPOT_ANGLE,ld.spot_angle);
//l->set_parameter(Light::PARAM_SPOT_ATTENUATION,ld.spot_exp);
}
@@ -261,43 +247,33 @@ Error ColladaImport::_create_scene(Collada::Node *p_node, Spatial *p_parent) {
}
} else {
-
- node = memnew(Spatial);
+ node = memnew(Node3D);
}
} break;
case Collada::Node::TYPE_CAMERA: {
-
Collada::NodeCamera *cam = static_cast<Collada::NodeCamera *>(p_node);
- Camera *camera = memnew(Camera);
+ Camera3D *camera = memnew(Camera3D);
if (collada.state.camera_data_map.has(cam->camera)) {
-
const Collada::CameraData &cd = collada.state.camera_data_map[cam->camera];
switch (cd.mode) {
-
case Collada::CameraData::MODE_ORTHOGONAL: {
-
if (cd.orthogonal.y_mag) {
-
- camera->set_keep_aspect_mode(Camera::KEEP_HEIGHT);
+ camera->set_keep_aspect_mode(Camera3D::KEEP_HEIGHT);
camera->set_orthogonal(cd.orthogonal.y_mag * 2.0, cd.z_near, cd.z_far);
} else if (!cd.orthogonal.y_mag && cd.orthogonal.x_mag) {
-
- camera->set_keep_aspect_mode(Camera::KEEP_WIDTH);
+ camera->set_keep_aspect_mode(Camera3D::KEEP_WIDTH);
camera->set_orthogonal(cd.orthogonal.x_mag * 2.0, cd.z_near, cd.z_far);
}
} break;
case Collada::CameraData::MODE_PERSPECTIVE: {
-
if (cd.perspective.y_fov) {
-
camera->set_perspective(cd.perspective.y_fov, cd.z_near, cd.z_far);
} else if (!cd.perspective.y_fov && cd.perspective.x_fov) {
-
camera->set_perspective(cd.perspective.x_fov / cd.aspect, cd.z_near, cd.z_far);
}
@@ -309,28 +285,26 @@ Error ColladaImport::_create_scene(Collada::Node *p_node, Spatial *p_parent) {
} break;
case Collada::Node::TYPE_GEOMETRY: {
-
Collada::NodeGeometry *ng = static_cast<Collada::NodeGeometry *>(p_node);
if (collada.state.curve_data_map.has(ng->source)) {
-
- node = memnew(Path);
+ node = memnew(Path3D);
} else {
//mesh since nothing else
- node = memnew(MeshInstance);
- //Object::cast_to<MeshInstance>(node)->set_flag(GeometryInstance::FLAG_USE_BAKED_LIGHT, true);
+ node = memnew(MeshInstance3D);
+ //Object::cast_to<MeshInstance3D>(node)->set_flag(GeometryInstance3D::FLAG_USE_BAKED_LIGHT, true);
}
} break;
case Collada::Node::TYPE_SKELETON: {
-
ERR_FAIL_COND_V(!skeleton_map.has(p_node), ERR_CANT_CREATE);
- Skeleton *sk = skeleton_map[p_node];
+ Skeleton3D *sk = skeleton_map[p_node];
node = sk;
} break;
}
- if (p_node->name != "")
+ if (p_node->name != "") {
node->set_name(p_node->name);
+ }
NodeMap nm;
nm.node = node;
node_map[p_node->id] = nm;
@@ -347,45 +321,42 @@ Error ColladaImport::_create_scene(Collada::Node *p_node, Spatial *p_parent) {
}
for (int i = 0; i < p_node->children.size(); i++) {
-
Error err = _create_scene(p_node->children[i], node);
- if (err)
+ if (err) {
return err;
+ }
}
return OK;
}
Error ColladaImport::_create_material(const String &p_target) {
-
ERR_FAIL_COND_V(material_cache.has(p_target), ERR_ALREADY_EXISTS);
ERR_FAIL_COND_V(!collada.state.material_map.has(p_target), ERR_INVALID_PARAMETER);
Collada::Material &src_mat = collada.state.material_map[p_target];
ERR_FAIL_COND_V(!collada.state.effect_map.has(src_mat.instance_effect), ERR_INVALID_PARAMETER);
Collada::Effect &effect = collada.state.effect_map[src_mat.instance_effect];
- Ref<SpatialMaterial> material = memnew(SpatialMaterial);
+ Ref<StandardMaterial3D> material = memnew(StandardMaterial3D);
- if (src_mat.name != "")
+ if (src_mat.name != "") {
material->set_name(src_mat.name);
- else if (effect.name != "")
+ } else if (effect.name != "") {
material->set_name(effect.name);
+ }
// DIFFUSE
if (effect.diffuse.texture != "") {
-
String texfile = effect.get_texture_path(effect.diffuse.texture, collada);
if (texfile != "") {
-
if (texfile.begins_with("/")) {
texfile = texfile.replace_first("/", "res://");
}
- Ref<Texture> texture = ResourceLoader::load(texfile, "Texture");
+ Ref<Texture2D> texture = ResourceLoader::load(texfile, "Texture2D");
if (texture.is_valid()) {
-
- material->set_texture(SpatialMaterial::TEXTURE_ALBEDO, texture);
+ material->set_texture(StandardMaterial3D::TEXTURE_ALBEDO, texture);
material->set_albedo(Color(1, 1, 1, 1));
- //material->set_parameter(SpatialMaterial::PARAM_DIFFUSE,Color(1,1,1,1));
+ //material->set_parameter(StandardMaterial3D::PARAM_DIFFUSE,Color(1,1,1,1));
} else {
missing_textures.push_back(texfile.get_file());
}
@@ -397,21 +368,19 @@ Error ColladaImport::_create_material(const String &p_target) {
// SPECULAR
if (effect.specular.texture != "") {
-
String texfile = effect.get_texture_path(effect.specular.texture, collada);
if (texfile != "") {
-
if (texfile.begins_with("/")) {
texfile = texfile.replace_first("/", "res://");
}
- Ref<Texture> texture = ResourceLoader::load(texfile, "Texture");
+ Ref<Texture2D> texture = ResourceLoader::load(texfile, "Texture2D");
if (texture.is_valid()) {
- material->set_texture(SpatialMaterial::TEXTURE_METALLIC, texture);
+ material->set_texture(StandardMaterial3D::TEXTURE_METALLIC, texture);
material->set_specular(1.0);
- //material->set_texture(SpatialMaterial::PARAM_SPECULAR,texture);
- //material->set_parameter(SpatialMaterial::PARAM_SPECULAR,Color(1,1,1,1));
+ //material->set_texture(StandardMaterial3D::PARAM_SPECULAR,texture);
+ //material->set_parameter(StandardMaterial3D::PARAM_SPECULAR,Color(1,1,1,1));
} else {
missing_textures.push_back(texfile.get_file());
}
@@ -424,29 +393,26 @@ Error ColladaImport::_create_material(const String &p_target) {
// EMISSION
if (effect.emission.texture != "") {
-
String texfile = effect.get_texture_path(effect.emission.texture, collada);
if (texfile != "") {
-
if (texfile.begins_with("/")) {
texfile = texfile.replace_first("/", "res://");
}
- Ref<Texture> texture = ResourceLoader::load(texfile, "Texture");
+ Ref<Texture2D> texture = ResourceLoader::load(texfile, "Texture2D");
if (texture.is_valid()) {
-
- material->set_feature(SpatialMaterial::FEATURE_EMISSION, true);
- material->set_texture(SpatialMaterial::TEXTURE_EMISSION, texture);
+ material->set_feature(StandardMaterial3D::FEATURE_EMISSION, true);
+ material->set_texture(StandardMaterial3D::TEXTURE_EMISSION, texture);
material->set_emission(Color(1, 1, 1, 1));
- //material->set_parameter(SpatialMaterial::PARAM_EMISSION,Color(1,1,1,1));
+ //material->set_parameter(StandardMaterial3D::PARAM_EMISSION,Color(1,1,1,1));
} else {
missing_textures.push_back(texfile.get_file());
}
}
} else {
if (effect.emission.color != Color()) {
- material->set_feature(SpatialMaterial::FEATURE_EMISSION, true);
+ material->set_feature(StandardMaterial3D::FEATURE_EMISSION, true);
material->set_emission(effect.emission.color);
}
}
@@ -454,21 +420,19 @@ Error ColladaImport::_create_material(const String &p_target) {
// NORMAL
if (effect.bump.texture != "") {
-
String texfile = effect.get_texture_path(effect.bump.texture, collada);
if (texfile != "") {
-
if (texfile.begins_with("/")) {
texfile = texfile.replace_first("/", "res://");
}
- Ref<Texture> texture = ResourceLoader::load(texfile, "Texture");
+ Ref<Texture2D> texture = ResourceLoader::load(texfile, "Texture2D");
if (texture.is_valid()) {
- material->set_feature(SpatialMaterial::FEATURE_NORMAL_MAPPING, true);
- material->set_texture(SpatialMaterial::TEXTURE_NORMAL, texture);
+ material->set_feature(StandardMaterial3D::FEATURE_NORMAL_MAPPING, true);
+ material->set_texture(StandardMaterial3D::TEXTURE_NORMAL, texture);
//material->set_emission(Color(1,1,1,1));
- //material->set_texture(SpatialMaterial::PARAM_NORMAL,texture);
+ //material->set_texture(StandardMaterial3D::PARAM_NORMAL,texture);
} else {
//missing_textures.push_back(texfile.get_file());
}
@@ -479,42 +443,41 @@ Error ColladaImport::_create_material(const String &p_target) {
material->set_roughness(roughness);
if (effect.double_sided) {
- material->set_cull_mode(SpatialMaterial::CULL_DISABLED);
+ material->set_cull_mode(StandardMaterial3D::CULL_DISABLED);
+ }
+ if (effect.unshaded) {
+ material->set_shading_mode(StandardMaterial3D::SHADING_MODE_UNSHADED);
}
- material->set_flag(SpatialMaterial::FLAG_UNSHADED, effect.unshaded);
material_cache[p_target] = material;
return OK;
}
-Error ColladaImport::_create_mesh_surfaces(bool p_optimize, Ref<ArrayMesh> &p_mesh, const Map<String, Collada::NodeGeometry::Material> &p_material_map, const Collada::MeshData &meshdata, const Transform &p_local_xform, const Vector<int> &bone_remap, const Collada::SkinControllerData *p_skin_controller, const Collada::MorphControllerData *p_morph_data, Vector<Ref<ArrayMesh> > p_morph_meshes, bool p_use_compression, bool p_use_mesh_material) {
-
+Error ColladaImport::_create_mesh_surfaces(bool p_optimize, Ref<ArrayMesh> &p_mesh, const Map<String, Collada::NodeGeometry::Material> &p_material_map, const Collada::MeshData &meshdata, const Transform &p_local_xform, const Vector<int> &bone_remap, const Collada::SkinControllerData *p_skin_controller, const Collada::MorphControllerData *p_morph_data, Vector<Ref<ArrayMesh>> p_morph_meshes, bool p_use_compression, bool p_use_mesh_material) {
bool local_xform_mirror = p_local_xform.basis.determinant() < 0;
if (p_morph_data) {
-
//add morphie target
ERR_FAIL_COND_V(!p_morph_data->targets.has("MORPH_TARGET"), ERR_INVALID_DATA);
String mt = p_morph_data->targets["MORPH_TARGET"];
ERR_FAIL_COND_V(!p_morph_data->sources.has(mt), ERR_INVALID_DATA);
int morph_targets = p_morph_data->sources[mt].sarray.size();
for (int i = 0; i < morph_targets; i++) {
-
String target = p_morph_data->sources[mt].sarray[i];
ERR_FAIL_COND_V(!collada.state.mesh_data_map.has(target), ERR_INVALID_DATA);
String name = collada.state.mesh_data_map[target].name;
p_mesh->add_blend_shape(name);
}
- if (p_morph_data->mode == "RELATIVE")
+ if (p_morph_data->mode == "RELATIVE") {
p_mesh->set_blend_shape_mode(Mesh::BLEND_SHAPE_MODE_RELATIVE);
- else if (p_morph_data->mode == "NORMALIZED")
+ } else if (p_morph_data->mode == "NORMALIZED") {
p_mesh->set_blend_shape_mode(Mesh::BLEND_SHAPE_MODE_NORMALIZED);
+ }
}
int surface = 0;
for (int p_i = 0; p_i < meshdata.primitives.size(); p_i++) {
-
const Collada::MeshData::Primitives &p = meshdata.primitives[p_i];
/* VERTEX SOURCE */
@@ -534,66 +497,60 @@ Error ColladaImport::_create_mesh_surfaces(bool p_optimize, Ref<ArrayMesh> &p_me
/* NORMAL SOURCE */
- const Collada::MeshData::Source *normal_src = NULL;
+ const Collada::MeshData::Source *normal_src = nullptr;
int normal_ofs = 0;
if (p.sources.has("NORMAL")) {
-
String normal_source_id = p.sources["NORMAL"].source;
normal_ofs = p.sources["NORMAL"].offset;
ERR_FAIL_COND_V(!meshdata.sources.has(normal_source_id), ERR_INVALID_DATA);
normal_src = &meshdata.sources[normal_source_id];
}
- const Collada::MeshData::Source *binormal_src = NULL;
+ const Collada::MeshData::Source *binormal_src = nullptr;
int binormal_ofs = 0;
if (p.sources.has("TEXBINORMAL")) {
-
String binormal_source_id = p.sources["TEXBINORMAL"].source;
binormal_ofs = p.sources["TEXBINORMAL"].offset;
ERR_FAIL_COND_V(!meshdata.sources.has(binormal_source_id), ERR_INVALID_DATA);
binormal_src = &meshdata.sources[binormal_source_id];
}
- const Collada::MeshData::Source *tangent_src = NULL;
+ const Collada::MeshData::Source *tangent_src = nullptr;
int tangent_ofs = 0;
if (p.sources.has("TEXTANGENT")) {
-
String tangent_source_id = p.sources["TEXTANGENT"].source;
tangent_ofs = p.sources["TEXTANGENT"].offset;
ERR_FAIL_COND_V(!meshdata.sources.has(tangent_source_id), ERR_INVALID_DATA);
tangent_src = &meshdata.sources[tangent_source_id];
}
- const Collada::MeshData::Source *uv_src = NULL;
+ const Collada::MeshData::Source *uv_src = nullptr;
int uv_ofs = 0;
if (p.sources.has("TEXCOORD0")) {
-
String uv_source_id = p.sources["TEXCOORD0"].source;
uv_ofs = p.sources["TEXCOORD0"].offset;
ERR_FAIL_COND_V(!meshdata.sources.has(uv_source_id), ERR_INVALID_DATA);
uv_src = &meshdata.sources[uv_source_id];
}
- const Collada::MeshData::Source *uv2_src = NULL;
+ const Collada::MeshData::Source *uv2_src = nullptr;
int uv2_ofs = 0;
if (p.sources.has("TEXCOORD1")) {
-
String uv2_source_id = p.sources["TEXCOORD1"].source;
uv2_ofs = p.sources["TEXCOORD1"].offset;
ERR_FAIL_COND_V(!meshdata.sources.has(uv2_source_id), ERR_INVALID_DATA);
uv2_src = &meshdata.sources[uv2_source_id];
}
- const Collada::MeshData::Source *color_src = NULL;
+ const Collada::MeshData::Source *color_src = nullptr;
int color_ofs = 0;
if (p.sources.has("COLOR")) {
-
String color_source_id = p.sources["COLOR"].source;
color_ofs = p.sources["COLOR"].offset;
ERR_FAIL_COND_V(!meshdata.sources.has(color_source_id), ERR_INVALID_DATA);
@@ -606,21 +563,18 @@ Error ColladaImport::_create_mesh_surfaces(bool p_optimize, Ref<ArrayMesh> &p_me
/* ADD WEIGHTS IF EXIST */
/************************/
- Map<int, Vector<Collada::Vertex::Weight> > pre_weights;
+ Map<int, Vector<Collada::Vertex::Weight>> pre_weights;
bool has_weights = false;
if (p_skin_controller) {
-
- const Collada::SkinControllerData::Source *weight_src = NULL;
+ const Collada::SkinControllerData::Source *weight_src = nullptr;
int weight_ofs = 0;
if (p_skin_controller->weights.sources.has("WEIGHT")) {
-
String weight_id = p_skin_controller->weights.sources["WEIGHT"].source;
weight_ofs = p_skin_controller->weights.sources["WEIGHT"].offset;
if (p_skin_controller->sources.has(weight_id)) {
-
weight_src = &p_skin_controller->sources[weight_id];
}
}
@@ -628,7 +582,6 @@ Error ColladaImport::_create_mesh_surfaces(bool p_optimize, Ref<ArrayMesh> &p_me
int joint_ofs = 0;
if (p_skin_controller->weights.sources.has("JOINT")) {
-
joint_ofs = p_skin_controller->weights.sources["JOINT"].offset;
}
@@ -637,13 +590,11 @@ Error ColladaImport::_create_mesh_surfaces(bool p_optimize, Ref<ArrayMesh> &p_me
int index_ofs = 0;
int wstride = p_skin_controller->weights.sources.size();
for (int w_i = 0; w_i < p_skin_controller->weights.sets.size(); w_i++) {
-
int amount = p_skin_controller->weights.sets[w_i];
Vector<Collada::Vertex::Weight> weights;
for (int a_i = 0; a_i < amount; a_i++) {
-
Collada::Vertex::Weight w;
int read_from = index_ofs + a_i * wstride;
@@ -654,8 +605,9 @@ Error ColladaImport::_create_mesh_surfaces(bool p_optimize, Ref<ArrayMesh> &p_me
w.weight = weight_src->array[weight_index];
int bone_index = p_skin_controller->weights.indices[read_from + joint_ofs];
- if (bone_index == -1)
+ if (bone_index == -1) {
continue; //ignore this weight (refers to bind shape)
+ }
ERR_FAIL_INDEX_V(bone_index, bone_remap.size(), ERR_INVALID_DATA);
w.bone_idx = bone_remap[bone_index];
@@ -674,11 +626,14 @@ Error ColladaImport::_create_mesh_surfaces(bool p_optimize, Ref<ArrayMesh> &p_me
//make sure weights always add up to 1
float total = 0;
- for (int i = 0; i < weights.size(); i++)
+ for (int i = 0; i < weights.size(); i++) {
total += weights[i].weight;
- if (total)
- for (int i = 0; i < weights.size(); i++)
+ }
+ if (total) {
+ for (int i = 0; i < weights.size(); i++) {
weights.write[i].weight /= total;
+ }
+ }
if (weights.size() == 0 || total == 0) { //if nothing, add a weight to bone 0
//no weights assigned
@@ -713,10 +668,8 @@ Error ColladaImport::_create_mesh_surfaces(bool p_optimize, Ref<ArrayMesh> &p_me
int _prim_ofs = 0;
int vertidx = 0;
for (int p_j = 0; p_j < p.count; p_j++) {
-
int amount;
if (p.polygons.size()) {
-
ERR_FAIL_INDEX_V(p_j, p.polygons.size(), ERR_INVALID_DATA);
amount = p.polygons[p_j];
} else {
@@ -728,15 +681,15 @@ Error ColladaImport::_create_mesh_surfaces(bool p_optimize, Ref<ArrayMesh> &p_me
int prev2[2] = { 0, 0 };
for (int j = 0; j < amount; j++) {
-
int src = _prim_ofs;
//_prim_ofs+=p.sources.size()
ERR_FAIL_INDEX_V(src, p.indices.size(), ERR_INVALID_DATA);
Collada::Vertex vertex;
- if (!p_optimize)
+ if (!p_optimize) {
vertex.uid = vertidx++;
+ }
int vertex_index = p.indices[src + vertex_ofs]; //used for index field (later used by controllers)
int vertex_pos = (vertex_src->stride ? vertex_src->stride : 3) * vertex_index;
@@ -748,13 +701,11 @@ Error ColladaImport::_create_mesh_surfaces(bool p_optimize, Ref<ArrayMesh> &p_me
}
if (normal_src) {
-
int normal_pos = (normal_src->stride ? normal_src->stride : 3) * p.indices[src + normal_ofs];
ERR_FAIL_INDEX_V(normal_pos, normal_src->array.size(), ERR_INVALID_DATA);
vertex.normal = Vector3(normal_src->array[normal_pos + 0], normal_src->array[normal_pos + 1], normal_src->array[normal_pos + 2]);
if (tangent_src && binormal_src) {
-
int binormal_pos = (binormal_src->stride ? binormal_src->stride : 3) * p.indices[src + binormal_ofs];
ERR_FAIL_INDEX_V(binormal_pos, binormal_src->array.size(), ERR_INVALID_DATA);
Vector3 binormal = Vector3(binormal_src->array[binormal_pos + 0], binormal_src->array[binormal_pos + 1], binormal_src->array[binormal_pos + 2]);
@@ -769,21 +720,18 @@ Error ColladaImport::_create_mesh_surfaces(bool p_optimize, Ref<ArrayMesh> &p_me
}
if (uv_src) {
-
int uv_pos = (uv_src->stride ? uv_src->stride : 2) * p.indices[src + uv_ofs];
ERR_FAIL_INDEX_V(uv_pos, uv_src->array.size(), ERR_INVALID_DATA);
vertex.uv = Vector3(uv_src->array[uv_pos + 0], 1.0 - uv_src->array[uv_pos + 1], 0);
}
if (uv2_src) {
-
int uv2_pos = (uv2_src->stride ? uv2_src->stride : 2) * p.indices[src + uv2_ofs];
ERR_FAIL_INDEX_V(uv2_pos, uv2_src->array.size(), ERR_INVALID_DATA);
vertex.uv2 = Vector3(uv2_src->array[uv2_pos + 0], 1.0 - uv2_src->array[uv2_pos + 1], 0);
}
if (color_src) {
-
int color_pos = (color_src->stride ? color_src->stride : 3) * p.indices[src + color_ofs]; // colors are RGB in collada..
ERR_FAIL_INDEX_V(color_pos, color_src->array.size(), ERR_INVALID_DATA);
vertex.color = Color(color_src->array[color_pos + 0], color_src->array[color_pos + 1], color_src->array[color_pos + 2], (color_src->stride > 3) ? color_src->array[color_pos + 3] : 1.0);
@@ -791,7 +739,6 @@ Error ColladaImport::_create_mesh_surfaces(bool p_optimize, Ref<ArrayMesh> &p_me
#ifndef NO_UP_AXIS_SWAP
if (collada.state.up_axis == Vector3::AXIS_Z) {
-
Vector3 bn = vertex.normal.cross(vertex.tangent.normal) * vertex.tangent.d;
SWAP(vertex.vertex.z, vertex.vertex.y);
@@ -813,23 +760,21 @@ Error ColladaImport::_create_mesh_surfaces(bool p_optimize, Ref<ArrayMesh> &p_me
//COLLADA_PRINT("vertex: "+vertex.vertex);
if (vertex_set.has(vertex)) {
-
index = vertex_set.find(vertex)->get().idx;
} else {
-
index = vertex_set.size();
vertex.idx = index;
vertex_set.insert(vertex);
}
//build triangles if needed
- if (j == 0)
+ if (j == 0) {
prev2[0] = index;
+ }
if (j >= 2) {
//insert indices in reverse order (collada uses CCW as frontface)
if (local_xform_mirror) {
-
indices_list.push_back(prev2[0]);
indices_list.push_back(prev2[1]);
indices_list.push_back(index);
@@ -850,16 +795,13 @@ Error ColladaImport::_create_mesh_surfaces(bool p_optimize, Ref<ArrayMesh> &p_me
vertex_array.resize(vertex_set.size());
for (Set<Collada::Vertex>::Element *F = vertex_set.front(); F; F = F->next()) {
-
vertex_array.write[F->get().idx] = F->get();
}
if (has_weights) {
-
//if skeleton, localize
Transform local_xform = p_local_xform;
for (int i = 0; i < vertex_array.size(); i++) {
-
vertex_array.write[i].vertex = local_xform.xform(vertex_array[i].vertex);
vertex_array.write[i].normal = local_xform.basis.xform(vertex_array[i].normal).normalized();
vertex_array.write[i].tangent.normal = local_xform.basis.xform(vertex_array[i].tangent.normal).normalized();
@@ -876,23 +818,23 @@ Error ColladaImport::_create_mesh_surfaces(bool p_optimize, Ref<ArrayMesh> &p_me
/*****************/
{
-
- Ref<SpatialMaterial> material;
+ Ref<StandardMaterial3D> material;
{
-
if (p_material_map.has(p.material)) {
String target = p_material_map[p.material].target;
if (!material_cache.has(target)) {
Error err = _create_material(target);
- if (!err)
+ if (!err) {
material = material_cache[target];
- } else
+ }
+ } else {
material = material_cache[target];
+ }
} else if (p.material != "") {
- WARN_PRINTS("Collada: Unreferenced material in geometry instance: " + p.material);
+ WARN_PRINT("Collada: Unreferenced material in geometry instance: " + p.material);
}
}
@@ -920,16 +862,15 @@ Error ColladaImport::_create_mesh_surfaces(bool p_optimize, Ref<ArrayMesh> &p_me
if (has_weights) {
Vector<float> weights;
Vector<int> bones;
- weights.resize(VS::ARRAY_WEIGHTS_SIZE);
- bones.resize(VS::ARRAY_WEIGHTS_SIZE);
+ weights.resize(RS::ARRAY_WEIGHTS_SIZE);
+ bones.resize(RS::ARRAY_WEIGHTS_SIZE);
//float sum=0.0;
- for (int l = 0; l < VS::ARRAY_WEIGHTS_SIZE; l++) {
+ for (int l = 0; l < RS::ARRAY_WEIGHTS_SIZE; l++) {
if (l < vertex_array[k].weights.size()) {
weights.write[l] = vertex_array[k].weights[l].weight;
bones.write[l] = vertex_array[k].weights[l].bone_idx;
//sum += vertex_array[k].weights[l].weight;
} else {
-
weights.write[l] = 0;
bones.write[l] = 0;
}
@@ -952,7 +893,6 @@ Error ColladaImport::_create_mesh_surfaces(bool p_optimize, Ref<ArrayMesh> &p_me
}
if ((!binormal_src || !tangent_src) && normal_src && uv_src && force_make_tangents) {
-
surftool->generate_tangents();
}
@@ -961,7 +901,7 @@ Error ColladaImport::_create_mesh_surfaces(bool p_optimize, Ref<ArrayMesh> &p_me
////////////////////////////
Array d = surftool->commit_to_arrays();
- d.resize(VS::ARRAY_MAX);
+ d.resize(RS::ARRAY_MAX);
Array mr;
@@ -970,7 +910,6 @@ Error ColladaImport::_create_mesh_surfaces(bool p_optimize, Ref<ArrayMesh> &p_me
////////////////////////////
for (int mi = 0; mi < p_morph_meshes.size(); mi++) {
-
Array a = p_morph_meshes[mi]->surface_get_arrays(surface);
//add valid weight and bone arrays if they exist, TODO check if they are unique to shape (generally not)
@@ -984,7 +923,7 @@ Error ColladaImport::_create_mesh_surfaces(bool p_optimize, Ref<ArrayMesh> &p_me
mr.push_back(a);
}
- p_mesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, d, mr, p_use_compression ? Mesh::ARRAY_COMPRESS_DEFAULT : 0);
+ p_mesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, d, mr, Dictionary(), p_use_compression ? Mesh::ARRAY_COMPRESS_DEFAULT : 0);
if (material.is_valid()) {
if (p_use_mesh_material) {
@@ -1005,23 +944,16 @@ Error ColladaImport::_create_mesh_surfaces(bool p_optimize, Ref<ArrayMesh> &p_me
}
Error ColladaImport::_create_resources(Collada::Node *p_node, bool p_use_compression) {
-
if (p_node->type == Collada::Node::TYPE_GEOMETRY && node_map.has(p_node->id)) {
-
- Spatial *node = node_map[p_node->id].node;
+ Node3D *node = node_map[p_node->id].node;
Collada::NodeGeometry *ng = static_cast<Collada::NodeGeometry *>(p_node);
- if (Object::cast_to<Path>(node)) {
-
- Path *path = Object::cast_to<Path>(node);
-
- String curve = ng->source;
+ if (Object::cast_to<Path3D>(node)) {
+ Path3D *path = Object::cast_to<Path3D>(node);
if (curve_cache.has(ng->source)) {
-
path->set_curve(curve_cache[ng->source]);
} else {
-
Ref<Curve3D> c = memnew(Curve3D);
const Collada::CurveData &cd = collada.state.curve_data_map[ng->source];
@@ -1047,20 +979,19 @@ Error ColladaImport::_create_resources(Collada::Node *p_node, bool p_use_compres
const Collada::CurveData::Source &interps = cd.sources[cd.control_vertices["INTERPOLATION"]];
ERR_FAIL_COND_V(interps.stride != 1, ERR_INVALID_DATA);
- const Collada::CurveData::Source *tilts = NULL;
- if (cd.control_vertices.has("TILT") && cd.sources.has(cd.control_vertices["TILT"]))
+ const Collada::CurveData::Source *tilts = nullptr;
+ if (cd.control_vertices.has("TILT") && cd.sources.has(cd.control_vertices["TILT"])) {
tilts = &cd.sources[cd.control_vertices["TILT"]];
+ }
int pc = vertices.array.size() / 3;
for (int i = 0; i < pc; i++) {
-
Vector3 pos(vertices.array[i * 3 + 0], vertices.array[i * 3 + 1], vertices.array[i * 3 + 2]);
Vector3 in(in_tangents.array[i * 3 + 0], in_tangents.array[i * 3 + 1], in_tangents.array[i * 3 + 2]);
Vector3 out(out_tangents.array[i * 3 + 0], out_tangents.array[i * 3 + 1], out_tangents.array[i * 3 + 2]);
#ifndef NO_UP_AXIS_SWAP
if (collada.state.up_axis == Vector3::AXIS_Z) {
-
SWAP(pos.y, pos.z);
pos.z = -pos.z;
SWAP(in.y, in.z);
@@ -1074,8 +1005,9 @@ Error ColladaImport::_create_resources(Collada::Node *p_node, bool p_use_compres
out *= collada.state.unit_scale;
c->add_point(pos, in - pos, out - pos);
- if (tilts)
+ if (tilts) {
c->set_point_tilt(i, tilts->array[i]);
+ }
}
curve_cache[ng->source] = c;
@@ -1083,27 +1015,24 @@ Error ColladaImport::_create_resources(Collada::Node *p_node, bool p_use_compres
}
}
- if (Object::cast_to<MeshInstance>(node)) {
-
+ if (Object::cast_to<MeshInstance3D>(node)) {
Collada::NodeGeometry *ng2 = static_cast<Collada::NodeGeometry *>(p_node);
- MeshInstance *mi = Object::cast_to<MeshInstance>(node);
+ MeshInstance3D *mi = Object::cast_to<MeshInstance3D>(node);
ERR_FAIL_COND_V(!mi, ERR_BUG);
- Collada::SkinControllerData *skin = NULL;
- Collada::MorphControllerData *morph = NULL;
+ Collada::SkinControllerData *skin = nullptr;
+ Collada::MorphControllerData *morph = nullptr;
String meshid;
Transform apply_xform;
Vector<int> bone_remap;
- Vector<Ref<ArrayMesh> > morphs;
+ Vector<Ref<ArrayMesh>> morphs;
if (ng2->controller) {
-
String ngsource = ng2->source;
if (collada.state.skin_controller_data_map.has(ngsource)) {
-
ERR_FAIL_COND_V(!collada.state.skin_controller_data_map.has(ngsource), ERR_INVALID_DATA);
skin = &collada.state.skin_controller_data_map[ngsource];
@@ -1114,7 +1043,7 @@ Error ColladaImport::_create_resources(Collada::Node *p_node, bool p_use_compres
String skname = skeletons[0];
ERR_FAIL_COND_V(!node_map.has(skname), ERR_INVALID_DATA);
NodeMap nmsk = node_map[skname];
- Skeleton *sk = Object::cast_to<Skeleton>(nmsk.node);
+ Skeleton3D *sk = Object::cast_to<Skeleton3D>(nmsk.node);
ERR_FAIL_COND_V(!sk, ERR_INVALID_DATA);
ERR_FAIL_COND_V(!skeleton_bone_map.has(sk), ERR_INVALID_DATA);
Map<String, int> &bone_remap_map = skeleton_bone_map[sk];
@@ -1147,7 +1076,6 @@ Error ColladaImport::_create_resources(Collada::Node *p_node, bool p_use_compres
bone_remap.resize(joint_src->sarray.size());
for (int i = 0; i < bone_remap.size(); i++) {
-
String str = joint_src->sarray[i];
ERR_FAIL_COND_V(!bone_remap_map.has(str), ERR_INVALID_DATA);
bone_remap.write[i] = bone_remap_map[str];
@@ -1155,7 +1083,6 @@ Error ColladaImport::_create_resources(Collada::Node *p_node, bool p_use_compres
}
if (collada.state.morph_controller_data_map.has(ngsource)) {
-
//it's a morph!!
morph = &collada.state.morph_controller_data_map[ngsource];
meshid = morph->mesh;
@@ -1167,13 +1094,12 @@ Error ColladaImport::_create_resources(Collada::Node *p_node, bool p_use_compres
valid = true;
Vector<String> names = morph->sources[target].sarray;
for (int i = 0; i < names.size(); i++) {
-
String meshid2 = names[i];
if (collada.state.mesh_data_map.has(meshid2)) {
Ref<ArrayMesh> mesh = Ref<ArrayMesh>(memnew(ArrayMesh));
const Collada::MeshData &meshdata = collada.state.mesh_data_map[meshid2];
mesh->set_name(meshdata.name);
- Error err = _create_mesh_surfaces(false, mesh, ng2->material_map, meshdata, apply_xform, bone_remap, skin, NULL, Vector<Ref<ArrayMesh> >(), false);
+ Error err = _create_mesh_surfaces(false, mesh, ng2->material_map, meshdata, apply_xform, bone_remap, skin, nullptr, Vector<Ref<ArrayMesh>>(), false);
ERR_FAIL_COND_V(err, err);
morphs.push_back(mesh);
@@ -1183,8 +1109,9 @@ Error ColladaImport::_create_resources(Collada::Node *p_node, bool p_use_compres
}
}
- if (!valid)
+ if (!valid) {
morphs.clear();
+ }
ngsource = "";
}
}
@@ -1211,19 +1138,16 @@ Error ColladaImport::_create_resources(Collada::Node *p_node, bool p_use_compres
mesh_cache[meshid] = mesh;
} else {
-
- WARN_PRINTS("Collada: Will not import geometry: " + meshid);
+ WARN_PRINT("Collada: Will not import geometry: " + meshid);
}
}
if (!mesh.is_null()) {
-
mi->set_mesh(mesh);
if (!use_mesh_builtin_materials) {
const Collada::MeshData &meshdata = collada.state.mesh_data_map[meshid];
for (int i = 0; i < meshdata.primitives.size(); i++) {
-
String matname = meshdata.primitives[i].material;
if (ng2->material_map.has(matname)) {
@@ -1232,14 +1156,16 @@ Error ColladaImport::_create_resources(Collada::Node *p_node, bool p_use_compres
Ref<Material> material;
if (!material_cache.has(target)) {
Error err = _create_material(target);
- if (!err)
+ if (!err) {
material = material_cache[target];
- } else
+ }
+ } else {
material = material_cache[target];
+ }
mi->set_surface_material(i, material);
} else if (matname != "") {
- WARN_PRINTS("Collada: Unreferenced material in geometry instance: " + matname);
+ WARN_PRINT("Collada: Unreferenced material in geometry instance: " + matname);
}
}
}
@@ -1248,16 +1174,15 @@ Error ColladaImport::_create_resources(Collada::Node *p_node, bool p_use_compres
}
for (int i = 0; i < p_node->children.size(); i++) {
-
Error err = _create_resources(p_node->children[i], p_use_compression);
- if (err)
+ if (err) {
return err;
+ }
}
return OK;
}
Error ColladaImport::load(const String &p_path, int p_flags, bool p_force_make_tangents, bool p_use_compression) {
-
Error err = collada.load(p_path, p_flags);
ERR_FAIL_COND_V_MSG(err, err, "Cannot load file '" + p_path + "'.");
@@ -1265,17 +1190,15 @@ Error ColladaImport::load(const String &p_path, int p_flags, bool p_force_make_t
ERR_FAIL_COND_V(!collada.state.visual_scene_map.has(collada.state.root_visual_scene), ERR_INVALID_DATA);
Collada::VisualScene &vs = collada.state.visual_scene_map[collada.state.root_visual_scene];
- scene = memnew(Spatial); // root
+ scene = memnew(Node3D); // root
//determine what's going on with the lights
for (int i = 0; i < vs.root_nodes.size(); i++) {
-
_pre_process_lights(vs.root_nodes[i]);
}
//import scene
for (int i = 0; i < vs.root_nodes.size(); i++) {
-
Error err2 = _create_scene_skeletons(vs.root_nodes[i]);
if (err2 != OK) {
memdelete(scene);
@@ -1284,7 +1207,6 @@ Error ColladaImport::load(const String &p_path, int p_flags, bool p_force_make_t
}
for (int i = 0; i < vs.root_nodes.size(); i++) {
-
Error err2 = _create_scene(vs.root_nodes[i], scene);
if (err2 != OK) {
memdelete(scene);
@@ -1305,48 +1227,36 @@ Error ColladaImport::load(const String &p_path, int p_flags, bool p_force_make_t
}
void ColladaImport::_fix_param_animation_tracks() {
-
for (Map<String, Collada::Node *>::Element *E = collada.state.scene_map.front(); E; E = E->next()) {
-
Collada::Node *n = E->get();
switch (n->type) {
-
case Collada::Node::TYPE_NODE: {
// ? do nothing
} break;
case Collada::Node::TYPE_JOINT: {
-
} break;
case Collada::Node::TYPE_SKELETON: {
-
} break;
case Collada::Node::TYPE_LIGHT: {
-
} break;
case Collada::Node::TYPE_CAMERA: {
-
} break;
case Collada::Node::TYPE_GEOMETRY: {
-
Collada::NodeGeometry *ng = static_cast<Collada::NodeGeometry *>(n);
// test source(s)
String source = ng->source;
while (source != "") {
-
if (collada.state.skin_controller_data_map.has(source)) {
-
const Collada::SkinControllerData &skin = collada.state.skin_controller_data_map[source];
//nothing to animate here i think
source = skin.base;
} else if (collada.state.morph_controller_data_map.has(source)) {
-
const Collada::MorphControllerData &morph = collada.state.morph_controller_data_map[source];
if (morph.targets.has("MORPH_WEIGHT") && morph.targets.has("MORPH_TARGET")) {
-
String weights = morph.targets["MORPH_WEIGHT"];
String targets = morph.targets["MORPH_TARGET"];
//fails here
@@ -1358,11 +1268,9 @@ void ColladaImport::_fix_param_animation_tracks() {
ERR_FAIL_COND(weight_src.array.size() != target_src.sarray.size());
for (int i = 0; i < weight_src.array.size(); i++) {
-
String track_name = weights + "(" + itos(i) + ")";
String mesh_name = target_src.sarray[i];
if (collada.state.mesh_name_map.has(mesh_name) && collada.state.referenced_tracks.has(track_name)) {
-
const Vector<int> &rt = collada.state.referenced_tracks[track_name];
for (int rti = 0; rti < rt.size(); rti++) {
@@ -1379,7 +1287,6 @@ void ColladaImport::_fix_param_animation_tracks() {
}
source = morph.mesh;
} else {
-
source = ""; // for now nothing else supported
}
}
@@ -1390,27 +1297,23 @@ void ColladaImport::_fix_param_animation_tracks() {
}
void ColladaImport::create_animations(bool p_make_tracks_in_all_bones, bool p_import_value_tracks) {
-
_fix_param_animation_tracks();
for (int i = 0; i < collada.state.animation_clips.size(); i++) {
-
- for (int j = 0; j < collada.state.animation_clips[i].tracks.size(); j++)
+ for (int j = 0; j < collada.state.animation_clips[i].tracks.size(); j++) {
tracks_in_clips.insert(collada.state.animation_clips[i].tracks[j]);
+ }
}
for (int i = 0; i < collada.state.animation_tracks.size(); i++) {
-
const Collada::AnimationTrack &at = collada.state.animation_tracks[i];
String node;
if (!node_map.has(at.target)) {
-
if (node_name_map.has(at.target)) {
-
node = node_name_map[at.target];
} else {
- WARN_PRINTS("Collada: Couldn't find node: " + at.target);
+ WARN_PRINT("Collada: Couldn't find node: " + at.target);
continue;
}
} else {
@@ -1418,23 +1321,21 @@ void ColladaImport::create_animations(bool p_make_tracks_in_all_bones, bool p_im
}
if (at.property) {
-
valid_animated_properties.push_back(i);
} else {
-
node_map[node].anim_tracks.push_back(i);
valid_animated_nodes.insert(node);
}
}
create_animation(-1, p_make_tracks_in_all_bones, p_import_value_tracks);
- for (int i = 0; i < collada.state.animation_clips.size(); i++)
+ for (int i = 0; i < collada.state.animation_clips.size(); i++) {
create_animation(i, p_make_tracks_in_all_bones, p_import_value_tracks);
+ }
}
void ColladaImport::create_animation(int p_clip, bool p_make_tracks_in_all_bones, bool p_import_value_tracks) {
-
Ref<Animation> animation = Ref<Animation>(memnew(Animation));
if (p_clip == -1) {
@@ -1444,9 +1345,9 @@ void ColladaImport::create_animation(int p_clip, bool p_make_tracks_in_all_bones
}
for (Map<String, NodeMap>::Element *E = node_map.front(); E; E = E->next()) {
-
- if (E->get().bone < 0)
+ if (E->get().bone < 0) {
continue;
+ }
bones_with_animation[E->key()] = false;
}
//store and validate tracks
@@ -1458,15 +1359,11 @@ void ColladaImport::create_animation(int p_clip, bool p_make_tracks_in_all_bones
Set<int> track_filter;
if (p_clip == -1) {
-
for (int i = 0; i < collada.state.animation_clips.size(); i++) {
-
int tc = collada.state.animation_clips[i].tracks.size();
for (int j = 0; j < tc; j++) {
-
String n = collada.state.animation_clips[i].tracks[j];
if (collada.state.by_id_tracks.has(n)) {
-
const Vector<int> &ti = collada.state.by_id_tracks[n];
for (int k = 0; k < ti.size(); k++) {
track_filter.insert(ti[k]);
@@ -1475,13 +1372,10 @@ void ColladaImport::create_animation(int p_clip, bool p_make_tracks_in_all_bones
}
}
} else {
-
int tc = collada.state.animation_clips[p_clip].tracks.size();
for (int j = 0; j < tc; j++) {
-
String n = collada.state.animation_clips[p_clip].tracks[j];
if (collada.state.by_id_tracks.has(n)) {
-
const Vector<int> &ti = collada.state.by_id_tracks[n];
for (int k = 0; k < ti.size(); k++) {
track_filter.insert(ti[k]);
@@ -1499,11 +1393,11 @@ void ColladaImport::create_animation(int p_clip, bool p_make_tracks_in_all_bones
float snapshot_interval = 1.0 / bake_fps; //should be customizable somewhere...
float anim_length = collada.state.animation_length;
- if (p_clip >= 0 && collada.state.animation_clips[p_clip].end)
+ if (p_clip >= 0 && collada.state.animation_clips[p_clip].end) {
anim_length = collada.state.animation_clips[p_clip].end;
+ }
while (f < anim_length) {
-
base_snapshots.push_back(f);
f += snapshot_interval;
@@ -1518,11 +1412,9 @@ void ColladaImport::create_animation(int p_clip, bool p_make_tracks_in_all_bones
bool tracks_found = false;
for (Set<String>::Element *E = valid_animated_nodes.front(); E; E = E->next()) {
-
// take snapshots
if (!collada.state.scene_map.has(E->get())) {
-
continue;
}
@@ -1530,7 +1422,7 @@ void ColladaImport::create_animation(int p_clip, bool p_make_tracks_in_all_bones
String path = scene->get_path_to(nm.node);
if (nm.bone >= 0) {
- Skeleton *sk = static_cast<Skeleton *>(nm.node);
+ Skeleton3D *sk = static_cast<Skeleton3D *>(nm.node);
String name = sk->get_bone_name(nm.bone);
path = path + ":" + name;
}
@@ -1539,7 +1431,6 @@ void ColladaImport::create_animation(int p_clip, bool p_make_tracks_in_all_bones
Collada::Node *cn = collada.state.scene_map[E->get()];
if (cn->ignore_anim) {
-
continue;
}
@@ -1554,25 +1445,23 @@ void ColladaImport::create_animation(int p_clip, bool p_make_tracks_in_all_bones
//use snapshot keys from anim track instead, because this was most likely exported baked
const Collada::AnimationTrack &at = collada.state.animation_tracks[nm.anim_tracks.front()->get()];
snapshots.clear();
- for (int i = 0; i < at.keys.size(); i++)
+ for (int i = 0; i < at.keys.size(); i++) {
snapshots.push_back(at.keys[i].time);
+ }
}
for (int i = 0; i < snapshots.size(); i++) {
-
for (List<int>::Element *ET = nm.anim_tracks.front(); ET; ET = ET->next()) {
//apply tracks
if (p_clip == -1) {
-
if (track_filter.has(ET->get())) {
-
continue;
}
} else {
-
- if (!track_filter.has(ET->get()))
+ if (!track_filter.has(ET->get())) {
continue;
+ }
}
found_anim = true;
@@ -1581,16 +1470,14 @@ void ColladaImport::create_animation(int p_clip, bool p_make_tracks_in_all_bones
int xform_idx = -1;
for (int j = 0; j < cn->xform_list.size(); j++) {
-
if (cn->xform_list[j].id == at.param) {
-
xform_idx = j;
break;
}
}
if (xform_idx == -1) {
- WARN_PRINTS("Collada: Couldn't find matching node " + at.target + " xform for track " + at.param + ".");
+ WARN_PRINT("Collada: Couldn't find matching node " + at.target + " xform for track " + at.param + ".");
continue;
}
@@ -1621,12 +1508,10 @@ void ColladaImport::create_animation(int p_clip, bool p_make_tracks_in_all_bones
if (nm.bone >= 0) {
//make bone transform relative to rest (in case of skeleton)
- Skeleton *sk = Object::cast_to<Skeleton>(nm.node);
+ Skeleton3D *sk = Object::cast_to<Skeleton3D>(nm.node);
if (sk) {
-
xform = sk->get_bone_rest(nm.bone).affine_inverse() * xform;
} else {
-
ERR_PRINT("Collada: Invalid skeleton");
}
}
@@ -1640,35 +1525,35 @@ void ColladaImport::create_animation(int p_clip, bool p_make_tracks_in_all_bones
}
if (nm.bone >= 0) {
- if (found_anim)
+ if (found_anim) {
bones_with_animation[E->get()] = true;
+ }
}
- if (found_anim)
+ if (found_anim) {
tracks_found = true;
- else {
+ } else {
animation->remove_track(track);
}
}
if (p_make_tracks_in_all_bones) {
-
//some bones may lack animation, but since we don't store pose as a property, we must add keyframes!
for (Map<String, bool>::Element *E = bones_with_animation.front(); E; E = E->next()) {
-
- if (E->get())
+ if (E->get()) {
continue;
+ }
NodeMap &nm = node_map[E->key()];
String path = scene->get_path_to(nm.node);
ERR_CONTINUE(nm.bone < 0);
- Skeleton *sk = static_cast<Skeleton *>(nm.node);
+ Skeleton3D *sk = static_cast<Skeleton3D *>(nm.node);
String name = sk->get_bone_name(nm.bone);
path = path + ":" + name;
Collada::Node *cn = collada.state.scene_map[E->key()];
if (cn->ignore_anim) {
- WARN_PRINTS("Collada: Ignoring animation on node: " + path);
+ WARN_PRINT("Collada: Ignoring animation on node: " + path);
continue;
}
@@ -1695,24 +1580,24 @@ void ColladaImport::create_animation(int p_clip, bool p_make_tracks_in_all_bones
if (p_import_value_tracks) {
for (int i = 0; i < valid_animated_properties.size(); i++) {
-
int ti = valid_animated_properties[i];
if (p_clip == -1) {
-
- if (track_filter.has(ti))
+ if (track_filter.has(ti)) {
continue;
+ }
} else {
-
- if (!track_filter.has(ti))
+ if (!track_filter.has(ti)) {
continue;
+ }
}
const Collada::AnimationTrack &at = collada.state.animation_tracks[ti];
// take snapshots
- if (!collada.state.scene_map.has(at.target))
+ if (!collada.state.scene_map.has(at.target)) {
continue;
+ }
NodeMap &nm = node_map[at.target];
String path = scene->get_path_to(nm.node);
@@ -1725,7 +1610,6 @@ void ColladaImport::create_animation(int p_clip, bool p_make_tracks_in_all_bones
animation->track_set_imported(track, true); //helps merging later
for (int j = 0; j < at.keys.size(); j++) {
-
float time = at.keys[j].time;
Variant value;
Vector<float> data = at.keys[j].data;
@@ -1737,7 +1621,7 @@ void ColladaImport::create_animation(int p_clip, bool p_make_tracks_in_all_bones
//matrix
WARN_PRINT("Collada: Value keys for matrices not supported.");
} else {
- WARN_PRINTS("Collada: Unexpected amount of value keys: " + itos(data.size()));
+ WARN_PRINT("Collada: Unexpected amount of value keys: " + itos(data.size()));
}
animation->track_insert_key(track, time, value);
@@ -1748,7 +1632,6 @@ void ColladaImport::create_animation(int p_clip, bool p_make_tracks_in_all_bones
}
if (tracks_found) {
-
animations.push_back(animation);
}
}
@@ -1758,37 +1641,35 @@ void ColladaImport::create_animation(int p_clip, bool p_make_tracks_in_all_bones
/*********************************************************************************/
uint32_t EditorSceneImporterCollada::get_import_flags() const {
-
return IMPORT_SCENE | IMPORT_ANIMATION;
}
-void EditorSceneImporterCollada::get_extensions(List<String> *r_extensions) const {
+void EditorSceneImporterCollada::get_extensions(List<String> *r_extensions) const {
r_extensions->push_back("dae");
}
-Node *EditorSceneImporterCollada::import_scene(const String &p_path, uint32_t p_flags, int p_bake_fps, List<String> *r_missing_deps, Error *r_err) {
+Node *EditorSceneImporterCollada::import_scene(const String &p_path, uint32_t p_flags, int p_bake_fps, List<String> *r_missing_deps, Error *r_err) {
ColladaImport state;
uint32_t flags = Collada::IMPORT_FLAG_SCENE;
- if (p_flags & IMPORT_ANIMATION)
+ if (p_flags & IMPORT_ANIMATION) {
flags |= Collada::IMPORT_FLAG_ANIMATION;
+ }
state.use_mesh_builtin_materials = !(p_flags & IMPORT_MATERIALS_IN_INSTANCES);
state.bake_fps = p_bake_fps;
Error err = state.load(p_path, flags, p_flags & EditorSceneImporter::IMPORT_GENERATE_TANGENT_ARRAYS, p_flags & EditorSceneImporter::IMPORT_USE_COMPRESSION);
- ERR_FAIL_COND_V_MSG(err != OK, NULL, "Cannot load scene from file '" + p_path + "'.");
+ ERR_FAIL_COND_V_MSG(err != OK, nullptr, "Cannot load scene from file '" + p_path + "'.");
if (state.missing_textures.size()) {
-
/*
- for(int i=0;i<state.missing_textures.size();i++) {
- EditorNode::add_io_error("Texture Not Found: "+state.missing_textures[i]);
- }
- */
+ for(int i=0;i<state.missing_textures.size();i++) {
+ EditorNode::add_io_error("Texture Not Found: "+state.missing_textures[i]);
+ }
+ */
if (r_missing_deps) {
-
for (int i = 0; i < state.missing_textures.size(); i++) {
//EditorNode::add_io_error("Texture Not Found: "+state.missing_textures[i]);
r_missing_deps->push_back(state.missing_textures[i]);
@@ -1797,18 +1678,17 @@ Node *EditorSceneImporterCollada::import_scene(const String &p_path, uint32_t p_
}
if (p_flags & IMPORT_ANIMATION) {
-
state.create_animations(p_flags & IMPORT_ANIMATION_FORCE_ALL_TRACKS_IN_ALL_CLIPS, p_flags & EditorSceneImporter::IMPORT_ANIMATION_KEEP_VALUE_TRACKS);
AnimationPlayer *ap = memnew(AnimationPlayer);
for (int i = 0; i < state.animations.size(); i++) {
String name;
- if (state.animations[i]->get_name() == "")
+ if (state.animations[i]->get_name() == "") {
name = "default";
- else
+ } else {
name = state.animations[i]->get_name();
+ }
if (p_flags & IMPORT_ANIMATION_DETECT_LOOP) {
-
if (name.begins_with("loop") || name.ends_with("loop") || name.begins_with("cycle") || name.ends_with("cycle")) {
state.animations.write[i]->set_loop(true);
}
@@ -1824,7 +1704,6 @@ Node *EditorSceneImporterCollada::import_scene(const String &p_path, uint32_t p_
}
Ref<Animation> EditorSceneImporterCollada::import_animation(const String &p_path, uint32_t p_flags, int p_bake_fps) {
-
ColladaImport state;
state.use_mesh_builtin_materials = false;
@@ -1833,15 +1712,16 @@ Ref<Animation> EditorSceneImporterCollada::import_animation(const String &p_path
ERR_FAIL_COND_V_MSG(err != OK, RES(), "Cannot load animation from file '" + p_path + "'.");
state.create_animations(p_flags & EditorSceneImporter::IMPORT_ANIMATION_FORCE_ALL_TRACKS_IN_ALL_CLIPS, p_flags & EditorSceneImporter::IMPORT_ANIMATION_KEEP_VALUE_TRACKS);
- if (state.scene)
+ if (state.scene) {
memdelete(state.scene);
+ }
- if (state.animations.size() == 0)
+ if (state.animations.size() == 0) {
return Ref<Animation>();
+ }
Ref<Animation> anim = state.animations[0];
String base = p_path.get_basename().to_lower();
if (p_flags & IMPORT_ANIMATION_DETECT_LOOP) {
-
if (base.begins_with("loop") || base.ends_with("loop") || base.begins_with("cycle") || base.ends_with("cycle")) {
anim->set_loop(true);
}
diff --git a/editor/import/editor_import_collada.h b/editor/import/editor_import_collada.h
index 6497cdb110..57c694b698 100644
--- a/editor/import/editor_import_collada.h
+++ b/editor/import/editor_import_collada.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -34,13 +34,12 @@
#include "editor/import/resource_importer_scene.h"
class EditorSceneImporterCollada : public EditorSceneImporter {
-
GDCLASS(EditorSceneImporterCollada, EditorSceneImporter);
public:
virtual uint32_t get_import_flags() const;
virtual void get_extensions(List<String> *r_extensions) const;
- virtual Node *import_scene(const String &p_path, uint32_t p_flags, int p_bake_fps, List<String> *r_missing_deps = NULL, Error *r_err = NULL);
+ virtual Node *import_scene(const String &p_path, uint32_t p_flags, int p_bake_fps, List<String> *r_missing_deps = nullptr, Error *r_err = nullptr);
virtual Ref<Animation> import_animation(const String &p_path, uint32_t p_flags, int p_bake_fps);
EditorSceneImporterCollada();
diff --git a/editor/import/editor_import_plugin.cpp b/editor/import/editor_import_plugin.cpp
index 98f4947c2d..6d46d4d2e9 100644
--- a/editor/import/editor_import_plugin.cpp
+++ b/editor/import/editor_import_plugin.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -87,7 +87,6 @@ int EditorImportPlugin::get_import_order() const {
}
void EditorImportPlugin::get_import_options(List<ResourceImporter::ImportOption> *r_options, int p_preset) const {
-
ERR_FAIL_COND(!(get_script_instance() && get_script_instance()->has_method("get_import_options")));
Array needed;
needed.push_back("name");
@@ -131,7 +130,6 @@ bool EditorImportPlugin::get_option_visibility(const String &p_option, const Map
}
Error EditorImportPlugin::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) {
-
ERR_FAIL_COND_V(!(get_script_instance() && get_script_instance()->has_method("import")), ERR_UNAVAILABLE);
Dictionary options;
Array platform_variants, gen_files;
@@ -153,7 +151,6 @@ Error EditorImportPlugin::import(const String &p_source_file, const String &p_sa
}
void EditorImportPlugin::_bind_methods() {
-
ClassDB::add_virtual_method(get_class_static(), MethodInfo(Variant::STRING, "get_importer_name"));
ClassDB::add_virtual_method(get_class_static(), MethodInfo(Variant::STRING, "get_visible_name"));
ClassDB::add_virtual_method(get_class_static(), MethodInfo(Variant::INT, "get_preset_count"));
@@ -162,7 +159,7 @@ void EditorImportPlugin::_bind_methods() {
ClassDB::add_virtual_method(get_class_static(), MethodInfo(Variant::ARRAY, "get_import_options", PropertyInfo(Variant::INT, "preset")));
ClassDB::add_virtual_method(get_class_static(), MethodInfo(Variant::STRING, "get_save_extension"));
ClassDB::add_virtual_method(get_class_static(), MethodInfo(Variant::STRING, "get_resource_type"));
- ClassDB::add_virtual_method(get_class_static(), MethodInfo(Variant::REAL, "get_priority"));
+ ClassDB::add_virtual_method(get_class_static(), MethodInfo(Variant::FLOAT, "get_priority"));
ClassDB::add_virtual_method(get_class_static(), MethodInfo(Variant::INT, "get_import_order"));
ClassDB::add_virtual_method(get_class_static(), MethodInfo(Variant::BOOL, "get_option_visibility", PropertyInfo(Variant::STRING, "option"), PropertyInfo(Variant::DICTIONARY, "options")));
ClassDB::add_virtual_method(get_class_static(), MethodInfo(Variant::INT, "import", PropertyInfo(Variant::STRING, "source_file"), PropertyInfo(Variant::STRING, "save_path"), PropertyInfo(Variant::DICTIONARY, "options"), PropertyInfo(Variant::ARRAY, "platform_variants"), PropertyInfo(Variant::ARRAY, "gen_files")));
diff --git a/editor/import/editor_import_plugin.h b/editor/import/editor_import_plugin.h
index eb119b4ba3..be4679b6d3 100644
--- a/editor/import/editor_import_plugin.h
+++ b/editor/import/editor_import_plugin.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -52,7 +52,7 @@ public:
virtual int get_import_order() const;
virtual void get_import_options(List<ImportOption> *r_options, int p_preset) const;
virtual bool get_option_visibility(const String &p_option, const Map<StringName, Variant> &p_options) const;
- virtual Error 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 = NULL);
+ virtual Error 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 = nullptr);
};
#endif //EDITOR_IMPORT_PLUGIN_H
diff --git a/editor/import/editor_scene_importer_gltf.cpp b/editor/import/editor_scene_importer_gltf.cpp
index fcf0e4af6f..6ffff09ce5 100644
--- a/editor/import/editor_scene_importer_gltf.cpp
+++ b/editor/import/editor_scene_importer_gltf.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -29,6 +29,7 @@
/*************************************************************************/
#include "editor_scene_importer_gltf.h"
+
#include "core/crypto/crypto_core.h"
#include "core/io/json.h"
#include "core/math/disjoint_set.h"
@@ -36,24 +37,22 @@
#include "core/os/file_access.h"
#include "core/os/os.h"
#include "modules/regex/regex.h"
-#include "scene/3d/bone_attachment.h"
-#include "scene/3d/camera.h"
-#include "scene/3d/mesh_instance.h"
+#include "scene/3d/bone_attachment_3d.h"
+#include "scene/3d/camera_3d.h"
+#include "scene/3d/mesh_instance_3d.h"
#include "scene/animation/animation_player.h"
#include "scene/resources/surface_tool.h"
uint32_t EditorSceneImporterGLTF::get_import_flags() const {
-
return IMPORT_SCENE | IMPORT_ANIMATION;
}
-void EditorSceneImporterGLTF::get_extensions(List<String> *r_extensions) const {
+void EditorSceneImporterGLTF::get_extensions(List<String> *r_extensions) const {
r_extensions->push_back("gltf");
r_extensions->push_back("glb");
}
Error EditorSceneImporterGLTF::_parse_json(const String &p_path, GLTFState &state) {
-
Error err;
FileAccessRef f = FileAccess::open(p_path, FileAccess::READ, &err);
if (!f) {
@@ -80,7 +79,6 @@ Error EditorSceneImporterGLTF::_parse_json(const String &p_path, GLTFState &stat
}
Error EditorSceneImporterGLTF::_parse_glb(const String &p_path, GLTFState &state) {
-
Error err;
FileAccessRef f = FileAccess::open(p_path, FileAccess::READ, &err);
if (!f) {
@@ -162,7 +160,6 @@ String EditorSceneImporterGLTF::_sanitize_scene_name(const String &name) {
}
String EditorSceneImporterGLTF::_gen_unique_name(GLTFState &state, const String &p_name) {
-
const String s_name = _sanitize_scene_name(p_name);
String name;
@@ -203,7 +200,6 @@ String EditorSceneImporterGLTF::_sanitize_bone_name(const String &name) {
}
String EditorSceneImporterGLTF::_gen_unique_bone_name(GLTFState &state, const GLTFSkeletonIndex skel_i, const String &p_name) {
-
const String s_name = _sanitize_bone_name(p_name);
String name;
@@ -226,11 +222,18 @@ String EditorSceneImporterGLTF::_gen_unique_bone_name(GLTFState &state, const GL
}
Error EditorSceneImporterGLTF::_parse_scenes(GLTFState &state) {
-
ERR_FAIL_COND_V(!state.json.has("scenes"), ERR_FILE_CORRUPT);
const Array &scenes = state.json["scenes"];
- for (int i = 0; i < 1; i++) { //only first scene is imported
- const Dictionary &s = scenes[i];
+ int loaded_scene = 0;
+ if (state.json.has("scene")) {
+ loaded_scene = state.json["scene"];
+ } else {
+ WARN_PRINT("The load-time scene is not defined in the glTF2 file. Picking the first scene.");
+ }
+
+ if (scenes.size()) {
+ ERR_FAIL_COND_V(loaded_scene >= scenes.size(), ERR_FILE_CORRUPT);
+ const Dictionary &s = scenes[loaded_scene];
ERR_FAIL_COND_V(!s.has("nodes"), ERR_UNAVAILABLE);
const Array &nodes = s["nodes"];
for (int j = 0; j < nodes.size(); j++) {
@@ -248,11 +251,9 @@ Error EditorSceneImporterGLTF::_parse_scenes(GLTFState &state) {
}
Error EditorSceneImporterGLTF::_parse_nodes(GLTFState &state) {
-
ERR_FAIL_COND_V(!state.json.has("nodes"), ERR_FILE_CORRUPT);
const Array &nodes = state.json["nodes"];
for (int i = 0; i < nodes.size(); i++) {
-
GLTFNode *node = memnew(GLTFNode);
const Dictionary &n = nodes[i];
@@ -272,7 +273,6 @@ Error EditorSceneImporterGLTF::_parse_nodes(GLTFState &state) {
node->xform = _arr_to_xform(n["matrix"]);
} else {
-
if (n.has("translation")) {
node->translation = _arr_to_vec3(n["translation"]);
}
@@ -299,7 +299,6 @@ Error EditorSceneImporterGLTF::_parse_nodes(GLTFState &state) {
// build the hierarchy
for (GLTFNodeIndex node_i = 0; node_i < state.nodes.size(); node_i++) {
-
for (int j = 0; j < state.nodes[node_i]->children.size(); j++) {
GLTFNodeIndex child_i = state.nodes[node_i]->children[j];
@@ -316,7 +315,6 @@ Error EditorSceneImporterGLTF::_parse_nodes(GLTFState &state) {
}
void EditorSceneImporterGLTF::_compute_node_heights(GLTFState &state) {
-
state.root_nodes.clear();
for (GLTFNodeIndex node_i = 0; node_i < state.nodes.size(); ++node_i) {
GLTFNode *node = state.nodes[node_i];
@@ -338,7 +336,6 @@ void EditorSceneImporterGLTF::_compute_node_heights(GLTFState &state) {
}
static Vector<uint8_t> _parse_base64_uri(const String &uri) {
-
int start = uri.find(",");
ERR_FAIL_COND_V(start == -1, Vector<uint8_t>());
@@ -358,20 +355,18 @@ static Vector<uint8_t> _parse_base64_uri(const String &uri) {
}
Error EditorSceneImporterGLTF::_parse_buffers(GLTFState &state, const String &p_base_path) {
-
- if (!state.json.has("buffers"))
+ if (!state.json.has("buffers")) {
return OK;
+ }
const Array &buffers = state.json["buffers"];
for (GLTFBufferIndex i = 0; i < buffers.size(); i++) {
-
if (i == 0 && state.glb_data.size()) {
state.buffers.push_back(state.glb_data);
} else {
const Dictionary &buffer = buffers[i];
if (buffer.has("uri")) {
-
Vector<uint8_t> buffer_data;
String uri = buffer["uri"];
@@ -379,7 +374,6 @@ Error EditorSceneImporterGLTF::_parse_buffers(GLTFState &state, const String &p_
//embedded data
buffer_data = _parse_base64_uri(uri);
} else {
-
uri = p_base_path.plus_file(uri).replace("\\", "/"); //fix for windows
buffer_data = FileAccess::get_file_as_array(uri);
ERR_FAIL_COND_V(buffer.size() == 0, ERR_PARSE_ERROR);
@@ -399,11 +393,9 @@ Error EditorSceneImporterGLTF::_parse_buffers(GLTFState &state, const String &p_
}
Error EditorSceneImporterGLTF::_parse_buffer_views(GLTFState &state) {
-
ERR_FAIL_COND_V(!state.json.has("bufferViews"), ERR_FILE_CORRUPT);
const Array &buffers = state.json["bufferViews"];
for (GLTFBufferViewIndex i = 0; i < buffers.size(); i++) {
-
const Dictionary &d = buffers[i];
GLTFBufferView buffer_view;
@@ -435,33 +427,37 @@ Error EditorSceneImporterGLTF::_parse_buffer_views(GLTFState &state) {
}
EditorSceneImporterGLTF::GLTFType EditorSceneImporterGLTF::_get_type_from_str(const String &p_string) {
-
- if (p_string == "SCALAR")
+ if (p_string == "SCALAR") {
return TYPE_SCALAR;
+ }
- if (p_string == "VEC2")
+ if (p_string == "VEC2") {
return TYPE_VEC2;
- if (p_string == "VEC3")
+ }
+ if (p_string == "VEC3") {
return TYPE_VEC3;
- if (p_string == "VEC4")
+ }
+ if (p_string == "VEC4") {
return TYPE_VEC4;
+ }
- if (p_string == "MAT2")
+ if (p_string == "MAT2") {
return TYPE_MAT2;
- if (p_string == "MAT3")
+ }
+ if (p_string == "MAT3") {
return TYPE_MAT3;
- if (p_string == "MAT4")
+ }
+ if (p_string == "MAT4") {
return TYPE_MAT4;
+ }
ERR_FAIL_V(TYPE_SCALAR);
}
Error EditorSceneImporterGLTF::_parse_accessors(GLTFState &state) {
-
ERR_FAIL_COND_V(!state.json.has("accessors"), ERR_FILE_CORRUPT);
const Array &accessors = state.json["accessors"];
for (GLTFAccessorIndex i = 0; i < accessors.size(); i++) {
-
const Dictionary &d = accessors[i];
GLTFAccessor accessor;
@@ -527,21 +523,25 @@ Error EditorSceneImporterGLTF::_parse_accessors(GLTFState &state) {
}
String EditorSceneImporterGLTF::_get_component_type_name(const uint32_t p_component) {
-
switch (p_component) {
- case COMPONENT_TYPE_BYTE: return "Byte";
- case COMPONENT_TYPE_UNSIGNED_BYTE: return "UByte";
- case COMPONENT_TYPE_SHORT: return "Short";
- case COMPONENT_TYPE_UNSIGNED_SHORT: return "UShort";
- case COMPONENT_TYPE_INT: return "Int";
- case COMPONENT_TYPE_FLOAT: return "Float";
+ case COMPONENT_TYPE_BYTE:
+ return "Byte";
+ case COMPONENT_TYPE_UNSIGNED_BYTE:
+ return "UByte";
+ case COMPONENT_TYPE_SHORT:
+ return "Short";
+ case COMPONENT_TYPE_UNSIGNED_SHORT:
+ return "UShort";
+ case COMPONENT_TYPE_INT:
+ return "Int";
+ case COMPONENT_TYPE_FLOAT:
+ return "Float";
}
return "<Error>";
}
String EditorSceneImporterGLTF::_get_type_name(const GLTFType p_component) {
-
static const char *names[] = {
"float",
"vec2",
@@ -556,7 +556,6 @@ String EditorSceneImporterGLTF::_get_type_name(const GLTFType p_component) {
}
Error EditorSceneImporterGLTF::_decode_buffer_view(GLTFState &state, double *dst, const GLTFBufferViewIndex p_buffer_view, const int skip_every, const int skip_bytes, const int element_size, const int count, const GLTFType type, const int component_count, const int component_type, const int component_size, const bool normalized, const int byte_offset, const bool for_vertex) {
-
const GLTFBufferView &bv = state.buffer_views[p_buffer_view];
int stride = bv.byte_stride ? bv.byte_stride : element_size;
@@ -582,11 +581,9 @@ Error EditorSceneImporterGLTF::_decode_buffer_view(GLTFState &state, double *dst
//fill everything as doubles
for (int i = 0; i < count; i++) {
-
const uint8_t *src = &bufptr[offset + i * stride];
for (int j = 0; j < component_count; j++) {
-
if (skip_every && j > 0 && (j % skip_every) == 0) {
src += skip_bytes;
}
@@ -644,14 +641,25 @@ Error EditorSceneImporterGLTF::_decode_buffer_view(GLTFState &state, double *dst
}
int EditorSceneImporterGLTF::_get_component_type_size(const int component_type) {
-
switch (component_type) {
- case COMPONENT_TYPE_BYTE: return 1; break;
- case COMPONENT_TYPE_UNSIGNED_BYTE: return 1; break;
- case COMPONENT_TYPE_SHORT: return 2; break;
- case COMPONENT_TYPE_UNSIGNED_SHORT: return 2; break;
- case COMPONENT_TYPE_INT: return 4; break;
- case COMPONENT_TYPE_FLOAT: return 4; break;
+ case COMPONENT_TYPE_BYTE:
+ return 1;
+ break;
+ case COMPONENT_TYPE_UNSIGNED_BYTE:
+ return 1;
+ break;
+ case COMPONENT_TYPE_SHORT:
+ return 2;
+ break;
+ case COMPONENT_TYPE_UNSIGNED_SHORT:
+ return 2;
+ break;
+ case COMPONENT_TYPE_INT:
+ return 4;
+ break;
+ case COMPONENT_TYPE_FLOAT:
+ return 4;
+ break;
default: {
ERR_FAIL_V(0);
}
@@ -660,7 +668,6 @@ int EditorSceneImporterGLTF::_get_component_type_size(const int component_type)
}
Vector<double> EditorSceneImporterGLTF::_decode_accessor(GLTFState &state, const GLTFAccessorIndex p_accessor, const bool p_for_vertex) {
-
//spec, for reference:
//https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#data-alignment
@@ -683,7 +690,6 @@ Vector<double> EditorSceneImporterGLTF::_decode_accessor(GLTFState &state, const
switch (a.component_type) {
case COMPONENT_TYPE_BYTE:
case COMPONENT_TYPE_UNSIGNED_BYTE: {
-
if (a.type == TYPE_MAT2) {
skip_every = 2;
skip_bytes = 2;
@@ -713,12 +719,12 @@ Vector<double> EditorSceneImporterGLTF::_decode_accessor(GLTFState &state, const
double *dst = dst_buffer.ptrw();
if (a.buffer_view >= 0) {
-
ERR_FAIL_INDEX_V(a.buffer_view, state.buffer_views.size(), Vector<double>());
const Error err = _decode_buffer_view(state, dst, a.buffer_view, skip_every, skip_bytes, element_size, a.count, a.type, component_count, a.component_type, component_size, a.normalized, a.byte_offset, p_for_vertex);
- if (err != OK)
+ if (err != OK) {
return Vector<double>();
+ }
} else {
//fill with zeros, as bufferview is not defined.
@@ -734,14 +740,16 @@ Vector<double> EditorSceneImporterGLTF::_decode_accessor(GLTFState &state, const
const int indices_component_size = _get_component_type_size(a.sparse_indices_component_type);
Error err = _decode_buffer_view(state, indices.ptrw(), a.sparse_indices_buffer_view, 0, 0, indices_component_size, a.sparse_count, TYPE_SCALAR, 1, a.sparse_indices_component_type, indices_component_size, false, a.sparse_indices_byte_offset, false);
- if (err != OK)
+ if (err != OK) {
return Vector<double>();
+ }
Vector<double> data;
data.resize(component_count * a.sparse_count);
err = _decode_buffer_view(state, data.ptrw(), a.sparse_values_buffer_view, skip_every, skip_bytes, element_size, a.sparse_count, a.type, component_count, a.component_type, component_size, a.normalized, a.sparse_values_byte_offset, p_for_vertex);
- if (err != OK)
+ if (err != OK) {
return Vector<double>();
+ }
for (int i = 0; i < indices.size(); i++) {
const int write_offset = int(indices[i]) * component_count;
@@ -755,19 +763,19 @@ Vector<double> EditorSceneImporterGLTF::_decode_accessor(GLTFState &state, const
return dst_buffer;
}
-PoolVector<int> EditorSceneImporterGLTF::_decode_accessor_as_ints(GLTFState &state, const GLTFAccessorIndex p_accessor, const bool p_for_vertex) {
-
+Vector<int> EditorSceneImporterGLTF::_decode_accessor_as_ints(GLTFState &state, const GLTFAccessorIndex p_accessor, const bool p_for_vertex) {
const Vector<double> attribs = _decode_accessor(state, p_accessor, p_for_vertex);
- PoolVector<int> ret;
+ Vector<int> ret;
- if (attribs.size() == 0)
+ if (attribs.size() == 0) {
return ret;
+ }
const double *attribs_ptr = attribs.ptr();
const int ret_size = attribs.size();
ret.resize(ret_size);
{
- PoolVector<int>::Write w = ret.write();
+ int *w = ret.ptrw();
for (int i = 0; i < ret_size; i++) {
w[i] = int(attribs_ptr[i]);
}
@@ -775,19 +783,19 @@ PoolVector<int> EditorSceneImporterGLTF::_decode_accessor_as_ints(GLTFState &sta
return ret;
}
-PoolVector<float> EditorSceneImporterGLTF::_decode_accessor_as_floats(GLTFState &state, const GLTFAccessorIndex p_accessor, const bool p_for_vertex) {
-
+Vector<float> EditorSceneImporterGLTF::_decode_accessor_as_floats(GLTFState &state, const GLTFAccessorIndex p_accessor, const bool p_for_vertex) {
const Vector<double> attribs = _decode_accessor(state, p_accessor, p_for_vertex);
- PoolVector<float> ret;
+ Vector<float> ret;
- if (attribs.size() == 0)
+ if (attribs.size() == 0) {
return ret;
+ }
const double *attribs_ptr = attribs.ptr();
const int ret_size = attribs.size();
ret.resize(ret_size);
{
- PoolVector<float>::Write w = ret.write();
+ float *w = ret.ptrw();
for (int i = 0; i < ret_size; i++) {
w[i] = float(attribs_ptr[i]);
}
@@ -795,20 +803,20 @@ PoolVector<float> EditorSceneImporterGLTF::_decode_accessor_as_floats(GLTFState
return ret;
}
-PoolVector<Vector2> EditorSceneImporterGLTF::_decode_accessor_as_vec2(GLTFState &state, const GLTFAccessorIndex p_accessor, const bool p_for_vertex) {
-
+Vector<Vector2> EditorSceneImporterGLTF::_decode_accessor_as_vec2(GLTFState &state, const GLTFAccessorIndex p_accessor, const bool p_for_vertex) {
const Vector<double> attribs = _decode_accessor(state, p_accessor, p_for_vertex);
- PoolVector<Vector2> ret;
+ Vector<Vector2> ret;
- if (attribs.size() == 0)
+ if (attribs.size() == 0) {
return ret;
+ }
ERR_FAIL_COND_V(attribs.size() % 2 != 0, ret);
const double *attribs_ptr = attribs.ptr();
const int ret_size = attribs.size() / 2;
ret.resize(ret_size);
{
- PoolVector<Vector2>::Write w = ret.write();
+ Vector2 *w = ret.ptrw();
for (int i = 0; i < ret_size; i++) {
w[i] = Vector2(attribs_ptr[i * 2 + 0], attribs_ptr[i * 2 + 1]);
}
@@ -816,20 +824,20 @@ PoolVector<Vector2> EditorSceneImporterGLTF::_decode_accessor_as_vec2(GLTFState
return ret;
}
-PoolVector<Vector3> EditorSceneImporterGLTF::_decode_accessor_as_vec3(GLTFState &state, const GLTFAccessorIndex p_accessor, const bool p_for_vertex) {
-
+Vector<Vector3> EditorSceneImporterGLTF::_decode_accessor_as_vec3(GLTFState &state, const GLTFAccessorIndex p_accessor, const bool p_for_vertex) {
const Vector<double> attribs = _decode_accessor(state, p_accessor, p_for_vertex);
- PoolVector<Vector3> ret;
+ Vector<Vector3> ret;
- if (attribs.size() == 0)
+ if (attribs.size() == 0) {
return ret;
+ }
ERR_FAIL_COND_V(attribs.size() % 3 != 0, ret);
const double *attribs_ptr = attribs.ptr();
const int ret_size = attribs.size() / 3;
ret.resize(ret_size);
{
- PoolVector<Vector3>::Write w = ret.write();
+ Vector3 *w = ret.ptrw();
for (int i = 0; i < ret_size; i++) {
w[i] = Vector3(attribs_ptr[i * 3 + 0], attribs_ptr[i * 3 + 1], attribs_ptr[i * 3 + 2]);
}
@@ -837,42 +845,41 @@ PoolVector<Vector3> EditorSceneImporterGLTF::_decode_accessor_as_vec3(GLTFState
return ret;
}
-PoolVector<Color> EditorSceneImporterGLTF::_decode_accessor_as_color(GLTFState &state, const GLTFAccessorIndex p_accessor, const bool p_for_vertex) {
-
+Vector<Color> EditorSceneImporterGLTF::_decode_accessor_as_color(GLTFState &state, const GLTFAccessorIndex p_accessor, const bool p_for_vertex) {
const Vector<double> attribs = _decode_accessor(state, p_accessor, p_for_vertex);
- PoolVector<Color> ret;
+ Vector<Color> ret;
- if (attribs.size() == 0)
+ if (attribs.size() == 0) {
return ret;
+ }
const int type = state.accessors[p_accessor].type;
ERR_FAIL_COND_V(!(type == TYPE_VEC3 || type == TYPE_VEC4), ret);
- int components;
- if (type == TYPE_VEC3) {
- components = 3;
- } else { // TYPE_VEC4
- components = 4;
+ int vec_len = 3;
+ if (type == TYPE_VEC4) {
+ vec_len = 4;
}
- ERR_FAIL_COND_V(attribs.size() % components != 0, ret);
+ ERR_FAIL_COND_V(attribs.size() % vec_len != 0, ret);
const double *attribs_ptr = attribs.ptr();
- const int ret_size = attribs.size() / components;
+ const int ret_size = attribs.size() / vec_len;
ret.resize(ret_size);
{
- PoolVector<Color>::Write w = ret.write();
+ Color *w = ret.ptrw();
for (int i = 0; i < ret_size; i++) {
- w[i] = Color(attribs_ptr[i * 4 + 0], attribs_ptr[i * 4 + 1], attribs_ptr[i * 4 + 2], components == 4 ? attribs_ptr[i * 4 + 3] : 1.0);
+ w[i] = Color(attribs_ptr[i * vec_len + 0], attribs_ptr[i * vec_len + 1], attribs_ptr[i * vec_len + 2], vec_len == 4 ? attribs_ptr[i * 4 + 3] : 1.0);
}
}
return ret;
}
-Vector<Quat> EditorSceneImporterGLTF::_decode_accessor_as_quat(GLTFState &state, const GLTFAccessorIndex p_accessor, const bool p_for_vertex) {
+Vector<Quat> EditorSceneImporterGLTF::_decode_accessor_as_quat(GLTFState &state, const GLTFAccessorIndex p_accessor, const bool p_for_vertex) {
const Vector<double> attribs = _decode_accessor(state, p_accessor, p_for_vertex);
Vector<Quat> ret;
- if (attribs.size() == 0)
+ if (attribs.size() == 0) {
return ret;
+ }
ERR_FAIL_COND_V(attribs.size() % 4 != 0, ret);
const double *attribs_ptr = attribs.ptr();
@@ -885,13 +892,14 @@ Vector<Quat> EditorSceneImporterGLTF::_decode_accessor_as_quat(GLTFState &state,
}
return ret;
}
-Vector<Transform2D> EditorSceneImporterGLTF::_decode_accessor_as_xform2d(GLTFState &state, const GLTFAccessorIndex p_accessor, const bool p_for_vertex) {
+Vector<Transform2D> EditorSceneImporterGLTF::_decode_accessor_as_xform2d(GLTFState &state, const GLTFAccessorIndex p_accessor, const bool p_for_vertex) {
const Vector<double> attribs = _decode_accessor(state, p_accessor, p_for_vertex);
Vector<Transform2D> ret;
- if (attribs.size() == 0)
+ if (attribs.size() == 0) {
return ret;
+ }
ERR_FAIL_COND_V(attribs.size() % 4 != 0, ret);
ret.resize(attribs.size() / 4);
@@ -903,12 +911,12 @@ Vector<Transform2D> EditorSceneImporterGLTF::_decode_accessor_as_xform2d(GLTFSta
}
Vector<Basis> EditorSceneImporterGLTF::_decode_accessor_as_basis(GLTFState &state, const GLTFAccessorIndex p_accessor, bool p_for_vertex) {
-
const Vector<double> attribs = _decode_accessor(state, p_accessor, p_for_vertex);
Vector<Basis> ret;
- if (attribs.size() == 0)
+ if (attribs.size() == 0) {
return ret;
+ }
ERR_FAIL_COND_V(attribs.size() % 9 != 0, ret);
ret.resize(attribs.size() / 9);
@@ -921,12 +929,12 @@ Vector<Basis> EditorSceneImporterGLTF::_decode_accessor_as_basis(GLTFState &stat
}
Vector<Transform> EditorSceneImporterGLTF::_decode_accessor_as_xform(GLTFState &state, const GLTFAccessorIndex p_accessor, const bool p_for_vertex) {
-
const Vector<double> attribs = _decode_accessor(state, p_accessor, p_for_vertex);
Vector<Transform> ret;
- if (attribs.size() == 0)
+ if (attribs.size() == 0) {
return ret;
+ }
ERR_FAIL_COND_V(attribs.size() % 16 != 0, ret);
ret.resize(attribs.size() / 16);
@@ -940,13 +948,12 @@ Vector<Transform> EditorSceneImporterGLTF::_decode_accessor_as_xform(GLTFState &
}
Error EditorSceneImporterGLTF::_parse_meshes(GLTFState &state) {
-
- if (!state.json.has("meshes"))
+ if (!state.json.has("meshes")) {
return OK;
+ }
Array meshes = state.json["meshes"];
for (GLTFMeshIndex i = 0; i < meshes.size(); i++) {
-
print_verbose("glTF: Parsing mesh: " + itos(i));
Dictionary d = meshes[i];
@@ -959,7 +966,6 @@ Error EditorSceneImporterGLTF::_parse_meshes(GLTFState &state) {
const Dictionary &extras = d.has("extras") ? (Dictionary)d["extras"] : Dictionary();
for (int j = 0; j < primitives.size(); j++) {
-
Dictionary p = primitives[j];
Array array;
@@ -976,11 +982,15 @@ Error EditorSceneImporterGLTF::_parse_meshes(GLTFState &state) {
static const Mesh::PrimitiveType primitives2[7] = {
Mesh::PRIMITIVE_POINTS,
Mesh::PRIMITIVE_LINES,
- Mesh::PRIMITIVE_LINE_LOOP,
- Mesh::PRIMITIVE_LINE_STRIP,
+ Mesh::PRIMITIVE_LINES, //loop not supported, should ce converted
+ Mesh::PRIMITIVE_LINES,
Mesh::PRIMITIVE_TRIANGLES,
Mesh::PRIMITIVE_TRIANGLE_STRIP,
- Mesh::PRIMITIVE_TRIANGLE_FAN,
+ Mesh::PRIMITIVE_TRIANGLES, //fan not supported, should be converted
+#ifndef _MSC_VER
+#warning line loop and triangle fan are not supported and need to be converted to lines and triangles
+#endif
+
};
primitive = primitives2[mode];
@@ -1009,10 +1019,10 @@ Error EditorSceneImporterGLTF::_parse_meshes(GLTFState &state) {
array[Mesh::ARRAY_BONES] = _decode_accessor_as_ints(state, a["JOINTS_0"], true);
}
if (a.has("WEIGHTS_0")) {
- PoolVector<float> weights = _decode_accessor_as_floats(state, a["WEIGHTS_0"], true);
+ Vector<float> weights = _decode_accessor_as_floats(state, a["WEIGHTS_0"], true);
{ //gltf does not seem to normalize the weights for some reason..
int wc = weights.size();
- PoolVector<float>::Write w = weights.write();
+ float *w = weights.ptrw();
for (int k = 0; k < wc; k += 4) {
float total = 0.0;
@@ -1032,13 +1042,13 @@ Error EditorSceneImporterGLTF::_parse_meshes(GLTFState &state) {
}
if (p.has("indices")) {
- PoolVector<int> indices = _decode_accessor_as_ints(state, p["indices"], false);
+ Vector<int> indices = _decode_accessor_as_ints(state, p["indices"], false);
if (primitive == Mesh::PRIMITIVE_TRIANGLES) {
//swap around indices, convert ccw to cw for front face
const int is = indices.size();
- const PoolVector<int>::Write w = indices.write();
+ int *w = indices.ptrw();
for (int k = 0; k < is; k += 3) {
SWAP(w[k + 1], w[k + 2]);
}
@@ -1047,13 +1057,13 @@ Error EditorSceneImporterGLTF::_parse_meshes(GLTFState &state) {
} else if (primitive == Mesh::PRIMITIVE_TRIANGLES) {
//generate indices because they need to be swapped for CW/CCW
- const PoolVector<Vector3> &vertices = array[Mesh::ARRAY_VERTEX];
+ const Vector<Vector3> &vertices = array[Mesh::ARRAY_VERTEX];
ERR_FAIL_COND_V(vertices.size() == 0, ERR_PARSE_ERROR);
- PoolVector<int> indices;
+ Vector<int> indices;
const int vs = vertices.size();
indices.resize(vs);
{
- const PoolVector<int>::Write w = indices.write();
+ int *w = indices.ptrw();
for (int k = 0; k < vs; k += 3) {
w[k] = k;
w[k + 1] = k + 2;
@@ -1063,24 +1073,15 @@ Error EditorSceneImporterGLTF::_parse_meshes(GLTFState &state) {
array[Mesh::ARRAY_INDEX] = indices;
}
- bool generated_tangents = false;
- Variant erased_indices;
+ bool generate_tangents = (primitive == Mesh::PRIMITIVE_TRIANGLES && !a.has("TANGENT") && a.has("TEXCOORD_0") && a.has("NORMAL"));
- if (primitive == Mesh::PRIMITIVE_TRIANGLES && !a.has("TANGENT") && a.has("TEXCOORD_0") && a.has("NORMAL")) {
+ if (generate_tangents) {
//must generate mikktspace tangents.. ergh..
Ref<SurfaceTool> st;
st.instance();
st->create_from_triangle_arrays(array);
- if (!p.has("targets")) {
- //morph targets should not be reindexed, as array size might differ
- //removing indices is the best bet here
- st->deindex();
- erased_indices = a[Mesh::ARRAY_INDEX];
- a[Mesh::ARRAY_INDEX] = Variant();
- }
st->generate_tangents();
array = st->commit_to_arrays();
- generated_tangents = true;
}
Array morphs;
@@ -1102,7 +1103,6 @@ Error EditorSceneImporterGLTF::_parse_meshes(GLTFState &state) {
}
for (int k = 0; k < targets.size(); k++) {
-
const Dictionary &t = targets[k];
Array array_copy;
@@ -1115,18 +1115,17 @@ Error EditorSceneImporterGLTF::_parse_meshes(GLTFState &state) {
array_copy[Mesh::ARRAY_INDEX] = Variant();
if (t.has("POSITION")) {
- PoolVector<Vector3> varr = _decode_accessor_as_vec3(state, t["POSITION"], true);
- const PoolVector<Vector3> src_varr = array[Mesh::ARRAY_VERTEX];
+ Vector<Vector3> varr = _decode_accessor_as_vec3(state, t["POSITION"], true);
+ const Vector<Vector3> src_varr = array[Mesh::ARRAY_VERTEX];
const int size = src_varr.size();
ERR_FAIL_COND_V(size == 0, ERR_PARSE_ERROR);
{
-
const int max_idx = varr.size();
varr.resize(size);
- const PoolVector<Vector3>::Write w_varr = varr.write();
- const PoolVector<Vector3>::Read r_varr = varr.read();
- const PoolVector<Vector3>::Read r_src_varr = src_varr.read();
+ Vector3 *w_varr = varr.ptrw();
+ const Vector3 *r_varr = varr.ptr();
+ const Vector3 *r_src_varr = src_varr.ptr();
for (int l = 0; l < size; l++) {
if (l < max_idx) {
w_varr[l] = r_varr[l] + r_src_varr[l];
@@ -1138,17 +1137,17 @@ Error EditorSceneImporterGLTF::_parse_meshes(GLTFState &state) {
array_copy[Mesh::ARRAY_VERTEX] = varr;
}
if (t.has("NORMAL")) {
- PoolVector<Vector3> narr = _decode_accessor_as_vec3(state, t["NORMAL"], true);
- const PoolVector<Vector3> src_narr = array[Mesh::ARRAY_NORMAL];
+ Vector<Vector3> narr = _decode_accessor_as_vec3(state, t["NORMAL"], true);
+ const Vector<Vector3> src_narr = array[Mesh::ARRAY_NORMAL];
int size = src_narr.size();
ERR_FAIL_COND_V(size == 0, ERR_PARSE_ERROR);
{
int max_idx = narr.size();
narr.resize(size);
- const PoolVector<Vector3>::Write w_narr = narr.write();
- const PoolVector<Vector3>::Read r_narr = narr.read();
- const PoolVector<Vector3>::Read r_src_narr = src_narr.read();
+ Vector3 *w_narr = narr.ptrw();
+ const Vector3 *r_narr = narr.ptr();
+ const Vector3 *r_src_narr = src_narr.ptr();
for (int l = 0; l < size; l++) {
if (l < max_idx) {
w_narr[l] = r_narr[l] + r_src_narr[l];
@@ -1160,25 +1159,23 @@ Error EditorSceneImporterGLTF::_parse_meshes(GLTFState &state) {
array_copy[Mesh::ARRAY_NORMAL] = narr;
}
if (t.has("TANGENT")) {
- const PoolVector<Vector3> tangents_v3 = _decode_accessor_as_vec3(state, t["TANGENT"], true);
- const PoolVector<float> src_tangents = array[Mesh::ARRAY_TANGENT];
+ const Vector<Vector3> tangents_v3 = _decode_accessor_as_vec3(state, t["TANGENT"], true);
+ const Vector<float> src_tangents = array[Mesh::ARRAY_TANGENT];
ERR_FAIL_COND_V(src_tangents.size() == 0, ERR_PARSE_ERROR);
- PoolVector<float> tangents_v4;
+ Vector<float> tangents_v4;
{
-
int max_idx = tangents_v3.size();
int size4 = src_tangents.size();
tangents_v4.resize(size4);
- const PoolVector<float>::Write w4 = tangents_v4.write();
+ float *w4 = tangents_v4.ptrw();
- const PoolVector<Vector3>::Read r3 = tangents_v3.read();
- const PoolVector<float>::Read r4 = src_tangents.read();
+ const Vector3 *r3 = tangents_v3.ptr();
+ const float *r4 = src_tangents.ptr();
for (int l = 0; l < size4 / 4; l++) {
-
if (l < max_idx) {
w4[l * 4 + 0] = r3[l].x + r4[l * 4 + 0];
w4[l * 4 + 1] = r3[l].y + r4[l * 4 + 1];
@@ -1195,10 +1192,9 @@ Error EditorSceneImporterGLTF::_parse_meshes(GLTFState &state) {
array_copy[Mesh::ARRAY_TANGENT] = tangents_v4;
}
- if (generated_tangents) {
+ if (generate_tangents) {
Ref<SurfaceTool> st;
st.instance();
- array_copy[Mesh::ARRAY_INDEX] = erased_indices; //needed for tangent generation, erased by deindex
st->create_from_triangle_arrays(array_copy);
st->deindex();
st->generate_tangents();
@@ -1239,13 +1235,12 @@ Error EditorSceneImporterGLTF::_parse_meshes(GLTFState &state) {
}
Error EditorSceneImporterGLTF::_parse_images(GLTFState &state, const String &p_base_path) {
-
- if (!state.json.has("images"))
+ if (!state.json.has("images")) {
return OK;
+ }
const Array &images = state.json["images"];
for (int i = 0; i < images.size(); i++) {
-
const Dictionary &d = images[i];
String mimetype;
@@ -1254,7 +1249,7 @@ Error EditorSceneImporterGLTF::_parse_images(GLTFState &state, const String &p_b
}
Vector<uint8_t> data;
- const uint8_t *data_ptr = NULL;
+ const uint8_t *data_ptr = nullptr;
int data_size = 0;
if (d.has("uri")) {
@@ -1267,9 +1262,8 @@ Error EditorSceneImporterGLTF::_parse_images(GLTFState &state, const String &p_b
data_ptr = data.ptr();
data_size = data.size();
} else {
-
uri = p_base_path.plus_file(uri).replace("\\", "/"); //fix for windows
- Ref<Texture> texture = ResourceLoader::load(uri);
+ Ref<Texture2D> texture = ResourceLoader::load(uri);
state.images.push_back(texture);
continue;
}
@@ -1295,6 +1289,8 @@ Error EditorSceneImporterGLTF::_parse_images(GLTFState &state, const String &p_b
if (mimetype.findn("png") != -1) {
//is a png
+ ERR_FAIL_COND_V(Image::_png_mem_loader_func == nullptr, ERR_UNAVAILABLE);
+
const Ref<Image> img = Image::_png_mem_loader_func(data_ptr, data_size);
ERR_FAIL_COND_V(img.is_null(), ERR_FILE_CORRUPT);
@@ -1309,6 +1305,8 @@ Error EditorSceneImporterGLTF::_parse_images(GLTFState &state, const String &p_b
if (mimetype.findn("jpeg") != -1) {
//is a jpg
+ ERR_FAIL_COND_V(Image::_jpg_mem_loader_func == nullptr, ERR_UNAVAILABLE);
+
const Ref<Image> img = Image::_jpg_mem_loader_func(data_ptr, data_size);
ERR_FAIL_COND_V(img.is_null(), ERR_FILE_CORRUPT);
@@ -1331,13 +1329,12 @@ Error EditorSceneImporterGLTF::_parse_images(GLTFState &state, const String &p_b
}
Error EditorSceneImporterGLTF::_parse_textures(GLTFState &state) {
-
- if (!state.json.has("textures"))
+ if (!state.json.has("textures")) {
return OK;
+ }
const Array &textures = state.json["textures"];
for (GLTFTextureIndex i = 0; i < textures.size(); i++) {
-
const Dictionary &d = textures[i];
ERR_FAIL_COND_V(!d.has("source"), ERR_PARSE_ERROR);
@@ -1350,33 +1347,31 @@ Error EditorSceneImporterGLTF::_parse_textures(GLTFState &state) {
return OK;
}
-Ref<Texture> EditorSceneImporterGLTF::_get_texture(GLTFState &state, const GLTFTextureIndex p_texture) {
- ERR_FAIL_INDEX_V(p_texture, state.textures.size(), Ref<Texture>());
+Ref<Texture2D> EditorSceneImporterGLTF::_get_texture(GLTFState &state, const GLTFTextureIndex p_texture) {
+ ERR_FAIL_INDEX_V(p_texture, state.textures.size(), Ref<Texture2D>());
const GLTFImageIndex image = state.textures[p_texture].src_image;
- ERR_FAIL_INDEX_V(image, state.images.size(), Ref<Texture>());
+ ERR_FAIL_INDEX_V(image, state.images.size(), Ref<Texture2D>());
return state.images[image];
}
Error EditorSceneImporterGLTF::_parse_materials(GLTFState &state) {
-
- if (!state.json.has("materials"))
+ if (!state.json.has("materials")) {
return OK;
+ }
const Array &materials = state.json["materials"];
for (GLTFMaterialIndex i = 0; i < materials.size(); i++) {
-
const Dictionary &d = materials[i];
- Ref<SpatialMaterial> material;
+ Ref<StandardMaterial3D> material;
material.instance();
if (d.has("name")) {
material->set_name(d["name"]);
}
if (d.has("pbrMetallicRoughness")) {
-
const Dictionary &mr = d["pbrMetallicRoughness"];
if (mr.has("baseColorFactor")) {
const Array &arr = mr["baseColorFactor"];
@@ -1389,7 +1384,7 @@ Error EditorSceneImporterGLTF::_parse_materials(GLTFState &state) {
if (mr.has("baseColorTexture")) {
const Dictionary &bct = mr["baseColorTexture"];
if (bct.has("index")) {
- material->set_texture(SpatialMaterial::TEXTURE_ALBEDO, _get_texture(state, bct["index"]));
+ material->set_texture(StandardMaterial3D::TEXTURE_ALBEDO, _get_texture(state, bct["index"]));
}
if (!mr.has("baseColorFactor")) {
material->set_albedo(Color(1, 1, 1));
@@ -1411,11 +1406,11 @@ Error EditorSceneImporterGLTF::_parse_materials(GLTFState &state) {
if (mr.has("metallicRoughnessTexture")) {
const Dictionary &bct = mr["metallicRoughnessTexture"];
if (bct.has("index")) {
- const Ref<Texture> t = _get_texture(state, bct["index"]);
- material->set_texture(SpatialMaterial::TEXTURE_METALLIC, t);
- material->set_metallic_texture_channel(SpatialMaterial::TEXTURE_CHANNEL_BLUE);
- material->set_texture(SpatialMaterial::TEXTURE_ROUGHNESS, t);
- material->set_roughness_texture_channel(SpatialMaterial::TEXTURE_CHANNEL_GREEN);
+ const Ref<Texture2D> t = _get_texture(state, bct["index"]);
+ material->set_texture(StandardMaterial3D::TEXTURE_METALLIC, t);
+ material->set_metallic_texture_channel(StandardMaterial3D::TEXTURE_CHANNEL_BLUE);
+ material->set_texture(StandardMaterial3D::TEXTURE_ROUGHNESS, t);
+ material->set_roughness_texture_channel(StandardMaterial3D::TEXTURE_CHANNEL_GREEN);
if (!mr.has("metallicFactor")) {
material->set_metallic(1);
}
@@ -1429,8 +1424,8 @@ Error EditorSceneImporterGLTF::_parse_materials(GLTFState &state) {
if (d.has("normalTexture")) {
const Dictionary &bct = d["normalTexture"];
if (bct.has("index")) {
- material->set_texture(SpatialMaterial::TEXTURE_NORMAL, _get_texture(state, bct["index"]));
- material->set_feature(SpatialMaterial::FEATURE_NORMAL_MAPPING, true);
+ material->set_texture(StandardMaterial3D::TEXTURE_NORMAL, _get_texture(state, bct["index"]));
+ material->set_feature(StandardMaterial3D::FEATURE_NORMAL_MAPPING, true);
}
if (bct.has("scale")) {
material->set_normal_scale(bct["scale"]);
@@ -1439,9 +1434,9 @@ Error EditorSceneImporterGLTF::_parse_materials(GLTFState &state) {
if (d.has("occlusionTexture")) {
const Dictionary &bct = d["occlusionTexture"];
if (bct.has("index")) {
- material->set_texture(SpatialMaterial::TEXTURE_AMBIENT_OCCLUSION, _get_texture(state, bct["index"]));
- material->set_ao_texture_channel(SpatialMaterial::TEXTURE_CHANNEL_RED);
- material->set_feature(SpatialMaterial::FEATURE_AMBIENT_OCCLUSION, true);
+ material->set_texture(StandardMaterial3D::TEXTURE_AMBIENT_OCCLUSION, _get_texture(state, bct["index"]));
+ material->set_ao_texture_channel(StandardMaterial3D::TEXTURE_CHANNEL_RED);
+ material->set_feature(StandardMaterial3D::FEATURE_AMBIENT_OCCLUSION, true);
}
}
@@ -1449,7 +1444,7 @@ Error EditorSceneImporterGLTF::_parse_materials(GLTFState &state) {
const Array &arr = d["emissiveFactor"];
ERR_FAIL_COND_V(arr.size() != 3, ERR_PARSE_ERROR);
const Color c = Color(arr[0], arr[1], arr[2]).to_srgb();
- material->set_feature(SpatialMaterial::FEATURE_EMISSION, true);
+ material->set_feature(StandardMaterial3D::FEATURE_EMISSION, true);
material->set_emission(c);
}
@@ -1457,8 +1452,8 @@ Error EditorSceneImporterGLTF::_parse_materials(GLTFState &state) {
if (d.has("emissiveTexture")) {
const Dictionary &bct = d["emissiveTexture"];
if (bct.has("index")) {
- material->set_texture(SpatialMaterial::TEXTURE_EMISSION, _get_texture(state, bct["index"]));
- material->set_feature(SpatialMaterial::FEATURE_EMISSION, true);
+ material->set_texture(StandardMaterial3D::TEXTURE_EMISSION, _get_texture(state, bct["index"]));
+ material->set_feature(StandardMaterial3D::FEATURE_EMISSION, true);
material->set_emission(Color(0, 0, 0));
}
}
@@ -1466,15 +1461,21 @@ Error EditorSceneImporterGLTF::_parse_materials(GLTFState &state) {
if (d.has("doubleSided")) {
const bool ds = d["doubleSided"];
if (ds) {
- material->set_cull_mode(SpatialMaterial::CULL_DISABLED);
+ material->set_cull_mode(StandardMaterial3D::CULL_DISABLED);
}
}
if (d.has("alphaMode")) {
const String &am = d["alphaMode"];
- if (am != "OPAQUE") {
- material->set_feature(SpatialMaterial::FEATURE_TRANSPARENT, true);
- material->set_depth_draw_mode(SpatialMaterial::DEPTH_DRAW_ALPHA_OPAQUE_PREPASS);
+ if (am == "BLEND") {
+ material->set_transparency(StandardMaterial3D::TRANSPARENCY_ALPHA_DEPTH_PRE_PASS);
+ } else if (am == "MASK") {
+ material->set_transparency(StandardMaterial3D::TRANSPARENCY_ALPHA_SCISSOR);
+ if (d.has("alphaCutoff")) {
+ material->set_alpha_scissor_threshold(d["alphaCutoff"]);
+ } else {
+ material->set_alpha_scissor_threshold(0.5f);
+ }
}
}
@@ -1487,15 +1488,15 @@ Error EditorSceneImporterGLTF::_parse_materials(GLTFState &state) {
}
EditorSceneImporterGLTF::GLTFNodeIndex EditorSceneImporterGLTF::_find_highest_node(GLTFState &state, const Vector<GLTFNodeIndex> &subset) {
- int heighest = -1;
+ int highest = -1;
GLTFNodeIndex best_node = -1;
for (int i = 0; i < subset.size(); ++i) {
const GLTFNodeIndex node_i = subset[i];
const GLTFNode *node = state.nodes[node_i];
- if (heighest == -1 || node->height < heighest) {
- heighest = node->height;
+ if (highest == -1 || node->height < highest) {
+ highest = node->height;
best_node = node_i;
}
}
@@ -1504,7 +1505,6 @@ EditorSceneImporterGLTF::GLTFNodeIndex EditorSceneImporterGLTF::_find_highest_no
}
bool EditorSceneImporterGLTF::_capture_nodes_in_skin(GLTFState &state, GLTFSkin &skin, const GLTFNodeIndex node_index) {
-
bool found_joint = false;
for (int i = 0; i < state.nodes[node_index]->children.size(); ++i) {
@@ -1528,7 +1528,6 @@ bool EditorSceneImporterGLTF::_capture_nodes_in_skin(GLTFState &state, GLTFSkin
}
void EditorSceneImporterGLTF::_capture_nodes_for_multirooted_skin(GLTFState &state, GLTFSkin &skin) {
-
DisjointSet<GLTFNodeIndex> disjoint_set;
for (int i = 0; i < skin.joints.size(); ++i) {
@@ -1562,7 +1561,6 @@ void EditorSceneImporterGLTF::_capture_nodes_for_multirooted_skin(GLTFState &sta
// Go up the tree till all of the multiple roots of the skin are at the same hierarchy level.
// This sucks, but 99% of all game engines (not just Godot) would have this same issue.
for (int i = 0; i < roots.size(); ++i) {
-
GLTFNodeIndex current_node = roots[i];
while (state.nodes[current_node]->height > maxHeight) {
GLTFNodeIndex parent = state.nodes[current_node]->parent;
@@ -1610,7 +1608,6 @@ void EditorSceneImporterGLTF::_capture_nodes_for_multirooted_skin(GLTFState &sta
}
Error EditorSceneImporterGLTF::_expand_skin(GLTFState &state, GLTFSkin &skin) {
-
_capture_nodes_for_multirooted_skin(state, skin);
// Grab all nodes that lay in between skin joints/nodes
@@ -1656,7 +1653,6 @@ Error EditorSceneImporterGLTF::_expand_skin(GLTFState &state, GLTFSkin &skin) {
}
Error EditorSceneImporterGLTF::_verify_skin(GLTFState &state, GLTFSkin &skin) {
-
// This may seem duplicated from expand_skins, but this is really a sanity check! (so it kinda is)
// In case additional interpolating logic is added to the skins, this will help ensure that you
// do not cause it to self implode into a fiery blaze
@@ -1722,15 +1718,14 @@ Error EditorSceneImporterGLTF::_verify_skin(GLTFState &state, GLTFSkin &skin) {
}
Error EditorSceneImporterGLTF::_parse_skins(GLTFState &state) {
-
- if (!state.json.has("skins"))
+ if (!state.json.has("skins")) {
return OK;
+ }
const Array &skins = state.json["skins"];
// Create the base skins, and mark nodes that are joints
for (int i = 0; i < skins.size(); i++) {
-
const Dictionary &d = skins[i];
GLTFSkin skin;
@@ -1780,7 +1775,6 @@ Error EditorSceneImporterGLTF::_parse_skins(GLTFState &state) {
}
Error EditorSceneImporterGLTF::_determine_skeletons(GLTFState &state) {
-
// Using a disjoint set, we are going to potentially combine all skins that are actually branches
// of a main skeleton, or treat skins defining the same set of nodes as ONE skeleton.
// This is another unclear issue caused by the current glTF specification.
@@ -1816,7 +1810,7 @@ Error EditorSceneImporterGLTF::_determine_skeletons(GLTFState &state) {
skeleton_sets.get_representatives(groups_representatives);
Vector<GLTFNodeIndex> highest_group_members;
- Vector<Vector<GLTFNodeIndex> > groups;
+ Vector<Vector<GLTFNodeIndex>> groups;
for (int i = 0; i < groups_representatives.size(); ++i) {
Vector<GLTFNodeIndex> group;
skeleton_sets.get_members(group, groups_representatives[i]);
@@ -1858,7 +1852,6 @@ Error EditorSceneImporterGLTF::_determine_skeletons(GLTFState &state) {
// Mark all the skins actual skeletons, after we have merged them
for (GLTFSkeletonIndex skel_i = 0; skel_i < skeleton_owners.size(); ++skel_i) {
-
const GLTFNodeIndex skeleton_owner = skeleton_owners[skel_i];
GLTFSkeleton skeleton;
@@ -1913,7 +1906,6 @@ Error EditorSceneImporterGLTF::_determine_skeletons(GLTFState &state) {
}
Error EditorSceneImporterGLTF::_reparent_non_joint_skeleton_subtrees(GLTFState &state, GLTFSkeleton &skeleton, const Vector<GLTFNodeIndex> &non_joints) {
-
DisjointSet<GLTFNodeIndex> subtree_set;
// Populate the disjoint set with ONLY non joints that are in the skeleton hierarchy (non_joints vector)
@@ -1973,8 +1965,9 @@ Error EditorSceneImporterGLTF::_reparent_to_fake_joint(GLTFState &state, GLTFSke
state.nodes.push_back(fake_joint);
// We better not be a joint, or we messed up in our logic
- if (node->joint)
+ if (node->joint) {
return FAILED;
+ }
fake_joint->translation = node->translation;
fake_joint->rotation = node->rotation;
@@ -2028,7 +2021,6 @@ Error EditorSceneImporterGLTF::_reparent_to_fake_joint(GLTFState &state, GLTFSke
}
Error EditorSceneImporterGLTF::_determine_skeleton_roots(GLTFState &state, const GLTFSkeletonIndex skel_i) {
-
DisjointSet<GLTFNodeIndex> disjoint_set;
for (GLTFNodeIndex i = 0; i < state.nodes.size(); ++i) {
@@ -2083,10 +2075,9 @@ Error EditorSceneImporterGLTF::_determine_skeleton_roots(GLTFState &state, const
Error EditorSceneImporterGLTF::_create_skeletons(GLTFState &state) {
for (GLTFSkeletonIndex skel_i = 0; skel_i < state.skeletons.size(); ++skel_i) {
-
GLTFSkeleton &gltf_skeleton = state.skeletons.write[skel_i];
- Skeleton *skeleton = memnew(Skeleton);
+ Skeleton3D *skeleton = memnew(Skeleton3D);
gltf_skeleton.godot_skeleton = skeleton;
// Make a unique name, no gltf node represents this skeleton
@@ -2135,7 +2126,6 @@ Error EditorSceneImporterGLTF::_create_skeletons(GLTFState &state) {
skeleton->add_bone(node->name);
skeleton->set_bone_rest(bone_index, node->xform);
- skeleton->set_bone_pose(bone_index, node->xform);
if (node->parent >= 0 && state.nodes[node->parent]->skeleton == skel_i) {
const int bone_parent = skeleton->find_bone(state.nodes[node->parent]->name);
@@ -2162,6 +2152,8 @@ Error EditorSceneImporterGLTF::_map_skin_joints_indices_to_skeleton_bone_indices
const GLTFNodeIndex node_i = skin.joints_original[joint_index];
const GLTFNode *node = state.nodes[node_i];
+ skin.joint_i_to_name.insert(joint_index, node->name);
+
const int bone_index = skeleton.godot_skeleton->find_bone(node->name);
ERR_FAIL_COND_V(bone_index < 0, FAILED);
@@ -2183,12 +2175,17 @@ Error EditorSceneImporterGLTF::_create_skins(GLTFState &state) {
const bool has_ibms = !gltf_skin.inverse_binds.empty();
for (int joint_i = 0; joint_i < gltf_skin.joints_original.size(); ++joint_i) {
- int bone_i = gltf_skin.joint_i_to_bone_i[joint_i];
-
+ Transform xform;
if (has_ibms) {
- skin->add_bind(bone_i, gltf_skin.inverse_binds[joint_i]);
+ xform = gltf_skin.inverse_binds[joint_i];
+ }
+
+ if (state.use_named_skin_binds) {
+ StringName name = gltf_skin.joint_i_to_name[joint_i];
+ skin->add_named_bind(name, xform);
} else {
- skin->add_bind(bone_i, Transform());
+ int bone_i = gltf_skin.joint_i_to_bone_i[joint_i];
+ skin->add_bind(bone_i, xform);
}
}
@@ -2216,7 +2213,6 @@ bool EditorSceneImporterGLTF::_skins_are_same(const Ref<Skin> &skin_a, const Ref
}
for (int i = 0; i < skin_a->get_bind_count(); ++i) {
-
if (skin_a->get_bind_bone(i) != skin_b->get_bind_bone(i)) {
return false;
}
@@ -2247,21 +2243,19 @@ void EditorSceneImporterGLTF::_remove_duplicate_skins(GLTFState &state) {
}
Error EditorSceneImporterGLTF::_parse_cameras(GLTFState &state) {
-
- if (!state.json.has("cameras"))
+ if (!state.json.has("cameras")) {
return OK;
+ }
const Array &cameras = state.json["cameras"];
for (GLTFCameraIndex i = 0; i < cameras.size(); i++) {
-
const Dictionary &d = cameras[i];
GLTFCamera camera;
ERR_FAIL_COND_V(!d.has("type"), ERR_PARSE_ERROR);
const String &type = d["type"];
if (type == "orthographic") {
-
camera.perspective = false;
if (d.has("orthographic")) {
const Dictionary &og = d["orthographic"];
@@ -2273,7 +2267,6 @@ Error EditorSceneImporterGLTF::_parse_cameras(GLTFState &state) {
}
} else if (type == "perspective") {
-
camera.perspective = true;
if (d.has("perspective")) {
const Dictionary &ppt = d["perspective"];
@@ -2297,33 +2290,37 @@ Error EditorSceneImporterGLTF::_parse_cameras(GLTFState &state) {
}
Error EditorSceneImporterGLTF::_parse_animations(GLTFState &state) {
-
- if (!state.json.has("animations"))
+ if (!state.json.has("animations")) {
return OK;
+ }
const Array &animations = state.json["animations"];
for (GLTFAnimationIndex i = 0; i < animations.size(); i++) {
-
const Dictionary &d = animations[i];
GLTFAnimation animation;
- if (!d.has("channels") || !d.has("samplers"))
+ if (!d.has("channels") || !d.has("samplers")) {
continue;
+ }
Array channels = d["channels"];
Array samplers = d["samplers"];
if (d.has("name")) {
- animation.name = d["name"];
+ String name = d["name"];
+ if (name.begins_with("loop") || name.ends_with("loop") || name.begins_with("cycle") || name.ends_with("cycle")) {
+ animation.loop = true;
+ }
+ animation.name = _sanitize_scene_name(name);
}
for (int j = 0; j < channels.size(); j++) {
-
const Dictionary &c = channels[j];
- if (!c.has("target"))
+ if (!c.has("target")) {
continue;
+ }
const Dictionary &t = c["target"];
if (!t.has("node") || !t.has("path")) {
@@ -2356,6 +2353,7 @@ Error EditorSceneImporterGLTF::_parse_animations(GLTFState &state) {
const int output = s["output"];
GLTFAnimation::Interpolation interp = GLTFAnimation::INTERP_LINEAR;
+ int output_count = 1;
if (s.has("interpolation")) {
const String &in = s["interpolation"];
if (in == "STEP") {
@@ -2364,14 +2362,16 @@ Error EditorSceneImporterGLTF::_parse_animations(GLTFState &state) {
interp = GLTFAnimation::INTERP_LINEAR;
} else if (in == "CATMULLROMSPLINE") {
interp = GLTFAnimation::INTERP_CATMULLROMSPLINE;
+ output_count = 3;
} else if (in == "CUBICSPLINE") {
interp = GLTFAnimation::INTERP_CUBIC_SPLINE;
+ output_count = 3;
}
}
- const PoolVector<float> times = _decode_accessor_as_floats(state, input, false);
+ const Vector<float> times = _decode_accessor_as_floats(state, input, false);
if (path == "translation") {
- const PoolVector<Vector3> translations = _decode_accessor_as_vec3(state, output, false);
+ const Vector<Vector3> translations = _decode_accessor_as_vec3(state, output, false);
track->translation_track.interpolation = interp;
track->translation_track.times = Variant(times); //convert via variant
track->translation_track.values = Variant(translations); //convert via variant
@@ -2381,12 +2381,12 @@ Error EditorSceneImporterGLTF::_parse_animations(GLTFState &state) {
track->rotation_track.times = Variant(times); //convert via variant
track->rotation_track.values = rotations; //convert via variant
} else if (path == "scale") {
- const PoolVector<Vector3> scales = _decode_accessor_as_vec3(state, output, false);
+ const Vector<Vector3> scales = _decode_accessor_as_vec3(state, output, false);
track->scale_track.interpolation = interp;
track->scale_track.times = Variant(times); //convert via variant
track->scale_track.values = Variant(scales); //convert via variant
} else if (path == "weights") {
- const PoolVector<float> weights = _decode_accessor_as_floats(state, output, false);
+ const Vector<float> weights = _decode_accessor_as_floats(state, output, false);
ERR_FAIL_INDEX_V(state.nodes[node]->mesh, state.meshes.size(), ERR_PARSE_ERROR);
const GLTFMesh *mesh = &state.meshes[state.nodes[node]->mesh];
@@ -2395,8 +2395,11 @@ Error EditorSceneImporterGLTF::_parse_animations(GLTFState &state) {
track->weight_tracks.resize(wc);
+ const int expected_value_count = times.size() * output_count * wc;
+ ERR_FAIL_COND_V_MSG(weights.size() != expected_value_count, ERR_PARSE_ERROR, "Invalid weight data, expected " + itos(expected_value_count) + " weight values, got " + itos(weights.size()) + " instead.");
+
const int wlen = weights.size() / wc;
- PoolVector<float>::Read r = weights.read();
+ const float *r = weights.ptr();
for (int k = 0; k < wc; k++) { //separate tracks, having them together is not such a good idea
GLTFAnimation::Channel<float> cf;
cf.interpolation = interp;
@@ -2411,7 +2414,7 @@ Error EditorSceneImporterGLTF::_parse_animations(GLTFState &state) {
track->weight_tracks.write[k] = cf;
}
} else {
- WARN_PRINTS("Invalid path '" + path + "'.");
+ WARN_PRINT("Invalid path '" + path + "'.");
}
}
@@ -2424,13 +2427,13 @@ Error EditorSceneImporterGLTF::_parse_animations(GLTFState &state) {
}
void EditorSceneImporterGLTF::_assign_scene_names(GLTFState &state) {
-
for (int i = 0; i < state.nodes.size(); i++) {
GLTFNode *n = state.nodes[i];
// Any joints get unique names generated when the skeleton is made, unique to the skeleton
- if (n->skeleton >= 0)
+ if (n->skeleton >= 0) {
continue;
+ }
if (n->name.empty()) {
if (n->mesh >= 0) {
@@ -2446,12 +2449,11 @@ void EditorSceneImporterGLTF::_assign_scene_names(GLTFState &state) {
}
}
-BoneAttachment *EditorSceneImporterGLTF::_generate_bone_attachment(GLTFState &state, Skeleton *skeleton, const GLTFNodeIndex node_index) {
-
+BoneAttachment3D *EditorSceneImporterGLTF::_generate_bone_attachment(GLTFState &state, Skeleton3D *skeleton, const GLTFNodeIndex node_index) {
const GLTFNode *gltf_node = state.nodes[node_index];
const GLTFNode *bone_node = state.nodes[gltf_node->parent];
- BoneAttachment *bone_attachment = memnew(BoneAttachment);
+ BoneAttachment3D *bone_attachment = memnew(BoneAttachment3D);
print_verbose("glTF: Creating bone attachment for: " + gltf_node->name);
ERR_FAIL_COND_V(!bone_node->joint, nullptr);
@@ -2461,12 +2463,12 @@ BoneAttachment *EditorSceneImporterGLTF::_generate_bone_attachment(GLTFState &st
return bone_attachment;
}
-MeshInstance *EditorSceneImporterGLTF::_generate_mesh_instance(GLTFState &state, Node *scene_parent, const GLTFNodeIndex node_index) {
+MeshInstance3D *EditorSceneImporterGLTF::_generate_mesh_instance(GLTFState &state, Node *scene_parent, const GLTFNodeIndex node_index) {
const GLTFNode *gltf_node = state.nodes[node_index];
ERR_FAIL_INDEX_V(gltf_node->mesh, state.meshes.size(), nullptr);
- MeshInstance *mi = memnew(MeshInstance);
+ MeshInstance3D *mi = memnew(MeshInstance3D);
print_verbose("glTF: Creating mesh for: " + gltf_node->name);
GLTFMesh &mesh = state.meshes.write[gltf_node->mesh];
@@ -2483,44 +2485,43 @@ MeshInstance *EditorSceneImporterGLTF::_generate_mesh_instance(GLTFState &state,
return mi;
}
-Camera *EditorSceneImporterGLTF::_generate_camera(GLTFState &state, Node *scene_parent, const GLTFNodeIndex node_index) {
+Camera3D *EditorSceneImporterGLTF::_generate_camera(GLTFState &state, Node *scene_parent, const GLTFNodeIndex node_index) {
const GLTFNode *gltf_node = state.nodes[node_index];
ERR_FAIL_INDEX_V(gltf_node->camera, state.cameras.size(), nullptr);
- Camera *camera = memnew(Camera);
+ Camera3D *camera = memnew(Camera3D);
print_verbose("glTF: Creating camera for: " + gltf_node->name);
const GLTFCamera &c = state.cameras[gltf_node->camera];
if (c.perspective) {
- camera->set_perspective(c.fov_size, c.znear, c.znear);
+ camera->set_perspective(c.fov_size, c.znear, c.zfar);
} else {
- camera->set_orthogonal(c.fov_size, c.znear, c.znear);
+ camera->set_orthogonal(c.fov_size, c.znear, c.zfar);
}
return camera;
}
-Spatial *EditorSceneImporterGLTF::_generate_spatial(GLTFState &state, Node *scene_parent, const GLTFNodeIndex node_index) {
+Node3D *EditorSceneImporterGLTF::_generate_spatial(GLTFState &state, Node *scene_parent, const GLTFNodeIndex node_index) {
const GLTFNode *gltf_node = state.nodes[node_index];
- Spatial *spatial = memnew(Spatial);
+ Node3D *spatial = memnew(Node3D);
print_verbose("glTF: Creating spatial for: " + gltf_node->name);
return spatial;
}
-void EditorSceneImporterGLTF::_generate_scene_node(GLTFState &state, Node *scene_parent, Spatial *scene_root, const GLTFNodeIndex node_index) {
-
+void EditorSceneImporterGLTF::_generate_scene_node(GLTFState &state, Node *scene_parent, Node3D *scene_root, const GLTFNodeIndex node_index) {
const GLTFNode *gltf_node = state.nodes[node_index];
- Spatial *current_node = nullptr;
+ Node3D *current_node = nullptr;
// Is our parent a skeleton
- Skeleton *active_skeleton = Object::cast_to<Skeleton>(scene_parent);
+ Skeleton3D *active_skeleton = Object::cast_to<Skeleton3D>(scene_parent);
if (gltf_node->skeleton >= 0) {
- Skeleton *skeleton = state.skeletons[gltf_node->skeleton].godot_skeleton;
+ Skeleton3D *skeleton = state.skeletons[gltf_node->skeleton].godot_skeleton;
if (active_skeleton != skeleton) {
ERR_FAIL_COND_MSG(active_skeleton != nullptr, "glTF: Generating scene detected direct parented Skeletons");
@@ -2538,7 +2539,7 @@ void EditorSceneImporterGLTF::_generate_scene_node(GLTFState &state, Node *scene
// If we have an active skeleton, and the node is node skinned, we need to create a bone attachment
if (current_node == nullptr && active_skeleton != nullptr && gltf_node->skin < 0) {
- BoneAttachment *bone_attachment = _generate_bone_attachment(state, active_skeleton, node_index);
+ BoneAttachment3D *bone_attachment = _generate_bone_attachment(state, active_skeleton, node_index);
scene_parent->add_child(bone_attachment);
bone_attachment->set_owner(scene_root);
@@ -2576,18 +2577,15 @@ void EditorSceneImporterGLTF::_generate_scene_node(GLTFState &state, Node *scene
template <class T>
struct EditorSceneImporterGLTFInterpolate {
-
T lerp(const T &a, const T &b, float c) const {
-
return a + (b - a) * c;
}
T catmull_rom(const T &p0, const T &p1, const T &p2, const T &p3, float t) {
-
const float t2 = t * t;
const float t3 = t2 * t;
- return 0.5f * ((2.0f * p1) + (-p0 + p2) * t + (2.0f * p0 - 5.0f * p1 + 4 * p2 - p3) * t2 + (-p0 + 3.0f * p1 - 3.0f * p2 + p3) * t3);
+ return 0.5f * ((2.0f * p1) + (-p0 + p2) * t + (2.0f * p0 - 5.0f * p1 + 4.0f * p2 - p3) * t2 + (-p0 + 3.0f * p1 - 3.0f * p2 + p3) * t3);
}
T bezier(T start, T control_1, T control_2, T end, float t) {
@@ -2605,24 +2603,23 @@ struct EditorSceneImporterGLTFInterpolate {
// thank you for existing, partial specialization
template <>
struct EditorSceneImporterGLTFInterpolate<Quat> {
-
Quat lerp(const Quat &a, const Quat &b, const float c) const {
- ERR_FAIL_COND_V(!a.is_normalized(), Quat());
- ERR_FAIL_COND_V(!b.is_normalized(), Quat());
+ ERR_FAIL_COND_V_MSG(!a.is_normalized(), Quat(), "The quaternion \"a\" must be normalized.");
+ ERR_FAIL_COND_V_MSG(!b.is_normalized(), Quat(), "The quaternion \"b\" must be normalized.");
return a.slerp(b, c).normalized();
}
Quat catmull_rom(const Quat &p0, const Quat &p1, const Quat &p2, const Quat &p3, const float c) {
- ERR_FAIL_COND_V(!p1.is_normalized(), Quat());
- ERR_FAIL_COND_V(!p2.is_normalized(), Quat());
+ ERR_FAIL_COND_V_MSG(!p1.is_normalized(), Quat(), "The quaternion \"p1\" must be normalized.");
+ ERR_FAIL_COND_V_MSG(!p2.is_normalized(), Quat(), "The quaternion \"p2\" must be normalized.");
return p1.slerp(p2, c).normalized();
}
Quat bezier(const Quat start, const Quat control_1, const Quat control_2, const Quat end, const float t) {
- ERR_FAIL_COND_V(!start.is_normalized(), Quat());
- ERR_FAIL_COND_V(!end.is_normalized(), Quat());
+ ERR_FAIL_COND_V_MSG(!start.is_normalized(), Quat(), "The start quaternion must be normalized.");
+ ERR_FAIL_COND_V_MSG(!end.is_normalized(), Quat(), "The end quaternion must be normalized.");
return start.slerp(end, t).normalized();
}
@@ -2630,12 +2627,12 @@ struct EditorSceneImporterGLTFInterpolate<Quat> {
template <class T>
T EditorSceneImporterGLTF::_interpolate_track(const Vector<float> &p_times, const Vector<T> &p_values, const float p_time, const GLTFAnimation::Interpolation p_interp) {
-
//could use binary search, worth it?
int idx = -1;
for (int i = 0; i < p_times.size(); i++) {
- if (p_times[i] > p_time)
+ if (p_times[i] > p_time) {
break;
+ }
idx++;
}
@@ -2643,7 +2640,6 @@ T EditorSceneImporterGLTF::_interpolate_track(const Vector<float> &p_times, cons
switch (p_interp) {
case GLTFAnimation::INTERP_LINEAR: {
-
if (idx == -1) {
return p_values[0];
} else if (idx >= p_times.size() - 1) {
@@ -2656,7 +2652,6 @@ T EditorSceneImporterGLTF::_interpolate_track(const Vector<float> &p_times, cons
} break;
case GLTFAnimation::INTERP_STEP: {
-
if (idx == -1) {
return p_values[0];
} else if (idx >= p_times.size() - 1) {
@@ -2667,7 +2662,6 @@ T EditorSceneImporterGLTF::_interpolate_track(const Vector<float> &p_times, cons
} break;
case GLTFAnimation::INTERP_CATMULLROMSPLINE: {
-
if (idx == -1) {
return p_values[1];
} else if (idx >= p_times.size() - 1) {
@@ -2680,7 +2674,6 @@ T EditorSceneImporterGLTF::_interpolate_track(const Vector<float> &p_times, cons
} break;
case GLTFAnimation::INTERP_CUBIC_SPLINE: {
-
if (idx == -1) {
return p_values[1];
} else if (idx >= p_times.size() - 1) {
@@ -2703,7 +2696,6 @@ T EditorSceneImporterGLTF::_interpolate_track(const Vector<float> &p_times, cons
}
void EditorSceneImporterGLTF::_import_animation(GLTFState &state, AnimationPlayer *ap, const GLTFAnimationIndex index, const int bake_fps) {
-
const GLTFAnimation &anim = state.animations[index];
String name = anim.name;
@@ -2716,10 +2708,13 @@ void EditorSceneImporterGLTF::_import_animation(GLTFState &state, AnimationPlaye
animation.instance();
animation->set_name(name);
+ if (anim.loop) {
+ animation->set_loop(true);
+ }
+
float length = 0;
for (Map<int, GLTFAnimation::Track>::Element *E = anim.tracks.front(); E; E = E->next()) {
-
const GLTFAnimation::Track &track = E->get();
//need to find the path
NodePath node_path;
@@ -2733,7 +2728,7 @@ void EditorSceneImporterGLTF::_import_animation(GLTFState &state, AnimationPlaye
const GLTFNode *node = state.nodes[E->key()];
if (node->skeleton >= 0) {
- const Skeleton *sk = Object::cast_to<Skeleton>(state.scene_nodes.find(node_index)->get());
+ const Skeleton3D *sk = Object::cast_to<Skeleton3D>(state.scene_nodes.find(node_index)->get());
ERR_FAIL_COND(sk == nullptr);
const String path = ap->get_parent()->get_path_to(sk);
@@ -2787,7 +2782,6 @@ void EditorSceneImporterGLTF::_import_animation(GLTFState &state, AnimationPlaye
bool last = false;
while (true) {
-
Vector3 pos = base_pos;
Quat rot = base_rot;
Vector3 scale = base_scale;
@@ -2805,12 +2799,11 @@ void EditorSceneImporterGLTF::_import_animation(GLTFState &state, AnimationPlaye
}
if (node->skeleton >= 0) {
-
Transform xform;
xform.basis.set_quat_scale(rot, scale);
xform.origin = pos;
- const Skeleton *skeleton = state.skeletons[node->skeleton].godot_skeleton;
+ const Skeleton3D *skeleton = state.skeletons[node->skeleton].godot_skeleton;
const int bone_idx = skeleton->find_bone(node->name);
xform = skeleton->get_bone_rest(bone_idx).affine_inverse() * xform;
@@ -2879,7 +2872,7 @@ void EditorSceneImporterGLTF::_import_animation(GLTFState &state, AnimationPlaye
ap->add_animation(name, animation);
}
-void EditorSceneImporterGLTF::_process_mesh_instances(GLTFState &state, Spatial *scene_root) {
+void EditorSceneImporterGLTF::_process_mesh_instances(GLTFState &state, Node3D *scene_root) {
for (GLTFNodeIndex node_i = 0; node_i < state.nodes.size(); ++node_i) {
const GLTFNode *node = state.nodes[node_i];
@@ -2887,12 +2880,12 @@ void EditorSceneImporterGLTF::_process_mesh_instances(GLTFState &state, Spatial
const GLTFSkinIndex skin_i = node->skin;
Map<GLTFNodeIndex, Node *>::Element *mi_element = state.scene_nodes.find(node_i);
- MeshInstance *mi = Object::cast_to<MeshInstance>(mi_element->get());
+ MeshInstance3D *mi = Object::cast_to<MeshInstance3D>(mi_element->get());
ERR_FAIL_COND(mi == nullptr);
const GLTFSkeletonIndex skel_i = state.skins[node->skin].skeleton;
const GLTFSkeleton &gltf_skeleton = state.skeletons[skel_i];
- Skeleton *skeleton = gltf_skeleton.godot_skeleton;
+ Skeleton3D *skeleton = gltf_skeleton.godot_skeleton;
ERR_FAIL_COND(skeleton == nullptr);
mi->get_parent()->remove_child(mi);
@@ -2906,9 +2899,8 @@ void EditorSceneImporterGLTF::_process_mesh_instances(GLTFState &state, Spatial
}
}
-Spatial *EditorSceneImporterGLTF::_generate_scene(GLTFState &state, const int p_bake_fps) {
-
- Spatial *root = memnew(Spatial);
+Node3D *EditorSceneImporterGLTF::_generate_scene(GLTFState &state, const int p_bake_fps) {
+ Node3D *root = memnew(Node3D);
// scene_name is already unique
root->set_name(state.scene_name);
@@ -2934,119 +2926,135 @@ Spatial *EditorSceneImporterGLTF::_generate_scene(GLTFState &state, const int p_
}
Node *EditorSceneImporterGLTF::import_scene(const String &p_path, uint32_t p_flags, int p_bake_fps, List<String> *r_missing_deps, Error *r_err) {
-
GLTFState state;
if (p_path.to_lower().ends_with("glb")) {
//binary file
//text file
Error err = _parse_glb(p_path, state);
- if (err)
- return NULL;
+ if (err) {
+ return nullptr;
+ }
} else {
//text file
Error err = _parse_json(p_path, state);
- if (err)
- return NULL;
+ if (err) {
+ return nullptr;
+ }
}
- ERR_FAIL_COND_V(!state.json.has("asset"), NULL);
+ ERR_FAIL_COND_V(!state.json.has("asset"), nullptr);
Dictionary asset = state.json["asset"];
- ERR_FAIL_COND_V(!asset.has("version"), NULL);
+ ERR_FAIL_COND_V(!asset.has("version"), nullptr);
String version = asset["version"];
state.major_version = version.get_slice(".", 0).to_int();
state.minor_version = version.get_slice(".", 1).to_int();
+ state.use_named_skin_binds = p_flags & IMPORT_USE_NAMED_SKIN_BINDS;
/* STEP 0 PARSE SCENE */
Error err = _parse_scenes(state);
- if (err != OK)
- return NULL;
+ if (err != OK) {
+ return nullptr;
+ }
/* STEP 1 PARSE NODES */
err = _parse_nodes(state);
- if (err != OK)
- return NULL;
+ if (err != OK) {
+ return nullptr;
+ }
/* STEP 2 PARSE BUFFERS */
err = _parse_buffers(state, p_path.get_base_dir());
- if (err != OK)
- return NULL;
+ if (err != OK) {
+ return nullptr;
+ }
/* STEP 3 PARSE BUFFER VIEWS */
err = _parse_buffer_views(state);
- if (err != OK)
- return NULL;
+ if (err != OK) {
+ return nullptr;
+ }
/* STEP 4 PARSE ACCESSORS */
err = _parse_accessors(state);
- if (err != OK)
- return NULL;
+ if (err != OK) {
+ return nullptr;
+ }
/* STEP 5 PARSE IMAGES */
err = _parse_images(state, p_path.get_base_dir());
- if (err != OK)
- return NULL;
+ if (err != OK) {
+ return nullptr;
+ }
/* STEP 6 PARSE TEXTURES */
err = _parse_textures(state);
- if (err != OK)
- return NULL;
+ if (err != OK) {
+ return nullptr;
+ }
/* STEP 7 PARSE TEXTURES */
err = _parse_materials(state);
- if (err != OK)
- return NULL;
+ if (err != OK) {
+ return nullptr;
+ }
/* STEP 9 PARSE SKINS */
err = _parse_skins(state);
- if (err != OK)
- return NULL;
+ if (err != OK) {
+ return nullptr;
+ }
/* STEP 10 DETERMINE SKELETONS */
err = _determine_skeletons(state);
- if (err != OK)
- return NULL;
+ if (err != OK) {
+ return nullptr;
+ }
/* STEP 11 CREATE SKELETONS */
err = _create_skeletons(state);
- if (err != OK)
- return NULL;
+ if (err != OK) {
+ return nullptr;
+ }
/* STEP 12 CREATE SKINS */
err = _create_skins(state);
- if (err != OK)
- return NULL;
+ if (err != OK) {
+ return nullptr;
+ }
/* STEP 13 PARSE MESHES (we have enough info now) */
err = _parse_meshes(state);
- if (err != OK)
- return NULL;
+ if (err != OK) {
+ return nullptr;
+ }
/* STEP 14 PARSE CAMERAS */
err = _parse_cameras(state);
- if (err != OK)
- return NULL;
+ if (err != OK) {
+ return nullptr;
+ }
/* STEP 15 PARSE ANIMATIONS */
err = _parse_animations(state);
- if (err != OK)
- return NULL;
+ if (err != OK) {
+ return nullptr;
+ }
/* STEP 16 ASSIGN SCENE NAMES */
_assign_scene_names(state);
/* STEP 17 MAKE SCENE! */
- Spatial *scene = _generate_scene(state, p_bake_fps);
+ Node3D *scene = _generate_scene(state, p_bake_fps);
return scene;
}
Ref<Animation> EditorSceneImporterGLTF::import_animation(const String &p_path, uint32_t p_flags, int p_bake_fps) {
-
return Ref<Animation>();
}
diff --git a/editor/import/editor_scene_importer_gltf.h b/editor/import/editor_scene_importer_gltf.h
index 6021bf10c8..eee978ce16 100644
--- a/editor/import/editor_scene_importer_gltf.h
+++ b/editor/import/editor_scene_importer_gltf.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -32,15 +32,14 @@
#define EDITOR_SCENE_IMPORTER_GLTF_H
#include "editor/import/resource_importer_scene.h"
-#include "scene/3d/skeleton.h"
-#include "scene/3d/spatial.h"
+#include "scene/3d/node_3d.h"
+#include "scene/3d/skeleton_3d.h"
class AnimationPlayer;
-class BoneAttachment;
-class MeshInstance;
+class BoneAttachment3D;
+class MeshInstance3D;
class EditorSceneImporterGLTF : public EditorSceneImporter {
-
GDCLASS(EditorSceneImporterGLTF, EditorSceneImporter);
typedef int GLTFAccessorIndex;
@@ -92,89 +91,59 @@ class EditorSceneImporterGLTF : public EditorSceneImporter {
String _get_type_name(const GLTFType p_component);
struct GLTFNode {
-
//matrices need to be transformed to this
- GLTFNodeIndex parent;
- int height;
+ GLTFNodeIndex parent = -1;
+ int height = -1;
Transform xform;
String name;
- GLTFMeshIndex mesh;
- GLTFCameraIndex camera;
- GLTFSkinIndex skin;
+ GLTFMeshIndex mesh = -1;
+ GLTFCameraIndex camera = -1;
+ GLTFSkinIndex skin = -1;
- GLTFSkeletonIndex skeleton;
- bool joint;
+ GLTFSkeletonIndex skeleton = -1;
+ bool joint = false;
Vector3 translation;
Quat rotation;
- Vector3 scale;
+ Vector3 scale = Vector3(1, 1, 1);
Vector<int> children;
- GLTFNodeIndex fake_joint_parent;
-
- GLTFNode() :
- parent(-1),
- height(-1),
- mesh(-1),
- camera(-1),
- skin(-1),
- skeleton(-1),
- joint(false),
- translation(0, 0, 0),
- scale(Vector3(1, 1, 1)),
- fake_joint_parent(-1) {}
+ GLTFNodeIndex fake_joint_parent = -1;
+
+ GLTFNode() {}
};
struct GLTFBufferView {
-
- GLTFBufferIndex buffer;
- int byte_offset;
- int byte_length;
- int byte_stride;
- bool indices;
+ GLTFBufferIndex buffer = -1;
+ int byte_offset = 0;
+ int byte_length = 0;
+ int byte_stride = 0;
+ bool indices = false;
//matrices need to be transformed to this
- GLTFBufferView() :
- buffer(-1),
- byte_offset(0),
- byte_length(0),
- byte_stride(0),
- indices(false) {
- }
+ GLTFBufferView() {}
};
struct GLTFAccessor {
-
- GLTFBufferViewIndex buffer_view;
- int byte_offset;
- int component_type;
- bool normalized;
- int count;
+ GLTFBufferViewIndex buffer_view = 0;
+ int byte_offset = 0;
+ int component_type = 0;
+ bool normalized = false;
+ int count = 0;
GLTFType type;
- float min;
- float max;
- int sparse_count;
- int sparse_indices_buffer_view;
- int sparse_indices_byte_offset;
- int sparse_indices_component_type;
- int sparse_values_buffer_view;
- int sparse_values_byte_offset;
-
- GLTFAccessor() {
- buffer_view = 0;
- byte_offset = 0;
- component_type = 0;
- normalized = false;
- count = 0;
- min = 0;
- max = 0;
- sparse_count = 0;
- sparse_indices_byte_offset = 0;
- sparse_values_byte_offset = 0;
- }
+ float min = 0;
+ float max = 0;
+ int sparse_count = 0;
+ int sparse_indices_buffer_view = 0;
+ int sparse_indices_byte_offset = 0;
+ int sparse_indices_component_type = 0;
+ int sparse_values_buffer_view = 0;
+ int sparse_values_byte_offset = 0;
+
+ GLTFAccessor() {}
};
struct GLTFTexture {
GLTFImageIndex src_image;
@@ -189,21 +158,19 @@ class EditorSceneImporterGLTF : public EditorSceneImporter {
Vector<GLTFNodeIndex> roots;
// The created Skeleton for the scene
- Skeleton *godot_skeleton;
+ Skeleton3D *godot_skeleton = nullptr;
// Set of unique bone names for the skeleton
Set<String> unique_names;
- GLTFSkeleton() :
- godot_skeleton(nullptr) {
- }
+ GLTFSkeleton() {}
};
struct GLTFSkin {
String name;
// The "skeleton" property defined in the gltf spec. -1 = Scene Root
- GLTFNodeIndex skin_root;
+ GLTFNodeIndex skin_root = -1;
Vector<GLTFNodeIndex> joints_original;
Vector<Transform> inverse_binds;
@@ -223,19 +190,18 @@ class EditorSceneImporterGLTF : public EditorSceneImporter {
Vector<GLTFNodeIndex> roots;
// The GLTF Skeleton this Skin points to (after we determine skeletons)
- GLTFSkeletonIndex skeleton;
+ GLTFSkeletonIndex skeleton = -1;
// A mapping from the joint indices (in the order of joints_original) to the
// Godot Skeleton's bone_indices
Map<int, int> joint_i_to_bone_i;
+ Map<int, StringName> joint_i_to_name;
// The Actual Skin that will be created as a mapping between the IBM's of this skin
// to the generated skeleton for the mesh instances.
Ref<Skin> godot_skin;
- GLTFSkin() :
- skin_root(-1),
- skeleton(-1) {}
+ GLTFSkin() {}
};
struct GLTFMesh {
@@ -244,21 +210,16 @@ class EditorSceneImporterGLTF : public EditorSceneImporter {
};
struct GLTFCamera {
+ bool perspective = true;
+ float fov_size = 64;
+ float zfar = 500;
+ float znear = 0.1;
- bool perspective;
- float fov_size;
- float zfar;
- float znear;
-
- GLTFCamera() {
- perspective = true;
- fov_size = 65;
- zfar = 500;
- znear = 0.1;
- }
+ GLTFCamera() {}
};
struct GLTFAnimation {
+ bool loop = false;
enum Interpolation {
INTERP_LINEAR,
@@ -275,11 +236,10 @@ class EditorSceneImporterGLTF : public EditorSceneImporter {
};
struct Track {
-
Channel<Vector3> translation_track;
Channel<Quat> rotation_track;
Channel<Vector3> scale_track;
- Vector<Channel<float> > weight_tracks;
+ Vector<Channel<float>> weight_tracks;
};
String name;
@@ -288,25 +248,26 @@ class EditorSceneImporterGLTF : public EditorSceneImporter {
};
struct GLTFState {
-
Dictionary json;
int major_version;
int minor_version;
Vector<uint8_t> glb_data;
+ bool use_named_skin_binds;
+
Vector<GLTFNode *> nodes;
- Vector<Vector<uint8_t> > buffers;
+ Vector<Vector<uint8_t>> buffers;
Vector<GLTFBufferView> buffer_views;
Vector<GLTFAccessor> accessors;
Vector<GLTFMesh> meshes; //meshes are loaded directly, no reason not to.
- Vector<Ref<Material> > materials;
+ Vector<Ref<Material>> materials;
String scene_name;
Vector<int> root_nodes;
Vector<GLTFTexture> textures;
- Vector<Ref<Texture> > images;
+ Vector<Ref<Texture2D>> images;
Vector<GLTFSkin> skins;
Vector<GLTFCamera> cameras;
@@ -331,7 +292,7 @@ class EditorSceneImporterGLTF : public EditorSceneImporter {
String _sanitize_bone_name(const String &name);
String _gen_unique_bone_name(GLTFState &state, const GLTFSkeletonIndex skel_i, const String &p_name);
- Ref<Texture> _get_texture(GLTFState &state, const GLTFTextureIndex p_texture);
+ Ref<Texture2D> _get_texture(GLTFState &state, const GLTFTextureIndex p_texture);
Error _parse_json(const String &p_path, GLTFState &state);
Error _parse_glb(const String &p_path, GLTFState &state);
@@ -348,11 +309,11 @@ class EditorSceneImporterGLTF : public EditorSceneImporter {
Error _decode_buffer_view(GLTFState &state, double *dst, const GLTFBufferViewIndex p_buffer_view, const int skip_every, const int skip_bytes, const int element_size, const int count, const GLTFType type, const int component_count, const int component_type, const int component_size, const bool normalized, const int byte_offset, const bool for_vertex);
Vector<double> _decode_accessor(GLTFState &state, const GLTFAccessorIndex p_accessor, const bool p_for_vertex);
- PoolVector<float> _decode_accessor_as_floats(GLTFState &state, const GLTFAccessorIndex p_accessor, const bool p_for_vertex);
- PoolVector<int> _decode_accessor_as_ints(GLTFState &state, const GLTFAccessorIndex p_accessor, const bool p_for_vertex);
- PoolVector<Vector2> _decode_accessor_as_vec2(GLTFState &state, const GLTFAccessorIndex p_accessor, const bool p_for_vertex);
- PoolVector<Vector3> _decode_accessor_as_vec3(GLTFState &state, const GLTFAccessorIndex p_accessor, const bool p_for_vertex);
- PoolVector<Color> _decode_accessor_as_color(GLTFState &state, const GLTFAccessorIndex p_accessor, const bool p_for_vertex);
+ Vector<float> _decode_accessor_as_floats(GLTFState &state, const GLTFAccessorIndex p_accessor, const bool p_for_vertex);
+ Vector<int> _decode_accessor_as_ints(GLTFState &state, const GLTFAccessorIndex p_accessor, const bool p_for_vertex);
+ Vector<Vector2> _decode_accessor_as_vec2(GLTFState &state, const GLTFAccessorIndex p_accessor, const bool p_for_vertex);
+ Vector<Vector3> _decode_accessor_as_vec3(GLTFState &state, const GLTFAccessorIndex p_accessor, const bool p_for_vertex);
+ Vector<Color> _decode_accessor_as_color(GLTFState &state, const GLTFAccessorIndex p_accessor, const bool p_for_vertex);
Vector<Quat> _decode_accessor_as_quat(GLTFState &state, const GLTFAccessorIndex p_accessor, const bool p_for_vertex);
Vector<Transform2D> _decode_accessor_as_xform2d(GLTFState &state, const GLTFAccessorIndex p_accessor, const bool p_for_vertex);
Vector<Basis> _decode_accessor_as_basis(GLTFState &state, const GLTFAccessorIndex p_accessor, const bool p_for_vertex);
@@ -388,15 +349,15 @@ class EditorSceneImporterGLTF : public EditorSceneImporter {
Error _parse_animations(GLTFState &state);
- BoneAttachment *_generate_bone_attachment(GLTFState &state, Skeleton *skeleton, const GLTFNodeIndex node_index);
- MeshInstance *_generate_mesh_instance(GLTFState &state, Node *scene_parent, const GLTFNodeIndex node_index);
- Camera *_generate_camera(GLTFState &state, Node *scene_parent, const GLTFNodeIndex node_index);
- Spatial *_generate_spatial(GLTFState &state, Node *scene_parent, const GLTFNodeIndex node_index);
+ BoneAttachment3D *_generate_bone_attachment(GLTFState &state, Skeleton3D *skeleton, const GLTFNodeIndex node_index);
+ MeshInstance3D *_generate_mesh_instance(GLTFState &state, Node *scene_parent, const GLTFNodeIndex node_index);
+ Camera3D *_generate_camera(GLTFState &state, Node *scene_parent, const GLTFNodeIndex node_index);
+ Node3D *_generate_spatial(GLTFState &state, Node *scene_parent, const GLTFNodeIndex node_index);
- void _generate_scene_node(GLTFState &state, Node *scene_parent, Spatial *scene_root, const GLTFNodeIndex node_index);
- Spatial *_generate_scene(GLTFState &state, const int p_bake_fps);
+ void _generate_scene_node(GLTFState &state, Node *scene_parent, Node3D *scene_root, const GLTFNodeIndex node_index);
+ Node3D *_generate_scene(GLTFState &state, const int p_bake_fps);
- void _process_mesh_instances(GLTFState &state, Spatial *scene_root);
+ void _process_mesh_instances(GLTFState &state, Node3D *scene_root);
void _assign_scene_names(GLTFState &state);
@@ -408,7 +369,7 @@ class EditorSceneImporterGLTF : public EditorSceneImporter {
public:
virtual uint32_t get_import_flags() const;
virtual void get_extensions(List<String> *r_extensions) const;
- virtual Node *import_scene(const String &p_path, uint32_t p_flags, int p_bake_fps, List<String> *r_missing_deps = NULL, Error *r_err = NULL);
+ virtual Node *import_scene(const String &p_path, uint32_t p_flags, int p_bake_fps, List<String> *r_missing_deps = nullptr, Error *r_err = nullptr);
virtual Ref<Animation> import_animation(const String &p_path, uint32_t p_flags, int p_bake_fps);
EditorSceneImporterGLTF();
diff --git a/editor/import/resource_importer_bitmask.cpp b/editor/import/resource_importer_bitmask.cpp
index 18e53fc783..da2d1c9bdf 100644
--- a/editor/import/resource_importer_bitmask.cpp
+++ b/editor/import/resource_importer_bitmask.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -38,55 +38,51 @@
#include "scene/resources/texture.h"
String ResourceImporterBitMap::get_importer_name() const {
-
return "bitmap";
}
String ResourceImporterBitMap::get_visible_name() const {
-
return "BitMap";
}
-void ResourceImporterBitMap::get_recognized_extensions(List<String> *p_extensions) const {
+void ResourceImporterBitMap::get_recognized_extensions(List<String> *p_extensions) const {
ImageLoader::get_recognized_extensions(p_extensions);
}
+
String ResourceImporterBitMap::get_save_extension() const {
return "res";
}
String ResourceImporterBitMap::get_resource_type() const {
-
return "BitMap";
}
bool ResourceImporterBitMap::get_option_visibility(const String &p_option, const Map<StringName, Variant> &p_options) const {
-
return true;
}
int ResourceImporterBitMap::get_preset_count() const {
return 0;
}
-String ResourceImporterBitMap::get_preset_name(int p_idx) const {
+String ResourceImporterBitMap::get_preset_name(int p_idx) const {
return String();
}
void ResourceImporterBitMap::get_import_options(List<ImportOption> *r_options, int p_preset) const {
-
r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "create_from", PROPERTY_HINT_ENUM, "Black & White,Alpha"), 0));
- r_options->push_back(ImportOption(PropertyInfo(Variant::REAL, "threshold", PROPERTY_HINT_RANGE, "0,1,0.01"), 0.5));
+ r_options->push_back(ImportOption(PropertyInfo(Variant::FLOAT, "threshold", PROPERTY_HINT_RANGE, "0,1,0.01"), 0.5));
}
Error ResourceImporterBitMap::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) {
-
int create_from = p_options["create_from"];
float threshold = p_options["threshold"];
Ref<Image> image;
image.instance();
Error err = ImageLoader::load_image(p_source_file, image);
- if (err != OK)
+ if (err != OK) {
return err;
+ }
int w = image->get_width();
int h = image->get_height();
@@ -94,11 +90,9 @@ Error ResourceImporterBitMap::import(const String &p_source_file, const String &
Ref<BitMap> bitmap;
bitmap.instance();
bitmap->create(Size2(w, h));
- image->lock();
for (int i = 0; i < h; i++) {
for (int j = 0; j < w; j++) {
-
bool bit;
Color c = image->get_pixel(j, i);
if (create_from == 0) { //b&W
diff --git a/editor/import/resource_importer_bitmask.h b/editor/import/resource_importer_bitmask.h
index 6ae7608ff2..927fac566e 100644
--- a/editor/import/resource_importer_bitmask.h
+++ b/editor/import/resource_importer_bitmask.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -51,7 +51,7 @@ public:
virtual void get_import_options(List<ImportOption> *r_options, int p_preset = 0) const;
virtual bool get_option_visibility(const String &p_option, const Map<StringName, Variant> &p_options) const;
- virtual Error 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 = NULL, Variant *r_metadata = NULL);
+ virtual Error 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 = nullptr, Variant *r_metadata = nullptr);
ResourceImporterBitMap();
~ResourceImporterBitMap();
diff --git a/editor/import/resource_importer_csv.cpp b/editor/import/resource_importer_csv.cpp
index 64b5309cab..d29ba28a96 100644
--- a/editor/import/resource_importer_csv.cpp
+++ b/editor/import/resource_importer_csv.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -34,16 +34,14 @@
#include "core/os/file_access.h"
String ResourceImporterCSV::get_importer_name() const {
-
return "csv";
}
String ResourceImporterCSV::get_visible_name() const {
-
return "CSV";
}
-void ResourceImporterCSV::get_recognized_extensions(List<String> *p_extensions) const {
+void ResourceImporterCSV::get_recognized_extensions(List<String> *p_extensions) const {
p_extensions->push_back("csv");
}
@@ -52,20 +50,18 @@ String ResourceImporterCSV::get_save_extension() const {
}
String ResourceImporterCSV::get_resource_type() const {
-
return "TextFile";
}
bool ResourceImporterCSV::get_option_visibility(const String &p_option, const Map<StringName, Variant> &p_options) const {
-
return true;
}
int ResourceImporterCSV::get_preset_count() const {
return 0;
}
-String ResourceImporterCSV::get_preset_name(int p_idx) const {
+String ResourceImporterCSV::get_preset_name(int p_idx) const {
return "";
}
diff --git a/editor/import/resource_importer_csv.h b/editor/import/resource_importer_csv.h
index 7d06bdb188..7aa48f68de 100644
--- a/editor/import/resource_importer_csv.h
+++ b/editor/import/resource_importer_csv.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -49,7 +49,7 @@ public:
virtual void get_import_options(List<ImportOption> *r_options, int p_preset = 0) const;
virtual bool get_option_visibility(const String &p_option, const Map<StringName, Variant> &p_options) const;
- virtual Error 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 = NULL, Variant *r_metadata = NULL);
+ virtual Error 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 = nullptr, Variant *r_metadata = nullptr);
ResourceImporterCSV();
};
diff --git a/editor/import/resource_importer_csv_translation.cpp b/editor/import/resource_importer_csv_translation.cpp
index d988e1dcc3..04e20dee86 100644
--- a/editor/import/resource_importer_csv_translation.cpp
+++ b/editor/import/resource_importer_csv_translation.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -36,16 +36,14 @@
#include "core/translation.h"
String ResourceImporterCSVTranslation::get_importer_name() const {
-
return "csv_translation";
}
String ResourceImporterCSVTranslation::get_visible_name() const {
-
return "CSV Translation";
}
-void ResourceImporterCSVTranslation::get_recognized_extensions(List<String> *p_extensions) const {
+void ResourceImporterCSVTranslation::get_recognized_extensions(List<String> *p_extensions) const {
p_extensions->push_back("csv");
}
@@ -54,38 +52,40 @@ String ResourceImporterCSVTranslation::get_save_extension() const {
}
String ResourceImporterCSVTranslation::get_resource_type() const {
-
return "Translation";
}
bool ResourceImporterCSVTranslation::get_option_visibility(const String &p_option, const Map<StringName, Variant> &p_options) const {
-
return true;
}
int ResourceImporterCSVTranslation::get_preset_count() const {
return 0;
}
-String ResourceImporterCSVTranslation::get_preset_name(int p_idx) const {
+String ResourceImporterCSVTranslation::get_preset_name(int p_idx) const {
return "";
}
void ResourceImporterCSVTranslation::get_import_options(List<ImportOption> *r_options, int p_preset) const {
-
r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "compress"), true));
r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "delimiter", PROPERTY_HINT_ENUM, "Comma,Semicolon,Tab"), 0));
}
Error ResourceImporterCSVTranslation::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) {
-
bool compress = p_options["compress"];
String delimiter;
switch ((int)p_options["delimiter"]) {
- case 0: delimiter = ","; break;
- case 1: delimiter = ";"; break;
- case 2: delimiter = "\t"; break;
+ case 0:
+ delimiter = ",";
+ break;
+ case 1:
+ delimiter = ";";
+ break;
+ case 2:
+ delimiter = "\t";
+ break;
}
FileAccessRef f = FileAccess::open(p_source_file, FileAccess::READ);
@@ -96,10 +96,9 @@ Error ResourceImporterCSVTranslation::import(const String &p_source_file, const
ERR_FAIL_COND_V(line.size() <= 1, ERR_PARSE_ERROR);
Vector<String> locales;
- Vector<Ref<Translation> > translations;
+ Vector<Ref<Translation>> translations;
for (int i = 1; i < line.size(); i++) {
-
String locale = line[i];
ERR_FAIL_COND_V_MSG(!TranslationServer::is_locale_valid(locale), ERR_PARSE_ERROR, "Error importing CSV translation: '" + locale + "' is not a valid locale.");
@@ -113,10 +112,8 @@ Error ResourceImporterCSVTranslation::import(const String &p_source_file, const
line = f->get_csv_line(delimiter);
while (line.size() == locales.size() + 1) {
-
String key = line[0];
if (key != "") {
-
for (int i = 1; i < line.size(); i++) {
translations.write[i - 1]->add_message(key, line[i].c_unescape());
}
diff --git a/editor/import/resource_importer_csv_translation.h b/editor/import/resource_importer_csv_translation.h
index c2753b326f..742f6b8f60 100644
--- a/editor/import/resource_importer_csv_translation.h
+++ b/editor/import/resource_importer_csv_translation.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -49,7 +49,7 @@ public:
virtual void get_import_options(List<ImportOption> *r_options, int p_preset = 0) const;
virtual bool get_option_visibility(const String &p_option, const Map<StringName, Variant> &p_options) const;
- virtual Error 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 = NULL, Variant *r_metadata = NULL);
+ virtual Error 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 = nullptr, Variant *r_metadata = nullptr);
ResourceImporterCSVTranslation();
};
diff --git a/editor/import/resource_importer_image.cpp b/editor/import/resource_importer_image.cpp
index 3d7663ba8f..885b00865b 100644
--- a/editor/import/resource_importer_image.cpp
+++ b/editor/import/resource_importer_image.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -36,16 +36,14 @@
#include "scene/resources/texture.h"
String ResourceImporterImage::get_importer_name() const {
-
return "image";
}
String ResourceImporterImage::get_visible_name() const {
-
return "Image";
}
-void ResourceImporterImage::get_recognized_extensions(List<String> *p_extensions) const {
+void ResourceImporterImage::get_recognized_extensions(List<String> *p_extensions) const {
ImageLoader::get_recognized_extensions(p_extensions);
}
@@ -54,20 +52,18 @@ String ResourceImporterImage::get_save_extension() const {
}
String ResourceImporterImage::get_resource_type() const {
-
return "Image";
}
bool ResourceImporterImage::get_option_visibility(const String &p_option, const Map<StringName, Variant> &p_options) const {
-
return true;
}
int ResourceImporterImage::get_preset_count() const {
return 0;
}
-String ResourceImporterImage::get_preset_name(int p_idx) const {
+String ResourceImporterImage::get_preset_name(int p_idx) const {
return String();
}
@@ -75,7 +71,6 @@ void ResourceImporterImage::get_import_options(List<ImportOption> *r_options, in
}
Error ResourceImporterImage::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) {
-
FileAccess *f = FileAccess::open(p_source_file, FileAccess::READ);
ERR_FAIL_COND_V_MSG(!f, ERR_CANT_OPEN, "Cannot open file from path '" + p_source_file + "'.");
diff --git a/editor/import/resource_importer_image.h b/editor/import/resource_importer_image.h
index beadf5a8ea..abb74d0665 100644
--- a/editor/import/resource_importer_image.h
+++ b/editor/import/resource_importer_image.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -50,7 +50,7 @@ public:
virtual void get_import_options(List<ImportOption> *r_options, int p_preset = 0) const;
virtual bool get_option_visibility(const String &p_option, const Map<StringName, Variant> &p_options) const;
- virtual Error 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 = NULL, Variant *r_metadata = NULL);
+ virtual Error 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 = nullptr, Variant *r_metadata = nullptr);
ResourceImporterImage();
};
diff --git a/editor/import/resource_importer_layered_texture.cpp b/editor/import/resource_importer_layered_texture.cpp
index 7e3c4cecf4..1f39a12c25 100644
--- a/editor/import/resource_importer_layered_texture.cpp
+++ b/editor/import/resource_importer_layered_texture.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -36,208 +36,247 @@
#include "core/io/image_loader.h"
#include "editor/editor_file_system.h"
#include "editor/editor_node.h"
+#include "resource_importer_texture.h"
#include "scene/resources/texture.h"
String ResourceImporterLayeredTexture::get_importer_name() const {
+ switch (mode) {
+ case MODE_CUBEMAP: {
+ return "cubemap_texture";
+ } break;
+ case MODE_2D_ARRAY: {
+ return "2d_array_texture";
+ } break;
+ case MODE_CUBEMAP_ARRAY: {
+ return "cubemap_array_texture";
+ } break;
+ case MODE_3D: {
+ return "cubemap_3d_texture";
+ } break;
+ }
- return is_3d ? "texture_3d" : "texture_array";
+ ERR_FAIL_V("");
}
String ResourceImporterLayeredTexture::get_visible_name() const {
+ switch (mode) {
+ case MODE_CUBEMAP: {
+ return "Cubemap";
+ } break;
+ case MODE_2D_ARRAY: {
+ return "Texture2DArray";
+ } break;
+ case MODE_CUBEMAP_ARRAY: {
+ return "CubemapArray";
+ } break;
+ case MODE_3D: {
+ return "3D";
+ } break;
+ }
- return is_3d ? "Texture3D" : "TextureArray";
+ ERR_FAIL_V("");
}
-void ResourceImporterLayeredTexture::get_recognized_extensions(List<String> *p_extensions) const {
+void ResourceImporterLayeredTexture::get_recognized_extensions(List<String> *p_extensions) const {
ImageLoader::get_recognized_extensions(p_extensions);
}
+
String ResourceImporterLayeredTexture::get_save_extension() const {
- return is_3d ? "tex3d" : "texarr";
+ switch (mode) {
+ case MODE_CUBEMAP: {
+ return "scube";
+ } break;
+ case MODE_2D_ARRAY: {
+ return "stexarray";
+ } break;
+ case MODE_CUBEMAP_ARRAY: {
+ return "scubearray";
+ } break;
+ case MODE_3D: {
+ return "stex3d";
+ } break;
+ }
+
+ ERR_FAIL_V(String());
}
String ResourceImporterLayeredTexture::get_resource_type() const {
-
- return is_3d ? "Texture3D" : "TextureArray";
+ switch (mode) {
+ case MODE_CUBEMAP: {
+ return "StreamCubemap";
+ } break;
+ case MODE_2D_ARRAY: {
+ return "StreamTexture2DArray";
+ } break;
+ case MODE_CUBEMAP_ARRAY: {
+ return "StreamCubemapArray";
+ } break;
+ case MODE_3D: {
+ return "StreamTexture3D";
+ } break;
+ }
+ ERR_FAIL_V(String());
}
bool ResourceImporterLayeredTexture::get_option_visibility(const String &p_option, const Map<StringName, Variant> &p_options) const {
-
+ if (p_option == "compress/lossy_quality" && p_options.has("compress/mode")) {
+ return int(p_options["compress/mode"]) == COMPRESS_LOSSY;
+ }
return true;
}
int ResourceImporterLayeredTexture::get_preset_count() const {
- return 3;
+ return 0;
}
-String ResourceImporterLayeredTexture::get_preset_name(int p_idx) const {
- static const char *preset_names[] = {
- "3D",
- "2D",
- "ColorCorrect"
- };
-
- return preset_names[p_idx];
+String ResourceImporterLayeredTexture::get_preset_name(int p_idx) const {
+ return "";
}
void ResourceImporterLayeredTexture::get_import_options(List<ImportOption> *r_options, int p_preset) const {
-
- r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "compress/mode", PROPERTY_HINT_ENUM, "Lossless,Video RAM,Uncompressed", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), p_preset == PRESET_3D ? 1 : 0));
- r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "compress/no_bptc_if_rgb"), false));
- r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "flags/repeat", PROPERTY_HINT_ENUM, "Disabled,Enabled,Mirrored"), 0));
- r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "flags/filter"), true));
- r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "flags/mipmaps"), p_preset == PRESET_COLOR_CORRECT ? 0 : 1));
- r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "flags/srgb", PROPERTY_HINT_ENUM, "Disable,Enable"), p_preset == PRESET_3D ? 1 : 0));
- r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "slices/horizontal", PROPERTY_HINT_RANGE, "1,256,1"), p_preset == PRESET_COLOR_CORRECT ? 16 : 8));
- r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "slices/vertical", PROPERTY_HINT_RANGE, "1,256,1"), p_preset == PRESET_COLOR_CORRECT ? 1 : 8));
-}
-
-void ResourceImporterLayeredTexture::_save_tex(const Vector<Ref<Image> > &p_images, const String &p_to_path, int p_compress_mode, Image::CompressMode p_vram_compression, bool p_mipmaps, int p_texture_flags) {
-
- FileAccess *f = FileAccess::open(p_to_path, FileAccess::WRITE);
- f->store_8('G');
- f->store_8('D');
- if (is_3d) {
- f->store_8('3');
- } else {
- f->store_8('A');
- }
- f->store_8('T'); //godot streamable texture
-
- f->store_32(p_images[0]->get_width());
- f->store_32(p_images[0]->get_height());
- f->store_32(p_images.size()); //depth
- f->store_32(p_texture_flags);
- if (p_compress_mode != COMPRESS_VIDEO_RAM) {
- //vram needs to do a first compression to tell what the format is, for the rest its ok
- f->store_32(p_images[0]->get_format());
- f->store_32(p_compress_mode); // 0 - lossless (PNG), 1 - vram, 2 - uncompressed
+ r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "compress/mode", PROPERTY_HINT_ENUM, "Lossless,Lossy,Video RAM,Uncompressed,Basis Universal", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), 1));
+ r_options->push_back(ImportOption(PropertyInfo(Variant::FLOAT, "compress/lossy_quality", PROPERTY_HINT_RANGE, "0,1,0.01"), 0.7));
+ r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "compress/hdr_compression", PROPERTY_HINT_ENUM, "Disabled,Opaque Only,Always"), 1));
+ r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "compress/bptc_ldr", PROPERTY_HINT_ENUM, "Disabled,Enabled,RGBA Only"), 0));
+ r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "compress/channel_pack", PROPERTY_HINT_ENUM, "sRGB Friendly,Optimized"), 0));
+ r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "mipmaps/generate"), true));
+ r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "mipmaps/limit", PROPERTY_HINT_RANGE, "-1,256"), -1));
+
+ if (mode == MODE_2D_ARRAY || mode == MODE_3D) {
+ r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "slices/horizontal", PROPERTY_HINT_RANGE, "1,256,1"), 8));
+ r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "slices/vertical", PROPERTY_HINT_RANGE, "1,256,1"), 8));
}
-
- if ((p_compress_mode == COMPRESS_LOSSLESS) && p_images[0]->get_format() > Image::FORMAT_RGBA8) {
- p_compress_mode = COMPRESS_UNCOMPRESSED; //these can't go as lossy
+ if (mode == MODE_CUBEMAP || mode == MODE_CUBEMAP_ARRAY) {
+ r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "slices/arrangement", PROPERTY_HINT_ENUM, "1x6,2x3,3x2,6x1"), 1));
+ if (mode == MODE_CUBEMAP_ARRAY) {
+ r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "slices/layout", PROPERTY_HINT_ENUM, "Horizontal,Vertical"), 1));
+ r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "slices/amount", PROPERTY_HINT_RANGE, "1,1024,1,or_greater"), 1));
+ }
}
+}
+void ResourceImporterLayeredTexture::_save_tex(Vector<Ref<Image>> p_images, const String &p_to_path, int p_compress_mode, float p_lossy, Image::CompressMode p_vram_compression, Image::CompressSource p_csource, Image::UsedChannels used_channels, bool p_mipmaps, bool p_force_po2) {
for (int i = 0; i < p_images.size(); i++) {
+ if (p_force_po2) {
+ p_images.write[i]->resize_to_po2();
+ }
- switch (p_compress_mode) {
- case COMPRESS_LOSSLESS: {
-
- Ref<Image> image = p_images[i]->duplicate();
- if (p_mipmaps) {
- image->generate_mipmaps();
- } else {
- image->clear_mipmaps();
- }
+ if (p_mipmaps) {
+ p_images.write[i]->generate_mipmaps();
+ } else {
+ p_images.write[i]->clear_mipmaps();
+ }
+ }
- int mmc = image->get_mipmap_count() + 1;
- f->store_32(mmc);
+ FileAccessRef f = FileAccess::open(p_to_path, FileAccess::WRITE);
+ f->store_8('G');
+ f->store_8('S');
+ f->store_8('T');
+ f->store_8('L');
- for (int j = 0; j < mmc; j++) {
+ f->store_32(StreamTextureLayered::FORMAT_VERSION);
+ f->store_32(p_images.size());
+ f->store_32(mode);
+ f->store_32(0); //dataformat
+ f->store_32(0); //mipmap limit
- if (j > 0) {
- image->shrink_x2();
- }
+ //reserverd
+ f->store_32(0);
+ f->store_32(0);
+ f->store_32(0);
- PoolVector<uint8_t> data = Image::lossless_packer(image);
- int data_len = data.size();
- f->store_32(data_len);
+ for (int i = 0; i < p_images.size(); i++) {
+ ResourceImporterTexture::save_to_stex_format(f, p_images[i], ResourceImporterTexture::CompressMode(p_compress_mode), used_channels, p_vram_compression, p_lossy);
+ }
- PoolVector<uint8_t>::Read r = data.read();
- f->store_buffer(r.ptr(), data_len);
- }
+ f->close();
+}
+Error ResourceImporterLayeredTexture::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) {
+ int compress_mode = p_options["compress/mode"];
+ float lossy = p_options["compress/lossy_quality"];
+ int hdr_compression = p_options["compress/hdr_compression"];
+ int bptc_ldr = p_options["compress/bptc_ldr"];
+ bool mipmaps = p_options["mipmaps/generate"];
+ //bool mipmap_limit = p_options["mipmaps/limit"];
+
+ int channel_pack = p_options["compress/channel_pack"];
+ int hslices = (p_options.has("slices/horizontal")) ? int(p_options["slices/horizontal"]) : 0;
+ int vslices = (p_options.has("slices/vertical")) ? int(p_options["slices/vertical"]) : 0;
+ int arrangement = (p_options.has("slices/arrangement")) ? int(p_options["slices/arrangement"]) : 0;
+ int layout = (p_options.has("slices/layout")) ? int(p_options["slices/layout"]) : 0;
+ int amount = (p_options.has("slices/amount")) ? int(p_options["slices/amount"]) : 0;
+
+ if (mode == MODE_CUBEMAP || mode == MODE_CUBEMAP_ARRAY) {
+ switch (arrangement) {
+ case CUBEMAP_FORMAT_1X6: {
+ hslices = 1;
+ vslices = 6;
} break;
- case COMPRESS_VIDEO_RAM: {
-
- Ref<Image> image = p_images[i]->duplicate();
- image->generate_mipmaps(false);
-
- Image::CompressSource csource = Image::COMPRESS_SOURCE_LAYERED;
- image->compress(p_vram_compression, csource, 0.7);
-
- if (i == 0) {
- //hack so we can properly tell the format
- f->store_32(image->get_format());
- f->store_32(p_compress_mode); // 0 - lossless (PNG), 1 - vram, 2 - uncompressed
- }
-
- PoolVector<uint8_t> data = image->get_data();
- int dl = data.size();
-
- PoolVector<uint8_t>::Read r = data.read();
- f->store_buffer(r.ptr(), dl);
+ case CUBEMAP_FORMAT_2X3: {
+ hslices = 2;
+ vslices = 3;
} break;
- case COMPRESS_UNCOMPRESSED: {
-
- Ref<Image> image = p_images[i]->duplicate();
-
- if (p_mipmaps) {
- image->generate_mipmaps();
- } else {
- image->clear_mipmaps();
- }
-
- PoolVector<uint8_t> data = image->get_data();
- int dl = data.size();
-
- PoolVector<uint8_t>::Read r = data.read();
-
- f->store_buffer(r.ptr(), dl);
-
+ case CUBEMAP_FORMAT_3X2: {
+ hslices = 3;
+ vslices = 2;
+ } break;
+ case CUBEMAP_FORMAT_6X1: {
+ hslices = 6;
+ vslices = 1;
} break;
}
- }
- memdelete(f);
-}
-
-Error ResourceImporterLayeredTexture::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) {
-
- int compress_mode = p_options["compress/mode"];
- int no_bptc_if_rgb = p_options["compress/no_bptc_if_rgb"];
- int repeat = p_options["flags/repeat"];
- bool filter = p_options["flags/filter"];
- bool mipmaps = p_options["flags/mipmaps"];
- int srgb = p_options["flags/srgb"];
- int hslices = p_options["slices/horizontal"];
- int vslices = p_options["slices/vertical"];
+ if (mode == MODE_CUBEMAP_ARRAY) {
+ if (layout == 0) {
+ hslices *= amount;
+ } else {
+ vslices *= amount;
+ }
+ }
+ }
Ref<Image> image;
image.instance();
- Error err = ImageLoader::load_image(p_source_file, image, NULL, false, 1.0);
- if (err != OK)
+ Error err = ImageLoader::load_image(p_source_file, image, nullptr, false, 1.0);
+ if (err != OK) {
return err;
+ }
- int tex_flags = 0;
- if (repeat > 0)
- tex_flags |= Texture::FLAG_REPEAT;
- if (repeat == 2)
- tex_flags |= Texture::FLAG_MIRRORED_REPEAT;
- if (filter)
- tex_flags |= Texture::FLAG_FILTER;
- if (mipmaps || compress_mode == COMPRESS_VIDEO_RAM)
- tex_flags |= Texture::FLAG_MIPMAPS;
- if (srgb == 1)
- tex_flags |= Texture::FLAG_CONVERT_TO_LINEAR;
-
- Vector<Ref<Image> > slices;
+ if (compress_mode == COMPRESS_BASIS_UNIVERSAL && image->get_format() >= Image::FORMAT_RF) {
+ //basis universal does not support float formats, fall back
+ compress_mode = COMPRESS_VRAM_COMPRESSED;
+ }
- int slice_w = image->get_width() / hslices;
- int slice_h = image->get_height() / vslices;
+ if (compress_mode == COMPRESS_VRAM_COMPRESSED) {
+ mipmaps = true;
+ }
//optimize
- if (compress_mode == COMPRESS_VIDEO_RAM) {
+ if (compress_mode == COMPRESS_VRAM_COMPRESSED) {
//if using video ram, optimize
- if (srgb) {
+ if (channel_pack == 0) {
//remove alpha if not needed, so compression is more efficient
if (image->get_format() == Image::FORMAT_RGBA8 && !image->detect_alpha()) {
image->convert(Image::FORMAT_RGB8);
}
- } else {
+ } else if (image->get_format() < Image::FORMAT_RGBA8) {
image->optimize_channels();
}
}
+ Image::CompressSource csource = Image::COMPRESS_SOURCE_GENERIC;
+ if (channel_pack == 0) {
+ csource = Image::COMPRESS_SOURCE_SRGB;
+ }
+
+ Image::UsedChannels used_channels = image->detect_used_channels(csource);
+
+ Vector<Ref<Image>> slices;
+
+ int slice_w = image->get_width() / hslices;
+ int slice_h = image->get_height() / vslices;
+
for (int i = 0; i < vslices; i++) {
for (int j = 0; j < hslices; j++) {
int x = slice_w * j;
@@ -254,58 +293,77 @@ Error ResourceImporterLayeredTexture::import(const String &p_source_file, const
String extension = get_save_extension();
Array formats_imported;
- if (compress_mode == COMPRESS_VIDEO_RAM) {
+ if (compress_mode == COMPRESS_VRAM_COMPRESSED) {
//must import in all formats, in order of priority (so platform choses the best supported one. IE, etc2 over etc).
//Android, GLES 2.x
bool ok_on_pc = false;
- bool encode_bptc = false;
+ bool is_hdr = (image->get_format() >= Image::FORMAT_RF && image->get_format() <= Image::FORMAT_RGBE9995);
+ bool is_ldr = (image->get_format() >= Image::FORMAT_L8 && image->get_format() <= Image::FORMAT_RGB565);
+ bool can_bptc = ProjectSettings::get_singleton()->get("rendering/vram_compression/import_bptc");
+ bool can_s3tc = ProjectSettings::get_singleton()->get("rendering/vram_compression/import_s3tc");
- if (ProjectSettings::get_singleton()->get("rendering/vram_compression/import_bptc")) {
-
- encode_bptc = true;
-
- if (no_bptc_if_rgb) {
- Image::DetectChannels channels = image->get_detected_channels();
- if (channels != Image::DETECTED_LA && channels != Image::DETECTED_RGBA) {
- encode_bptc = false;
+ if (can_bptc) {
+ formats_imported.push_back("bptc"); //needs to be aded anyway
+ }
+ bool can_compress_hdr = hdr_compression > 0;
+
+ if (is_hdr && can_compress_hdr) {
+ if (used_channels == Image::USED_CHANNELS_LA || used_channels == Image::USED_CHANNELS_RGBA) {
+ //can compress hdr, but hdr with alpha is not compressible
+
+ if (hdr_compression == 2) {
+ //but user selected to compress hdr anyway, so force an alpha-less format.
+ if (image->get_format() == Image::FORMAT_RGBAF) {
+ for (int i = 0; i < slices.size(); i++) {
+ slices.write[i]->convert(Image::FORMAT_RGBF);
+ }
+
+ } else if (image->get_format() == Image::FORMAT_RGBAH) {
+ for (int i = 0; i < slices.size(); i++) {
+ slices.write[i]->convert(Image::FORMAT_RGBH);
+ }
+ }
+ } else {
+ can_compress_hdr = false;
}
}
- formats_imported.push_back("bptc");
+ if (can_compress_hdr) {
+ if (!can_bptc) {
+ //default to rgbe
+ if (image->get_format() != Image::FORMAT_RGBE9995) {
+ for (int i = 0; i < slices.size(); i++) {
+ slices.write[i]->convert(Image::FORMAT_RGBE9995);
+ }
+ }
+ }
+ } else {
+ can_bptc = false;
+ }
}
- if (encode_bptc) {
-
- _save_tex(slices, p_save_path + ".bptc." + extension, compress_mode, Image::COMPRESS_BPTC, mipmaps, tex_flags);
- r_platform_variants->push_back("bptc");
- ok_on_pc = true;
+ if (is_ldr && can_bptc) {
+ if (bptc_ldr == 0 || (bptc_ldr == 1 && !(used_channels == Image::USED_CHANNELS_LA || used_channels == Image::USED_CHANNELS_RGBA))) {
+ can_bptc = false;
+ }
}
- if (ProjectSettings::get_singleton()->get("rendering/vram_compression/import_s3tc")) {
-
- _save_tex(slices, p_save_path + ".s3tc." + extension, compress_mode, Image::COMPRESS_S3TC, mipmaps, tex_flags);
+ if (can_bptc || can_s3tc) {
+ _save_tex(slices, p_save_path + ".s3tc." + extension, compress_mode, lossy, can_bptc ? Image::COMPRESS_BPTC : Image::COMPRESS_S3TC, csource, used_channels, mipmaps, false);
r_platform_variants->push_back("s3tc");
- ok_on_pc = true;
formats_imported.push_back("s3tc");
+ ok_on_pc = true;
}
if (ProjectSettings::get_singleton()->get("rendering/vram_compression/import_etc2")) {
-
- _save_tex(slices, p_save_path + ".etc2." + extension, compress_mode, Image::COMPRESS_ETC2, mipmaps, tex_flags);
+ _save_tex(slices, p_save_path + ".etc2." + extension, compress_mode, lossy, Image::COMPRESS_ETC2, csource, used_channels, mipmaps, true);
r_platform_variants->push_back("etc2");
formats_imported.push_back("etc2");
}
- if (ProjectSettings::get_singleton()->get("rendering/vram_compression/import_etc")) {
- _save_tex(slices, p_save_path + ".etc." + extension, compress_mode, Image::COMPRESS_ETC, mipmaps, tex_flags);
- r_platform_variants->push_back("etc");
- formats_imported.push_back("etc");
- }
-
if (ProjectSettings::get_singleton()->get("rendering/vram_compression/import_pvrtc")) {
-
- _save_tex(slices, p_save_path + ".pvrtc." + extension, compress_mode, Image::COMPRESS_PVRTC4, mipmaps, tex_flags);
+ _save_tex(slices, p_save_path + ".etc2." + extension, compress_mode, lossy, Image::COMPRESS_ETC2, csource, used_channels, mipmaps, true);
r_platform_variants->push_back("pvrtc");
formats_imported.push_back("pvrtc");
}
@@ -315,12 +373,12 @@ Error ResourceImporterLayeredTexture::import(const String &p_source_file, const
}
} else {
//import normally
- _save_tex(slices, p_save_path + "." + extension, compress_mode, Image::COMPRESS_S3TC /*this is ignored */, mipmaps, tex_flags);
+ _save_tex(slices, p_save_path + "." + extension, compress_mode, lossy, Image::COMPRESS_S3TC /* IGNORED */, csource, used_channels, mipmaps, false);
}
if (r_metadata) {
Dictionary metadata;
- metadata["vram_texture"] = compress_mode == COMPRESS_VIDEO_RAM;
+ metadata["vram_texture"] = compress_mode == COMPRESS_VRAM_COMPRESSED;
if (formats_imported.size()) {
metadata["imported_formats"] = formats_imported;
}
@@ -336,10 +394,9 @@ const char *ResourceImporterLayeredTexture::compression_formats[] = {
"etc",
"etc2",
"pvrtc",
- NULL
+ nullptr
};
String ResourceImporterLayeredTexture::get_import_settings_string() const {
-
String s;
int index = 0;
@@ -356,7 +413,6 @@ String ResourceImporterLayeredTexture::get_import_settings_string() const {
}
bool ResourceImporterLayeredTexture::are_import_settings_valid(const String &p_path) const {
-
//will become invalid if formats are missing to import
Dictionary metadata = ResourceFormatImporter::get_singleton()->get_resource_metadata(p_path);
@@ -391,12 +447,11 @@ bool ResourceImporterLayeredTexture::are_import_settings_valid(const String &p_p
return valid;
}
-ResourceImporterLayeredTexture *ResourceImporterLayeredTexture::singleton = NULL;
+ResourceImporterLayeredTexture *ResourceImporterLayeredTexture::singleton = nullptr;
ResourceImporterLayeredTexture::ResourceImporterLayeredTexture() {
-
singleton = this;
- is_3d = true;
+ mode = MODE_CUBEMAP;
}
ResourceImporterLayeredTexture::~ResourceImporterLayeredTexture() {
diff --git a/editor/import/resource_importer_layered_texture.h b/editor/import/resource_importer_layered_texture.h
index d6acbbabca..18eaf31f6b 100644
--- a/editor/import/resource_importer_layered_texture.h
+++ b/editor/import/resource_importer_layered_texture.h
@@ -5,8 +5,38 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+/*************************************************************************/
+/* resource_importer_layered_texture.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -34,18 +64,38 @@
#include "core/image.h"
#include "core/io/resource_importer.h"
-class StreamTexture;
+class StreamTexture2D;
class ResourceImporterLayeredTexture : public ResourceImporter {
GDCLASS(ResourceImporterLayeredTexture, ResourceImporter);
- bool is_3d;
+public:
+ enum Mode {
+ MODE_2D_ARRAY,
+ MODE_CUBEMAP,
+ MODE_CUBEMAP_ARRAY,
+ MODE_3D,
+ };
+
+ enum CubemapFormat {
+ CUBEMAP_FORMAT_1X6,
+ CUBEMAP_FORMAT_2X3,
+ CUBEMAP_FORMAT_3X2,
+ CUBEMAP_FORMAT_6X1,
+ };
+
+ enum TextureFlags {
+ TEXTURE_FLAGS_MIPMAPS = 1
+ };
+
+private:
+ Mode mode;
static const char *compression_formats[];
protected:
- static void _texture_reimport_srgb(const Ref<StreamTexture> &p_tex);
- static void _texture_reimport_3d(const Ref<StreamTexture> &p_tex);
- static void _texture_reimport_normal(const Ref<StreamTexture> &p_tex);
+ static void _texture_reimport_srgb(const Ref<StreamTexture2D> &p_tex);
+ static void _texture_reimport_3d(const Ref<StreamTexture2D> &p_tex);
+ static void _texture_reimport_normal(const Ref<StreamTexture2D> &p_tex);
static ResourceImporterLayeredTexture *singleton;
@@ -57,16 +107,12 @@ public:
virtual String get_save_extension() const;
virtual String get_resource_type() const;
- enum Preset {
- PRESET_3D,
- PRESET_2D,
- PRESET_COLOR_CORRECT,
- };
-
enum CompressMode {
COMPRESS_LOSSLESS,
- COMPRESS_VIDEO_RAM,
- COMPRESS_UNCOMPRESSED
+ COMPRESS_LOSSY,
+ COMPRESS_VRAM_COMPRESSED,
+ COMPRESS_VRAM_UNCOMPRESSED,
+ COMPRESS_BASIS_UNIVERSAL
};
virtual int get_preset_count() const;
@@ -75,17 +121,19 @@ public:
virtual void get_import_options(List<ImportOption> *r_options, int p_preset = 0) const;
virtual bool get_option_visibility(const String &p_option, const Map<StringName, Variant> &p_options) const;
- void _save_tex(const Vector<Ref<Image> > &p_images, const String &p_to_path, int p_compress_mode, Image::CompressMode p_vram_compression, bool p_mipmaps, int p_texture_flags);
+ void _save_tex(Vector<Ref<Image>> p_images, const String &p_to_path, int p_compress_mode, float p_lossy, Image::CompressMode p_vram_compression, Image::CompressSource p_csource, Image::UsedChannels used_channels, bool p_mipmaps, bool p_force_po2);
- virtual Error 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 = NULL, Variant *r_metadata = NULL);
+ virtual Error 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 = nullptr, Variant *r_metadata = nullptr);
void update_imports();
virtual bool are_import_settings_valid(const String &p_path) const;
virtual String get_import_settings_string() const;
- void set_3d(bool p_3d) { is_3d = p_3d; }
+ void set_mode(Mode p_mode) { mode = p_mode; }
+
ResourceImporterLayeredTexture();
~ResourceImporterLayeredTexture();
};
+
#endif // RESOURCE_IMPORTER_LAYERED_TEXTURE_H
diff --git a/editor/import/resource_importer_obj.cpp b/editor/import/resource_importer_obj.cpp
index 31a099ef83..49b47bf4be 100644
--- a/editor/import/resource_importer_obj.cpp
+++ b/editor/import/resource_importer_obj.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -32,26 +32,23 @@
#include "core/io/resource_saver.h"
#include "core/os/file_access.h"
-#include "scene/3d/mesh_instance.h"
-#include "scene/3d/spatial.h"
+#include "scene/3d/mesh_instance_3d.h"
+#include "scene/3d/node_3d.h"
#include "scene/resources/mesh.h"
#include "scene/resources/surface_tool.h"
uint32_t EditorOBJImporter::get_import_flags() const {
-
return IMPORT_SCENE;
}
-static Error _parse_material_library(const String &p_path, Map<String, Ref<SpatialMaterial> > &material_map, List<String> *r_missing_deps) {
-
+static Error _parse_material_library(const String &p_path, Map<String, Ref<StandardMaterial3D>> &material_map, List<String> *r_missing_deps) {
FileAccessRef f = FileAccess::open(p_path, FileAccess::READ);
ERR_FAIL_COND_V_MSG(!f, ERR_CANT_OPEN, vformat("Couldn't open MTL file '%s', it may not exist or not be readable.", p_path));
- Ref<SpatialMaterial> current;
+ Ref<StandardMaterial3D> current;
String current_name;
String base_path = p_path.get_base_dir();
while (true) {
-
String l = f->get_line().strip_edges();
if (l.begins_with("newmtl ")) {
@@ -63,7 +60,7 @@ static Error _parse_material_library(const String &p_path, Map<String, Ref<Spati
material_map[current_name] = current;
} else if (l.begins_with("Ka ")) {
//uv
- WARN_PRINTS("OBJ: Ambient light for material '" + current_name + "' is ignored in PBR");
+ WARN_PRINT("OBJ: Ambient light for material '" + current_name + "' is ignored in PBR");
} else if (l.begins_with("Kd ")) {
//normal
@@ -102,7 +99,7 @@ static Error _parse_material_library(const String &p_path, Map<String, Ref<Spati
c.a = d;
current->set_albedo(c);
if (c.a < 0.99) {
- current->set_feature(SpatialMaterial::FEATURE_TRANSPARENT, true);
+ current->set_transparency(StandardMaterial3D::TRANSPARENCY_ALPHA);
}
} else if (l.begins_with("Tr ")) {
//normal
@@ -114,12 +111,12 @@ static Error _parse_material_library(const String &p_path, Map<String, Ref<Spati
c.a = 1.0 - d;
current->set_albedo(c);
if (c.a < 0.99) {
- current->set_feature(SpatialMaterial::FEATURE_TRANSPARENT, true);
+ current->set_transparency(StandardMaterial3D::TRANSPARENCY_ALPHA);
}
} else if (l.begins_with("map_Ka ")) {
//uv
- WARN_PRINTS("OBJ: Ambient light texture for material '" + current_name + "' is ignored in PBR");
+ WARN_PRINT("OBJ: Ambient light texture for material '" + current_name + "' is ignored in PBR");
} else if (l.begins_with("map_Kd ")) {
//normal
@@ -133,10 +130,10 @@ static Error _parse_material_library(const String &p_path, Map<String, Ref<Spati
path = base_path.plus_file(p);
}
- Ref<Texture> texture = ResourceLoader::load(path);
+ Ref<Texture2D> texture = ResourceLoader::load(path);
if (texture.is_valid()) {
- current->set_texture(SpatialMaterial::TEXTURE_ALBEDO, texture);
+ current->set_texture(StandardMaterial3D::TEXTURE_ALBEDO, texture);
} else if (r_missing_deps) {
r_missing_deps->push_back(path);
}
@@ -153,10 +150,10 @@ static Error _parse_material_library(const String &p_path, Map<String, Ref<Spati
path = base_path.plus_file(p);
}
- Ref<Texture> texture = ResourceLoader::load(path);
+ Ref<Texture2D> texture = ResourceLoader::load(path);
if (texture.is_valid()) {
- current->set_texture(SpatialMaterial::TEXTURE_METALLIC, texture);
+ current->set_texture(StandardMaterial3D::TEXTURE_METALLIC, texture);
} else if (r_missing_deps) {
r_missing_deps->push_back(path);
}
@@ -173,10 +170,10 @@ static Error _parse_material_library(const String &p_path, Map<String, Ref<Spati
path = base_path.plus_file(p);
}
- Ref<Texture> texture = ResourceLoader::load(path);
+ Ref<Texture2D> texture = ResourceLoader::load(path);
if (texture.is_valid()) {
- current->set_texture(SpatialMaterial::TEXTURE_ROUGHNESS, texture);
+ current->set_texture(StandardMaterial3D::TEXTURE_ROUGHNESS, texture);
} else if (r_missing_deps) {
r_missing_deps->push_back(path);
}
@@ -187,11 +184,11 @@ static Error _parse_material_library(const String &p_path, Map<String, Ref<Spati
String p = l.replace("map_bump", "").replace("\\", "/").strip_edges();
String path = base_path.plus_file(p);
- Ref<Texture> texture = ResourceLoader::load(path);
+ Ref<Texture2D> texture = ResourceLoader::load(path);
if (texture.is_valid()) {
- current->set_feature(SpatialMaterial::FEATURE_NORMAL_MAPPING, true);
- current->set_texture(SpatialMaterial::TEXTURE_NORMAL, texture);
+ current->set_feature(StandardMaterial3D::FEATURE_NORMAL_MAPPING, true);
+ current->set_texture(StandardMaterial3D::TEXTURE_NORMAL, texture);
} else if (r_missing_deps) {
r_missing_deps->push_back(path);
}
@@ -203,8 +200,7 @@ static Error _parse_material_library(const String &p_path, Map<String, Ref<Spati
return OK;
}
-static Error _parse_obj(const String &p_path, List<Ref<Mesh> > &r_meshes, bool p_single_mesh, bool p_generate_tangents, bool p_optimize, Vector3 p_scale_mesh, List<String> *r_missing_deps) {
-
+static Error _parse_obj(const String &p_path, List<Ref<Mesh>> &r_meshes, bool p_single_mesh, bool p_generate_tangents, bool p_optimize, Vector3 p_scale_mesh, Vector3 p_offset_mesh, List<String> *r_missing_deps) {
FileAccessRef f = FileAccess::open(p_path, FileAccess::READ);
ERR_FAIL_COND_V_MSG(!f, ERR_CANT_OPEN, vformat("Couldn't open OBJ file '%s', it may not exist or not be readable.", p_path));
@@ -213,6 +209,7 @@ static Error _parse_obj(const String &p_path, List<Ref<Mesh> > &r_meshes, bool p
bool generate_tangents = p_generate_tangents;
Vector3 scale_mesh = p_scale_mesh;
+ Vector3 offset_mesh = p_offset_mesh;
int mesh_flags = p_optimize ? Mesh::ARRAY_COMPRESS_DEFAULT : 0;
Vector<Vector3> vertices;
@@ -220,7 +217,7 @@ static Error _parse_obj(const String &p_path, List<Ref<Mesh> > &r_meshes, bool p
Vector<Vector2> uvs;
String name;
- Map<String, Map<String, Ref<SpatialMaterial> > > material_map;
+ Map<String, Map<String, Ref<StandardMaterial3D>>> material_map;
Ref<SurfaceTool> surf_tool = memnew(SurfaceTool);
surf_tool->begin(Mesh::PRIMITIVE_TRIANGLES);
@@ -230,7 +227,6 @@ static Error _parse_obj(const String &p_path, List<Ref<Mesh> > &r_meshes, bool p
String current_group;
while (true) {
-
String l = f->get_line().strip_edges();
while (l.length() && l[l.length() - 1] == '\\') {
String add = f->get_line().strip_edges();
@@ -245,9 +241,9 @@ static Error _parse_obj(const String &p_path, List<Ref<Mesh> > &r_meshes, bool p
Vector<String> v = l.split(" ", false);
ERR_FAIL_COND_V(v.size() < 4, ERR_FILE_CORRUPT);
Vector3 vtx;
- vtx.x = v[1].to_float() * scale_mesh.x;
- vtx.y = v[2].to_float() * scale_mesh.y;
- vtx.z = v[3].to_float() * scale_mesh.z;
+ vtx.x = v[1].to_float() * scale_mesh.x + offset_mesh.x;
+ vtx.y = v[2].to_float() * scale_mesh.y + offset_mesh.y;
+ vtx.z = v[3].to_float() * scale_mesh.z + offset_mesh.z;
vertices.push_back(vtx);
} else if (l.begins_with("vt ")) {
//uv
@@ -282,12 +278,10 @@ static Error _parse_obj(const String &p_path, List<Ref<Mesh> > &r_meshes, bool p
ERR_FAIL_COND_V(face[0].size() != face[1].size(), ERR_FILE_CORRUPT);
for (int i = 2; i < v.size() - 1; i++) {
-
face[2] = v[i + 1].split("/");
ERR_FAIL_COND_V(face[0].size() != face[2].size(), ERR_FILE_CORRUPT);
for (int j = 0; j < 3; j++) {
-
int idx = j;
if (idx < 2) {
@@ -296,23 +290,26 @@ static Error _parse_obj(const String &p_path, List<Ref<Mesh> > &r_meshes, bool p
if (face[idx].size() == 3) {
int norm = face[idx][2].to_int() - 1;
- if (norm < 0)
+ if (norm < 0) {
norm += normals.size() + 1;
+ }
ERR_FAIL_INDEX_V(norm, normals.size(), ERR_FILE_CORRUPT);
surf_tool->add_normal(normals[norm]);
}
if (face[idx].size() >= 2 && face[idx][1] != String()) {
int uv = face[idx][1].to_int() - 1;
- if (uv < 0)
+ if (uv < 0) {
uv += uvs.size() + 1;
+ }
ERR_FAIL_INDEX_V(uv, uvs.size(), ERR_FILE_CORRUPT);
surf_tool->add_uv(uvs[uv]);
}
int vtx = face[idx][0].to_int() - 1;
- if (vtx < 0)
+ if (vtx < 0) {
vtx += vertices.size() + 1;
+ }
ERR_FAIL_INDEX_V(vtx, vertices.size(), ERR_FILE_CORRUPT);
Vector3 vertex = vertices[vtx];
@@ -325,10 +322,11 @@ static Error _parse_obj(const String &p_path, List<Ref<Mesh> > &r_meshes, bool p
}
} else if (l.begins_with("s ")) { //smoothing
String what = l.substr(2, l.length()).strip_edges();
- if (what == "off")
+ if (what == "off") {
surf_tool->add_smooth_group(false);
- else
+ } else {
surf_tool->add_smooth_group(true);
+ }
} else if (/*l.begins_with("g ") ||*/ l.begins_with("usemtl ") || (l.begins_with("o ") || f->eof_reached())) { //commit group to mesh
//groups are too annoying
if (surf_tool->get_vertex_array().size()) {
@@ -364,7 +362,6 @@ static Error _parse_obj(const String &p_path, List<Ref<Mesh> > &r_meshes, bool p
}
if (l.begins_with("o ") || f->eof_reached()) {
-
if (!p_single_mesh) {
mesh->set_name(name);
r_meshes.push_back(mesh);
@@ -383,12 +380,10 @@ static Error _parse_obj(const String &p_path, List<Ref<Mesh> > &r_meshes, bool p
}
if (l.begins_with("usemtl ")) {
-
current_material = l.replace("usemtl", "").strip_edges();
}
if (l.begins_with("g ")) {
-
current_group = l.substr(2, l.length()).strip_edges();
}
@@ -396,7 +391,7 @@ static Error _parse_obj(const String &p_path, List<Ref<Mesh> > &r_meshes, bool p
current_material_library = l.replace("mtllib", "").strip_edges();
if (!material_map.has(current_material_library)) {
- Map<String, Ref<SpatialMaterial> > lib;
+ Map<String, Ref<StandardMaterial3D>> lib;
Error err = _parse_material_library(current_material_library, lib, r_missing_deps);
if (err == ERR_CANT_OPEN) {
String dir = p_path.get_base_dir();
@@ -410,7 +405,6 @@ static Error _parse_obj(const String &p_path, List<Ref<Mesh> > &r_meshes, bool p
}
if (p_single_mesh) {
-
r_meshes.push_back(mesh);
}
@@ -418,23 +412,21 @@ static Error _parse_obj(const String &p_path, List<Ref<Mesh> > &r_meshes, bool p
}
Node *EditorOBJImporter::import_scene(const String &p_path, uint32_t p_flags, int p_bake_fps, List<String> *r_missing_deps, Error *r_err) {
+ List<Ref<Mesh>> meshes;
- List<Ref<Mesh> > meshes;
-
- Error err = _parse_obj(p_path, meshes, false, p_flags & IMPORT_GENERATE_TANGENT_ARRAYS, p_flags & IMPORT_USE_COMPRESSION, Vector3(1, 1, 1), r_missing_deps);
+ Error err = _parse_obj(p_path, meshes, false, p_flags & IMPORT_GENERATE_TANGENT_ARRAYS, p_flags & IMPORT_USE_COMPRESSION, Vector3(1, 1, 1), Vector3(0, 0, 0), r_missing_deps);
if (err != OK) {
if (r_err) {
*r_err = err;
}
- return NULL;
+ return nullptr;
}
- Spatial *scene = memnew(Spatial);
+ Node3D *scene = memnew(Node3D);
- for (List<Ref<Mesh> >::Element *E = meshes.front(); E; E = E->next()) {
-
- MeshInstance *mi = memnew(MeshInstance);
+ for (List<Ref<Mesh>>::Element *E = meshes.front(); E; E = E->next()) {
+ MeshInstance3D *mi = memnew(MeshInstance3D);
mi->set_mesh(E->get());
mi->set_name(E->get()->get_name());
scene->add_child(mi);
@@ -447,33 +439,36 @@ Node *EditorOBJImporter::import_scene(const String &p_path, uint32_t p_flags, in
return scene;
}
-Ref<Animation> EditorOBJImporter::import_animation(const String &p_path, uint32_t p_flags, int p_bake_fps) {
+Ref<Animation> EditorOBJImporter::import_animation(const String &p_path, uint32_t p_flags, int p_bake_fps) {
return Ref<Animation>();
}
void EditorOBJImporter::get_extensions(List<String> *r_extensions) const {
-
r_extensions->push_back("obj");
}
EditorOBJImporter::EditorOBJImporter() {
}
+
////////////////////////////////////////////////////
String ResourceImporterOBJ::get_importer_name() const {
return "wavefront_obj";
}
+
String ResourceImporterOBJ::get_visible_name() const {
return "OBJ As Mesh";
}
-void ResourceImporterOBJ::get_recognized_extensions(List<String> *p_extensions) const {
+void ResourceImporterOBJ::get_recognized_extensions(List<String> *p_extensions) const {
p_extensions->push_back("obj");
}
+
String ResourceImporterOBJ::get_save_extension() const {
return "mesh";
}
+
String ResourceImporterOBJ::get_resource_type() const {
return "Mesh";
}
@@ -481,26 +476,26 @@ String ResourceImporterOBJ::get_resource_type() const {
int ResourceImporterOBJ::get_preset_count() const {
return 0;
}
+
String ResourceImporterOBJ::get_preset_name(int p_idx) const {
return "";
}
void ResourceImporterOBJ::get_import_options(List<ImportOption> *r_options, int p_preset) const {
-
r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "generate_tangents"), true));
r_options->push_back(ImportOption(PropertyInfo(Variant::VECTOR3, "scale_mesh"), Vector3(1, 1, 1)));
+ r_options->push_back(ImportOption(PropertyInfo(Variant::VECTOR3, "offset_mesh"), Vector3(0, 0, 0)));
r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "optimize_mesh"), true));
}
-bool ResourceImporterOBJ::get_option_visibility(const String &p_option, const Map<StringName, Variant> &p_options) const {
+bool ResourceImporterOBJ::get_option_visibility(const String &p_option, const Map<StringName, Variant> &p_options) const {
return true;
}
Error ResourceImporterOBJ::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) {
+ List<Ref<Mesh>> meshes;
- List<Ref<Mesh> > meshes;
-
- Error err = _parse_obj(p_source_file, meshes, true, p_options["generate_tangents"], p_options["optimize_mesh"], p_options["scale_mesh"], NULL);
+ Error err = _parse_obj(p_source_file, meshes, true, p_options["generate_tangents"], p_options["optimize_mesh"], p_options["scale_mesh"], p_options["offset_mesh"], nullptr);
ERR_FAIL_COND_V(err != OK, err);
ERR_FAIL_COND_V(meshes.size() != 1, ERR_BUG);
diff --git a/editor/import/resource_importer_obj.h b/editor/import/resource_importer_obj.h
index adad21da61..aec5de3dcc 100644
--- a/editor/import/resource_importer_obj.h
+++ b/editor/import/resource_importer_obj.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -34,13 +34,12 @@
#include "resource_importer_scene.h"
class EditorOBJImporter : public EditorSceneImporter {
-
GDCLASS(EditorOBJImporter, EditorSceneImporter);
public:
virtual uint32_t get_import_flags() const;
virtual void get_extensions(List<String> *r_extensions) const;
- virtual Node *import_scene(const String &p_path, uint32_t p_flags, int p_bake_fps, List<String> *r_missing_deps, Error *r_err = NULL);
+ virtual Node *import_scene(const String &p_path, uint32_t p_flags, int p_bake_fps, List<String> *r_missing_deps, Error *r_err = nullptr);
virtual Ref<Animation> import_animation(const String &p_path, uint32_t p_flags, int p_bake_fps);
EditorOBJImporter();
@@ -62,7 +61,7 @@ public:
virtual void get_import_options(List<ImportOption> *r_options, int p_preset = 0) const;
virtual bool get_option_visibility(const String &p_option, const Map<StringName, Variant> &p_options) const;
- virtual Error 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 = NULL, Variant *r_metadata = NULL);
+ virtual Error 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 = nullptr, Variant *r_metadata = nullptr);
ResourceImporterOBJ();
};
diff --git a/editor/import/resource_importer_scene.cpp b/editor/import/resource_importer_scene.cpp
index 3a99968192..ec82f78e75 100644
--- a/editor/import/resource_importer_scene.cpp
+++ b/editor/import/resource_importer_scene.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -32,33 +32,29 @@
#include "core/io/resource_saver.h"
#include "editor/editor_node.h"
-#include "scene/resources/packed_scene.h"
-
-#include "scene/3d/collision_shape.h"
-#include "scene/3d/mesh_instance.h"
-#include "scene/3d/navigation.h"
-#include "scene/3d/physics_body.h"
-#include "scene/3d/portal.h"
-#include "scene/3d/room_instance.h"
-#include "scene/3d/vehicle_body.h"
+#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"
+#include "scene/3d/vehicle_body_3d.h"
#include "scene/animation/animation_player.h"
#include "scene/resources/animation.h"
-#include "scene/resources/box_shape.h"
-#include "scene/resources/plane_shape.h"
-#include "scene/resources/ray_shape.h"
+#include "scene/resources/box_shape_3d.h"
+#include "scene/resources/packed_scene.h"
+#include "scene/resources/ray_shape_3d.h"
#include "scene/resources/resource_format_text.h"
-#include "scene/resources/sphere_shape.h"
+#include "scene/resources/sphere_shape_3d.h"
+#include "scene/resources/world_margin_shape_3d.h"
uint32_t EditorSceneImporter::get_import_flags() const {
-
if (get_script_instance()) {
return get_script_instance()->call("_get_import_flags");
}
ERR_FAIL_V(0);
}
-void EditorSceneImporter::get_extensions(List<String> *r_extensions) const {
+void EditorSceneImporter::get_extensions(List<String> *r_extensions) const {
if (get_script_instance()) {
Array arr = get_script_instance()->call("_get_extensions");
for (int i = 0; i < arr.size(); i++) {
@@ -69,39 +65,35 @@ void EditorSceneImporter::get_extensions(List<String> *r_extensions) const {
ERR_FAIL();
}
-Node *EditorSceneImporter::import_scene(const String &p_path, uint32_t p_flags, int p_bake_fps, List<String> *r_missing_deps, Error *r_err) {
+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()) {
return get_script_instance()->call("_import_scene", p_path, p_flags, p_bake_fps);
}
- ERR_FAIL_V(NULL);
+ ERR_FAIL_V(nullptr);
}
Ref<Animation> EditorSceneImporter::import_animation(const String &p_path, uint32_t p_flags, int p_bake_fps) {
-
if (get_script_instance()) {
return get_script_instance()->call("_import_animation", p_path, p_flags);
}
- ERR_FAIL_V(NULL);
+ ERR_FAIL_V(nullptr);
}
//for documenters, these functions are useful when an importer calls an external conversion helper (like, fbx2gltf),
//and you want to load the resulting file
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);
}
Ref<Animation> EditorSceneImporter::import_animation_from_other_importer(const String &p_path, uint32_t p_flags, int p_bake_fps) {
-
return ResourceImporterScene::get_singleton()->import_animation_from_other_importer(this, p_path, p_flags, p_bake_fps);
}
void EditorSceneImporter::_bind_methods() {
-
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);
@@ -129,27 +121,24 @@ void EditorSceneImporter::_bind_methods() {
/////////////////////////////////
void EditorScenePostImport::_bind_methods() {
-
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);
}
Node *EditorScenePostImport::post_import(Node *p_scene) {
-
- if (get_script_instance())
+ if (get_script_instance()) {
return get_script_instance()->call("post_import", p_scene);
+ }
return p_scene;
}
String EditorScenePostImport::get_source_folder() const {
-
return source_folder;
}
String EditorScenePostImport::get_source_file() const {
-
return source_file;
}
@@ -162,18 +151,15 @@ EditorScenePostImport::EditorScenePostImport() {
}
String ResourceImporterScene::get_importer_name() const {
-
return "scene";
}
String ResourceImporterScene::get_visible_name() const {
-
return "Scene";
}
void ResourceImporterScene::get_recognized_extensions(List<String> *p_extensions) const {
-
- for (Set<Ref<EditorSceneImporter> >::Element *E = importers.front(); E; E = E->next()) {
+ for (Set<Ref<EditorSceneImporter>>::Element *E = importers.front(); E; E = E->next()) {
E->get()->get_extensions(p_extensions);
}
}
@@ -183,27 +169,29 @@ String ResourceImporterScene::get_save_extension() const {
}
String ResourceImporterScene::get_resource_type() const {
-
return "PackedScene";
}
bool ResourceImporterScene::get_option_visibility(const String &p_option, const Map<StringName, Variant> &p_options) const {
-
if (p_option.begins_with("animation/")) {
- if (p_option != "animation/import" && !bool(p_options["animation/import"]))
+ if (p_option != "animation/import" && !bool(p_options["animation/import"])) {
return false;
+ }
- if (p_option == "animation/keep_custom_tracks" && int(p_options["animation/storage"]) == 0)
+ if (p_option == "animation/keep_custom_tracks" && int(p_options["animation/storage"]) == 0) {
return false;
+ }
- if (p_option.begins_with("animation/optimizer/") && p_option != "animation/optimizer/enabled" && !bool(p_options["animation/optimizer/enabled"]))
+ if (p_option.begins_with("animation/optimizer/") && p_option != "animation/optimizer/enabled" && !bool(p_options["animation/optimizer/enabled"])) {
return false;
+ }
if (p_option.begins_with("animation/clip_")) {
int max_clip = p_options["animation/clips/amount"];
int clip = p_option.get_slice("/", 1).get_slice("_", 1).to_int() - 1;
- if (clip >= max_clip)
+ if (clip >= max_clip) {
return false;
+ }
}
}
@@ -221,73 +209,82 @@ bool ResourceImporterScene::get_option_visibility(const String &p_option, const
int ResourceImporterScene::get_preset_count() const {
return PRESET_MAX;
}
-String ResourceImporterScene::get_preset_name(int p_idx) const {
+String ResourceImporterScene::get_preset_name(int p_idx) const {
switch (p_idx) {
- 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");
+ 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");
}
return "";
}
static bool _teststr(const String &p_what, const String &p_str) {
-
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);
}
- if (what.findn("$" + p_str) != -1) //blender and other stuff
+ if (what.findn("$" + p_str) != -1) { //blender and other stuff
return true;
- if (what.to_lower().ends_with("-" + p_str)) //collada only supports "_" and "-" besides letters
+ }
+ if (what.to_lower().ends_with("-" + p_str)) { //collada only supports "_" and "-" besides letters
return true;
- if (what.to_lower().ends_with("_" + p_str)) //collada only supports "_" and "-" besides letters
+ }
+ if (what.to_lower().ends_with("_" + p_str)) { //collada only supports "_" and "-" besides letters
return true;
+ }
return false;
}
static String _fixstr(const String &p_what, const String &p_str) {
-
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());
- if (what.findn("$" + p_str) != -1) //blender and other stuff
+ if (what.findn("$" + p_str) != -1) { //blender and other stuff
return what.replace("$" + p_str, "") + end;
- if (what.to_lower().ends_with("-" + p_str)) //collada only supports "_" and "-" besides letters
+ }
+ if (what.to_lower().ends_with("-" + p_str)) { //collada only supports "_" and "-" besides letters
return what.substr(0, what.length() - (p_str.length() + 1)) + end;
- if (what.to_lower().ends_with("_" + p_str)) //collada only supports "_" and "-" besides letters
+ }
+ if (what.to_lower().ends_with("_" + p_str)) { //collada only supports "_" and "-" besides letters
return what.substr(0, what.length() - (p_str.length() + 1)) + end;
+ }
return what;
}
-static void _gen_shape_list(const Ref<Mesh> &mesh, List<Ref<Shape> > &r_shape_list, bool p_convex) {
-
+static void _gen_shape_list(const Ref<Mesh> &mesh, List<Ref<Shape3D>> &r_shape_list, bool p_convex) {
if (!p_convex) {
-
- Ref<Shape> shape = mesh->create_trimesh_shape();
+ Ref<Shape3D> shape = mesh->create_trimesh_shape();
r_shape_list.push_back(shape);
} else {
-
- Vector<Ref<Shape> > cd = mesh->convex_decompose();
+ Vector<Ref<Shape3D>> cd = mesh->convex_decompose();
if (cd.size()) {
for (int i = 0; i < cd.size(); i++) {
r_shape_list.push_back(cd[i]);
@@ -296,11 +293,9 @@ static void _gen_shape_list(const Ref<Mesh> &mesh, List<Ref<Shape> > &r_shape_li
}
}
-Node *ResourceImporterScene::_fix_node(Node *p_node, Node *p_root, Map<Ref<Mesh>, List<Ref<Shape> > > &collision_map, LightBakeMode p_light_bake_mode) {
-
+Node *ResourceImporterScene::_fix_node(Node *p_node, Node *p_root, Map<Ref<Mesh>, List<Ref<Shape3D>>> &collision_map, LightBakeMode p_light_bake_mode) {
// children first
for (int i = 0; i < p_node->get_child_count(); i++) {
-
Node *r = _fix_node(p_node->get_child(i), p_root, collision_map, p_light_bake_mode);
if (!r) {
i--; //was erased
@@ -312,42 +307,36 @@ Node *ResourceImporterScene::_fix_node(Node *p_node, Node *p_root, Map<Ref<Mesh>
bool isroot = p_node == p_root;
if (!isroot && _teststr(name, "noimp")) {
-
memdelete(p_node);
- return NULL;
+ return nullptr;
}
- if (Object::cast_to<MeshInstance>(p_node)) {
-
- MeshInstance *mi = Object::cast_to<MeshInstance>(p_node);
+ if (Object::cast_to<MeshInstance3D>(p_node)) {
+ MeshInstance3D *mi = Object::cast_to<MeshInstance3D>(p_node);
Ref<ArrayMesh> m = mi->get_mesh();
if (m.is_valid()) {
-
for (int i = 0; i < m->get_surface_count(); i++) {
-
- Ref<SpatialMaterial> mat = m->surface_get_material(i);
- if (!mat.is_valid())
+ Ref<StandardMaterial3D> mat = m->surface_get_material(i);
+ if (!mat.is_valid()) {
continue;
+ }
if (_teststr(mat->get_name(), "alpha")) {
-
- mat->set_feature(SpatialMaterial::FEATURE_TRANSPARENT, true);
+ mat->set_transparency(StandardMaterial3D::TRANSPARENCY_ALPHA);
mat->set_name(_fixstr(mat->get_name(), "alpha"));
}
if (_teststr(mat->get_name(), "vcol")) {
-
- mat->set_flag(SpatialMaterial::FLAG_ALBEDO_FROM_VERTEX_COLOR, true);
- mat->set_flag(SpatialMaterial::FLAG_SRGB_VERTEX_COLOR, true);
+ mat->set_flag(StandardMaterial3D::FLAG_ALBEDO_FROM_VERTEX_COLOR, true);
+ mat->set_flag(StandardMaterial3D::FLAG_SRGB_VERTEX_COLOR, true);
mat->set_name(_fixstr(mat->get_name(), "vcol"));
}
}
}
if (p_light_bake_mode != LIGHT_BAKE_DISABLED) {
-
- mi->set_flag(GeometryInstance::FLAG_USE_BAKED_LIGHT, true);
+ mi->set_gi_mode(GeometryInstance3D::GI_MODE_BAKED);
}
}
@@ -358,7 +347,6 @@ Node *ResourceImporterScene::_fix_node(Node *p_node, Node *p_root, Map<Ref<Mesh>
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());
for (int i = 0; i < anim->get_track_count(); i++) {
@@ -377,15 +365,15 @@ Node *ResourceImporterScene::_fix_node(Node *p_node, Node *p_root, Map<Ref<Mesh>
}
if (_teststr(name, "colonly") || _teststr(name, "convcolonly")) {
-
- if (isroot)
+ if (isroot) {
return p_node;
- MeshInstance *mi = Object::cast_to<MeshInstance>(p_node);
+ }
+ MeshInstance3D *mi = Object::cast_to<MeshInstance3D>(p_node);
if (mi) {
Ref<Mesh> mesh = mi->get_mesh();
if (mesh.is_valid()) {
- List<Ref<Shape> > shapes;
+ List<Ref<Shape3D>> shapes;
String fixed_name;
if (collision_map.has(mesh)) {
shapes = collision_map[mesh];
@@ -403,11 +391,10 @@ Node *ResourceImporterScene::_fix_node(Node *p_node, Node *p_root, Map<Ref<Mesh>
fixed_name = _fixstr(name, "convcolonly");
}
- ERR_FAIL_COND_V(fixed_name == String(), NULL);
+ ERR_FAIL_COND_V(fixed_name == String(), nullptr);
if (shapes.size()) {
-
- StaticBody *col = memnew(StaticBody);
+ StaticBody3D *col = memnew(StaticBody3D);
col->set_transform(mi->get_transform());
col->set_name(fixed_name);
p_node->replace_by(col);
@@ -415,9 +402,8 @@ Node *ResourceImporterScene::_fix_node(Node *p_node, Node *p_root, Map<Ref<Mesh>
p_node = col;
int idx = 0;
- for (List<Ref<Shape> >::Element *E = shapes.front(); E; E = E->next()) {
-
- CollisionShape *cshape = memnew(CollisionShape);
+ for (List<Ref<Shape3D>>::Element *E = shapes.front(); E; E = E->next()) {
+ CollisionShape3D *cshape = memnew(CollisionShape3D);
cshape->set_shape(E->get());
col->add_child(cshape);
@@ -430,55 +416,55 @@ Node *ResourceImporterScene::_fix_node(Node *p_node, Node *p_root, Map<Ref<Mesh>
} else if (p_node->has_meta("empty_draw_type")) {
String empty_draw_type = String(p_node->get_meta("empty_draw_type"));
- StaticBody *sb = memnew(StaticBody);
+ StaticBody3D *sb = memnew(StaticBody3D);
sb->set_name(_fixstr(name, "colonly"));
- Object::cast_to<Spatial>(sb)->set_transform(Object::cast_to<Spatial>(p_node)->get_transform());
+ Object::cast_to<Node3D>(sb)->set_transform(Object::cast_to<Node3D>(p_node)->get_transform());
p_node->replace_by(sb);
memdelete(p_node);
- p_node = NULL;
- CollisionShape *colshape = memnew(CollisionShape);
+ p_node = nullptr;
+ CollisionShape3D *colshape = memnew(CollisionShape3D);
if (empty_draw_type == "CUBE") {
- BoxShape *boxShape = memnew(BoxShape);
+ BoxShape3D *boxShape = memnew(BoxShape3D);
boxShape->set_extents(Vector3(1, 1, 1));
colshape->set_shape(boxShape);
- colshape->set_name("BoxShape");
+ colshape->set_name("BoxShape3D");
} else if (empty_draw_type == "SINGLE_ARROW") {
- RayShape *rayShape = memnew(RayShape);
+ RayShape3D *rayShape = memnew(RayShape3D);
rayShape->set_length(1);
colshape->set_shape(rayShape);
- colshape->set_name("RayShape");
- Object::cast_to<Spatial>(sb)->rotate_x(Math_PI / 2);
+ colshape->set_name("RayShape3D");
+ Object::cast_to<Node3D>(sb)->rotate_x(Math_PI / 2);
} else if (empty_draw_type == "IMAGE") {
- PlaneShape *planeShape = memnew(PlaneShape);
- colshape->set_shape(planeShape);
- colshape->set_name("PlaneShape");
+ WorldMarginShape3D *world_margin_shape = memnew(WorldMarginShape3D);
+ colshape->set_shape(world_margin_shape);
+ colshape->set_name("WorldMarginShape3D");
} else {
- SphereShape *sphereShape = memnew(SphereShape);
+ SphereShape3D *sphereShape = memnew(SphereShape3D);
sphereShape->set_radius(1);
colshape->set_shape(sphereShape);
- colshape->set_name("SphereShape");
+ colshape->set_name("SphereShape3D");
}
sb->add_child(colshape);
colshape->set_owner(sb->get_owner());
}
- } else if (_teststr(name, "rigid") && Object::cast_to<MeshInstance>(p_node)) {
-
- if (isroot)
+ } else if (_teststr(name, "rigid") && Object::cast_to<MeshInstance3D>(p_node)) {
+ if (isroot) {
return p_node;
+ }
- MeshInstance *mi = Object::cast_to<MeshInstance>(p_node);
+ MeshInstance3D *mi = Object::cast_to<MeshInstance3D>(p_node);
Ref<Mesh> mesh = mi->get_mesh();
if (mesh.is_valid()) {
- List<Ref<Shape> > shapes;
+ List<Ref<Shape3D>> shapes;
if (collision_map.has(mesh)) {
shapes = collision_map[mesh];
} else {
_gen_shape_list(mesh, shapes, true);
}
- RigidBody *rigid_body = memnew(RigidBody);
+ RigidBody3D *rigid_body = memnew(RigidBody3D);
rigid_body->set_name(_fixstr(name, "rigid"));
p_node->replace_by(rigid_body);
rigid_body->set_transform(mi->get_transform());
@@ -489,9 +475,8 @@ Node *ResourceImporterScene::_fix_node(Node *p_node, Node *p_root, Map<Ref<Mesh>
mi->set_owner(rigid_body->get_owner());
int idx = 0;
- for (List<Ref<Shape> >::Element *E = shapes.front(); E; E = E->next()) {
-
- CollisionShape *cshape = memnew(CollisionShape);
+ for (List<Ref<Shape3D>>::Element *E = shapes.front(); E; E = E->next()) {
+ CollisionShape3D *cshape = memnew(CollisionShape3D);
cshape->set_shape(E->get());
rigid_body->add_child(cshape);
@@ -501,14 +486,13 @@ Node *ResourceImporterScene::_fix_node(Node *p_node, Node *p_root, Map<Ref<Mesh>
}
}
- } else if ((_teststr(name, "col") || (_teststr(name, "convcol"))) && Object::cast_to<MeshInstance>(p_node)) {
-
- MeshInstance *mi = Object::cast_to<MeshInstance>(p_node);
+ } else if ((_teststr(name, "col") || (_teststr(name, "convcol"))) && Object::cast_to<MeshInstance3D>(p_node)) {
+ MeshInstance3D *mi = Object::cast_to<MeshInstance3D>(p_node);
Ref<Mesh> mesh = mi->get_mesh();
if (mesh.is_valid()) {
- List<Ref<Shape> > shapes;
+ List<Ref<Shape3D>> shapes;
String fixed_name;
if (collision_map.has(mesh)) {
shapes = collision_map[mesh];
@@ -533,15 +517,14 @@ Node *ResourceImporterScene::_fix_node(Node *p_node, Node *p_root, Map<Ref<Mesh>
}
if (shapes.size()) {
- StaticBody *col = memnew(StaticBody);
+ StaticBody3D *col = memnew(StaticBody3D);
col->set_name("static_collision");
mi->add_child(col);
col->set_owner(mi->get_owner());
int idx = 0;
- for (List<Ref<Shape> >::Element *E = shapes.front(); E; E = E->next()) {
-
- CollisionShape *cshape = memnew(CollisionShape);
+ for (List<Ref<Shape3D>>::Element *E = shapes.front(); E; E = E->next()) {
+ CollisionShape3D *cshape = memnew(CollisionShape3D);
cshape->set_shape(E->get());
col->add_child(cshape);
@@ -553,33 +536,33 @@ Node *ResourceImporterScene::_fix_node(Node *p_node, Node *p_root, Map<Ref<Mesh>
}
}
- } else if (_teststr(name, "navmesh") && Object::cast_to<MeshInstance>(p_node)) {
-
- if (isroot)
+ } else if (_teststr(name, "navmesh") && Object::cast_to<MeshInstance3D>(p_node)) {
+ if (isroot) {
return p_node;
+ }
- MeshInstance *mi = Object::cast_to<MeshInstance>(p_node);
+ MeshInstance3D *mi = Object::cast_to<MeshInstance3D>(p_node);
Ref<ArrayMesh> mesh = mi->get_mesh();
- ERR_FAIL_COND_V(mesh.is_null(), NULL);
- NavigationMeshInstance *nmi = memnew(NavigationMeshInstance);
+ ERR_FAIL_COND_V(mesh.is_null(), nullptr);
+ NavigationRegion3D *nmi = memnew(NavigationRegion3D);
nmi->set_name(_fixstr(name, "navmesh"));
Ref<NavigationMesh> nmesh = memnew(NavigationMesh);
nmesh->create_from_mesh(mesh);
nmi->set_navigation_mesh(nmesh);
- Object::cast_to<Spatial>(nmi)->set_transform(mi->get_transform());
+ Object::cast_to<Node3D>(nmi)->set_transform(mi->get_transform());
p_node->replace_by(nmi);
memdelete(p_node);
p_node = nmi;
} else if (_teststr(name, "vehicle")) {
-
- if (isroot)
+ if (isroot) {
return p_node;
+ }
Node *owner = p_node->get_owner();
- Spatial *s = Object::cast_to<Spatial>(p_node);
- VehicleBody *bv = memnew(VehicleBody);
+ Node3D *s = Object::cast_to<Node3D>(p_node);
+ VehicleBody3D *bv = memnew(VehicleBody3D);
String n = _fixstr(p_node->get_name(), "vehicle");
bv->set_name(n);
p_node->replace_by(bv);
@@ -593,13 +576,13 @@ Node *ResourceImporterScene::_fix_node(Node *p_node, Node *p_root, Map<Ref<Mesh>
p_node = bv;
} else if (_teststr(name, "wheel")) {
-
- if (isroot)
+ if (isroot) {
return p_node;
+ }
Node *owner = p_node->get_owner();
- Spatial *s = Object::cast_to<Spatial>(p_node);
- VehicleWheel *bv = memnew(VehicleWheel);
+ Node3D *s = Object::cast_to<Node3D>(p_node);
+ VehicleWheel3D *bv = memnew(VehicleWheel3D);
String n = _fixstr(p_node->get_name(), "wheel");
bv->set_name(n);
p_node->replace_by(bv);
@@ -612,16 +595,14 @@ Node *ResourceImporterScene::_fix_node(Node *p_node, Node *p_root, Map<Ref<Mesh>
p_node = bv;
- } else if (Object::cast_to<MeshInstance>(p_node)) {
-
+ } else if (Object::cast_to<MeshInstance3D>(p_node)) {
//last attempt, maybe collision inside the mesh data
- MeshInstance *mi = Object::cast_to<MeshInstance>(p_node);
+ MeshInstance3D *mi = Object::cast_to<MeshInstance3D>(p_node);
Ref<ArrayMesh> mesh = mi->get_mesh();
if (!mesh.is_null()) {
-
- List<Ref<Shape> > shapes;
+ List<Ref<Shape3D>> shapes;
if (collision_map.has(mesh)) {
shapes = collision_map[mesh];
} else if (_teststr(mesh->get_name(), "col")) {
@@ -635,15 +616,14 @@ Node *ResourceImporterScene::_fix_node(Node *p_node, Node *p_root, Map<Ref<Mesh>
}
if (shapes.size()) {
- StaticBody *col = memnew(StaticBody);
+ StaticBody3D *col = memnew(StaticBody3D);
col->set_name("static_collision");
p_node->add_child(col);
col->set_owner(p_node->get_owner());
int idx = 0;
- for (List<Ref<Shape> >::Element *E = shapes.front(); E; E = E->next()) {
-
- CollisionShape *cshape = memnew(CollisionShape);
+ for (List<Ref<Shape3D>>::Element *E = shapes.front(); E; E = E->next()) {
+ CollisionShape3D *cshape = memnew(CollisionShape3D);
cshape->set_shape(E->get());
col->add_child(cshape);
@@ -659,41 +639,39 @@ Node *ResourceImporterScene::_fix_node(Node *p_node, Node *p_root, Map<Ref<Mesh>
}
void ResourceImporterScene::_create_clips(Node *scene, const Array &p_clips, bool p_bake_all) {
-
- if (!scene->has_node(String("AnimationPlayer")))
+ if (!scene->has_node(String("AnimationPlayer"))) {
return;
+ }
Node *n = scene->get_node(String("AnimationPlayer"));
ERR_FAIL_COND(!n);
AnimationPlayer *anim = Object::cast_to<AnimationPlayer>(n);
ERR_FAIL_COND(!anim);
- if (!anim->has_animation("default"))
+ if (!anim->has_animation("default")) {
return;
+ }
Ref<Animation> default_anim = anim->get_animation("default");
for (int i = 0; i < p_clips.size(); i += 4) {
-
String name = p_clips[i];
float from = p_clips[i + 1];
float to = p_clips[i + 2];
bool loop = p_clips[i + 3];
- if (from >= to)
+ if (from >= to) {
continue;
+ }
Ref<Animation> new_anim = memnew(Animation);
for (int j = 0; j < default_anim->get_track_count(); j++) {
-
List<float> keys;
int kc = default_anim->track_get_key_count(j);
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) {
-
//found a key within range, so create track
if (dtrack == -1) {
new_anim->add_track(default_anim->track_get_type(j));
@@ -701,7 +679,6 @@ void ResourceImporterScene::_create_clips(Node *scene, const Array &p_clips, boo
new_anim->track_set_path(dtrack, default_anim->track_get_path(j));
if (kt > (from + 0.01) && k > 0) {
-
if (default_anim->track_get_type(j) == Animation::TYPE_TRANSFORM) {
Quat q;
Vector3 p;
@@ -730,7 +707,6 @@ void ResourceImporterScene::_create_clips(Node *scene, const Array &p_clips, boo
}
if (dtrack != -1 && kt >= to) {
-
if (default_anim->track_get_type(j) == Animation::TYPE_TRANSFORM) {
Quat q;
Vector3 p;
@@ -750,7 +726,6 @@ void ResourceImporterScene::_create_clips(Node *scene, const Array &p_clips, boo
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) {
-
Quat q;
Vector3 p;
Vector3 s;
@@ -777,12 +752,10 @@ void ResourceImporterScene::_create_clips(Node *scene, const Array &p_clips, boo
}
void ResourceImporterScene::_filter_anim_tracks(Ref<Animation> anim, Set<String> &keep) {
-
Ref<Animation> a = anim;
ERR_FAIL_COND(!a.is_valid());
for (int j = 0; j < a->get_track_count(); j++) {
-
String path = a->track_get_path(j);
if (!keep.has(path)) {
@@ -793,9 +766,9 @@ void ResourceImporterScene::_filter_anim_tracks(Ref<Animation> anim, Set<String>
}
void ResourceImporterScene::_filter_tracks(Node *scene, const String &p_text) {
-
- if (!scene->has_node(String("AnimationPlayer")))
+ if (!scene->has_node(String("AnimationPlayer"))) {
return;
+ }
Node *n = scene->get_node(String("AnimationPlayer"));
ERR_FAIL_COND(!n);
AnimationPlayer *anim = Object::cast_to<AnimationPlayer>(n);
@@ -803,14 +776,12 @@ void ResourceImporterScene::_filter_tracks(Node *scene, const String &p_text) {
Vector<String> strings = p_text.split("\n");
for (int i = 0; i < strings.size(); i++) {
-
strings.write[i] = strings[i].strip_edges();
}
List<StringName> anim_names;
anim->get_animation_list(&anim_names);
for (List<StringName>::Element *E = anim_names.front(); E; E = E->next()) {
-
String name = E->get();
bool valid_for_this = false;
bool valid = false;
@@ -819,9 +790,7 @@ void ResourceImporterScene::_filter_tracks(Node *scene, const String &p_text) {
Set<String> keep_local;
for (int i = 0; i < strings.size(); i++) {
-
if (strings[i].begins_with("@")) {
-
valid_for_this = false;
for (Set<String>::Element *F = keep_local.front(); F; F = F->next()) {
keep.insert(F->get());
@@ -830,59 +799,64 @@ void ResourceImporterScene::_filter_tracks(Node *scene, const String &p_text) {
Vector<String> filters = strings[i].substr(1, strings[i].length()).split(",");
for (int j = 0; j < filters.size(); j++) {
-
String fname = filters[j].strip_edges();
- if (fname == "")
+ if (fname == "") {
continue;
+ }
int fc = fname[0];
bool plus;
- if (fc == '+')
+ if (fc == '+') {
plus = true;
- else if (fc == '-')
+ } else if (fc == '-') {
plus = false;
- else
+ } else {
continue;
+ }
String filter = fname.substr(1, fname.length()).strip_edges();
- if (!name.matchn(filter))
+ if (!name.matchn(filter)) {
continue;
+ }
valid_for_this = plus;
}
- if (valid_for_this)
+ if (valid_for_this) {
valid = true;
+ }
} else if (valid_for_this) {
-
Ref<Animation> a = anim->get_animation(name);
- if (!a.is_valid())
+ if (!a.is_valid()) {
continue;
+ }
for (int j = 0; j < a->get_track_count(); j++) {
-
String path = a->track_get_path(j);
String tname = strings[i];
- if (tname == "")
+ if (tname == "") {
continue;
+ }
int fc = tname[0];
bool plus;
- if (fc == '+')
+ if (fc == '+') {
plus = true;
- else if (fc == '-')
+ } else if (fc == '-') {
plus = false;
- else
+ } else {
continue;
+ }
String filter = tname.substr(1, tname.length()).strip_edges();
- if (!path.matchn(filter))
+ if (!path.matchn(filter)) {
continue;
+ }
- if (plus)
+ if (plus) {
keep_local.insert(path);
- else if (!keep.has(path)) {
+ } else if (!keep.has(path)) {
keep_local.erase(path);
}
}
@@ -899,9 +873,9 @@ void ResourceImporterScene::_filter_tracks(Node *scene, const String &p_text) {
}
void ResourceImporterScene::_optimize_animations(Node *scene, float p_max_lin_error, float p_max_ang_error, float p_max_angle) {
-
- if (!scene->has_node(String("AnimationPlayer")))
+ if (!scene->has_node(String("AnimationPlayer"))) {
return;
+ }
Node *n = scene->get_node(String("AnimationPlayer"));
ERR_FAIL_COND(!n);
AnimationPlayer *anim = Object::cast_to<AnimationPlayer>(n);
@@ -910,14 +884,12 @@ void ResourceImporterScene::_optimize_animations(Node *scene, float p_max_lin_er
List<StringName> anim_names;
anim->get_animation_list(&anim_names);
for (List<StringName>::Element *E = anim_names.front(); E; E = E->next()) {
-
Ref<Animation> a = anim->get_animation(E->get());
a->optimize(p_max_lin_error, p_max_ang_error, Math::deg2rad(p_max_angle));
}
}
static String _make_extname(const String &p_str) {
-
String ext_name = p_str.replace(".", "_");
ext_name = ext_name.replace(":", "_");
ext_name = ext_name.replace("\"", "_");
@@ -933,35 +905,31 @@ static String _make_extname(const String &p_str) {
}
void ResourceImporterScene::_find_meshes(Node *p_node, Map<Ref<ArrayMesh>, Transform> &meshes) {
-
List<PropertyInfo> pi;
p_node->get_property_list(&pi);
- MeshInstance *mi = Object::cast_to<MeshInstance>(p_node);
+ MeshInstance3D *mi = Object::cast_to<MeshInstance3D>(p_node);
if (mi) {
-
Ref<ArrayMesh> mesh = mi->get_mesh();
if (mesh.is_valid() && !meshes.has(mesh)) {
- Spatial *s = mi;
+ Node3D *s = mi;
Transform transform;
while (s) {
transform = transform * s->get_transform();
- s = s->get_parent_spatial();
+ s = Object::cast_to<Node3D>(s->get_parent());
}
meshes[mesh] = transform;
}
}
for (int i = 0; i < p_node->get_child_count(); i++) {
-
_find_meshes(p_node->get_child(i), meshes);
}
}
-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) {
-
+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) {
List<PropertyInfo> pi;
if (p_make_animations) {
@@ -971,12 +939,10 @@ void ResourceImporterScene::_make_external_resources(Node *p_node, const String
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)) {
-
//mark what comes from the file first, this helps eventually keep user data
for (int i = 0; i < anim->get_track_count(); i++) {
anim->track_set_imported(i, true);
@@ -1015,15 +981,11 @@ void ResourceImporterScene::_make_external_resources(Node *p_node, const String
p_node->get_property_list(&pi);
for (List<PropertyInfo>::Element *E = pi.front(); E; E = E->next()) {
-
if (E->get().type == Variant::OBJECT) {
-
Ref<Material> mat = p_node->get(E->get().name);
if (p_make_materials && mat.is_valid() && mat->get_name() != "") {
-
if (!p_materials.has(mat)) {
-
String ext_name;
if (p_materials_as_text) {
@@ -1036,28 +998,22 @@ void ResourceImporterScene::_make_external_resources(Node *p_node, const String
//if exists, use it
p_materials[mat] = ResourceLoader::load(ext_name);
} else {
-
ResourceSaver::save(ext_name, mat, ResourceSaver::FLAG_CHANGE_PATH);
p_materials[mat] = ResourceLoader::load(ext_name, "", true); // disable loading from the cache.
}
}
if (p_materials[mat] != mat) {
-
p_node->set(E->get().name, p_materials[mat]);
}
} else {
-
Ref<ArrayMesh> mesh = p_node->get(E->get().name);
if (mesh.is_valid()) {
-
bool mesh_just_added = false;
if (p_make_meshes) {
-
if (!p_meshes.has(mesh)) {
-
//meshes are always overwritten, keeping them is not practical
String ext_name;
@@ -1075,16 +1031,16 @@ void ResourceImporterScene::_make_external_resources(Node *p_node, const String
}
if (p_make_materials) {
-
if (mesh_just_added || !p_meshes.has(mesh)) {
-
for (int i = 0; i < mesh->get_surface_count(); i++) {
mat = mesh->surface_get_material(i);
- if (!mat.is_valid())
+ if (!mat.is_valid()) {
continue;
- if (mat->get_name() == "")
+ }
+ if (mat->get_name() == "") {
continue;
+ }
if (!p_materials.has(mat)) {
String ext_name;
@@ -1099,19 +1055,16 @@ void ResourceImporterScene::_make_external_resources(Node *p_node, const String
//if exists, use it
p_materials[mat] = ResourceLoader::load(ext_name);
} else {
-
ResourceSaver::save(ext_name, mat, ResourceSaver::FLAG_CHANGE_PATH);
p_materials[mat] = ResourceLoader::load(ext_name, "", true); // disable loading from the cache.
}
}
if (p_materials[mat] != mat) {
-
mesh->surface_set_material(i, p_materials[mat]);
//re-save the mesh since a material is now assigned
if (p_make_meshes) {
-
String ext_name;
if (p_meshes_as_text) {
@@ -1137,14 +1090,12 @@ void ResourceImporterScene::_make_external_resources(Node *p_node, const String
}
for (int i = 0; i < p_node->get_child_count(); i++) {
-
_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);
}
}
void ResourceImporterScene::get_import_options(List<ImportOption> *r_options, int p_preset) const {
-
- r_options->push_back(ImportOption(PropertyInfo(Variant::STRING, "nodes/root_type", PROPERTY_HINT_TYPE_STRING, "Node"), "Spatial"));
+ r_options->push_back(ImportOption(PropertyInfo(Variant::STRING, "nodes/root_type", PROPERTY_HINT_TYPE_STRING, "Node"), "Node3D"));
r_options->push_back(ImportOption(PropertyInfo(Variant::STRING, "nodes/root_name"), "Scene Root"));
List<String> script_extentions;
@@ -1153,8 +1104,9 @@ void ResourceImporterScene::get_import_options(List<ImportOption> *r_options, in
String script_ext_hint;
for (List<String>::Element *E = script_extentions.front(); E; E = E->next()) {
- if (script_ext_hint != "")
+ if (script_ext_hint != "") {
script_ext_hint += ",";
+ }
script_ext_hint += "*." + E->get();
}
@@ -1163,7 +1115,7 @@ void ResourceImporterScene::get_import_options(List<ImportOption> *r_options, in
bool scenes_out = p_preset == PRESET_MULTIPLE_SCENES || p_preset == PRESET_MULTIPLE_SCENES_AND_MATERIALS;
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;
- r_options->push_back(ImportOption(PropertyInfo(Variant::REAL, "nodes/root_scale", PROPERTY_HINT_RANGE, "0.001,1000,0.001"), 1.0));
+ r_options->push_back(ImportOption(PropertyInfo(Variant::FLOAT, "nodes/root_scale", PROPERTY_HINT_RANGE, "0.001,1000,0.001"), 1.0));
r_options->push_back(ImportOption(PropertyInfo(Variant::STRING, "nodes/custom_script", PROPERTY_HINT_FILE, script_ext_hint), ""));
r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "nodes/storage", PROPERTY_HINT_ENUM, "Single Scene,Instanced Sub-Scenes"), scenes_out ? 1 : 0));
r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "materials/location", PROPERTY_HINT_ENUM, "Node,Mesh"), (meshes_out || materials_out) ? 1 : 0));
@@ -1173,17 +1125,18 @@ void ResourceImporterScene::get_import_options(List<ImportOption> *r_options, in
r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "meshes/ensure_tangents"), true));
r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "meshes/storage", PROPERTY_HINT_ENUM, "Built-In,Files (.mesh),Files (.tres)"), meshes_out ? 1 : 0));
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));
- r_options->push_back(ImportOption(PropertyInfo(Variant::REAL, "meshes/lightmap_texel_size", PROPERTY_HINT_RANGE, "0.001,100,0.001"), 0.1));
+ r_options->push_back(ImportOption(PropertyInfo(Variant::FLOAT, "meshes/lightmap_texel_size", PROPERTY_HINT_RANGE, "0.001,100,0.001"), 0.1));
+ r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "skins/use_named_skins"), true));
r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "external_files/store_in_subdir"), false));
r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "animation/import", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), true));
- r_options->push_back(ImportOption(PropertyInfo(Variant::REAL, "animation/fps", PROPERTY_HINT_RANGE, "1,120,1"), 15));
+ r_options->push_back(ImportOption(PropertyInfo(Variant::FLOAT, "animation/fps", PROPERTY_HINT_RANGE, "1,120,1"), 15));
r_options->push_back(ImportOption(PropertyInfo(Variant::STRING, "animation/filter_script", PROPERTY_HINT_MULTILINE_TEXT), ""));
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));
r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "animation/keep_custom_tracks"), animations_out));
r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "animation/optimizer/enabled", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), true));
- r_options->push_back(ImportOption(PropertyInfo(Variant::REAL, "animation/optimizer/max_linear_error"), 0.05));
- r_options->push_back(ImportOption(PropertyInfo(Variant::REAL, "animation/optimizer/max_angular_error"), 0.01));
- r_options->push_back(ImportOption(PropertyInfo(Variant::REAL, "animation/optimizer/max_angle"), 22));
+ 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));
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++) {
@@ -1195,7 +1148,6 @@ void ResourceImporterScene::get_import_options(List<ImportOption> *r_options, in
}
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);
}
@@ -1207,31 +1159,29 @@ void ResourceImporterScene::_replace_owner(Node *p_node, Node *p_scene, Node *p_
}
Node *ResourceImporterScene::import_scene_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();
- for (Set<Ref<EditorSceneImporter> >::Element *E = importers.front(); E; E = E->next()) {
-
- if (E->get().ptr() == p_exception)
+ for (Set<Ref<EditorSceneImporter>>::Element *E = importers.front(); E; E = E->next()) {
+ if (E->get().ptr() == p_exception) {
continue;
+ }
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;
}
}
- if (importer.is_valid())
+ if (importer.is_valid()) {
break;
+ }
}
- ERR_FAIL_COND_V(!importer.is_valid(), NULL);
+ ERR_FAIL_COND_V(!importer.is_valid(), nullptr);
List<String> missing;
Error err;
@@ -1239,37 +1189,34 @@ Node *ResourceImporterScene::import_scene_from_other_importer(EditorSceneImporte
}
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();
- for (Set<Ref<EditorSceneImporter> >::Element *E = importers.front(); E; E = E->next()) {
-
- if (E->get().ptr() == p_exception)
+ for (Set<Ref<EditorSceneImporter>>::Element *E = importers.front(); E; E = E->next()) {
+ if (E->get().ptr() == p_exception) {
continue;
+ }
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;
}
}
- if (importer.is_valid())
+ if (importer.is_valid()) {
break;
+ }
}
- ERR_FAIL_COND_V(!importer.is_valid(), NULL);
+ ERR_FAIL_COND_V(!importer.is_valid(), nullptr);
return importer->import_animation(p_path, p_flags, p_bake_fps);
}
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) {
-
const String &src_path = p_source_file;
Ref<EditorSceneImporter> importer;
@@ -1278,22 +1225,20 @@ Error ResourceImporterScene::import(const String &p_source_file, const String &p
EditorProgress progress("import", TTR("Import Scene"), 104);
progress.step(TTR("Importing Scene..."), 0);
- for (Set<Ref<EditorSceneImporter> >::Element *E = importers.front(); E; E = E->next()) {
-
+ for (Set<Ref<EditorSceneImporter>>::Element *E = importers.front(); E; E = E->next()) {
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;
}
}
- if (importer.is_valid())
+ if (importer.is_valid()) {
break;
+ }
}
ERR_FAIL_COND_V(!importer.is_valid(), ERR_FILE_UNRECOGNIZED);
@@ -1301,20 +1246,29 @@ Error ResourceImporterScene::import(const String &p_source_file, const String &p
float fps = p_options["animation/fps"];
int import_flags = EditorSceneImporter::IMPORT_ANIMATION_DETECT_LOOP;
- if (!bool(p_options["animation/optimizer/remove_unused_tracks"]))
+ if (!bool(p_options["animation/optimizer/remove_unused_tracks"])) {
import_flags |= EditorSceneImporter::IMPORT_ANIMATION_FORCE_ALL_TRACKS_IN_ALL_CLIPS;
+ }
- if (bool(p_options["animation/import"]))
+ if (bool(p_options["animation/import"])) {
import_flags |= EditorSceneImporter::IMPORT_ANIMATION;
+ }
- if (int(p_options["meshes/compress"]))
+ if (int(p_options["meshes/compress"])) {
import_flags |= EditorSceneImporter::IMPORT_USE_COMPRESSION;
+ }
- if (bool(p_options["meshes/ensure_tangents"]))
+ if (bool(p_options["meshes/ensure_tangents"])) {
import_flags |= EditorSceneImporter::IMPORT_GENERATE_TANGENT_ARRAYS;
+ }
- if (int(p_options["materials/location"]) == 0)
+ if (int(p_options["materials/location"]) == 0) {
import_flags |= EditorSceneImporter::IMPORT_MATERIALS_IN_INSTANCES;
+ }
+
+ if (bool(p_options["skins/use_named_skins"])) {
+ import_flags |= EditorSceneImporter::IMPORT_USE_NAMED_SKIN_BINDS;
+ }
Error err = OK;
List<String> missing_deps; // for now, not much will be done with this
@@ -1326,17 +1280,16 @@ Error ResourceImporterScene::import(const String &p_source_file, const String &p
String root_type = p_options["nodes/root_type"];
root_type = root_type.split(" ")[0]; // full root_type is "ClassName (filename.gd)" for a script global class.
- Ref<Script> root_script = NULL;
+ Ref<Script> root_script = nullptr;
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);
}
- if (root_type != "Spatial") {
+ if (root_type != "Node3D") {
Node *base_node = Object::cast_to<Node>(ClassDB::instance(root_type));
if (base_node) {
-
scene->replace_by(base_node);
memdelete(scene);
scene = base_node;
@@ -1347,15 +1300,17 @@ Error ResourceImporterScene::import(const String &p_source_file, const String &p
scene->set_script(Variant(root_script));
}
- if (Object::cast_to<Spatial>(scene)) {
- float root_scale = p_options["nodes/root_scale"];
- Object::cast_to<Spatial>(scene)->scale(Vector3(root_scale, root_scale, root_scale));
+ float root_scale = 1.0;
+ if (Object::cast_to<Node3D>(scene)) {
+ root_scale = p_options["nodes/root_scale"];
+ Object::cast_to<Node3D>(scene)->scale(Vector3(root_scale, root_scale, root_scale));
}
- if (p_options["nodes/root_name"] != "Scene Root")
+ if (p_options["nodes/root_name"] != "Scene Root") {
scene->set_name(p_options["nodes/root_name"]);
- else
+ } else {
scene->set_name(p_save_path.get_file().get_basename());
+ }
err = OK;
@@ -1367,7 +1322,7 @@ Error ResourceImporterScene::import(const String &p_source_file, const String &p
float anim_optimizer_maxang = p_options["animation/optimizer/max_angle"];
int light_bake_mode = p_options["meshes/light_baking"];
- Map<Ref<Mesh>, List<Ref<Shape> > > collision_map;
+ Map<Ref<Mesh>, List<Ref<Shape3D>>> collision_map;
scene = _fix_node(scene, scene, collision_map, LightBakeMode(light_bake_mode));
@@ -1377,7 +1332,6 @@ Error ResourceImporterScene::import(const String &p_source_file, const String &p
Array animation_clips;
{
-
int clip_count = p_options["animation/clips/amount"];
for (int i = 0; i < clip_count; i++) {
@@ -1412,7 +1366,6 @@ Error ResourceImporterScene::import(const String &p_source_file, const String &p
String base_path = p_source_file.get_base_dir();
if (external_animations || external_materials || external_meshes || external_scenes) {
-
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);
@@ -1424,40 +1377,119 @@ Error ResourceImporterScene::import(const String &p_source_file, const String &p
}
if (light_bake_mode == 2 /* || generate LOD */) {
-
Map<Ref<ArrayMesh>, Transform> meshes;
_find_meshes(scene, meshes);
- if (light_bake_mode == 2) {
+ String file_id = src_path.get_file();
+ String cache_file_path = base_path.plus_file(file_id + ".unwrap_cache");
+
+ Vector<unsigned char> cache_data;
+
+ if (FileAccess::exists(cache_file_path)) {
+ Error err2;
+ FileAccess *file = FileAccess::open(cache_file_path, FileAccess::READ, &err2);
+
+ if (err2) {
+ if (file) {
+ memdelete(file);
+ }
+ } 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;
+
+ 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);
+ }
- float texel_size = p_options["meshes/lightmap_texel_size"];
- texel_size = MAX(0.001, texel_size);
+ progress2.step(TTR("Generating for Mesh: ") + name + " (" + itos(step) + "/" + itos(meshes.size()) + ")", step);
- 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()) {
+ 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);
- Ref<ArrayMesh> mesh = E->key();
- String name = mesh->get_name();
- if (name == "") { //should not happen but..
- name = "Mesh " + itos(step);
+ 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;
+ }
}
+ }
+ step++;
+ }
- progress2.step(TTR("Generating for Mesh: ") + name + " (" + itos(step) + "/" + itos(meshes.size()) + ")", step);
+ Error err2;
+ FileAccess *file = FileAccess::open(cache_file_path, FileAccess::WRITE, &err2);
- Error err2 = mesh->lightmap_unwrap(E->get(), texel_size);
- if (err2 != OK) {
- EditorNode::add_io_error("Mesh '" + name + "' failed lightmap generation. Please fix geometry.");
+ if (err2) {
+ if (file) {
+ memdelete(file);
+ }
+ } 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);
}
- step++;
+
+ 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();
}
}
if (external_animations || external_materials || external_meshes) {
- Map<Ref<Animation>, Ref<Animation> > anim_map;
- Map<Ref<Material>, Ref<Material> > mat_map;
- Map<Ref<ArrayMesh>, Ref<ArrayMesh> > mesh_map;
+ Map<Ref<Animation>, Ref<Animation>> anim_map;
+ Map<Ref<Material>, Ref<Material>> mat_map;
+ Map<Ref<ArrayMesh>, Ref<ArrayMesh>> mesh_map;
bool keep_materials = bool(p_options["materials/keep_on_reimport"]);
@@ -1474,9 +1506,8 @@ Error ResourceImporterScene::import(const String &p_source_file, const String &p
if (!scr.is_valid()) {
EditorNode::add_io_error(TTR("Couldn't load post-import script:") + " " + post_import_script_path);
} else {
-
post_import_script = Ref<EditorScenePostImport>(memnew(EditorScenePostImport));
- post_import_script->set_script(scr.get_ref_ptr());
+ post_import_script->set_script(scr);
if (!post_import_script->get_script_instance()) {
EditorNode::add_io_error(TTR("Invalid/broken script for post-import (check console):") + " " + post_import_script_path);
post_import_script.unref();
@@ -1489,7 +1520,9 @@ Error ResourceImporterScene::import(const String &p_source_file, const String &p
post_import_script->init(base_path, p_source_file);
scene = post_import_script->post_import(scene);
if (!scene) {
- EditorNode::add_io_error(TTR("Error running post-import script:") + " " + post_import_script_path);
+ 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?"));
return err;
}
}
@@ -1500,8 +1533,9 @@ Error ResourceImporterScene::import(const String &p_source_file, const String &p
//save sub-scenes as instances!
for (int i = 0; i < scene->get_child_count(); i++) {
Node *child = scene->get_child(i);
- if (child->get_owner() != scene)
+ if (child->get_owner() != scene) {
continue; //not a real child probably created by scene type (ig, a scrollbar)
+ }
_replace_owner(child, scene, child);
String cn = String(child->get_name()).strip_edges().replace(".", "_").replace(":", "_");
@@ -1532,30 +1566,33 @@ Error ResourceImporterScene::import(const String &p_source_file, const String &p
return OK;
}
-ResourceImporterScene *ResourceImporterScene::singleton = NULL;
+ResourceImporterScene *ResourceImporterScene::singleton = nullptr;
ResourceImporterScene::ResourceImporterScene() {
singleton = this;
}
+
///////////////////////////////////////
uint32_t EditorSceneImporterESCN::get_import_flags() const {
return IMPORT_SCENE;
}
+
void EditorSceneImporterESCN::get_extensions(List<String> *r_extensions) const {
r_extensions->push_back("escn");
}
-Node *EditorSceneImporterESCN::import_scene(const String &p_path, uint32_t p_flags, int p_bake_fps, List<String> *r_missing_deps, Error *r_err) {
+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);
- ERR_FAIL_COND_V_MSG(!ps.is_valid(), NULL, "Cannot load scene as text resource from path '" + p_path + "'.");
+ ERR_FAIL_COND_V_MSG(!ps.is_valid(), nullptr, "Cannot load scene as text resource from path '" + p_path + "'.");
Node *scene = ps->instance();
- ERR_FAIL_COND_V(!scene, NULL);
+ ERR_FAIL_COND_V(!scene, nullptr);
return scene;
}
+
Ref<Animation> EditorSceneImporterESCN::import_animation(const String &p_path, uint32_t p_flags, int p_bake_fps) {
ERR_FAIL_V(Ref<Animation>());
}
diff --git a/editor/import/resource_importer_scene.h b/editor/import/resource_importer_scene.h
index ef9a77917f..34d96bbc44 100644
--- a/editor/import/resource_importer_scene.h
+++ b/editor/import/resource_importer_scene.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -34,12 +34,11 @@
#include "core/io/resource_importer.h"
#include "scene/resources/animation.h"
#include "scene/resources/mesh.h"
-#include "scene/resources/shape.h"
+#include "scene/resources/shape_3d.h"
class Material;
class EditorSceneImporter : public Reference {
-
GDCLASS(EditorSceneImporter, Reference);
protected:
@@ -59,20 +58,20 @@ public:
IMPORT_GENERATE_TANGENT_ARRAYS = 256,
IMPORT_FAIL_ON_MISSING_DEPENDENCIES = 512,
IMPORT_MATERIALS_IN_INSTANCES = 1024,
- IMPORT_USE_COMPRESSION = 2048
+ IMPORT_USE_COMPRESSION = 2048,
+ IMPORT_USE_NAMED_SKIN_BINDS = 4096,
};
virtual uint32_t get_import_flags() const;
virtual void get_extensions(List<String> *r_extensions) const;
- virtual Node *import_scene(const String &p_path, uint32_t p_flags, int p_bake_fps, List<String> *r_missing_deps, Error *r_err = NULL);
+ virtual Node *import_scene(const String &p_path, uint32_t p_flags, int p_bake_fps, List<String> *r_missing_deps, Error *r_err = nullptr);
virtual Ref<Animation> import_animation(const String &p_path, uint32_t p_flags, int p_bake_fps);
EditorSceneImporter() {}
};
class EditorScenePostImport : public Reference {
-
GDCLASS(EditorScenePostImport, Reference);
String source_folder;
@@ -92,7 +91,7 @@ public:
class ResourceImporterScene : public ResourceImporter {
GDCLASS(ResourceImporterScene, ResourceImporter);
- Set<Ref<EditorSceneImporter> > importers;
+ Set<Ref<EditorSceneImporter>> importers;
static ResourceImporterScene *singleton;
@@ -124,7 +123,7 @@ class ResourceImporterScene : public ResourceImporter {
public:
static ResourceImporterScene *get_singleton() { return singleton; }
- const Set<Ref<EditorSceneImporter> > &get_importers() const { return importers; }
+ const Set<Ref<EditorSceneImporter>> &get_importers() const { return importers; }
void add_importer(Ref<EditorSceneImporter> p_importer) { importers.insert(p_importer); }
void remove_importer(Ref<EditorSceneImporter> p_importer) { importers.erase(p_importer); }
@@ -144,16 +143,16 @@ public:
void _find_meshes(Node *p_node, Map<Ref<ArrayMesh>, Transform> &meshes);
- void _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);
+ void _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);
- Node *_fix_node(Node *p_node, Node *p_root, Map<Ref<Mesh>, List<Ref<Shape> > > &collision_map, LightBakeMode p_light_bake_mode);
+ Node *_fix_node(Node *p_node, Node *p_root, Map<Ref<Mesh>, List<Ref<Shape3D>>> &collision_map, LightBakeMode p_light_bake_mode);
void _create_clips(Node *scene, const Array &p_clips, bool p_bake_all);
void _filter_anim_tracks(Ref<Animation> anim, Set<String> &keep);
void _filter_tracks(Node *scene, const String &p_text);
void _optimize_animations(Node *scene, float p_max_lin_error, float p_max_ang_error, float p_max_angle);
- virtual Error 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 = NULL, Variant *r_metadata = NULL);
+ virtual Error 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 = nullptr, Variant *r_metadata = nullptr);
Node *import_scene_from_other_importer(EditorSceneImporter *p_exception, const String &p_path, uint32_t p_flags, int p_bake_fps);
Ref<Animation> import_animation_from_other_importer(EditorSceneImporter *p_exception, const String &p_path, uint32_t p_flags, int p_bake_fps);
@@ -167,7 +166,7 @@ class EditorSceneImporterESCN : public EditorSceneImporter {
public:
virtual uint32_t get_import_flags() const;
virtual void get_extensions(List<String> *r_extensions) const;
- virtual Node *import_scene(const String &p_path, uint32_t p_flags, int p_bake_fps, List<String> *r_missing_deps, Error *r_err = NULL);
+ virtual Node *import_scene(const String &p_path, uint32_t p_flags, int p_bake_fps, List<String> *r_missing_deps, Error *r_err = nullptr);
virtual Ref<Animation> import_animation(const String &p_path, uint32_t p_flags, int p_bake_fps);
};
diff --git a/editor/import/resource_importer_shader_file.cpp b/editor/import/resource_importer_shader_file.cpp
new file mode 100644
index 0000000000..a2e80dfa18
--- /dev/null
+++ b/editor/import/resource_importer_shader_file.cpp
@@ -0,0 +1,118 @@
+/*************************************************************************/
+/* resource_importer_shader_file.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "resource_importer_shader_file.h"
+
+#include "core/io/marshalls.h"
+#include "core/io/resource_saver.h"
+#include "core/os/file_access.h"
+#include "editor/editor_node.h"
+#include "editor/plugins/shader_file_editor_plugin.h"
+#include "servers/rendering/rendering_device_binds.h"
+
+String ResourceImporterShaderFile::get_importer_name() const {
+ return "glsl";
+}
+
+String ResourceImporterShaderFile::get_visible_name() const {
+ return "GLSL Shader File";
+}
+
+void ResourceImporterShaderFile::get_recognized_extensions(List<String> *p_extensions) const {
+ p_extensions->push_back("glsl");
+}
+
+String ResourceImporterShaderFile::get_save_extension() const {
+ return "res";
+}
+
+String ResourceImporterShaderFile::get_resource_type() const {
+ return "RDShaderFile";
+}
+
+int ResourceImporterShaderFile::get_preset_count() const {
+ return 0;
+}
+
+String ResourceImporterShaderFile::get_preset_name(int p_idx) const {
+ return String();
+}
+
+void ResourceImporterShaderFile::get_import_options(List<ImportOption> *r_options, int p_preset) const {
+}
+
+bool ResourceImporterShaderFile::get_option_visibility(const String &p_option, const Map<StringName, Variant> &p_options) const {
+ return true;
+}
+
+static String _include_function(const String &p_path, void *userpointer) {
+ Error err;
+
+ String *base_path = (String *)userpointer;
+
+ String include = p_path;
+ if (include.is_rel_path()) {
+ include = base_path->plus_file(include);
+ }
+
+ FileAccessRef file_inc = FileAccess::open(include, FileAccess::READ, &err);
+ if (err != OK) {
+ return String();
+ }
+ return file_inc->get_as_utf8_string();
+}
+
+Error ResourceImporterShaderFile::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) {
+ /* STEP 1, Read shader code */
+
+ Error err;
+ FileAccessRef file = FileAccess::open(p_source_file, FileAccess::READ, &err);
+ ERR_FAIL_COND_V(err != OK, ERR_CANT_OPEN);
+ ERR_FAIL_COND_V(!file.operator->(), ERR_CANT_OPEN);
+
+ String file_txt = file->get_as_utf8_string();
+ Ref<RDShaderFile> shader_file;
+ shader_file.instance();
+ String base_path = p_source_file.get_base_dir();
+ err = shader_file->parse_versions_from_text(file_txt, "", _include_function, &base_path);
+
+ if (err != OK) {
+ if (!ShaderFileEditor::singleton->is_visible_in_tree()) {
+ EditorNode::get_singleton()->add_io_error(vformat(TTR("Error importing GLSL shader file: '%s'. Open the file in the filesystem dock in order to see the reason."), p_source_file));
+ }
+ }
+
+ ResourceSaver::save(p_save_path + ".res", shader_file);
+
+ return OK;
+}
+
+ResourceImporterShaderFile::ResourceImporterShaderFile() {
+}
diff --git a/editor/import/resource_importer_shader_file.h b/editor/import/resource_importer_shader_file.h
new file mode 100644
index 0000000000..fa95ceecc1
--- /dev/null
+++ b/editor/import/resource_importer_shader_file.h
@@ -0,0 +1,57 @@
+/*************************************************************************/
+/* resource_importer_shader_file.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef RESOURCE_IMPORTER_SHADER_FILE_H
+#define RESOURCE_IMPORTER_SHADER_FILE_H
+
+#include "core/io/resource_importer.h"
+
+class ResourceImporterShaderFile : public ResourceImporter {
+ GDCLASS(ResourceImporterShaderFile, ResourceImporter);
+
+public:
+ virtual String get_importer_name() const;
+ virtual String get_visible_name() const;
+ virtual void get_recognized_extensions(List<String> *p_extensions) const;
+ virtual String get_save_extension() const;
+ virtual String get_resource_type() const;
+
+ virtual int get_preset_count() const;
+ virtual String get_preset_name(int p_idx) const;
+
+ virtual void get_import_options(List<ImportOption> *r_options, int p_preset = 0) const;
+ virtual bool get_option_visibility(const String &p_option, const Map<StringName, Variant> &p_options) const;
+
+ virtual Error 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 = nullptr, Variant *r_metadata = nullptr);
+
+ ResourceImporterShaderFile();
+};
+
+#endif // RESOURCE_IMPORTER_SHADER_FILE_H
diff --git a/editor/import/resource_importer_texture.cpp b/editor/import/resource_importer_texture.cpp
index 25431179b5..a13324f0fc 100644
--- a/editor/import/resource_importer_texture.cpp
+++ b/editor/import/resource_importer_texture.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -32,103 +32,101 @@
#include "core/io/config_file.h"
#include "core/io/image_loader.h"
+#include "core/version.h"
#include "editor/editor_file_system.h"
#include "editor/editor_node.h"
-#include "scene/resources/texture.h"
-void ResourceImporterTexture::_texture_reimport_srgb(const Ref<StreamTexture> &p_tex) {
+void ResourceImporterTexture::_texture_reimport_roughness(const Ref<StreamTexture2D> &p_tex, const String &p_normal_path, RS::TextureDetectRoughnessChannel p_channel) {
+ MutexLock lock(singleton->mutex);
- singleton->mutex->lock();
StringName path = p_tex->get_path();
if (!singleton->make_flags.has(path)) {
- singleton->make_flags[path] = 0;
+ singleton->make_flags[path] = MakeInfo();
}
- singleton->make_flags[path] |= MAKE_SRGB_FLAG;
-
- singleton->mutex->unlock();
+ singleton->make_flags[path].flags |= MAKE_ROUGHNESS_FLAG;
+ singleton->make_flags[path].channel_for_roughness = p_channel;
+ singleton->make_flags[path].normal_path_for_roughness = p_normal_path;
}
-void ResourceImporterTexture::_texture_reimport_3d(const Ref<StreamTexture> &p_tex) {
+void ResourceImporterTexture::_texture_reimport_3d(const Ref<StreamTexture2D> &p_tex) {
+ MutexLock lock(singleton->mutex);
- singleton->mutex->lock();
StringName path = p_tex->get_path();
if (!singleton->make_flags.has(path)) {
- singleton->make_flags[path] = 0;
+ singleton->make_flags[path] = MakeInfo();
}
- singleton->make_flags[path] |= MAKE_3D_FLAG;
-
- singleton->mutex->unlock();
+ singleton->make_flags[path].flags |= MAKE_3D_FLAG;
}
-void ResourceImporterTexture::_texture_reimport_normal(const Ref<StreamTexture> &p_tex) {
+void ResourceImporterTexture::_texture_reimport_normal(const Ref<StreamTexture2D> &p_tex) {
+ MutexLock lock(singleton->mutex);
- singleton->mutex->lock();
StringName path = p_tex->get_path();
if (!singleton->make_flags.has(path)) {
- singleton->make_flags[path] = 0;
+ singleton->make_flags[path] = MakeInfo();
}
- singleton->make_flags[path] |= MAKE_NORMAL_FLAG;
-
- singleton->mutex->unlock();
+ singleton->make_flags[path].flags |= MAKE_NORMAL_FLAG;
}
void ResourceImporterTexture::update_imports() {
-
if (EditorFileSystem::get_singleton()->is_scanning() || EditorFileSystem::get_singleton()->is_importing()) {
return; // do nothing for now
}
- mutex->lock();
-
- if (make_flags.empty()) {
- mutex->unlock();
- return;
- }
+ MutexLock lock(mutex);
Vector<String> to_reimport;
- for (Map<StringName, int>::Element *E = make_flags.front(); E; E = E->next()) {
+ {
+ if (make_flags.empty()) {
+ return;
+ }
- Ref<ConfigFile> cf;
- cf.instance();
- String src_path = String(E->key()) + ".import";
+ for (Map<StringName, MakeInfo>::Element *E = make_flags.front(); E; E = E->next()) {
+ Ref<ConfigFile> cf;
+ cf.instance();
+ String src_path = String(E->key()) + ".import";
- Error err = cf->load(src_path);
- ERR_CONTINUE(err != OK);
+ Error err = cf->load(src_path);
+ ERR_CONTINUE(err != OK);
- bool changed = false;
- if (E->get() & MAKE_SRGB_FLAG && int(cf->get_value("params", "flags/srgb")) == 2) {
- cf->set_value("params", "flags/srgb", 1);
- changed = true;
- }
+ bool changed = false;
- if (E->get() & MAKE_NORMAL_FLAG && int(cf->get_value("params", "compress/normal_map")) == 0) {
- cf->set_value("params", "compress/normal_map", 1);
- changed = true;
- }
+ if (E->get().flags & MAKE_NORMAL_FLAG && int(cf->get_value("params", "compress/normal_map")) == 0) {
+ cf->set_value("params", "compress/normal_map", 1);
+ changed = true;
+ }
- if (E->get() & MAKE_3D_FLAG && bool(cf->get_value("params", "detect_3d"))) {
- cf->set_value("params", "detect_3d", false);
- cf->set_value("params", "compress/mode", 2);
- cf->set_value("params", "flags/repeat", true);
- cf->set_value("params", "flags/filter", true);
- cf->set_value("params", "flags/mipmaps", true);
- changed = true;
- }
+ if (E->get().flags & MAKE_ROUGHNESS_FLAG && int(cf->get_value("params", "roughness/mode")) == 0) {
+ cf->set_value("params", "roughness/mode", E->get().channel_for_roughness + 2);
+ cf->set_value("params", "roughness/src_normal", E->get().normal_path_for_roughness);
+ changed = true;
+ }
- if (changed) {
- cf->save(src_path);
- to_reimport.push_back(E->key());
- }
- }
+ if (E->get().flags & MAKE_3D_FLAG && bool(cf->get_value("params", "detect_3d/compress_to"))) {
+ int compress_to = cf->get_value("params", "detect_3d/compress_to");
+ cf->set_value("params", "detect_3d/compress_to", 0);
+ if (compress_to == 1) {
+ cf->set_value("params", "compress/mode", COMPRESS_VRAM_COMPRESSED);
+ } else if (compress_to == 2) {
+ cf->set_value("params", "compress/mode", COMPRESS_BASIS_UNIVERSAL);
+ }
+ cf->set_value("params", "mipmaps/generate", true);
+ changed = true;
+ }
- make_flags.clear();
+ if (changed) {
+ cf->save(src_path);
+ to_reimport.push_back(E->key());
+ }
+ }
- mutex->unlock();
+ make_flags.clear();
+ }
if (to_reimport.size()) {
EditorFileSystem::get_singleton()->reimport_files(to_reimport);
@@ -136,42 +134,42 @@ void ResourceImporterTexture::update_imports() {
}
String ResourceImporterTexture::get_importer_name() const {
-
return "texture";
}
String ResourceImporterTexture::get_visible_name() const {
-
- return "Texture";
+ return "Texture2D";
}
-void ResourceImporterTexture::get_recognized_extensions(List<String> *p_extensions) const {
+void ResourceImporterTexture::get_recognized_extensions(List<String> *p_extensions) const {
ImageLoader::get_recognized_extensions(p_extensions);
}
+
String ResourceImporterTexture::get_save_extension() const {
return "stex";
}
String ResourceImporterTexture::get_resource_type() const {
-
- return "StreamTexture";
+ return "StreamTexture2D";
}
bool ResourceImporterTexture::get_option_visibility(const String &p_option, const Map<StringName, Variant> &p_options) const {
-
if (p_option == "compress/lossy_quality") {
int compress_mode = int(p_options["compress/mode"]);
- if (compress_mode != COMPRESS_LOSSY && compress_mode != COMPRESS_VIDEO_RAM) {
+ if (compress_mode != COMPRESS_LOSSY && compress_mode != COMPRESS_VRAM_COMPRESSED) {
return false;
}
} else if (p_option == "compress/hdr_mode") {
int compress_mode = int(p_options["compress/mode"]);
- if (compress_mode != COMPRESS_VIDEO_RAM) {
+ if (compress_mode < COMPRESS_VRAM_COMPRESSED) {
return false;
}
+ } else if (p_option == "mipmaps/limit") {
+ return p_options["mipmaps/generate"];
+
} else if (p_option == "compress/bptc_ldr") {
int compress_mode = int(p_options["compress/mode"]);
- if (compress_mode != COMPRESS_VIDEO_RAM) {
+ if (compress_mode < COMPRESS_VRAM_COMPRESSED) {
return false;
}
if (!ProjectSettings::get_singleton()->get("rendering/vram_compression/import_bptc")) {
@@ -185,8 +183,8 @@ bool ResourceImporterTexture::get_option_visibility(const String &p_option, cons
int ResourceImporterTexture::get_preset_count() const {
return 4;
}
-String ResourceImporterTexture::get_preset_name(int p_idx) const {
+String ResourceImporterTexture::get_preset_name(int p_idx) const {
static const char *preset_names[] = {
"2D, Detect 3D",
"2D",
@@ -198,225 +196,228 @@ String ResourceImporterTexture::get_preset_name(int p_idx) const {
}
void ResourceImporterTexture::get_import_options(List<ImportOption> *r_options, int p_preset) const {
-
- r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "compress/mode", PROPERTY_HINT_ENUM, "Lossless,Lossy,Video RAM,Uncompressed", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), p_preset == PRESET_3D ? 2 : 0));
- r_options->push_back(ImportOption(PropertyInfo(Variant::REAL, "compress/lossy_quality", PROPERTY_HINT_RANGE, "0,1,0.01"), 0.7));
- r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "compress/hdr_mode", PROPERTY_HINT_ENUM, "Enabled,Force RGBE"), 0));
- r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "compress/bptc_ldr", PROPERTY_HINT_ENUM, "Enabled,RGBA Only"), 0));
+ r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "compress/mode", PROPERTY_HINT_ENUM, "Lossless,Lossy,VRAM Compressed,VRAM Uncompressed,Basis Universal", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), p_preset == PRESET_3D ? 2 : 0));
+ r_options->push_back(ImportOption(PropertyInfo(Variant::FLOAT, "compress/lossy_quality", PROPERTY_HINT_RANGE, "0,1,0.01"), 0.7));
+ r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "compress/hdr_compression", PROPERTY_HINT_ENUM, "Disabled,Opaque Only,Always"), 1));
+ r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "compress/bptc_ldr", PROPERTY_HINT_ENUM, "Disabled,Enabled,RGBA Only"), 0));
r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "compress/normal_map", PROPERTY_HINT_ENUM, "Detect,Enable,Disabled"), 0));
- r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "flags/repeat", PROPERTY_HINT_ENUM, "Disabled,Enabled,Mirrored"), p_preset == PRESET_3D ? 1 : 0));
- r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "flags/filter"), p_preset != PRESET_2D_PIXEL));
- r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "flags/mipmaps"), p_preset == PRESET_3D));
- r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "flags/anisotropic"), false));
- r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "flags/srgb", PROPERTY_HINT_ENUM, "Disable,Enable,Detect"), 2));
+ r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "compress/channel_pack", PROPERTY_HINT_ENUM, "sRGB Friendly,Optimized"), 0));
+ r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "compress/streamed"), false));
+ r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "mipmaps/generate"), (p_preset == PRESET_3D ? true : false)));
+ r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "mipmaps/limit", PROPERTY_HINT_RANGE, "-1,256"), -1));
+ r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "roughness/mode", PROPERTY_HINT_ENUM, "Detect,Disabled,Red,Green,Blue,Alpha,Gray"), 0));
+ r_options->push_back(ImportOption(PropertyInfo(Variant::STRING, "roughness/src_normal", PROPERTY_HINT_FILE, "*.png,*.jpg"), ""));
r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "process/fix_alpha_border"), p_preset != PRESET_3D));
r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "process/premult_alpha"), false));
- r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "process/HDR_as_SRGB"), false));
r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "process/invert_color"), false));
- r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "stream"), false));
- r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "size_limit", PROPERTY_HINT_RANGE, "0,4096,1"), 0));
- r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "detect_3d"), p_preset == PRESET_DETECT));
- r_options->push_back(ImportOption(PropertyInfo(Variant::REAL, "svg/scale", PROPERTY_HINT_RANGE, "0.001,100,0.001"), 1.0));
+ r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "process/HDR_as_SRGB"), false));
+ r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "process/size_limit", PROPERTY_HINT_RANGE, "0,4096,1"), 0));
+ r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "detect_3d/compress_to", PROPERTY_HINT_ENUM, "Disabled,VRAM Compressed,Basis Universal"), (p_preset == PRESET_DETECT) ? 1 : 0));
+ r_options->push_back(ImportOption(PropertyInfo(Variant::FLOAT, "svg/scale", PROPERTY_HINT_RANGE, "0.001,100,0.001"), 1.0));
}
-void ResourceImporterTexture::_save_stex(const Ref<Image> &p_image, const String &p_to_path, int p_compress_mode, float p_lossy_quality, Image::CompressMode p_vram_compression, bool p_mipmaps, int p_texture_flags, bool p_streamable, bool p_detect_3d, bool p_detect_srgb, bool p_force_rgbe, bool p_detect_normal, bool p_force_normal, bool p_force_po2_for_compressed) {
-
- FileAccess *f = FileAccess::open(p_to_path, FileAccess::WRITE);
- f->store_8('G');
- f->store_8('D');
- f->store_8('S');
- f->store_8('T'); //godot streamable texture
-
- bool resize_to_po2 = false;
-
- if (p_compress_mode == COMPRESS_VIDEO_RAM && p_force_po2_for_compressed && (p_mipmaps || p_texture_flags & Texture::FLAG_REPEAT)) {
- resize_to_po2 = true;
- f->store_16(next_power_of_2(p_image->get_width()));
- f->store_16(p_image->get_width());
- f->store_16(next_power_of_2(p_image->get_height()));
- f->store_16(p_image->get_height());
- } else {
- f->store_16(p_image->get_width());
- f->store_16(0);
- f->store_16(p_image->get_height());
- f->store_16(0);
- }
- f->store_32(p_texture_flags);
-
- uint32_t format = 0;
-
- if (p_streamable)
- format |= StreamTexture::FORMAT_BIT_STREAM;
- if (p_mipmaps)
- format |= StreamTexture::FORMAT_BIT_HAS_MIPMAPS; //mipmaps bit
- if (p_detect_3d)
- format |= StreamTexture::FORMAT_BIT_DETECT_3D;
- if (p_detect_srgb)
- format |= StreamTexture::FORMAT_BIT_DETECT_SRGB;
- if (p_detect_normal)
- format |= StreamTexture::FORMAT_BIT_DETECT_NORMAL;
-
- if ((p_compress_mode == COMPRESS_LOSSLESS || p_compress_mode == COMPRESS_LOSSY) && p_image->get_format() > Image::FORMAT_RGBA8) {
- p_compress_mode = COMPRESS_UNCOMPRESSED; //these can't go as lossy
- }
-
+void ResourceImporterTexture::save_to_stex_format(FileAccess *f, const Ref<Image> &p_image, CompressMode p_compress_mode, Image::UsedChannels p_channels, Image::CompressMode p_compress_format, float p_lossy_quality) {
switch (p_compress_mode) {
case COMPRESS_LOSSLESS: {
+ f->store_32(StreamTexture2D::DATA_FORMAT_LOSSLESS);
+ f->store_16(p_image->get_width());
+ f->store_16(p_image->get_height());
+ f->store_32(p_image->get_mipmap_count());
+ f->store_32(p_image->get_format());
+
+ for (int i = 0; i < p_image->get_mipmap_count() + 1; i++) {
+ Vector<uint8_t> data = Image::lossless_packer(p_image->get_image_from_mipmap(i));
+ int data_len = data.size();
+ f->store_32(data_len);
- Ref<Image> image = p_image->duplicate();
- if (p_mipmaps) {
- image->generate_mipmaps();
- } else {
- image->clear_mipmaps();
+ const uint8_t *r = data.ptr();
+ f->store_buffer(r, data_len);
}
- int mmc = image->get_mipmap_count() + 1;
-
- format |= StreamTexture::FORMAT_BIT_LOSSLESS;
- f->store_32(format);
- f->store_32(mmc);
-
- for (int i = 0; i < mmc; i++) {
-
- if (i > 0) {
- image->shrink_x2();
- }
-
- PoolVector<uint8_t> data = Image::lossless_packer(image);
+ } break;
+ case COMPRESS_LOSSY: {
+ f->store_32(StreamTexture2D::DATA_FORMAT_LOSSY);
+ f->store_16(p_image->get_width());
+ f->store_16(p_image->get_height());
+ f->store_32(p_image->get_mipmap_count());
+ f->store_32(p_image->get_format());
+
+ for (int i = 0; i < p_image->get_mipmap_count() + 1; i++) {
+ Vector<uint8_t> data = Image::lossy_packer(p_image->get_image_from_mipmap(i), p_lossy_quality);
int data_len = data.size();
f->store_32(data_len);
- PoolVector<uint8_t>::Read r = data.read();
- f->store_buffer(r.ptr(), data_len);
+ const uint8_t *r = data.ptr();
+ f->store_buffer(r, data_len);
}
-
} break;
- case COMPRESS_LOSSY: {
+ case COMPRESS_VRAM_COMPRESSED: {
Ref<Image> image = p_image->duplicate();
- if (p_mipmaps) {
- image->generate_mipmaps();
- } else {
- image->clear_mipmaps();
- }
- int mmc = image->get_mipmap_count() + 1;
+ image->compress_from_channels(p_compress_format, p_channels, p_lossy_quality);
- format |= StreamTexture::FORMAT_BIT_LOSSY;
- f->store_32(format);
- f->store_32(mmc);
+ f->store_32(StreamTexture2D::DATA_FORMAT_IMAGE);
+ f->store_16(image->get_width());
+ f->store_16(image->get_height());
+ f->store_32(image->get_mipmap_count());
+ f->store_32(image->get_format());
- for (int i = 0; i < mmc; i++) {
+ Vector<uint8_t> data = image->get_data();
+ int dl = data.size();
+ const uint8_t *r = data.ptr();
+ f->store_buffer(r, dl);
+ } break;
+ case COMPRESS_VRAM_UNCOMPRESSED: {
+ f->store_32(StreamTexture2D::DATA_FORMAT_IMAGE);
+ f->store_16(p_image->get_width());
+ f->store_16(p_image->get_height());
+ f->store_32(p_image->get_mipmap_count());
+ f->store_32(p_image->get_format());
+
+ Vector<uint8_t> data = p_image->get_data();
+ int dl = data.size();
+ const uint8_t *r = data.ptr();
- if (i > 0) {
- image->shrink_x2();
- }
+ f->store_buffer(r, dl);
- PoolVector<uint8_t> data = Image::lossy_packer(image, p_lossy_quality);
+ } break;
+ case COMPRESS_BASIS_UNIVERSAL: {
+ f->store_32(StreamTexture2D::DATA_FORMAT_BASIS_UNIVERSAL);
+ f->store_16(p_image->get_width());
+ f->store_16(p_image->get_height());
+ f->store_32(p_image->get_mipmap_count());
+ f->store_32(p_image->get_format());
+
+ for (int i = 0; i < p_image->get_mipmap_count() + 1; i++) {
+ Vector<uint8_t> data = Image::basis_universal_packer(p_image->get_image_from_mipmap(i), p_channels);
int data_len = data.size();
f->store_32(data_len);
- PoolVector<uint8_t>::Read r = data.read();
- f->store_buffer(r.ptr(), data_len);
+ const uint8_t *r = data.ptr();
+ f->store_buffer(r, data_len);
}
} break;
- case COMPRESS_VIDEO_RAM: {
+ }
+}
- Ref<Image> image = p_image->duplicate();
- if (resize_to_po2) {
- image->resize_to_po2();
- }
- if (p_mipmaps) {
- image->generate_mipmaps(p_force_normal);
- }
+void ResourceImporterTexture::_save_stex(const Ref<Image> &p_image, const String &p_to_path, CompressMode p_compress_mode, float p_lossy_quality, Image::CompressMode p_vram_compression, bool p_mipmaps, bool p_streamable, bool p_detect_3d, bool p_detect_roughness, bool p_detect_normal, bool p_force_normal, bool p_srgb_friendly, bool p_force_po2_for_compressed, uint32_t p_limit_mipmap, const Ref<Image> &p_normal, Image::RoughnessChannel p_roughness_channel) {
+ FileAccess *f = FileAccess::open(p_to_path, FileAccess::WRITE);
+ f->store_8('G');
+ f->store_8('S');
+ f->store_8('T');
+ f->store_8('2'); //godot streamable texture 2D
+
+ //format version
+ f->store_32(StreamTexture2D::FORMAT_VERSION);
+ //texture may be resized later, so original size must be saved first
+ f->store_32(p_image->get_width());
+ f->store_32(p_image->get_height());
+
+ uint32_t flags = 0;
+ if (p_streamable) {
+ flags |= StreamTexture2D::FORMAT_BIT_STREAM;
+ }
+ if (p_mipmaps) {
+ flags |= StreamTexture2D::FORMAT_BIT_HAS_MIPMAPS; //mipmaps bit
+ }
+ if (p_detect_3d) {
+ flags |= StreamTexture2D::FORMAT_BIT_DETECT_3D;
+ }
+ if (p_detect_roughness) {
+ flags |= StreamTexture2D::FORMAT_BIT_DETECT_ROUGNESS;
+ }
+ if (p_detect_normal) {
+ flags |= StreamTexture2D::FORMAT_BIT_DETECT_NORMAL;
+ }
- if (p_force_rgbe && image->get_format() >= Image::FORMAT_R8 && image->get_format() <= Image::FORMAT_RGBE9995) {
- image->convert(Image::FORMAT_RGBE9995);
- } else {
- Image::CompressSource csource = Image::COMPRESS_SOURCE_GENERIC;
- if (p_force_normal) {
- csource = Image::COMPRESS_SOURCE_NORMAL;
- } else if (p_texture_flags & VS::TEXTURE_FLAG_CONVERT_TO_LINEAR) {
- csource = Image::COMPRESS_SOURCE_SRGB;
- }
+ f->store_32(flags);
+ f->store_32(p_limit_mipmap);
+ //reserved for future use
+ f->store_32(0);
+ f->store_32(0);
+ f->store_32(0);
+
+ /*
+ print_line("streamable " + itos(p_streamable));
+ print_line("mipmaps " + itos(p_mipmaps));
+ print_line("detect_3d " + itos(p_detect_3d));
+ print_line("roughness " + itos(p_detect_roughness));
+ print_line("normal " + itos(p_detect_normal));
+*/
- image->compress(p_vram_compression, csource, p_lossy_quality);
- }
+ if ((p_compress_mode == COMPRESS_LOSSLESS || p_compress_mode == COMPRESS_LOSSY) && p_image->get_format() > Image::FORMAT_RGBA8) {
+ p_compress_mode = COMPRESS_VRAM_UNCOMPRESSED; //these can't go as lossy
+ }
- format |= image->get_format();
+ Ref<Image> image = p_image->duplicate();
- f->store_32(format);
+ if (((p_compress_mode == COMPRESS_BASIS_UNIVERSAL) || (p_compress_mode == COMPRESS_VRAM_COMPRESSED && p_force_po2_for_compressed)) && p_mipmaps) {
+ image->resize_to_po2();
+ }
- PoolVector<uint8_t> data = image->get_data();
- int dl = data.size();
- PoolVector<uint8_t>::Read r = data.read();
- f->store_buffer(r.ptr(), dl);
- } break;
- case COMPRESS_UNCOMPRESSED: {
+ if (p_mipmaps && (!image->has_mipmaps() || p_force_normal)) {
+ image->generate_mipmaps(p_force_normal);
+ }
- Ref<Image> image = p_image->duplicate();
- if (p_mipmaps) {
- image->generate_mipmaps();
- } else {
- image->clear_mipmaps();
- }
+ if (!p_mipmaps) {
+ image->clear_mipmaps();
+ }
- format |= image->get_format();
- f->store_32(format);
+ if (image->has_mipmaps() && p_normal.is_valid()) {
+ image->generate_mipmap_roughness(p_roughness_channel, p_normal);
+ }
- PoolVector<uint8_t> data = image->get_data();
- int dl = data.size();
- PoolVector<uint8_t>::Read r = data.read();
+ Image::CompressSource csource = Image::COMPRESS_SOURCE_GENERIC;
+ if (p_force_normal) {
+ csource = Image::COMPRESS_SOURCE_NORMAL;
+ } else if (p_srgb_friendly) {
+ csource = Image::COMPRESS_SOURCE_SRGB;
+ }
- f->store_buffer(r.ptr(), dl);
+ Image::UsedChannels used_channels = image->detect_used_channels(csource);
- } break;
- }
+ save_to_stex_format(f, image, p_compress_mode, used_channels, p_vram_compression, p_lossy_quality);
memdelete(f);
}
Error ResourceImporterTexture::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) {
-
- int compress_mode = p_options["compress/mode"];
+ CompressMode compress_mode = CompressMode(int(p_options["compress/mode"]));
float lossy = p_options["compress/lossy_quality"];
- int repeat = p_options["flags/repeat"];
- bool filter = p_options["flags/filter"];
- bool mipmaps = p_options["flags/mipmaps"];
- bool anisotropic = p_options["flags/anisotropic"];
- int srgb = p_options["flags/srgb"];
+ int pack_channels = p_options["compress/channel_pack"];
+ bool mipmaps = p_options["mipmaps/generate"];
+ uint32_t mipmap_limit = int(mipmaps ? int(p_options["mipmaps/limit"]) : int(-1));
bool fix_alpha_border = p_options["process/fix_alpha_border"];
bool premult_alpha = p_options["process/premult_alpha"];
bool invert_color = p_options["process/invert_color"];
- bool stream = p_options["stream"];
- int size_limit = p_options["size_limit"];
+ bool stream = p_options["compress/streamed"];
+ int size_limit = p_options["process/size_limit"];
bool hdr_as_srgb = p_options["process/HDR_as_SRGB"];
int normal = p_options["compress/normal_map"];
float scale = p_options["svg/scale"];
- bool force_rgbe = p_options["compress/hdr_mode"];
+ int hdr_compression = p_options["compress/hdr_compression"];
int bptc_ldr = p_options["compress/bptc_ldr"];
+ int roughness = p_options["roughness/mode"];
+ String normal_map = p_options["roughness/src_normal"];
+ Ref<Image> normal_image;
+ Image::RoughnessChannel roughness_channel = Image::ROUGHNESS_CHANNEL_R;
+
+ if (mipmaps && roughness > 1 && FileAccess::exists(normal_map)) {
+ normal_image.instance();
+ if (ImageLoader::load_image(normal_map, normal_image) == OK) {
+ roughness_channel = Image::RoughnessChannel(roughness - 2);
+ }
+ }
Ref<Image> image;
image.instance();
- Error err = ImageLoader::load_image(p_source_file, image, NULL, hdr_as_srgb, scale);
- if (err != OK)
+ Error err = ImageLoader::load_image(p_source_file, image, nullptr, hdr_as_srgb, scale);
+ if (err != OK) {
return err;
+ }
Array formats_imported;
- int tex_flags = 0;
- if (repeat > 0)
- tex_flags |= Texture::FLAG_REPEAT;
- if (repeat == 2)
- tex_flags |= Texture::FLAG_MIRRORED_REPEAT;
- if (filter)
- tex_flags |= Texture::FLAG_FILTER;
- if (mipmaps || compress_mode == COMPRESS_VIDEO_RAM)
- tex_flags |= Texture::FLAG_MIPMAPS;
- if (anisotropic)
- tex_flags |= Texture::FLAG_ANISOTROPIC_FILTER;
- if (srgb == 1)
- tex_flags |= Texture::FLAG_CONVERT_TO_LINEAR;
-
if (size_limit > 0 && (image->get_width() > size_limit || image->get_height() > size_limit)) {
//limit size
if (image->get_width() >= image->get_height()) {
@@ -425,7 +426,6 @@ Error ResourceImporterTexture::import(const String &p_source_file, const String
image->resize(new_width, new_height, Image::INTERPOLATE_CUBIC);
} else {
-
int new_height = size_limit;
int new_width = image->get_width() * new_height / image->get_height();
@@ -449,76 +449,96 @@ Error ResourceImporterTexture::import(const String &p_source_file, const String
int height = image->get_height();
int width = image->get_width();
- image->lock();
for (int i = 0; i < width; i++) {
for (int j = 0; j < height; j++) {
image->set_pixel(i, j, image->get_pixel(i, j).inverted());
}
}
- image->unlock();
}
- bool detect_3d = p_options["detect_3d"];
- bool detect_srgb = srgb == 2;
+ if (compress_mode == COMPRESS_BASIS_UNIVERSAL && image->get_format() >= Image::FORMAT_RF) {
+ //basis universal does not support float formats, fall back
+ compress_mode = COMPRESS_VRAM_COMPRESSED;
+ }
+
+ bool detect_3d = int(p_options["detect_3d/compress_to"]) > 0;
+ bool detect_roughness = roughness == 0;
bool detect_normal = normal == 0;
bool force_normal = normal == 1;
+ bool srgb_friendly_pack = pack_channels == 0;
- if (compress_mode == COMPRESS_VIDEO_RAM) {
+ if (compress_mode == COMPRESS_VRAM_COMPRESSED) {
//must import in all formats, in order of priority (so platform choses the best supported one. IE, etc2 over etc).
//Android, GLES 2.x
bool ok_on_pc = false;
bool is_hdr = (image->get_format() >= Image::FORMAT_RF && image->get_format() <= Image::FORMAT_RGBE9995);
- bool is_ldr = (image->get_format() >= Image::FORMAT_L8 && image->get_format() <= Image::FORMAT_RGBA5551);
+ bool is_ldr = (image->get_format() >= Image::FORMAT_L8 && image->get_format() <= Image::FORMAT_RGB565);
bool can_bptc = ProjectSettings::get_singleton()->get("rendering/vram_compression/import_bptc");
bool can_s3tc = ProjectSettings::get_singleton()->get("rendering/vram_compression/import_s3tc");
if (can_bptc) {
- Image::DetectChannels channels = image->get_detected_channels();
- if (is_hdr) {
+ //add to the list anyway
+ formats_imported.push_back("bptc");
+ }
- if (channels == Image::DETECTED_LA || channels == Image::DETECTED_RGBA) {
- can_bptc = false;
+ bool can_compress_hdr = hdr_compression > 0;
+ bool has_alpha = image->detect_alpha() != Image::ALPHA_NONE;
+
+ if (is_hdr && can_compress_hdr) {
+ if (has_alpha) {
+ //can compress hdr, but hdr with alpha is not compressible
+ if (hdr_compression == 2) {
+ //but user selected to compress hdr anyway, so force an alpha-less format.
+ if (image->get_format() == Image::FORMAT_RGBAF) {
+ image->convert(Image::FORMAT_RGBF);
+ } else if (image->get_format() == Image::FORMAT_RGBAH) {
+ image->convert(Image::FORMAT_RGBH);
+ }
+ } else {
+ can_compress_hdr = false;
}
- } else if (is_ldr) {
+ }
- //handle "RGBA Only" setting
- if (bptc_ldr == 1 && channels != Image::DETECTED_LA && channels != Image::DETECTED_RGBA) {
- can_bptc = false;
+ if (can_compress_hdr) {
+ if (!can_bptc) {
+ //fallback to RGBE99995
+ if (image->get_format() != Image::FORMAT_RGBE9995) {
+ image->convert(Image::FORMAT_RGBE9995);
+ }
}
+ } else {
+ can_bptc = false;
}
-
- formats_imported.push_back("bptc");
}
- if (!can_bptc && is_hdr && !force_rgbe) {
- //convert to ldr if this can't be stored hdr
- image->convert(Image::FORMAT_RGBA8);
+ if (is_ldr && can_bptc) {
+ if (bptc_ldr == 0 || (bptc_ldr == 1 && !has_alpha)) {
+ can_bptc = false;
+ }
}
if (can_bptc || can_s3tc) {
- _save_stex(image, p_save_path + ".s3tc.stex", compress_mode, lossy, can_bptc ? Image::COMPRESS_BPTC : Image::COMPRESS_S3TC, mipmaps, tex_flags, stream, detect_3d, detect_srgb, force_rgbe, detect_normal, force_normal, false);
+ _save_stex(image, p_save_path + ".s3tc.stex", compress_mode, lossy, can_bptc ? Image::COMPRESS_BPTC : Image::COMPRESS_S3TC, mipmaps, stream, detect_3d, detect_roughness, detect_normal, force_normal, srgb_friendly_pack, false, mipmap_limit, normal_image, roughness_channel);
r_platform_variants->push_back("s3tc");
formats_imported.push_back("s3tc");
ok_on_pc = true;
}
if (ProjectSettings::get_singleton()->get("rendering/vram_compression/import_etc2")) {
-
- _save_stex(image, p_save_path + ".etc2.stex", compress_mode, lossy, Image::COMPRESS_ETC2, mipmaps, tex_flags, stream, detect_3d, detect_srgb, force_rgbe, detect_normal, force_normal, true);
+ _save_stex(image, p_save_path + ".etc2.stex", compress_mode, lossy, Image::COMPRESS_ETC2, mipmaps, stream, detect_3d, detect_roughness, detect_normal, force_normal, srgb_friendly_pack, true, mipmap_limit, normal_image, roughness_channel);
r_platform_variants->push_back("etc2");
formats_imported.push_back("etc2");
}
if (ProjectSettings::get_singleton()->get("rendering/vram_compression/import_etc")) {
- _save_stex(image, p_save_path + ".etc.stex", compress_mode, lossy, Image::COMPRESS_ETC, mipmaps, tex_flags, stream, detect_3d, detect_srgb, force_rgbe, detect_normal, force_normal, true);
+ _save_stex(image, p_save_path + ".etc.stex", compress_mode, lossy, Image::COMPRESS_ETC, mipmaps, stream, detect_3d, detect_roughness, detect_normal, force_normal, srgb_friendly_pack, true, mipmap_limit, normal_image, roughness_channel);
r_platform_variants->push_back("etc");
formats_imported.push_back("etc");
}
if (ProjectSettings::get_singleton()->get("rendering/vram_compression/import_pvrtc")) {
-
- _save_stex(image, p_save_path + ".pvrtc.stex", compress_mode, lossy, Image::COMPRESS_PVRTC4, mipmaps, tex_flags, stream, detect_3d, detect_srgb, force_rgbe, detect_normal, force_normal, true);
+ _save_stex(image, p_save_path + ".pvrtc.stex", compress_mode, lossy, Image::COMPRESS_PVRTC4, mipmaps, stream, detect_3d, detect_roughness, detect_normal, force_normal, srgb_friendly_pack, true, mipmap_limit, normal_image, roughness_channel);
r_platform_variants->push_back("pvrtc");
formats_imported.push_back("pvrtc");
}
@@ -528,12 +548,12 @@ Error ResourceImporterTexture::import(const String &p_source_file, const String
}
} else {
//import normally
- _save_stex(image, p_save_path + ".stex", compress_mode, lossy, Image::COMPRESS_S3TC /*this is ignored */, mipmaps, tex_flags, stream, detect_3d, detect_srgb, force_rgbe, detect_normal, force_normal, false);
+ _save_stex(image, p_save_path + ".stex", compress_mode, lossy, Image::COMPRESS_S3TC /*this is ignored */, mipmaps, stream, detect_3d, detect_roughness, detect_normal, force_normal, srgb_friendly_pack, false, mipmap_limit, normal_image, roughness_channel);
}
if (r_metadata) {
Dictionary metadata;
- metadata["vram_texture"] = compress_mode == COMPRESS_VIDEO_RAM;
+ metadata["vram_texture"] = compress_mode == COMPRESS_VRAM_COMPRESSED;
if (formats_imported.size()) {
metadata["imported_formats"] = formats_imported;
}
@@ -548,10 +568,9 @@ const char *ResourceImporterTexture::compression_formats[] = {
"etc",
"etc2",
"pvrtc",
- NULL
+ nullptr
};
String ResourceImporterTexture::get_import_settings_string() const {
-
String s;
int index = 0;
@@ -568,7 +587,6 @@ String ResourceImporterTexture::get_import_settings_string() const {
}
bool ResourceImporterTexture::are_import_settings_valid(const String &p_path) const {
-
//will become invalid if formats are missing to import
Dictionary metadata = ResourceFormatImporter::get_singleton()->get_resource_metadata(p_path);
@@ -603,18 +621,14 @@ bool ResourceImporterTexture::are_import_settings_valid(const String &p_path) co
return valid;
}
-ResourceImporterTexture *ResourceImporterTexture::singleton = NULL;
+ResourceImporterTexture *ResourceImporterTexture::singleton = nullptr;
ResourceImporterTexture::ResourceImporterTexture() {
-
singleton = this;
- StreamTexture::request_3d_callback = _texture_reimport_3d;
- StreamTexture::request_srgb_callback = _texture_reimport_srgb;
- StreamTexture::request_normal_callback = _texture_reimport_normal;
- mutex = Mutex::create();
+ StreamTexture2D::request_3d_callback = _texture_reimport_3d;
+ StreamTexture2D::request_roughness_callback = _texture_reimport_roughness;
+ StreamTexture2D::request_normal_callback = _texture_reimport_normal;
}
ResourceImporterTexture::~ResourceImporterTexture() {
-
- memdelete(mutex);
}
diff --git a/editor/import/resource_importer_texture.h b/editor/import/resource_importer_texture.h
index da712bf84d..b770d240eb 100644
--- a/editor/import/resource_importer_texture.h
+++ b/editor/import/resource_importer_texture.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -33,30 +33,56 @@
#include "core/image.h"
#include "core/io/resource_importer.h"
+#include "core/os/file_access.h"
+#include "scene/resources/texture.h"
+#include "servers/rendering_server.h"
-class StreamTexture;
+class StreamTexture2D;
class ResourceImporterTexture : public ResourceImporter {
GDCLASS(ResourceImporterTexture, ResourceImporter);
+public:
+ enum CompressMode {
+ COMPRESS_LOSSLESS,
+ COMPRESS_LOSSY,
+ COMPRESS_VRAM_COMPRESSED,
+ COMPRESS_VRAM_UNCOMPRESSED,
+ COMPRESS_BASIS_UNIVERSAL
+ };
+
protected:
enum {
MAKE_3D_FLAG = 1,
- MAKE_SRGB_FLAG = 2,
+ MAKE_ROUGHNESS_FLAG = 2,
MAKE_NORMAL_FLAG = 4
};
- Mutex *mutex;
- Map<StringName, int> make_flags;
+ Mutex mutex;
+ struct MakeInfo {
+ int flags;
+ String normal_path_for_roughness;
+ RS::TextureDetectRoughnessChannel channel_for_roughness;
+ MakeInfo() {
+ flags = 0;
+ channel_for_roughness = RS::TEXTURE_DETECT_ROUGNHESS_R;
+ }
+ };
+
+ Map<StringName, MakeInfo> make_flags;
- static void _texture_reimport_srgb(const Ref<StreamTexture> &p_tex);
- static void _texture_reimport_3d(const Ref<StreamTexture> &p_tex);
- static void _texture_reimport_normal(const Ref<StreamTexture> &p_tex);
+ static void _texture_reimport_roughness(const Ref<StreamTexture2D> &p_tex, const String &p_normal_path, RenderingServer::TextureDetectRoughnessChannel p_channel);
+ static void _texture_reimport_3d(const Ref<StreamTexture2D> &p_tex);
+ static void _texture_reimport_normal(const Ref<StreamTexture2D> &p_tex);
static ResourceImporterTexture *singleton;
static const char *compression_formats[];
+ void _save_stex(const Ref<Image> &p_image, const String &p_to_path, CompressMode p_compress_mode, float p_lossy_quality, Image::CompressMode p_vram_compression, bool p_mipmaps, bool p_streamable, bool p_detect_3d, bool p_detect_srgb, bool p_detect_normal, bool p_force_normal, bool p_srgb_friendly, bool p_force_po2_for_compressed, uint32_t p_limit_mipmap, const Ref<Image> &p_normal, Image::RoughnessChannel p_roughness_channel);
+
public:
+ static void save_to_stex_format(FileAccess *f, const Ref<Image> &p_image, CompressMode p_compress_mode, Image::UsedChannels p_channels, Image::CompressMode p_compress_format, float p_lossy_quality);
+
static ResourceImporterTexture *get_singleton() { return singleton; }
virtual String get_importer_name() const;
virtual String get_visible_name() const;
@@ -71,22 +97,13 @@ public:
PRESET_3D,
};
- enum CompressMode {
- COMPRESS_LOSSLESS,
- COMPRESS_LOSSY,
- COMPRESS_VIDEO_RAM,
- COMPRESS_UNCOMPRESSED
- };
-
virtual int get_preset_count() const;
virtual String get_preset_name(int p_idx) const;
virtual void get_import_options(List<ImportOption> *r_options, int p_preset = 0) const;
virtual bool get_option_visibility(const String &p_option, const Map<StringName, Variant> &p_options) const;
- void _save_stex(const Ref<Image> &p_image, const String &p_to_path, int p_compress_mode, float p_lossy_quality, Image::CompressMode p_vram_compression, bool p_mipmaps, int p_texture_flags, bool p_streamable, bool p_detect_3d, bool p_detect_srgb, bool p_force_rgbe, bool p_detect_normal, bool p_force_normal, bool p_force_po2_for_compressed);
-
- virtual Error 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 = NULL, Variant *r_metadata = NULL);
+ virtual Error 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 = nullptr, Variant *r_metadata = nullptr);
void update_imports();
diff --git a/editor/import/resource_importer_texture_atlas.cpp b/editor/import/resource_importer_texture_atlas.cpp
index 51a6cc6757..0818655c4c 100644
--- a/editor/import/resource_importer_texture_atlas.cpp
+++ b/editor/import/resource_importer_texture_atlas.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -39,16 +39,14 @@
#include "scene/resources/texture.h"
String ResourceImporterTextureAtlas::get_importer_name() const {
-
return "texture_atlas";
}
String ResourceImporterTextureAtlas::get_visible_name() const {
-
return "TextureAtlas";
}
-void ResourceImporterTextureAtlas::get_recognized_extensions(List<String> *p_extensions) const {
+void ResourceImporterTextureAtlas::get_recognized_extensions(List<String> *p_extensions) const {
ImageLoader::get_recognized_extensions(p_extensions);
}
@@ -57,25 +55,22 @@ String ResourceImporterTextureAtlas::get_save_extension() const {
}
String ResourceImporterTextureAtlas::get_resource_type() const {
-
- return "Texture";
+ return "Texture2D";
}
bool ResourceImporterTextureAtlas::get_option_visibility(const String &p_option, const Map<StringName, Variant> &p_options) const {
-
return true;
}
int ResourceImporterTextureAtlas::get_preset_count() const {
return 0;
}
-String ResourceImporterTextureAtlas::get_preset_name(int p_idx) const {
+String ResourceImporterTextureAtlas::get_preset_name(int p_idx) const {
return String();
}
void ResourceImporterTextureAtlas::get_import_options(List<ImportOption> *r_options, int p_preset) const {
-
r_options->push_back(ImportOption(PropertyInfo(Variant::STRING, "atlas_file", PROPERTY_HINT_SAVE_FILE, "*.png"), ""));
r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "import_mode", PROPERTY_HINT_ENUM, "Region,Mesh2D"), 0));
}
@@ -85,7 +80,6 @@ String ResourceImporterTextureAtlas::get_option_group_file() const {
}
Error ResourceImporterTextureAtlas::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) {
-
/* If this happens, it's because the atlas_file field was not filled, so just import a broken texture */
//use an xpm because it's size independent, the editor images are vector and size dependent
@@ -103,7 +97,6 @@ Error ResourceImporterTextureAtlas::import(const String &p_source_file, const St
}
static void _plot_triangle(Vector2 *vertices, const Vector2 &p_offset, bool p_transposed, Ref<Image> p_image, const Ref<Image> &p_src_image) {
-
int width = p_image->get_width();
int height = p_image->get_height();
int src_width = p_src_image->get_width();
@@ -113,7 +106,6 @@ static void _plot_triangle(Vector2 *vertices, const Vector2 &p_offset, bool p_tr
int y[3];
for (int j = 0; j < 3; j++) {
-
x[j] = vertices[j].x;
y[j] = vertices[j].y;
}
@@ -140,11 +132,10 @@ static void _plot_triangle(Vector2 *vertices, const Vector2 &p_offset, bool p_tr
for (int yi = y[0]; yi <= (y[2] > height - 1 ? height - 1 : y[2]); yi++) {
if (yi >= 0) {
for (int xi = (xf > 0 ? int(xf) : 0); xi <= (xt < width ? xt : width - 1); xi++) {
-
int px = xi, py = yi;
int sx = px, sy = py;
- sx = CLAMP(sx, 0, src_width);
- sy = CLAMP(sy, 0, src_height);
+ sx = CLAMP(sx, 0, src_width - 1);
+ sy = CLAMP(sy, 0, src_height - 1);
Color color = p_src_image->get_pixel(sx, sy);
if (p_transposed) {
SWAP(px, py);
@@ -165,8 +156,8 @@ static void _plot_triangle(Vector2 *vertices, const Vector2 &p_offset, bool p_tr
for (int xi = (xf < width ? int(xf) : width - 1); xi >= (xt > 0 ? xt : 0); xi--) {
int px = xi, py = yi;
int sx = px, sy = py;
- sx = CLAMP(sx, 0, src_width);
- sy = CLAMP(sy, 0, src_height);
+ sx = CLAMP(sx, 0, src_width - 1);
+ sy = CLAMP(sy, 0, src_height - 1);
Color color = p_src_image->get_pixel(sx, sy);
if (p_transposed) {
SWAP(px, py);
@@ -185,15 +176,15 @@ static void _plot_triangle(Vector2 *vertices, const Vector2 &p_offset, bool p_tr
}
}
xf += dx_far;
- if (yi < y[1])
+ if (yi < y[1]) {
xt += dx_upper;
- else
+ } else {
xt += dx_low;
+ }
}
}
-Error ResourceImporterTextureAtlas::import_group_file(const String &p_group_file, const Map<String, Map<StringName, Variant> > &p_source_file_options, const Map<String, String> &p_base_paths) {
-
+Error ResourceImporterTextureAtlas::import_group_file(const String &p_group_file, const Map<String, Map<StringName, Variant>> &p_source_file_options, const Map<String, String> &p_base_paths) {
ERR_FAIL_COND_V(p_source_file_options.size() == 0, ERR_BUG); //should never happen
Vector<EditorAtlasPacker::Chart> charts;
@@ -202,8 +193,7 @@ Error ResourceImporterTextureAtlas::import_group_file(const String &p_group_file
pack_data_files.resize(p_source_file_options.size());
int idx = 0;
- for (const Map<String, Map<StringName, Variant> >::Element *E = p_source_file_options.front(); E; E = E->next(), idx++) {
-
+ for (const Map<String, Map<StringName, Variant>>::Element *E = p_source_file_options.front(); E; E = E->next(), idx++) {
PackData &pack_data = pack_data_files.write[idx];
const String &source = E->key();
const Map<StringName, Variant> &options = E->get();
@@ -218,7 +208,6 @@ Error ResourceImporterTextureAtlas::import_group_file(const String &p_group_file
int mode = options["import_mode"];
if (mode == IMPORT_MODE_REGION) {
-
pack_data.is_mesh = false;
EditorAtlasPacker::Chart chart;
@@ -251,17 +240,15 @@ Error ResourceImporterTextureAtlas::import_group_file(const String &p_group_file
Ref<BitMap> bit_map;
bit_map.instance();
bit_map->create_from_image_alpha(image);
- Vector<Vector<Vector2> > polygons = bit_map->clip_opaque_to_polygons(Rect2(0, 0, image->get_width(), image->get_height()));
+ Vector<Vector<Vector2>> polygons = bit_map->clip_opaque_to_polygons(Rect2(0, 0, image->get_width(), image->get_height()));
for (int j = 0; j < polygons.size(); j++) {
-
EditorAtlasPacker::Chart chart;
chart.vertices = polygons[j];
chart.can_transpose = true;
Vector<int> poly = Geometry::triangulate_polygon(polygons[j]);
for (int i = 0; i < poly.size(); i += 3) {
-
EditorAtlasPacker::Chart::Face f;
f.vertex[0] = poly[i + 0];
f.vertex[1] = poly[i + 1];
@@ -286,12 +273,9 @@ Error ResourceImporterTextureAtlas::import_group_file(const String &p_group_file
new_atlas.instance();
new_atlas->create(atlas_width, atlas_height, false, Image::FORMAT_RGBA8);
- new_atlas->lock();
-
for (int i = 0; i < pack_data_files.size(); i++) {
-
PackData &pack_data = pack_data_files.write[i];
- pack_data.image->lock();
+
for (int j = 0; j < pack_data.chart_pieces.size(); j++) {
const EditorAtlasPacker::Chart &chart = charts[pack_data.chart_pieces[j]];
for (int k = 0; k < chart.faces.size(); k++) {
@@ -304,16 +288,14 @@ Error ResourceImporterTextureAtlas::import_group_file(const String &p_group_file
_plot_triangle(positions, chart.final_offset, chart.transposed, new_atlas, pack_data.image);
}
}
- pack_data.image->unlock();
}
- new_atlas->unlock();
//save the atlas
new_atlas->save_png(p_group_file);
//update cache if existing, else create
- Ref<Texture> cache;
+ Ref<Texture2D> cache;
if (ResourceCache::has(p_group_file)) {
Resource *resptr = ResourceCache::get(p_group_file);
cache.reference_ptr(resptr);
@@ -327,11 +309,10 @@ Error ResourceImporterTextureAtlas::import_group_file(const String &p_group_file
//save the images
idx = 0;
- for (const Map<String, Map<StringName, Variant> >::Element *E = p_source_file_options.front(); E; E = E->next(), idx++) {
-
+ for (const Map<String, Map<StringName, Variant>>::Element *E = p_source_file_options.front(); E; E = E->next(), idx++) {
PackData &pack_data = pack_data_files.write[idx];
- Ref<Texture> texture;
+ Ref<Texture2D> texture;
if (!pack_data.is_mesh) {
Vector2 offset = charts[pack_data.chart_pieces[0]].vertices[0] + charts[pack_data.chart_pieces[0]].final_offset;
@@ -350,9 +331,9 @@ Error ResourceImporterTextureAtlas::import_group_file(const String &p_group_file
for (int i = 0; i < pack_data.chart_pieces.size(); i++) {
const EditorAtlasPacker::Chart &chart = charts[pack_data.chart_pieces[i]];
- PoolVector<Vector2> vertices;
- PoolVector<int> indices;
- PoolVector<Vector2> uvs;
+ Vector<Vector2> vertices;
+ Vector<int> indices;
+ Vector<Vector2> uvs;
int vc = chart.vertices.size();
int fc = chart.faces.size();
vertices.resize(vc);
@@ -360,9 +341,9 @@ Error ResourceImporterTextureAtlas::import_group_file(const String &p_group_file
indices.resize(fc * 3);
{
- PoolVector<Vector2>::Write vw = vertices.write();
- PoolVector<int>::Write iw = indices.write();
- PoolVector<Vector2>::Write uvw = uvs.write();
+ Vector2 *vw = vertices.ptrw();
+ int *iw = indices.ptrw();
+ Vector2 *uvw = uvs.ptrw();
for (int j = 0; j < vc; j++) {
vw[j] = chart.vertices[j];
diff --git a/editor/import/resource_importer_texture_atlas.h b/editor/import/resource_importer_texture_atlas.h
index 3c6fc343c4..c61fa5c040 100644
--- a/editor/import/resource_importer_texture_atlas.h
+++ b/editor/import/resource_importer_texture_atlas.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -40,7 +40,7 @@ class ResourceImporterTextureAtlas : public ResourceImporter {
Rect2 region;
bool is_mesh;
Vector<int> chart_pieces; //one for region, many for mesh
- Vector<Vector<Vector2> > chart_vertices; //for mesh
+ Vector<Vector<Vector2>> chart_vertices; //for mesh
Ref<Image> image;
};
@@ -63,8 +63,8 @@ public:
virtual bool get_option_visibility(const String &p_option, const Map<StringName, Variant> &p_options) const;
virtual String get_option_group_file() const;
- virtual Error 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 = NULL, Variant *r_metadata = NULL);
- virtual Error import_group_file(const String &p_group_file, const Map<String, Map<StringName, Variant> > &p_source_file_options, const Map<String, String> &p_base_paths);
+ virtual Error 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 = nullptr, Variant *r_metadata = nullptr);
+ virtual Error import_group_file(const String &p_group_file, const Map<String, Map<StringName, Variant>> &p_source_file_options, const Map<String, String> &p_base_paths);
ResourceImporterTextureAtlas();
};
diff --git a/editor/import/resource_importer_wav.cpp b/editor/import/resource_importer_wav.cpp
index 74586a4100..cb669b4c89 100644
--- a/editor/import/resource_importer_wav.cpp
+++ b/editor/import/resource_importer_wav.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -39,29 +39,26 @@ const float TRIM_DB_LIMIT = -50;
const int TRIM_FADE_OUT_FRAMES = 500;
String ResourceImporterWAV::get_importer_name() const {
-
return "wav";
}
String ResourceImporterWAV::get_visible_name() const {
-
return "Microsoft WAV";
}
-void ResourceImporterWAV::get_recognized_extensions(List<String> *p_extensions) const {
+void ResourceImporterWAV::get_recognized_extensions(List<String> *p_extensions) const {
p_extensions->push_back("wav");
}
+
String ResourceImporterWAV::get_save_extension() const {
return "sample";
}
String ResourceImporterWAV::get_resource_type() const {
-
return "AudioStreamSample";
}
bool ResourceImporterWAV::get_option_visibility(const String &p_option, const Map<StringName, Variant> &p_options) const {
-
if (p_option == "force/max_rate_hz" && !bool(p_options["force/max_rate"])) {
return false;
}
@@ -72,17 +69,16 @@ bool ResourceImporterWAV::get_option_visibility(const String &p_option, const Ma
int ResourceImporterWAV::get_preset_count() const {
return 0;
}
-String ResourceImporterWAV::get_preset_name(int p_idx) const {
+String ResourceImporterWAV::get_preset_name(int p_idx) const {
return String();
}
void ResourceImporterWAV::get_import_options(List<ImportOption> *r_options, int p_preset) const {
-
r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "force/8_bit"), false));
r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "force/mono"), false));
r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "force/max_rate", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), false));
- r_options->push_back(ImportOption(PropertyInfo(Variant::REAL, "force/max_rate_hz", PROPERTY_HINT_EXP_RANGE, "11025,192000,1"), 44100));
+ r_options->push_back(ImportOption(PropertyInfo(Variant::FLOAT, "force/max_rate_hz", PROPERTY_HINT_EXP_RANGE, "11025,192000,1"), 44100));
r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "edit/trim"), false));
r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "edit/normalize"), false));
r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "edit/loop"), false));
@@ -90,7 +86,6 @@ void ResourceImporterWAV::get_import_options(List<ImportOption> *r_options, int
}
Error ResourceImporterWAV::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) {
-
/* STEP 1, READ WAVE FILE */
Error err;
@@ -104,7 +99,6 @@ Error ResourceImporterWAV::import(const String &p_source_file, const String &p_s
file->get_buffer((uint8_t *)&riff, 4); //RIFF
if (riff[0] != 'R' || riff[1] != 'I' || riff[2] != 'F' || riff[3] != 'F') {
-
file->close();
memdelete(file);
ERR_FAIL_V(ERR_FILE_UNRECOGNIZED);
@@ -120,7 +114,6 @@ Error ResourceImporterWAV::import(const String &p_source_file, const String &p_s
file->get_buffer((uint8_t *)&wave, 4); //RIFF
if (wave[0] != 'W' || wave[1] != 'A' || wave[2] != 'V' || wave[3] != 'E') {
-
file->close();
memdelete(file);
ERR_FAIL_V_MSG(ERR_FILE_UNRECOGNIZED, "Not a WAV file (no WAVE RIFF header).");
@@ -141,7 +134,6 @@ Error ResourceImporterWAV::import(const String &p_source_file, const String &p_s
Vector<float> data;
while (!file->eof_reached()) {
-
/* chunk */
char chunkID[4];
file->get_buffer((uint8_t *)&chunkID, 4); //RIFF
@@ -151,7 +143,6 @@ Error ResourceImporterWAV::import(const String &p_source_file, const String &p_s
uint32_t file_pos = file->get_position(); //save file pos, so we can skip to next chunk safely
if (file->eof_reached()) {
-
//ERR_PRINT("EOF REACH");
break;
}
@@ -242,7 +233,6 @@ Error ResourceImporterWAV::import(const String &p_source_file, const String &p_s
uint32_t s = 0;
for (int b = 0; b < (format_bits >> 3); b++) {
-
s |= ((uint32_t)file->get_8()) << (b * 8);
}
s <<= (32 - format_bits);
@@ -270,8 +260,9 @@ Error ResourceImporterWAV::import(const String &p_source_file, const String &p_s
* 22:38 06.07.2017 GMT
**/
- for (int i = 0; i < 10; i++)
+ for (int i = 0; i < 10; i++) {
file->get_32(); // i wish to know why should i do this... no doc!
+ }
// only read 0x00 (loop forward), 0x01 (loop ping-pong) and 0x02 (loop backward)
// Skip anything else because it's not supported, reserved for future uses or sampler specific
@@ -322,12 +313,10 @@ Error ResourceImporterWAV::import(const String &p_source_file, const String &p_s
Vector<float> new_data;
new_data.resize(new_data_frames * format_channels);
for (int c = 0; c < format_channels; c++) {
-
float frac = .0f;
int ipos = 0;
for (int i = 0; i < new_data_frames; i++) {
-
//simple cubic interpolation should be enough.
float mu = frac;
@@ -370,20 +359,17 @@ Error ResourceImporterWAV::import(const String &p_source_file, const String &p_s
bool normalize = p_options["edit/normalize"];
if (normalize) {
-
float max = 0;
for (int i = 0; i < data.size(); i++) {
-
float amp = Math::abs(data[i]);
- if (amp > max)
+ if (amp > max) {
max = amp;
+ }
}
if (max > 0) {
-
float mult = 1.0 / max;
for (int i = 0; i < data.size(); i++) {
-
data.write[i] *= mult;
}
}
@@ -392,7 +378,6 @@ Error ResourceImporterWAV::import(const String &p_source_file, const String &p_s
bool trim = p_options["edit/trim"];
if (trim && !loop && format_channels > 0) {
-
int first = 0;
int last = (frames / format_channels) - 1;
bool found = false;
@@ -420,7 +405,6 @@ Error ResourceImporterWAV::import(const String &p_source_file, const String &p_s
Vector<float> new_data;
new_data.resize((last - first) * format_channels);
for (int i = first; i < last; i++) {
-
float fadeOutMult = 1;
if (last - i < TRIM_FADE_OUT_FRAMES) {
@@ -440,7 +424,6 @@ Error ResourceImporterWAV::import(const String &p_source_file, const String &p_s
bool make_loop = p_options["edit/loop"];
if (make_loop && !loop) {
-
loop = AudioStreamSample::LOOP_FORWARD;
loop_begin = 0;
loop_end = frames;
@@ -450,7 +433,6 @@ Error ResourceImporterWAV::import(const String &p_source_file, const String &p_s
bool force_mono = p_options["force/mono"];
if (force_mono && format_channels == 2) {
-
Vector<float> new_data;
new_data.resize(data.size() / 2);
for (int i = 0; i < frames; i++) {
@@ -463,20 +445,17 @@ Error ResourceImporterWAV::import(const String &p_source_file, const String &p_s
bool force_8_bit = p_options["force/8_bit"];
if (force_8_bit) {
-
is16 = false;
}
- PoolVector<uint8_t> dst_data;
+ Vector<uint8_t> dst_data;
AudioStreamSample::Format dst_format;
if (compression == 1) {
-
dst_format = AudioStreamSample::FORMAT_IMA_ADPCM;
if (format_channels == 1) {
_compress_ima_adpcm(data, dst_data);
} else {
-
//byte interleave
Vector<float> left;
Vector<float> right;
@@ -490,8 +469,8 @@ Error ResourceImporterWAV::import(const String &p_source_file, const String &p_s
right.write[i] = data[i * 2 + 1];
}
- PoolVector<uint8_t> bleft;
- PoolVector<uint8_t> bright;
+ Vector<uint8_t> bleft;
+ Vector<uint8_t> bright;
_compress_ima_adpcm(left, bleft);
_compress_ima_adpcm(right, bright);
@@ -499,9 +478,9 @@ Error ResourceImporterWAV::import(const String &p_source_file, const String &p_s
int dl = bleft.size();
dst_data.resize(dl * 2);
- PoolVector<uint8_t>::Write w = dst_data.write();
- PoolVector<uint8_t>::Read rl = bleft.read();
- PoolVector<uint8_t>::Read rr = bright.read();
+ uint8_t *w = dst_data.ptrw();
+ const uint8_t *rl = bleft.ptr();
+ const uint8_t *rr = bright.ptr();
for (int i = 0; i < dl; i++) {
w[i * 2 + 0] = rl[i];
@@ -510,15 +489,13 @@ Error ResourceImporterWAV::import(const String &p_source_file, const String &p_s
}
} else {
-
dst_format = is16 ? AudioStreamSample::FORMAT_16_BITS : AudioStreamSample::FORMAT_8_BITS;
dst_data.resize(data.size() * (is16 ? 2 : 1));
{
- PoolVector<uint8_t>::Write w = dst_data.write();
+ uint8_t *w = dst_data.ptrw();
int ds = data.size();
for (int i = 0; i < ds; i++) {
-
if (is16) {
int16_t v = CLAMP(data[i] * 32768, -32768, 32767);
encode_uint16(v, &w[i * 2]);
diff --git a/editor/import/resource_importer_wav.h b/editor/import/resource_importer_wav.h
index 24481ea46b..3ff3aea9f4 100644
--- a/editor/import/resource_importer_wav.h
+++ b/editor/import/resource_importer_wav.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -49,7 +49,7 @@ public:
virtual void get_import_options(List<ImportOption> *r_options, int p_preset = 0) const;
virtual bool get_option_visibility(const String &p_option, const Map<StringName, Variant> &p_options) const;
- static void _compress_ima_adpcm(const Vector<float> &p_data, PoolVector<uint8_t> &dst_data) {
+ static void _compress_ima_adpcm(const Vector<float> &p_data, Vector<uint8_t> &dst_data) {
/*p_sample_data->data = (void*)malloc(len);
xm_s8 *dataptr=(xm_s8*)p_sample_data->data;*/
@@ -72,14 +72,15 @@ public:
int datalen = p_data.size();
int datamax = datalen;
- if (datalen & 1)
+ if (datalen & 1) {
datalen++;
+ }
dst_data.resize(datalen / 2 + 4);
- PoolVector<uint8_t>::Write w = dst_data.write();
+ uint8_t *w = dst_data.ptrw();
int i, step_idx = 0, prev = 0;
- uint8_t *out = w.ptr();
+ uint8_t *out = w;
//int16_t xm_prev=0;
const float *in = p_data.ptr();
@@ -96,10 +97,9 @@ public:
uint8_t nibble;
int16_t xm_sample;
- if (i >= datamax)
+ if (i >= datamax) {
xm_sample = 0;
- else {
-
+ } else {
xm_sample = CLAMP(in[i] * 32767.0, -32768, 32767);
/*
if (xm_sample==32767 || xm_sample==-32768)
@@ -121,9 +121,7 @@ public:
}
mask = 4;
while (mask) {
-
if (diff >= step) {
-
nibble |= mask;
diff -= step;
vpdiff += step;
@@ -133,10 +131,11 @@ public:
mask >>= 1;
};
- if (nibble & 8)
+ if (nibble & 8) {
prev -= vpdiff;
- else
+ } else {
prev += vpdiff;
+ }
if (prev > 32767) {
//printf("%i,xms %i, prev %i,diff %i, vpdiff %i, clip up %i\n",i,xm_sample,prev,diff,vpdiff,prev);
@@ -147,10 +146,11 @@ public:
}
step_idx += _ima_adpcm_index_table[nibble];
- if (step_idx < 0)
+ if (step_idx < 0) {
step_idx = 0;
- else if (step_idx > 88)
+ } else if (step_idx > 88) {
step_idx = 88;
+ }
if (i & 1) {
*out |= nibble << 4;
@@ -162,7 +162,7 @@ public:
}
}
- virtual Error 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 = NULL, Variant *r_metadata = NULL);
+ virtual Error 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 = nullptr, Variant *r_metadata = nullptr);
ResourceImporterWAV();
};