| 1 | /**************************************************************************/ | 
| 2 | /*  gltf_document.cpp                                                     */ | 
| 3 | /**************************************************************************/ | 
| 4 | /*                         This file is part of:                          */ | 
| 5 | /*                             GODOT ENGINE                               */ | 
| 6 | /*                        https://godotengine.org                         */ | 
| 7 | /**************************************************************************/ | 
| 8 | /* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ | 
| 9 | /* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur.                  */ | 
| 10 | /*                                                                        */ | 
| 11 | /* Permission is hereby granted, free of charge, to any person obtaining  */ | 
| 12 | /* a copy of this software and associated documentation files (the        */ | 
| 13 | /* "Software"), to deal in the Software without restriction, including    */ | 
| 14 | /* without limitation the rights to use, copy, modify, merge, publish,    */ | 
| 15 | /* distribute, sublicense, and/or sell copies of the Software, and to     */ | 
| 16 | /* permit persons to whom the Software is furnished to do so, subject to  */ | 
| 17 | /* the following conditions:                                              */ | 
| 18 | /*                                                                        */ | 
| 19 | /* The above copyright notice and this permission notice shall be         */ | 
| 20 | /* included in all copies or substantial portions of the Software.        */ | 
| 21 | /*                                                                        */ | 
| 22 | /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,        */ | 
| 23 | /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF     */ | 
| 24 | /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ | 
| 25 | /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY   */ | 
| 26 | /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,   */ | 
| 27 | /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE      */ | 
| 28 | /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                 */ | 
| 29 | /**************************************************************************/ | 
| 30 |  | 
| 31 | #include "gltf_document.h" | 
| 32 |  | 
| 33 | #include "extensions/gltf_spec_gloss.h" | 
| 34 |  | 
| 35 | #include "core/config/project_settings.h" | 
| 36 | #include "core/crypto/crypto_core.h" | 
| 37 | #include "core/io/config_file.h" | 
| 38 | #include "core/io/dir_access.h" | 
| 39 | #include "core/io/file_access.h" | 
| 40 | #include "core/io/file_access_memory.h" | 
| 41 | #include "core/io/json.h" | 
| 42 | #include "core/io/stream_peer.h" | 
| 43 | #include "core/math/disjoint_set.h" | 
| 44 | #include "core/version.h" | 
| 45 | #include "scene/3d/bone_attachment_3d.h" | 
| 46 | #include "scene/3d/camera_3d.h" | 
| 47 | #include "scene/3d/importer_mesh_instance_3d.h" | 
| 48 | #include "scene/3d/light_3d.h" | 
| 49 | #include "scene/3d/mesh_instance_3d.h" | 
| 50 | #include "scene/3d/multimesh_instance_3d.h" | 
| 51 | #include "scene/resources/image_texture.h" | 
| 52 | #include "scene/resources/portable_compressed_texture.h" | 
| 53 | #include "scene/resources/skin.h" | 
| 54 | #include "scene/resources/surface_tool.h" | 
| 55 |  | 
| 56 | #include "modules/modules_enabled.gen.h" // For csg, gridmap. | 
| 57 |  | 
| 58 | #ifdef TOOLS_ENABLED | 
| 59 | #include "editor/editor_file_system.h" | 
| 60 | #endif | 
| 61 | #ifdef MODULE_CSG_ENABLED | 
| 62 | #include "modules/csg/csg_shape.h" | 
| 63 | #endif // MODULE_CSG_ENABLED | 
| 64 | #ifdef MODULE_GRIDMAP_ENABLED | 
| 65 | #include "modules/gridmap/grid_map.h" | 
| 66 | #endif // MODULE_GRIDMAP_ENABLED | 
| 67 |  | 
| 68 | // FIXME: Hardcoded to avoid editor dependency. | 
| 69 | #define GLTF_IMPORT_USE_NAMED_SKIN_BINDS 16 | 
| 70 | #define GLTF_IMPORT_DISCARD_MESHES_AND_MATERIALS 32 | 
| 71 |  | 
| 72 | #include <stdio.h> | 
| 73 | #include <stdlib.h> | 
| 74 | #include <cstdint> | 
| 75 | #include <limits> | 
| 76 |  | 
| 77 | static Ref<ImporterMesh> _mesh_to_importer_mesh(Ref<Mesh> p_mesh) { | 
| 78 | 	Ref<ImporterMesh> importer_mesh; | 
| 79 | 	importer_mesh.instantiate(); | 
| 80 | 	if (p_mesh.is_null()) { | 
| 81 | 		return importer_mesh; | 
| 82 | 	} | 
| 83 |  | 
| 84 | 	Ref<ArrayMesh> array_mesh = p_mesh; | 
| 85 | 	if (p_mesh->get_blend_shape_count()) { | 
| 86 | 		ArrayMesh::BlendShapeMode shape_mode = ArrayMesh::BLEND_SHAPE_MODE_NORMALIZED; | 
| 87 | 		if (array_mesh.is_valid()) { | 
| 88 | 			shape_mode = array_mesh->get_blend_shape_mode(); | 
| 89 | 		} | 
| 90 | 		importer_mesh->set_blend_shape_mode(shape_mode); | 
| 91 | 		for (int morph_i = 0; morph_i < p_mesh->get_blend_shape_count(); morph_i++) { | 
| 92 | 			importer_mesh->add_blend_shape(p_mesh->get_blend_shape_name(morph_i)); | 
| 93 | 		} | 
| 94 | 	} | 
| 95 | 	for (int32_t surface_i = 0; surface_i < p_mesh->get_surface_count(); surface_i++) { | 
| 96 | 		Array array = p_mesh->surface_get_arrays(surface_i); | 
| 97 | 		Ref<Material> mat = p_mesh->surface_get_material(surface_i); | 
| 98 | 		String mat_name; | 
| 99 | 		if (mat.is_valid()) { | 
| 100 | 			mat_name = mat->get_name(); | 
| 101 | 		} else { | 
| 102 | 			// Assign default material when no material is assigned. | 
| 103 | 			mat = Ref<StandardMaterial3D>(memnew(StandardMaterial3D)); | 
| 104 | 		} | 
| 105 | 		importer_mesh->add_surface(p_mesh->surface_get_primitive_type(surface_i), | 
| 106 | 				array, p_mesh->surface_get_blend_shape_arrays(surface_i), p_mesh->surface_get_lods(surface_i), mat, | 
| 107 | 				mat_name, p_mesh->surface_get_format(surface_i)); | 
| 108 | 	} | 
| 109 | 	return importer_mesh; | 
| 110 | } | 
| 111 |  | 
| 112 | Error GLTFDocument::_serialize(Ref<GLTFState> p_state) { | 
| 113 | 	if (!p_state->buffers.size()) { | 
| 114 | 		p_state->buffers.push_back(Vector<uint8_t>()); | 
| 115 | 	} | 
| 116 |  | 
| 117 | 	for (Ref<GLTFDocumentExtension> ext : document_extensions) { | 
| 118 | 		ERR_CONTINUE(ext.is_null()); | 
| 119 | 		Error err = ext->export_preserialize(p_state); | 
| 120 | 		ERR_CONTINUE(err != OK); | 
| 121 | 	} | 
| 122 |  | 
| 123 | 	/* STEP CONVERT MESH INSTANCES */ | 
| 124 | 	_convert_mesh_instances(p_state); | 
| 125 |  | 
| 126 | 	/* STEP SERIALIZE CAMERAS */ | 
| 127 | 	Error err = _serialize_cameras(p_state); | 
| 128 | 	if (err != OK) { | 
| 129 | 		return Error::FAILED; | 
| 130 | 	} | 
| 131 |  | 
| 132 | 	/* STEP 3 CREATE SKINS */ | 
| 133 | 	err = _serialize_skins(p_state); | 
| 134 | 	if (err != OK) { | 
| 135 | 		return Error::FAILED; | 
| 136 | 	} | 
| 137 |  | 
| 138 | 	/* STEP SERIALIZE MESHES (we have enough info now) */ | 
| 139 | 	err = _serialize_meshes(p_state); | 
| 140 | 	if (err != OK) { | 
| 141 | 		return Error::FAILED; | 
| 142 | 	} | 
| 143 |  | 
| 144 | 	/* STEP SERIALIZE TEXTURES */ | 
| 145 | 	err = _serialize_materials(p_state); | 
| 146 | 	if (err != OK) { | 
| 147 | 		return Error::FAILED; | 
| 148 | 	} | 
| 149 |  | 
| 150 | 	/* STEP SERIALIZE TEXTURE SAMPLERS */ | 
| 151 | 	err = _serialize_texture_samplers(p_state); | 
| 152 | 	if (err != OK) { | 
| 153 | 		return Error::FAILED; | 
| 154 | 	} | 
| 155 |  | 
| 156 | 	/* STEP SERIALIZE ANIMATIONS */ | 
| 157 | 	err = _serialize_animations(p_state); | 
| 158 | 	if (err != OK) { | 
| 159 | 		return Error::FAILED; | 
| 160 | 	} | 
| 161 |  | 
| 162 | 	/* STEP SERIALIZE ACCESSORS */ | 
| 163 | 	err = _encode_accessors(p_state); | 
| 164 | 	if (err != OK) { | 
| 165 | 		return Error::FAILED; | 
| 166 | 	} | 
| 167 |  | 
| 168 | 	/* STEP SERIALIZE IMAGES */ | 
| 169 | 	err = _serialize_images(p_state); | 
| 170 | 	if (err != OK) { | 
| 171 | 		return Error::FAILED; | 
| 172 | 	} | 
| 173 |  | 
| 174 | 	/* STEP SERIALIZE TEXTURES */ | 
| 175 | 	err = _serialize_textures(p_state); | 
| 176 | 	if (err != OK) { | 
| 177 | 		return Error::FAILED; | 
| 178 | 	} | 
| 179 |  | 
| 180 | 	for (GLTFBufferViewIndex i = 0; i < p_state->buffer_views.size(); i++) { | 
| 181 | 		p_state->buffer_views.write[i]->buffer = 0; | 
| 182 | 	} | 
| 183 |  | 
| 184 | 	/* STEP SERIALIZE BUFFER VIEWS */ | 
| 185 | 	err = _encode_buffer_views(p_state); | 
| 186 | 	if (err != OK) { | 
| 187 | 		return Error::FAILED; | 
| 188 | 	} | 
| 189 |  | 
| 190 | 	/* STEP SERIALIZE NODES */ | 
| 191 | 	err = _serialize_nodes(p_state); | 
| 192 | 	if (err != OK) { | 
| 193 | 		return Error::FAILED; | 
| 194 | 	} | 
| 195 |  | 
| 196 | 	/* STEP SERIALIZE SCENE */ | 
| 197 | 	err = _serialize_scenes(p_state); | 
| 198 | 	if (err != OK) { | 
| 199 | 		return Error::FAILED; | 
| 200 | 	} | 
| 201 |  | 
| 202 | 	/* STEP SERIALIZE LIGHTS */ | 
| 203 | 	err = _serialize_lights(p_state); | 
| 204 | 	if (err != OK) { | 
| 205 | 		return Error::FAILED; | 
| 206 | 	} | 
| 207 |  | 
| 208 | 	/* STEP SERIALIZE EXTENSIONS */ | 
| 209 | 	err = _serialize_gltf_extensions(p_state); | 
| 210 | 	if (err != OK) { | 
| 211 | 		return Error::FAILED; | 
| 212 | 	} | 
| 213 |  | 
| 214 | 	/* STEP SERIALIZE VERSION */ | 
| 215 | 	err = _serialize_asset_header(p_state); | 
| 216 | 	if (err != OK) { | 
| 217 | 		return Error::FAILED; | 
| 218 | 	} | 
| 219 |  | 
| 220 | 	for (Ref<GLTFDocumentExtension> ext : document_extensions) { | 
| 221 | 		ERR_CONTINUE(ext.is_null()); | 
| 222 | 		err = ext->export_post(p_state); | 
| 223 | 		ERR_FAIL_COND_V(err != OK, err); | 
| 224 | 	} | 
| 225 |  | 
| 226 | 	return OK; | 
| 227 | } | 
| 228 |  | 
| 229 | Error GLTFDocument::_serialize_gltf_extensions(Ref<GLTFState> p_state) const { | 
| 230 | 	Vector<String> extensions_used = p_state->extensions_used; | 
| 231 | 	Vector<String> extensions_required = p_state->extensions_required; | 
| 232 | 	if (!p_state->lights.is_empty()) { | 
| 233 | 		extensions_used.push_back("KHR_lights_punctual" ); | 
| 234 | 	} | 
| 235 | 	if (p_state->use_khr_texture_transform) { | 
| 236 | 		extensions_used.push_back("KHR_texture_transform" ); | 
| 237 | 		extensions_required.push_back("KHR_texture_transform" ); | 
| 238 | 	} | 
| 239 | 	if (!extensions_used.is_empty()) { | 
| 240 | 		extensions_used.sort(); | 
| 241 | 		p_state->json["extensionsUsed" ] = extensions_used; | 
| 242 | 	} | 
| 243 | 	if (!extensions_required.is_empty()) { | 
| 244 | 		extensions_required.sort(); | 
| 245 | 		p_state->json["extensionsRequired" ] = extensions_required; | 
| 246 | 	} | 
| 247 | 	return OK; | 
| 248 | } | 
| 249 |  | 
| 250 | Error GLTFDocument::_serialize_scenes(Ref<GLTFState> p_state) { | 
| 251 | 	ERR_FAIL_COND_V_MSG(p_state->root_nodes.size() == 0, ERR_INVALID_DATA, "GLTF export: The scene must have at least one root node." ); | 
| 252 | 	// Godot only supports one scene per glTF file. | 
| 253 | 	Array scenes; | 
| 254 | 	Dictionary scene_dict; | 
| 255 | 	scenes.append(scene_dict); | 
| 256 | 	p_state->json["scenes" ] = scenes; | 
| 257 | 	p_state->json["scene" ] = 0; | 
| 258 | 	// Add nodes to the scene dict. | 
| 259 | 	scene_dict["nodes" ] = p_state->root_nodes; | 
| 260 | 	if (!p_state->scene_name.is_empty()) { | 
| 261 | 		scene_dict["name" ] = p_state->scene_name; | 
| 262 | 	} | 
| 263 | 	return OK; | 
| 264 | } | 
| 265 |  | 
| 266 | Error GLTFDocument::_parse_json(const String &p_path, Ref<GLTFState> p_state) { | 
| 267 | 	Error err; | 
| 268 | 	Ref<FileAccess> file = FileAccess::open(p_path, FileAccess::READ, &err); | 
| 269 | 	if (file.is_null()) { | 
| 270 | 		return err; | 
| 271 | 	} | 
| 272 |  | 
| 273 | 	Vector<uint8_t> array; | 
| 274 | 	array.resize(file->get_length()); | 
| 275 | 	file->get_buffer(array.ptrw(), array.size()); | 
| 276 | 	String text; | 
| 277 | 	text.parse_utf8((const char *)array.ptr(), array.size()); | 
| 278 |  | 
| 279 | 	JSON json; | 
| 280 | 	err = json.parse(text); | 
| 281 | 	if (err != OK) { | 
| 282 | 		_err_print_error("" , p_path.utf8().get_data(), json.get_error_line(), json.get_error_message().utf8().get_data(), false, ERR_HANDLER_SCRIPT); | 
| 283 | 		return err; | 
| 284 | 	} | 
| 285 | 	p_state->json = json.get_data(); | 
| 286 |  | 
| 287 | 	return OK; | 
| 288 | } | 
| 289 |  | 
| 290 | Error GLTFDocument::_parse_glb(Ref<FileAccess> p_file, Ref<GLTFState> p_state) { | 
| 291 | 	ERR_FAIL_NULL_V(p_file, ERR_INVALID_PARAMETER); | 
| 292 | 	ERR_FAIL_NULL_V(p_state, ERR_INVALID_PARAMETER); | 
| 293 | 	ERR_FAIL_COND_V(p_file->get_position() != 0, ERR_FILE_CANT_READ); | 
| 294 | 	uint32_t magic = p_file->get_32(); | 
| 295 | 	ERR_FAIL_COND_V(magic != 0x46546C67, ERR_FILE_UNRECOGNIZED); //glTF | 
| 296 | 	p_file->get_32(); // version | 
| 297 | 	p_file->get_32(); // length | 
| 298 | 	uint32_t chunk_length = p_file->get_32(); | 
| 299 | 	uint32_t chunk_type = p_file->get_32(); | 
| 300 |  | 
| 301 | 	ERR_FAIL_COND_V(chunk_type != 0x4E4F534A, ERR_PARSE_ERROR); //JSON | 
| 302 | 	Vector<uint8_t> json_data; | 
| 303 | 	json_data.resize(chunk_length); | 
| 304 | 	uint32_t len = p_file->get_buffer(json_data.ptrw(), chunk_length); | 
| 305 | 	ERR_FAIL_COND_V(len != chunk_length, ERR_FILE_CORRUPT); | 
| 306 |  | 
| 307 | 	String text; | 
| 308 | 	text.parse_utf8((const char *)json_data.ptr(), json_data.size()); | 
| 309 |  | 
| 310 | 	JSON json; | 
| 311 | 	Error err = json.parse(text); | 
| 312 | 	if (err != OK) { | 
| 313 | 		_err_print_error("" , "" , json.get_error_line(), json.get_error_message().utf8().get_data(), false, ERR_HANDLER_SCRIPT); | 
| 314 | 		return err; | 
| 315 | 	} | 
| 316 |  | 
| 317 | 	p_state->json = json.get_data(); | 
| 318 |  | 
| 319 | 	//data? | 
| 320 |  | 
| 321 | 	chunk_length = p_file->get_32(); | 
| 322 | 	chunk_type = p_file->get_32(); | 
| 323 |  | 
| 324 | 	if (p_file->eof_reached()) { | 
| 325 | 		return OK; //all good | 
| 326 | 	} | 
| 327 |  | 
| 328 | 	ERR_FAIL_COND_V(chunk_type != 0x004E4942, ERR_PARSE_ERROR); //BIN | 
| 329 |  | 
| 330 | 	p_state->glb_data.resize(chunk_length); | 
| 331 | 	len = p_file->get_buffer(p_state->glb_data.ptrw(), chunk_length); | 
| 332 | 	ERR_FAIL_COND_V(len != chunk_length, ERR_FILE_CORRUPT); | 
| 333 |  | 
| 334 | 	return OK; | 
| 335 | } | 
| 336 |  | 
| 337 | static Array _vec3_to_arr(const Vector3 &p_vec3) { | 
| 338 | 	Array array; | 
| 339 | 	array.resize(3); | 
| 340 | 	array[0] = p_vec3.x; | 
| 341 | 	array[1] = p_vec3.y; | 
| 342 | 	array[2] = p_vec3.z; | 
| 343 | 	return array; | 
| 344 | } | 
| 345 |  | 
| 346 | static Vector3 _arr_to_vec3(const Array &p_array) { | 
| 347 | 	ERR_FAIL_COND_V(p_array.size() != 3, Vector3()); | 
| 348 | 	return Vector3(p_array[0], p_array[1], p_array[2]); | 
| 349 | } | 
| 350 |  | 
| 351 | static Array _quaternion_to_array(const Quaternion &p_quaternion) { | 
| 352 | 	Array array; | 
| 353 | 	array.resize(4); | 
| 354 | 	array[0] = p_quaternion.x; | 
| 355 | 	array[1] = p_quaternion.y; | 
| 356 | 	array[2] = p_quaternion.z; | 
| 357 | 	array[3] = p_quaternion.w; | 
| 358 | 	return array; | 
| 359 | } | 
| 360 |  | 
| 361 | static Quaternion _arr_to_quaternion(const Array &p_array) { | 
| 362 | 	ERR_FAIL_COND_V(p_array.size() != 4, Quaternion()); | 
| 363 | 	return Quaternion(p_array[0], p_array[1], p_array[2], p_array[3]); | 
| 364 | } | 
| 365 |  | 
| 366 | static Transform3D _arr_to_xform(const Array &p_array) { | 
| 367 | 	ERR_FAIL_COND_V(p_array.size() != 16, Transform3D()); | 
| 368 |  | 
| 369 | 	Transform3D xform; | 
| 370 | 	xform.basis.set_column(Vector3::AXIS_X, Vector3(p_array[0], p_array[1], p_array[2])); | 
| 371 | 	xform.basis.set_column(Vector3::AXIS_Y, Vector3(p_array[4], p_array[5], p_array[6])); | 
| 372 | 	xform.basis.set_column(Vector3::AXIS_Z, Vector3(p_array[8], p_array[9], p_array[10])); | 
| 373 | 	xform.set_origin(Vector3(p_array[12], p_array[13], p_array[14])); | 
| 374 |  | 
| 375 | 	return xform; | 
| 376 | } | 
| 377 |  | 
| 378 | static Vector<real_t> _xform_to_array(const Transform3D p_transform) { | 
| 379 | 	Vector<real_t> array; | 
| 380 | 	array.resize(16); | 
| 381 | 	Vector3 axis_x = p_transform.get_basis().get_column(Vector3::AXIS_X); | 
| 382 | 	array.write[0] = axis_x.x; | 
| 383 | 	array.write[1] = axis_x.y; | 
| 384 | 	array.write[2] = axis_x.z; | 
| 385 | 	array.write[3] = 0.0f; | 
| 386 | 	Vector3 axis_y = p_transform.get_basis().get_column(Vector3::AXIS_Y); | 
| 387 | 	array.write[4] = axis_y.x; | 
| 388 | 	array.write[5] = axis_y.y; | 
| 389 | 	array.write[6] = axis_y.z; | 
| 390 | 	array.write[7] = 0.0f; | 
| 391 | 	Vector3 axis_z = p_transform.get_basis().get_column(Vector3::AXIS_Z); | 
| 392 | 	array.write[8] = axis_z.x; | 
| 393 | 	array.write[9] = axis_z.y; | 
| 394 | 	array.write[10] = axis_z.z; | 
| 395 | 	array.write[11] = 0.0f; | 
| 396 | 	Vector3 origin = p_transform.get_origin(); | 
| 397 | 	array.write[12] = origin.x; | 
| 398 | 	array.write[13] = origin.y; | 
| 399 | 	array.write[14] = origin.z; | 
| 400 | 	array.write[15] = 1.0f; | 
| 401 | 	return array; | 
| 402 | } | 
| 403 |  | 
| 404 | Error GLTFDocument::_serialize_nodes(Ref<GLTFState> p_state) { | 
| 405 | 	Array nodes; | 
| 406 | 	for (int i = 0; i < p_state->nodes.size(); i++) { | 
| 407 | 		Dictionary node; | 
| 408 | 		Ref<GLTFNode> gltf_node = p_state->nodes[i]; | 
| 409 | 		Dictionary extensions; | 
| 410 | 		node["extensions" ] = extensions; | 
| 411 | 		if (!gltf_node->get_name().is_empty()) { | 
| 412 | 			node["name" ] = gltf_node->get_name(); | 
| 413 | 		} | 
| 414 | 		if (gltf_node->camera != -1) { | 
| 415 | 			node["camera" ] = gltf_node->camera; | 
| 416 | 		} | 
| 417 | 		if (gltf_node->light != -1) { | 
| 418 | 			Dictionary lights_punctual; | 
| 419 | 			extensions["KHR_lights_punctual" ] = lights_punctual; | 
| 420 | 			lights_punctual["light" ] = gltf_node->light; | 
| 421 | 		} | 
| 422 | 		if (gltf_node->mesh != -1) { | 
| 423 | 			node["mesh" ] = gltf_node->mesh; | 
| 424 | 		} | 
| 425 | 		if (gltf_node->skin != -1) { | 
| 426 | 			node["skin" ] = gltf_node->skin; | 
| 427 | 		} | 
| 428 | 		if (gltf_node->skeleton != -1 && gltf_node->skin < 0) { | 
| 429 | 		} | 
| 430 | 		if (gltf_node->xform != Transform3D()) { | 
| 431 | 			node["matrix" ] = _xform_to_array(gltf_node->xform); | 
| 432 | 		} | 
| 433 |  | 
| 434 | 		if (!gltf_node->rotation.is_equal_approx(Quaternion())) { | 
| 435 | 			node["rotation" ] = _quaternion_to_array(gltf_node->rotation); | 
| 436 | 		} | 
| 437 |  | 
| 438 | 		if (!gltf_node->scale.is_equal_approx(Vector3(1.0f, 1.0f, 1.0f))) { | 
| 439 | 			node["scale" ] = _vec3_to_arr(gltf_node->scale); | 
| 440 | 		} | 
| 441 |  | 
| 442 | 		if (!gltf_node->position.is_zero_approx()) { | 
| 443 | 			node["translation" ] = _vec3_to_arr(gltf_node->position); | 
| 444 | 		} | 
| 445 | 		if (gltf_node->children.size()) { | 
| 446 | 			Array children; | 
| 447 | 			for (int j = 0; j < gltf_node->children.size(); j++) { | 
| 448 | 				children.push_back(gltf_node->children[j]); | 
| 449 | 			} | 
| 450 | 			node["children" ] = children; | 
| 451 | 		} | 
| 452 |  | 
| 453 | 		for (Ref<GLTFDocumentExtension> ext : document_extensions) { | 
| 454 | 			ERR_CONTINUE(ext.is_null()); | 
| 455 | 			ERR_CONTINUE(!p_state->scene_nodes.find(i)); | 
| 456 | 			Error err = ext->export_node(p_state, gltf_node, node, p_state->scene_nodes[i]); | 
| 457 | 			ERR_CONTINUE(err != OK); | 
| 458 | 		} | 
| 459 |  | 
| 460 | 		nodes.push_back(node); | 
| 461 | 	} | 
| 462 | 	p_state->json["nodes" ] = nodes; | 
| 463 | 	return OK; | 
| 464 | } | 
| 465 |  | 
| 466 | String GLTFDocument::_gen_unique_name(Ref<GLTFState> p_state, const String &p_name) { | 
| 467 | 	const String s_name = p_name.validate_node_name(); | 
| 468 |  | 
| 469 | 	String u_name; | 
| 470 | 	int index = 1; | 
| 471 | 	while (true) { | 
| 472 | 		u_name = s_name; | 
| 473 |  | 
| 474 | 		if (index > 1) { | 
| 475 | 			u_name += itos(index); | 
| 476 | 		} | 
| 477 | 		if (!p_state->unique_names.has(u_name)) { | 
| 478 | 			break; | 
| 479 | 		} | 
| 480 | 		index++; | 
| 481 | 	} | 
| 482 |  | 
| 483 | 	p_state->unique_names.insert(u_name); | 
| 484 |  | 
| 485 | 	return u_name; | 
| 486 | } | 
| 487 |  | 
| 488 | String GLTFDocument::_sanitize_animation_name(const String &p_name) { | 
| 489 | 	// Animations disallow the normal node invalid characters as well as  "," and "[" | 
| 490 | 	// (See animation/animation_player.cpp::add_animation) | 
| 491 |  | 
| 492 | 	// TODO: Consider adding invalid_characters or a validate_animation_name to animation_player to mirror Node. | 
| 493 | 	String anim_name = p_name.validate_node_name(); | 
| 494 | 	anim_name = anim_name.replace("," , "" ); | 
| 495 | 	anim_name = anim_name.replace("[" , "" ); | 
| 496 | 	return anim_name; | 
| 497 | } | 
| 498 |  | 
| 499 | String GLTFDocument::_gen_unique_animation_name(Ref<GLTFState> p_state, const String &p_name) { | 
| 500 | 	const String s_name = _sanitize_animation_name(p_name); | 
| 501 |  | 
| 502 | 	String u_name; | 
| 503 | 	int index = 1; | 
| 504 | 	while (true) { | 
| 505 | 		u_name = s_name; | 
| 506 |  | 
| 507 | 		if (index > 1) { | 
| 508 | 			u_name += itos(index); | 
| 509 | 		} | 
| 510 | 		if (!p_state->unique_animation_names.has(u_name)) { | 
| 511 | 			break; | 
| 512 | 		} | 
| 513 | 		index++; | 
| 514 | 	} | 
| 515 |  | 
| 516 | 	p_state->unique_animation_names.insert(u_name); | 
| 517 |  | 
| 518 | 	return u_name; | 
| 519 | } | 
| 520 |  | 
| 521 | String GLTFDocument::_sanitize_bone_name(const String &p_name) { | 
| 522 | 	String bone_name = p_name; | 
| 523 | 	bone_name = bone_name.replace(":" , "_" ); | 
| 524 | 	bone_name = bone_name.replace("/" , "_" ); | 
| 525 | 	return bone_name; | 
| 526 | } | 
| 527 |  | 
| 528 | String GLTFDocument::_gen_unique_bone_name(Ref<GLTFState> p_state, const GLTFSkeletonIndex p_skel_i, const String &p_name) { | 
| 529 | 	String s_name = _sanitize_bone_name(p_name); | 
| 530 | 	if (s_name.is_empty()) { | 
| 531 | 		s_name = "bone" ; | 
| 532 | 	} | 
| 533 | 	String u_name; | 
| 534 | 	int index = 1; | 
| 535 | 	while (true) { | 
| 536 | 		u_name = s_name; | 
| 537 |  | 
| 538 | 		if (index > 1) { | 
| 539 | 			u_name += "_"  + itos(index); | 
| 540 | 		} | 
| 541 | 		if (!p_state->skeletons[p_skel_i]->unique_names.has(u_name)) { | 
| 542 | 			break; | 
| 543 | 		} | 
| 544 | 		index++; | 
| 545 | 	} | 
| 546 |  | 
| 547 | 	p_state->skeletons.write[p_skel_i]->unique_names.insert(u_name); | 
| 548 |  | 
| 549 | 	return u_name; | 
| 550 | } | 
| 551 |  | 
| 552 | Error GLTFDocument::_parse_scenes(Ref<GLTFState> p_state) { | 
| 553 | 	p_state->unique_names.insert("Skeleton3D" ); // Reserve skeleton name. | 
| 554 | 	ERR_FAIL_COND_V(!p_state->json.has("scenes" ), ERR_FILE_CORRUPT); | 
| 555 | 	const Array &scenes = p_state->json["scenes" ]; | 
| 556 | 	int loaded_scene = 0; | 
| 557 | 	if (p_state->json.has("scene" )) { | 
| 558 | 		loaded_scene = p_state->json["scene" ]; | 
| 559 | 	} else { | 
| 560 | 		WARN_PRINT("The load-time scene is not defined in the glTF2 file. Picking the first scene." ); | 
| 561 | 	} | 
| 562 |  | 
| 563 | 	if (scenes.size()) { | 
| 564 | 		ERR_FAIL_COND_V(loaded_scene >= scenes.size(), ERR_FILE_CORRUPT); | 
| 565 | 		const Dictionary &scene_dict = scenes[loaded_scene]; | 
| 566 | 		ERR_FAIL_COND_V(!scene_dict.has("nodes" ), ERR_UNAVAILABLE); | 
| 567 | 		const Array &nodes = scene_dict["nodes" ]; | 
| 568 | 		for (int j = 0; j < nodes.size(); j++) { | 
| 569 | 			p_state->root_nodes.push_back(nodes[j]); | 
| 570 | 		} | 
| 571 | 		// Determine what to use for the scene name. | 
| 572 | 		if (scene_dict.has("name" ) && !String(scene_dict["name" ]).is_empty() && !((String)scene_dict["name" ]).begins_with("Scene" )) { | 
| 573 | 			p_state->scene_name = scene_dict["name" ]; | 
| 574 | 		} else { | 
| 575 | 			p_state->scene_name = p_state->filename; | 
| 576 | 		} | 
| 577 | 	} | 
| 578 |  | 
| 579 | 	return OK; | 
| 580 | } | 
| 581 |  | 
| 582 | Error GLTFDocument::_parse_nodes(Ref<GLTFState> p_state) { | 
| 583 | 	ERR_FAIL_COND_V(!p_state->json.has("nodes" ), ERR_FILE_CORRUPT); | 
| 584 | 	const Array &nodes = p_state->json["nodes" ]; | 
| 585 | 	for (int i = 0; i < nodes.size(); i++) { | 
| 586 | 		Ref<GLTFNode> node; | 
| 587 | 		node.instantiate(); | 
| 588 | 		const Dictionary &n = nodes[i]; | 
| 589 |  | 
| 590 | 		if (n.has("name" )) { | 
| 591 | 			node->set_name(n["name" ]); | 
| 592 | 		} | 
| 593 | 		if (n.has("camera" )) { | 
| 594 | 			node->camera = n["camera" ]; | 
| 595 | 		} | 
| 596 | 		if (n.has("mesh" )) { | 
| 597 | 			node->mesh = n["mesh" ]; | 
| 598 | 		} | 
| 599 | 		if (n.has("skin" )) { | 
| 600 | 			node->skin = n["skin" ]; | 
| 601 | 		} | 
| 602 | 		if (n.has("matrix" )) { | 
| 603 | 			node->xform = _arr_to_xform(n["matrix" ]); | 
| 604 | 		} else { | 
| 605 | 			if (n.has("translation" )) { | 
| 606 | 				node->position = _arr_to_vec3(n["translation" ]); | 
| 607 | 			} | 
| 608 | 			if (n.has("rotation" )) { | 
| 609 | 				node->rotation = _arr_to_quaternion(n["rotation" ]); | 
| 610 | 			} | 
| 611 | 			if (n.has("scale" )) { | 
| 612 | 				node->scale = _arr_to_vec3(n["scale" ]); | 
| 613 | 			} | 
| 614 |  | 
| 615 | 			node->xform.basis.set_quaternion_scale(node->rotation, node->scale); | 
| 616 | 			node->xform.origin = node->position; | 
| 617 | 		} | 
| 618 |  | 
| 619 | 		if (n.has("extensions" )) { | 
| 620 | 			Dictionary extensions = n["extensions" ]; | 
| 621 | 			if (extensions.has("KHR_lights_punctual" )) { | 
| 622 | 				Dictionary lights_punctual = extensions["KHR_lights_punctual" ]; | 
| 623 | 				if (lights_punctual.has("light" )) { | 
| 624 | 					GLTFLightIndex light = lights_punctual["light" ]; | 
| 625 | 					node->light = light; | 
| 626 | 				} | 
| 627 | 			} | 
| 628 | 			for (Ref<GLTFDocumentExtension> ext : document_extensions) { | 
| 629 | 				ERR_CONTINUE(ext.is_null()); | 
| 630 | 				Error err = ext->parse_node_extensions(p_state, node, extensions); | 
| 631 | 				ERR_CONTINUE_MSG(err != OK, "GLTF: Encountered error "  + itos(err) + " when parsing node extensions for node "  + node->get_name() + " in file "  + p_state->filename + ". Continuing." ); | 
| 632 | 			} | 
| 633 | 		} | 
| 634 |  | 
| 635 | 		if (n.has("children" )) { | 
| 636 | 			const Array &children = n["children" ]; | 
| 637 | 			for (int j = 0; j < children.size(); j++) { | 
| 638 | 				node->children.push_back(children[j]); | 
| 639 | 			} | 
| 640 | 		} | 
| 641 |  | 
| 642 | 		p_state->nodes.push_back(node); | 
| 643 | 	} | 
| 644 |  | 
| 645 | 	// build the hierarchy | 
| 646 | 	for (GLTFNodeIndex node_i = 0; node_i < p_state->nodes.size(); node_i++) { | 
| 647 | 		for (int j = 0; j < p_state->nodes[node_i]->children.size(); j++) { | 
| 648 | 			GLTFNodeIndex child_i = p_state->nodes[node_i]->children[j]; | 
| 649 |  | 
| 650 | 			ERR_FAIL_INDEX_V(child_i, p_state->nodes.size(), ERR_FILE_CORRUPT); | 
| 651 | 			ERR_CONTINUE(p_state->nodes[child_i]->parent != -1); //node already has a parent, wtf. | 
| 652 |  | 
| 653 | 			p_state->nodes.write[child_i]->parent = node_i; | 
| 654 | 		} | 
| 655 | 	} | 
| 656 |  | 
| 657 | 	_compute_node_heights(p_state); | 
| 658 |  | 
| 659 | 	return OK; | 
| 660 | } | 
| 661 |  | 
| 662 | void GLTFDocument::_compute_node_heights(Ref<GLTFState> p_state) { | 
| 663 | 	p_state->root_nodes.clear(); | 
| 664 | 	for (GLTFNodeIndex node_i = 0; node_i < p_state->nodes.size(); ++node_i) { | 
| 665 | 		Ref<GLTFNode> node = p_state->nodes[node_i]; | 
| 666 | 		node->height = 0; | 
| 667 |  | 
| 668 | 		GLTFNodeIndex current_i = node_i; | 
| 669 | 		while (current_i >= 0) { | 
| 670 | 			const GLTFNodeIndex parent_i = p_state->nodes[current_i]->parent; | 
| 671 | 			if (parent_i >= 0) { | 
| 672 | 				++node->height; | 
| 673 | 			} | 
| 674 | 			current_i = parent_i; | 
| 675 | 		} | 
| 676 |  | 
| 677 | 		if (node->height == 0) { | 
| 678 | 			p_state->root_nodes.push_back(node_i); | 
| 679 | 		} | 
| 680 | 	} | 
| 681 | } | 
| 682 |  | 
| 683 | static Vector<uint8_t> _parse_base64_uri(const String &p_uri) { | 
| 684 | 	int start = p_uri.find("," ); | 
| 685 | 	ERR_FAIL_COND_V(start == -1, Vector<uint8_t>()); | 
| 686 |  | 
| 687 | 	CharString substr = p_uri.substr(start + 1).ascii(); | 
| 688 |  | 
| 689 | 	int strlen = substr.length(); | 
| 690 |  | 
| 691 | 	Vector<uint8_t> buf; | 
| 692 | 	buf.resize(strlen / 4 * 3 + 1 + 1); | 
| 693 |  | 
| 694 | 	size_t len = 0; | 
| 695 | 	ERR_FAIL_COND_V(CryptoCore::b64_decode(buf.ptrw(), buf.size(), &len, (unsigned char *)substr.get_data(), strlen) != OK, Vector<uint8_t>()); | 
| 696 |  | 
| 697 | 	buf.resize(len); | 
| 698 |  | 
| 699 | 	return buf; | 
| 700 | } | 
| 701 |  | 
| 702 | Error GLTFDocument::_encode_buffer_glb(Ref<GLTFState> p_state, const String &p_path) { | 
| 703 | 	print_verbose("glTF: Total buffers: "  + itos(p_state->buffers.size())); | 
| 704 |  | 
| 705 | 	if (!p_state->buffers.size()) { | 
| 706 | 		return OK; | 
| 707 | 	} | 
| 708 | 	Array buffers; | 
| 709 | 	if (p_state->buffers.size()) { | 
| 710 | 		Vector<uint8_t> buffer_data = p_state->buffers[0]; | 
| 711 | 		Dictionary gltf_buffer; | 
| 712 |  | 
| 713 | 		gltf_buffer["byteLength" ] = buffer_data.size(); | 
| 714 | 		buffers.push_back(gltf_buffer); | 
| 715 | 	} | 
| 716 |  | 
| 717 | 	for (GLTFBufferIndex i = 1; i < p_state->buffers.size() - 1; i++) { | 
| 718 | 		Vector<uint8_t> buffer_data = p_state->buffers[i]; | 
| 719 | 		Dictionary gltf_buffer; | 
| 720 | 		String filename = p_path.get_basename().get_file() + itos(i) + ".bin" ; | 
| 721 | 		String path = p_path.get_base_dir() + "/"  + filename; | 
| 722 | 		Error err; | 
| 723 | 		Ref<FileAccess> file = FileAccess::open(path, FileAccess::WRITE, &err); | 
| 724 | 		if (file.is_null()) { | 
| 725 | 			return err; | 
| 726 | 		} | 
| 727 | 		if (buffer_data.size() == 0) { | 
| 728 | 			return OK; | 
| 729 | 		} | 
| 730 | 		file->create(FileAccess::ACCESS_RESOURCES); | 
| 731 | 		file->store_buffer(buffer_data.ptr(), buffer_data.size()); | 
| 732 | 		gltf_buffer["uri" ] = filename; | 
| 733 | 		gltf_buffer["byteLength" ] = buffer_data.size(); | 
| 734 | 		buffers.push_back(gltf_buffer); | 
| 735 | 	} | 
| 736 | 	p_state->json["buffers" ] = buffers; | 
| 737 |  | 
| 738 | 	return OK; | 
| 739 | } | 
| 740 |  | 
| 741 | Error GLTFDocument::_encode_buffer_bins(Ref<GLTFState> p_state, const String &p_path) { | 
| 742 | 	print_verbose("glTF: Total buffers: "  + itos(p_state->buffers.size())); | 
| 743 |  | 
| 744 | 	if (!p_state->buffers.size()) { | 
| 745 | 		return OK; | 
| 746 | 	} | 
| 747 | 	Array buffers; | 
| 748 |  | 
| 749 | 	for (GLTFBufferIndex i = 0; i < p_state->buffers.size(); i++) { | 
| 750 | 		Vector<uint8_t> buffer_data = p_state->buffers[i]; | 
| 751 | 		Dictionary gltf_buffer; | 
| 752 | 		String filename = p_path.get_basename().get_file() + itos(i) + ".bin" ; | 
| 753 | 		String path = p_path.get_base_dir() + "/"  + filename; | 
| 754 | 		Error err; | 
| 755 | 		Ref<FileAccess> file = FileAccess::open(path, FileAccess::WRITE, &err); | 
| 756 | 		if (file.is_null()) { | 
| 757 | 			return err; | 
| 758 | 		} | 
| 759 | 		if (buffer_data.size() == 0) { | 
| 760 | 			return OK; | 
| 761 | 		} | 
| 762 | 		file->create(FileAccess::ACCESS_RESOURCES); | 
| 763 | 		file->store_buffer(buffer_data.ptr(), buffer_data.size()); | 
| 764 | 		gltf_buffer["uri" ] = filename; | 
| 765 | 		gltf_buffer["byteLength" ] = buffer_data.size(); | 
| 766 | 		buffers.push_back(gltf_buffer); | 
| 767 | 	} | 
| 768 | 	p_state->json["buffers" ] = buffers; | 
| 769 |  | 
| 770 | 	return OK; | 
| 771 | } | 
| 772 |  | 
| 773 | Error GLTFDocument::_parse_buffers(Ref<GLTFState> p_state, const String &p_base_path) { | 
| 774 | 	if (!p_state->json.has("buffers" )) { | 
| 775 | 		return OK; | 
| 776 | 	} | 
| 777 |  | 
| 778 | 	const Array &buffers = p_state->json["buffers" ]; | 
| 779 | 	for (GLTFBufferIndex i = 0; i < buffers.size(); i++) { | 
| 780 | 		if (i == 0 && p_state->glb_data.size()) { | 
| 781 | 			p_state->buffers.push_back(p_state->glb_data); | 
| 782 |  | 
| 783 | 		} else { | 
| 784 | 			const Dictionary &buffer = buffers[i]; | 
| 785 | 			if (buffer.has("uri" )) { | 
| 786 | 				Vector<uint8_t> buffer_data; | 
| 787 | 				String uri = buffer["uri" ]; | 
| 788 |  | 
| 789 | 				if (uri.begins_with("data:" )) { // Embedded data using base64. | 
| 790 | 					// Validate data MIME types and throw an error if it's one we don't know/support. | 
| 791 | 					if (!uri.begins_with("data:application/octet-stream;base64" ) && | 
| 792 | 							!uri.begins_with("data:application/gltf-buffer;base64" )) { | 
| 793 | 						ERR_PRINT("glTF: Got buffer with an unknown URI data type: "  + uri); | 
| 794 | 					} | 
| 795 | 					buffer_data = _parse_base64_uri(uri); | 
| 796 | 				} else { // Relative path to an external image file. | 
| 797 | 					ERR_FAIL_COND_V(p_base_path.is_empty(), ERR_INVALID_PARAMETER); | 
| 798 | 					uri = uri.uri_decode(); | 
| 799 | 					uri = p_base_path.path_join(uri).replace("\\" , "/" ); // Fix for Windows. | 
| 800 | 					buffer_data = FileAccess::get_file_as_bytes(uri); | 
| 801 | 					ERR_FAIL_COND_V_MSG(buffer.size() == 0, ERR_PARSE_ERROR, "glTF: Couldn't load binary file as an array: "  + uri); | 
| 802 | 				} | 
| 803 |  | 
| 804 | 				ERR_FAIL_COND_V(!buffer.has("byteLength" ), ERR_PARSE_ERROR); | 
| 805 | 				int byteLength = buffer["byteLength" ]; | 
| 806 | 				ERR_FAIL_COND_V(byteLength < buffer_data.size(), ERR_PARSE_ERROR); | 
| 807 | 				p_state->buffers.push_back(buffer_data); | 
| 808 | 			} | 
| 809 | 		} | 
| 810 | 	} | 
| 811 |  | 
| 812 | 	print_verbose("glTF: Total buffers: "  + itos(p_state->buffers.size())); | 
| 813 |  | 
| 814 | 	return OK; | 
| 815 | } | 
| 816 |  | 
| 817 | Error GLTFDocument::_encode_buffer_views(Ref<GLTFState> p_state) { | 
| 818 | 	Array buffers; | 
| 819 | 	for (GLTFBufferViewIndex i = 0; i < p_state->buffer_views.size(); i++) { | 
| 820 | 		Dictionary d; | 
| 821 |  | 
| 822 | 		Ref<GLTFBufferView> buffer_view = p_state->buffer_views[i]; | 
| 823 |  | 
| 824 | 		d["buffer" ] = buffer_view->buffer; | 
| 825 | 		d["byteLength" ] = buffer_view->byte_length; | 
| 826 |  | 
| 827 | 		d["byteOffset" ] = buffer_view->byte_offset; | 
| 828 |  | 
| 829 | 		if (buffer_view->byte_stride != -1) { | 
| 830 | 			d["byteStride" ] = buffer_view->byte_stride; | 
| 831 | 		} | 
| 832 |  | 
| 833 | 		// TODO Sparse | 
| 834 | 		// d["target"] = buffer_view->indices; | 
| 835 |  | 
| 836 | 		ERR_FAIL_COND_V(!d.has("buffer" ), ERR_INVALID_DATA); | 
| 837 | 		ERR_FAIL_COND_V(!d.has("byteLength" ), ERR_INVALID_DATA); | 
| 838 | 		buffers.push_back(d); | 
| 839 | 	} | 
| 840 | 	print_verbose("glTF: Total buffer views: "  + itos(p_state->buffer_views.size())); | 
| 841 | 	if (!buffers.size()) { | 
| 842 | 		return OK; | 
| 843 | 	} | 
| 844 | 	p_state->json["bufferViews" ] = buffers; | 
| 845 | 	return OK; | 
| 846 | } | 
| 847 |  | 
| 848 | Error GLTFDocument::_parse_buffer_views(Ref<GLTFState> p_state) { | 
| 849 | 	if (!p_state->json.has("bufferViews" )) { | 
| 850 | 		return OK; | 
| 851 | 	} | 
| 852 | 	const Array &buffers = p_state->json["bufferViews" ]; | 
| 853 | 	for (GLTFBufferViewIndex i = 0; i < buffers.size(); i++) { | 
| 854 | 		const Dictionary &d = buffers[i]; | 
| 855 |  | 
| 856 | 		Ref<GLTFBufferView> buffer_view; | 
| 857 | 		buffer_view.instantiate(); | 
| 858 |  | 
| 859 | 		ERR_FAIL_COND_V(!d.has("buffer" ), ERR_PARSE_ERROR); | 
| 860 | 		buffer_view->buffer = d["buffer" ]; | 
| 861 | 		ERR_FAIL_COND_V(!d.has("byteLength" ), ERR_PARSE_ERROR); | 
| 862 | 		buffer_view->byte_length = d["byteLength" ]; | 
| 863 |  | 
| 864 | 		if (d.has("byteOffset" )) { | 
| 865 | 			buffer_view->byte_offset = d["byteOffset" ]; | 
| 866 | 		} | 
| 867 |  | 
| 868 | 		if (d.has("byteStride" )) { | 
| 869 | 			buffer_view->byte_stride = d["byteStride" ]; | 
| 870 | 		} | 
| 871 |  | 
| 872 | 		if (d.has("target" )) { | 
| 873 | 			const int target = d["target" ]; | 
| 874 | 			buffer_view->indices = target == GLTFDocument::ELEMENT_ARRAY_BUFFER; | 
| 875 | 		} | 
| 876 |  | 
| 877 | 		p_state->buffer_views.push_back(buffer_view); | 
| 878 | 	} | 
| 879 |  | 
| 880 | 	print_verbose("glTF: Total buffer views: "  + itos(p_state->buffer_views.size())); | 
| 881 |  | 
| 882 | 	return OK; | 
| 883 | } | 
| 884 |  | 
| 885 | Error GLTFDocument::_encode_accessors(Ref<GLTFState> p_state) { | 
| 886 | 	Array accessors; | 
| 887 | 	for (GLTFAccessorIndex i = 0; i < p_state->accessors.size(); i++) { | 
| 888 | 		Dictionary d; | 
| 889 |  | 
| 890 | 		Ref<GLTFAccessor> accessor = p_state->accessors[i]; | 
| 891 | 		d["componentType" ] = accessor->component_type; | 
| 892 | 		d["count" ] = accessor->count; | 
| 893 | 		d["type" ] = _get_accessor_type_name(accessor->type); | 
| 894 | 		d["byteOffset" ] = accessor->byte_offset; | 
| 895 | 		d["normalized" ] = accessor->normalized; | 
| 896 | 		d["max" ] = accessor->max; | 
| 897 | 		d["min" ] = accessor->min; | 
| 898 | 		d["bufferView" ] = accessor->buffer_view; //optional because it may be sparse... | 
| 899 |  | 
| 900 | 		// Dictionary s; | 
| 901 | 		// s["count"] = accessor->sparse_count; | 
| 902 | 		// ERR_FAIL_COND_V(!s.has("count"), ERR_PARSE_ERROR); | 
| 903 |  | 
| 904 | 		// s["indices"] = accessor->sparse_accessors; | 
| 905 | 		// ERR_FAIL_COND_V(!s.has("indices"), ERR_PARSE_ERROR); | 
| 906 |  | 
| 907 | 		// Dictionary si; | 
| 908 |  | 
| 909 | 		// si["bufferView"] = accessor->sparse_indices_buffer_view; | 
| 910 |  | 
| 911 | 		// ERR_FAIL_COND_V(!si.has("bufferView"), ERR_PARSE_ERROR); | 
| 912 | 		// si["componentType"] = accessor->sparse_indices_component_type; | 
| 913 |  | 
| 914 | 		// if (si.has("byteOffset")) { | 
| 915 | 		// 	si["byteOffset"] = accessor->sparse_indices_byte_offset; | 
| 916 | 		// } | 
| 917 |  | 
| 918 | 		// ERR_FAIL_COND_V(!si.has("componentType"), ERR_PARSE_ERROR); | 
| 919 | 		// s["indices"] = si; | 
| 920 | 		// Dictionary sv; | 
| 921 |  | 
| 922 | 		// sv["bufferView"] = accessor->sparse_values_buffer_view; | 
| 923 | 		// if (sv.has("byteOffset")) { | 
| 924 | 		// 	sv["byteOffset"] = accessor->sparse_values_byte_offset; | 
| 925 | 		// } | 
| 926 | 		// ERR_FAIL_COND_V(!sv.has("bufferView"), ERR_PARSE_ERROR); | 
| 927 | 		// s["values"] = sv; | 
| 928 | 		// ERR_FAIL_COND_V(!s.has("values"), ERR_PARSE_ERROR); | 
| 929 | 		// d["sparse"] = s; | 
| 930 | 		accessors.push_back(d); | 
| 931 | 	} | 
| 932 |  | 
| 933 | 	if (!accessors.size()) { | 
| 934 | 		return OK; | 
| 935 | 	} | 
| 936 | 	p_state->json["accessors" ] = accessors; | 
| 937 | 	ERR_FAIL_COND_V(!p_state->json.has("accessors" ), ERR_FILE_CORRUPT); | 
| 938 | 	print_verbose("glTF: Total accessors: "  + itos(p_state->accessors.size())); | 
| 939 |  | 
| 940 | 	return OK; | 
| 941 | } | 
| 942 |  | 
| 943 | String GLTFDocument::_get_accessor_type_name(const GLTFType p_type) { | 
| 944 | 	if (p_type == GLTFType::TYPE_SCALAR) { | 
| 945 | 		return "SCALAR" ; | 
| 946 | 	} | 
| 947 | 	if (p_type == GLTFType::TYPE_VEC2) { | 
| 948 | 		return "VEC2" ; | 
| 949 | 	} | 
| 950 | 	if (p_type == GLTFType::TYPE_VEC3) { | 
| 951 | 		return "VEC3" ; | 
| 952 | 	} | 
| 953 | 	if (p_type == GLTFType::TYPE_VEC4) { | 
| 954 | 		return "VEC4" ; | 
| 955 | 	} | 
| 956 |  | 
| 957 | 	if (p_type == GLTFType::TYPE_MAT2) { | 
| 958 | 		return "MAT2" ; | 
| 959 | 	} | 
| 960 | 	if (p_type == GLTFType::TYPE_MAT3) { | 
| 961 | 		return "MAT3" ; | 
| 962 | 	} | 
| 963 | 	if (p_type == GLTFType::TYPE_MAT4) { | 
| 964 | 		return "MAT4" ; | 
| 965 | 	} | 
| 966 | 	ERR_FAIL_V("SCALAR" ); | 
| 967 | } | 
| 968 |  | 
| 969 | GLTFType GLTFDocument::_get_type_from_str(const String &p_string) { | 
| 970 | 	if (p_string == "SCALAR" ) { | 
| 971 | 		return GLTFType::TYPE_SCALAR; | 
| 972 | 	} | 
| 973 |  | 
| 974 | 	if (p_string == "VEC2" ) { | 
| 975 | 		return GLTFType::TYPE_VEC2; | 
| 976 | 	} | 
| 977 | 	if (p_string == "VEC3" ) { | 
| 978 | 		return GLTFType::TYPE_VEC3; | 
| 979 | 	} | 
| 980 | 	if (p_string == "VEC4" ) { | 
| 981 | 		return GLTFType::TYPE_VEC4; | 
| 982 | 	} | 
| 983 |  | 
| 984 | 	if (p_string == "MAT2" ) { | 
| 985 | 		return GLTFType::TYPE_MAT2; | 
| 986 | 	} | 
| 987 | 	if (p_string == "MAT3" ) { | 
| 988 | 		return GLTFType::TYPE_MAT3; | 
| 989 | 	} | 
| 990 | 	if (p_string == "MAT4" ) { | 
| 991 | 		return GLTFType::TYPE_MAT4; | 
| 992 | 	} | 
| 993 |  | 
| 994 | 	ERR_FAIL_V(GLTFType::TYPE_SCALAR); | 
| 995 | } | 
| 996 |  | 
| 997 | Error GLTFDocument::_parse_accessors(Ref<GLTFState> p_state) { | 
| 998 | 	if (!p_state->json.has("accessors" )) { | 
| 999 | 		return OK; | 
| 1000 | 	} | 
| 1001 | 	const Array &accessors = p_state->json["accessors" ]; | 
| 1002 | 	for (GLTFAccessorIndex i = 0; i < accessors.size(); i++) { | 
| 1003 | 		const Dictionary &d = accessors[i]; | 
| 1004 |  | 
| 1005 | 		Ref<GLTFAccessor> accessor; | 
| 1006 | 		accessor.instantiate(); | 
| 1007 |  | 
| 1008 | 		ERR_FAIL_COND_V(!d.has("componentType" ), ERR_PARSE_ERROR); | 
| 1009 | 		accessor->component_type = d["componentType" ]; | 
| 1010 | 		ERR_FAIL_COND_V(!d.has("count" ), ERR_PARSE_ERROR); | 
| 1011 | 		accessor->count = d["count" ]; | 
| 1012 | 		ERR_FAIL_COND_V(!d.has("type" ), ERR_PARSE_ERROR); | 
| 1013 | 		accessor->type = _get_type_from_str(d["type" ]); | 
| 1014 |  | 
| 1015 | 		if (d.has("bufferView" )) { | 
| 1016 | 			accessor->buffer_view = d["bufferView" ]; //optional because it may be sparse... | 
| 1017 | 		} | 
| 1018 |  | 
| 1019 | 		if (d.has("byteOffset" )) { | 
| 1020 | 			accessor->byte_offset = d["byteOffset" ]; | 
| 1021 | 		} | 
| 1022 |  | 
| 1023 | 		if (d.has("normalized" )) { | 
| 1024 | 			accessor->normalized = d["normalized" ]; | 
| 1025 | 		} | 
| 1026 |  | 
| 1027 | 		if (d.has("max" )) { | 
| 1028 | 			accessor->max = d["max" ]; | 
| 1029 | 		} | 
| 1030 |  | 
| 1031 | 		if (d.has("min" )) { | 
| 1032 | 			accessor->min = d["min" ]; | 
| 1033 | 		} | 
| 1034 |  | 
| 1035 | 		if (d.has("sparse" )) { | 
| 1036 | 			//eeh.. | 
| 1037 |  | 
| 1038 | 			const Dictionary &s = d["sparse" ]; | 
| 1039 |  | 
| 1040 | 			ERR_FAIL_COND_V(!s.has("count" ), ERR_PARSE_ERROR); | 
| 1041 | 			accessor->sparse_count = s["count" ]; | 
| 1042 | 			ERR_FAIL_COND_V(!s.has("indices" ), ERR_PARSE_ERROR); | 
| 1043 | 			const Dictionary &si = s["indices" ]; | 
| 1044 |  | 
| 1045 | 			ERR_FAIL_COND_V(!si.has("bufferView" ), ERR_PARSE_ERROR); | 
| 1046 | 			accessor->sparse_indices_buffer_view = si["bufferView" ]; | 
| 1047 | 			ERR_FAIL_COND_V(!si.has("componentType" ), ERR_PARSE_ERROR); | 
| 1048 | 			accessor->sparse_indices_component_type = si["componentType" ]; | 
| 1049 |  | 
| 1050 | 			if (si.has("byteOffset" )) { | 
| 1051 | 				accessor->sparse_indices_byte_offset = si["byteOffset" ]; | 
| 1052 | 			} | 
| 1053 |  | 
| 1054 | 			ERR_FAIL_COND_V(!s.has("values" ), ERR_PARSE_ERROR); | 
| 1055 | 			const Dictionary &sv = s["values" ]; | 
| 1056 |  | 
| 1057 | 			ERR_FAIL_COND_V(!sv.has("bufferView" ), ERR_PARSE_ERROR); | 
| 1058 | 			accessor->sparse_values_buffer_view = sv["bufferView" ]; | 
| 1059 | 			if (sv.has("byteOffset" )) { | 
| 1060 | 				accessor->sparse_values_byte_offset = sv["byteOffset" ]; | 
| 1061 | 			} | 
| 1062 | 		} | 
| 1063 |  | 
| 1064 | 		p_state->accessors.push_back(accessor); | 
| 1065 | 	} | 
| 1066 |  | 
| 1067 | 	print_verbose("glTF: Total accessors: "  + itos(p_state->accessors.size())); | 
| 1068 |  | 
| 1069 | 	return OK; | 
| 1070 | } | 
| 1071 |  | 
| 1072 | double GLTFDocument::_filter_number(double p_float) { | 
| 1073 | 	if (Math::is_nan(p_float)) { | 
| 1074 | 		return 0.0f; | 
| 1075 | 	} | 
| 1076 | 	return p_float; | 
| 1077 | } | 
| 1078 |  | 
| 1079 | String GLTFDocument::_get_component_type_name(const uint32_t p_component) { | 
| 1080 | 	switch (p_component) { | 
| 1081 | 		case GLTFDocument::COMPONENT_TYPE_BYTE: | 
| 1082 | 			return "Byte" ; | 
| 1083 | 		case GLTFDocument::COMPONENT_TYPE_UNSIGNED_BYTE: | 
| 1084 | 			return "UByte" ; | 
| 1085 | 		case GLTFDocument::COMPONENT_TYPE_SHORT: | 
| 1086 | 			return "Short" ; | 
| 1087 | 		case GLTFDocument::COMPONENT_TYPE_UNSIGNED_SHORT: | 
| 1088 | 			return "UShort" ; | 
| 1089 | 		case GLTFDocument::COMPONENT_TYPE_INT: | 
| 1090 | 			return "Int" ; | 
| 1091 | 		case GLTFDocument::COMPONENT_TYPE_FLOAT: | 
| 1092 | 			return "Float" ; | 
| 1093 | 	} | 
| 1094 |  | 
| 1095 | 	return "<Error>" ; | 
| 1096 | } | 
| 1097 |  | 
| 1098 | String GLTFDocument::_get_type_name(const GLTFType p_component) { | 
| 1099 | 	static const char *names[] = { | 
| 1100 | 		"float" , | 
| 1101 | 		"vec2" , | 
| 1102 | 		"vec3" , | 
| 1103 | 		"vec4" , | 
| 1104 | 		"mat2" , | 
| 1105 | 		"mat3" , | 
| 1106 | 		"mat4"  | 
| 1107 | 	}; | 
| 1108 |  | 
| 1109 | 	return names[p_component]; | 
| 1110 | } | 
| 1111 |  | 
| 1112 | Error GLTFDocument::_encode_buffer_view(Ref<GLTFState> p_state, const double *p_src, const int p_count, const GLTFType p_type, const int p_component_type, const bool p_normalized, const int p_byte_offset, const bool p_for_vertex, GLTFBufferViewIndex &r_accessor) { | 
| 1113 | 	const int component_count_for_type[7] = { | 
| 1114 | 		1, 2, 3, 4, 4, 9, 16 | 
| 1115 | 	}; | 
| 1116 |  | 
| 1117 | 	const int component_count = component_count_for_type[p_type]; | 
| 1118 | 	const int component_size = _get_component_type_size(p_component_type); | 
| 1119 | 	ERR_FAIL_COND_V(component_size == 0, FAILED); | 
| 1120 |  | 
| 1121 | 	int skip_every = 0; | 
| 1122 | 	int skip_bytes = 0; | 
| 1123 | 	//special case of alignments, as described in spec | 
| 1124 | 	switch (p_component_type) { | 
| 1125 | 		case COMPONENT_TYPE_BYTE: | 
| 1126 | 		case COMPONENT_TYPE_UNSIGNED_BYTE: { | 
| 1127 | 			if (p_type == TYPE_MAT2) { | 
| 1128 | 				skip_every = 2; | 
| 1129 | 				skip_bytes = 2; | 
| 1130 | 			} | 
| 1131 | 			if (p_type == TYPE_MAT3) { | 
| 1132 | 				skip_every = 3; | 
| 1133 | 				skip_bytes = 1; | 
| 1134 | 			} | 
| 1135 | 		} break; | 
| 1136 | 		case COMPONENT_TYPE_SHORT: | 
| 1137 | 		case COMPONENT_TYPE_UNSIGNED_SHORT: { | 
| 1138 | 			if (p_type == TYPE_MAT3) { | 
| 1139 | 				skip_every = 6; | 
| 1140 | 				skip_bytes = 4; | 
| 1141 | 			} | 
| 1142 | 		} break; | 
| 1143 | 		default: { | 
| 1144 | 		} | 
| 1145 | 	} | 
| 1146 |  | 
| 1147 | 	Ref<GLTFBufferView> bv; | 
| 1148 | 	bv.instantiate(); | 
| 1149 | 	const uint32_t offset = bv->byte_offset = p_byte_offset; | 
| 1150 | 	Vector<uint8_t> &gltf_buffer = p_state->buffers.write[0]; | 
| 1151 |  | 
| 1152 | 	int stride = _get_component_type_size(p_component_type); | 
| 1153 | 	if (p_for_vertex && stride % 4) { | 
| 1154 | 		stride += 4 - (stride % 4); //according to spec must be multiple of 4 | 
| 1155 | 	} | 
| 1156 | 	//use to debug | 
| 1157 | 	print_verbose("glTF: encoding type "  + _get_type_name(p_type) + " component type: "  + _get_component_type_name(p_component_type) + " stride: "  + itos(stride) + " amount "  + itos(p_count)); | 
| 1158 |  | 
| 1159 | 	print_verbose("glTF: encoding accessor offset "  + itos(p_byte_offset) + " view offset: "  + itos(bv->byte_offset) + " total buffer len: "  + itos(gltf_buffer.size()) + " view len "  + itos(bv->byte_length)); | 
| 1160 |  | 
| 1161 | 	const int buffer_end = (stride * (p_count - 1)) + _get_component_type_size(p_component_type); | 
| 1162 | 	// TODO define bv->byte_stride | 
| 1163 | 	bv->byte_offset = gltf_buffer.size(); | 
| 1164 |  | 
| 1165 | 	switch (p_component_type) { | 
| 1166 | 		case COMPONENT_TYPE_BYTE: { | 
| 1167 | 			Vector<int8_t> buffer; | 
| 1168 | 			buffer.resize(p_count * component_count); | 
| 1169 | 			int32_t dst_i = 0; | 
| 1170 | 			for (int i = 0; i < p_count; i++) { | 
| 1171 | 				for (int j = 0; j < component_count; j++) { | 
| 1172 | 					if (skip_every && j > 0 && (j % skip_every) == 0) { | 
| 1173 | 						dst_i += skip_bytes; | 
| 1174 | 					} | 
| 1175 | 					double d = *p_src; | 
| 1176 | 					if (p_normalized) { | 
| 1177 | 						buffer.write[dst_i] = d * 128.0; | 
| 1178 | 					} else { | 
| 1179 | 						buffer.write[dst_i] = d; | 
| 1180 | 					} | 
| 1181 | 					p_src++; | 
| 1182 | 					dst_i++; | 
| 1183 | 				} | 
| 1184 | 			} | 
| 1185 | 			int64_t old_size = gltf_buffer.size(); | 
| 1186 | 			gltf_buffer.resize(old_size + (buffer.size() * sizeof(int8_t))); | 
| 1187 | 			memcpy(gltf_buffer.ptrw() + old_size, buffer.ptrw(), buffer.size() * sizeof(int8_t)); | 
| 1188 | 			bv->byte_length = buffer.size() * sizeof(int8_t); | 
| 1189 | 		} break; | 
| 1190 | 		case COMPONENT_TYPE_UNSIGNED_BYTE: { | 
| 1191 | 			Vector<uint8_t> buffer; | 
| 1192 | 			buffer.resize(p_count * component_count); | 
| 1193 | 			int32_t dst_i = 0; | 
| 1194 | 			for (int i = 0; i < p_count; i++) { | 
| 1195 | 				for (int j = 0; j < component_count; j++) { | 
| 1196 | 					if (skip_every && j > 0 && (j % skip_every) == 0) { | 
| 1197 | 						dst_i += skip_bytes; | 
| 1198 | 					} | 
| 1199 | 					double d = *p_src; | 
| 1200 | 					if (p_normalized) { | 
| 1201 | 						buffer.write[dst_i] = d * 255.0; | 
| 1202 | 					} else { | 
| 1203 | 						buffer.write[dst_i] = d; | 
| 1204 | 					} | 
| 1205 | 					p_src++; | 
| 1206 | 					dst_i++; | 
| 1207 | 				} | 
| 1208 | 			} | 
| 1209 | 			gltf_buffer.append_array(buffer); | 
| 1210 | 			bv->byte_length = buffer.size() * sizeof(uint8_t); | 
| 1211 | 		} break; | 
| 1212 | 		case COMPONENT_TYPE_SHORT: { | 
| 1213 | 			Vector<int16_t> buffer; | 
| 1214 | 			buffer.resize(p_count * component_count); | 
| 1215 | 			int32_t dst_i = 0; | 
| 1216 | 			for (int i = 0; i < p_count; i++) { | 
| 1217 | 				for (int j = 0; j < component_count; j++) { | 
| 1218 | 					if (skip_every && j > 0 && (j % skip_every) == 0) { | 
| 1219 | 						dst_i += skip_bytes; | 
| 1220 | 					} | 
| 1221 | 					double d = *p_src; | 
| 1222 | 					if (p_normalized) { | 
| 1223 | 						buffer.write[dst_i] = d * 32768.0; | 
| 1224 | 					} else { | 
| 1225 | 						buffer.write[dst_i] = d; | 
| 1226 | 					} | 
| 1227 | 					p_src++; | 
| 1228 | 					dst_i++; | 
| 1229 | 				} | 
| 1230 | 			} | 
| 1231 | 			int64_t old_size = gltf_buffer.size(); | 
| 1232 | 			gltf_buffer.resize(old_size + (buffer.size() * sizeof(int16_t))); | 
| 1233 | 			memcpy(gltf_buffer.ptrw() + old_size, buffer.ptrw(), buffer.size() * sizeof(int16_t)); | 
| 1234 | 			bv->byte_length = buffer.size() * sizeof(int16_t); | 
| 1235 | 		} break; | 
| 1236 | 		case COMPONENT_TYPE_UNSIGNED_SHORT: { | 
| 1237 | 			Vector<uint16_t> buffer; | 
| 1238 | 			buffer.resize(p_count * component_count); | 
| 1239 | 			int32_t dst_i = 0; | 
| 1240 | 			for (int i = 0; i < p_count; i++) { | 
| 1241 | 				for (int j = 0; j < component_count; j++) { | 
| 1242 | 					if (skip_every && j > 0 && (j % skip_every) == 0) { | 
| 1243 | 						dst_i += skip_bytes; | 
| 1244 | 					} | 
| 1245 | 					double d = *p_src; | 
| 1246 | 					if (p_normalized) { | 
| 1247 | 						buffer.write[dst_i] = d * 65535.0; | 
| 1248 | 					} else { | 
| 1249 | 						buffer.write[dst_i] = d; | 
| 1250 | 					} | 
| 1251 | 					p_src++; | 
| 1252 | 					dst_i++; | 
| 1253 | 				} | 
| 1254 | 			} | 
| 1255 | 			int64_t old_size = gltf_buffer.size(); | 
| 1256 | 			gltf_buffer.resize(old_size + (buffer.size() * sizeof(uint16_t))); | 
| 1257 | 			memcpy(gltf_buffer.ptrw() + old_size, buffer.ptrw(), buffer.size() * sizeof(uint16_t)); | 
| 1258 | 			bv->byte_length = buffer.size() * sizeof(uint16_t); | 
| 1259 | 		} break; | 
| 1260 | 		case COMPONENT_TYPE_INT: { | 
| 1261 | 			Vector<int> buffer; | 
| 1262 | 			buffer.resize(p_count * component_count); | 
| 1263 | 			int32_t dst_i = 0; | 
| 1264 | 			for (int i = 0; i < p_count; i++) { | 
| 1265 | 				for (int j = 0; j < component_count; j++) { | 
| 1266 | 					if (skip_every && j > 0 && (j % skip_every) == 0) { | 
| 1267 | 						dst_i += skip_bytes; | 
| 1268 | 					} | 
| 1269 | 					double d = *p_src; | 
| 1270 | 					buffer.write[dst_i] = d; | 
| 1271 | 					p_src++; | 
| 1272 | 					dst_i++; | 
| 1273 | 				} | 
| 1274 | 			} | 
| 1275 | 			int64_t old_size = gltf_buffer.size(); | 
| 1276 | 			gltf_buffer.resize(old_size + (buffer.size() * sizeof(int32_t))); | 
| 1277 | 			memcpy(gltf_buffer.ptrw() + old_size, buffer.ptrw(), buffer.size() * sizeof(int32_t)); | 
| 1278 | 			bv->byte_length = buffer.size() * sizeof(int32_t); | 
| 1279 | 		} break; | 
| 1280 | 		case COMPONENT_TYPE_FLOAT: { | 
| 1281 | 			Vector<float> buffer; | 
| 1282 | 			buffer.resize(p_count * component_count); | 
| 1283 | 			int32_t dst_i = 0; | 
| 1284 | 			for (int i = 0; i < p_count; i++) { | 
| 1285 | 				for (int j = 0; j < component_count; j++) { | 
| 1286 | 					if (skip_every && j > 0 && (j % skip_every) == 0) { | 
| 1287 | 						dst_i += skip_bytes; | 
| 1288 | 					} | 
| 1289 | 					double d = *p_src; | 
| 1290 | 					buffer.write[dst_i] = d; | 
| 1291 | 					p_src++; | 
| 1292 | 					dst_i++; | 
| 1293 | 				} | 
| 1294 | 			} | 
| 1295 | 			int64_t old_size = gltf_buffer.size(); | 
| 1296 | 			gltf_buffer.resize(old_size + (buffer.size() * sizeof(float))); | 
| 1297 | 			memcpy(gltf_buffer.ptrw() + old_size, buffer.ptrw(), buffer.size() * sizeof(float)); | 
| 1298 | 			bv->byte_length = buffer.size() * sizeof(float); | 
| 1299 | 		} break; | 
| 1300 | 	} | 
| 1301 | 	ERR_FAIL_COND_V(buffer_end > bv->byte_length, ERR_INVALID_DATA); | 
| 1302 |  | 
| 1303 | 	ERR_FAIL_COND_V((int)(offset + buffer_end) > gltf_buffer.size(), ERR_INVALID_DATA); | 
| 1304 | 	r_accessor = bv->buffer = p_state->buffer_views.size(); | 
| 1305 | 	p_state->buffer_views.push_back(bv); | 
| 1306 | 	return OK; | 
| 1307 | } | 
| 1308 |  | 
| 1309 | Error GLTFDocument::_decode_buffer_view(Ref<GLTFState> p_state, double *p_dst, const GLTFBufferViewIndex p_buffer_view, const int p_skip_every, const int p_skip_bytes, const int p_element_size, const int p_count, const GLTFType p_type, const int p_component_count, const int p_component_type, const int p_component_size, const bool p_normalized, const int p_byte_offset, const bool p_for_vertex) { | 
| 1310 | 	const Ref<GLTFBufferView> bv = p_state->buffer_views[p_buffer_view]; | 
| 1311 |  | 
| 1312 | 	int stride = p_element_size; | 
| 1313 | 	if (bv->byte_stride != -1) { | 
| 1314 | 		stride = bv->byte_stride; | 
| 1315 | 	} | 
| 1316 | 	if (p_for_vertex && stride % 4) { | 
| 1317 | 		stride += 4 - (stride % 4); //according to spec must be multiple of 4 | 
| 1318 | 	} | 
| 1319 |  | 
| 1320 | 	ERR_FAIL_INDEX_V(bv->buffer, p_state->buffers.size(), ERR_PARSE_ERROR); | 
| 1321 |  | 
| 1322 | 	const uint32_t offset = bv->byte_offset + p_byte_offset; | 
| 1323 | 	Vector<uint8_t> buffer = p_state->buffers[bv->buffer]; //copy on write, so no performance hit | 
| 1324 | 	const uint8_t *bufptr = buffer.ptr(); | 
| 1325 |  | 
| 1326 | 	//use to debug | 
| 1327 | 	print_verbose("glTF: type "  + _get_type_name(p_type) + " component type: "  + _get_component_type_name(p_component_type) + " stride: "  + itos(stride) + " amount "  + itos(p_count)); | 
| 1328 | 	print_verbose("glTF: accessor offset "  + itos(p_byte_offset) + " view offset: "  + itos(bv->byte_offset) + " total buffer len: "  + itos(buffer.size()) + " view len "  + itos(bv->byte_length)); | 
| 1329 |  | 
| 1330 | 	const int buffer_end = (stride * (p_count - 1)) + p_element_size; | 
| 1331 | 	ERR_FAIL_COND_V(buffer_end > bv->byte_length, ERR_PARSE_ERROR); | 
| 1332 |  | 
| 1333 | 	ERR_FAIL_COND_V((int)(offset + buffer_end) > buffer.size(), ERR_PARSE_ERROR); | 
| 1334 |  | 
| 1335 | 	//fill everything as doubles | 
| 1336 |  | 
| 1337 | 	for (int i = 0; i < p_count; i++) { | 
| 1338 | 		const uint8_t *src = &bufptr[offset + i * stride]; | 
| 1339 |  | 
| 1340 | 		for (int j = 0; j < p_component_count; j++) { | 
| 1341 | 			if (p_skip_every && j > 0 && (j % p_skip_every) == 0) { | 
| 1342 | 				src += p_skip_bytes; | 
| 1343 | 			} | 
| 1344 |  | 
| 1345 | 			double d = 0; | 
| 1346 |  | 
| 1347 | 			switch (p_component_type) { | 
| 1348 | 				case COMPONENT_TYPE_BYTE: { | 
| 1349 | 					int8_t b = int8_t(*src); | 
| 1350 | 					if (p_normalized) { | 
| 1351 | 						d = (double(b) / 128.0); | 
| 1352 | 					} else { | 
| 1353 | 						d = double(b); | 
| 1354 | 					} | 
| 1355 | 				} break; | 
| 1356 | 				case COMPONENT_TYPE_UNSIGNED_BYTE: { | 
| 1357 | 					uint8_t b = *src; | 
| 1358 | 					if (p_normalized) { | 
| 1359 | 						d = (double(b) / 255.0); | 
| 1360 | 					} else { | 
| 1361 | 						d = double(b); | 
| 1362 | 					} | 
| 1363 | 				} break; | 
| 1364 | 				case COMPONENT_TYPE_SHORT: { | 
| 1365 | 					int16_t s = *(int16_t *)src; | 
| 1366 | 					if (p_normalized) { | 
| 1367 | 						d = (double(s) / 32768.0); | 
| 1368 | 					} else { | 
| 1369 | 						d = double(s); | 
| 1370 | 					} | 
| 1371 | 				} break; | 
| 1372 | 				case COMPONENT_TYPE_UNSIGNED_SHORT: { | 
| 1373 | 					uint16_t s = *(uint16_t *)src; | 
| 1374 | 					if (p_normalized) { | 
| 1375 | 						d = (double(s) / 65535.0); | 
| 1376 | 					} else { | 
| 1377 | 						d = double(s); | 
| 1378 | 					} | 
| 1379 | 				} break; | 
| 1380 | 				case COMPONENT_TYPE_INT: { | 
| 1381 | 					d = *(int *)src; | 
| 1382 | 				} break; | 
| 1383 | 				case COMPONENT_TYPE_FLOAT: { | 
| 1384 | 					d = *(float *)src; | 
| 1385 | 				} break; | 
| 1386 | 			} | 
| 1387 |  | 
| 1388 | 			*p_dst++ = d; | 
| 1389 | 			src += p_component_size; | 
| 1390 | 		} | 
| 1391 | 	} | 
| 1392 |  | 
| 1393 | 	return OK; | 
| 1394 | } | 
| 1395 |  | 
| 1396 | int GLTFDocument::_get_component_type_size(const int p_component_type) { | 
| 1397 | 	switch (p_component_type) { | 
| 1398 | 		case COMPONENT_TYPE_BYTE: | 
| 1399 | 		case COMPONENT_TYPE_UNSIGNED_BYTE: | 
| 1400 | 			return 1; | 
| 1401 | 			break; | 
| 1402 | 		case COMPONENT_TYPE_SHORT: | 
| 1403 | 		case COMPONENT_TYPE_UNSIGNED_SHORT: | 
| 1404 | 			return 2; | 
| 1405 | 			break; | 
| 1406 | 		case COMPONENT_TYPE_INT: | 
| 1407 | 		case COMPONENT_TYPE_FLOAT: | 
| 1408 | 			return 4; | 
| 1409 | 			break; | 
| 1410 | 		default: { | 
| 1411 | 			ERR_FAIL_V(0); | 
| 1412 | 		} | 
| 1413 | 	} | 
| 1414 | 	return 0; | 
| 1415 | } | 
| 1416 |  | 
| 1417 | Vector<double> GLTFDocument::_decode_accessor(Ref<GLTFState> p_state, const GLTFAccessorIndex p_accessor, const bool p_for_vertex) { | 
| 1418 | 	//spec, for reference: | 
| 1419 | 	//https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#data-alignment | 
| 1420 |  | 
| 1421 | 	ERR_FAIL_INDEX_V(p_accessor, p_state->accessors.size(), Vector<double>()); | 
| 1422 |  | 
| 1423 | 	const Ref<GLTFAccessor> a = p_state->accessors[p_accessor]; | 
| 1424 |  | 
| 1425 | 	const int component_count_for_type[7] = { | 
| 1426 | 		1, 2, 3, 4, 4, 9, 16 | 
| 1427 | 	}; | 
| 1428 |  | 
| 1429 | 	const int component_count = component_count_for_type[a->type]; | 
| 1430 | 	const int component_size = _get_component_type_size(a->component_type); | 
| 1431 | 	ERR_FAIL_COND_V(component_size == 0, Vector<double>()); | 
| 1432 | 	int element_size = component_count * component_size; | 
| 1433 |  | 
| 1434 | 	int skip_every = 0; | 
| 1435 | 	int skip_bytes = 0; | 
| 1436 | 	//special case of alignments, as described in spec | 
| 1437 | 	switch (a->component_type) { | 
| 1438 | 		case COMPONENT_TYPE_BYTE: | 
| 1439 | 		case COMPONENT_TYPE_UNSIGNED_BYTE: { | 
| 1440 | 			if (a->type == TYPE_MAT2) { | 
| 1441 | 				skip_every = 2; | 
| 1442 | 				skip_bytes = 2; | 
| 1443 | 				element_size = 8; //override for this case | 
| 1444 | 			} | 
| 1445 | 			if (a->type == TYPE_MAT3) { | 
| 1446 | 				skip_every = 3; | 
| 1447 | 				skip_bytes = 1; | 
| 1448 | 				element_size = 12; //override for this case | 
| 1449 | 			} | 
| 1450 | 		} break; | 
| 1451 | 		case COMPONENT_TYPE_SHORT: | 
| 1452 | 		case COMPONENT_TYPE_UNSIGNED_SHORT: { | 
| 1453 | 			if (a->type == TYPE_MAT3) { | 
| 1454 | 				skip_every = 6; | 
| 1455 | 				skip_bytes = 4; | 
| 1456 | 				element_size = 16; //override for this case | 
| 1457 | 			} | 
| 1458 | 		} break; | 
| 1459 | 		default: { | 
| 1460 | 		} | 
| 1461 | 	} | 
| 1462 |  | 
| 1463 | 	Vector<double> dst_buffer; | 
| 1464 | 	dst_buffer.resize(component_count * a->count); | 
| 1465 | 	double *dst = dst_buffer.ptrw(); | 
| 1466 |  | 
| 1467 | 	if (a->buffer_view >= 0) { | 
| 1468 | 		ERR_FAIL_INDEX_V(a->buffer_view, p_state->buffer_views.size(), Vector<double>()); | 
| 1469 |  | 
| 1470 | 		const Error err = _decode_buffer_view(p_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); | 
| 1471 | 		if (err != OK) { | 
| 1472 | 			return Vector<double>(); | 
| 1473 | 		} | 
| 1474 | 	} else { | 
| 1475 | 		//fill with zeros, as bufferview is not defined. | 
| 1476 | 		for (int i = 0; i < (a->count * component_count); i++) { | 
| 1477 | 			dst_buffer.write[i] = 0; | 
| 1478 | 		} | 
| 1479 | 	} | 
| 1480 |  | 
| 1481 | 	if (a->sparse_count > 0) { | 
| 1482 | 		// I could not find any file using this, so this code is so far untested | 
| 1483 | 		Vector<double> indices; | 
| 1484 | 		indices.resize(a->sparse_count); | 
| 1485 | 		const int indices_component_size = _get_component_type_size(a->sparse_indices_component_type); | 
| 1486 |  | 
| 1487 | 		Error err = _decode_buffer_view(p_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); | 
| 1488 | 		if (err != OK) { | 
| 1489 | 			return Vector<double>(); | 
| 1490 | 		} | 
| 1491 |  | 
| 1492 | 		Vector<double> data; | 
| 1493 | 		data.resize(component_count * a->sparse_count); | 
| 1494 | 		err = _decode_buffer_view(p_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); | 
| 1495 | 		if (err != OK) { | 
| 1496 | 			return Vector<double>(); | 
| 1497 | 		} | 
| 1498 |  | 
| 1499 | 		for (int i = 0; i < indices.size(); i++) { | 
| 1500 | 			const int write_offset = int(indices[i]) * component_count; | 
| 1501 |  | 
| 1502 | 			for (int j = 0; j < component_count; j++) { | 
| 1503 | 				dst[write_offset + j] = data[i * component_count + j]; | 
| 1504 | 			} | 
| 1505 | 		} | 
| 1506 | 	} | 
| 1507 |  | 
| 1508 | 	return dst_buffer; | 
| 1509 | } | 
| 1510 |  | 
| 1511 | GLTFAccessorIndex GLTFDocument::_encode_accessor_as_ints(Ref<GLTFState> p_state, const Vector<int32_t> p_attribs, const bool p_for_vertex) { | 
| 1512 | 	if (p_attribs.size() == 0) { | 
| 1513 | 		return -1; | 
| 1514 | 	} | 
| 1515 | 	const int element_count = 1; | 
| 1516 | 	const int ret_size = p_attribs.size(); | 
| 1517 | 	Vector<double> attribs; | 
| 1518 | 	attribs.resize(ret_size); | 
| 1519 | 	Vector<double> type_max; | 
| 1520 | 	type_max.resize(element_count); | 
| 1521 | 	Vector<double> type_min; | 
| 1522 | 	type_min.resize(element_count); | 
| 1523 | 	for (int i = 0; i < p_attribs.size(); i++) { | 
| 1524 | 		attribs.write[i] = Math::snapped(p_attribs[i], 1.0); | 
| 1525 | 		if (i == 0) { | 
| 1526 | 			for (int32_t type_i = 0; type_i < element_count; type_i++) { | 
| 1527 | 				type_max.write[type_i] = attribs[(i * element_count) + type_i]; | 
| 1528 | 				type_min.write[type_i] = attribs[(i * element_count) + type_i]; | 
| 1529 | 			} | 
| 1530 | 		} | 
| 1531 | 		for (int32_t type_i = 0; type_i < element_count; type_i++) { | 
| 1532 | 			type_max.write[type_i] = MAX(attribs[(i * element_count) + type_i], type_max[type_i]); | 
| 1533 | 			type_min.write[type_i] = MIN(attribs[(i * element_count) + type_i], type_min[type_i]); | 
| 1534 | 			type_max.write[type_i] = _filter_number(type_max.write[type_i]); | 
| 1535 | 			type_min.write[type_i] = _filter_number(type_min.write[type_i]); | 
| 1536 | 		} | 
| 1537 | 	} | 
| 1538 |  | 
| 1539 | 	ERR_FAIL_COND_V(attribs.size() == 0, -1); | 
| 1540 |  | 
| 1541 | 	Ref<GLTFAccessor> accessor; | 
| 1542 | 	accessor.instantiate(); | 
| 1543 | 	GLTFBufferIndex buffer_view_i; | 
| 1544 | 	int64_t size = p_state->buffers[0].size(); | 
| 1545 | 	const GLTFType type = GLTFType::TYPE_SCALAR; | 
| 1546 | 	const int component_type = GLTFDocument::COMPONENT_TYPE_INT; | 
| 1547 |  | 
| 1548 | 	accessor->max = type_max; | 
| 1549 | 	accessor->min = type_min; | 
| 1550 | 	accessor->normalized = false; | 
| 1551 | 	accessor->count = ret_size; | 
| 1552 | 	accessor->type = type; | 
| 1553 | 	accessor->component_type = component_type; | 
| 1554 | 	accessor->byte_offset = 0; | 
| 1555 | 	Error err = _encode_buffer_view(p_state, attribs.ptr(), attribs.size(), type, component_type, accessor->normalized, size, p_for_vertex, buffer_view_i); | 
| 1556 | 	if (err != OK) { | 
| 1557 | 		return -1; | 
| 1558 | 	} | 
| 1559 | 	accessor->buffer_view = buffer_view_i; | 
| 1560 | 	p_state->accessors.push_back(accessor); | 
| 1561 | 	return p_state->accessors.size() - 1; | 
| 1562 | } | 
| 1563 |  | 
| 1564 | Vector<int> GLTFDocument::_decode_accessor_as_ints(Ref<GLTFState> p_state, const GLTFAccessorIndex p_accessor, const bool p_for_vertex) { | 
| 1565 | 	const Vector<double> attribs = _decode_accessor(p_state, p_accessor, p_for_vertex); | 
| 1566 | 	Vector<int> ret; | 
| 1567 |  | 
| 1568 | 	if (attribs.size() == 0) { | 
| 1569 | 		return ret; | 
| 1570 | 	} | 
| 1571 |  | 
| 1572 | 	const double *attribs_ptr = attribs.ptr(); | 
| 1573 | 	const int ret_size = attribs.size(); | 
| 1574 | 	ret.resize(ret_size); | 
| 1575 | 	{ | 
| 1576 | 		for (int i = 0; i < ret_size; i++) { | 
| 1577 | 			ret.write[i] = int(attribs_ptr[i]); | 
| 1578 | 		} | 
| 1579 | 	} | 
| 1580 | 	return ret; | 
| 1581 | } | 
| 1582 |  | 
| 1583 | Vector<float> GLTFDocument::_decode_accessor_as_floats(Ref<GLTFState> p_state, const GLTFAccessorIndex p_accessor, const bool p_for_vertex) { | 
| 1584 | 	const Vector<double> attribs = _decode_accessor(p_state, p_accessor, p_for_vertex); | 
| 1585 | 	Vector<float> ret; | 
| 1586 |  | 
| 1587 | 	if (attribs.size() == 0) { | 
| 1588 | 		return ret; | 
| 1589 | 	} | 
| 1590 |  | 
| 1591 | 	const double *attribs_ptr = attribs.ptr(); | 
| 1592 | 	const int ret_size = attribs.size(); | 
| 1593 | 	ret.resize(ret_size); | 
| 1594 | 	{ | 
| 1595 | 		for (int i = 0; i < ret_size; i++) { | 
| 1596 | 			ret.write[i] = float(attribs_ptr[i]); | 
| 1597 | 		} | 
| 1598 | 	} | 
| 1599 | 	return ret; | 
| 1600 | } | 
| 1601 |  | 
| 1602 | GLTFAccessorIndex GLTFDocument::_encode_accessor_as_vec2(Ref<GLTFState> p_state, const Vector<Vector2> p_attribs, const bool p_for_vertex) { | 
| 1603 | 	if (p_attribs.size() == 0) { | 
| 1604 | 		return -1; | 
| 1605 | 	} | 
| 1606 | 	const int element_count = 2; | 
| 1607 |  | 
| 1608 | 	const int ret_size = p_attribs.size() * element_count; | 
| 1609 | 	Vector<double> attribs; | 
| 1610 | 	attribs.resize(ret_size); | 
| 1611 | 	Vector<double> type_max; | 
| 1612 | 	type_max.resize(element_count); | 
| 1613 | 	Vector<double> type_min; | 
| 1614 | 	type_min.resize(element_count); | 
| 1615 |  | 
| 1616 | 	for (int i = 0; i < p_attribs.size(); i++) { | 
| 1617 | 		Vector2 attrib = p_attribs[i]; | 
| 1618 | 		attribs.write[(i * element_count) + 0] = Math::snapped(attrib.x, CMP_NORMALIZE_TOLERANCE); | 
| 1619 | 		attribs.write[(i * element_count) + 1] = Math::snapped(attrib.y, CMP_NORMALIZE_TOLERANCE); | 
| 1620 | 		_calc_accessor_min_max(i, element_count, type_max, attribs, type_min); | 
| 1621 | 	} | 
| 1622 |  | 
| 1623 | 	ERR_FAIL_COND_V(attribs.size() % element_count != 0, -1); | 
| 1624 |  | 
| 1625 | 	Ref<GLTFAccessor> accessor; | 
| 1626 | 	accessor.instantiate(); | 
| 1627 | 	GLTFBufferIndex buffer_view_i; | 
| 1628 | 	int64_t size = p_state->buffers[0].size(); | 
| 1629 | 	const GLTFType type = GLTFType::TYPE_VEC2; | 
| 1630 | 	const int component_type = GLTFDocument::COMPONENT_TYPE_FLOAT; | 
| 1631 |  | 
| 1632 | 	accessor->max = type_max; | 
| 1633 | 	accessor->min = type_min; | 
| 1634 | 	accessor->normalized = false; | 
| 1635 | 	accessor->count = p_attribs.size(); | 
| 1636 | 	accessor->type = type; | 
| 1637 | 	accessor->component_type = component_type; | 
| 1638 | 	accessor->byte_offset = 0; | 
| 1639 | 	Error err = _encode_buffer_view(p_state, attribs.ptr(), p_attribs.size(), type, component_type, accessor->normalized, size, p_for_vertex, buffer_view_i); | 
| 1640 | 	if (err != OK) { | 
| 1641 | 		return -1; | 
| 1642 | 	} | 
| 1643 | 	accessor->buffer_view = buffer_view_i; | 
| 1644 | 	p_state->accessors.push_back(accessor); | 
| 1645 | 	return p_state->accessors.size() - 1; | 
| 1646 | } | 
| 1647 |  | 
| 1648 | GLTFAccessorIndex GLTFDocument::_encode_accessor_as_color(Ref<GLTFState> p_state, const Vector<Color> p_attribs, const bool p_for_vertex) { | 
| 1649 | 	if (p_attribs.size() == 0) { | 
| 1650 | 		return -1; | 
| 1651 | 	} | 
| 1652 |  | 
| 1653 | 	const int ret_size = p_attribs.size() * 4; | 
| 1654 | 	Vector<double> attribs; | 
| 1655 | 	attribs.resize(ret_size); | 
| 1656 |  | 
| 1657 | 	const int element_count = 4; | 
| 1658 | 	Vector<double> type_max; | 
| 1659 | 	type_max.resize(element_count); | 
| 1660 | 	Vector<double> type_min; | 
| 1661 | 	type_min.resize(element_count); | 
| 1662 | 	for (int i = 0; i < p_attribs.size(); i++) { | 
| 1663 | 		Color attrib = p_attribs[i]; | 
| 1664 | 		attribs.write[(i * element_count) + 0] = Math::snapped(attrib.r, CMP_NORMALIZE_TOLERANCE); | 
| 1665 | 		attribs.write[(i * element_count) + 1] = Math::snapped(attrib.g, CMP_NORMALIZE_TOLERANCE); | 
| 1666 | 		attribs.write[(i * element_count) + 2] = Math::snapped(attrib.b, CMP_NORMALIZE_TOLERANCE); | 
| 1667 | 		attribs.write[(i * element_count) + 3] = Math::snapped(attrib.a, CMP_NORMALIZE_TOLERANCE); | 
| 1668 |  | 
| 1669 | 		_calc_accessor_min_max(i, element_count, type_max, attribs, type_min); | 
| 1670 | 	} | 
| 1671 |  | 
| 1672 | 	ERR_FAIL_COND_V(attribs.size() % element_count != 0, -1); | 
| 1673 |  | 
| 1674 | 	Ref<GLTFAccessor> accessor; | 
| 1675 | 	accessor.instantiate(); | 
| 1676 | 	GLTFBufferIndex buffer_view_i; | 
| 1677 | 	int64_t size = p_state->buffers[0].size(); | 
| 1678 | 	const GLTFType type = GLTFType::TYPE_VEC4; | 
| 1679 | 	const int component_type = GLTFDocument::COMPONENT_TYPE_FLOAT; | 
| 1680 |  | 
| 1681 | 	accessor->max = type_max; | 
| 1682 | 	accessor->min = type_min; | 
| 1683 | 	accessor->normalized = false; | 
| 1684 | 	accessor->count = p_attribs.size(); | 
| 1685 | 	accessor->type = type; | 
| 1686 | 	accessor->component_type = component_type; | 
| 1687 | 	accessor->byte_offset = 0; | 
| 1688 | 	Error err = _encode_buffer_view(p_state, attribs.ptr(), p_attribs.size(), type, component_type, accessor->normalized, size, p_for_vertex, buffer_view_i); | 
| 1689 | 	if (err != OK) { | 
| 1690 | 		return -1; | 
| 1691 | 	} | 
| 1692 | 	accessor->buffer_view = buffer_view_i; | 
| 1693 | 	p_state->accessors.push_back(accessor); | 
| 1694 | 	return p_state->accessors.size() - 1; | 
| 1695 | } | 
| 1696 |  | 
| 1697 | void GLTFDocument::_calc_accessor_min_max(int p_i, const int p_element_count, Vector<double> &p_type_max, Vector<double> p_attribs, Vector<double> &p_type_min) { | 
| 1698 | 	if (p_i == 0) { | 
| 1699 | 		for (int32_t type_i = 0; type_i < p_element_count; type_i++) { | 
| 1700 | 			p_type_max.write[type_i] = p_attribs[(p_i * p_element_count) + type_i]; | 
| 1701 | 			p_type_min.write[type_i] = p_attribs[(p_i * p_element_count) + type_i]; | 
| 1702 | 		} | 
| 1703 | 	} | 
| 1704 | 	for (int32_t type_i = 0; type_i < p_element_count; type_i++) { | 
| 1705 | 		p_type_max.write[type_i] = MAX(p_attribs[(p_i * p_element_count) + type_i], p_type_max[type_i]); | 
| 1706 | 		p_type_min.write[type_i] = MIN(p_attribs[(p_i * p_element_count) + type_i], p_type_min[type_i]); | 
| 1707 | 		p_type_max.write[type_i] = _filter_number(p_type_max.write[type_i]); | 
| 1708 | 		p_type_min.write[type_i] = _filter_number(p_type_min.write[type_i]); | 
| 1709 | 	} | 
| 1710 | } | 
| 1711 |  | 
| 1712 | GLTFAccessorIndex GLTFDocument::_encode_accessor_as_weights(Ref<GLTFState> p_state, const Vector<Color> p_attribs, const bool p_for_vertex) { | 
| 1713 | 	if (p_attribs.size() == 0) { | 
| 1714 | 		return -1; | 
| 1715 | 	} | 
| 1716 |  | 
| 1717 | 	const int ret_size = p_attribs.size() * 4; | 
| 1718 | 	Vector<double> attribs; | 
| 1719 | 	attribs.resize(ret_size); | 
| 1720 |  | 
| 1721 | 	const int element_count = 4; | 
| 1722 |  | 
| 1723 | 	Vector<double> type_max; | 
| 1724 | 	type_max.resize(element_count); | 
| 1725 | 	Vector<double> type_min; | 
| 1726 | 	type_min.resize(element_count); | 
| 1727 | 	for (int i = 0; i < p_attribs.size(); i++) { | 
| 1728 | 		Color attrib = p_attribs[i]; | 
| 1729 | 		attribs.write[(i * element_count) + 0] = Math::snapped(attrib.r, CMP_NORMALIZE_TOLERANCE); | 
| 1730 | 		attribs.write[(i * element_count) + 1] = Math::snapped(attrib.g, CMP_NORMALIZE_TOLERANCE); | 
| 1731 | 		attribs.write[(i * element_count) + 2] = Math::snapped(attrib.b, CMP_NORMALIZE_TOLERANCE); | 
| 1732 | 		attribs.write[(i * element_count) + 3] = Math::snapped(attrib.a, CMP_NORMALIZE_TOLERANCE); | 
| 1733 |  | 
| 1734 | 		_calc_accessor_min_max(i, element_count, type_max, attribs, type_min); | 
| 1735 | 	} | 
| 1736 |  | 
| 1737 | 	ERR_FAIL_COND_V(attribs.size() % element_count != 0, -1); | 
| 1738 |  | 
| 1739 | 	Ref<GLTFAccessor> accessor; | 
| 1740 | 	accessor.instantiate(); | 
| 1741 | 	GLTFBufferIndex buffer_view_i; | 
| 1742 | 	int64_t size = p_state->buffers[0].size(); | 
| 1743 | 	const GLTFType type = GLTFType::TYPE_VEC4; | 
| 1744 | 	const int component_type = GLTFDocument::COMPONENT_TYPE_FLOAT; | 
| 1745 |  | 
| 1746 | 	accessor->max = type_max; | 
| 1747 | 	accessor->min = type_min; | 
| 1748 | 	accessor->normalized = false; | 
| 1749 | 	accessor->count = p_attribs.size(); | 
| 1750 | 	accessor->type = type; | 
| 1751 | 	accessor->component_type = component_type; | 
| 1752 | 	accessor->byte_offset = 0; | 
| 1753 | 	Error err = _encode_buffer_view(p_state, attribs.ptr(), p_attribs.size(), type, component_type, accessor->normalized, size, p_for_vertex, buffer_view_i); | 
| 1754 | 	if (err != OK) { | 
| 1755 | 		return -1; | 
| 1756 | 	} | 
| 1757 | 	accessor->buffer_view = buffer_view_i; | 
| 1758 | 	p_state->accessors.push_back(accessor); | 
| 1759 | 	return p_state->accessors.size() - 1; | 
| 1760 | } | 
| 1761 |  | 
| 1762 | GLTFAccessorIndex GLTFDocument::_encode_accessor_as_joints(Ref<GLTFState> p_state, const Vector<Color> p_attribs, const bool p_for_vertex) { | 
| 1763 | 	if (p_attribs.size() == 0) { | 
| 1764 | 		return -1; | 
| 1765 | 	} | 
| 1766 |  | 
| 1767 | 	const int element_count = 4; | 
| 1768 | 	const int ret_size = p_attribs.size() * element_count; | 
| 1769 | 	Vector<double> attribs; | 
| 1770 | 	attribs.resize(ret_size); | 
| 1771 |  | 
| 1772 | 	Vector<double> type_max; | 
| 1773 | 	type_max.resize(element_count); | 
| 1774 | 	Vector<double> type_min; | 
| 1775 | 	type_min.resize(element_count); | 
| 1776 | 	for (int i = 0; i < p_attribs.size(); i++) { | 
| 1777 | 		Color attrib = p_attribs[i]; | 
| 1778 | 		attribs.write[(i * element_count) + 0] = Math::snapped(attrib.r, CMP_NORMALIZE_TOLERANCE); | 
| 1779 | 		attribs.write[(i * element_count) + 1] = Math::snapped(attrib.g, CMP_NORMALIZE_TOLERANCE); | 
| 1780 | 		attribs.write[(i * element_count) + 2] = Math::snapped(attrib.b, CMP_NORMALIZE_TOLERANCE); | 
| 1781 | 		attribs.write[(i * element_count) + 3] = Math::snapped(attrib.a, CMP_NORMALIZE_TOLERANCE); | 
| 1782 | 		_calc_accessor_min_max(i, element_count, type_max, attribs, type_min); | 
| 1783 | 	} | 
| 1784 | 	ERR_FAIL_COND_V(attribs.size() % element_count != 0, -1); | 
| 1785 |  | 
| 1786 | 	Ref<GLTFAccessor> accessor; | 
| 1787 | 	accessor.instantiate(); | 
| 1788 | 	GLTFBufferIndex buffer_view_i; | 
| 1789 | 	int64_t size = p_state->buffers[0].size(); | 
| 1790 | 	const GLTFType type = GLTFType::TYPE_VEC4; | 
| 1791 | 	const int component_type = GLTFDocument::COMPONENT_TYPE_UNSIGNED_SHORT; | 
| 1792 |  | 
| 1793 | 	accessor->max = type_max; | 
| 1794 | 	accessor->min = type_min; | 
| 1795 | 	accessor->normalized = false; | 
| 1796 | 	accessor->count = p_attribs.size(); | 
| 1797 | 	accessor->type = type; | 
| 1798 | 	accessor->component_type = component_type; | 
| 1799 | 	accessor->byte_offset = 0; | 
| 1800 | 	Error err = _encode_buffer_view(p_state, attribs.ptr(), p_attribs.size(), type, component_type, accessor->normalized, size, p_for_vertex, buffer_view_i); | 
| 1801 | 	if (err != OK) { | 
| 1802 | 		return -1; | 
| 1803 | 	} | 
| 1804 | 	accessor->buffer_view = buffer_view_i; | 
| 1805 | 	p_state->accessors.push_back(accessor); | 
| 1806 | 	return p_state->accessors.size() - 1; | 
| 1807 | } | 
| 1808 |  | 
| 1809 | GLTFAccessorIndex GLTFDocument::_encode_accessor_as_quaternions(Ref<GLTFState> p_state, const Vector<Quaternion> p_attribs, const bool p_for_vertex) { | 
| 1810 | 	if (p_attribs.size() == 0) { | 
| 1811 | 		return -1; | 
| 1812 | 	} | 
| 1813 | 	const int element_count = 4; | 
| 1814 |  | 
| 1815 | 	const int ret_size = p_attribs.size() * element_count; | 
| 1816 | 	Vector<double> attribs; | 
| 1817 | 	attribs.resize(ret_size); | 
| 1818 |  | 
| 1819 | 	Vector<double> type_max; | 
| 1820 | 	type_max.resize(element_count); | 
| 1821 | 	Vector<double> type_min; | 
| 1822 | 	type_min.resize(element_count); | 
| 1823 | 	for (int i = 0; i < p_attribs.size(); i++) { | 
| 1824 | 		Quaternion quaternion = p_attribs[i]; | 
| 1825 | 		attribs.write[(i * element_count) + 0] = Math::snapped(quaternion.x, CMP_NORMALIZE_TOLERANCE); | 
| 1826 | 		attribs.write[(i * element_count) + 1] = Math::snapped(quaternion.y, CMP_NORMALIZE_TOLERANCE); | 
| 1827 | 		attribs.write[(i * element_count) + 2] = Math::snapped(quaternion.z, CMP_NORMALIZE_TOLERANCE); | 
| 1828 | 		attribs.write[(i * element_count) + 3] = Math::snapped(quaternion.w, CMP_NORMALIZE_TOLERANCE); | 
| 1829 |  | 
| 1830 | 		_calc_accessor_min_max(i, element_count, type_max, attribs, type_min); | 
| 1831 | 	} | 
| 1832 |  | 
| 1833 | 	ERR_FAIL_COND_V(attribs.size() % element_count != 0, -1); | 
| 1834 |  | 
| 1835 | 	Ref<GLTFAccessor> accessor; | 
| 1836 | 	accessor.instantiate(); | 
| 1837 | 	GLTFBufferIndex buffer_view_i; | 
| 1838 | 	int64_t size = p_state->buffers[0].size(); | 
| 1839 | 	const GLTFType type = GLTFType::TYPE_VEC4; | 
| 1840 | 	const int component_type = GLTFDocument::COMPONENT_TYPE_FLOAT; | 
| 1841 |  | 
| 1842 | 	accessor->max = type_max; | 
| 1843 | 	accessor->min = type_min; | 
| 1844 | 	accessor->normalized = false; | 
| 1845 | 	accessor->count = p_attribs.size(); | 
| 1846 | 	accessor->type = type; | 
| 1847 | 	accessor->component_type = component_type; | 
| 1848 | 	accessor->byte_offset = 0; | 
| 1849 | 	Error err = _encode_buffer_view(p_state, attribs.ptr(), p_attribs.size(), type, component_type, accessor->normalized, size, p_for_vertex, buffer_view_i); | 
| 1850 | 	if (err != OK) { | 
| 1851 | 		return -1; | 
| 1852 | 	} | 
| 1853 | 	accessor->buffer_view = buffer_view_i; | 
| 1854 | 	p_state->accessors.push_back(accessor); | 
| 1855 | 	return p_state->accessors.size() - 1; | 
| 1856 | } | 
| 1857 |  | 
| 1858 | Vector<Vector2> GLTFDocument::_decode_accessor_as_vec2(Ref<GLTFState> p_state, const GLTFAccessorIndex p_accessor, const bool p_for_vertex) { | 
| 1859 | 	const Vector<double> attribs = _decode_accessor(p_state, p_accessor, p_for_vertex); | 
| 1860 | 	Vector<Vector2> ret; | 
| 1861 |  | 
| 1862 | 	if (attribs.size() == 0) { | 
| 1863 | 		return ret; | 
| 1864 | 	} | 
| 1865 |  | 
| 1866 | 	ERR_FAIL_COND_V(attribs.size() % 2 != 0, ret); | 
| 1867 | 	const double *attribs_ptr = attribs.ptr(); | 
| 1868 | 	const int ret_size = attribs.size() / 2; | 
| 1869 | 	ret.resize(ret_size); | 
| 1870 | 	{ | 
| 1871 | 		for (int i = 0; i < ret_size; i++) { | 
| 1872 | 			ret.write[i] = Vector2(attribs_ptr[i * 2 + 0], attribs_ptr[i * 2 + 1]); | 
| 1873 | 		} | 
| 1874 | 	} | 
| 1875 | 	return ret; | 
| 1876 | } | 
| 1877 |  | 
| 1878 | GLTFAccessorIndex GLTFDocument::_encode_accessor_as_floats(Ref<GLTFState> p_state, const Vector<real_t> p_attribs, const bool p_for_vertex) { | 
| 1879 | 	if (p_attribs.size() == 0) { | 
| 1880 | 		return -1; | 
| 1881 | 	} | 
| 1882 | 	const int element_count = 1; | 
| 1883 | 	const int ret_size = p_attribs.size(); | 
| 1884 | 	Vector<double> attribs; | 
| 1885 | 	attribs.resize(ret_size); | 
| 1886 |  | 
| 1887 | 	Vector<double> type_max; | 
| 1888 | 	type_max.resize(element_count); | 
| 1889 | 	Vector<double> type_min; | 
| 1890 | 	type_min.resize(element_count); | 
| 1891 |  | 
| 1892 | 	for (int i = 0; i < p_attribs.size(); i++) { | 
| 1893 | 		attribs.write[i] = Math::snapped(p_attribs[i], CMP_NORMALIZE_TOLERANCE); | 
| 1894 |  | 
| 1895 | 		_calc_accessor_min_max(i, element_count, type_max, attribs, type_min); | 
| 1896 | 	} | 
| 1897 |  | 
| 1898 | 	ERR_FAIL_COND_V(!attribs.size(), -1); | 
| 1899 |  | 
| 1900 | 	Ref<GLTFAccessor> accessor; | 
| 1901 | 	accessor.instantiate(); | 
| 1902 | 	GLTFBufferIndex buffer_view_i; | 
| 1903 | 	int64_t size = p_state->buffers[0].size(); | 
| 1904 | 	const GLTFType type = GLTFType::TYPE_SCALAR; | 
| 1905 | 	const int component_type = GLTFDocument::COMPONENT_TYPE_FLOAT; | 
| 1906 |  | 
| 1907 | 	accessor->max = type_max; | 
| 1908 | 	accessor->min = type_min; | 
| 1909 | 	accessor->normalized = false; | 
| 1910 | 	accessor->count = ret_size; | 
| 1911 | 	accessor->type = type; | 
| 1912 | 	accessor->component_type = component_type; | 
| 1913 | 	accessor->byte_offset = 0; | 
| 1914 | 	Error err = _encode_buffer_view(p_state, attribs.ptr(), attribs.size(), type, component_type, accessor->normalized, size, p_for_vertex, buffer_view_i); | 
| 1915 | 	if (err != OK) { | 
| 1916 | 		return -1; | 
| 1917 | 	} | 
| 1918 | 	accessor->buffer_view = buffer_view_i; | 
| 1919 | 	p_state->accessors.push_back(accessor); | 
| 1920 | 	return p_state->accessors.size() - 1; | 
| 1921 | } | 
| 1922 |  | 
| 1923 | GLTFAccessorIndex GLTFDocument::_encode_accessor_as_vec3(Ref<GLTFState> p_state, const Vector<Vector3> p_attribs, const bool p_for_vertex) { | 
| 1924 | 	if (p_attribs.size() == 0) { | 
| 1925 | 		return -1; | 
| 1926 | 	} | 
| 1927 | 	const int element_count = 3; | 
| 1928 | 	const int ret_size = p_attribs.size() * element_count; | 
| 1929 | 	Vector<double> attribs; | 
| 1930 | 	attribs.resize(ret_size); | 
| 1931 |  | 
| 1932 | 	Vector<double> type_max; | 
| 1933 | 	type_max.resize(element_count); | 
| 1934 | 	Vector<double> type_min; | 
| 1935 | 	type_min.resize(element_count); | 
| 1936 | 	for (int i = 0; i < p_attribs.size(); i++) { | 
| 1937 | 		Vector3 attrib = p_attribs[i]; | 
| 1938 | 		attribs.write[(i * element_count) + 0] = Math::snapped(attrib.x, CMP_NORMALIZE_TOLERANCE); | 
| 1939 | 		attribs.write[(i * element_count) + 1] = Math::snapped(attrib.y, CMP_NORMALIZE_TOLERANCE); | 
| 1940 | 		attribs.write[(i * element_count) + 2] = Math::snapped(attrib.z, CMP_NORMALIZE_TOLERANCE); | 
| 1941 |  | 
| 1942 | 		_calc_accessor_min_max(i, element_count, type_max, attribs, type_min); | 
| 1943 | 	} | 
| 1944 | 	ERR_FAIL_COND_V(attribs.size() % element_count != 0, -1); | 
| 1945 |  | 
| 1946 | 	Ref<GLTFAccessor> accessor; | 
| 1947 | 	accessor.instantiate(); | 
| 1948 | 	GLTFBufferIndex buffer_view_i; | 
| 1949 | 	int64_t size = p_state->buffers[0].size(); | 
| 1950 | 	const GLTFType type = GLTFType::TYPE_VEC3; | 
| 1951 | 	const int component_type = GLTFDocument::COMPONENT_TYPE_FLOAT; | 
| 1952 |  | 
| 1953 | 	accessor->max = type_max; | 
| 1954 | 	accessor->min = type_min; | 
| 1955 | 	accessor->normalized = false; | 
| 1956 | 	accessor->count = p_attribs.size(); | 
| 1957 | 	accessor->type = type; | 
| 1958 | 	accessor->component_type = component_type; | 
| 1959 | 	accessor->byte_offset = 0; | 
| 1960 | 	Error err = _encode_buffer_view(p_state, attribs.ptr(), p_attribs.size(), type, component_type, accessor->normalized, size, p_for_vertex, buffer_view_i); | 
| 1961 | 	if (err != OK) { | 
| 1962 | 		return -1; | 
| 1963 | 	} | 
| 1964 | 	accessor->buffer_view = buffer_view_i; | 
| 1965 | 	p_state->accessors.push_back(accessor); | 
| 1966 | 	return p_state->accessors.size() - 1; | 
| 1967 | } | 
| 1968 |  | 
| 1969 | GLTFAccessorIndex GLTFDocument::_encode_accessor_as_xform(Ref<GLTFState> p_state, const Vector<Transform3D> p_attribs, const bool p_for_vertex) { | 
| 1970 | 	if (p_attribs.size() == 0) { | 
| 1971 | 		return -1; | 
| 1972 | 	} | 
| 1973 | 	const int element_count = 16; | 
| 1974 | 	const int ret_size = p_attribs.size() * element_count; | 
| 1975 | 	Vector<double> attribs; | 
| 1976 | 	attribs.resize(ret_size); | 
| 1977 |  | 
| 1978 | 	Vector<double> type_max; | 
| 1979 | 	type_max.resize(element_count); | 
| 1980 | 	Vector<double> type_min; | 
| 1981 | 	type_min.resize(element_count); | 
| 1982 | 	for (int i = 0; i < p_attribs.size(); i++) { | 
| 1983 | 		Transform3D attrib = p_attribs[i]; | 
| 1984 | 		Basis basis = attrib.get_basis(); | 
| 1985 | 		Vector3 axis_0 = basis.get_column(Vector3::AXIS_X); | 
| 1986 |  | 
| 1987 | 		attribs.write[i * element_count + 0] = Math::snapped(axis_0.x, CMP_NORMALIZE_TOLERANCE); | 
| 1988 | 		attribs.write[i * element_count + 1] = Math::snapped(axis_0.y, CMP_NORMALIZE_TOLERANCE); | 
| 1989 | 		attribs.write[i * element_count + 2] = Math::snapped(axis_0.z, CMP_NORMALIZE_TOLERANCE); | 
| 1990 | 		attribs.write[i * element_count + 3] = 0.0; | 
| 1991 |  | 
| 1992 | 		Vector3 axis_1 = basis.get_column(Vector3::AXIS_Y); | 
| 1993 | 		attribs.write[i * element_count + 4] = Math::snapped(axis_1.x, CMP_NORMALIZE_TOLERANCE); | 
| 1994 | 		attribs.write[i * element_count + 5] = Math::snapped(axis_1.y, CMP_NORMALIZE_TOLERANCE); | 
| 1995 | 		attribs.write[i * element_count + 6] = Math::snapped(axis_1.z, CMP_NORMALIZE_TOLERANCE); | 
| 1996 | 		attribs.write[i * element_count + 7] = 0.0; | 
| 1997 |  | 
| 1998 | 		Vector3 axis_2 = basis.get_column(Vector3::AXIS_Z); | 
| 1999 | 		attribs.write[i * element_count + 8] = Math::snapped(axis_2.x, CMP_NORMALIZE_TOLERANCE); | 
| 2000 | 		attribs.write[i * element_count + 9] = Math::snapped(axis_2.y, CMP_NORMALIZE_TOLERANCE); | 
| 2001 | 		attribs.write[i * element_count + 10] = Math::snapped(axis_2.z, CMP_NORMALIZE_TOLERANCE); | 
| 2002 | 		attribs.write[i * element_count + 11] = 0.0; | 
| 2003 |  | 
| 2004 | 		Vector3 origin = attrib.get_origin(); | 
| 2005 | 		attribs.write[i * element_count + 12] = Math::snapped(origin.x, CMP_NORMALIZE_TOLERANCE); | 
| 2006 | 		attribs.write[i * element_count + 13] = Math::snapped(origin.y, CMP_NORMALIZE_TOLERANCE); | 
| 2007 | 		attribs.write[i * element_count + 14] = Math::snapped(origin.z, CMP_NORMALIZE_TOLERANCE); | 
| 2008 | 		attribs.write[i * element_count + 15] = 1.0; | 
| 2009 |  | 
| 2010 | 		_calc_accessor_min_max(i, element_count, type_max, attribs, type_min); | 
| 2011 | 	} | 
| 2012 | 	ERR_FAIL_COND_V(attribs.size() % element_count != 0, -1); | 
| 2013 |  | 
| 2014 | 	Ref<GLTFAccessor> accessor; | 
| 2015 | 	accessor.instantiate(); | 
| 2016 | 	GLTFBufferIndex buffer_view_i; | 
| 2017 | 	int64_t size = p_state->buffers[0].size(); | 
| 2018 | 	const GLTFType type = GLTFType::TYPE_MAT4; | 
| 2019 | 	const int component_type = GLTFDocument::COMPONENT_TYPE_FLOAT; | 
| 2020 |  | 
| 2021 | 	accessor->max = type_max; | 
| 2022 | 	accessor->min = type_min; | 
| 2023 | 	accessor->normalized = false; | 
| 2024 | 	accessor->count = p_attribs.size(); | 
| 2025 | 	accessor->type = type; | 
| 2026 | 	accessor->component_type = component_type; | 
| 2027 | 	accessor->byte_offset = 0; | 
| 2028 | 	Error err = _encode_buffer_view(p_state, attribs.ptr(), p_attribs.size(), type, component_type, accessor->normalized, size, p_for_vertex, buffer_view_i); | 
| 2029 | 	if (err != OK) { | 
| 2030 | 		return -1; | 
| 2031 | 	} | 
| 2032 | 	accessor->buffer_view = buffer_view_i; | 
| 2033 | 	p_state->accessors.push_back(accessor); | 
| 2034 | 	return p_state->accessors.size() - 1; | 
| 2035 | } | 
| 2036 |  | 
| 2037 | Vector<Vector3> GLTFDocument::_decode_accessor_as_vec3(Ref<GLTFState> p_state, const GLTFAccessorIndex p_accessor, const bool p_for_vertex) { | 
| 2038 | 	const Vector<double> attribs = _decode_accessor(p_state, p_accessor, p_for_vertex); | 
| 2039 | 	Vector<Vector3> ret; | 
| 2040 |  | 
| 2041 | 	if (attribs.size() == 0) { | 
| 2042 | 		return ret; | 
| 2043 | 	} | 
| 2044 |  | 
| 2045 | 	ERR_FAIL_COND_V(attribs.size() % 3 != 0, ret); | 
| 2046 | 	const double *attribs_ptr = attribs.ptr(); | 
| 2047 | 	const int ret_size = attribs.size() / 3; | 
| 2048 | 	ret.resize(ret_size); | 
| 2049 | 	{ | 
| 2050 | 		for (int i = 0; i < ret_size; i++) { | 
| 2051 | 			ret.write[i] = Vector3(attribs_ptr[i * 3 + 0], attribs_ptr[i * 3 + 1], attribs_ptr[i * 3 + 2]); | 
| 2052 | 		} | 
| 2053 | 	} | 
| 2054 | 	return ret; | 
| 2055 | } | 
| 2056 |  | 
| 2057 | Vector<Color> GLTFDocument::_decode_accessor_as_color(Ref<GLTFState> p_state, const GLTFAccessorIndex p_accessor, const bool p_for_vertex) { | 
| 2058 | 	const Vector<double> attribs = _decode_accessor(p_state, p_accessor, p_for_vertex); | 
| 2059 | 	Vector<Color> ret; | 
| 2060 |  | 
| 2061 | 	if (attribs.size() == 0) { | 
| 2062 | 		return ret; | 
| 2063 | 	} | 
| 2064 |  | 
| 2065 | 	const int type = p_state->accessors[p_accessor]->type; | 
| 2066 | 	ERR_FAIL_COND_V(!(type == TYPE_VEC3 || type == TYPE_VEC4), ret); | 
| 2067 | 	int vec_len = 3; | 
| 2068 | 	if (type == TYPE_VEC4) { | 
| 2069 | 		vec_len = 4; | 
| 2070 | 	} | 
| 2071 |  | 
| 2072 | 	ERR_FAIL_COND_V(attribs.size() % vec_len != 0, ret); | 
| 2073 | 	const double *attribs_ptr = attribs.ptr(); | 
| 2074 | 	const int ret_size = attribs.size() / vec_len; | 
| 2075 | 	ret.resize(ret_size); | 
| 2076 | 	{ | 
| 2077 | 		for (int i = 0; i < ret_size; i++) { | 
| 2078 | 			ret.write[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); | 
| 2079 | 		} | 
| 2080 | 	} | 
| 2081 | 	return ret; | 
| 2082 | } | 
| 2083 | Vector<Quaternion> GLTFDocument::_decode_accessor_as_quaternion(Ref<GLTFState> p_state, const GLTFAccessorIndex p_accessor, const bool p_for_vertex) { | 
| 2084 | 	const Vector<double> attribs = _decode_accessor(p_state, p_accessor, p_for_vertex); | 
| 2085 | 	Vector<Quaternion> ret; | 
| 2086 |  | 
| 2087 | 	if (attribs.size() == 0) { | 
| 2088 | 		return ret; | 
| 2089 | 	} | 
| 2090 |  | 
| 2091 | 	ERR_FAIL_COND_V(attribs.size() % 4 != 0, ret); | 
| 2092 | 	const double *attribs_ptr = attribs.ptr(); | 
| 2093 | 	const int ret_size = attribs.size() / 4; | 
| 2094 | 	ret.resize(ret_size); | 
| 2095 | 	{ | 
| 2096 | 		for (int i = 0; i < ret_size; i++) { | 
| 2097 | 			ret.write[i] = Quaternion(attribs_ptr[i * 4 + 0], attribs_ptr[i * 4 + 1], attribs_ptr[i * 4 + 2], attribs_ptr[i * 4 + 3]).normalized(); | 
| 2098 | 		} | 
| 2099 | 	} | 
| 2100 | 	return ret; | 
| 2101 | } | 
| 2102 | Vector<Transform2D> GLTFDocument::_decode_accessor_as_xform2d(Ref<GLTFState> p_state, const GLTFAccessorIndex p_accessor, const bool p_for_vertex) { | 
| 2103 | 	const Vector<double> attribs = _decode_accessor(p_state, p_accessor, p_for_vertex); | 
| 2104 | 	Vector<Transform2D> ret; | 
| 2105 |  | 
| 2106 | 	if (attribs.size() == 0) { | 
| 2107 | 		return ret; | 
| 2108 | 	} | 
| 2109 |  | 
| 2110 | 	ERR_FAIL_COND_V(attribs.size() % 4 != 0, ret); | 
| 2111 | 	ret.resize(attribs.size() / 4); | 
| 2112 | 	for (int i = 0; i < ret.size(); i++) { | 
| 2113 | 		ret.write[i][0] = Vector2(attribs[i * 4 + 0], attribs[i * 4 + 1]); | 
| 2114 | 		ret.write[i][1] = Vector2(attribs[i * 4 + 2], attribs[i * 4 + 3]); | 
| 2115 | 	} | 
| 2116 | 	return ret; | 
| 2117 | } | 
| 2118 |  | 
| 2119 | Vector<Basis> GLTFDocument::_decode_accessor_as_basis(Ref<GLTFState> p_state, const GLTFAccessorIndex p_accessor, const bool p_for_vertex) { | 
| 2120 | 	const Vector<double> attribs = _decode_accessor(p_state, p_accessor, p_for_vertex); | 
| 2121 | 	Vector<Basis> ret; | 
| 2122 |  | 
| 2123 | 	if (attribs.size() == 0) { | 
| 2124 | 		return ret; | 
| 2125 | 	} | 
| 2126 |  | 
| 2127 | 	ERR_FAIL_COND_V(attribs.size() % 9 != 0, ret); | 
| 2128 | 	ret.resize(attribs.size() / 9); | 
| 2129 | 	for (int i = 0; i < ret.size(); i++) { | 
| 2130 | 		ret.write[i].set_column(0, Vector3(attribs[i * 9 + 0], attribs[i * 9 + 1], attribs[i * 9 + 2])); | 
| 2131 | 		ret.write[i].set_column(1, Vector3(attribs[i * 9 + 3], attribs[i * 9 + 4], attribs[i * 9 + 5])); | 
| 2132 | 		ret.write[i].set_column(2, Vector3(attribs[i * 9 + 6], attribs[i * 9 + 7], attribs[i * 9 + 8])); | 
| 2133 | 	} | 
| 2134 | 	return ret; | 
| 2135 | } | 
| 2136 |  | 
| 2137 | Vector<Transform3D> GLTFDocument::_decode_accessor_as_xform(Ref<GLTFState> p_state, const GLTFAccessorIndex p_accessor, const bool p_for_vertex) { | 
| 2138 | 	const Vector<double> attribs = _decode_accessor(p_state, p_accessor, p_for_vertex); | 
| 2139 | 	Vector<Transform3D> ret; | 
| 2140 |  | 
| 2141 | 	if (attribs.size() == 0) { | 
| 2142 | 		return ret; | 
| 2143 | 	} | 
| 2144 |  | 
| 2145 | 	ERR_FAIL_COND_V(attribs.size() % 16 != 0, ret); | 
| 2146 | 	ret.resize(attribs.size() / 16); | 
| 2147 | 	for (int i = 0; i < ret.size(); i++) { | 
| 2148 | 		ret.write[i].basis.set_column(0, Vector3(attribs[i * 16 + 0], attribs[i * 16 + 1], attribs[i * 16 + 2])); | 
| 2149 | 		ret.write[i].basis.set_column(1, Vector3(attribs[i * 16 + 4], attribs[i * 16 + 5], attribs[i * 16 + 6])); | 
| 2150 | 		ret.write[i].basis.set_column(2, Vector3(attribs[i * 16 + 8], attribs[i * 16 + 9], attribs[i * 16 + 10])); | 
| 2151 | 		ret.write[i].set_origin(Vector3(attribs[i * 16 + 12], attribs[i * 16 + 13], attribs[i * 16 + 14])); | 
| 2152 | 	} | 
| 2153 | 	return ret; | 
| 2154 | } | 
| 2155 |  | 
| 2156 | Error GLTFDocument::_serialize_meshes(Ref<GLTFState> p_state) { | 
| 2157 | 	Array meshes; | 
| 2158 | 	for (GLTFMeshIndex gltf_mesh_i = 0; gltf_mesh_i < p_state->meshes.size(); gltf_mesh_i++) { | 
| 2159 | 		print_verbose("glTF: Serializing mesh: "  + itos(gltf_mesh_i)); | 
| 2160 | 		Ref<ImporterMesh> import_mesh = p_state->meshes.write[gltf_mesh_i]->get_mesh(); | 
| 2161 | 		if (import_mesh.is_null()) { | 
| 2162 | 			continue; | 
| 2163 | 		} | 
| 2164 | 		Array instance_materials = p_state->meshes.write[gltf_mesh_i]->get_instance_materials(); | 
| 2165 | 		Array primitives; | 
| 2166 | 		Dictionary gltf_mesh; | 
| 2167 | 		Array target_names; | 
| 2168 | 		Array weights; | 
| 2169 | 		for (int morph_i = 0; morph_i < import_mesh->get_blend_shape_count(); morph_i++) { | 
| 2170 | 			target_names.push_back(import_mesh->get_blend_shape_name(morph_i)); | 
| 2171 | 		} | 
| 2172 | 		for (int surface_i = 0; surface_i < import_mesh->get_surface_count(); surface_i++) { | 
| 2173 | 			Array targets; | 
| 2174 | 			Dictionary primitive; | 
| 2175 | 			Mesh::PrimitiveType primitive_type = import_mesh->get_surface_primitive_type(surface_i); | 
| 2176 | 			switch (primitive_type) { | 
| 2177 | 				case Mesh::PRIMITIVE_POINTS: { | 
| 2178 | 					primitive["mode" ] = 0; | 
| 2179 | 					break; | 
| 2180 | 				} | 
| 2181 | 				case Mesh::PRIMITIVE_LINES: { | 
| 2182 | 					primitive["mode" ] = 1; | 
| 2183 | 					break; | 
| 2184 | 				} | 
| 2185 | 				// case Mesh::PRIMITIVE_LINE_LOOP: { | 
| 2186 | 				// 	primitive["mode"] = 2; | 
| 2187 | 				// 	break; | 
| 2188 | 				// } | 
| 2189 | 				case Mesh::PRIMITIVE_LINE_STRIP: { | 
| 2190 | 					primitive["mode" ] = 3; | 
| 2191 | 					break; | 
| 2192 | 				} | 
| 2193 | 				case Mesh::PRIMITIVE_TRIANGLES: { | 
| 2194 | 					primitive["mode" ] = 4; | 
| 2195 | 					break; | 
| 2196 | 				} | 
| 2197 | 				case Mesh::PRIMITIVE_TRIANGLE_STRIP: { | 
| 2198 | 					primitive["mode" ] = 5; | 
| 2199 | 					break; | 
| 2200 | 				} | 
| 2201 | 				// case Mesh::PRIMITIVE_TRIANGLE_FAN: { | 
| 2202 | 				// 	primitive["mode"] = 6; | 
| 2203 | 				// 	break; | 
| 2204 | 				// } | 
| 2205 | 				default: { | 
| 2206 | 					ERR_FAIL_V(FAILED); | 
| 2207 | 				} | 
| 2208 | 			} | 
| 2209 |  | 
| 2210 | 			Array array = import_mesh->get_surface_arrays(surface_i); | 
| 2211 | 			uint32_t format = import_mesh->get_surface_format(surface_i); | 
| 2212 | 			int32_t vertex_num = 0; | 
| 2213 | 			Dictionary attributes; | 
| 2214 | 			{ | 
| 2215 | 				Vector<Vector3> a = array[Mesh::ARRAY_VERTEX]; | 
| 2216 | 				ERR_FAIL_COND_V(!a.size(), ERR_INVALID_DATA); | 
| 2217 | 				attributes["POSITION" ] = _encode_accessor_as_vec3(p_state, a, true); | 
| 2218 | 				vertex_num = a.size(); | 
| 2219 | 			} | 
| 2220 | 			{ | 
| 2221 | 				Vector<real_t> a = array[Mesh::ARRAY_TANGENT]; | 
| 2222 | 				if (a.size()) { | 
| 2223 | 					const int ret_size = a.size() / 4; | 
| 2224 | 					Vector<Color> attribs; | 
| 2225 | 					attribs.resize(ret_size); | 
| 2226 | 					for (int i = 0; i < ret_size; i++) { | 
| 2227 | 						Color out; | 
| 2228 | 						out.r = a[(i * 4) + 0]; | 
| 2229 | 						out.g = a[(i * 4) + 1]; | 
| 2230 | 						out.b = a[(i * 4) + 2]; | 
| 2231 | 						out.a = a[(i * 4) + 3]; | 
| 2232 | 						attribs.write[i] = out; | 
| 2233 | 					} | 
| 2234 | 					attributes["TANGENT" ] = _encode_accessor_as_color(p_state, attribs, true); | 
| 2235 | 				} | 
| 2236 | 			} | 
| 2237 | 			{ | 
| 2238 | 				Vector<Vector3> a = array[Mesh::ARRAY_NORMAL]; | 
| 2239 | 				if (a.size()) { | 
| 2240 | 					const int ret_size = a.size(); | 
| 2241 | 					Vector<Vector3> attribs; | 
| 2242 | 					attribs.resize(ret_size); | 
| 2243 | 					for (int i = 0; i < ret_size; i++) { | 
| 2244 | 						attribs.write[i] = Vector3(a[i]).normalized(); | 
| 2245 | 					} | 
| 2246 | 					attributes["NORMAL" ] = _encode_accessor_as_vec3(p_state, attribs, true); | 
| 2247 | 				} | 
| 2248 | 			} | 
| 2249 | 			{ | 
| 2250 | 				Vector<Vector2> a = array[Mesh::ARRAY_TEX_UV]; | 
| 2251 | 				if (a.size()) { | 
| 2252 | 					attributes["TEXCOORD_0" ] = _encode_accessor_as_vec2(p_state, a, true); | 
| 2253 | 				} | 
| 2254 | 			} | 
| 2255 | 			{ | 
| 2256 | 				Vector<Vector2> a = array[Mesh::ARRAY_TEX_UV2]; | 
| 2257 | 				if (a.size()) { | 
| 2258 | 					attributes["TEXCOORD_1" ] = _encode_accessor_as_vec2(p_state, a, true); | 
| 2259 | 				} | 
| 2260 | 			} | 
| 2261 | 			for (int custom_i = 0; custom_i < 3; custom_i++) { | 
| 2262 | 				Vector<float> a = array[Mesh::ARRAY_CUSTOM0 + custom_i]; | 
| 2263 | 				if (a.size()) { | 
| 2264 | 					int num_channels = 4; | 
| 2265 | 					int custom_shift = Mesh::ARRAY_FORMAT_CUSTOM0_SHIFT + custom_i * Mesh::ARRAY_FORMAT_CUSTOM_BITS; | 
| 2266 | 					switch ((format >> custom_shift) & Mesh::ARRAY_FORMAT_CUSTOM_MASK) { | 
| 2267 | 						case Mesh::ARRAY_CUSTOM_R_FLOAT: | 
| 2268 | 							num_channels = 1; | 
| 2269 | 							break; | 
| 2270 | 						case Mesh::ARRAY_CUSTOM_RG_FLOAT: | 
| 2271 | 							num_channels = 2; | 
| 2272 | 							break; | 
| 2273 | 						case Mesh::ARRAY_CUSTOM_RGB_FLOAT: | 
| 2274 | 							num_channels = 3; | 
| 2275 | 							break; | 
| 2276 | 						case Mesh::ARRAY_CUSTOM_RGBA_FLOAT: | 
| 2277 | 							num_channels = 4; | 
| 2278 | 							break; | 
| 2279 | 					} | 
| 2280 | 					int texcoord_i = 2 + 2 * custom_i; | 
| 2281 | 					String gltf_texcoord_key; | 
| 2282 | 					for (int prev_texcoord_i = 0; prev_texcoord_i < texcoord_i; prev_texcoord_i++) { | 
| 2283 | 						gltf_texcoord_key = vformat("TEXCOORD_%d" , prev_texcoord_i); | 
| 2284 | 						if (!attributes.has(gltf_texcoord_key)) { | 
| 2285 | 							Vector<Vector2> empty; | 
| 2286 | 							empty.resize(vertex_num); | 
| 2287 | 							attributes[gltf_texcoord_key] = _encode_accessor_as_vec2(p_state, empty, true); | 
| 2288 | 						} | 
| 2289 | 					} | 
| 2290 |  | 
| 2291 | 					LocalVector<Vector2> first_channel; | 
| 2292 | 					first_channel.resize(vertex_num); | 
| 2293 | 					LocalVector<Vector2> second_channel; | 
| 2294 | 					second_channel.resize(vertex_num); | 
| 2295 | 					for (int32_t vert_i = 0; vert_i < vertex_num; vert_i++) { | 
| 2296 | 						float u = a[vert_i * num_channels + 0]; | 
| 2297 | 						float v = (num_channels == 1 ? 0.0f : a[vert_i * num_channels + 1]); | 
| 2298 | 						first_channel[vert_i] = Vector2(u, v); | 
| 2299 | 						u = 0; | 
| 2300 | 						v = 0; | 
| 2301 | 						if (num_channels >= 3) { | 
| 2302 | 							u = a[vert_i * num_channels + 2]; | 
| 2303 | 							v = (num_channels == 3 ? 0.0f : a[vert_i * num_channels + 3]); | 
| 2304 | 							second_channel[vert_i] = Vector2(u, v); | 
| 2305 | 						} | 
| 2306 | 					} | 
| 2307 | 					gltf_texcoord_key = vformat("TEXCOORD_%d" , texcoord_i); | 
| 2308 | 					attributes[gltf_texcoord_key] = _encode_accessor_as_vec2(p_state, first_channel, true); | 
| 2309 | 					gltf_texcoord_key = vformat("TEXCOORD_%d" , texcoord_i + 1); | 
| 2310 | 					attributes[gltf_texcoord_key] = _encode_accessor_as_vec2(p_state, second_channel, true); | 
| 2311 | 				} | 
| 2312 | 			} | 
| 2313 | 			{ | 
| 2314 | 				Vector<Color> a = array[Mesh::ARRAY_COLOR]; | 
| 2315 | 				if (a.size()) { | 
| 2316 | 					attributes["COLOR_0" ] = _encode_accessor_as_color(p_state, a, true); | 
| 2317 | 				} | 
| 2318 | 			} | 
| 2319 | 			HashMap<int, int> joint_i_to_bone_i; | 
| 2320 | 			for (GLTFNodeIndex node_i = 0; node_i < p_state->nodes.size(); node_i++) { | 
| 2321 | 				GLTFSkinIndex skin_i = -1; | 
| 2322 | 				if (p_state->nodes[node_i]->mesh == gltf_mesh_i) { | 
| 2323 | 					skin_i = p_state->nodes[node_i]->skin; | 
| 2324 | 				} | 
| 2325 | 				if (skin_i != -1) { | 
| 2326 | 					joint_i_to_bone_i = p_state->skins[skin_i]->joint_i_to_bone_i; | 
| 2327 | 					break; | 
| 2328 | 				} | 
| 2329 | 			} | 
| 2330 | 			{ | 
| 2331 | 				const Array &a = array[Mesh::ARRAY_BONES]; | 
| 2332 | 				const Vector<Vector3> &vertex_array = array[Mesh::ARRAY_VERTEX]; | 
| 2333 | 				if ((a.size() / JOINT_GROUP_SIZE) == vertex_array.size()) { | 
| 2334 | 					const int ret_size = a.size() / JOINT_GROUP_SIZE; | 
| 2335 | 					Vector<Color> attribs; | 
| 2336 | 					attribs.resize(ret_size); | 
| 2337 | 					{ | 
| 2338 | 						for (int array_i = 0; array_i < attribs.size(); array_i++) { | 
| 2339 | 							int32_t joint_0 = a[(array_i * JOINT_GROUP_SIZE) + 0]; | 
| 2340 | 							int32_t joint_1 = a[(array_i * JOINT_GROUP_SIZE) + 1]; | 
| 2341 | 							int32_t joint_2 = a[(array_i * JOINT_GROUP_SIZE) + 2]; | 
| 2342 | 							int32_t joint_3 = a[(array_i * JOINT_GROUP_SIZE) + 3]; | 
| 2343 | 							attribs.write[array_i] = Color(joint_0, joint_1, joint_2, joint_3); | 
| 2344 | 						} | 
| 2345 | 					} | 
| 2346 | 					attributes["JOINTS_0" ] = _encode_accessor_as_joints(p_state, attribs, true); | 
| 2347 | 				} else if ((a.size() / (JOINT_GROUP_SIZE * 2)) >= vertex_array.size()) { | 
| 2348 | 					Vector<Color> joints_0; | 
| 2349 | 					joints_0.resize(vertex_num); | 
| 2350 | 					Vector<Color> joints_1; | 
| 2351 | 					joints_1.resize(vertex_num); | 
| 2352 | 					int32_t weights_8_count = JOINT_GROUP_SIZE * 2; | 
| 2353 | 					for (int32_t vertex_i = 0; vertex_i < vertex_num; vertex_i++) { | 
| 2354 | 						Color joint_0; | 
| 2355 | 						joint_0.r = a[vertex_i * weights_8_count + 0]; | 
| 2356 | 						joint_0.g = a[vertex_i * weights_8_count + 1]; | 
| 2357 | 						joint_0.b = a[vertex_i * weights_8_count + 2]; | 
| 2358 | 						joint_0.a = a[vertex_i * weights_8_count + 3]; | 
| 2359 | 						joints_0.write[vertex_i] = joint_0; | 
| 2360 | 						Color joint_1; | 
| 2361 | 						joint_1.r = a[vertex_i * weights_8_count + 4]; | 
| 2362 | 						joint_1.g = a[vertex_i * weights_8_count + 5]; | 
| 2363 | 						joint_1.b = a[vertex_i * weights_8_count + 6]; | 
| 2364 | 						joint_1.a = a[vertex_i * weights_8_count + 7]; | 
| 2365 | 						joints_1.write[vertex_i] = joint_1; | 
| 2366 | 					} | 
| 2367 | 					attributes["JOINTS_0" ] = _encode_accessor_as_joints(p_state, joints_0, true); | 
| 2368 | 					attributes["JOINTS_1" ] = _encode_accessor_as_joints(p_state, joints_1, true); | 
| 2369 | 				} | 
| 2370 | 			} | 
| 2371 | 			{ | 
| 2372 | 				const Array &a = array[Mesh::ARRAY_WEIGHTS]; | 
| 2373 | 				const Vector<Vector3> &vertex_array = array[Mesh::ARRAY_VERTEX]; | 
| 2374 | 				if ((a.size() / JOINT_GROUP_SIZE) == vertex_array.size()) { | 
| 2375 | 					int32_t vertex_count = vertex_array.size(); | 
| 2376 | 					Vector<Color> attribs; | 
| 2377 | 					attribs.resize(vertex_count); | 
| 2378 | 					for (int i = 0; i < vertex_count; i++) { | 
| 2379 | 						attribs.write[i] = Color(a[(i * JOINT_GROUP_SIZE) + 0], a[(i * JOINT_GROUP_SIZE) + 1], a[(i * JOINT_GROUP_SIZE) + 2], a[(i * JOINT_GROUP_SIZE) + 3]); | 
| 2380 | 					} | 
| 2381 | 					attributes["WEIGHTS_0" ] = _encode_accessor_as_weights(p_state, attribs, true); | 
| 2382 | 				} else if ((a.size() / (JOINT_GROUP_SIZE * 2)) >= vertex_array.size()) { | 
| 2383 | 					Vector<Color> weights_0; | 
| 2384 | 					weights_0.resize(vertex_num); | 
| 2385 | 					Vector<Color> weights_1; | 
| 2386 | 					weights_1.resize(vertex_num); | 
| 2387 | 					int32_t weights_8_count = JOINT_GROUP_SIZE * 2; | 
| 2388 | 					for (int32_t vertex_i = 0; vertex_i < vertex_num; vertex_i++) { | 
| 2389 | 						Color weight_0; | 
| 2390 | 						weight_0.r = a[vertex_i * weights_8_count + 0]; | 
| 2391 | 						weight_0.g = a[vertex_i * weights_8_count + 1]; | 
| 2392 | 						weight_0.b = a[vertex_i * weights_8_count + 2]; | 
| 2393 | 						weight_0.a = a[vertex_i * weights_8_count + 3]; | 
| 2394 | 						weights_0.write[vertex_i] = weight_0; | 
| 2395 | 						Color weight_1; | 
| 2396 | 						weight_1.r = a[vertex_i * weights_8_count + 4]; | 
| 2397 | 						weight_1.g = a[vertex_i * weights_8_count + 5]; | 
| 2398 | 						weight_1.b = a[vertex_i * weights_8_count + 6]; | 
| 2399 | 						weight_1.a = a[vertex_i * weights_8_count + 7]; | 
| 2400 | 						weights_1.write[vertex_i] = weight_1; | 
| 2401 | 					} | 
| 2402 | 					attributes["WEIGHTS_0" ] = _encode_accessor_as_weights(p_state, weights_0, true); | 
| 2403 | 					attributes["WEIGHTS_1" ] = _encode_accessor_as_weights(p_state, weights_1, true); | 
| 2404 | 				} | 
| 2405 | 			} | 
| 2406 | 			{ | 
| 2407 | 				Vector<int32_t> mesh_indices = array[Mesh::ARRAY_INDEX]; | 
| 2408 | 				if (mesh_indices.size()) { | 
| 2409 | 					if (primitive_type == Mesh::PRIMITIVE_TRIANGLES) { | 
| 2410 | 						//swap around indices, convert ccw to cw for front face | 
| 2411 | 						const int is = mesh_indices.size(); | 
| 2412 | 						for (int k = 0; k < is; k += 3) { | 
| 2413 | 							SWAP(mesh_indices.write[k + 0], mesh_indices.write[k + 2]); | 
| 2414 | 						} | 
| 2415 | 					} | 
| 2416 | 					primitive["indices" ] = _encode_accessor_as_ints(p_state, mesh_indices, true); | 
| 2417 | 				} else { | 
| 2418 | 					if (primitive_type == Mesh::PRIMITIVE_TRIANGLES) { | 
| 2419 | 						//generate indices because they need to be swapped for CW/CCW | 
| 2420 | 						const Vector<Vector3> &vertices = array[Mesh::ARRAY_VERTEX]; | 
| 2421 | 						Ref<SurfaceTool> st; | 
| 2422 | 						st.instantiate(); | 
| 2423 | 						st->create_from_triangle_arrays(array); | 
| 2424 | 						st->index(); | 
| 2425 | 						Vector<int32_t> generated_indices = st->commit_to_arrays()[Mesh::ARRAY_INDEX]; | 
| 2426 | 						const int vs = vertices.size(); | 
| 2427 | 						generated_indices.resize(vs); | 
| 2428 | 						{ | 
| 2429 | 							for (int k = 0; k < vs; k += 3) { | 
| 2430 | 								generated_indices.write[k] = k; | 
| 2431 | 								generated_indices.write[k + 1] = k + 2; | 
| 2432 | 								generated_indices.write[k + 2] = k + 1; | 
| 2433 | 							} | 
| 2434 | 						} | 
| 2435 | 						primitive["indices" ] = _encode_accessor_as_ints(p_state, generated_indices, true); | 
| 2436 | 					} | 
| 2437 | 				} | 
| 2438 | 			} | 
| 2439 |  | 
| 2440 | 			primitive["attributes" ] = attributes; | 
| 2441 |  | 
| 2442 | 			//blend shapes | 
| 2443 | 			print_verbose("glTF: Mesh has targets" ); | 
| 2444 | 			if (import_mesh->get_blend_shape_count()) { | 
| 2445 | 				ArrayMesh::BlendShapeMode shape_mode = import_mesh->get_blend_shape_mode(); | 
| 2446 | 				for (int morph_i = 0; morph_i < import_mesh->get_blend_shape_count(); morph_i++) { | 
| 2447 | 					Array array_morph = import_mesh->get_surface_blend_shape_arrays(surface_i, morph_i); | 
| 2448 | 					Dictionary t; | 
| 2449 | 					Vector<Vector3> varr = array_morph[Mesh::ARRAY_VERTEX]; | 
| 2450 | 					Array mesh_arrays = import_mesh->get_surface_arrays(surface_i); | 
| 2451 | 					if (varr.size()) { | 
| 2452 | 						Vector<Vector3> src_varr = array[Mesh::ARRAY_VERTEX]; | 
| 2453 | 						if (shape_mode == ArrayMesh::BlendShapeMode::BLEND_SHAPE_MODE_NORMALIZED) { | 
| 2454 | 							const int max_idx = src_varr.size(); | 
| 2455 | 							for (int blend_i = 0; blend_i < max_idx; blend_i++) { | 
| 2456 | 								varr.write[blend_i] = Vector3(varr[blend_i]) - src_varr[blend_i]; | 
| 2457 | 							} | 
| 2458 | 						} | 
| 2459 |  | 
| 2460 | 						t["POSITION" ] = _encode_accessor_as_vec3(p_state, varr, true); | 
| 2461 | 					} | 
| 2462 |  | 
| 2463 | 					Vector<Vector3> narr = array_morph[Mesh::ARRAY_NORMAL]; | 
| 2464 | 					if (narr.size()) { | 
| 2465 | 						t["NORMAL" ] = _encode_accessor_as_vec3(p_state, narr, true); | 
| 2466 | 					} | 
| 2467 | 					Vector<real_t> tarr = array_morph[Mesh::ARRAY_TANGENT]; | 
| 2468 | 					if (tarr.size()) { | 
| 2469 | 						const int ret_size = tarr.size() / 4; | 
| 2470 | 						Vector<Vector3> attribs; | 
| 2471 | 						attribs.resize(ret_size); | 
| 2472 | 						for (int i = 0; i < ret_size; i++) { | 
| 2473 | 							Vector3 vec3; | 
| 2474 | 							vec3.x = tarr[(i * 4) + 0]; | 
| 2475 | 							vec3.y = tarr[(i * 4) + 1]; | 
| 2476 | 							vec3.z = tarr[(i * 4) + 2]; | 
| 2477 | 						} | 
| 2478 | 						t["TANGENT" ] = _encode_accessor_as_vec3(p_state, attribs, true); | 
| 2479 | 					} | 
| 2480 | 					targets.push_back(t); | 
| 2481 | 				} | 
| 2482 | 			} | 
| 2483 |  | 
| 2484 | 			Variant v; | 
| 2485 | 			if (surface_i < instance_materials.size()) { | 
| 2486 | 				v = instance_materials.get(surface_i); | 
| 2487 | 			} | 
| 2488 | 			Ref<Material> mat = v; | 
| 2489 | 			if (!mat.is_valid()) { | 
| 2490 | 				mat = import_mesh->get_surface_material(surface_i); | 
| 2491 | 			} | 
| 2492 | 			if (mat.is_valid()) { | 
| 2493 | 				HashMap<Ref<Material>, GLTFMaterialIndex>::Iterator material_cache_i = p_state->material_cache.find(mat); | 
| 2494 | 				if (material_cache_i && material_cache_i->value != -1) { | 
| 2495 | 					primitive["material" ] = material_cache_i->value; | 
| 2496 | 				} else { | 
| 2497 | 					GLTFMaterialIndex mat_i = p_state->materials.size(); | 
| 2498 | 					p_state->materials.push_back(mat); | 
| 2499 | 					primitive["material" ] = mat_i; | 
| 2500 | 					p_state->material_cache.insert(mat, mat_i); | 
| 2501 | 				} | 
| 2502 | 			} | 
| 2503 |  | 
| 2504 | 			if (targets.size()) { | 
| 2505 | 				primitive["targets" ] = targets; | 
| 2506 | 			} | 
| 2507 |  | 
| 2508 | 			primitives.push_back(primitive); | 
| 2509 | 		} | 
| 2510 |  | 
| 2511 | 		Dictionary e; | 
| 2512 | 		e["targetNames" ] = target_names; | 
| 2513 |  | 
| 2514 | 		weights.resize(target_names.size()); | 
| 2515 | 		for (int name_i = 0; name_i < target_names.size(); name_i++) { | 
| 2516 | 			real_t weight = 0.0; | 
| 2517 | 			if (name_i < p_state->meshes.write[gltf_mesh_i]->get_blend_weights().size()) { | 
| 2518 | 				weight = p_state->meshes.write[gltf_mesh_i]->get_blend_weights()[name_i]; | 
| 2519 | 			} | 
| 2520 | 			weights[name_i] = weight; | 
| 2521 | 		} | 
| 2522 | 		if (weights.size()) { | 
| 2523 | 			gltf_mesh["weights" ] = weights; | 
| 2524 | 		} | 
| 2525 |  | 
| 2526 | 		ERR_FAIL_COND_V(target_names.size() != weights.size(), FAILED); | 
| 2527 |  | 
| 2528 | 		gltf_mesh["extras" ] = e; | 
| 2529 |  | 
| 2530 | 		gltf_mesh["primitives" ] = primitives; | 
| 2531 |  | 
| 2532 | 		meshes.push_back(gltf_mesh); | 
| 2533 | 	} | 
| 2534 |  | 
| 2535 | 	if (!meshes.size()) { | 
| 2536 | 		return OK; | 
| 2537 | 	} | 
| 2538 | 	p_state->json["meshes" ] = meshes; | 
| 2539 | 	print_verbose("glTF: Total meshes: "  + itos(meshes.size())); | 
| 2540 |  | 
| 2541 | 	return OK; | 
| 2542 | } | 
| 2543 |  | 
| 2544 | Error GLTFDocument::_parse_meshes(Ref<GLTFState> p_state) { | 
| 2545 | 	if (!p_state->json.has("meshes" )) { | 
| 2546 | 		return OK; | 
| 2547 | 	} | 
| 2548 |  | 
| 2549 | 	Array meshes = p_state->json["meshes" ]; | 
| 2550 | 	for (GLTFMeshIndex i = 0; i < meshes.size(); i++) { | 
| 2551 | 		print_verbose("glTF: Parsing mesh: "  + itos(i)); | 
| 2552 | 		Dictionary d = meshes[i]; | 
| 2553 |  | 
| 2554 | 		Ref<GLTFMesh> mesh; | 
| 2555 | 		mesh.instantiate(); | 
| 2556 | 		bool has_vertex_color = false; | 
| 2557 |  | 
| 2558 | 		ERR_FAIL_COND_V(!d.has("primitives" ), ERR_PARSE_ERROR); | 
| 2559 |  | 
| 2560 | 		Array primitives = d["primitives" ]; | 
| 2561 | 		const Dictionary & = d.has("extras" ) ? (Dictionary)d["extras" ] : Dictionary(); | 
| 2562 | 		Ref<ImporterMesh> import_mesh; | 
| 2563 | 		import_mesh.instantiate(); | 
| 2564 | 		String mesh_name = "mesh" ; | 
| 2565 | 		if (d.has("name" ) && !String(d["name" ]).is_empty()) { | 
| 2566 | 			mesh_name = d["name" ]; | 
| 2567 | 		} | 
| 2568 | 		import_mesh->set_name(_gen_unique_name(p_state, vformat("%s_%s" , p_state->scene_name, mesh_name))); | 
| 2569 |  | 
| 2570 | 		for (int j = 0; j < primitives.size(); j++) { | 
| 2571 | 			uint32_t flags = 0; | 
| 2572 | 			Dictionary p = primitives[j]; | 
| 2573 |  | 
| 2574 | 			Array array; | 
| 2575 | 			array.resize(Mesh::ARRAY_MAX); | 
| 2576 |  | 
| 2577 | 			ERR_FAIL_COND_V(!p.has("attributes" ), ERR_PARSE_ERROR); | 
| 2578 |  | 
| 2579 | 			Dictionary a = p["attributes" ]; | 
| 2580 |  | 
| 2581 | 			Mesh::PrimitiveType primitive = Mesh::PRIMITIVE_TRIANGLES; | 
| 2582 | 			if (p.has("mode" )) { | 
| 2583 | 				const int mode = p["mode" ]; | 
| 2584 | 				ERR_FAIL_INDEX_V(mode, 7, ERR_FILE_CORRUPT); | 
| 2585 | 				// Convert mesh.primitive.mode to Godot Mesh enum. See: | 
| 2586 | 				// https://www.khronos.org/registry/glTF/specs/2.0/glTF-2.0.html#_mesh_primitive_mode | 
| 2587 | 				static const Mesh::PrimitiveType primitives2[7] = { | 
| 2588 | 					Mesh::PRIMITIVE_POINTS, // 0 POINTS | 
| 2589 | 					Mesh::PRIMITIVE_LINES, // 1 LINES | 
| 2590 | 					Mesh::PRIMITIVE_LINES, // 2 LINE_LOOP; loop not supported, should be converted | 
| 2591 | 					Mesh::PRIMITIVE_LINE_STRIP, // 3 LINE_STRIP | 
| 2592 | 					Mesh::PRIMITIVE_TRIANGLES, // 4 TRIANGLES | 
| 2593 | 					Mesh::PRIMITIVE_TRIANGLE_STRIP, // 5 TRIANGLE_STRIP | 
| 2594 | 					Mesh::PRIMITIVE_TRIANGLES, // 6 TRIANGLE_FAN fan not supported, should be converted | 
| 2595 | 					// TODO: Line loop and triangle fan are not supported and need to be converted to lines and triangles. | 
| 2596 | 				}; | 
| 2597 |  | 
| 2598 | 				primitive = primitives2[mode]; | 
| 2599 | 			} | 
| 2600 |  | 
| 2601 | 			ERR_FAIL_COND_V(!a.has("POSITION" ), ERR_PARSE_ERROR); | 
| 2602 | 			int32_t vertex_num = 0; | 
| 2603 | 			if (a.has("POSITION" )) { | 
| 2604 | 				PackedVector3Array vertices = _decode_accessor_as_vec3(p_state, a["POSITION" ], true); | 
| 2605 | 				array[Mesh::ARRAY_VERTEX] = vertices; | 
| 2606 | 				vertex_num = vertices.size(); | 
| 2607 | 			} | 
| 2608 | 			if (a.has("NORMAL" )) { | 
| 2609 | 				array[Mesh::ARRAY_NORMAL] = _decode_accessor_as_vec3(p_state, a["NORMAL" ], true); | 
| 2610 | 			} | 
| 2611 | 			if (a.has("TANGENT" )) { | 
| 2612 | 				array[Mesh::ARRAY_TANGENT] = _decode_accessor_as_floats(p_state, a["TANGENT" ], true); | 
| 2613 | 			} | 
| 2614 | 			if (a.has("TEXCOORD_0" )) { | 
| 2615 | 				array[Mesh::ARRAY_TEX_UV] = _decode_accessor_as_vec2(p_state, a["TEXCOORD_0" ], true); | 
| 2616 | 			} | 
| 2617 | 			if (a.has("TEXCOORD_1" )) { | 
| 2618 | 				array[Mesh::ARRAY_TEX_UV2] = _decode_accessor_as_vec2(p_state, a["TEXCOORD_1" ], true); | 
| 2619 | 			} | 
| 2620 | 			for (int custom_i = 0; custom_i < 3; custom_i++) { | 
| 2621 | 				Vector<float> cur_custom; | 
| 2622 | 				Vector<Vector2> texcoord_first; | 
| 2623 | 				Vector<Vector2> texcoord_second; | 
| 2624 |  | 
| 2625 | 				int texcoord_i = 2 + 2 * custom_i; | 
| 2626 | 				String gltf_texcoord_key = vformat("TEXCOORD_%d" , texcoord_i); | 
| 2627 | 				int num_channels = 0; | 
| 2628 | 				if (a.has(gltf_texcoord_key)) { | 
| 2629 | 					texcoord_first = _decode_accessor_as_vec2(p_state, a[gltf_texcoord_key], true); | 
| 2630 | 					num_channels = 2; | 
| 2631 | 				} | 
| 2632 | 				gltf_texcoord_key = vformat("TEXCOORD_%d" , texcoord_i + 1); | 
| 2633 | 				if (a.has(gltf_texcoord_key)) { | 
| 2634 | 					texcoord_second = _decode_accessor_as_vec2(p_state, a[gltf_texcoord_key], true); | 
| 2635 | 					num_channels = 4; | 
| 2636 | 				} | 
| 2637 | 				if (!num_channels) { | 
| 2638 | 					break; | 
| 2639 | 				} | 
| 2640 | 				if (num_channels == 2 || num_channels == 4) { | 
| 2641 | 					cur_custom.resize(vertex_num * num_channels); | 
| 2642 | 					for (int32_t uv_i = 0; uv_i < texcoord_first.size() && uv_i < vertex_num; uv_i++) { | 
| 2643 | 						cur_custom.write[uv_i * num_channels + 0] = texcoord_first[uv_i].x; | 
| 2644 | 						cur_custom.write[uv_i * num_channels + 1] = texcoord_first[uv_i].y; | 
| 2645 | 					} | 
| 2646 | 					// Vector.resize seems to not zero-initialize. Ensure all unused elements are 0: | 
| 2647 | 					for (int32_t uv_i = texcoord_first.size(); uv_i < vertex_num; uv_i++) { | 
| 2648 | 						cur_custom.write[uv_i * num_channels + 0] = 0; | 
| 2649 | 						cur_custom.write[uv_i * num_channels + 1] = 0; | 
| 2650 | 					} | 
| 2651 | 				} | 
| 2652 | 				if (num_channels == 4) { | 
| 2653 | 					for (int32_t uv_i = 0; uv_i < texcoord_second.size() && uv_i < vertex_num; uv_i++) { | 
| 2654 | 						// num_channels must be 4 | 
| 2655 | 						cur_custom.write[uv_i * num_channels + 2] = texcoord_second[uv_i].x; | 
| 2656 | 						cur_custom.write[uv_i * num_channels + 3] = texcoord_second[uv_i].y; | 
| 2657 | 					} | 
| 2658 | 					// Vector.resize seems to not zero-initialize. Ensure all unused elements are 0: | 
| 2659 | 					for (int32_t uv_i = texcoord_second.size(); uv_i < vertex_num; uv_i++) { | 
| 2660 | 						cur_custom.write[uv_i * num_channels + 2] = 0; | 
| 2661 | 						cur_custom.write[uv_i * num_channels + 3] = 0; | 
| 2662 | 					} | 
| 2663 | 				} | 
| 2664 | 				if (cur_custom.size() > 0) { | 
| 2665 | 					array[Mesh::ARRAY_CUSTOM0 + custom_i] = cur_custom; | 
| 2666 | 					int custom_shift = Mesh::ARRAY_FORMAT_CUSTOM0_SHIFT + custom_i * Mesh::ARRAY_FORMAT_CUSTOM_BITS; | 
| 2667 | 					if (num_channels == 2) { | 
| 2668 | 						flags |= Mesh::ARRAY_CUSTOM_RG_FLOAT << custom_shift; | 
| 2669 | 					} else { | 
| 2670 | 						flags |= Mesh::ARRAY_CUSTOM_RGBA_FLOAT << custom_shift; | 
| 2671 | 					} | 
| 2672 | 				} | 
| 2673 | 			} | 
| 2674 | 			if (a.has("COLOR_0" )) { | 
| 2675 | 				array[Mesh::ARRAY_COLOR] = _decode_accessor_as_color(p_state, a["COLOR_0" ], true); | 
| 2676 | 				has_vertex_color = true; | 
| 2677 | 			} | 
| 2678 | 			if (a.has("JOINTS_0" ) && !a.has("JOINTS_1" )) { | 
| 2679 | 				array[Mesh::ARRAY_BONES] = _decode_accessor_as_ints(p_state, a["JOINTS_0" ], true); | 
| 2680 | 			} else if (a.has("JOINTS_0" ) && a.has("JOINTS_1" )) { | 
| 2681 | 				PackedInt32Array joints_0 = _decode_accessor_as_ints(p_state, a["JOINTS_0" ], true); | 
| 2682 | 				PackedInt32Array joints_1 = _decode_accessor_as_ints(p_state, a["JOINTS_1" ], true); | 
| 2683 | 				ERR_FAIL_COND_V(joints_0.size() != joints_1.size(), ERR_INVALID_DATA); | 
| 2684 | 				int32_t weight_8_count = JOINT_GROUP_SIZE * 2; | 
| 2685 | 				Vector<int> joints; | 
| 2686 | 				joints.resize(vertex_num * weight_8_count); | 
| 2687 | 				for (int32_t vertex_i = 0; vertex_i < vertex_num; vertex_i++) { | 
| 2688 | 					joints.write[vertex_i * weight_8_count + 0] = joints_0[vertex_i * JOINT_GROUP_SIZE + 0]; | 
| 2689 | 					joints.write[vertex_i * weight_8_count + 1] = joints_0[vertex_i * JOINT_GROUP_SIZE + 1]; | 
| 2690 | 					joints.write[vertex_i * weight_8_count + 2] = joints_0[vertex_i * JOINT_GROUP_SIZE + 2]; | 
| 2691 | 					joints.write[vertex_i * weight_8_count + 3] = joints_0[vertex_i * JOINT_GROUP_SIZE + 3]; | 
| 2692 | 					joints.write[vertex_i * weight_8_count + 4] = joints_1[vertex_i * JOINT_GROUP_SIZE + 0]; | 
| 2693 | 					joints.write[vertex_i * weight_8_count + 5] = joints_1[vertex_i * JOINT_GROUP_SIZE + 1]; | 
| 2694 | 					joints.write[vertex_i * weight_8_count + 6] = joints_1[vertex_i * JOINT_GROUP_SIZE + 2]; | 
| 2695 | 					joints.write[vertex_i * weight_8_count + 7] = joints_1[vertex_i * JOINT_GROUP_SIZE + 3]; | 
| 2696 | 				} | 
| 2697 | 				array[Mesh::ARRAY_BONES] = joints; | 
| 2698 | 			} | 
| 2699 | 			if (a.has("WEIGHTS_0" ) && !a.has("WEIGHTS_1" )) { | 
| 2700 | 				Vector<float> weights = _decode_accessor_as_floats(p_state, a["WEIGHTS_0" ], true); | 
| 2701 | 				{ //gltf does not seem to normalize the weights for some reason.. | 
| 2702 | 					int wc = weights.size(); | 
| 2703 | 					float *w = weights.ptrw(); | 
| 2704 |  | 
| 2705 | 					for (int k = 0; k < wc; k += 4) { | 
| 2706 | 						float total = 0.0; | 
| 2707 | 						total += w[k + 0]; | 
| 2708 | 						total += w[k + 1]; | 
| 2709 | 						total += w[k + 2]; | 
| 2710 | 						total += w[k + 3]; | 
| 2711 | 						if (total > 0.0) { | 
| 2712 | 							w[k + 0] /= total; | 
| 2713 | 							w[k + 1] /= total; | 
| 2714 | 							w[k + 2] /= total; | 
| 2715 | 							w[k + 3] /= total; | 
| 2716 | 						} | 
| 2717 | 					} | 
| 2718 | 				} | 
| 2719 | 				array[Mesh::ARRAY_WEIGHTS] = weights; | 
| 2720 | 			} else if (a.has("WEIGHTS_0" ) && a.has("WEIGHTS_1" )) { | 
| 2721 | 				Vector<float> weights_0 = _decode_accessor_as_floats(p_state, a["WEIGHTS_0" ], true); | 
| 2722 | 				Vector<float> weights_1 = _decode_accessor_as_floats(p_state, a["WEIGHTS_1" ], true); | 
| 2723 | 				Vector<float> weights; | 
| 2724 | 				ERR_FAIL_COND_V(weights_0.size() != weights_1.size(), ERR_INVALID_DATA); | 
| 2725 | 				int32_t weight_8_count = JOINT_GROUP_SIZE * 2; | 
| 2726 | 				weights.resize(vertex_num * weight_8_count); | 
| 2727 | 				for (int32_t vertex_i = 0; vertex_i < vertex_num; vertex_i++) { | 
| 2728 | 					weights.write[vertex_i * weight_8_count + 0] = weights_0[vertex_i * JOINT_GROUP_SIZE + 0]; | 
| 2729 | 					weights.write[vertex_i * weight_8_count + 1] = weights_0[vertex_i * JOINT_GROUP_SIZE + 1]; | 
| 2730 | 					weights.write[vertex_i * weight_8_count + 2] = weights_0[vertex_i * JOINT_GROUP_SIZE + 2]; | 
| 2731 | 					weights.write[vertex_i * weight_8_count + 3] = weights_0[vertex_i * JOINT_GROUP_SIZE + 3]; | 
| 2732 | 					weights.write[vertex_i * weight_8_count + 4] = weights_1[vertex_i * JOINT_GROUP_SIZE + 0]; | 
| 2733 | 					weights.write[vertex_i * weight_8_count + 5] = weights_1[vertex_i * JOINT_GROUP_SIZE + 1]; | 
| 2734 | 					weights.write[vertex_i * weight_8_count + 6] = weights_1[vertex_i * JOINT_GROUP_SIZE + 2]; | 
| 2735 | 					weights.write[vertex_i * weight_8_count + 7] = weights_1[vertex_i * JOINT_GROUP_SIZE + 3]; | 
| 2736 | 				} | 
| 2737 | 				{ //gltf does not seem to normalize the weights for some reason.. | 
| 2738 | 					int wc = weights.size(); | 
| 2739 | 					float *w = weights.ptrw(); | 
| 2740 |  | 
| 2741 | 					for (int k = 0; k < wc; k += weight_8_count) { | 
| 2742 | 						float total = 0.0; | 
| 2743 | 						total += w[k + 0]; | 
| 2744 | 						total += w[k + 1]; | 
| 2745 | 						total += w[k + 2]; | 
| 2746 | 						total += w[k + 3]; | 
| 2747 | 						total += w[k + 4]; | 
| 2748 | 						total += w[k + 5]; | 
| 2749 | 						total += w[k + 6]; | 
| 2750 | 						total += w[k + 7]; | 
| 2751 | 						if (total > 0.0) { | 
| 2752 | 							w[k + 0] /= total; | 
| 2753 | 							w[k + 1] /= total; | 
| 2754 | 							w[k + 2] /= total; | 
| 2755 | 							w[k + 3] /= total; | 
| 2756 | 							w[k + 4] /= total; | 
| 2757 | 							w[k + 5] /= total; | 
| 2758 | 							w[k + 6] /= total; | 
| 2759 | 							w[k + 7] /= total; | 
| 2760 | 						} | 
| 2761 | 					} | 
| 2762 | 				} | 
| 2763 | 				array[Mesh::ARRAY_WEIGHTS] = weights; | 
| 2764 | 			} | 
| 2765 |  | 
| 2766 | 			if (p.has("indices" )) { | 
| 2767 | 				Vector<int> indices = _decode_accessor_as_ints(p_state, p["indices" ], false); | 
| 2768 |  | 
| 2769 | 				if (primitive == Mesh::PRIMITIVE_TRIANGLES) { | 
| 2770 | 					//swap around indices, convert ccw to cw for front face | 
| 2771 |  | 
| 2772 | 					const int is = indices.size(); | 
| 2773 | 					int *w = indices.ptrw(); | 
| 2774 | 					for (int k = 0; k < is; k += 3) { | 
| 2775 | 						SWAP(w[k + 1], w[k + 2]); | 
| 2776 | 					} | 
| 2777 | 				} | 
| 2778 | 				array[Mesh::ARRAY_INDEX] = indices; | 
| 2779 |  | 
| 2780 | 			} else if (primitive == Mesh::PRIMITIVE_TRIANGLES) { | 
| 2781 | 				//generate indices because they need to be swapped for CW/CCW | 
| 2782 | 				const Vector<Vector3> &vertices = array[Mesh::ARRAY_VERTEX]; | 
| 2783 | 				ERR_FAIL_COND_V(vertices.size() == 0, ERR_PARSE_ERROR); | 
| 2784 | 				Vector<int> indices; | 
| 2785 | 				const int vs = vertices.size(); | 
| 2786 | 				indices.resize(vs); | 
| 2787 | 				{ | 
| 2788 | 					int *w = indices.ptrw(); | 
| 2789 | 					for (int k = 0; k < vs; k += 3) { | 
| 2790 | 						w[k] = k; | 
| 2791 | 						w[k + 1] = k + 2; | 
| 2792 | 						w[k + 2] = k + 1; | 
| 2793 | 					} | 
| 2794 | 				} | 
| 2795 | 				array[Mesh::ARRAY_INDEX] = indices; | 
| 2796 | 			} | 
| 2797 |  | 
| 2798 | 			bool generate_tangents = (primitive == Mesh::PRIMITIVE_TRIANGLES && !a.has("TANGENT" ) && a.has("TEXCOORD_0" ) && a.has("NORMAL" )); | 
| 2799 |  | 
| 2800 | 			Ref<SurfaceTool> mesh_surface_tool; | 
| 2801 | 			mesh_surface_tool.instantiate(); | 
| 2802 | 			mesh_surface_tool->create_from_triangle_arrays(array); | 
| 2803 | 			if (a.has("JOINTS_0" ) && a.has("JOINTS_1" )) { | 
| 2804 | 				mesh_surface_tool->set_skin_weight_count(SurfaceTool::SKIN_8_WEIGHTS); | 
| 2805 | 			} | 
| 2806 | 			mesh_surface_tool->index(); | 
| 2807 | 			if (generate_tangents) { | 
| 2808 | 				//must generate mikktspace tangents.. ergh.. | 
| 2809 | 				mesh_surface_tool->generate_tangents(); | 
| 2810 | 			} | 
| 2811 | 			array = mesh_surface_tool->commit_to_arrays(); | 
| 2812 |  | 
| 2813 | 			Array morphs; | 
| 2814 | 			//blend shapes | 
| 2815 | 			if (p.has("targets" )) { | 
| 2816 | 				print_verbose("glTF: Mesh has targets" ); | 
| 2817 | 				const Array &targets = p["targets" ]; | 
| 2818 |  | 
| 2819 | 				//ideally BLEND_SHAPE_MODE_RELATIVE since gltf2 stores in displacement | 
| 2820 | 				//but it could require a larger refactor? | 
| 2821 | 				import_mesh->set_blend_shape_mode(Mesh::BLEND_SHAPE_MODE_NORMALIZED); | 
| 2822 |  | 
| 2823 | 				if (j == 0) { | 
| 2824 | 					const Array &target_names = extras.has("targetNames" ) ? (Array)extras["targetNames" ] : Array(); | 
| 2825 | 					for (int k = 0; k < targets.size(); k++) { | 
| 2826 | 						String bs_name; | 
| 2827 | 						if (k < target_names.size() && ((String)target_names[k]).size() != 0) { | 
| 2828 | 							bs_name = (String)target_names[k]; | 
| 2829 | 						} else { | 
| 2830 | 							bs_name = String("morph_" ) + itos(k); | 
| 2831 | 						} | 
| 2832 | 						import_mesh->add_blend_shape(bs_name); | 
| 2833 | 					} | 
| 2834 | 				} | 
| 2835 |  | 
| 2836 | 				for (int k = 0; k < targets.size(); k++) { | 
| 2837 | 					const Dictionary &t = targets[k]; | 
| 2838 |  | 
| 2839 | 					Array array_copy; | 
| 2840 | 					array_copy.resize(Mesh::ARRAY_MAX); | 
| 2841 |  | 
| 2842 | 					for (int l = 0; l < Mesh::ARRAY_MAX; l++) { | 
| 2843 | 						array_copy[l] = array[l]; | 
| 2844 | 					} | 
| 2845 |  | 
| 2846 | 					if (t.has("POSITION" )) { | 
| 2847 | 						Vector<Vector3> varr = _decode_accessor_as_vec3(p_state, t["POSITION" ], true); | 
| 2848 | 						const Vector<Vector3> src_varr = array[Mesh::ARRAY_VERTEX]; | 
| 2849 | 						const int size = src_varr.size(); | 
| 2850 | 						ERR_FAIL_COND_V(size == 0, ERR_PARSE_ERROR); | 
| 2851 | 						{ | 
| 2852 | 							const int max_idx = varr.size(); | 
| 2853 | 							varr.resize(size); | 
| 2854 |  | 
| 2855 | 							Vector3 *w_varr = varr.ptrw(); | 
| 2856 | 							const Vector3 *r_varr = varr.ptr(); | 
| 2857 | 							const Vector3 *r_src_varr = src_varr.ptr(); | 
| 2858 | 							for (int l = 0; l < size; l++) { | 
| 2859 | 								if (l < max_idx) { | 
| 2860 | 									w_varr[l] = r_varr[l] + r_src_varr[l]; | 
| 2861 | 								} else { | 
| 2862 | 									w_varr[l] = r_src_varr[l]; | 
| 2863 | 								} | 
| 2864 | 							} | 
| 2865 | 						} | 
| 2866 | 						array_copy[Mesh::ARRAY_VERTEX] = varr; | 
| 2867 | 					} | 
| 2868 | 					if (t.has("NORMAL" )) { | 
| 2869 | 						Vector<Vector3> narr = _decode_accessor_as_vec3(p_state, t["NORMAL" ], true); | 
| 2870 | 						const Vector<Vector3> src_narr = array[Mesh::ARRAY_NORMAL]; | 
| 2871 | 						int size = src_narr.size(); | 
| 2872 | 						ERR_FAIL_COND_V(size == 0, ERR_PARSE_ERROR); | 
| 2873 | 						{ | 
| 2874 | 							int max_idx = narr.size(); | 
| 2875 | 							narr.resize(size); | 
| 2876 |  | 
| 2877 | 							Vector3 *w_narr = narr.ptrw(); | 
| 2878 | 							const Vector3 *r_narr = narr.ptr(); | 
| 2879 | 							const Vector3 *r_src_narr = src_narr.ptr(); | 
| 2880 | 							for (int l = 0; l < size; l++) { | 
| 2881 | 								if (l < max_idx) { | 
| 2882 | 									w_narr[l] = r_narr[l] + r_src_narr[l]; | 
| 2883 | 								} else { | 
| 2884 | 									w_narr[l] = r_src_narr[l]; | 
| 2885 | 								} | 
| 2886 | 							} | 
| 2887 | 						} | 
| 2888 | 						array_copy[Mesh::ARRAY_NORMAL] = narr; | 
| 2889 | 					} | 
| 2890 | 					if (t.has("TANGENT" )) { | 
| 2891 | 						const Vector<Vector3> tangents_v3 = _decode_accessor_as_vec3(p_state, t["TANGENT" ], true); | 
| 2892 | 						const Vector<float> src_tangents = array[Mesh::ARRAY_TANGENT]; | 
| 2893 | 						ERR_FAIL_COND_V(src_tangents.size() == 0, ERR_PARSE_ERROR); | 
| 2894 |  | 
| 2895 | 						Vector<float> tangents_v4; | 
| 2896 |  | 
| 2897 | 						{ | 
| 2898 | 							int max_idx = tangents_v3.size(); | 
| 2899 |  | 
| 2900 | 							int size4 = src_tangents.size(); | 
| 2901 | 							tangents_v4.resize(size4); | 
| 2902 | 							float *w4 = tangents_v4.ptrw(); | 
| 2903 |  | 
| 2904 | 							const Vector3 *r3 = tangents_v3.ptr(); | 
| 2905 | 							const float *r4 = src_tangents.ptr(); | 
| 2906 |  | 
| 2907 | 							for (int l = 0; l < size4 / 4; l++) { | 
| 2908 | 								if (l < max_idx) { | 
| 2909 | 									w4[l * 4 + 0] = r3[l].x + r4[l * 4 + 0]; | 
| 2910 | 									w4[l * 4 + 1] = r3[l].y + r4[l * 4 + 1]; | 
| 2911 | 									w4[l * 4 + 2] = r3[l].z + r4[l * 4 + 2]; | 
| 2912 | 								} else { | 
| 2913 | 									w4[l * 4 + 0] = r4[l * 4 + 0]; | 
| 2914 | 									w4[l * 4 + 1] = r4[l * 4 + 1]; | 
| 2915 | 									w4[l * 4 + 2] = r4[l * 4 + 2]; | 
| 2916 | 								} | 
| 2917 | 								w4[l * 4 + 3] = r4[l * 4 + 3]; //copy flip value | 
| 2918 | 							} | 
| 2919 | 						} | 
| 2920 |  | 
| 2921 | 						array_copy[Mesh::ARRAY_TANGENT] = tangents_v4; | 
| 2922 | 					} | 
| 2923 |  | 
| 2924 | 					Ref<SurfaceTool> blend_surface_tool; | 
| 2925 | 					blend_surface_tool.instantiate(); | 
| 2926 | 					blend_surface_tool->create_from_triangle_arrays(array_copy); | 
| 2927 | 					if (a.has("JOINTS_0" ) && a.has("JOINTS_1" )) { | 
| 2928 | 						blend_surface_tool->set_skin_weight_count(SurfaceTool::SKIN_8_WEIGHTS); | 
| 2929 | 					} | 
| 2930 | 					blend_surface_tool->index(); | 
| 2931 | 					if (generate_tangents) { | 
| 2932 | 						blend_surface_tool->generate_tangents(); | 
| 2933 | 					} | 
| 2934 | 					array_copy = blend_surface_tool->commit_to_arrays(); | 
| 2935 |  | 
| 2936 | 					// Enforce blend shape mask array format | 
| 2937 | 					for (int l = 0; l < Mesh::ARRAY_MAX; l++) { | 
| 2938 | 						if (!(Mesh::ARRAY_FORMAT_BLEND_SHAPE_MASK & (1 << l))) { | 
| 2939 | 							array_copy[l] = Variant(); | 
| 2940 | 						} | 
| 2941 | 					} | 
| 2942 |  | 
| 2943 | 					morphs.push_back(array_copy); | 
| 2944 | 				} | 
| 2945 | 			} | 
| 2946 |  | 
| 2947 | 			Ref<Material> mat; | 
| 2948 | 			String mat_name; | 
| 2949 | 			if (!p_state->discard_meshes_and_materials) { | 
| 2950 | 				if (p.has("material" )) { | 
| 2951 | 					const int material = p["material" ]; | 
| 2952 | 					ERR_FAIL_INDEX_V(material, p_state->materials.size(), ERR_FILE_CORRUPT); | 
| 2953 | 					Ref<Material> mat3d = p_state->materials[material]; | 
| 2954 | 					ERR_FAIL_NULL_V(mat3d, ERR_FILE_CORRUPT); | 
| 2955 |  | 
| 2956 | 					Ref<BaseMaterial3D> base_material = mat3d; | 
| 2957 | 					if (has_vertex_color && base_material.is_valid()) { | 
| 2958 | 						base_material->set_flag(BaseMaterial3D::FLAG_ALBEDO_FROM_VERTEX_COLOR, true); | 
| 2959 | 					} | 
| 2960 | 					mat = mat3d; | 
| 2961 |  | 
| 2962 | 				} else { | 
| 2963 | 					Ref<StandardMaterial3D> mat3d; | 
| 2964 | 					mat3d.instantiate(); | 
| 2965 | 					if (has_vertex_color) { | 
| 2966 | 						mat3d->set_flag(StandardMaterial3D::FLAG_ALBEDO_FROM_VERTEX_COLOR, true); | 
| 2967 | 					} | 
| 2968 | 					mat = mat3d; | 
| 2969 | 				} | 
| 2970 | 				ERR_FAIL_NULL_V(mat, ERR_FILE_CORRUPT); | 
| 2971 | 				mat_name = mat->get_name(); | 
| 2972 | 			} | 
| 2973 | 			import_mesh->add_surface(primitive, array, morphs, | 
| 2974 | 					Dictionary(), mat, mat_name, flags); | 
| 2975 | 		} | 
| 2976 |  | 
| 2977 | 		Vector<float> blend_weights; | 
| 2978 | 		blend_weights.resize(import_mesh->get_blend_shape_count()); | 
| 2979 | 		for (int32_t weight_i = 0; weight_i < blend_weights.size(); weight_i++) { | 
| 2980 | 			blend_weights.write[weight_i] = 0.0f; | 
| 2981 | 		} | 
| 2982 |  | 
| 2983 | 		if (d.has("weights" )) { | 
| 2984 | 			const Array &weights = d["weights" ]; | 
| 2985 | 			for (int j = 0; j < weights.size(); j++) { | 
| 2986 | 				if (j >= blend_weights.size()) { | 
| 2987 | 					break; | 
| 2988 | 				} | 
| 2989 | 				blend_weights.write[j] = weights[j]; | 
| 2990 | 			} | 
| 2991 | 		} | 
| 2992 | 		mesh->set_blend_weights(blend_weights); | 
| 2993 | 		mesh->set_mesh(import_mesh); | 
| 2994 |  | 
| 2995 | 		p_state->meshes.push_back(mesh); | 
| 2996 | 	} | 
| 2997 |  | 
| 2998 | 	print_verbose("glTF: Total meshes: "  + itos(p_state->meshes.size())); | 
| 2999 |  | 
| 3000 | 	return OK; | 
| 3001 | } | 
| 3002 |  | 
| 3003 | void GLTFDocument::set_image_format(const String &p_image_format) { | 
| 3004 | 	_image_format = p_image_format; | 
| 3005 | } | 
| 3006 |  | 
| 3007 | String GLTFDocument::get_image_format() const { | 
| 3008 | 	return _image_format; | 
| 3009 | } | 
| 3010 |  | 
| 3011 | void GLTFDocument::set_lossy_quality(float p_lossy_quality) { | 
| 3012 | 	_lossy_quality = p_lossy_quality; | 
| 3013 | } | 
| 3014 |  | 
| 3015 | float GLTFDocument::get_lossy_quality() const { | 
| 3016 | 	return _lossy_quality; | 
| 3017 | } | 
| 3018 |  | 
| 3019 | Error GLTFDocument::_serialize_images(Ref<GLTFState> p_state) { | 
| 3020 | 	Array images; | 
| 3021 | 	// Check if any extension wants to be the image saver. | 
| 3022 | 	_image_save_extension = Ref<GLTFDocumentExtension>(); | 
| 3023 | 	for (Ref<GLTFDocumentExtension> ext : document_extensions) { | 
| 3024 | 		ERR_CONTINUE(ext.is_null()); | 
| 3025 | 		Vector<String> image_formats = ext->get_saveable_image_formats(); | 
| 3026 | 		if (image_formats.has(_image_format)) { | 
| 3027 | 			_image_save_extension = ext; | 
| 3028 | 			break; | 
| 3029 | 		} | 
| 3030 | 	} | 
| 3031 | 	// Serialize every image in the state's images array. | 
| 3032 | 	for (int i = 0; i < p_state->images.size(); i++) { | 
| 3033 | 		Dictionary image_dict; | 
| 3034 |  | 
| 3035 | 		ERR_CONTINUE(p_state->images[i].is_null()); | 
| 3036 |  | 
| 3037 | 		Ref<Image> image = p_state->images[i]->get_image(); | 
| 3038 | 		ERR_CONTINUE(image.is_null()); | 
| 3039 | 		if (image->is_compressed()) { | 
| 3040 | 			image->decompress(); | 
| 3041 | 			ERR_FAIL_COND_V_MSG(image->is_compressed(), ERR_INVALID_DATA, "GLTF: Image was compressed, but could not be decompressed." ); | 
| 3042 | 		} | 
| 3043 |  | 
| 3044 | 		if (p_state->filename.to_lower().ends_with("gltf" )) { | 
| 3045 | 			String img_name = p_state->images[i]->get_name(); | 
| 3046 | 			if (img_name.is_empty()) { | 
| 3047 | 				img_name = itos(i); | 
| 3048 | 			} | 
| 3049 | 			img_name = _gen_unique_name(p_state, img_name); | 
| 3050 | 			img_name = img_name.pad_zeros(3); | 
| 3051 | 			String relative_texture_dir = "textures" ; | 
| 3052 | 			String full_texture_dir = p_state->base_path.path_join(relative_texture_dir); | 
| 3053 | 			Ref<DirAccess> da = DirAccess::open(p_state->base_path); | 
| 3054 | 			if (!da->dir_exists(full_texture_dir)) { | 
| 3055 | 				da->make_dir(full_texture_dir); | 
| 3056 | 			} | 
| 3057 | 			if (_image_save_extension.is_valid()) { | 
| 3058 | 				img_name = img_name + _image_save_extension->get_image_file_extension(); | 
| 3059 | 				Error err = _image_save_extension->save_image_at_path(p_state, image, full_texture_dir.path_join(img_name), _image_format, _lossy_quality); | 
| 3060 | 				ERR_FAIL_COND_V_MSG(err != OK, err, "GLTF: Failed to save image in '"  + _image_format + "' format as a separate file." ); | 
| 3061 | 			} else if (_image_format == "PNG" ) { | 
| 3062 | 				img_name = img_name + ".png" ; | 
| 3063 | 				image->save_png(full_texture_dir.path_join(img_name)); | 
| 3064 | 			} else if (_image_format == "JPEG" ) { | 
| 3065 | 				img_name = img_name + ".jpg" ; | 
| 3066 | 				image->save_jpg(full_texture_dir.path_join(img_name), _lossy_quality); | 
| 3067 | 			} else { | 
| 3068 | 				ERR_FAIL_V_MSG(ERR_UNAVAILABLE, "GLTF: Unknown image format '"  + _image_format + "'." ); | 
| 3069 | 			} | 
| 3070 | 			image_dict["uri" ] = relative_texture_dir.path_join(img_name).uri_encode(); | 
| 3071 | 		} else { | 
| 3072 | 			GLTFBufferViewIndex bvi; | 
| 3073 |  | 
| 3074 | 			Ref<GLTFBufferView> bv; | 
| 3075 | 			bv.instantiate(); | 
| 3076 |  | 
| 3077 | 			const GLTFBufferIndex bi = 0; | 
| 3078 | 			bv->buffer = bi; | 
| 3079 | 			bv->byte_offset = p_state->buffers[bi].size(); | 
| 3080 | 			ERR_FAIL_INDEX_V(bi, p_state->buffers.size(), ERR_PARAMETER_RANGE_ERROR); | 
| 3081 |  | 
| 3082 | 			Vector<uint8_t> buffer; | 
| 3083 | 			Ref<ImageTexture> img_tex = image; | 
| 3084 | 			if (img_tex.is_valid()) { | 
| 3085 | 				image = img_tex->get_image(); | 
| 3086 | 			} | 
| 3087 | 			// Save in various image formats. Note that if the format is "None", | 
| 3088 | 			// the state's images will be empty, so this code will not be reached. | 
| 3089 | 			if (_image_save_extension.is_valid()) { | 
| 3090 | 				buffer = _image_save_extension->serialize_image_to_bytes(p_state, image, image_dict, _image_format, _lossy_quality); | 
| 3091 | 			} else if (_image_format == "PNG" ) { | 
| 3092 | 				buffer = image->save_png_to_buffer(); | 
| 3093 | 				image_dict["mimeType" ] = "image/png" ; | 
| 3094 | 			} else if (_image_format == "JPEG" ) { | 
| 3095 | 				buffer = image->save_jpg_to_buffer(_lossy_quality); | 
| 3096 | 				image_dict["mimeType" ] = "image/jpeg" ; | 
| 3097 | 			} else { | 
| 3098 | 				ERR_FAIL_V_MSG(ERR_UNAVAILABLE, "GLTF: Unknown image format '"  + _image_format + "'." ); | 
| 3099 | 			} | 
| 3100 | 			ERR_FAIL_COND_V_MSG(buffer.is_empty(), ERR_INVALID_DATA, "GLTF: Failed to save image in '"  + _image_format + "' format." ); | 
| 3101 |  | 
| 3102 | 			bv->byte_length = buffer.size(); | 
| 3103 | 			p_state->buffers.write[bi].resize(p_state->buffers[bi].size() + bv->byte_length); | 
| 3104 | 			memcpy(&p_state->buffers.write[bi].write[bv->byte_offset], buffer.ptr(), buffer.size()); | 
| 3105 | 			ERR_FAIL_COND_V(bv->byte_offset + bv->byte_length > p_state->buffers[bi].size(), ERR_FILE_CORRUPT); | 
| 3106 |  | 
| 3107 | 			p_state->buffer_views.push_back(bv); | 
| 3108 | 			bvi = p_state->buffer_views.size() - 1; | 
| 3109 | 			image_dict["bufferView" ] = bvi; | 
| 3110 | 		} | 
| 3111 | 		images.push_back(image_dict); | 
| 3112 | 	} | 
| 3113 |  | 
| 3114 | 	print_verbose("Total images: "  + itos(p_state->images.size())); | 
| 3115 |  | 
| 3116 | 	if (!images.size()) { | 
| 3117 | 		return OK; | 
| 3118 | 	} | 
| 3119 | 	p_state->json["images" ] = images; | 
| 3120 |  | 
| 3121 | 	return OK; | 
| 3122 | } | 
| 3123 |  | 
| 3124 | Ref<Image> GLTFDocument::_parse_image_bytes_into_image(Ref<GLTFState> p_state, const Vector<uint8_t> &p_bytes, const String &p_mime_type, int p_index, String &r_file_extension) { | 
| 3125 | 	Ref<Image> r_image; | 
| 3126 | 	r_image.instantiate(); | 
| 3127 | 	// Check if any GLTFDocumentExtensions want to import this data as an image. | 
| 3128 | 	for (Ref<GLTFDocumentExtension> ext : document_extensions) { | 
| 3129 | 		ERR_CONTINUE(ext.is_null()); | 
| 3130 | 		Error err = ext->parse_image_data(p_state, p_bytes, p_mime_type, r_image); | 
| 3131 | 		ERR_CONTINUE_MSG(err != OK, "GLTF: Encountered error "  + itos(err) + " when parsing image "  + itos(p_index) + " in file "  + p_state->filename + ". Continuing." ); | 
| 3132 | 		if (!r_image->is_empty()) { | 
| 3133 | 			r_file_extension = ext->get_image_file_extension(); | 
| 3134 | 			return r_image; | 
| 3135 | 		} | 
| 3136 | 	} | 
| 3137 | 	// If no extension wanted to import this data as an image, try to load a PNG or JPEG. | 
| 3138 | 	// First we honor the mime types if they were defined. | 
| 3139 | 	if (p_mime_type == "image/png" ) { // Load buffer as PNG. | 
| 3140 | 		r_image->load_png_from_buffer(p_bytes); | 
| 3141 | 		r_file_extension = ".png" ; | 
| 3142 | 	} else if (p_mime_type == "image/jpeg" ) { // Loader buffer as JPEG. | 
| 3143 | 		r_image->load_jpg_from_buffer(p_bytes); | 
| 3144 | 		r_file_extension = ".jpg" ; | 
| 3145 | 	} | 
| 3146 | 	// If we didn't pass the above tests, we attempt loading as PNG and then JPEG directly. | 
| 3147 | 	// This covers URIs with base64-encoded data with application/* type but | 
| 3148 | 	// no optional mimeType property, or bufferViews with a bogus mimeType | 
| 3149 | 	// (e.g. `image/jpeg` but the data is actually PNG). | 
| 3150 | 	// That's not *exactly* what the spec mandates but this lets us be | 
| 3151 | 	// lenient with bogus glb files which do exist in production. | 
| 3152 | 	if (r_image->is_empty()) { // Try PNG first. | 
| 3153 | 		r_image->load_png_from_buffer(p_bytes); | 
| 3154 | 	} | 
| 3155 | 	if (r_image->is_empty()) { // And then JPEG. | 
| 3156 | 		r_image->load_jpg_from_buffer(p_bytes); | 
| 3157 | 	} | 
| 3158 | 	// If it still can't be loaded, give up and insert an empty image as placeholder. | 
| 3159 | 	if (r_image->is_empty()) { | 
| 3160 | 		ERR_PRINT(vformat("glTF: Couldn't load image index '%d' with its given mimetype: %s." , p_index, p_mime_type)); | 
| 3161 | 	} | 
| 3162 | 	return r_image; | 
| 3163 | } | 
| 3164 |  | 
| 3165 | void GLTFDocument::_parse_image_save_image(Ref<GLTFState> p_state, const Vector<uint8_t> &p_bytes, const String &p_file_extension, int p_index, Ref<Image> p_image) { | 
| 3166 | 	GLTFState::GLTFHandleBinary handling = GLTFState::GLTFHandleBinary(p_state->handle_binary_image); | 
| 3167 | 	if (p_image->is_empty() || handling == GLTFState::GLTFHandleBinary::HANDLE_BINARY_DISCARD_TEXTURES) { | 
| 3168 | 		p_state->images.push_back(Ref<Texture2D>()); | 
| 3169 | 		p_state->source_images.push_back(Ref<Image>()); | 
| 3170 | 		return; | 
| 3171 | 	} | 
| 3172 | #ifdef TOOLS_ENABLED | 
| 3173 | 	if (Engine::get_singleton()->is_editor_hint() && handling == GLTFState::GLTFHandleBinary::HANDLE_BINARY_EXTRACT_TEXTURES) { | 
| 3174 | 		if (p_state->base_path.is_empty()) { | 
| 3175 | 			p_state->images.push_back(Ref<Texture2D>()); | 
| 3176 | 			p_state->source_images.push_back(Ref<Image>()); | 
| 3177 | 		} else if (p_image->get_name().is_empty()) { | 
| 3178 | 			WARN_PRINT(vformat("glTF: Image index '%d' couldn't be named. Skipping it." , p_index)); | 
| 3179 | 			p_state->images.push_back(Ref<Texture2D>()); | 
| 3180 | 			p_state->source_images.push_back(Ref<Image>()); | 
| 3181 | 		} else { | 
| 3182 | 			bool must_import = true; | 
| 3183 | 			Vector<uint8_t> img_data = p_image->get_data(); | 
| 3184 | 			Dictionary generator_parameters; | 
| 3185 | 			String file_path = p_state->get_base_path() + "/"  + p_state->filename.get_basename() + "_"  + p_image->get_name(); | 
| 3186 | 			file_path += p_file_extension.is_empty() ? ".png"  : p_file_extension; | 
| 3187 | 			if (FileAccess::exists(file_path + ".import" )) { | 
| 3188 | 				Ref<ConfigFile> config; | 
| 3189 | 				config.instantiate(); | 
| 3190 | 				config->load(file_path + ".import" ); | 
| 3191 | 				if (config->has_section_key("remap" , "generator_parameters" )) { | 
| 3192 | 					generator_parameters = (Dictionary)config->get_value("remap" , "generator_parameters" ); | 
| 3193 | 				} | 
| 3194 | 				if (!generator_parameters.has("md5" )) { | 
| 3195 | 					must_import = false; // Didn't come from a gltf document; don't overwrite. | 
| 3196 | 				} | 
| 3197 | 				String existing_md5 = generator_parameters["md5" ]; | 
| 3198 | 				unsigned char md5_hash[16]; | 
| 3199 | 				CryptoCore::md5(img_data.ptr(), img_data.size(), md5_hash); | 
| 3200 | 				String new_md5 = String::hex_encode_buffer(md5_hash, 16); | 
| 3201 | 				generator_parameters["md5" ] = new_md5; | 
| 3202 | 				if (new_md5 == existing_md5) { | 
| 3203 | 					must_import = false; | 
| 3204 | 				} | 
| 3205 | 			} | 
| 3206 | 			if (must_import) { | 
| 3207 | 				Error err = OK; | 
| 3208 | 				if (p_file_extension.is_empty()) { | 
| 3209 | 					// If a file extension was not specified, save the image data to a PNG file. | 
| 3210 | 					err = p_image->save_png(file_path); | 
| 3211 | 					ERR_FAIL_COND(err != OK); | 
| 3212 | 				} else { | 
| 3213 | 					// If a file extension was specified, save the original bytes to a file with that extension. | 
| 3214 | 					Ref<FileAccess> file = FileAccess::open(file_path, FileAccess::WRITE, &err); | 
| 3215 | 					ERR_FAIL_COND(err != OK); | 
| 3216 | 					file->store_buffer(p_bytes); | 
| 3217 | 					file->close(); | 
| 3218 | 				} | 
| 3219 | 				// ResourceLoader::import will crash if not is_editor_hint(), so this case is protected above and will fall through to uncompressed. | 
| 3220 | 				HashMap<StringName, Variant> custom_options; | 
| 3221 | 				custom_options[SNAME("mipmaps/generate" )] = true; | 
| 3222 | 				// Will only use project settings defaults if custom_importer is empty. | 
| 3223 | 				EditorFileSystem::get_singleton()->update_file(file_path); | 
| 3224 | 				EditorFileSystem::get_singleton()->reimport_append(file_path, custom_options, String(), generator_parameters); | 
| 3225 | 			} | 
| 3226 | 			Ref<Texture2D> saved_image = ResourceLoader::load(file_path, "Texture2D" ); | 
| 3227 | 			if (saved_image.is_valid()) { | 
| 3228 | 				p_state->images.push_back(saved_image); | 
| 3229 | 				p_state->source_images.push_back(saved_image->get_image()); | 
| 3230 | 			} else { | 
| 3231 | 				WARN_PRINT(vformat("glTF: Image index '%d' couldn't be loaded with the name: %s. Skipping it." , p_index, p_image->get_name())); | 
| 3232 | 				// Placeholder to keep count. | 
| 3233 | 				p_state->images.push_back(Ref<Texture2D>()); | 
| 3234 | 				p_state->source_images.push_back(Ref<Image>()); | 
| 3235 | 			} | 
| 3236 | 		} | 
| 3237 | 		return; | 
| 3238 | 	} | 
| 3239 | #endif // TOOLS_ENABLED | 
| 3240 | 	if (handling == GLTFState::GLTFHandleBinary::HANDLE_BINARY_EMBED_AS_BASISU) { | 
| 3241 | 		Ref<PortableCompressedTexture2D> tex; | 
| 3242 | 		tex.instantiate(); | 
| 3243 | 		tex->set_name(p_image->get_name()); | 
| 3244 | 		tex->set_keep_compressed_buffer(true); | 
| 3245 | 		tex->create_from_image(p_image, PortableCompressedTexture2D::COMPRESSION_MODE_BASIS_UNIVERSAL); | 
| 3246 | 		p_state->images.push_back(tex); | 
| 3247 | 		p_state->source_images.push_back(p_image); | 
| 3248 | 		return; | 
| 3249 | 	} | 
| 3250 | 	// This handles the case of HANDLE_BINARY_EMBED_AS_UNCOMPRESSED, and it also serves | 
| 3251 | 	// as a fallback for HANDLE_BINARY_EXTRACT_TEXTURES when this is not the editor. | 
| 3252 | 	Ref<ImageTexture> tex; | 
| 3253 | 	tex.instantiate(); | 
| 3254 | 	tex->set_name(p_image->get_name()); | 
| 3255 | 	tex->set_image(p_image); | 
| 3256 | 	p_state->images.push_back(tex); | 
| 3257 | 	p_state->source_images.push_back(p_image); | 
| 3258 | } | 
| 3259 |  | 
| 3260 | Error GLTFDocument::_parse_images(Ref<GLTFState> p_state, const String &p_base_path) { | 
| 3261 | 	ERR_FAIL_NULL_V(p_state, ERR_INVALID_PARAMETER); | 
| 3262 | 	if (!p_state->json.has("images" )) { | 
| 3263 | 		return OK; | 
| 3264 | 	} | 
| 3265 |  | 
| 3266 | 	// Ref: https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/README.md#images | 
| 3267 |  | 
| 3268 | 	const Array &images = p_state->json["images" ]; | 
| 3269 | 	HashSet<String> used_names; | 
| 3270 | 	for (int i = 0; i < images.size(); i++) { | 
| 3271 | 		const Dictionary &dict = images[i]; | 
| 3272 |  | 
| 3273 | 		// glTF 2.0 supports PNG and JPEG types, which can be specified as (from spec): | 
| 3274 | 		// "- a URI to an external file in one of the supported images formats, or | 
| 3275 | 		//  - a URI with embedded base64-encoded data, or | 
| 3276 | 		//  - a reference to a bufferView; in that case mimeType must be defined." | 
| 3277 | 		// Since mimeType is optional for external files and base64 data, we'll have to | 
| 3278 | 		// fall back on letting Godot parse the data to figure out if it's PNG or JPEG. | 
| 3279 |  | 
| 3280 | 		// We'll assume that we use either URI or bufferView, so let's warn the user | 
| 3281 | 		// if their image somehow uses both. And fail if it has neither. | 
| 3282 | 		ERR_CONTINUE_MSG(!dict.has("uri" ) && !dict.has("bufferView" ), "Invalid image definition in glTF file, it should specify an 'uri' or 'bufferView'." ); | 
| 3283 | 		if (dict.has("uri" ) && dict.has("bufferView" )) { | 
| 3284 | 			WARN_PRINT("Invalid image definition in glTF file using both 'uri' and 'bufferView'. 'uri' will take precedence." ); | 
| 3285 | 		} | 
| 3286 |  | 
| 3287 | 		String mime_type; | 
| 3288 | 		if (dict.has("mimeType" )) { // Should be "image/png", "image/jpeg", or something handled by an extension. | 
| 3289 | 			mime_type = dict["mimeType" ]; | 
| 3290 | 		} | 
| 3291 |  | 
| 3292 | 		String image_name; | 
| 3293 | 		if (dict.has("name" )) { | 
| 3294 | 			image_name = dict["name" ]; | 
| 3295 | 			image_name = image_name.get_file().get_basename().validate_filename(); | 
| 3296 | 		} | 
| 3297 | 		if (image_name.is_empty()) { | 
| 3298 | 			image_name = itos(i); | 
| 3299 | 		} | 
| 3300 | 		while (used_names.has(image_name)) { | 
| 3301 | 			image_name += "_"  + itos(i); | 
| 3302 | 		} | 
| 3303 | 		used_names.insert(image_name); | 
| 3304 | 		// Load the image data. If we get a byte array, store here for later. | 
| 3305 | 		Vector<uint8_t> data; | 
| 3306 | 		if (dict.has("uri" )) { | 
| 3307 | 			// Handles the first two bullet points from the spec (embedded data, or external file). | 
| 3308 | 			String uri = dict["uri" ]; | 
| 3309 | 			if (uri.begins_with("data:" )) { // Embedded data using base64. | 
| 3310 | 				data = _parse_base64_uri(uri); | 
| 3311 | 				// mimeType is optional, but if we have it defined in the URI, let's use it. | 
| 3312 | 				if (mime_type.is_empty() && uri.contains(";" )) { | 
| 3313 | 					// Trim "data:" prefix which is 5 characters long, and end at ";base64". | 
| 3314 | 					mime_type = uri.substr(5, uri.find(";base64" ) - 5); | 
| 3315 | 				} | 
| 3316 | 			} else { // Relative path to an external image file. | 
| 3317 | 				ERR_FAIL_COND_V(p_base_path.is_empty(), ERR_INVALID_PARAMETER); | 
| 3318 | 				uri = uri.uri_decode(); | 
| 3319 | 				uri = p_base_path.path_join(uri).replace("\\" , "/" ); // Fix for Windows. | 
| 3320 | 				// ResourceLoader will rely on the file extension to use the relevant loader. | 
| 3321 | 				// The spec says that if mimeType is defined, it should take precedence (e.g. | 
| 3322 | 				// there could be a `.png` image which is actually JPEG), but there's no easy | 
| 3323 | 				// API for that in Godot, so we'd have to load as a buffer (i.e. embedded in | 
| 3324 | 				// the material), so we only do that only as fallback. | 
| 3325 | 				Ref<Texture2D> texture = ResourceLoader::load(uri); | 
| 3326 | 				if (texture.is_valid()) { | 
| 3327 | 					p_state->images.push_back(texture); | 
| 3328 | 					p_state->source_images.push_back(texture->get_image()); | 
| 3329 | 					continue; | 
| 3330 | 				} | 
| 3331 | 				// mimeType is optional, but if we have it in the file extension, let's use it. | 
| 3332 | 				// If the mimeType does not match with the file extension, either it should be | 
| 3333 | 				// specified in the file, or the GLTFDocumentExtension should handle it. | 
| 3334 | 				if (mime_type.is_empty()) { | 
| 3335 | 					mime_type = "image/"  + uri.get_extension(); | 
| 3336 | 				} | 
| 3337 | 				// Fallback to loading as byte array. This enables us to support the | 
| 3338 | 				// spec's requirement that we honor mimetype regardless of file URI. | 
| 3339 | 				data = FileAccess::get_file_as_bytes(uri); | 
| 3340 | 				if (data.size() == 0) { | 
| 3341 | 					WARN_PRINT(vformat("glTF: Image index '%d' couldn't be loaded as a buffer of MIME type '%s' from URI: %s because there was no data to load. Skipping it." , i, mime_type, uri)); | 
| 3342 | 					p_state->images.push_back(Ref<Texture2D>()); // Placeholder to keep count. | 
| 3343 | 					p_state->source_images.push_back(Ref<Image>()); | 
| 3344 | 					continue; | 
| 3345 | 				} | 
| 3346 | 			} | 
| 3347 | 		} else if (dict.has("bufferView" )) { | 
| 3348 | 			// Handles the third bullet point from the spec (bufferView). | 
| 3349 | 			ERR_FAIL_COND_V_MSG(mime_type.is_empty(), ERR_FILE_CORRUPT, vformat("glTF: Image index '%d' specifies 'bufferView' but no 'mimeType', which is invalid." , i)); | 
| 3350 | 			const GLTFBufferViewIndex bvi = dict["bufferView" ]; | 
| 3351 | 			ERR_FAIL_INDEX_V(bvi, p_state->buffer_views.size(), ERR_PARAMETER_RANGE_ERROR); | 
| 3352 | 			Ref<GLTFBufferView> bv = p_state->buffer_views[bvi]; | 
| 3353 | 			const GLTFBufferIndex bi = bv->buffer; | 
| 3354 | 			ERR_FAIL_INDEX_V(bi, p_state->buffers.size(), ERR_PARAMETER_RANGE_ERROR); | 
| 3355 | 			ERR_FAIL_COND_V(bv->byte_offset + bv->byte_length > p_state->buffers[bi].size(), ERR_FILE_CORRUPT); | 
| 3356 | 			const PackedByteArray &buffer = p_state->buffers[bi]; | 
| 3357 | 			data = buffer.slice(bv->byte_offset, bv->byte_offset + bv->byte_length); | 
| 3358 | 		} | 
| 3359 | 		// Done loading the image data bytes. Check that we actually got data to parse. | 
| 3360 | 		// Note: There are paths above that return early, so this point might not be reached. | 
| 3361 | 		if (data.is_empty()) { | 
| 3362 | 			WARN_PRINT(vformat("glTF: Image index '%d' couldn't be loaded, no data found. Skipping it." , i)); | 
| 3363 | 			p_state->images.push_back(Ref<Texture2D>()); // Placeholder to keep count. | 
| 3364 | 			p_state->source_images.push_back(Ref<Image>()); | 
| 3365 | 			continue; | 
| 3366 | 		} | 
| 3367 | 		// Parse the image data from bytes into an Image resource and save if needed. | 
| 3368 | 		String file_extension; | 
| 3369 | 		Ref<Image> img = _parse_image_bytes_into_image(p_state, data, mime_type, i, file_extension); | 
| 3370 | 		img->set_name(image_name); | 
| 3371 | 		_parse_image_save_image(p_state, data, file_extension, i, img); | 
| 3372 | 	} | 
| 3373 |  | 
| 3374 | 	print_verbose("glTF: Total images: "  + itos(p_state->images.size())); | 
| 3375 |  | 
| 3376 | 	return OK; | 
| 3377 | } | 
| 3378 |  | 
| 3379 | Error GLTFDocument::_serialize_textures(Ref<GLTFState> p_state) { | 
| 3380 | 	if (!p_state->textures.size()) { | 
| 3381 | 		return OK; | 
| 3382 | 	} | 
| 3383 |  | 
| 3384 | 	Array textures; | 
| 3385 | 	for (int32_t i = 0; i < p_state->textures.size(); i++) { | 
| 3386 | 		Dictionary texture_dict; | 
| 3387 | 		Ref<GLTFTexture> gltf_texture = p_state->textures[i]; | 
| 3388 | 		if (_image_save_extension.is_valid()) { | 
| 3389 | 			Error err = _image_save_extension->serialize_texture_json(p_state, texture_dict, gltf_texture, _image_format); | 
| 3390 | 			ERR_FAIL_COND_V(err != OK, err); | 
| 3391 | 		} else { | 
| 3392 | 			ERR_CONTINUE(gltf_texture->get_src_image() == -1); | 
| 3393 | 			texture_dict["source" ] = gltf_texture->get_src_image(); | 
| 3394 | 		} | 
| 3395 | 		GLTFTextureSamplerIndex sampler_index = gltf_texture->get_sampler(); | 
| 3396 | 		if (sampler_index != -1) { | 
| 3397 | 			texture_dict["sampler" ] = sampler_index; | 
| 3398 | 		} | 
| 3399 | 		textures.push_back(texture_dict); | 
| 3400 | 	} | 
| 3401 | 	p_state->json["textures" ] = textures; | 
| 3402 |  | 
| 3403 | 	return OK; | 
| 3404 | } | 
| 3405 |  | 
| 3406 | Error GLTFDocument::_parse_textures(Ref<GLTFState> p_state) { | 
| 3407 | 	if (!p_state->json.has("textures" )) { | 
| 3408 | 		return OK; | 
| 3409 | 	} | 
| 3410 |  | 
| 3411 | 	const Array &textures = p_state->json["textures" ]; | 
| 3412 | 	for (GLTFTextureIndex i = 0; i < textures.size(); i++) { | 
| 3413 | 		const Dictionary &texture_dict = textures[i]; | 
| 3414 | 		Ref<GLTFTexture> gltf_texture; | 
| 3415 | 		gltf_texture.instantiate(); | 
| 3416 | 		// Check if any GLTFDocumentExtensions want to handle this texture JSON. | 
| 3417 | 		for (Ref<GLTFDocumentExtension> ext : document_extensions) { | 
| 3418 | 			ERR_CONTINUE(ext.is_null()); | 
| 3419 | 			Error err = ext->parse_texture_json(p_state, texture_dict, gltf_texture); | 
| 3420 | 			ERR_CONTINUE_MSG(err != OK, "GLTF: Encountered error "  + itos(err) + " when parsing texture JSON "  + String(Variant(texture_dict)) + " in file "  + p_state->filename + ". Continuing." ); | 
| 3421 | 			if (gltf_texture->get_src_image() != -1) { | 
| 3422 | 				break; | 
| 3423 | 			} | 
| 3424 | 		} | 
| 3425 | 		if (gltf_texture->get_src_image() == -1) { | 
| 3426 | 			// No extensions handled it, so use the base GLTF source. | 
| 3427 | 			// This may be the fallback, or the only option anyway. | 
| 3428 | 			ERR_FAIL_COND_V(!texture_dict.has("source" ), ERR_PARSE_ERROR); | 
| 3429 | 			gltf_texture->set_src_image(texture_dict["source" ]); | 
| 3430 | 		} | 
| 3431 | 		if (gltf_texture->get_sampler() == -1 && texture_dict.has("sampler" )) { | 
| 3432 | 			gltf_texture->set_sampler(texture_dict["sampler" ]); | 
| 3433 | 		} | 
| 3434 | 		p_state->textures.push_back(gltf_texture); | 
| 3435 | 	} | 
| 3436 |  | 
| 3437 | 	return OK; | 
| 3438 | } | 
| 3439 |  | 
| 3440 | GLTFTextureIndex GLTFDocument::_set_texture(Ref<GLTFState> p_state, Ref<Texture2D> p_texture, StandardMaterial3D::TextureFilter p_filter_mode, bool p_repeats) { | 
| 3441 | 	ERR_FAIL_COND_V(p_texture.is_null(), -1); | 
| 3442 | 	Ref<GLTFTexture> gltf_texture; | 
| 3443 | 	gltf_texture.instantiate(); | 
| 3444 | 	ERR_FAIL_COND_V(p_texture->get_image().is_null(), -1); | 
| 3445 | 	GLTFImageIndex gltf_src_image_i = p_state->images.size(); | 
| 3446 | 	p_state->images.push_back(p_texture); | 
| 3447 | 	p_state->source_images.push_back(p_texture->get_image()); | 
| 3448 | 	gltf_texture->set_src_image(gltf_src_image_i); | 
| 3449 | 	gltf_texture->set_sampler(_set_sampler_for_mode(p_state, p_filter_mode, p_repeats)); | 
| 3450 | 	GLTFTextureIndex gltf_texture_i = p_state->textures.size(); | 
| 3451 | 	p_state->textures.push_back(gltf_texture); | 
| 3452 | 	return gltf_texture_i; | 
| 3453 | } | 
| 3454 |  | 
| 3455 | Ref<Texture2D> GLTFDocument::_get_texture(Ref<GLTFState> p_state, const GLTFTextureIndex p_texture, int p_texture_types) { | 
| 3456 | 	ERR_FAIL_INDEX_V(p_texture, p_state->textures.size(), Ref<Texture2D>()); | 
| 3457 | 	const GLTFImageIndex image = p_state->textures[p_texture]->get_src_image(); | 
| 3458 | 	ERR_FAIL_INDEX_V(image, p_state->images.size(), Ref<Texture2D>()); | 
| 3459 | 	if (GLTFState::GLTFHandleBinary(p_state->handle_binary_image) == GLTFState::GLTFHandleBinary::HANDLE_BINARY_EMBED_AS_BASISU) { | 
| 3460 | 		ERR_FAIL_INDEX_V(image, p_state->source_images.size(), Ref<Texture2D>()); | 
| 3461 | 		Ref<PortableCompressedTexture2D> portable_texture; | 
| 3462 | 		portable_texture.instantiate(); | 
| 3463 | 		portable_texture->set_keep_compressed_buffer(true); | 
| 3464 | 		Ref<Image> new_img = p_state->source_images[image]->duplicate(); | 
| 3465 | 		ERR_FAIL_COND_V(new_img.is_null(), Ref<Texture2D>()); | 
| 3466 | 		new_img->generate_mipmaps(); | 
| 3467 | 		if (p_texture_types) { | 
| 3468 | 			portable_texture->create_from_image(new_img, PortableCompressedTexture2D::COMPRESSION_MODE_BASIS_UNIVERSAL, true); | 
| 3469 | 		} else { | 
| 3470 | 			portable_texture->create_from_image(new_img, PortableCompressedTexture2D::COMPRESSION_MODE_BASIS_UNIVERSAL, false); | 
| 3471 | 		} | 
| 3472 | 		p_state->images.write[image] = portable_texture; | 
| 3473 | 		p_state->source_images.write[image] = new_img; | 
| 3474 | 	} | 
| 3475 | 	return p_state->images[image]; | 
| 3476 | } | 
| 3477 |  | 
| 3478 | GLTFTextureSamplerIndex GLTFDocument::_set_sampler_for_mode(Ref<GLTFState> p_state, StandardMaterial3D::TextureFilter p_filter_mode, bool p_repeats) { | 
| 3479 | 	for (int i = 0; i < p_state->texture_samplers.size(); ++i) { | 
| 3480 | 		if (p_state->texture_samplers[i]->get_filter_mode() == p_filter_mode) { | 
| 3481 | 			return i; | 
| 3482 | 		} | 
| 3483 | 	} | 
| 3484 |  | 
| 3485 | 	GLTFTextureSamplerIndex gltf_sampler_i = p_state->texture_samplers.size(); | 
| 3486 | 	Ref<GLTFTextureSampler> gltf_sampler; | 
| 3487 | 	gltf_sampler.instantiate(); | 
| 3488 | 	gltf_sampler->set_filter_mode(p_filter_mode); | 
| 3489 | 	gltf_sampler->set_wrap_mode(p_repeats); | 
| 3490 | 	p_state->texture_samplers.push_back(gltf_sampler); | 
| 3491 | 	return gltf_sampler_i; | 
| 3492 | } | 
| 3493 |  | 
| 3494 | Ref<GLTFTextureSampler> GLTFDocument::_get_sampler_for_texture(Ref<GLTFState> p_state, const GLTFTextureIndex p_texture) { | 
| 3495 | 	ERR_FAIL_INDEX_V(p_texture, p_state->textures.size(), Ref<Texture2D>()); | 
| 3496 | 	const GLTFTextureSamplerIndex sampler = p_state->textures[p_texture]->get_sampler(); | 
| 3497 |  | 
| 3498 | 	if (sampler == -1) { | 
| 3499 | 		return p_state->default_texture_sampler; | 
| 3500 | 	} else { | 
| 3501 | 		ERR_FAIL_INDEX_V(sampler, p_state->texture_samplers.size(), Ref<GLTFTextureSampler>()); | 
| 3502 |  | 
| 3503 | 		return p_state->texture_samplers[sampler]; | 
| 3504 | 	} | 
| 3505 | } | 
| 3506 |  | 
| 3507 | Error GLTFDocument::_serialize_texture_samplers(Ref<GLTFState> p_state) { | 
| 3508 | 	if (!p_state->texture_samplers.size()) { | 
| 3509 | 		return OK; | 
| 3510 | 	} | 
| 3511 |  | 
| 3512 | 	Array samplers; | 
| 3513 | 	for (int32_t i = 0; i < p_state->texture_samplers.size(); ++i) { | 
| 3514 | 		Dictionary d; | 
| 3515 | 		Ref<GLTFTextureSampler> s = p_state->texture_samplers[i]; | 
| 3516 | 		d["magFilter" ] = s->get_mag_filter(); | 
| 3517 | 		d["minFilter" ] = s->get_min_filter(); | 
| 3518 | 		d["wrapS" ] = s->get_wrap_s(); | 
| 3519 | 		d["wrapT" ] = s->get_wrap_t(); | 
| 3520 | 		samplers.push_back(d); | 
| 3521 | 	} | 
| 3522 | 	p_state->json["samplers" ] = samplers; | 
| 3523 |  | 
| 3524 | 	return OK; | 
| 3525 | } | 
| 3526 |  | 
| 3527 | Error GLTFDocument::_parse_texture_samplers(Ref<GLTFState> p_state) { | 
| 3528 | 	p_state->default_texture_sampler.instantiate(); | 
| 3529 | 	p_state->default_texture_sampler->set_min_filter(GLTFTextureSampler::FilterMode::LINEAR_MIPMAP_LINEAR); | 
| 3530 | 	p_state->default_texture_sampler->set_mag_filter(GLTFTextureSampler::FilterMode::LINEAR); | 
| 3531 | 	p_state->default_texture_sampler->set_wrap_s(GLTFTextureSampler::WrapMode::REPEAT); | 
| 3532 | 	p_state->default_texture_sampler->set_wrap_t(GLTFTextureSampler::WrapMode::REPEAT); | 
| 3533 |  | 
| 3534 | 	if (!p_state->json.has("samplers" )) { | 
| 3535 | 		return OK; | 
| 3536 | 	} | 
| 3537 |  | 
| 3538 | 	const Array &samplers = p_state->json["samplers" ]; | 
| 3539 | 	for (int i = 0; i < samplers.size(); ++i) { | 
| 3540 | 		const Dictionary &d = samplers[i]; | 
| 3541 |  | 
| 3542 | 		Ref<GLTFTextureSampler> sampler; | 
| 3543 | 		sampler.instantiate(); | 
| 3544 |  | 
| 3545 | 		if (d.has("minFilter" )) { | 
| 3546 | 			sampler->set_min_filter(d["minFilter" ]); | 
| 3547 | 		} else { | 
| 3548 | 			sampler->set_min_filter(GLTFTextureSampler::FilterMode::LINEAR_MIPMAP_LINEAR); | 
| 3549 | 		} | 
| 3550 | 		if (d.has("magFilter" )) { | 
| 3551 | 			sampler->set_mag_filter(d["magFilter" ]); | 
| 3552 | 		} else { | 
| 3553 | 			sampler->set_mag_filter(GLTFTextureSampler::FilterMode::LINEAR); | 
| 3554 | 		} | 
| 3555 |  | 
| 3556 | 		if (d.has("wrapS" )) { | 
| 3557 | 			sampler->set_wrap_s(d["wrapS" ]); | 
| 3558 | 		} else { | 
| 3559 | 			sampler->set_wrap_s(GLTFTextureSampler::WrapMode::DEFAULT); | 
| 3560 | 		} | 
| 3561 |  | 
| 3562 | 		if (d.has("wrapT" )) { | 
| 3563 | 			sampler->set_wrap_t(d["wrapT" ]); | 
| 3564 | 		} else { | 
| 3565 | 			sampler->set_wrap_t(GLTFTextureSampler::WrapMode::DEFAULT); | 
| 3566 | 		} | 
| 3567 |  | 
| 3568 | 		p_state->texture_samplers.push_back(sampler); | 
| 3569 | 	} | 
| 3570 |  | 
| 3571 | 	return OK; | 
| 3572 | } | 
| 3573 |  | 
| 3574 | Error GLTFDocument::_serialize_materials(Ref<GLTFState> p_state) { | 
| 3575 | 	Array materials; | 
| 3576 | 	for (int32_t i = 0; i < p_state->materials.size(); i++) { | 
| 3577 | 		Dictionary d; | 
| 3578 | 		Ref<Material> material = p_state->materials[i]; | 
| 3579 | 		if (material.is_null()) { | 
| 3580 | 			materials.push_back(d); | 
| 3581 | 			continue; | 
| 3582 | 		} | 
| 3583 | 		if (!material->get_name().is_empty()) { | 
| 3584 | 			d["name" ] = _gen_unique_name(p_state, material->get_name()); | 
| 3585 | 		} | 
| 3586 |  | 
| 3587 | 		Ref<BaseMaterial3D> base_material = material; | 
| 3588 | 		if (base_material.is_null()) { | 
| 3589 | 			materials.push_back(d); | 
| 3590 | 			continue; | 
| 3591 | 		} | 
| 3592 |  | 
| 3593 | 		Dictionary mr; | 
| 3594 | 		{ | 
| 3595 | 			Array arr; | 
| 3596 | 			const Color c = base_material->get_albedo().srgb_to_linear(); | 
| 3597 | 			arr.push_back(c.r); | 
| 3598 | 			arr.push_back(c.g); | 
| 3599 | 			arr.push_back(c.b); | 
| 3600 | 			arr.push_back(c.a); | 
| 3601 | 			mr["baseColorFactor" ] = arr; | 
| 3602 | 		} | 
| 3603 | 		if (_image_format != "None" ) { | 
| 3604 | 			Dictionary bct; | 
| 3605 | 			Ref<Texture2D> albedo_texture = base_material->get_texture(BaseMaterial3D::TEXTURE_ALBEDO); | 
| 3606 | 			GLTFTextureIndex gltf_texture_index = -1; | 
| 3607 |  | 
| 3608 | 			if (albedo_texture.is_valid() && albedo_texture->get_image().is_valid()) { | 
| 3609 | 				albedo_texture->set_name(material->get_name() + "_albedo" ); | 
| 3610 | 				gltf_texture_index = _set_texture(p_state, albedo_texture, base_material->get_texture_filter(), base_material->get_flag(BaseMaterial3D::FLAG_USE_TEXTURE_REPEAT)); | 
| 3611 | 			} | 
| 3612 | 			if (gltf_texture_index != -1) { | 
| 3613 | 				bct["index" ] = gltf_texture_index; | 
| 3614 | 				Dictionary extensions = _serialize_texture_transform_uv1(material); | 
| 3615 | 				if (!extensions.is_empty()) { | 
| 3616 | 					bct["extensions" ] = extensions; | 
| 3617 | 					p_state->use_khr_texture_transform = true; | 
| 3618 | 				} | 
| 3619 | 				mr["baseColorTexture" ] = bct; | 
| 3620 | 			} | 
| 3621 | 		} | 
| 3622 |  | 
| 3623 | 		mr["metallicFactor" ] = base_material->get_metallic(); | 
| 3624 | 		mr["roughnessFactor" ] = base_material->get_roughness(); | 
| 3625 | 		bool has_roughness = base_material->get_texture(BaseMaterial3D::TEXTURE_ROUGHNESS).is_valid() && base_material->get_texture(BaseMaterial3D::TEXTURE_ROUGHNESS)->get_image().is_valid(); | 
| 3626 | 		bool has_ao = base_material->get_feature(BaseMaterial3D::FEATURE_AMBIENT_OCCLUSION) && base_material->get_texture(BaseMaterial3D::TEXTURE_AMBIENT_OCCLUSION).is_valid(); | 
| 3627 | 		bool has_metalness = base_material->get_texture(BaseMaterial3D::TEXTURE_METALLIC).is_valid() && base_material->get_texture(BaseMaterial3D::TEXTURE_METALLIC)->get_image().is_valid(); | 
| 3628 | 		if (has_ao || has_roughness || has_metalness) { | 
| 3629 | 			Dictionary mrt; | 
| 3630 | 			Ref<Texture2D> roughness_texture = base_material->get_texture(BaseMaterial3D::TEXTURE_ROUGHNESS); | 
| 3631 | 			BaseMaterial3D::TextureChannel roughness_channel = base_material->get_roughness_texture_channel(); | 
| 3632 | 			Ref<Texture2D> metallic_texture = base_material->get_texture(BaseMaterial3D::TEXTURE_METALLIC); | 
| 3633 | 			BaseMaterial3D::TextureChannel metalness_channel = base_material->get_metallic_texture_channel(); | 
| 3634 | 			Ref<Texture2D> ao_texture = base_material->get_texture(BaseMaterial3D::TEXTURE_AMBIENT_OCCLUSION); | 
| 3635 | 			BaseMaterial3D::TextureChannel ao_channel = base_material->get_ao_texture_channel(); | 
| 3636 | 			Ref<ImageTexture> orm_texture; | 
| 3637 | 			orm_texture.instantiate(); | 
| 3638 | 			Ref<Image> orm_image; | 
| 3639 | 			orm_image.instantiate(); | 
| 3640 | 			int32_t height = 0; | 
| 3641 | 			int32_t width = 0; | 
| 3642 | 			Ref<Image> ao_image; | 
| 3643 | 			if (has_ao) { | 
| 3644 | 				height = ao_texture->get_height(); | 
| 3645 | 				width = ao_texture->get_width(); | 
| 3646 | 				ao_image = ao_texture->get_image(); | 
| 3647 | 				Ref<ImageTexture> img_tex = ao_image; | 
| 3648 | 				if (img_tex.is_valid()) { | 
| 3649 | 					ao_image = img_tex->get_image(); | 
| 3650 | 				} | 
| 3651 | 				if (ao_image->is_compressed()) { | 
| 3652 | 					ao_image->decompress(); | 
| 3653 | 				} | 
| 3654 | 			} | 
| 3655 | 			Ref<Image> roughness_image; | 
| 3656 | 			if (has_roughness) { | 
| 3657 | 				height = roughness_texture->get_height(); | 
| 3658 | 				width = roughness_texture->get_width(); | 
| 3659 | 				roughness_image = roughness_texture->get_image(); | 
| 3660 | 				Ref<ImageTexture> img_tex = roughness_image; | 
| 3661 | 				if (img_tex.is_valid()) { | 
| 3662 | 					roughness_image = img_tex->get_image(); | 
| 3663 | 				} | 
| 3664 | 				if (roughness_image->is_compressed()) { | 
| 3665 | 					roughness_image->decompress(); | 
| 3666 | 				} | 
| 3667 | 			} | 
| 3668 | 			Ref<Image> metallness_image; | 
| 3669 | 			if (has_metalness) { | 
| 3670 | 				height = metallic_texture->get_height(); | 
| 3671 | 				width = metallic_texture->get_width(); | 
| 3672 | 				metallness_image = metallic_texture->get_image(); | 
| 3673 | 				Ref<ImageTexture> img_tex = metallness_image; | 
| 3674 | 				if (img_tex.is_valid()) { | 
| 3675 | 					metallness_image = img_tex->get_image(); | 
| 3676 | 				} | 
| 3677 | 				if (metallness_image->is_compressed()) { | 
| 3678 | 					metallness_image->decompress(); | 
| 3679 | 				} | 
| 3680 | 			} | 
| 3681 | 			Ref<Texture2D> albedo_texture = base_material->get_texture(BaseMaterial3D::TEXTURE_ALBEDO); | 
| 3682 | 			if (albedo_texture.is_valid() && albedo_texture->get_image().is_valid()) { | 
| 3683 | 				height = albedo_texture->get_height(); | 
| 3684 | 				width = albedo_texture->get_width(); | 
| 3685 | 			} | 
| 3686 | 			orm_image->initialize_data(width, height, false, Image::FORMAT_RGBA8); | 
| 3687 | 			if (ao_image.is_valid() && ao_image->get_size() != Vector2(width, height)) { | 
| 3688 | 				ao_image->resize(width, height, Image::INTERPOLATE_LANCZOS); | 
| 3689 | 			} | 
| 3690 | 			if (roughness_image.is_valid() && roughness_image->get_size() != Vector2(width, height)) { | 
| 3691 | 				roughness_image->resize(width, height, Image::INTERPOLATE_LANCZOS); | 
| 3692 | 			} | 
| 3693 | 			if (metallness_image.is_valid() && metallness_image->get_size() != Vector2(width, height)) { | 
| 3694 | 				metallness_image->resize(width, height, Image::INTERPOLATE_LANCZOS); | 
| 3695 | 			} | 
| 3696 | 			for (int32_t h = 0; h < height; h++) { | 
| 3697 | 				for (int32_t w = 0; w < width; w++) { | 
| 3698 | 					Color c = Color(1.0f, 1.0f, 1.0f); | 
| 3699 | 					if (has_ao) { | 
| 3700 | 						if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_RED == ao_channel) { | 
| 3701 | 							c.r = ao_image->get_pixel(w, h).r; | 
| 3702 | 						} else if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_GREEN == ao_channel) { | 
| 3703 | 							c.r = ao_image->get_pixel(w, h).g; | 
| 3704 | 						} else if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_BLUE == ao_channel) { | 
| 3705 | 							c.r = ao_image->get_pixel(w, h).b; | 
| 3706 | 						} else if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_ALPHA == ao_channel) { | 
| 3707 | 							c.r = ao_image->get_pixel(w, h).a; | 
| 3708 | 						} | 
| 3709 | 					} | 
| 3710 | 					if (has_roughness) { | 
| 3711 | 						if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_RED == roughness_channel) { | 
| 3712 | 							c.g = roughness_image->get_pixel(w, h).r; | 
| 3713 | 						} else if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_GREEN == roughness_channel) { | 
| 3714 | 							c.g = roughness_image->get_pixel(w, h).g; | 
| 3715 | 						} else if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_BLUE == roughness_channel) { | 
| 3716 | 							c.g = roughness_image->get_pixel(w, h).b; | 
| 3717 | 						} else if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_ALPHA == roughness_channel) { | 
| 3718 | 							c.g = roughness_image->get_pixel(w, h).a; | 
| 3719 | 						} | 
| 3720 | 					} | 
| 3721 | 					if (has_metalness) { | 
| 3722 | 						if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_RED == metalness_channel) { | 
| 3723 | 							c.b = metallness_image->get_pixel(w, h).r; | 
| 3724 | 						} else if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_GREEN == metalness_channel) { | 
| 3725 | 							c.b = metallness_image->get_pixel(w, h).g; | 
| 3726 | 						} else if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_BLUE == metalness_channel) { | 
| 3727 | 							c.b = metallness_image->get_pixel(w, h).b; | 
| 3728 | 						} else if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_ALPHA == metalness_channel) { | 
| 3729 | 							c.b = metallness_image->get_pixel(w, h).a; | 
| 3730 | 						} | 
| 3731 | 					} | 
| 3732 | 					orm_image->set_pixel(w, h, c); | 
| 3733 | 				} | 
| 3734 | 			} | 
| 3735 | 			orm_image->generate_mipmaps(); | 
| 3736 | 			orm_texture->set_image(orm_image); | 
| 3737 | 			GLTFTextureIndex orm_texture_index = -1; | 
| 3738 | 			if (has_ao || has_roughness || has_metalness) { | 
| 3739 | 				orm_texture->set_name(material->get_name() + "_orm" ); | 
| 3740 | 				orm_texture_index = _set_texture(p_state, orm_texture, base_material->get_texture_filter(), base_material->get_flag(BaseMaterial3D::FLAG_USE_TEXTURE_REPEAT)); | 
| 3741 | 			} | 
| 3742 | 			if (has_ao) { | 
| 3743 | 				Dictionary occt; | 
| 3744 | 				occt["index" ] = orm_texture_index; | 
| 3745 | 				d["occlusionTexture" ] = occt; | 
| 3746 | 			} | 
| 3747 | 			if (has_roughness || has_metalness) { | 
| 3748 | 				mrt["index" ] = orm_texture_index; | 
| 3749 | 				Dictionary extensions = _serialize_texture_transform_uv1(material); | 
| 3750 | 				if (!extensions.is_empty()) { | 
| 3751 | 					mrt["extensions" ] = extensions; | 
| 3752 | 					p_state->use_khr_texture_transform = true; | 
| 3753 | 				} | 
| 3754 | 				mr["metallicRoughnessTexture" ] = mrt; | 
| 3755 | 			} | 
| 3756 | 		} | 
| 3757 |  | 
| 3758 | 		d["pbrMetallicRoughness" ] = mr; | 
| 3759 | 		if (base_material->get_feature(BaseMaterial3D::FEATURE_NORMAL_MAPPING)) { | 
| 3760 | 			Dictionary nt; | 
| 3761 | 			Ref<ImageTexture> tex; | 
| 3762 | 			tex.instantiate(); | 
| 3763 | 			{ | 
| 3764 | 				Ref<Texture2D> normal_texture = base_material->get_texture(BaseMaterial3D::TEXTURE_NORMAL); | 
| 3765 | 				if (normal_texture.is_valid()) { | 
| 3766 | 					// Code for uncompressing RG normal maps | 
| 3767 | 					Ref<Image> img = normal_texture->get_image(); | 
| 3768 | 					if (img.is_valid()) { | 
| 3769 | 						Ref<ImageTexture> img_tex = img; | 
| 3770 | 						if (img_tex.is_valid()) { | 
| 3771 | 							img = img_tex->get_image(); | 
| 3772 | 						} | 
| 3773 | 						img->decompress(); | 
| 3774 | 						img->convert(Image::FORMAT_RGBA8); | 
| 3775 | 						img->convert_ra_rgba8_to_rg(); | 
| 3776 | 						for (int32_t y = 0; y < img->get_height(); y++) { | 
| 3777 | 							for (int32_t x = 0; x < img->get_width(); x++) { | 
| 3778 | 								Color c = img->get_pixel(x, y); | 
| 3779 | 								Vector2 red_green = Vector2(c.r, c.g); | 
| 3780 | 								red_green = red_green * Vector2(2.0f, 2.0f) - Vector2(1.0f, 1.0f); | 
| 3781 | 								float blue = 1.0f - red_green.dot(red_green); | 
| 3782 | 								blue = MAX(0.0f, blue); | 
| 3783 | 								c.b = Math::sqrt(blue); | 
| 3784 | 								img->set_pixel(x, y, c); | 
| 3785 | 							} | 
| 3786 | 						} | 
| 3787 | 						tex->set_image(img); | 
| 3788 | 					} | 
| 3789 | 				} | 
| 3790 | 			} | 
| 3791 | 			GLTFTextureIndex gltf_texture_index = -1; | 
| 3792 | 			if (tex.is_valid() && tex->get_image().is_valid()) { | 
| 3793 | 				tex->set_name(material->get_name() + "_normal" ); | 
| 3794 | 				gltf_texture_index = _set_texture(p_state, tex, base_material->get_texture_filter(), base_material->get_flag(BaseMaterial3D::FLAG_USE_TEXTURE_REPEAT)); | 
| 3795 | 			} | 
| 3796 | 			nt["scale" ] = base_material->get_normal_scale(); | 
| 3797 | 			if (gltf_texture_index != -1) { | 
| 3798 | 				nt["index" ] = gltf_texture_index; | 
| 3799 | 				d["normalTexture" ] = nt; | 
| 3800 | 			} | 
| 3801 | 		} | 
| 3802 |  | 
| 3803 | 		if (base_material->get_feature(BaseMaterial3D::FEATURE_EMISSION)) { | 
| 3804 | 			const Color c = base_material->get_emission().linear_to_srgb(); | 
| 3805 | 			Array arr; | 
| 3806 | 			arr.push_back(c.r); | 
| 3807 | 			arr.push_back(c.g); | 
| 3808 | 			arr.push_back(c.b); | 
| 3809 | 			d["emissiveFactor" ] = arr; | 
| 3810 | 		} | 
| 3811 |  | 
| 3812 | 		if (base_material->get_feature(BaseMaterial3D::FEATURE_EMISSION)) { | 
| 3813 | 			Dictionary et; | 
| 3814 | 			Ref<Texture2D> emission_texture = base_material->get_texture(BaseMaterial3D::TEXTURE_EMISSION); | 
| 3815 | 			GLTFTextureIndex gltf_texture_index = -1; | 
| 3816 | 			if (emission_texture.is_valid() && emission_texture->get_image().is_valid()) { | 
| 3817 | 				emission_texture->set_name(material->get_name() + "_emission" ); | 
| 3818 | 				gltf_texture_index = _set_texture(p_state, emission_texture, base_material->get_texture_filter(), base_material->get_flag(BaseMaterial3D::FLAG_USE_TEXTURE_REPEAT)); | 
| 3819 | 			} | 
| 3820 |  | 
| 3821 | 			if (gltf_texture_index != -1) { | 
| 3822 | 				et["index" ] = gltf_texture_index; | 
| 3823 | 				d["emissiveTexture" ] = et; | 
| 3824 | 			} | 
| 3825 | 		} | 
| 3826 |  | 
| 3827 | 		const bool ds = base_material->get_cull_mode() == BaseMaterial3D::CULL_DISABLED; | 
| 3828 | 		if (ds) { | 
| 3829 | 			d["doubleSided" ] = ds; | 
| 3830 | 		} | 
| 3831 |  | 
| 3832 | 		if (base_material->get_transparency() == BaseMaterial3D::TRANSPARENCY_ALPHA_SCISSOR) { | 
| 3833 | 			d["alphaMode" ] = "MASK" ; | 
| 3834 | 			d["alphaCutoff" ] = base_material->get_alpha_scissor_threshold(); | 
| 3835 | 		} else if (base_material->get_transparency() != BaseMaterial3D::TRANSPARENCY_DISABLED) { | 
| 3836 | 			d["alphaMode" ] = "BLEND" ; | 
| 3837 | 		} | 
| 3838 |  | 
| 3839 | 		Dictionary extensions; | 
| 3840 | 		if (base_material->get_shading_mode() == BaseMaterial3D::SHADING_MODE_UNSHADED) { | 
| 3841 | 			Dictionary mat_unlit; | 
| 3842 | 			extensions["KHR_materials_unlit" ] = mat_unlit; | 
| 3843 | 			p_state->add_used_extension("KHR_materials_unlit" ); | 
| 3844 | 		} | 
| 3845 | 		if (base_material->get_feature(BaseMaterial3D::FEATURE_EMISSION) && !Math::is_equal_approx(base_material->get_emission_energy_multiplier(), 1.0f)) { | 
| 3846 | 			Dictionary mat_emissive_strength; | 
| 3847 | 			mat_emissive_strength["emissiveStrength" ] = base_material->get_emission_energy_multiplier(); | 
| 3848 | 			extensions["KHR_materials_emissive_strength" ] = mat_emissive_strength; | 
| 3849 | 			p_state->add_used_extension("KHR_materials_emissive_strength" ); | 
| 3850 | 		} | 
| 3851 | 		d["extensions" ] = extensions; | 
| 3852 |  | 
| 3853 | 		materials.push_back(d); | 
| 3854 | 	} | 
| 3855 | 	if (!materials.size()) { | 
| 3856 | 		return OK; | 
| 3857 | 	} | 
| 3858 | 	p_state->json["materials" ] = materials; | 
| 3859 | 	print_verbose("Total materials: "  + itos(p_state->materials.size())); | 
| 3860 |  | 
| 3861 | 	return OK; | 
| 3862 | } | 
| 3863 |  | 
| 3864 | Error GLTFDocument::_parse_materials(Ref<GLTFState> p_state) { | 
| 3865 | 	if (!p_state->json.has("materials" )) { | 
| 3866 | 		return OK; | 
| 3867 | 	} | 
| 3868 |  | 
| 3869 | 	const Array &materials = p_state->json["materials" ]; | 
| 3870 | 	for (GLTFMaterialIndex i = 0; i < materials.size(); i++) { | 
| 3871 | 		const Dictionary &material_dict = materials[i]; | 
| 3872 |  | 
| 3873 | 		Ref<StandardMaterial3D> material; | 
| 3874 | 		material.instantiate(); | 
| 3875 | 		if (material_dict.has("name" ) && !String(material_dict["name" ]).is_empty()) { | 
| 3876 | 			material->set_name(material_dict["name" ]); | 
| 3877 | 		} else { | 
| 3878 | 			material->set_name(vformat("material_%s" , itos(i))); | 
| 3879 | 		} | 
| 3880 | 		material->set_flag(BaseMaterial3D::FLAG_ALBEDO_FROM_VERTEX_COLOR, true); | 
| 3881 | 		Dictionary material_extensions; | 
| 3882 | 		if (material_dict.has("extensions" )) { | 
| 3883 | 			material_extensions = material_dict["extensions" ]; | 
| 3884 | 		} | 
| 3885 |  | 
| 3886 | 		if (material_extensions.has("KHR_materials_unlit" )) { | 
| 3887 | 			material->set_shading_mode(BaseMaterial3D::SHADING_MODE_UNSHADED); | 
| 3888 | 		} | 
| 3889 |  | 
| 3890 | 		if (material_extensions.has("KHR_materials_emissive_strength" )) { | 
| 3891 | 			Dictionary emissive_strength = material_extensions["KHR_materials_emissive_strength" ]; | 
| 3892 | 			if (emissive_strength.has("emissiveStrength" )) { | 
| 3893 | 				material->set_emission_energy_multiplier(emissive_strength["emissiveStrength" ]); | 
| 3894 | 			} | 
| 3895 | 		} | 
| 3896 |  | 
| 3897 | 		if (material_extensions.has("KHR_materials_pbrSpecularGlossiness" )) { | 
| 3898 | 			WARN_PRINT("Material uses a specular and glossiness workflow. Textures will be converted to roughness and metallic workflow, which may not be 100% accurate." ); | 
| 3899 | 			Dictionary sgm = material_extensions["KHR_materials_pbrSpecularGlossiness" ]; | 
| 3900 |  | 
| 3901 | 			Ref<GLTFSpecGloss> spec_gloss; | 
| 3902 | 			spec_gloss.instantiate(); | 
| 3903 | 			if (sgm.has("diffuseTexture" )) { | 
| 3904 | 				const Dictionary &diffuse_texture_dict = sgm["diffuseTexture" ]; | 
| 3905 | 				if (diffuse_texture_dict.has("index" )) { | 
| 3906 | 					Ref<GLTFTextureSampler> diffuse_sampler = _get_sampler_for_texture(p_state, diffuse_texture_dict["index" ]); | 
| 3907 | 					if (diffuse_sampler.is_valid()) { | 
| 3908 | 						material->set_texture_filter(diffuse_sampler->get_filter_mode()); | 
| 3909 | 						material->set_flag(BaseMaterial3D::FLAG_USE_TEXTURE_REPEAT, diffuse_sampler->get_wrap_mode()); | 
| 3910 | 					} | 
| 3911 | 					Ref<Texture2D> diffuse_texture = _get_texture(p_state, diffuse_texture_dict["index" ], TEXTURE_TYPE_GENERIC); | 
| 3912 | 					if (diffuse_texture.is_valid()) { | 
| 3913 | 						spec_gloss->diffuse_img = diffuse_texture->get_image(); | 
| 3914 | 						material->set_texture(BaseMaterial3D::TEXTURE_ALBEDO, diffuse_texture); | 
| 3915 | 					} | 
| 3916 | 				} | 
| 3917 | 			} | 
| 3918 | 			if (sgm.has("diffuseFactor" )) { | 
| 3919 | 				const Array &arr = sgm["diffuseFactor" ]; | 
| 3920 | 				ERR_FAIL_COND_V(arr.size() != 4, ERR_PARSE_ERROR); | 
| 3921 | 				const Color c = Color(arr[0], arr[1], arr[2], arr[3]).linear_to_srgb(); | 
| 3922 | 				spec_gloss->diffuse_factor = c; | 
| 3923 | 				material->set_albedo(spec_gloss->diffuse_factor); | 
| 3924 | 			} | 
| 3925 |  | 
| 3926 | 			if (sgm.has("specularFactor" )) { | 
| 3927 | 				const Array &arr = sgm["specularFactor" ]; | 
| 3928 | 				ERR_FAIL_COND_V(arr.size() != 3, ERR_PARSE_ERROR); | 
| 3929 | 				spec_gloss->specular_factor = Color(arr[0], arr[1], arr[2]); | 
| 3930 | 			} | 
| 3931 |  | 
| 3932 | 			if (sgm.has("glossinessFactor" )) { | 
| 3933 | 				spec_gloss->gloss_factor = sgm["glossinessFactor" ]; | 
| 3934 | 				material->set_roughness(1.0f - CLAMP(spec_gloss->gloss_factor, 0.0f, 1.0f)); | 
| 3935 | 			} | 
| 3936 | 			if (sgm.has("specularGlossinessTexture" )) { | 
| 3937 | 				const Dictionary &spec_gloss_texture = sgm["specularGlossinessTexture" ]; | 
| 3938 | 				if (spec_gloss_texture.has("index" )) { | 
| 3939 | 					const Ref<Texture2D> orig_texture = _get_texture(p_state, spec_gloss_texture["index" ], TEXTURE_TYPE_GENERIC); | 
| 3940 | 					if (orig_texture.is_valid()) { | 
| 3941 | 						spec_gloss->spec_gloss_img = orig_texture->get_image(); | 
| 3942 | 					} | 
| 3943 | 				} | 
| 3944 | 			} | 
| 3945 | 			spec_gloss_to_rough_metal(spec_gloss, material); | 
| 3946 |  | 
| 3947 | 		} else if (material_dict.has("pbrMetallicRoughness" )) { | 
| 3948 | 			const Dictionary &mr = material_dict["pbrMetallicRoughness" ]; | 
| 3949 | 			if (mr.has("baseColorFactor" )) { | 
| 3950 | 				const Array &arr = mr["baseColorFactor" ]; | 
| 3951 | 				ERR_FAIL_COND_V(arr.size() != 4, ERR_PARSE_ERROR); | 
| 3952 | 				const Color c = Color(arr[0], arr[1], arr[2], arr[3]).linear_to_srgb(); | 
| 3953 | 				material->set_albedo(c); | 
| 3954 | 			} | 
| 3955 |  | 
| 3956 | 			if (mr.has("baseColorTexture" )) { | 
| 3957 | 				const Dictionary &bct = mr["baseColorTexture" ]; | 
| 3958 | 				if (bct.has("index" )) { | 
| 3959 | 					Ref<GLTFTextureSampler> bct_sampler = _get_sampler_for_texture(p_state, bct["index" ]); | 
| 3960 | 					material->set_texture_filter(bct_sampler->get_filter_mode()); | 
| 3961 | 					material->set_flag(BaseMaterial3D::FLAG_USE_TEXTURE_REPEAT, bct_sampler->get_wrap_mode()); | 
| 3962 | 					material->set_texture(BaseMaterial3D::TEXTURE_ALBEDO, _get_texture(p_state, bct["index" ], TEXTURE_TYPE_GENERIC)); | 
| 3963 | 				} | 
| 3964 | 				if (!mr.has("baseColorFactor" )) { | 
| 3965 | 					material->set_albedo(Color(1, 1, 1)); | 
| 3966 | 				} | 
| 3967 | 				_set_texture_transform_uv1(bct, material); | 
| 3968 | 			} | 
| 3969 |  | 
| 3970 | 			if (mr.has("metallicFactor" )) { | 
| 3971 | 				material->set_metallic(mr["metallicFactor" ]); | 
| 3972 | 			} else { | 
| 3973 | 				material->set_metallic(1.0); | 
| 3974 | 			} | 
| 3975 |  | 
| 3976 | 			if (mr.has("roughnessFactor" )) { | 
| 3977 | 				material->set_roughness(mr["roughnessFactor" ]); | 
| 3978 | 			} else { | 
| 3979 | 				material->set_roughness(1.0); | 
| 3980 | 			} | 
| 3981 |  | 
| 3982 | 			if (mr.has("metallicRoughnessTexture" )) { | 
| 3983 | 				const Dictionary &bct = mr["metallicRoughnessTexture" ]; | 
| 3984 | 				if (bct.has("index" )) { | 
| 3985 | 					const Ref<Texture2D> t = _get_texture(p_state, bct["index" ], TEXTURE_TYPE_GENERIC); | 
| 3986 | 					material->set_texture(BaseMaterial3D::TEXTURE_METALLIC, t); | 
| 3987 | 					material->set_metallic_texture_channel(BaseMaterial3D::TEXTURE_CHANNEL_BLUE); | 
| 3988 | 					material->set_texture(BaseMaterial3D::TEXTURE_ROUGHNESS, t); | 
| 3989 | 					material->set_roughness_texture_channel(BaseMaterial3D::TEXTURE_CHANNEL_GREEN); | 
| 3990 | 					if (!mr.has("metallicFactor" )) { | 
| 3991 | 						material->set_metallic(1); | 
| 3992 | 					} | 
| 3993 | 					if (!mr.has("roughnessFactor" )) { | 
| 3994 | 						material->set_roughness(1); | 
| 3995 | 					} | 
| 3996 | 				} | 
| 3997 | 			} | 
| 3998 | 		} | 
| 3999 |  | 
| 4000 | 		if (material_dict.has("normalTexture" )) { | 
| 4001 | 			const Dictionary &bct = material_dict["normalTexture" ]; | 
| 4002 | 			if (bct.has("index" )) { | 
| 4003 | 				material->set_texture(BaseMaterial3D::TEXTURE_NORMAL, _get_texture(p_state, bct["index" ], TEXTURE_TYPE_NORMAL)); | 
| 4004 | 				material->set_feature(BaseMaterial3D::FEATURE_NORMAL_MAPPING, true); | 
| 4005 | 			} | 
| 4006 | 			if (bct.has("scale" )) { | 
| 4007 | 				material->set_normal_scale(bct["scale" ]); | 
| 4008 | 			} | 
| 4009 | 		} | 
| 4010 | 		if (material_dict.has("occlusionTexture" )) { | 
| 4011 | 			const Dictionary &bct = material_dict["occlusionTexture" ]; | 
| 4012 | 			if (bct.has("index" )) { | 
| 4013 | 				material->set_texture(BaseMaterial3D::TEXTURE_AMBIENT_OCCLUSION, _get_texture(p_state, bct["index" ], TEXTURE_TYPE_GENERIC)); | 
| 4014 | 				material->set_ao_texture_channel(BaseMaterial3D::TEXTURE_CHANNEL_RED); | 
| 4015 | 				material->set_feature(BaseMaterial3D::FEATURE_AMBIENT_OCCLUSION, true); | 
| 4016 | 			} | 
| 4017 | 		} | 
| 4018 |  | 
| 4019 | 		if (material_dict.has("emissiveFactor" )) { | 
| 4020 | 			const Array &arr = material_dict["emissiveFactor" ]; | 
| 4021 | 			ERR_FAIL_COND_V(arr.size() != 3, ERR_PARSE_ERROR); | 
| 4022 | 			const Color c = Color(arr[0], arr[1], arr[2]).linear_to_srgb(); | 
| 4023 | 			material->set_feature(BaseMaterial3D::FEATURE_EMISSION, true); | 
| 4024 |  | 
| 4025 | 			material->set_emission(c); | 
| 4026 | 		} | 
| 4027 |  | 
| 4028 | 		if (material_dict.has("emissiveTexture" )) { | 
| 4029 | 			const Dictionary &bct = material_dict["emissiveTexture" ]; | 
| 4030 | 			if (bct.has("index" )) { | 
| 4031 | 				material->set_texture(BaseMaterial3D::TEXTURE_EMISSION, _get_texture(p_state, bct["index" ], TEXTURE_TYPE_GENERIC)); | 
| 4032 | 				material->set_feature(BaseMaterial3D::FEATURE_EMISSION, true); | 
| 4033 | 				material->set_emission(Color(0, 0, 0)); | 
| 4034 | 			} | 
| 4035 | 		} | 
| 4036 |  | 
| 4037 | 		if (material_dict.has("doubleSided" )) { | 
| 4038 | 			const bool ds = material_dict["doubleSided" ]; | 
| 4039 | 			if (ds) { | 
| 4040 | 				material->set_cull_mode(BaseMaterial3D::CULL_DISABLED); | 
| 4041 | 			} | 
| 4042 | 		} | 
| 4043 | 		if (material_dict.has("alphaMode" )) { | 
| 4044 | 			const String &am = material_dict["alphaMode" ]; | 
| 4045 | 			if (am == "BLEND" ) { | 
| 4046 | 				material->set_transparency(BaseMaterial3D::TRANSPARENCY_ALPHA_DEPTH_PRE_PASS); | 
| 4047 | 			} else if (am == "MASK" ) { | 
| 4048 | 				material->set_transparency(BaseMaterial3D::TRANSPARENCY_ALPHA_SCISSOR); | 
| 4049 | 				if (material_dict.has("alphaCutoff" )) { | 
| 4050 | 					material->set_alpha_scissor_threshold(material_dict["alphaCutoff" ]); | 
| 4051 | 				} else { | 
| 4052 | 					material->set_alpha_scissor_threshold(0.5f); | 
| 4053 | 				} | 
| 4054 | 			} | 
| 4055 | 		} | 
| 4056 | 		p_state->materials.push_back(material); | 
| 4057 | 	} | 
| 4058 |  | 
| 4059 | 	print_verbose("Total materials: "  + itos(p_state->materials.size())); | 
| 4060 |  | 
| 4061 | 	return OK; | 
| 4062 | } | 
| 4063 |  | 
| 4064 | void GLTFDocument::_set_texture_transform_uv1(const Dictionary &p_dict, Ref<BaseMaterial3D> p_material) { | 
| 4065 | 	if (p_dict.has("extensions" )) { | 
| 4066 | 		const Dictionary &extensions = p_dict["extensions" ]; | 
| 4067 | 		if (extensions.has("KHR_texture_transform" )) { | 
| 4068 | 			if (p_material.is_valid()) { | 
| 4069 | 				const Dictionary &texture_transform = extensions["KHR_texture_transform" ]; | 
| 4070 | 				const Array &offset_arr = texture_transform["offset" ]; | 
| 4071 | 				if (offset_arr.size() == 2) { | 
| 4072 | 					const Vector3 offset_vector3 = Vector3(offset_arr[0], offset_arr[1], 0.0f); | 
| 4073 | 					p_material->set_uv1_offset(offset_vector3); | 
| 4074 | 				} | 
| 4075 |  | 
| 4076 | 				const Array &scale_arr = texture_transform["scale" ]; | 
| 4077 | 				if (scale_arr.size() == 2) { | 
| 4078 | 					const Vector3 scale_vector3 = Vector3(scale_arr[0], scale_arr[1], 1.0f); | 
| 4079 | 					p_material->set_uv1_scale(scale_vector3); | 
| 4080 | 				} | 
| 4081 | 			} | 
| 4082 | 		} | 
| 4083 | 	} | 
| 4084 | } | 
| 4085 |  | 
| 4086 | void GLTFDocument::spec_gloss_to_rough_metal(Ref<GLTFSpecGloss> r_spec_gloss, Ref<BaseMaterial3D> p_material) { | 
| 4087 | 	if (r_spec_gloss.is_null()) { | 
| 4088 | 		return; | 
| 4089 | 	} | 
| 4090 | 	if (r_spec_gloss->spec_gloss_img.is_null()) { | 
| 4091 | 		return; | 
| 4092 | 	} | 
| 4093 | 	if (r_spec_gloss->diffuse_img.is_null()) { | 
| 4094 | 		return; | 
| 4095 | 	} | 
| 4096 | 	if (p_material.is_null()) { | 
| 4097 | 		return; | 
| 4098 | 	} | 
| 4099 | 	bool has_roughness = false; | 
| 4100 | 	bool has_metal = false; | 
| 4101 | 	p_material->set_roughness(1.0f); | 
| 4102 | 	p_material->set_metallic(1.0f); | 
| 4103 | 	Ref<Image> rm_img = Image::create_empty(r_spec_gloss->spec_gloss_img->get_width(), r_spec_gloss->spec_gloss_img->get_height(), false, Image::FORMAT_RGBA8); | 
| 4104 | 	r_spec_gloss->spec_gloss_img->decompress(); | 
| 4105 | 	if (r_spec_gloss->diffuse_img.is_valid()) { | 
| 4106 | 		r_spec_gloss->diffuse_img->decompress(); | 
| 4107 | 		r_spec_gloss->diffuse_img->resize(r_spec_gloss->spec_gloss_img->get_width(), r_spec_gloss->spec_gloss_img->get_height(), Image::INTERPOLATE_LANCZOS); | 
| 4108 | 		r_spec_gloss->spec_gloss_img->resize(r_spec_gloss->diffuse_img->get_width(), r_spec_gloss->diffuse_img->get_height(), Image::INTERPOLATE_LANCZOS); | 
| 4109 | 	} | 
| 4110 | 	for (int32_t y = 0; y < r_spec_gloss->spec_gloss_img->get_height(); y++) { | 
| 4111 | 		for (int32_t x = 0; x < r_spec_gloss->spec_gloss_img->get_width(); x++) { | 
| 4112 | 			const Color specular_pixel = r_spec_gloss->spec_gloss_img->get_pixel(x, y).srgb_to_linear(); | 
| 4113 | 			Color specular = Color(specular_pixel.r, specular_pixel.g, specular_pixel.b); | 
| 4114 | 			specular *= r_spec_gloss->specular_factor; | 
| 4115 | 			Color diffuse = Color(1.0f, 1.0f, 1.0f); | 
| 4116 | 			diffuse *= r_spec_gloss->diffuse_img->get_pixel(x, y).srgb_to_linear(); | 
| 4117 | 			float metallic = 0.0f; | 
| 4118 | 			Color base_color; | 
| 4119 | 			spec_gloss_to_metal_base_color(specular, diffuse, base_color, metallic); | 
| 4120 | 			Color mr = Color(1.0f, 1.0f, 1.0f); | 
| 4121 | 			mr.g = specular_pixel.a; | 
| 4122 | 			mr.b = metallic; | 
| 4123 | 			if (!Math::is_equal_approx(mr.g, 1.0f)) { | 
| 4124 | 				has_roughness = true; | 
| 4125 | 			} | 
| 4126 | 			if (!Math::is_zero_approx(mr.b)) { | 
| 4127 | 				has_metal = true; | 
| 4128 | 			} | 
| 4129 | 			mr.g *= r_spec_gloss->gloss_factor; | 
| 4130 | 			mr.g = 1.0f - mr.g; | 
| 4131 | 			rm_img->set_pixel(x, y, mr); | 
| 4132 | 			if (r_spec_gloss->diffuse_img.is_valid()) { | 
| 4133 | 				r_spec_gloss->diffuse_img->set_pixel(x, y, base_color.linear_to_srgb()); | 
| 4134 | 			} | 
| 4135 | 		} | 
| 4136 | 	} | 
| 4137 | 	rm_img->generate_mipmaps(); | 
| 4138 | 	r_spec_gloss->diffuse_img->generate_mipmaps(); | 
| 4139 | 	p_material->set_texture(BaseMaterial3D::TEXTURE_ALBEDO, ImageTexture::create_from_image(r_spec_gloss->diffuse_img)); | 
| 4140 | 	Ref<ImageTexture> rm_image_texture = ImageTexture::create_from_image(rm_img); | 
| 4141 | 	if (has_roughness) { | 
| 4142 | 		p_material->set_texture(BaseMaterial3D::TEXTURE_ROUGHNESS, rm_image_texture); | 
| 4143 | 		p_material->set_roughness_texture_channel(BaseMaterial3D::TEXTURE_CHANNEL_GREEN); | 
| 4144 | 	} | 
| 4145 |  | 
| 4146 | 	if (has_metal) { | 
| 4147 | 		p_material->set_texture(BaseMaterial3D::TEXTURE_METALLIC, rm_image_texture); | 
| 4148 | 		p_material->set_metallic_texture_channel(BaseMaterial3D::TEXTURE_CHANNEL_BLUE); | 
| 4149 | 	} | 
| 4150 | } | 
| 4151 |  | 
| 4152 | void GLTFDocument::spec_gloss_to_metal_base_color(const Color &p_specular_factor, const Color &p_diffuse, Color &r_base_color, float &r_metallic) { | 
| 4153 | 	const Color DIELECTRIC_SPECULAR = Color(0.04f, 0.04f, 0.04f); | 
| 4154 | 	Color specular = Color(p_specular_factor.r, p_specular_factor.g, p_specular_factor.b); | 
| 4155 | 	const float one_minus_specular_strength = 1.0f - get_max_component(specular); | 
| 4156 | 	const float dielectric_specular_red = DIELECTRIC_SPECULAR.r; | 
| 4157 | 	float brightness_diffuse = get_perceived_brightness(p_diffuse); | 
| 4158 | 	const float brightness_specular = get_perceived_brightness(specular); | 
| 4159 | 	r_metallic = solve_metallic(dielectric_specular_red, brightness_diffuse, brightness_specular, one_minus_specular_strength); | 
| 4160 | 	const float one_minus_metallic = 1.0f - r_metallic; | 
| 4161 | 	const Color base_color_from_diffuse = p_diffuse * (one_minus_specular_strength / (1.0f - dielectric_specular_red) / MAX(one_minus_metallic, CMP_EPSILON)); | 
| 4162 | 	const Color base_color_from_specular = (specular - (DIELECTRIC_SPECULAR * (one_minus_metallic))) * (1.0f / MAX(r_metallic, CMP_EPSILON)); | 
| 4163 | 	r_base_color.r = Math::lerp(base_color_from_diffuse.r, base_color_from_specular.r, r_metallic * r_metallic); | 
| 4164 | 	r_base_color.g = Math::lerp(base_color_from_diffuse.g, base_color_from_specular.g, r_metallic * r_metallic); | 
| 4165 | 	r_base_color.b = Math::lerp(base_color_from_diffuse.b, base_color_from_specular.b, r_metallic * r_metallic); | 
| 4166 | 	r_base_color.a = p_diffuse.a; | 
| 4167 | 	r_base_color = r_base_color.clamp(); | 
| 4168 | } | 
| 4169 |  | 
| 4170 | GLTFNodeIndex GLTFDocument::_find_highest_node(Ref<GLTFState> p_state, const Vector<GLTFNodeIndex> &p_subset) { | 
| 4171 | 	int highest = -1; | 
| 4172 | 	GLTFNodeIndex best_node = -1; | 
| 4173 |  | 
| 4174 | 	for (int i = 0; i < p_subset.size(); ++i) { | 
| 4175 | 		const GLTFNodeIndex node_i = p_subset[i]; | 
| 4176 | 		const Ref<GLTFNode> node = p_state->nodes[node_i]; | 
| 4177 |  | 
| 4178 | 		if (highest == -1 || node->height < highest) { | 
| 4179 | 			highest = node->height; | 
| 4180 | 			best_node = node_i; | 
| 4181 | 		} | 
| 4182 | 	} | 
| 4183 |  | 
| 4184 | 	return best_node; | 
| 4185 | } | 
| 4186 |  | 
| 4187 | bool GLTFDocument::_capture_nodes_in_skin(Ref<GLTFState> p_state, Ref<GLTFSkin> p_skin, const GLTFNodeIndex p_node_index) { | 
| 4188 | 	bool found_joint = false; | 
| 4189 |  | 
| 4190 | 	for (int i = 0; i < p_state->nodes[p_node_index]->children.size(); ++i) { | 
| 4191 | 		found_joint |= _capture_nodes_in_skin(p_state, p_skin, p_state->nodes[p_node_index]->children[i]); | 
| 4192 | 	} | 
| 4193 |  | 
| 4194 | 	if (found_joint) { | 
| 4195 | 		// Mark it if we happen to find another skins joint... | 
| 4196 | 		if (p_state->nodes[p_node_index]->joint && p_skin->joints.find(p_node_index) < 0) { | 
| 4197 | 			p_skin->joints.push_back(p_node_index); | 
| 4198 | 		} else if (p_skin->non_joints.find(p_node_index) < 0) { | 
| 4199 | 			p_skin->non_joints.push_back(p_node_index); | 
| 4200 | 		} | 
| 4201 | 	} | 
| 4202 |  | 
| 4203 | 	if (p_skin->joints.find(p_node_index) > 0) { | 
| 4204 | 		return true; | 
| 4205 | 	} | 
| 4206 |  | 
| 4207 | 	return false; | 
| 4208 | } | 
| 4209 |  | 
| 4210 | void GLTFDocument::_capture_nodes_for_multirooted_skin(Ref<GLTFState> p_state, Ref<GLTFSkin> p_skin) { | 
| 4211 | 	DisjointSet<GLTFNodeIndex> disjoint_set; | 
| 4212 |  | 
| 4213 | 	for (int i = 0; i < p_skin->joints.size(); ++i) { | 
| 4214 | 		const GLTFNodeIndex node_index = p_skin->joints[i]; | 
| 4215 | 		const GLTFNodeIndex parent = p_state->nodes[node_index]->parent; | 
| 4216 | 		disjoint_set.insert(node_index); | 
| 4217 |  | 
| 4218 | 		if (p_skin->joints.find(parent) >= 0) { | 
| 4219 | 			disjoint_set.create_union(parent, node_index); | 
| 4220 | 		} | 
| 4221 | 	} | 
| 4222 |  | 
| 4223 | 	Vector<GLTFNodeIndex> roots; | 
| 4224 | 	disjoint_set.get_representatives(roots); | 
| 4225 |  | 
| 4226 | 	if (roots.size() <= 1) { | 
| 4227 | 		return; | 
| 4228 | 	} | 
| 4229 |  | 
| 4230 | 	int maxHeight = -1; | 
| 4231 |  | 
| 4232 | 	// Determine the max height rooted tree | 
| 4233 | 	for (int i = 0; i < roots.size(); ++i) { | 
| 4234 | 		const GLTFNodeIndex root = roots[i]; | 
| 4235 |  | 
| 4236 | 		if (maxHeight == -1 || p_state->nodes[root]->height < maxHeight) { | 
| 4237 | 			maxHeight = p_state->nodes[root]->height; | 
| 4238 | 		} | 
| 4239 | 	} | 
| 4240 |  | 
| 4241 | 	// Go up the tree till all of the multiple roots of the skin are at the same hierarchy level. | 
| 4242 | 	// This sucks, but 99% of all game engines (not just Godot) would have this same issue. | 
| 4243 | 	for (int i = 0; i < roots.size(); ++i) { | 
| 4244 | 		GLTFNodeIndex current_node = roots[i]; | 
| 4245 | 		while (p_state->nodes[current_node]->height > maxHeight) { | 
| 4246 | 			GLTFNodeIndex parent = p_state->nodes[current_node]->parent; | 
| 4247 |  | 
| 4248 | 			if (p_state->nodes[parent]->joint && p_skin->joints.find(parent) < 0) { | 
| 4249 | 				p_skin->joints.push_back(parent); | 
| 4250 | 			} else if (p_skin->non_joints.find(parent) < 0) { | 
| 4251 | 				p_skin->non_joints.push_back(parent); | 
| 4252 | 			} | 
| 4253 |  | 
| 4254 | 			current_node = parent; | 
| 4255 | 		} | 
| 4256 |  | 
| 4257 | 		// replace the roots | 
| 4258 | 		roots.write[i] = current_node; | 
| 4259 | 	} | 
| 4260 |  | 
| 4261 | 	// Climb up the tree until they all have the same parent | 
| 4262 | 	bool all_same; | 
| 4263 |  | 
| 4264 | 	do { | 
| 4265 | 		all_same = true; | 
| 4266 | 		const GLTFNodeIndex first_parent = p_state->nodes[roots[0]]->parent; | 
| 4267 |  | 
| 4268 | 		for (int i = 1; i < roots.size(); ++i) { | 
| 4269 | 			all_same &= (first_parent == p_state->nodes[roots[i]]->parent); | 
| 4270 | 		} | 
| 4271 |  | 
| 4272 | 		if (!all_same) { | 
| 4273 | 			for (int i = 0; i < roots.size(); ++i) { | 
| 4274 | 				const GLTFNodeIndex current_node = roots[i]; | 
| 4275 | 				const GLTFNodeIndex parent = p_state->nodes[current_node]->parent; | 
| 4276 |  | 
| 4277 | 				if (p_state->nodes[parent]->joint && p_skin->joints.find(parent) < 0) { | 
| 4278 | 					p_skin->joints.push_back(parent); | 
| 4279 | 				} else if (p_skin->non_joints.find(parent) < 0) { | 
| 4280 | 					p_skin->non_joints.push_back(parent); | 
| 4281 | 				} | 
| 4282 |  | 
| 4283 | 				roots.write[i] = parent; | 
| 4284 | 			} | 
| 4285 | 		} | 
| 4286 |  | 
| 4287 | 	} while (!all_same); | 
| 4288 | } | 
| 4289 |  | 
| 4290 | Error GLTFDocument::_expand_skin(Ref<GLTFState> p_state, Ref<GLTFSkin> p_skin) { | 
| 4291 | 	_capture_nodes_for_multirooted_skin(p_state, p_skin); | 
| 4292 |  | 
| 4293 | 	// Grab all nodes that lay in between skin joints/nodes | 
| 4294 | 	DisjointSet<GLTFNodeIndex> disjoint_set; | 
| 4295 |  | 
| 4296 | 	Vector<GLTFNodeIndex> all_skin_nodes; | 
| 4297 | 	all_skin_nodes.append_array(p_skin->joints); | 
| 4298 | 	all_skin_nodes.append_array(p_skin->non_joints); | 
| 4299 |  | 
| 4300 | 	for (int i = 0; i < all_skin_nodes.size(); ++i) { | 
| 4301 | 		const GLTFNodeIndex node_index = all_skin_nodes[i]; | 
| 4302 | 		const GLTFNodeIndex parent = p_state->nodes[node_index]->parent; | 
| 4303 | 		disjoint_set.insert(node_index); | 
| 4304 |  | 
| 4305 | 		if (all_skin_nodes.find(parent) >= 0) { | 
| 4306 | 			disjoint_set.create_union(parent, node_index); | 
| 4307 | 		} | 
| 4308 | 	} | 
| 4309 |  | 
| 4310 | 	Vector<GLTFNodeIndex> out_owners; | 
| 4311 | 	disjoint_set.get_representatives(out_owners); | 
| 4312 |  | 
| 4313 | 	Vector<GLTFNodeIndex> out_roots; | 
| 4314 |  | 
| 4315 | 	for (int i = 0; i < out_owners.size(); ++i) { | 
| 4316 | 		Vector<GLTFNodeIndex> set; | 
| 4317 | 		disjoint_set.get_members(set, out_owners[i]); | 
| 4318 |  | 
| 4319 | 		const GLTFNodeIndex root = _find_highest_node(p_state, set); | 
| 4320 | 		ERR_FAIL_COND_V(root < 0, FAILED); | 
| 4321 | 		out_roots.push_back(root); | 
| 4322 | 	} | 
| 4323 |  | 
| 4324 | 	out_roots.sort(); | 
| 4325 |  | 
| 4326 | 	for (int i = 0; i < out_roots.size(); ++i) { | 
| 4327 | 		_capture_nodes_in_skin(p_state, p_skin, out_roots[i]); | 
| 4328 | 	} | 
| 4329 |  | 
| 4330 | 	p_skin->roots = out_roots; | 
| 4331 |  | 
| 4332 | 	return OK; | 
| 4333 | } | 
| 4334 |  | 
| 4335 | Error GLTFDocument::_verify_skin(Ref<GLTFState> p_state, Ref<GLTFSkin> p_skin) { | 
| 4336 | 	// This may seem duplicated from expand_skins, but this is really a sanity check! (so it kinda is) | 
| 4337 | 	// In case additional interpolating logic is added to the skins, this will help ensure that you | 
| 4338 | 	// do not cause it to self implode into a fiery blaze | 
| 4339 |  | 
| 4340 | 	// We are going to re-calculate the root nodes and compare them to the ones saved in the skin, | 
| 4341 | 	// then ensure the multiple trees (if they exist) are on the same sublevel | 
| 4342 |  | 
| 4343 | 	// Grab all nodes that lay in between skin joints/nodes | 
| 4344 | 	DisjointSet<GLTFNodeIndex> disjoint_set; | 
| 4345 |  | 
| 4346 | 	Vector<GLTFNodeIndex> all_skin_nodes; | 
| 4347 | 	all_skin_nodes.append_array(p_skin->joints); | 
| 4348 | 	all_skin_nodes.append_array(p_skin->non_joints); | 
| 4349 |  | 
| 4350 | 	for (int i = 0; i < all_skin_nodes.size(); ++i) { | 
| 4351 | 		const GLTFNodeIndex node_index = all_skin_nodes[i]; | 
| 4352 | 		const GLTFNodeIndex parent = p_state->nodes[node_index]->parent; | 
| 4353 | 		disjoint_set.insert(node_index); | 
| 4354 |  | 
| 4355 | 		if (all_skin_nodes.find(parent) >= 0) { | 
| 4356 | 			disjoint_set.create_union(parent, node_index); | 
| 4357 | 		} | 
| 4358 | 	} | 
| 4359 |  | 
| 4360 | 	Vector<GLTFNodeIndex> out_owners; | 
| 4361 | 	disjoint_set.get_representatives(out_owners); | 
| 4362 |  | 
| 4363 | 	Vector<GLTFNodeIndex> out_roots; | 
| 4364 |  | 
| 4365 | 	for (int i = 0; i < out_owners.size(); ++i) { | 
| 4366 | 		Vector<GLTFNodeIndex> set; | 
| 4367 | 		disjoint_set.get_members(set, out_owners[i]); | 
| 4368 |  | 
| 4369 | 		const GLTFNodeIndex root = _find_highest_node(p_state, set); | 
| 4370 | 		ERR_FAIL_COND_V(root < 0, FAILED); | 
| 4371 | 		out_roots.push_back(root); | 
| 4372 | 	} | 
| 4373 |  | 
| 4374 | 	out_roots.sort(); | 
| 4375 |  | 
| 4376 | 	ERR_FAIL_COND_V(out_roots.size() == 0, FAILED); | 
| 4377 |  | 
| 4378 | 	// Make sure the roots are the exact same (they better be) | 
| 4379 | 	ERR_FAIL_COND_V(out_roots.size() != p_skin->roots.size(), FAILED); | 
| 4380 | 	for (int i = 0; i < out_roots.size(); ++i) { | 
| 4381 | 		ERR_FAIL_COND_V(out_roots[i] != p_skin->roots[i], FAILED); | 
| 4382 | 	} | 
| 4383 |  | 
| 4384 | 	// Single rooted skin? Perfectly ok! | 
| 4385 | 	if (out_roots.size() == 1) { | 
| 4386 | 		return OK; | 
| 4387 | 	} | 
| 4388 |  | 
| 4389 | 	// Make sure all parents of a multi-rooted skin are the SAME | 
| 4390 | 	const GLTFNodeIndex parent = p_state->nodes[out_roots[0]]->parent; | 
| 4391 | 	for (int i = 1; i < out_roots.size(); ++i) { | 
| 4392 | 		if (p_state->nodes[out_roots[i]]->parent != parent) { | 
| 4393 | 			return FAILED; | 
| 4394 | 		} | 
| 4395 | 	} | 
| 4396 |  | 
| 4397 | 	return OK; | 
| 4398 | } | 
| 4399 |  | 
| 4400 | Error GLTFDocument::_parse_skins(Ref<GLTFState> p_state) { | 
| 4401 | 	if (!p_state->json.has("skins" )) { | 
| 4402 | 		return OK; | 
| 4403 | 	} | 
| 4404 |  | 
| 4405 | 	const Array &skins = p_state->json["skins" ]; | 
| 4406 |  | 
| 4407 | 	// Create the base skins, and mark nodes that are joints | 
| 4408 | 	for (int i = 0; i < skins.size(); i++) { | 
| 4409 | 		const Dictionary &d = skins[i]; | 
| 4410 |  | 
| 4411 | 		Ref<GLTFSkin> skin; | 
| 4412 | 		skin.instantiate(); | 
| 4413 |  | 
| 4414 | 		ERR_FAIL_COND_V(!d.has("joints" ), ERR_PARSE_ERROR); | 
| 4415 |  | 
| 4416 | 		const Array &joints = d["joints" ]; | 
| 4417 |  | 
| 4418 | 		if (d.has("inverseBindMatrices" )) { | 
| 4419 | 			skin->inverse_binds = _decode_accessor_as_xform(p_state, d["inverseBindMatrices" ], false); | 
| 4420 | 			ERR_FAIL_COND_V(skin->inverse_binds.size() != joints.size(), ERR_PARSE_ERROR); | 
| 4421 | 		} | 
| 4422 |  | 
| 4423 | 		for (int j = 0; j < joints.size(); j++) { | 
| 4424 | 			const GLTFNodeIndex node = joints[j]; | 
| 4425 | 			ERR_FAIL_INDEX_V(node, p_state->nodes.size(), ERR_PARSE_ERROR); | 
| 4426 |  | 
| 4427 | 			skin->joints.push_back(node); | 
| 4428 | 			skin->joints_original.push_back(node); | 
| 4429 |  | 
| 4430 | 			p_state->nodes.write[node]->joint = true; | 
| 4431 | 		} | 
| 4432 |  | 
| 4433 | 		if (d.has("name" ) && !String(d["name" ]).is_empty()) { | 
| 4434 | 			skin->set_name(d["name" ]); | 
| 4435 | 		} else { | 
| 4436 | 			skin->set_name(vformat("skin_%s" , itos(i))); | 
| 4437 | 		} | 
| 4438 |  | 
| 4439 | 		if (d.has("skeleton" )) { | 
| 4440 | 			skin->skin_root = d["skeleton" ]; | 
| 4441 | 		} | 
| 4442 |  | 
| 4443 | 		p_state->skins.push_back(skin); | 
| 4444 | 	} | 
| 4445 |  | 
| 4446 | 	for (GLTFSkinIndex i = 0; i < p_state->skins.size(); ++i) { | 
| 4447 | 		Ref<GLTFSkin> skin = p_state->skins.write[i]; | 
| 4448 |  | 
| 4449 | 		// Expand the skin to capture all the extra non-joints that lie in between the actual joints, | 
| 4450 | 		// and expand the hierarchy to ensure multi-rooted trees lie on the same height level | 
| 4451 | 		ERR_FAIL_COND_V(_expand_skin(p_state, skin), ERR_PARSE_ERROR); | 
| 4452 | 		ERR_FAIL_COND_V(_verify_skin(p_state, skin), ERR_PARSE_ERROR); | 
| 4453 | 	} | 
| 4454 |  | 
| 4455 | 	print_verbose("glTF: Total skins: "  + itos(p_state->skins.size())); | 
| 4456 |  | 
| 4457 | 	return OK; | 
| 4458 | } | 
| 4459 |  | 
| 4460 | void GLTFDocument::_recurse_children(Ref<GLTFState> p_state, const GLTFNodeIndex p_node_index, | 
| 4461 | 		RBSet<GLTFNodeIndex> &p_all_skin_nodes, HashSet<GLTFNodeIndex> &p_child_visited_set) { | 
| 4462 | 	if (p_child_visited_set.has(p_node_index)) { | 
| 4463 | 		return; | 
| 4464 | 	} | 
| 4465 | 	p_child_visited_set.insert(p_node_index); | 
| 4466 | 	for (int i = 0; i < p_state->nodes[p_node_index]->children.size(); ++i) { | 
| 4467 | 		_recurse_children(p_state, p_state->nodes[p_node_index]->children[i], p_all_skin_nodes, p_child_visited_set); | 
| 4468 | 	} | 
| 4469 |  | 
| 4470 | 	if (p_state->nodes[p_node_index]->skin < 0 || p_state->nodes[p_node_index]->mesh < 0 || !p_state->nodes[p_node_index]->children.is_empty()) { | 
| 4471 | 		p_all_skin_nodes.insert(p_node_index); | 
| 4472 | 	} | 
| 4473 | } | 
| 4474 |  | 
| 4475 | Error GLTFDocument::_determine_skeletons(Ref<GLTFState> p_state) { | 
| 4476 | 	// Using a disjoint set, we are going to potentially combine all skins that are actually branches | 
| 4477 | 	// of a main skeleton, or treat skins defining the same set of nodes as ONE skeleton. | 
| 4478 | 	// This is another unclear issue caused by the current glTF specification. | 
| 4479 |  | 
| 4480 | 	DisjointSet<GLTFNodeIndex> skeleton_sets; | 
| 4481 |  | 
| 4482 | 	for (GLTFSkinIndex skin_i = 0; skin_i < p_state->skins.size(); ++skin_i) { | 
| 4483 | 		const Ref<GLTFSkin> skin = p_state->skins[skin_i]; | 
| 4484 |  | 
| 4485 | 		HashSet<GLTFNodeIndex> child_visited_set; | 
| 4486 | 		RBSet<GLTFNodeIndex> all_skin_nodes; | 
| 4487 | 		for (int i = 0; i < skin->joints.size(); ++i) { | 
| 4488 | 			all_skin_nodes.insert(skin->joints[i]); | 
| 4489 | 			_recurse_children(p_state, skin->joints[i], all_skin_nodes, child_visited_set); | 
| 4490 | 		} | 
| 4491 | 		for (int i = 0; i < skin->non_joints.size(); ++i) { | 
| 4492 | 			all_skin_nodes.insert(skin->non_joints[i]); | 
| 4493 | 			_recurse_children(p_state, skin->non_joints[i], all_skin_nodes, child_visited_set); | 
| 4494 | 		} | 
| 4495 | 		for (GLTFNodeIndex node_index : all_skin_nodes) { | 
| 4496 | 			const GLTFNodeIndex parent = p_state->nodes[node_index]->parent; | 
| 4497 | 			skeleton_sets.insert(node_index); | 
| 4498 |  | 
| 4499 | 			if (all_skin_nodes.has(parent)) { | 
| 4500 | 				skeleton_sets.create_union(parent, node_index); | 
| 4501 | 			} | 
| 4502 | 		} | 
| 4503 |  | 
| 4504 | 		// We are going to connect the separate skin subtrees in each skin together | 
| 4505 | 		// so that the final roots are entire sets of valid skin trees | 
| 4506 | 		for (int i = 1; i < skin->roots.size(); ++i) { | 
| 4507 | 			skeleton_sets.create_union(skin->roots[0], skin->roots[i]); | 
| 4508 | 		} | 
| 4509 | 	} | 
| 4510 |  | 
| 4511 | 	{ // attempt to joint all touching subsets (siblings/parent are part of another skin) | 
| 4512 | 		Vector<GLTFNodeIndex> groups_representatives; | 
| 4513 | 		skeleton_sets.get_representatives(groups_representatives); | 
| 4514 |  | 
| 4515 | 		Vector<GLTFNodeIndex> highest_group_members; | 
| 4516 | 		Vector<Vector<GLTFNodeIndex>> groups; | 
| 4517 | 		for (int i = 0; i < groups_representatives.size(); ++i) { | 
| 4518 | 			Vector<GLTFNodeIndex> group; | 
| 4519 | 			skeleton_sets.get_members(group, groups_representatives[i]); | 
| 4520 | 			highest_group_members.push_back(_find_highest_node(p_state, group)); | 
| 4521 | 			groups.push_back(group); | 
| 4522 | 		} | 
| 4523 |  | 
| 4524 | 		for (int i = 0; i < highest_group_members.size(); ++i) { | 
| 4525 | 			const GLTFNodeIndex node_i = highest_group_members[i]; | 
| 4526 |  | 
| 4527 | 			// Attach any siblings together (this needs to be done n^2/2 times) | 
| 4528 | 			for (int j = i + 1; j < highest_group_members.size(); ++j) { | 
| 4529 | 				const GLTFNodeIndex node_j = highest_group_members[j]; | 
| 4530 |  | 
| 4531 | 				// Even if they are siblings under the root! :) | 
| 4532 | 				if (p_state->nodes[node_i]->parent == p_state->nodes[node_j]->parent) { | 
| 4533 | 					skeleton_sets.create_union(node_i, node_j); | 
| 4534 | 				} | 
| 4535 | 			} | 
| 4536 |  | 
| 4537 | 			// Attach any parenting going on together (we need to do this n^2 times) | 
| 4538 | 			const GLTFNodeIndex node_i_parent = p_state->nodes[node_i]->parent; | 
| 4539 | 			if (node_i_parent >= 0) { | 
| 4540 | 				for (int j = 0; j < groups.size() && i != j; ++j) { | 
| 4541 | 					const Vector<GLTFNodeIndex> &group = groups[j]; | 
| 4542 |  | 
| 4543 | 					if (group.find(node_i_parent) >= 0) { | 
| 4544 | 						const GLTFNodeIndex node_j = highest_group_members[j]; | 
| 4545 | 						skeleton_sets.create_union(node_i, node_j); | 
| 4546 | 					} | 
| 4547 | 				} | 
| 4548 | 			} | 
| 4549 | 		} | 
| 4550 | 	} | 
| 4551 |  | 
| 4552 | 	// At this point, the skeleton groups should be finalized | 
| 4553 | 	Vector<GLTFNodeIndex> skeleton_owners; | 
| 4554 | 	skeleton_sets.get_representatives(skeleton_owners); | 
| 4555 |  | 
| 4556 | 	// Mark all the skins actual skeletons, after we have merged them | 
| 4557 | 	for (GLTFSkeletonIndex skel_i = 0; skel_i < skeleton_owners.size(); ++skel_i) { | 
| 4558 | 		const GLTFNodeIndex skeleton_owner = skeleton_owners[skel_i]; | 
| 4559 | 		Ref<GLTFSkeleton> skeleton; | 
| 4560 | 		skeleton.instantiate(); | 
| 4561 |  | 
| 4562 | 		Vector<GLTFNodeIndex> skeleton_nodes; | 
| 4563 | 		skeleton_sets.get_members(skeleton_nodes, skeleton_owner); | 
| 4564 |  | 
| 4565 | 		for (GLTFSkinIndex skin_i = 0; skin_i < p_state->skins.size(); ++skin_i) { | 
| 4566 | 			Ref<GLTFSkin> skin = p_state->skins.write[skin_i]; | 
| 4567 |  | 
| 4568 | 			// If any of the the skeletons nodes exist in a skin, that skin now maps to the skeleton | 
| 4569 | 			for (int i = 0; i < skeleton_nodes.size(); ++i) { | 
| 4570 | 				GLTFNodeIndex skel_node_i = skeleton_nodes[i]; | 
| 4571 | 				if (skin->joints.find(skel_node_i) >= 0 || skin->non_joints.find(skel_node_i) >= 0) { | 
| 4572 | 					skin->skeleton = skel_i; | 
| 4573 | 					continue; | 
| 4574 | 				} | 
| 4575 | 			} | 
| 4576 | 		} | 
| 4577 |  | 
| 4578 | 		Vector<GLTFNodeIndex> non_joints; | 
| 4579 | 		for (int i = 0; i < skeleton_nodes.size(); ++i) { | 
| 4580 | 			const GLTFNodeIndex node_i = skeleton_nodes[i]; | 
| 4581 |  | 
| 4582 | 			if (p_state->nodes[node_i]->joint) { | 
| 4583 | 				skeleton->joints.push_back(node_i); | 
| 4584 | 			} else { | 
| 4585 | 				non_joints.push_back(node_i); | 
| 4586 | 			} | 
| 4587 | 		} | 
| 4588 |  | 
| 4589 | 		p_state->skeletons.push_back(skeleton); | 
| 4590 |  | 
| 4591 | 		_reparent_non_joint_skeleton_subtrees(p_state, p_state->skeletons.write[skel_i], non_joints); | 
| 4592 | 	} | 
| 4593 |  | 
| 4594 | 	for (GLTFSkeletonIndex skel_i = 0; skel_i < p_state->skeletons.size(); ++skel_i) { | 
| 4595 | 		Ref<GLTFSkeleton> skeleton = p_state->skeletons.write[skel_i]; | 
| 4596 |  | 
| 4597 | 		for (int i = 0; i < skeleton->joints.size(); ++i) { | 
| 4598 | 			const GLTFNodeIndex node_i = skeleton->joints[i]; | 
| 4599 | 			Ref<GLTFNode> node = p_state->nodes[node_i]; | 
| 4600 |  | 
| 4601 | 			ERR_FAIL_COND_V(!node->joint, ERR_PARSE_ERROR); | 
| 4602 | 			ERR_FAIL_COND_V(node->skeleton >= 0, ERR_PARSE_ERROR); | 
| 4603 | 			node->skeleton = skel_i; | 
| 4604 | 		} | 
| 4605 |  | 
| 4606 | 		ERR_FAIL_COND_V(_determine_skeleton_roots(p_state, skel_i), ERR_PARSE_ERROR); | 
| 4607 | 	} | 
| 4608 |  | 
| 4609 | 	return OK; | 
| 4610 | } | 
| 4611 |  | 
| 4612 | Error GLTFDocument::_reparent_non_joint_skeleton_subtrees(Ref<GLTFState> p_state, Ref<GLTFSkeleton> p_skeleton, const Vector<GLTFNodeIndex> &p_non_joints) { | 
| 4613 | 	DisjointSet<GLTFNodeIndex> subtree_set; | 
| 4614 |  | 
| 4615 | 	// Populate the disjoint set with ONLY non joints that are in the skeleton hierarchy (non_joints vector) | 
| 4616 | 	// This way we can find any joints that lie in between joints, as the current glTF specification | 
| 4617 | 	// mentions nothing about non-joints being in between joints of the same skin. Hopefully one day we | 
| 4618 | 	// can remove this code. | 
| 4619 |  | 
| 4620 | 	// skinD depicted here explains this issue: | 
| 4621 | 	// https://github.com/KhronosGroup/glTF-Asset-Generator/blob/master/Output/Positive/Animation_Skin | 
| 4622 |  | 
| 4623 | 	for (int i = 0; i < p_non_joints.size(); ++i) { | 
| 4624 | 		const GLTFNodeIndex node_i = p_non_joints[i]; | 
| 4625 |  | 
| 4626 | 		subtree_set.insert(node_i); | 
| 4627 |  | 
| 4628 | 		const GLTFNodeIndex parent_i = p_state->nodes[node_i]->parent; | 
| 4629 | 		if (parent_i >= 0 && p_non_joints.find(parent_i) >= 0 && !p_state->nodes[parent_i]->joint) { | 
| 4630 | 			subtree_set.create_union(parent_i, node_i); | 
| 4631 | 		} | 
| 4632 | 	} | 
| 4633 |  | 
| 4634 | 	// Find all the non joint subtrees and re-parent them to a new "fake" joint | 
| 4635 |  | 
| 4636 | 	Vector<GLTFNodeIndex> non_joint_subtree_roots; | 
| 4637 | 	subtree_set.get_representatives(non_joint_subtree_roots); | 
| 4638 |  | 
| 4639 | 	for (int root_i = 0; root_i < non_joint_subtree_roots.size(); ++root_i) { | 
| 4640 | 		const GLTFNodeIndex subtree_root = non_joint_subtree_roots[root_i]; | 
| 4641 |  | 
| 4642 | 		Vector<GLTFNodeIndex> subtree_nodes; | 
| 4643 | 		subtree_set.get_members(subtree_nodes, subtree_root); | 
| 4644 |  | 
| 4645 | 		for (int subtree_i = 0; subtree_i < subtree_nodes.size(); ++subtree_i) { | 
| 4646 | 			Ref<GLTFNode> node = p_state->nodes[subtree_nodes[subtree_i]]; | 
| 4647 | 			node->joint = true; | 
| 4648 | 			// Add the joint to the skeletons joints | 
| 4649 | 			p_skeleton->joints.push_back(subtree_nodes[subtree_i]); | 
| 4650 | 		} | 
| 4651 | 	} | 
| 4652 |  | 
| 4653 | 	return OK; | 
| 4654 | } | 
| 4655 |  | 
| 4656 | Error GLTFDocument::_determine_skeleton_roots(Ref<GLTFState> p_state, const GLTFSkeletonIndex p_skel_i) { | 
| 4657 | 	DisjointSet<GLTFNodeIndex> disjoint_set; | 
| 4658 |  | 
| 4659 | 	for (GLTFNodeIndex i = 0; i < p_state->nodes.size(); ++i) { | 
| 4660 | 		const Ref<GLTFNode> node = p_state->nodes[i]; | 
| 4661 |  | 
| 4662 | 		if (node->skeleton != p_skel_i) { | 
| 4663 | 			continue; | 
| 4664 | 		} | 
| 4665 |  | 
| 4666 | 		disjoint_set.insert(i); | 
| 4667 |  | 
| 4668 | 		if (node->parent >= 0 && p_state->nodes[node->parent]->skeleton == p_skel_i) { | 
| 4669 | 			disjoint_set.create_union(node->parent, i); | 
| 4670 | 		} | 
| 4671 | 	} | 
| 4672 |  | 
| 4673 | 	Ref<GLTFSkeleton> skeleton = p_state->skeletons.write[p_skel_i]; | 
| 4674 |  | 
| 4675 | 	Vector<GLTFNodeIndex> representatives; | 
| 4676 | 	disjoint_set.get_representatives(representatives); | 
| 4677 |  | 
| 4678 | 	Vector<GLTFNodeIndex> roots; | 
| 4679 |  | 
| 4680 | 	for (int i = 0; i < representatives.size(); ++i) { | 
| 4681 | 		Vector<GLTFNodeIndex> set; | 
| 4682 | 		disjoint_set.get_members(set, representatives[i]); | 
| 4683 | 		const GLTFNodeIndex root = _find_highest_node(p_state, set); | 
| 4684 | 		ERR_FAIL_COND_V(root < 0, FAILED); | 
| 4685 | 		roots.push_back(root); | 
| 4686 | 	} | 
| 4687 |  | 
| 4688 | 	roots.sort(); | 
| 4689 |  | 
| 4690 | 	skeleton->roots = roots; | 
| 4691 |  | 
| 4692 | 	if (roots.size() == 0) { | 
| 4693 | 		return FAILED; | 
| 4694 | 	} else if (roots.size() == 1) { | 
| 4695 | 		return OK; | 
| 4696 | 	} | 
| 4697 |  | 
| 4698 | 	// Check that the subtrees have the same parent root | 
| 4699 | 	const GLTFNodeIndex parent = p_state->nodes[roots[0]]->parent; | 
| 4700 | 	for (int i = 1; i < roots.size(); ++i) { | 
| 4701 | 		if (p_state->nodes[roots[i]]->parent != parent) { | 
| 4702 | 			return FAILED; | 
| 4703 | 		} | 
| 4704 | 	} | 
| 4705 |  | 
| 4706 | 	return OK; | 
| 4707 | } | 
| 4708 |  | 
| 4709 | Error GLTFDocument::_create_skeletons(Ref<GLTFState> p_state) { | 
| 4710 | 	for (GLTFSkeletonIndex skel_i = 0; skel_i < p_state->skeletons.size(); ++skel_i) { | 
| 4711 | 		Ref<GLTFSkeleton> gltf_skeleton = p_state->skeletons.write[skel_i]; | 
| 4712 |  | 
| 4713 | 		Skeleton3D *skeleton = memnew(Skeleton3D); | 
| 4714 | 		gltf_skeleton->godot_skeleton = skeleton; | 
| 4715 | 		p_state->skeleton3d_to_gltf_skeleton[skeleton->get_instance_id()] = skel_i; | 
| 4716 |  | 
| 4717 | 		// Make a unique name, no gltf node represents this skeleton | 
| 4718 | 		skeleton->set_name("Skeleton3D" ); | 
| 4719 |  | 
| 4720 | 		List<GLTFNodeIndex> bones; | 
| 4721 |  | 
| 4722 | 		for (int i = 0; i < gltf_skeleton->roots.size(); ++i) { | 
| 4723 | 			bones.push_back(gltf_skeleton->roots[i]); | 
| 4724 | 		} | 
| 4725 |  | 
| 4726 | 		// Make the skeleton creation deterministic by going through the roots in | 
| 4727 | 		// a sorted order, and DEPTH FIRST | 
| 4728 | 		bones.sort(); | 
| 4729 |  | 
| 4730 | 		while (!bones.is_empty()) { | 
| 4731 | 			const GLTFNodeIndex node_i = bones.front()->get(); | 
| 4732 | 			bones.pop_front(); | 
| 4733 |  | 
| 4734 | 			Ref<GLTFNode> node = p_state->nodes[node_i]; | 
| 4735 | 			ERR_FAIL_COND_V(node->skeleton != skel_i, FAILED); | 
| 4736 |  | 
| 4737 | 			{ // Add all child nodes to the stack (deterministically) | 
| 4738 | 				Vector<GLTFNodeIndex> child_nodes; | 
| 4739 | 				for (int i = 0; i < node->children.size(); ++i) { | 
| 4740 | 					const GLTFNodeIndex child_i = node->children[i]; | 
| 4741 | 					if (p_state->nodes[child_i]->skeleton == skel_i) { | 
| 4742 | 						child_nodes.push_back(child_i); | 
| 4743 | 					} | 
| 4744 | 				} | 
| 4745 |  | 
| 4746 | 				// Depth first insertion | 
| 4747 | 				child_nodes.sort(); | 
| 4748 | 				for (int i = child_nodes.size() - 1; i >= 0; --i) { | 
| 4749 | 					bones.push_front(child_nodes[i]); | 
| 4750 | 				} | 
| 4751 | 			} | 
| 4752 |  | 
| 4753 | 			const int bone_index = skeleton->get_bone_count(); | 
| 4754 |  | 
| 4755 | 			if (node->get_name().is_empty()) { | 
| 4756 | 				node->set_name("bone" ); | 
| 4757 | 			} | 
| 4758 |  | 
| 4759 | 			node->set_name(_gen_unique_bone_name(p_state, skel_i, node->get_name())); | 
| 4760 |  | 
| 4761 | 			skeleton->add_bone(node->get_name()); | 
| 4762 | 			skeleton->set_bone_rest(bone_index, node->xform); | 
| 4763 | 			skeleton->set_bone_pose_position(bone_index, node->position); | 
| 4764 | 			skeleton->set_bone_pose_rotation(bone_index, node->rotation.normalized()); | 
| 4765 | 			skeleton->set_bone_pose_scale(bone_index, node->scale); | 
| 4766 |  | 
| 4767 | 			if (node->parent >= 0 && p_state->nodes[node->parent]->skeleton == skel_i) { | 
| 4768 | 				const int bone_parent = skeleton->find_bone(p_state->nodes[node->parent]->get_name()); | 
| 4769 | 				ERR_FAIL_COND_V(bone_parent < 0, FAILED); | 
| 4770 | 				skeleton->set_bone_parent(bone_index, skeleton->find_bone(p_state->nodes[node->parent]->get_name())); | 
| 4771 | 			} | 
| 4772 |  | 
| 4773 | 			p_state->scene_nodes.insert(node_i, skeleton); | 
| 4774 | 		} | 
| 4775 | 	} | 
| 4776 |  | 
| 4777 | 	ERR_FAIL_COND_V(_map_skin_joints_indices_to_skeleton_bone_indices(p_state), ERR_PARSE_ERROR); | 
| 4778 |  | 
| 4779 | 	return OK; | 
| 4780 | } | 
| 4781 |  | 
| 4782 | Error GLTFDocument::_map_skin_joints_indices_to_skeleton_bone_indices(Ref<GLTFState> p_state) { | 
| 4783 | 	for (GLTFSkinIndex skin_i = 0; skin_i < p_state->skins.size(); ++skin_i) { | 
| 4784 | 		Ref<GLTFSkin> skin = p_state->skins.write[skin_i]; | 
| 4785 |  | 
| 4786 | 		Ref<GLTFSkeleton> skeleton = p_state->skeletons[skin->skeleton]; | 
| 4787 |  | 
| 4788 | 		for (int joint_index = 0; joint_index < skin->joints_original.size(); ++joint_index) { | 
| 4789 | 			const GLTFNodeIndex node_i = skin->joints_original[joint_index]; | 
| 4790 | 			const Ref<GLTFNode> node = p_state->nodes[node_i]; | 
| 4791 |  | 
| 4792 | 			const int bone_index = skeleton->godot_skeleton->find_bone(node->get_name()); | 
| 4793 | 			ERR_FAIL_COND_V(bone_index < 0, FAILED); | 
| 4794 |  | 
| 4795 | 			skin->joint_i_to_bone_i.insert(joint_index, bone_index); | 
| 4796 | 		} | 
| 4797 | 	} | 
| 4798 |  | 
| 4799 | 	return OK; | 
| 4800 | } | 
| 4801 |  | 
| 4802 | Error GLTFDocument::_serialize_skins(Ref<GLTFState> p_state) { | 
| 4803 | 	_remove_duplicate_skins(p_state); | 
| 4804 | 	Array json_skins; | 
| 4805 | 	for (int skin_i = 0; skin_i < p_state->skins.size(); skin_i++) { | 
| 4806 | 		Ref<GLTFSkin> gltf_skin = p_state->skins[skin_i]; | 
| 4807 | 		Dictionary json_skin; | 
| 4808 | 		json_skin["inverseBindMatrices" ] = _encode_accessor_as_xform(p_state, gltf_skin->inverse_binds, false); | 
| 4809 | 		json_skin["joints" ] = gltf_skin->get_joints(); | 
| 4810 | 		json_skin["name" ] = gltf_skin->get_name(); | 
| 4811 | 		json_skins.push_back(json_skin); | 
| 4812 | 	} | 
| 4813 | 	if (!p_state->skins.size()) { | 
| 4814 | 		return OK; | 
| 4815 | 	} | 
| 4816 |  | 
| 4817 | 	p_state->json["skins" ] = json_skins; | 
| 4818 | 	return OK; | 
| 4819 | } | 
| 4820 |  | 
| 4821 | Error GLTFDocument::_create_skins(Ref<GLTFState> p_state) { | 
| 4822 | 	for (GLTFSkinIndex skin_i = 0; skin_i < p_state->skins.size(); ++skin_i) { | 
| 4823 | 		Ref<GLTFSkin> gltf_skin = p_state->skins.write[skin_i]; | 
| 4824 |  | 
| 4825 | 		Ref<Skin> skin; | 
| 4826 | 		skin.instantiate(); | 
| 4827 |  | 
| 4828 | 		// Some skins don't have IBM's! What absolute monsters! | 
| 4829 | 		const bool has_ibms = !gltf_skin->inverse_binds.is_empty(); | 
| 4830 |  | 
| 4831 | 		for (int joint_i = 0; joint_i < gltf_skin->joints_original.size(); ++joint_i) { | 
| 4832 | 			GLTFNodeIndex node = gltf_skin->joints_original[joint_i]; | 
| 4833 | 			String bone_name = p_state->nodes[node]->get_name(); | 
| 4834 |  | 
| 4835 | 			Transform3D xform; | 
| 4836 | 			if (has_ibms) { | 
| 4837 | 				xform = gltf_skin->inverse_binds[joint_i]; | 
| 4838 | 			} | 
| 4839 |  | 
| 4840 | 			if (p_state->use_named_skin_binds) { | 
| 4841 | 				skin->add_named_bind(bone_name, xform); | 
| 4842 | 			} else { | 
| 4843 | 				int32_t bone_i = gltf_skin->joint_i_to_bone_i[joint_i]; | 
| 4844 | 				skin->add_bind(bone_i, xform); | 
| 4845 | 			} | 
| 4846 | 		} | 
| 4847 |  | 
| 4848 | 		gltf_skin->godot_skin = skin; | 
| 4849 | 	} | 
| 4850 |  | 
| 4851 | 	// Purge the duplicates! | 
| 4852 | 	_remove_duplicate_skins(p_state); | 
| 4853 |  | 
| 4854 | 	// Create unique names now, after removing duplicates | 
| 4855 | 	for (GLTFSkinIndex skin_i = 0; skin_i < p_state->skins.size(); ++skin_i) { | 
| 4856 | 		Ref<Skin> skin = p_state->skins.write[skin_i]->godot_skin; | 
| 4857 | 		if (skin->get_name().is_empty()) { | 
| 4858 | 			// Make a unique name, no gltf node represents this skin | 
| 4859 | 			skin->set_name(_gen_unique_name(p_state, "Skin" )); | 
| 4860 | 		} | 
| 4861 | 	} | 
| 4862 |  | 
| 4863 | 	return OK; | 
| 4864 | } | 
| 4865 |  | 
| 4866 | bool GLTFDocument::_skins_are_same(const Ref<Skin> p_skin_a, const Ref<Skin> p_skin_b) { | 
| 4867 | 	if (p_skin_a->get_bind_count() != p_skin_b->get_bind_count()) { | 
| 4868 | 		return false; | 
| 4869 | 	} | 
| 4870 |  | 
| 4871 | 	for (int i = 0; i < p_skin_a->get_bind_count(); ++i) { | 
| 4872 | 		if (p_skin_a->get_bind_bone(i) != p_skin_b->get_bind_bone(i)) { | 
| 4873 | 			return false; | 
| 4874 | 		} | 
| 4875 | 		if (p_skin_a->get_bind_name(i) != p_skin_b->get_bind_name(i)) { | 
| 4876 | 			return false; | 
| 4877 | 		} | 
| 4878 |  | 
| 4879 | 		Transform3D a_xform = p_skin_a->get_bind_pose(i); | 
| 4880 | 		Transform3D b_xform = p_skin_b->get_bind_pose(i); | 
| 4881 |  | 
| 4882 | 		if (a_xform != b_xform) { | 
| 4883 | 			return false; | 
| 4884 | 		} | 
| 4885 | 	} | 
| 4886 |  | 
| 4887 | 	return true; | 
| 4888 | } | 
| 4889 |  | 
| 4890 | void GLTFDocument::_remove_duplicate_skins(Ref<GLTFState> p_state) { | 
| 4891 | 	for (int i = 0; i < p_state->skins.size(); ++i) { | 
| 4892 | 		for (int j = i + 1; j < p_state->skins.size(); ++j) { | 
| 4893 | 			const Ref<Skin> skin_i = p_state->skins[i]->godot_skin; | 
| 4894 | 			const Ref<Skin> skin_j = p_state->skins[j]->godot_skin; | 
| 4895 |  | 
| 4896 | 			if (_skins_are_same(skin_i, skin_j)) { | 
| 4897 | 				// replace it and delete the old | 
| 4898 | 				p_state->skins.write[j]->godot_skin = skin_i; | 
| 4899 | 			} | 
| 4900 | 		} | 
| 4901 | 	} | 
| 4902 | } | 
| 4903 |  | 
| 4904 | Error GLTFDocument::_serialize_lights(Ref<GLTFState> p_state) { | 
| 4905 | 	if (p_state->lights.is_empty()) { | 
| 4906 | 		return OK; | 
| 4907 | 	} | 
| 4908 | 	Array lights; | 
| 4909 | 	for (GLTFLightIndex i = 0; i < p_state->lights.size(); i++) { | 
| 4910 | 		lights.push_back(p_state->lights[i]->to_dictionary()); | 
| 4911 | 	} | 
| 4912 |  | 
| 4913 | 	Dictionary extensions; | 
| 4914 | 	if (p_state->json.has("extensions" )) { | 
| 4915 | 		extensions = p_state->json["extensions" ]; | 
| 4916 | 	} else { | 
| 4917 | 		p_state->json["extensions" ] = extensions; | 
| 4918 | 	} | 
| 4919 | 	Dictionary lights_punctual; | 
| 4920 | 	extensions["KHR_lights_punctual" ] = lights_punctual; | 
| 4921 | 	lights_punctual["lights" ] = lights; | 
| 4922 |  | 
| 4923 | 	print_verbose("glTF: Total lights: "  + itos(p_state->lights.size())); | 
| 4924 |  | 
| 4925 | 	return OK; | 
| 4926 | } | 
| 4927 |  | 
| 4928 | Error GLTFDocument::_serialize_cameras(Ref<GLTFState> p_state) { | 
| 4929 | 	Array cameras; | 
| 4930 | 	cameras.resize(p_state->cameras.size()); | 
| 4931 | 	for (GLTFCameraIndex i = 0; i < p_state->cameras.size(); i++) { | 
| 4932 | 		cameras[i] = p_state->cameras[i]->to_dictionary(); | 
| 4933 | 	} | 
| 4934 |  | 
| 4935 | 	if (!p_state->cameras.size()) { | 
| 4936 | 		return OK; | 
| 4937 | 	} | 
| 4938 |  | 
| 4939 | 	p_state->json["cameras" ] = cameras; | 
| 4940 |  | 
| 4941 | 	print_verbose("glTF: Total cameras: "  + itos(p_state->cameras.size())); | 
| 4942 |  | 
| 4943 | 	return OK; | 
| 4944 | } | 
| 4945 |  | 
| 4946 | Error GLTFDocument::_parse_lights(Ref<GLTFState> p_state) { | 
| 4947 | 	if (!p_state->json.has("extensions" )) { | 
| 4948 | 		return OK; | 
| 4949 | 	} | 
| 4950 | 	Dictionary extensions = p_state->json["extensions" ]; | 
| 4951 | 	if (!extensions.has("KHR_lights_punctual" )) { | 
| 4952 | 		return OK; | 
| 4953 | 	} | 
| 4954 | 	Dictionary lights_punctual = extensions["KHR_lights_punctual" ]; | 
| 4955 | 	if (!lights_punctual.has("lights" )) { | 
| 4956 | 		return OK; | 
| 4957 | 	} | 
| 4958 |  | 
| 4959 | 	const Array &lights = lights_punctual["lights" ]; | 
| 4960 |  | 
| 4961 | 	for (GLTFLightIndex light_i = 0; light_i < lights.size(); light_i++) { | 
| 4962 | 		Ref<GLTFLight> light = GLTFLight::from_dictionary(lights[light_i]); | 
| 4963 | 		if (light.is_null()) { | 
| 4964 | 			return Error::ERR_PARSE_ERROR; | 
| 4965 | 		} | 
| 4966 | 		p_state->lights.push_back(light); | 
| 4967 | 	} | 
| 4968 |  | 
| 4969 | 	print_verbose("glTF: Total lights: "  + itos(p_state->lights.size())); | 
| 4970 |  | 
| 4971 | 	return OK; | 
| 4972 | } | 
| 4973 |  | 
| 4974 | Error GLTFDocument::_parse_cameras(Ref<GLTFState> p_state) { | 
| 4975 | 	if (!p_state->json.has("cameras" )) { | 
| 4976 | 		return OK; | 
| 4977 | 	} | 
| 4978 |  | 
| 4979 | 	const Array cameras = p_state->json["cameras" ]; | 
| 4980 |  | 
| 4981 | 	for (GLTFCameraIndex i = 0; i < cameras.size(); i++) { | 
| 4982 | 		p_state->cameras.push_back(GLTFCamera::from_dictionary(cameras[i])); | 
| 4983 | 	} | 
| 4984 |  | 
| 4985 | 	print_verbose("glTF: Total cameras: "  + itos(p_state->cameras.size())); | 
| 4986 |  | 
| 4987 | 	return OK; | 
| 4988 | } | 
| 4989 |  | 
| 4990 | String GLTFDocument::interpolation_to_string(const GLTFAnimation::Interpolation p_interp) { | 
| 4991 | 	String interp = "LINEAR" ; | 
| 4992 | 	if (p_interp == GLTFAnimation::INTERP_STEP) { | 
| 4993 | 		interp = "STEP" ; | 
| 4994 | 	} else if (p_interp == GLTFAnimation::INTERP_LINEAR) { | 
| 4995 | 		interp = "LINEAR" ; | 
| 4996 | 	} else if (p_interp == GLTFAnimation::INTERP_CATMULLROMSPLINE) { | 
| 4997 | 		interp = "CATMULLROMSPLINE" ; | 
| 4998 | 	} else if (p_interp == GLTFAnimation::INTERP_CUBIC_SPLINE) { | 
| 4999 | 		interp = "CUBICSPLINE" ; | 
| 5000 | 	} | 
| 5001 |  | 
| 5002 | 	return interp; | 
| 5003 | } | 
| 5004 |  | 
| 5005 | Error GLTFDocument::_serialize_animations(Ref<GLTFState> p_state) { | 
| 5006 | 	if (!p_state->animation_players.size()) { | 
| 5007 | 		return OK; | 
| 5008 | 	} | 
| 5009 | 	for (int32_t player_i = 0; player_i < p_state->animation_players.size(); player_i++) { | 
| 5010 | 		AnimationPlayer *animation_player = p_state->animation_players[player_i]; | 
| 5011 | 		List<StringName> animations; | 
| 5012 | 		animation_player->get_animation_list(&animations); | 
| 5013 | 		for (StringName animation_name : animations) { | 
| 5014 | 			_convert_animation(p_state, animation_player, animation_name); | 
| 5015 | 		} | 
| 5016 | 	} | 
| 5017 | 	Array animations; | 
| 5018 | 	for (GLTFAnimationIndex animation_i = 0; animation_i < p_state->animations.size(); animation_i++) { | 
| 5019 | 		Dictionary d; | 
| 5020 | 		Ref<GLTFAnimation> gltf_animation = p_state->animations[animation_i]; | 
| 5021 | 		if (!gltf_animation->get_tracks().size()) { | 
| 5022 | 			continue; | 
| 5023 | 		} | 
| 5024 |  | 
| 5025 | 		if (!gltf_animation->get_name().is_empty()) { | 
| 5026 | 			d["name" ] = gltf_animation->get_name(); | 
| 5027 | 		} | 
| 5028 | 		Array channels; | 
| 5029 | 		Array samplers; | 
| 5030 |  | 
| 5031 | 		for (KeyValue<int, GLTFAnimation::Track> &track_i : gltf_animation->get_tracks()) { | 
| 5032 | 			GLTFAnimation::Track track = track_i.value; | 
| 5033 | 			if (track.position_track.times.size()) { | 
| 5034 | 				Dictionary t; | 
| 5035 | 				t["sampler" ] = samplers.size(); | 
| 5036 | 				Dictionary s; | 
| 5037 |  | 
| 5038 | 				s["interpolation" ] = interpolation_to_string(track.position_track.interpolation); | 
| 5039 | 				Vector<real_t> times = Variant(track.position_track.times); | 
| 5040 | 				s["input" ] = _encode_accessor_as_floats(p_state, times, false); | 
| 5041 | 				Vector<Vector3> values = Variant(track.position_track.values); | 
| 5042 | 				s["output" ] = _encode_accessor_as_vec3(p_state, values, false); | 
| 5043 |  | 
| 5044 | 				samplers.push_back(s); | 
| 5045 |  | 
| 5046 | 				Dictionary target; | 
| 5047 | 				target["path" ] = "translation" ; | 
| 5048 | 				target["node" ] = track_i.key; | 
| 5049 |  | 
| 5050 | 				t["target" ] = target; | 
| 5051 | 				channels.push_back(t); | 
| 5052 | 			} | 
| 5053 | 			if (track.rotation_track.times.size()) { | 
| 5054 | 				Dictionary t; | 
| 5055 | 				t["sampler" ] = samplers.size(); | 
| 5056 | 				Dictionary s; | 
| 5057 |  | 
| 5058 | 				s["interpolation" ] = interpolation_to_string(track.rotation_track.interpolation); | 
| 5059 | 				Vector<real_t> times = Variant(track.rotation_track.times); | 
| 5060 | 				s["input" ] = _encode_accessor_as_floats(p_state, times, false); | 
| 5061 | 				Vector<Quaternion> values = track.rotation_track.values; | 
| 5062 | 				s["output" ] = _encode_accessor_as_quaternions(p_state, values, false); | 
| 5063 |  | 
| 5064 | 				samplers.push_back(s); | 
| 5065 |  | 
| 5066 | 				Dictionary target; | 
| 5067 | 				target["path" ] = "rotation" ; | 
| 5068 | 				target["node" ] = track_i.key; | 
| 5069 |  | 
| 5070 | 				t["target" ] = target; | 
| 5071 | 				channels.push_back(t); | 
| 5072 | 			} | 
| 5073 | 			if (track.scale_track.times.size()) { | 
| 5074 | 				Dictionary t; | 
| 5075 | 				t["sampler" ] = samplers.size(); | 
| 5076 | 				Dictionary s; | 
| 5077 |  | 
| 5078 | 				s["interpolation" ] = interpolation_to_string(track.scale_track.interpolation); | 
| 5079 | 				Vector<real_t> times = Variant(track.scale_track.times); | 
| 5080 | 				s["input" ] = _encode_accessor_as_floats(p_state, times, false); | 
| 5081 | 				Vector<Vector3> values = Variant(track.scale_track.values); | 
| 5082 | 				s["output" ] = _encode_accessor_as_vec3(p_state, values, false); | 
| 5083 |  | 
| 5084 | 				samplers.push_back(s); | 
| 5085 |  | 
| 5086 | 				Dictionary target; | 
| 5087 | 				target["path" ] = "scale" ; | 
| 5088 | 				target["node" ] = track_i.key; | 
| 5089 |  | 
| 5090 | 				t["target" ] = target; | 
| 5091 | 				channels.push_back(t); | 
| 5092 | 			} | 
| 5093 | 			if (track.weight_tracks.size()) { | 
| 5094 | 				double length = 0.0f; | 
| 5095 |  | 
| 5096 | 				for (int32_t track_idx = 0; track_idx < track.weight_tracks.size(); track_idx++) { | 
| 5097 | 					int32_t last_time_index = track.weight_tracks[track_idx].times.size() - 1; | 
| 5098 | 					length = MAX(length, track.weight_tracks[track_idx].times[last_time_index]); | 
| 5099 | 				} | 
| 5100 |  | 
| 5101 | 				Dictionary t; | 
| 5102 | 				t["sampler" ] = samplers.size(); | 
| 5103 | 				Dictionary s; | 
| 5104 | 				Vector<real_t> times; | 
| 5105 | 				const double increment = 1.0 / BAKE_FPS; | 
| 5106 | 				{ | 
| 5107 | 					double time = 0.0; | 
| 5108 | 					bool last = false; | 
| 5109 | 					while (true) { | 
| 5110 | 						times.push_back(time); | 
| 5111 | 						if (last) { | 
| 5112 | 							break; | 
| 5113 | 						} | 
| 5114 | 						time += increment; | 
| 5115 | 						if (time >= length) { | 
| 5116 | 							last = true; | 
| 5117 | 							time = length; | 
| 5118 | 						} | 
| 5119 | 					} | 
| 5120 | 				} | 
| 5121 |  | 
| 5122 | 				for (int32_t track_idx = 0; track_idx < track.weight_tracks.size(); track_idx++) { | 
| 5123 | 					double time = 0.0; | 
| 5124 | 					bool last = false; | 
| 5125 | 					Vector<real_t> weight_track; | 
| 5126 | 					while (true) { | 
| 5127 | 						float weight = _interpolate_track<real_t>(track.weight_tracks[track_idx].times, | 
| 5128 | 								track.weight_tracks[track_idx].values, | 
| 5129 | 								time, | 
| 5130 | 								track.weight_tracks[track_idx].interpolation); | 
| 5131 | 						weight_track.push_back(weight); | 
| 5132 | 						if (last) { | 
| 5133 | 							break; | 
| 5134 | 						} | 
| 5135 | 						time += increment; | 
| 5136 | 						if (time >= length) { | 
| 5137 | 							last = true; | 
| 5138 | 							time = length; | 
| 5139 | 						} | 
| 5140 | 					} | 
| 5141 | 					track.weight_tracks.write[track_idx].times = times; | 
| 5142 | 					track.weight_tracks.write[track_idx].values = weight_track; | 
| 5143 | 				} | 
| 5144 |  | 
| 5145 | 				Vector<real_t> all_track_times = times; | 
| 5146 | 				Vector<real_t> all_track_values; | 
| 5147 | 				int32_t values_size = track.weight_tracks[0].values.size(); | 
| 5148 | 				int32_t weight_tracks_size = track.weight_tracks.size(); | 
| 5149 | 				all_track_values.resize(weight_tracks_size * values_size); | 
| 5150 | 				for (int k = 0; k < track.weight_tracks.size(); k++) { | 
| 5151 | 					Vector<real_t> wdata = track.weight_tracks[k].values; | 
| 5152 | 					for (int l = 0; l < wdata.size(); l++) { | 
| 5153 | 						int32_t index = l * weight_tracks_size + k; | 
| 5154 | 						ERR_BREAK(index >= all_track_values.size()); | 
| 5155 | 						all_track_values.write[index] = wdata.write[l]; | 
| 5156 | 					} | 
| 5157 | 				} | 
| 5158 |  | 
| 5159 | 				s["interpolation" ] = interpolation_to_string(track.weight_tracks[track.weight_tracks.size() - 1].interpolation); | 
| 5160 | 				s["input" ] = _encode_accessor_as_floats(p_state, all_track_times, false); | 
| 5161 | 				s["output" ] = _encode_accessor_as_floats(p_state, all_track_values, false); | 
| 5162 |  | 
| 5163 | 				samplers.push_back(s); | 
| 5164 |  | 
| 5165 | 				Dictionary target; | 
| 5166 | 				target["path" ] = "weights" ; | 
| 5167 | 				target["node" ] = track_i.key; | 
| 5168 |  | 
| 5169 | 				t["target" ] = target; | 
| 5170 | 				channels.push_back(t); | 
| 5171 | 			} | 
| 5172 | 		} | 
| 5173 | 		if (channels.size() && samplers.size()) { | 
| 5174 | 			d["channels" ] = channels; | 
| 5175 | 			d["samplers" ] = samplers; | 
| 5176 | 			animations.push_back(d); | 
| 5177 | 		} | 
| 5178 | 	} | 
| 5179 |  | 
| 5180 | 	if (!animations.size()) { | 
| 5181 | 		return OK; | 
| 5182 | 	} | 
| 5183 | 	p_state->json["animations" ] = animations; | 
| 5184 |  | 
| 5185 | 	print_verbose("glTF: Total animations '"  + itos(p_state->animations.size()) + "'." ); | 
| 5186 |  | 
| 5187 | 	return OK; | 
| 5188 | } | 
| 5189 |  | 
| 5190 | Error GLTFDocument::_parse_animations(Ref<GLTFState> p_state) { | 
| 5191 | 	if (!p_state->json.has("animations" )) { | 
| 5192 | 		return OK; | 
| 5193 | 	} | 
| 5194 |  | 
| 5195 | 	const Array &animations = p_state->json["animations" ]; | 
| 5196 |  | 
| 5197 | 	for (GLTFAnimationIndex i = 0; i < animations.size(); i++) { | 
| 5198 | 		const Dictionary &d = animations[i]; | 
| 5199 |  | 
| 5200 | 		Ref<GLTFAnimation> animation; | 
| 5201 | 		animation.instantiate(); | 
| 5202 |  | 
| 5203 | 		if (!d.has("channels" ) || !d.has("samplers" )) { | 
| 5204 | 			continue; | 
| 5205 | 		} | 
| 5206 |  | 
| 5207 | 		Array channels = d["channels" ]; | 
| 5208 | 		Array samplers = d["samplers" ]; | 
| 5209 |  | 
| 5210 | 		if (d.has("name" )) { | 
| 5211 | 			const String anim_name = d["name" ]; | 
| 5212 | 			const String anim_name_lower = anim_name.to_lower(); | 
| 5213 | 			if (anim_name_lower.begins_with("loop" ) || anim_name_lower.ends_with("loop" ) || anim_name_lower.begins_with("cycle" ) || anim_name_lower.ends_with("cycle" )) { | 
| 5214 | 				animation->set_loop(true); | 
| 5215 | 			} | 
| 5216 | 			animation->set_name(_gen_unique_animation_name(p_state, anim_name)); | 
| 5217 | 		} | 
| 5218 |  | 
| 5219 | 		for (int j = 0; j < channels.size(); j++) { | 
| 5220 | 			const Dictionary &c = channels[j]; | 
| 5221 | 			if (!c.has("target" )) { | 
| 5222 | 				continue; | 
| 5223 | 			} | 
| 5224 |  | 
| 5225 | 			const Dictionary &t = c["target" ]; | 
| 5226 | 			if (!t.has("node" ) || !t.has("path" )) { | 
| 5227 | 				continue; | 
| 5228 | 			} | 
| 5229 |  | 
| 5230 | 			ERR_FAIL_COND_V(!c.has("sampler" ), ERR_PARSE_ERROR); | 
| 5231 | 			const int sampler = c["sampler" ]; | 
| 5232 | 			ERR_FAIL_INDEX_V(sampler, samplers.size(), ERR_PARSE_ERROR); | 
| 5233 |  | 
| 5234 | 			GLTFNodeIndex node = t["node" ]; | 
| 5235 | 			String path = t["path" ]; | 
| 5236 |  | 
| 5237 | 			ERR_FAIL_INDEX_V(node, p_state->nodes.size(), ERR_PARSE_ERROR); | 
| 5238 |  | 
| 5239 | 			GLTFAnimation::Track *track = nullptr; | 
| 5240 |  | 
| 5241 | 			if (!animation->get_tracks().has(node)) { | 
| 5242 | 				animation->get_tracks()[node] = GLTFAnimation::Track(); | 
| 5243 | 			} | 
| 5244 |  | 
| 5245 | 			track = &animation->get_tracks()[node]; | 
| 5246 |  | 
| 5247 | 			const Dictionary &s = samplers[sampler]; | 
| 5248 |  | 
| 5249 | 			ERR_FAIL_COND_V(!s.has("input" ), ERR_PARSE_ERROR); | 
| 5250 | 			ERR_FAIL_COND_V(!s.has("output" ), ERR_PARSE_ERROR); | 
| 5251 |  | 
| 5252 | 			const int input = s["input" ]; | 
| 5253 | 			const int output = s["output" ]; | 
| 5254 |  | 
| 5255 | 			GLTFAnimation::Interpolation interp = GLTFAnimation::INTERP_LINEAR; | 
| 5256 | 			int output_count = 1; | 
| 5257 | 			if (s.has("interpolation" )) { | 
| 5258 | 				const String &in = s["interpolation" ]; | 
| 5259 | 				if (in == "STEP" ) { | 
| 5260 | 					interp = GLTFAnimation::INTERP_STEP; | 
| 5261 | 				} else if (in == "LINEAR" ) { | 
| 5262 | 					interp = GLTFAnimation::INTERP_LINEAR; | 
| 5263 | 				} else if (in == "CATMULLROMSPLINE" ) { | 
| 5264 | 					interp = GLTFAnimation::INTERP_CATMULLROMSPLINE; | 
| 5265 | 					output_count = 3; | 
| 5266 | 				} else if (in == "CUBICSPLINE" ) { | 
| 5267 | 					interp = GLTFAnimation::INTERP_CUBIC_SPLINE; | 
| 5268 | 					output_count = 3; | 
| 5269 | 				} | 
| 5270 | 			} | 
| 5271 |  | 
| 5272 | 			const Vector<float> times = _decode_accessor_as_floats(p_state, input, false); | 
| 5273 | 			if (path == "translation" ) { | 
| 5274 | 				const Vector<Vector3> positions = _decode_accessor_as_vec3(p_state, output, false); | 
| 5275 | 				track->position_track.interpolation = interp; | 
| 5276 | 				track->position_track.times = Variant(times); //convert via variant | 
| 5277 | 				track->position_track.values = Variant(positions); //convert via variant | 
| 5278 | 			} else if (path == "rotation" ) { | 
| 5279 | 				const Vector<Quaternion> rotations = _decode_accessor_as_quaternion(p_state, output, false); | 
| 5280 | 				track->rotation_track.interpolation = interp; | 
| 5281 | 				track->rotation_track.times = Variant(times); //convert via variant | 
| 5282 | 				track->rotation_track.values = rotations; | 
| 5283 | 			} else if (path == "scale" ) { | 
| 5284 | 				const Vector<Vector3> scales = _decode_accessor_as_vec3(p_state, output, false); | 
| 5285 | 				track->scale_track.interpolation = interp; | 
| 5286 | 				track->scale_track.times = Variant(times); //convert via variant | 
| 5287 | 				track->scale_track.values = Variant(scales); //convert via variant | 
| 5288 | 			} else if (path == "weights" ) { | 
| 5289 | 				const Vector<float> weights = _decode_accessor_as_floats(p_state, output, false); | 
| 5290 |  | 
| 5291 | 				ERR_FAIL_INDEX_V(p_state->nodes[node]->mesh, p_state->meshes.size(), ERR_PARSE_ERROR); | 
| 5292 | 				Ref<GLTFMesh> mesh = p_state->meshes[p_state->nodes[node]->mesh]; | 
| 5293 | 				ERR_CONTINUE(!mesh->get_blend_weights().size()); | 
| 5294 | 				const int wc = mesh->get_blend_weights().size(); | 
| 5295 |  | 
| 5296 | 				track->weight_tracks.resize(wc); | 
| 5297 |  | 
| 5298 | 				const int expected_value_count = times.size() * output_count * wc; | 
| 5299 | 				ERR_CONTINUE_MSG(weights.size() != expected_value_count, "Invalid weight data, expected "  + itos(expected_value_count) + " weight values, got "  + itos(weights.size()) + " instead." ); | 
| 5300 |  | 
| 5301 | 				const int wlen = weights.size() / wc; | 
| 5302 | 				for (int k = 0; k < wc; k++) { //separate tracks, having them together is not such a good idea | 
| 5303 | 					GLTFAnimation::Channel<real_t> cf; | 
| 5304 | 					cf.interpolation = interp; | 
| 5305 | 					cf.times = Variant(times); | 
| 5306 | 					Vector<real_t> wdata; | 
| 5307 | 					wdata.resize(wlen); | 
| 5308 | 					for (int l = 0; l < wlen; l++) { | 
| 5309 | 						wdata.write[l] = weights[l * wc + k]; | 
| 5310 | 					} | 
| 5311 |  | 
| 5312 | 					cf.values = wdata; | 
| 5313 | 					track->weight_tracks.write[k] = cf; | 
| 5314 | 				} | 
| 5315 | 			} else { | 
| 5316 | 				WARN_PRINT("Invalid path '"  + path + "'." ); | 
| 5317 | 			} | 
| 5318 | 		} | 
| 5319 |  | 
| 5320 | 		p_state->animations.push_back(animation); | 
| 5321 | 	} | 
| 5322 |  | 
| 5323 | 	print_verbose("glTF: Total animations '"  + itos(p_state->animations.size()) + "'." ); | 
| 5324 |  | 
| 5325 | 	return OK; | 
| 5326 | } | 
| 5327 |  | 
| 5328 | void GLTFDocument::_assign_node_names(Ref<GLTFState> p_state) { | 
| 5329 | 	for (int i = 0; i < p_state->nodes.size(); i++) { | 
| 5330 | 		Ref<GLTFNode> gltf_node = p_state->nodes[i]; | 
| 5331 | 		// Any joints get unique names generated when the skeleton is made, unique to the skeleton | 
| 5332 | 		if (gltf_node->skeleton >= 0) { | 
| 5333 | 			continue; | 
| 5334 | 		} | 
| 5335 | 		String gltf_node_name = gltf_node->get_name(); | 
| 5336 | 		if (gltf_node_name.is_empty()) { | 
| 5337 | 			if (gltf_node->mesh >= 0) { | 
| 5338 | 				gltf_node_name = "Mesh" ; | 
| 5339 | 			} else if (gltf_node->camera >= 0) { | 
| 5340 | 				gltf_node_name = "Camera" ; | 
| 5341 | 			} else { | 
| 5342 | 				gltf_node_name = "Node" ; | 
| 5343 | 			} | 
| 5344 | 		} | 
| 5345 | 		gltf_node->set_name(_gen_unique_name(p_state, gltf_node_name)); | 
| 5346 | 	} | 
| 5347 | } | 
| 5348 |  | 
| 5349 | BoneAttachment3D *GLTFDocument::_generate_bone_attachment(Ref<GLTFState> p_state, Skeleton3D *p_skeleton, const GLTFNodeIndex p_node_index, const GLTFNodeIndex p_bone_index) { | 
| 5350 | 	Ref<GLTFNode> gltf_node = p_state->nodes[p_node_index]; | 
| 5351 | 	Ref<GLTFNode> bone_node = p_state->nodes[p_bone_index]; | 
| 5352 | 	BoneAttachment3D *bone_attachment = memnew(BoneAttachment3D); | 
| 5353 | 	print_verbose("glTF: Creating bone attachment for: "  + gltf_node->get_name()); | 
| 5354 |  | 
| 5355 | 	ERR_FAIL_COND_V(!bone_node->joint, nullptr); | 
| 5356 |  | 
| 5357 | 	bone_attachment->set_bone_name(bone_node->get_name()); | 
| 5358 |  | 
| 5359 | 	return bone_attachment; | 
| 5360 | } | 
| 5361 |  | 
| 5362 | GLTFMeshIndex GLTFDocument::_convert_mesh_to_gltf(Ref<GLTFState> p_state, MeshInstance3D *p_mesh_instance) { | 
| 5363 | 	ERR_FAIL_NULL_V(p_mesh_instance, -1); | 
| 5364 | 	if (p_mesh_instance->get_mesh().is_null()) { | 
| 5365 | 		return -1; | 
| 5366 | 	} | 
| 5367 |  | 
| 5368 | 	Ref<Mesh> import_mesh = p_mesh_instance->get_mesh(); | 
| 5369 | 	Ref<ImporterMesh> current_mesh = _mesh_to_importer_mesh(import_mesh); | 
| 5370 | 	Vector<float> blend_weights; | 
| 5371 | 	int32_t blend_count = import_mesh->get_blend_shape_count(); | 
| 5372 | 	blend_weights.resize(blend_count); | 
| 5373 | 	for (int32_t blend_i = 0; blend_i < blend_count; blend_i++) { | 
| 5374 | 		blend_weights.write[blend_i] = 0.0f; | 
| 5375 | 	} | 
| 5376 |  | 
| 5377 | 	Ref<GLTFMesh> gltf_mesh; | 
| 5378 | 	gltf_mesh.instantiate(); | 
| 5379 | 	TypedArray<Material> instance_materials; | 
| 5380 | 	for (int32_t surface_i = 0; surface_i < current_mesh->get_surface_count(); surface_i++) { | 
| 5381 | 		Ref<Material> mat = current_mesh->get_surface_material(surface_i); | 
| 5382 | 		if (p_mesh_instance->get_surface_override_material(surface_i).is_valid()) { | 
| 5383 | 			mat = p_mesh_instance->get_surface_override_material(surface_i); | 
| 5384 | 		} | 
| 5385 | 		if (p_mesh_instance->get_material_override().is_valid()) { | 
| 5386 | 			mat = p_mesh_instance->get_material_override(); | 
| 5387 | 		} | 
| 5388 | 		instance_materials.append(mat); | 
| 5389 | 	} | 
| 5390 | 	gltf_mesh->set_instance_materials(instance_materials); | 
| 5391 | 	gltf_mesh->set_mesh(current_mesh); | 
| 5392 | 	gltf_mesh->set_blend_weights(blend_weights); | 
| 5393 | 	GLTFMeshIndex mesh_i = p_state->meshes.size(); | 
| 5394 | 	p_state->meshes.push_back(gltf_mesh); | 
| 5395 | 	return mesh_i; | 
| 5396 | } | 
| 5397 |  | 
| 5398 | ImporterMeshInstance3D *GLTFDocument::_generate_mesh_instance(Ref<GLTFState> p_state, const GLTFNodeIndex p_node_index) { | 
| 5399 | 	Ref<GLTFNode> gltf_node = p_state->nodes[p_node_index]; | 
| 5400 |  | 
| 5401 | 	ERR_FAIL_INDEX_V(gltf_node->mesh, p_state->meshes.size(), nullptr); | 
| 5402 |  | 
| 5403 | 	ImporterMeshInstance3D *mi = memnew(ImporterMeshInstance3D); | 
| 5404 | 	print_verbose("glTF: Creating mesh for: "  + gltf_node->get_name()); | 
| 5405 |  | 
| 5406 | 	p_state->scene_mesh_instances.insert(p_node_index, mi); | 
| 5407 | 	Ref<GLTFMesh> mesh = p_state->meshes.write[gltf_node->mesh]; | 
| 5408 | 	if (mesh.is_null()) { | 
| 5409 | 		return mi; | 
| 5410 | 	} | 
| 5411 | 	Ref<ImporterMesh> import_mesh = mesh->get_mesh(); | 
| 5412 | 	if (import_mesh.is_null()) { | 
| 5413 | 		return mi; | 
| 5414 | 	} | 
| 5415 | 	mi->set_mesh(import_mesh); | 
| 5416 | 	return mi; | 
| 5417 | } | 
| 5418 |  | 
| 5419 | Light3D *GLTFDocument::_generate_light(Ref<GLTFState> p_state, const GLTFNodeIndex p_node_index) { | 
| 5420 | 	Ref<GLTFNode> gltf_node = p_state->nodes[p_node_index]; | 
| 5421 |  | 
| 5422 | 	ERR_FAIL_INDEX_V(gltf_node->light, p_state->lights.size(), nullptr); | 
| 5423 |  | 
| 5424 | 	print_verbose("glTF: Creating light for: "  + gltf_node->get_name()); | 
| 5425 |  | 
| 5426 | 	Ref<GLTFLight> l = p_state->lights[gltf_node->light]; | 
| 5427 | 	return l->to_node(); | 
| 5428 | } | 
| 5429 |  | 
| 5430 | Camera3D *GLTFDocument::_generate_camera(Ref<GLTFState> p_state, const GLTFNodeIndex p_node_index) { | 
| 5431 | 	Ref<GLTFNode> gltf_node = p_state->nodes[p_node_index]; | 
| 5432 |  | 
| 5433 | 	ERR_FAIL_INDEX_V(gltf_node->camera, p_state->cameras.size(), nullptr); | 
| 5434 |  | 
| 5435 | 	print_verbose("glTF: Creating camera for: "  + gltf_node->get_name()); | 
| 5436 |  | 
| 5437 | 	Ref<GLTFCamera> c = p_state->cameras[gltf_node->camera]; | 
| 5438 | 	return c->to_node(); | 
| 5439 | } | 
| 5440 |  | 
| 5441 | GLTFCameraIndex GLTFDocument::_convert_camera(Ref<GLTFState> p_state, Camera3D *p_camera) { | 
| 5442 | 	print_verbose("glTF: Converting camera: "  + p_camera->get_name()); | 
| 5443 |  | 
| 5444 | 	Ref<GLTFCamera> c = GLTFCamera::from_node(p_camera); | 
| 5445 | 	GLTFCameraIndex camera_index = p_state->cameras.size(); | 
| 5446 | 	p_state->cameras.push_back(c); | 
| 5447 | 	return camera_index; | 
| 5448 | } | 
| 5449 |  | 
| 5450 | GLTFLightIndex GLTFDocument::_convert_light(Ref<GLTFState> p_state, Light3D *p_light) { | 
| 5451 | 	print_verbose("glTF: Converting light: "  + p_light->get_name()); | 
| 5452 |  | 
| 5453 | 	Ref<GLTFLight> l = GLTFLight::from_node(p_light); | 
| 5454 |  | 
| 5455 | 	GLTFLightIndex light_index = p_state->lights.size(); | 
| 5456 | 	p_state->lights.push_back(l); | 
| 5457 | 	return light_index; | 
| 5458 | } | 
| 5459 |  | 
| 5460 | void GLTFDocument::_convert_spatial(Ref<GLTFState> p_state, Node3D *p_spatial, Ref<GLTFNode> p_node) { | 
| 5461 | 	Transform3D xform = p_spatial->get_transform(); | 
| 5462 | 	p_node->scale = xform.basis.get_scale(); | 
| 5463 | 	p_node->rotation = xform.basis.get_rotation_quaternion(); | 
| 5464 | 	p_node->position = xform.origin; | 
| 5465 | } | 
| 5466 |  | 
| 5467 | Node3D *GLTFDocument::_generate_spatial(Ref<GLTFState> p_state, const GLTFNodeIndex p_node_index) { | 
| 5468 | 	Ref<GLTFNode> gltf_node = p_state->nodes[p_node_index]; | 
| 5469 |  | 
| 5470 | 	Node3D *spatial = memnew(Node3D); | 
| 5471 | 	print_verbose("glTF: Converting spatial: "  + gltf_node->get_name()); | 
| 5472 |  | 
| 5473 | 	return spatial; | 
| 5474 | } | 
| 5475 |  | 
| 5476 | void GLTFDocument::_convert_scene_node(Ref<GLTFState> p_state, Node *p_current, const GLTFNodeIndex p_gltf_parent, const GLTFNodeIndex p_gltf_root) { | 
| 5477 | 	bool retflag = true; | 
| 5478 | 	_check_visibility(p_current, retflag); | 
| 5479 | 	if (retflag) { | 
| 5480 | 		return; | 
| 5481 | 	} | 
| 5482 | 	Ref<GLTFNode> gltf_node; | 
| 5483 | 	gltf_node.instantiate(); | 
| 5484 | 	gltf_node->set_name(_gen_unique_name(p_state, p_current->get_name())); | 
| 5485 | 	if (cast_to<Node3D>(p_current)) { | 
| 5486 | 		Node3D *spatial = cast_to<Node3D>(p_current); | 
| 5487 | 		_convert_spatial(p_state, spatial, gltf_node); | 
| 5488 | 	} | 
| 5489 | 	if (cast_to<MeshInstance3D>(p_current)) { | 
| 5490 | 		MeshInstance3D *mi = cast_to<MeshInstance3D>(p_current); | 
| 5491 | 		_convert_mesh_instance_to_gltf(mi, p_state, gltf_node); | 
| 5492 | 	} else if (cast_to<BoneAttachment3D>(p_current)) { | 
| 5493 | 		BoneAttachment3D *bone = cast_to<BoneAttachment3D>(p_current); | 
| 5494 | 		_convert_bone_attachment_to_gltf(bone, p_state, p_gltf_parent, p_gltf_root, gltf_node); | 
| 5495 | 		return; | 
| 5496 | 	} else if (cast_to<Skeleton3D>(p_current)) { | 
| 5497 | 		Skeleton3D *skel = cast_to<Skeleton3D>(p_current); | 
| 5498 | 		_convert_skeleton_to_gltf(skel, p_state, p_gltf_parent, p_gltf_root, gltf_node); | 
| 5499 | 		// We ignore the Godot Engine node that is the skeleton. | 
| 5500 | 		return; | 
| 5501 | 	} else if (cast_to<MultiMeshInstance3D>(p_current)) { | 
| 5502 | 		MultiMeshInstance3D *multi = cast_to<MultiMeshInstance3D>(p_current); | 
| 5503 | 		_convert_multi_mesh_instance_to_gltf(multi, p_gltf_parent, p_gltf_root, gltf_node, p_state); | 
| 5504 | #ifdef MODULE_CSG_ENABLED | 
| 5505 | 	} else if (cast_to<CSGShape3D>(p_current)) { | 
| 5506 | 		CSGShape3D *shape = cast_to<CSGShape3D>(p_current); | 
| 5507 | 		if (shape->get_parent() && shape->is_root_shape()) { | 
| 5508 | 			_convert_csg_shape_to_gltf(shape, p_gltf_parent, gltf_node, p_state); | 
| 5509 | 		} | 
| 5510 | #endif // MODULE_CSG_ENABLED | 
| 5511 | #ifdef MODULE_GRIDMAP_ENABLED | 
| 5512 | 	} else if (cast_to<GridMap>(p_current)) { | 
| 5513 | 		GridMap *gridmap = Object::cast_to<GridMap>(p_current); | 
| 5514 | 		_convert_grid_map_to_gltf(gridmap, p_gltf_parent, p_gltf_root, gltf_node, p_state); | 
| 5515 | #endif // MODULE_GRIDMAP_ENABLED | 
| 5516 | 	} else if (cast_to<Camera3D>(p_current)) { | 
| 5517 | 		Camera3D *camera = Object::cast_to<Camera3D>(p_current); | 
| 5518 | 		_convert_camera_to_gltf(camera, p_state, gltf_node); | 
| 5519 | 	} else if (cast_to<Light3D>(p_current)) { | 
| 5520 | 		Light3D *light = Object::cast_to<Light3D>(p_current); | 
| 5521 | 		_convert_light_to_gltf(light, p_state, gltf_node); | 
| 5522 | 	} else if (cast_to<AnimationPlayer>(p_current)) { | 
| 5523 | 		AnimationPlayer *animation_player = Object::cast_to<AnimationPlayer>(p_current); | 
| 5524 | 		_convert_animation_player_to_gltf(animation_player, p_state, p_gltf_parent, p_gltf_root, gltf_node, p_current); | 
| 5525 | 	} | 
| 5526 | 	for (Ref<GLTFDocumentExtension> ext : document_extensions) { | 
| 5527 | 		ERR_CONTINUE(ext.is_null()); | 
| 5528 | 		ext->convert_scene_node(p_state, gltf_node, p_current); | 
| 5529 | 	} | 
| 5530 | 	GLTFNodeIndex current_node_i = p_state->nodes.size(); | 
| 5531 | 	GLTFNodeIndex gltf_root = p_gltf_root; | 
| 5532 | 	if (gltf_root == -1) { | 
| 5533 | 		gltf_root = current_node_i; | 
| 5534 | 		p_state->root_nodes.push_back(gltf_root); | 
| 5535 | 	} | 
| 5536 | 	_create_gltf_node(p_state, p_current, current_node_i, p_gltf_parent, gltf_root, gltf_node); | 
| 5537 | 	for (int node_i = 0; node_i < p_current->get_child_count(); node_i++) { | 
| 5538 | 		_convert_scene_node(p_state, p_current->get_child(node_i), current_node_i, gltf_root); | 
| 5539 | 	} | 
| 5540 | } | 
| 5541 |  | 
| 5542 | #ifdef MODULE_CSG_ENABLED | 
| 5543 | void GLTFDocument::_convert_csg_shape_to_gltf(CSGShape3D *p_current, GLTFNodeIndex p_gltf_parent, Ref<GLTFNode> p_gltf_node, Ref<GLTFState> p_state) { | 
| 5544 | 	CSGShape3D *csg = p_current; | 
| 5545 | 	csg->call("_update_shape" ); | 
| 5546 | 	Array meshes = csg->get_meshes(); | 
| 5547 | 	if (meshes.size() != 2) { | 
| 5548 | 		return; | 
| 5549 | 	} | 
| 5550 |  | 
| 5551 | 	Ref<ImporterMesh> mesh; | 
| 5552 | 	mesh.instantiate(); | 
| 5553 | 	{ | 
| 5554 | 		Ref<Mesh> csg_mesh = csg->get_meshes()[1]; | 
| 5555 |  | 
| 5556 | 		for (int32_t surface_i = 0; surface_i < csg_mesh->get_surface_count(); surface_i++) { | 
| 5557 | 			Array array = csg_mesh->surface_get_arrays(surface_i); | 
| 5558 | 			Ref<Material> mat = csg_mesh->surface_get_material(surface_i); | 
| 5559 | 			String mat_name; | 
| 5560 | 			if (mat.is_valid()) { | 
| 5561 | 				mat_name = mat->get_name(); | 
| 5562 | 			} else { | 
| 5563 | 				// Assign default material when no material is assigned. | 
| 5564 | 				mat = Ref<StandardMaterial3D>(memnew(StandardMaterial3D)); | 
| 5565 | 			} | 
| 5566 | 			mesh->add_surface(csg_mesh->surface_get_primitive_type(surface_i), | 
| 5567 | 					array, csg_mesh->surface_get_blend_shape_arrays(surface_i), csg_mesh->surface_get_lods(surface_i), mat, | 
| 5568 | 					mat_name, csg_mesh->surface_get_format(surface_i)); | 
| 5569 | 		} | 
| 5570 | 	} | 
| 5571 |  | 
| 5572 | 	Ref<GLTFMesh> gltf_mesh; | 
| 5573 | 	gltf_mesh.instantiate(); | 
| 5574 | 	gltf_mesh->set_mesh(mesh); | 
| 5575 | 	GLTFMeshIndex mesh_i = p_state->meshes.size(); | 
| 5576 | 	p_state->meshes.push_back(gltf_mesh); | 
| 5577 | 	p_gltf_node->mesh = mesh_i; | 
| 5578 | 	p_gltf_node->xform = csg->get_meshes()[0]; | 
| 5579 | 	p_gltf_node->set_name(_gen_unique_name(p_state, csg->get_name())); | 
| 5580 | } | 
| 5581 | #endif // MODULE_CSG_ENABLED | 
| 5582 |  | 
| 5583 | void GLTFDocument::_create_gltf_node(Ref<GLTFState> p_state, Node *p_scene_parent, GLTFNodeIndex p_current_node_i, | 
| 5584 | 		GLTFNodeIndex p_parent_node_index, GLTFNodeIndex p_root_gltf_node, Ref<GLTFNode> p_gltf_node) { | 
| 5585 | 	p_state->scene_nodes.insert(p_current_node_i, p_scene_parent); | 
| 5586 | 	p_state->nodes.push_back(p_gltf_node); | 
| 5587 | 	ERR_FAIL_COND(p_current_node_i == p_parent_node_index); | 
| 5588 | 	p_state->nodes.write[p_current_node_i]->parent = p_parent_node_index; | 
| 5589 | 	if (p_parent_node_index == -1) { | 
| 5590 | 		return; | 
| 5591 | 	} | 
| 5592 | 	p_state->nodes.write[p_parent_node_index]->children.push_back(p_current_node_i); | 
| 5593 | } | 
| 5594 |  | 
| 5595 | void GLTFDocument::_convert_animation_player_to_gltf(AnimationPlayer *p_animation_player, Ref<GLTFState> p_state, GLTFNodeIndex p_gltf_current, GLTFNodeIndex p_gltf_root_index, Ref<GLTFNode> p_gltf_node, Node *p_scene_parent) { | 
| 5596 | 	ERR_FAIL_COND(!p_animation_player); | 
| 5597 | 	p_state->animation_players.push_back(p_animation_player); | 
| 5598 | 	print_verbose(String("glTF: Converting animation player: " ) + p_animation_player->get_name()); | 
| 5599 | } | 
| 5600 |  | 
| 5601 | void GLTFDocument::_check_visibility(Node *p_node, bool &r_retflag) { | 
| 5602 | 	r_retflag = true; | 
| 5603 | 	Node3D *spatial = Object::cast_to<Node3D>(p_node); | 
| 5604 | 	Node2D *node_2d = Object::cast_to<Node2D>(p_node); | 
| 5605 | 	if (node_2d && !node_2d->is_visible()) { | 
| 5606 | 		return; | 
| 5607 | 	} | 
| 5608 | 	if (spatial && !spatial->is_visible()) { | 
| 5609 | 		return; | 
| 5610 | 	} | 
| 5611 | 	r_retflag = false; | 
| 5612 | } | 
| 5613 |  | 
| 5614 | void GLTFDocument::_convert_camera_to_gltf(Camera3D *camera, Ref<GLTFState> p_state, Ref<GLTFNode> p_gltf_node) { | 
| 5615 | 	ERR_FAIL_COND(!camera); | 
| 5616 | 	GLTFCameraIndex camera_index = _convert_camera(p_state, camera); | 
| 5617 | 	if (camera_index != -1) { | 
| 5618 | 		p_gltf_node->camera = camera_index; | 
| 5619 | 	} | 
| 5620 | } | 
| 5621 |  | 
| 5622 | void GLTFDocument::_convert_light_to_gltf(Light3D *light, Ref<GLTFState> p_state, Ref<GLTFNode> p_gltf_node) { | 
| 5623 | 	ERR_FAIL_COND(!light); | 
| 5624 | 	GLTFLightIndex light_index = _convert_light(p_state, light); | 
| 5625 | 	if (light_index != -1) { | 
| 5626 | 		p_gltf_node->light = light_index; | 
| 5627 | 	} | 
| 5628 | } | 
| 5629 |  | 
| 5630 | #ifdef MODULE_GRIDMAP_ENABLED | 
| 5631 | void GLTFDocument::_convert_grid_map_to_gltf(GridMap *p_grid_map, GLTFNodeIndex p_parent_node_index, GLTFNodeIndex p_root_node_index, Ref<GLTFNode> p_gltf_node, Ref<GLTFState> p_state) { | 
| 5632 | 	Array cells = p_grid_map->get_used_cells(); | 
| 5633 | 	for (int32_t k = 0; k < cells.size(); k++) { | 
| 5634 | 		GLTFNode *new_gltf_node = memnew(GLTFNode); | 
| 5635 | 		p_gltf_node->children.push_back(p_state->nodes.size()); | 
| 5636 | 		p_state->nodes.push_back(new_gltf_node); | 
| 5637 | 		Vector3 cell_location = cells[k]; | 
| 5638 | 		int32_t cell = p_grid_map->get_cell_item( | 
| 5639 | 				Vector3(cell_location.x, cell_location.y, cell_location.z)); | 
| 5640 | 		Transform3D cell_xform; | 
| 5641 | 		cell_xform.basis = p_grid_map->get_basis_with_orthogonal_index( | 
| 5642 | 				p_grid_map->get_cell_item_orientation( | 
| 5643 | 						Vector3(cell_location.x, cell_location.y, cell_location.z))); | 
| 5644 | 		cell_xform.basis.scale(Vector3(p_grid_map->get_cell_scale(), | 
| 5645 | 				p_grid_map->get_cell_scale(), | 
| 5646 | 				p_grid_map->get_cell_scale())); | 
| 5647 | 		cell_xform.set_origin(p_grid_map->map_to_local( | 
| 5648 | 				Vector3(cell_location.x, cell_location.y, cell_location.z))); | 
| 5649 | 		Ref<GLTFMesh> gltf_mesh; | 
| 5650 | 		gltf_mesh.instantiate(); | 
| 5651 | 		gltf_mesh->set_mesh(_mesh_to_importer_mesh(p_grid_map->get_mesh_library()->get_item_mesh(cell))); | 
| 5652 | 		new_gltf_node->mesh = p_state->meshes.size(); | 
| 5653 | 		p_state->meshes.push_back(gltf_mesh); | 
| 5654 | 		new_gltf_node->xform = cell_xform * p_grid_map->get_transform(); | 
| 5655 | 		new_gltf_node->set_name(_gen_unique_name(p_state, p_grid_map->get_mesh_library()->get_item_name(cell))); | 
| 5656 | 	} | 
| 5657 | } | 
| 5658 | #endif // MODULE_GRIDMAP_ENABLED | 
| 5659 |  | 
| 5660 | void GLTFDocument::_convert_multi_mesh_instance_to_gltf( | 
| 5661 | 		MultiMeshInstance3D *p_multi_mesh_instance, | 
| 5662 | 		GLTFNodeIndex p_parent_node_index, | 
| 5663 | 		GLTFNodeIndex p_root_node_index, | 
| 5664 | 		Ref<GLTFNode> p_gltf_node, Ref<GLTFState> p_state) { | 
| 5665 | 	ERR_FAIL_COND(!p_multi_mesh_instance); | 
| 5666 | 	Ref<MultiMesh> multi_mesh = p_multi_mesh_instance->get_multimesh(); | 
| 5667 | 	if (multi_mesh.is_null()) { | 
| 5668 | 		return; | 
| 5669 | 	} | 
| 5670 | 	Ref<GLTFMesh> gltf_mesh; | 
| 5671 | 	gltf_mesh.instantiate(); | 
| 5672 | 	Ref<Mesh> mesh = multi_mesh->get_mesh(); | 
| 5673 | 	if (mesh.is_null()) { | 
| 5674 | 		return; | 
| 5675 | 	} | 
| 5676 | 	gltf_mesh->set_name(multi_mesh->get_name()); | 
| 5677 | 	Ref<ImporterMesh> importer_mesh; | 
| 5678 | 	importer_mesh.instantiate(); | 
| 5679 | 	Ref<ArrayMesh> array_mesh = multi_mesh->get_mesh(); | 
| 5680 | 	if (array_mesh.is_valid()) { | 
| 5681 | 		importer_mesh->set_blend_shape_mode(array_mesh->get_blend_shape_mode()); | 
| 5682 | 		for (int32_t blend_i = 0; blend_i < array_mesh->get_blend_shape_count(); blend_i++) { | 
| 5683 | 			importer_mesh->add_blend_shape(array_mesh->get_blend_shape_name(blend_i)); | 
| 5684 | 		} | 
| 5685 | 	} | 
| 5686 | 	for (int32_t surface_i = 0; surface_i < mesh->get_surface_count(); surface_i++) { | 
| 5687 | 		Ref<Material> mat = mesh->surface_get_material(surface_i); | 
| 5688 | 		String material_name; | 
| 5689 | 		if (mat.is_valid()) { | 
| 5690 | 			material_name = mat->get_name(); | 
| 5691 | 		} | 
| 5692 | 		Array blend_arrays; | 
| 5693 | 		if (array_mesh.is_valid()) { | 
| 5694 | 			blend_arrays = array_mesh->surface_get_blend_shape_arrays(surface_i); | 
| 5695 | 		} | 
| 5696 | 		importer_mesh->add_surface(mesh->surface_get_primitive_type(surface_i), mesh->surface_get_arrays(surface_i), | 
| 5697 | 				blend_arrays, mesh->surface_get_lods(surface_i), mat, material_name, mesh->surface_get_format(surface_i)); | 
| 5698 | 	} | 
| 5699 | 	gltf_mesh->set_mesh(importer_mesh); | 
| 5700 | 	GLTFMeshIndex mesh_index = p_state->meshes.size(); | 
| 5701 | 	p_state->meshes.push_back(gltf_mesh); | 
| 5702 | 	for (int32_t instance_i = 0; instance_i < multi_mesh->get_instance_count(); | 
| 5703 | 			instance_i++) { | 
| 5704 | 		Transform3D transform; | 
| 5705 | 		if (multi_mesh->get_transform_format() == MultiMesh::TRANSFORM_2D) { | 
| 5706 | 			Transform2D xform_2d = multi_mesh->get_instance_transform_2d(instance_i); | 
| 5707 | 			transform.origin = | 
| 5708 | 					Vector3(xform_2d.get_origin().x, 0, xform_2d.get_origin().y); | 
| 5709 | 			real_t rotation = xform_2d.get_rotation(); | 
| 5710 | 			Quaternion quaternion(Vector3(0, 1, 0), rotation); | 
| 5711 | 			Size2 scale = xform_2d.get_scale(); | 
| 5712 | 			transform.basis.set_quaternion_scale(quaternion, | 
| 5713 | 					Vector3(scale.x, 0, scale.y)); | 
| 5714 | 			transform = p_multi_mesh_instance->get_transform() * transform; | 
| 5715 | 		} else if (multi_mesh->get_transform_format() == MultiMesh::TRANSFORM_3D) { | 
| 5716 | 			transform = p_multi_mesh_instance->get_transform() * | 
| 5717 | 					multi_mesh->get_instance_transform(instance_i); | 
| 5718 | 		} | 
| 5719 | 		Ref<GLTFNode> new_gltf_node; | 
| 5720 | 		new_gltf_node.instantiate(); | 
| 5721 | 		new_gltf_node->mesh = mesh_index; | 
| 5722 | 		new_gltf_node->xform = transform; | 
| 5723 | 		new_gltf_node->set_name(_gen_unique_name(p_state, p_multi_mesh_instance->get_name())); | 
| 5724 | 		p_gltf_node->children.push_back(p_state->nodes.size()); | 
| 5725 | 		p_state->nodes.push_back(new_gltf_node); | 
| 5726 | 	} | 
| 5727 | } | 
| 5728 |  | 
| 5729 | void GLTFDocument::_convert_skeleton_to_gltf(Skeleton3D *p_skeleton3d, Ref<GLTFState> p_state, GLTFNodeIndex p_parent_node_index, GLTFNodeIndex p_root_node_index, Ref<GLTFNode> p_gltf_node) { | 
| 5730 | 	Skeleton3D *skeleton = p_skeleton3d; | 
| 5731 | 	Ref<GLTFSkeleton> gltf_skeleton; | 
| 5732 | 	gltf_skeleton.instantiate(); | 
| 5733 | 	// GLTFSkeleton is only used to hold internal p_state data. It will not be written to the document. | 
| 5734 | 	// | 
| 5735 | 	gltf_skeleton->godot_skeleton = skeleton; | 
| 5736 | 	GLTFSkeletonIndex skeleton_i = p_state->skeletons.size(); | 
| 5737 | 	p_state->skeleton3d_to_gltf_skeleton[skeleton->get_instance_id()] = skeleton_i; | 
| 5738 | 	p_state->skeletons.push_back(gltf_skeleton); | 
| 5739 |  | 
| 5740 | 	BoneId bone_count = skeleton->get_bone_count(); | 
| 5741 | 	for (BoneId bone_i = 0; bone_i < bone_count; bone_i++) { | 
| 5742 | 		Ref<GLTFNode> joint_node; | 
| 5743 | 		joint_node.instantiate(); | 
| 5744 | 		// Note that we cannot use _gen_unique_bone_name here, because glTF spec requires all node | 
| 5745 | 		// names to be unique regardless of whether or not they are used as joints. | 
| 5746 | 		joint_node->set_name(_gen_unique_name(p_state, skeleton->get_bone_name(bone_i))); | 
| 5747 | 		Transform3D xform = skeleton->get_bone_pose(bone_i); | 
| 5748 | 		joint_node->scale = xform.basis.get_scale(); | 
| 5749 | 		joint_node->rotation = xform.basis.get_rotation_quaternion(); | 
| 5750 | 		joint_node->position = xform.origin; | 
| 5751 | 		joint_node->joint = true; | 
| 5752 | 		GLTFNodeIndex current_node_i = p_state->nodes.size(); | 
| 5753 | 		p_state->scene_nodes.insert(current_node_i, skeleton); | 
| 5754 | 		p_state->nodes.push_back(joint_node); | 
| 5755 |  | 
| 5756 | 		gltf_skeleton->joints.push_back(current_node_i); | 
| 5757 | 		if (skeleton->get_bone_parent(bone_i) == -1) { | 
| 5758 | 			gltf_skeleton->roots.push_back(current_node_i); | 
| 5759 | 		} | 
| 5760 | 		gltf_skeleton->godot_bone_node.insert(bone_i, current_node_i); | 
| 5761 | 	} | 
| 5762 | 	for (BoneId bone_i = 0; bone_i < bone_count; bone_i++) { | 
| 5763 | 		GLTFNodeIndex current_node_i = gltf_skeleton->godot_bone_node[bone_i]; | 
| 5764 | 		BoneId parent_bone_id = skeleton->get_bone_parent(bone_i); | 
| 5765 | 		if (parent_bone_id == -1) { | 
| 5766 | 			if (p_parent_node_index != -1) { | 
| 5767 | 				p_state->nodes.write[current_node_i]->parent = p_parent_node_index; | 
| 5768 | 				p_state->nodes.write[p_parent_node_index]->children.push_back(current_node_i); | 
| 5769 | 			} | 
| 5770 | 		} else { | 
| 5771 | 			GLTFNodeIndex parent_node_i = gltf_skeleton->godot_bone_node[parent_bone_id]; | 
| 5772 | 			p_state->nodes.write[current_node_i]->parent = parent_node_i; | 
| 5773 | 			p_state->nodes.write[parent_node_i]->children.push_back(current_node_i); | 
| 5774 | 		} | 
| 5775 | 	} | 
| 5776 | 	// Remove placeholder skeleton3d node by not creating the gltf node | 
| 5777 | 	// Skins are per mesh | 
| 5778 | 	for (int node_i = 0; node_i < skeleton->get_child_count(); node_i++) { | 
| 5779 | 		_convert_scene_node(p_state, skeleton->get_child(node_i), p_parent_node_index, p_root_node_index); | 
| 5780 | 	} | 
| 5781 | } | 
| 5782 |  | 
| 5783 | void GLTFDocument::_convert_bone_attachment_to_gltf(BoneAttachment3D *p_bone_attachment, Ref<GLTFState> p_state, GLTFNodeIndex p_parent_node_index, GLTFNodeIndex p_root_node_index, Ref<GLTFNode> p_gltf_node) { | 
| 5784 | 	Skeleton3D *skeleton; | 
| 5785 | 	// Note that relative transforms to external skeletons and pose overrides are not supported. | 
| 5786 | 	if (p_bone_attachment->get_use_external_skeleton()) { | 
| 5787 | 		skeleton = cast_to<Skeleton3D>(p_bone_attachment->get_node_or_null(p_bone_attachment->get_external_skeleton())); | 
| 5788 | 	} else { | 
| 5789 | 		skeleton = cast_to<Skeleton3D>(p_bone_attachment->get_parent()); | 
| 5790 | 	} | 
| 5791 | 	GLTFSkeletonIndex skel_gltf_i = -1; | 
| 5792 | 	if (skeleton != nullptr && p_state->skeleton3d_to_gltf_skeleton.has(skeleton->get_instance_id())) { | 
| 5793 | 		skel_gltf_i = p_state->skeleton3d_to_gltf_skeleton[skeleton->get_instance_id()]; | 
| 5794 | 	} | 
| 5795 | 	int bone_idx = -1; | 
| 5796 | 	if (skeleton != nullptr) { | 
| 5797 | 		bone_idx = p_bone_attachment->get_bone_idx(); | 
| 5798 | 		if (bone_idx == -1) { | 
| 5799 | 			bone_idx = skeleton->find_bone(p_bone_attachment->get_bone_name()); | 
| 5800 | 		} | 
| 5801 | 	} | 
| 5802 | 	GLTFNodeIndex par_node_index = p_parent_node_index; | 
| 5803 | 	if (skeleton != nullptr && bone_idx != -1 && skel_gltf_i != -1) { | 
| 5804 | 		Ref<GLTFSkeleton> gltf_skeleton = p_state->skeletons.write[skel_gltf_i]; | 
| 5805 | 		gltf_skeleton->bone_attachments.push_back(p_bone_attachment); | 
| 5806 | 		par_node_index = gltf_skeleton->joints[bone_idx]; | 
| 5807 | 	} | 
| 5808 |  | 
| 5809 | 	for (int node_i = 0; node_i < p_bone_attachment->get_child_count(); node_i++) { | 
| 5810 | 		_convert_scene_node(p_state, p_bone_attachment->get_child(node_i), par_node_index, p_root_node_index); | 
| 5811 | 	} | 
| 5812 | } | 
| 5813 |  | 
| 5814 | void GLTFDocument::_convert_mesh_instance_to_gltf(MeshInstance3D *p_scene_parent, Ref<GLTFState> p_state, Ref<GLTFNode> p_gltf_node) { | 
| 5815 | 	GLTFMeshIndex gltf_mesh_index = _convert_mesh_to_gltf(p_state, p_scene_parent); | 
| 5816 | 	if (gltf_mesh_index != -1) { | 
| 5817 | 		p_gltf_node->mesh = gltf_mesh_index; | 
| 5818 | 	} | 
| 5819 | } | 
| 5820 |  | 
| 5821 | void GLTFDocument::_generate_scene_node(Ref<GLTFState> p_state, const GLTFNodeIndex p_node_index, Node *p_scene_parent, Node *p_scene_root) { | 
| 5822 | 	Ref<GLTFNode> gltf_node = p_state->nodes[p_node_index]; | 
| 5823 |  | 
| 5824 | 	if (gltf_node->skeleton >= 0) { | 
| 5825 | 		_generate_skeleton_bone_node(p_state, p_node_index, p_scene_parent, p_scene_root); | 
| 5826 | 		return; | 
| 5827 | 	} | 
| 5828 |  | 
| 5829 | 	Node3D *current_node = nullptr; | 
| 5830 |  | 
| 5831 | 	// Is our parent a skeleton | 
| 5832 | 	Skeleton3D *active_skeleton = Object::cast_to<Skeleton3D>(p_scene_parent); | 
| 5833 |  | 
| 5834 | 	const bool non_bone_parented_to_skeleton = active_skeleton; | 
| 5835 |  | 
| 5836 | 	// skinned meshes must not be placed in a bone attachment. | 
| 5837 | 	if (non_bone_parented_to_skeleton && gltf_node->skin < 0) { | 
| 5838 | 		// Bone Attachment - Parent Case | 
| 5839 | 		BoneAttachment3D *bone_attachment = _generate_bone_attachment(p_state, active_skeleton, p_node_index, gltf_node->parent); | 
| 5840 |  | 
| 5841 | 		p_scene_parent->add_child(bone_attachment, true); | 
| 5842 | 		bone_attachment->set_owner(p_scene_root); | 
| 5843 |  | 
| 5844 | 		// There is no gltf_node that represent this, so just directly create a unique name | 
| 5845 | 		bone_attachment->set_name(gltf_node->get_name()); | 
| 5846 |  | 
| 5847 | 		// We change the scene_parent to our bone attachment now. We do not set current_node because we want to make the node | 
| 5848 | 		// and attach it to the bone_attachment | 
| 5849 | 		p_scene_parent = bone_attachment; | 
| 5850 | 	} | 
| 5851 | 	// Check if any GLTFDocumentExtension classes want to generate a node for us. | 
| 5852 | 	for (Ref<GLTFDocumentExtension> ext : document_extensions) { | 
| 5853 | 		ERR_CONTINUE(ext.is_null()); | 
| 5854 | 		current_node = ext->generate_scene_node(p_state, gltf_node, p_scene_parent); | 
| 5855 | 		if (current_node) { | 
| 5856 | 			break; | 
| 5857 | 		} | 
| 5858 | 	} | 
| 5859 | 	// If none of our GLTFDocumentExtension classes generated us a node, we generate one. | 
| 5860 | 	if (!current_node) { | 
| 5861 | 		if (gltf_node->skin >= 0 && gltf_node->mesh >= 0 && !gltf_node->children.is_empty()) { | 
| 5862 | 			// GLTF specifies that skinned meshes should ignore their node transforms, | 
| 5863 | 			// only being controlled by the skeleton, so Godot will reparent a skinned | 
| 5864 | 			// mesh to its skeleton. However, we still need to ensure any child nodes | 
| 5865 | 			// keep their place in the tree, so if there are any child nodes, the skinned | 
| 5866 | 			// mesh must not be the base node, so generate an empty spatial base. | 
| 5867 | 			current_node = _generate_spatial(p_state, p_node_index); | 
| 5868 | 			Node3D *mesh_inst = _generate_mesh_instance(p_state, p_node_index); | 
| 5869 | 			mesh_inst->set_name(gltf_node->get_name()); | 
| 5870 | 			current_node->add_child(mesh_inst, true); | 
| 5871 | 		} else if (gltf_node->mesh >= 0) { | 
| 5872 | 			current_node = _generate_mesh_instance(p_state, p_node_index); | 
| 5873 | 		} else if (gltf_node->camera >= 0) { | 
| 5874 | 			current_node = _generate_camera(p_state, p_node_index); | 
| 5875 | 		} else if (gltf_node->light >= 0) { | 
| 5876 | 			current_node = _generate_light(p_state, p_node_index); | 
| 5877 | 		} else { | 
| 5878 | 			current_node = _generate_spatial(p_state, p_node_index); | 
| 5879 | 		} | 
| 5880 | 	} | 
| 5881 | 	String gltf_node_name = gltf_node->get_name(); | 
| 5882 | 	if (!gltf_node_name.is_empty()) { | 
| 5883 | 		current_node->set_name(gltf_node_name); | 
| 5884 | 	} | 
| 5885 | 	// Add the node we generated and set the owner to the scene root. | 
| 5886 | 	p_scene_parent->add_child(current_node, true); | 
| 5887 | 	if (current_node != p_scene_root) { | 
| 5888 | 		Array args; | 
| 5889 | 		args.append(p_scene_root); | 
| 5890 | 		current_node->propagate_call(StringName("set_owner" ), args); | 
| 5891 | 	} | 
| 5892 | 	current_node->set_transform(gltf_node->xform); | 
| 5893 |  | 
| 5894 | 	p_state->scene_nodes.insert(p_node_index, current_node); | 
| 5895 | 	for (int i = 0; i < gltf_node->children.size(); ++i) { | 
| 5896 | 		_generate_scene_node(p_state, gltf_node->children[i], current_node, p_scene_root); | 
| 5897 | 	} | 
| 5898 | } | 
| 5899 |  | 
| 5900 | void GLTFDocument::_generate_skeleton_bone_node(Ref<GLTFState> p_state, const GLTFNodeIndex p_node_index, Node *p_scene_parent, Node *p_scene_root) { | 
| 5901 | 	Ref<GLTFNode> gltf_node = p_state->nodes[p_node_index]; | 
| 5902 |  | 
| 5903 | 	Node3D *current_node = nullptr; | 
| 5904 |  | 
| 5905 | 	Skeleton3D *skeleton = p_state->skeletons[gltf_node->skeleton]->godot_skeleton; | 
| 5906 | 	// In this case, this node is already a bone in skeleton. | 
| 5907 | 	const bool is_skinned_mesh = (gltf_node->skin >= 0 && gltf_node->mesh >= 0); | 
| 5908 | 	const bool  = (gltf_node->mesh >= 0 || gltf_node->camera >= 0 || gltf_node->light >= 0); | 
| 5909 |  | 
| 5910 | 	Skeleton3D *active_skeleton = Object::cast_to<Skeleton3D>(p_scene_parent); | 
| 5911 | 	if (active_skeleton != skeleton) { | 
| 5912 | 		if (active_skeleton) { | 
| 5913 | 			// Should no longer be possible. | 
| 5914 | 			ERR_PRINT(vformat("glTF: Generating scene detected direct parented Skeletons at node %d" , p_node_index)); | 
| 5915 | 			BoneAttachment3D *bone_attachment = _generate_bone_attachment(p_state, active_skeleton, p_node_index, gltf_node->parent); | 
| 5916 | 			p_scene_parent->add_child(bone_attachment, true); | 
| 5917 | 			bone_attachment->set_owner(p_scene_root); | 
| 5918 | 			// There is no gltf_node that represent this, so just directly create a unique name | 
| 5919 | 			bone_attachment->set_name(_gen_unique_name(p_state, "BoneAttachment3D" )); | 
| 5920 | 			// We change the scene_parent to our bone attachment now. We do not set current_node because we want to make the node | 
| 5921 | 			// and attach it to the bone_attachment | 
| 5922 | 			p_scene_parent = bone_attachment; | 
| 5923 | 		} | 
| 5924 | 		if (skeleton->get_parent() == nullptr) { | 
| 5925 | 			p_scene_parent->add_child(skeleton, true); | 
| 5926 | 			skeleton->set_owner(p_scene_root); | 
| 5927 | 		} | 
| 5928 | 	} | 
| 5929 |  | 
| 5930 | 	active_skeleton = skeleton; | 
| 5931 | 	current_node = active_skeleton; | 
| 5932 |  | 
| 5933 | 	if (requires_extra_node) { | 
| 5934 | 		current_node = nullptr; | 
| 5935 | 		// skinned meshes must not be placed in a bone attachment. | 
| 5936 | 		if (!is_skinned_mesh) { | 
| 5937 | 			// Bone Attachment - Same Node Case | 
| 5938 | 			BoneAttachment3D *bone_attachment = _generate_bone_attachment(p_state, active_skeleton, p_node_index, p_node_index); | 
| 5939 |  | 
| 5940 | 			p_scene_parent->add_child(bone_attachment, true); | 
| 5941 | 			bone_attachment->set_owner(p_scene_root); | 
| 5942 |  | 
| 5943 | 			// There is no gltf_node that represent this, so just directly create a unique name | 
| 5944 | 			bone_attachment->set_name(gltf_node->get_name()); | 
| 5945 |  | 
| 5946 | 			// We change the scene_parent to our bone attachment now. We do not set current_node because we want to make the node | 
| 5947 | 			// and attach it to the bone_attachment | 
| 5948 | 			p_scene_parent = bone_attachment; | 
| 5949 | 		} | 
| 5950 | 		// Check if any GLTFDocumentExtension classes want to generate a node for us. | 
| 5951 | 		for (Ref<GLTFDocumentExtension> ext : document_extensions) { | 
| 5952 | 			ERR_CONTINUE(ext.is_null()); | 
| 5953 | 			current_node = ext->generate_scene_node(p_state, gltf_node, p_scene_parent); | 
| 5954 | 			if (current_node) { | 
| 5955 | 				break; | 
| 5956 | 			} | 
| 5957 | 		} | 
| 5958 | 		// If none of our GLTFDocumentExtension classes generated us a node, we generate one. | 
| 5959 | 		if (!current_node) { | 
| 5960 | 			if (gltf_node->mesh >= 0) { | 
| 5961 | 				current_node = _generate_mesh_instance(p_state, p_node_index); | 
| 5962 | 			} else if (gltf_node->camera >= 0) { | 
| 5963 | 				current_node = _generate_camera(p_state, p_node_index); | 
| 5964 | 			} else if (gltf_node->light >= 0) { | 
| 5965 | 				current_node = _generate_light(p_state, p_node_index); | 
| 5966 | 			} else { | 
| 5967 | 				current_node = _generate_spatial(p_state, p_node_index); | 
| 5968 | 			} | 
| 5969 | 		} | 
| 5970 | 		// Add the node we generated and set the owner to the scene root. | 
| 5971 | 		p_scene_parent->add_child(current_node, true); | 
| 5972 | 		if (current_node != p_scene_root) { | 
| 5973 | 			Array args; | 
| 5974 | 			args.append(p_scene_root); | 
| 5975 | 			current_node->propagate_call(StringName("set_owner" ), args); | 
| 5976 | 		} | 
| 5977 | 		// Do not set transform here. Transform is already applied to our bone. | 
| 5978 | 		current_node->set_name(gltf_node->get_name()); | 
| 5979 | 	} | 
| 5980 |  | 
| 5981 | 	p_state->scene_nodes.insert(p_node_index, current_node); | 
| 5982 |  | 
| 5983 | 	for (int i = 0; i < gltf_node->children.size(); ++i) { | 
| 5984 | 		_generate_scene_node(p_state, gltf_node->children[i], active_skeleton, p_scene_root); | 
| 5985 | 	} | 
| 5986 | } | 
| 5987 |  | 
| 5988 | template <class T> | 
| 5989 | struct SceneFormatImporterGLTFInterpolate { | 
| 5990 | 	T lerp(const T &a, const T &b, float c) const { | 
| 5991 | 		return a + (b - a) * c; | 
| 5992 | 	} | 
| 5993 |  | 
| 5994 | 	T catmull_rom(const T &p0, const T &p1, const T &p2, const T &p3, float t) { | 
| 5995 | 		const float t2 = t * t; | 
| 5996 | 		const float t3 = t2 * t; | 
| 5997 |  | 
| 5998 | 		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); | 
| 5999 | 	} | 
| 6000 |  | 
| 6001 | 	T bezier(T start, T control_1, T control_2, T end, float t) { | 
| 6002 | 		/* Formula from Wikipedia article on Bezier curves. */ | 
| 6003 | 		const real_t omt = (1.0 - t); | 
| 6004 | 		const real_t omt2 = omt * omt; | 
| 6005 | 		const real_t omt3 = omt2 * omt; | 
| 6006 | 		const real_t t2 = t * t; | 
| 6007 | 		const real_t t3 = t2 * t; | 
| 6008 |  | 
| 6009 | 		return start * omt3 + control_1 * omt2 * t * 3.0 + control_2 * omt * t2 * 3.0 + end * t3; | 
| 6010 | 	} | 
| 6011 | }; | 
| 6012 |  | 
| 6013 | // thank you for existing, partial specialization | 
| 6014 | template <> | 
| 6015 | struct SceneFormatImporterGLTFInterpolate<Quaternion> { | 
| 6016 | 	Quaternion lerp(const Quaternion &a, const Quaternion &b, const float c) const { | 
| 6017 | 		ERR_FAIL_COND_V_MSG(!a.is_normalized(), Quaternion(), "The quaternion \"a\" must be normalized." ); | 
| 6018 | 		ERR_FAIL_COND_V_MSG(!b.is_normalized(), Quaternion(), "The quaternion \"b\" must be normalized." ); | 
| 6019 |  | 
| 6020 | 		return a.slerp(b, c).normalized(); | 
| 6021 | 	} | 
| 6022 |  | 
| 6023 | 	Quaternion catmull_rom(const Quaternion &p0, const Quaternion &p1, const Quaternion &p2, const Quaternion &p3, const float c) { | 
| 6024 | 		ERR_FAIL_COND_V_MSG(!p1.is_normalized(), Quaternion(), "The quaternion \"p1\" must be normalized." ); | 
| 6025 | 		ERR_FAIL_COND_V_MSG(!p2.is_normalized(), Quaternion(), "The quaternion \"p2\" must be normalized." ); | 
| 6026 |  | 
| 6027 | 		return p1.slerp(p2, c).normalized(); | 
| 6028 | 	} | 
| 6029 |  | 
| 6030 | 	Quaternion bezier(const Quaternion start, const Quaternion control_1, const Quaternion control_2, const Quaternion end, const float t) { | 
| 6031 | 		ERR_FAIL_COND_V_MSG(!start.is_normalized(), Quaternion(), "The start quaternion must be normalized." ); | 
| 6032 | 		ERR_FAIL_COND_V_MSG(!end.is_normalized(), Quaternion(), "The end quaternion must be normalized." ); | 
| 6033 |  | 
| 6034 | 		return start.slerp(end, t).normalized(); | 
| 6035 | 	} | 
| 6036 | }; | 
| 6037 |  | 
| 6038 | template <class T> | 
| 6039 | T GLTFDocument::_interpolate_track(const Vector<real_t> &p_times, const Vector<T> &p_values, const float p_time, const GLTFAnimation::Interpolation p_interp) { | 
| 6040 | 	ERR_FAIL_COND_V(!p_values.size(), T()); | 
| 6041 | 	if (p_times.size() != (p_values.size() / (p_interp == GLTFAnimation::INTERP_CUBIC_SPLINE ? 3 : 1))) { | 
| 6042 | 		ERR_PRINT_ONCE("The interpolated values are not corresponding to its times." ); | 
| 6043 | 		return p_values[0]; | 
| 6044 | 	} | 
| 6045 | 	//could use binary search, worth it? | 
| 6046 | 	int idx = -1; | 
| 6047 | 	for (int i = 0; i < p_times.size(); i++) { | 
| 6048 | 		if (p_times[i] > p_time) { | 
| 6049 | 			break; | 
| 6050 | 		} | 
| 6051 | 		idx++; | 
| 6052 | 	} | 
| 6053 |  | 
| 6054 | 	SceneFormatImporterGLTFInterpolate<T> interp; | 
| 6055 |  | 
| 6056 | 	switch (p_interp) { | 
| 6057 | 		case GLTFAnimation::INTERP_LINEAR: { | 
| 6058 | 			if (idx == -1) { | 
| 6059 | 				return p_values[0]; | 
| 6060 | 			} else if (idx >= p_times.size() - 1) { | 
| 6061 | 				return p_values[p_times.size() - 1]; | 
| 6062 | 			} | 
| 6063 |  | 
| 6064 | 			const float c = (p_time - p_times[idx]) / (p_times[idx + 1] - p_times[idx]); | 
| 6065 |  | 
| 6066 | 			return interp.lerp(p_values[idx], p_values[idx + 1], c); | 
| 6067 | 		} break; | 
| 6068 | 		case GLTFAnimation::INTERP_STEP: { | 
| 6069 | 			if (idx == -1) { | 
| 6070 | 				return p_values[0]; | 
| 6071 | 			} else if (idx >= p_times.size() - 1) { | 
| 6072 | 				return p_values[p_times.size() - 1]; | 
| 6073 | 			} | 
| 6074 |  | 
| 6075 | 			return p_values[idx]; | 
| 6076 | 		} break; | 
| 6077 | 		case GLTFAnimation::INTERP_CATMULLROMSPLINE: { | 
| 6078 | 			if (idx == -1) { | 
| 6079 | 				return p_values[1]; | 
| 6080 | 			} else if (idx >= p_times.size() - 1) { | 
| 6081 | 				return p_values[1 + p_times.size() - 1]; | 
| 6082 | 			} | 
| 6083 |  | 
| 6084 | 			const float c = (p_time - p_times[idx]) / (p_times[idx + 1] - p_times[idx]); | 
| 6085 |  | 
| 6086 | 			return interp.catmull_rom(p_values[idx - 1], p_values[idx], p_values[idx + 1], p_values[idx + 3], c); | 
| 6087 | 		} break; | 
| 6088 | 		case GLTFAnimation::INTERP_CUBIC_SPLINE: { | 
| 6089 | 			if (idx == -1) { | 
| 6090 | 				return p_values[1]; | 
| 6091 | 			} else if (idx >= p_times.size() - 1) { | 
| 6092 | 				return p_values[(p_times.size() - 1) * 3 + 1]; | 
| 6093 | 			} | 
| 6094 |  | 
| 6095 | 			const float c = (p_time - p_times[idx]) / (p_times[idx + 1] - p_times[idx]); | 
| 6096 |  | 
| 6097 | 			const T from = p_values[idx * 3 + 1]; | 
| 6098 | 			const T c1 = from + p_values[idx * 3 + 2]; | 
| 6099 | 			const T to = p_values[idx * 3 + 4]; | 
| 6100 | 			const T c2 = to + p_values[idx * 3 + 3]; | 
| 6101 |  | 
| 6102 | 			return interp.bezier(from, c1, c2, to, c); | 
| 6103 | 		} break; | 
| 6104 | 	} | 
| 6105 |  | 
| 6106 | 	ERR_FAIL_V(p_values[0]); | 
| 6107 | } | 
| 6108 |  | 
| 6109 | void GLTFDocument::_import_animation(Ref<GLTFState> p_state, AnimationPlayer *p_animation_player, const GLTFAnimationIndex p_index, const float p_bake_fps, const bool p_trimming, const bool p_remove_immutable_tracks) { | 
| 6110 | 	Ref<GLTFAnimation> anim = p_state->animations[p_index]; | 
| 6111 |  | 
| 6112 | 	String anim_name = anim->get_name(); | 
| 6113 | 	if (anim_name.is_empty()) { | 
| 6114 | 		// No node represent these, and they are not in the hierarchy, so just make a unique name | 
| 6115 | 		anim_name = _gen_unique_name(p_state, "Animation" ); | 
| 6116 | 	} | 
| 6117 |  | 
| 6118 | 	Ref<Animation> animation; | 
| 6119 | 	animation.instantiate(); | 
| 6120 | 	animation->set_name(anim_name); | 
| 6121 |  | 
| 6122 | 	if (anim->get_loop()) { | 
| 6123 | 		animation->set_loop_mode(Animation::LOOP_LINEAR); | 
| 6124 | 	} | 
| 6125 |  | 
| 6126 | 	double anim_start = p_trimming ? INFINITY : 0.0; | 
| 6127 | 	double anim_end = 0.0; | 
| 6128 |  | 
| 6129 | 	for (const KeyValue<int, GLTFAnimation::Track> &track_i : anim->get_tracks()) { | 
| 6130 | 		const GLTFAnimation::Track &track = track_i.value; | 
| 6131 | 		//need to find the path: for skeletons, weight tracks will affect the mesh | 
| 6132 | 		NodePath node_path; | 
| 6133 | 		//for skeletons, transform tracks always affect bones | 
| 6134 | 		NodePath transform_node_path; | 
| 6135 | 		//for meshes, especially skinned meshes, there are cases where it will be added as a child | 
| 6136 | 		NodePath mesh_instance_node_path; | 
| 6137 |  | 
| 6138 | 		GLTFNodeIndex node_index = track_i.key; | 
| 6139 |  | 
| 6140 | 		const Ref<GLTFNode> gltf_node = p_state->nodes[track_i.key]; | 
| 6141 |  | 
| 6142 | 		Node *root = p_animation_player->get_parent(); | 
| 6143 | 		ERR_FAIL_COND(root == nullptr); | 
| 6144 | 		HashMap<GLTFNodeIndex, Node *>::Iterator node_element = p_state->scene_nodes.find(node_index); | 
| 6145 | 		ERR_CONTINUE_MSG(!node_element, vformat("Unable to find node %d for animation." , node_index)); | 
| 6146 | 		node_path = root->get_path_to(node_element->value); | 
| 6147 | 		HashMap<GLTFNodeIndex, ImporterMeshInstance3D *>::Iterator mesh_instance_element = p_state->scene_mesh_instances.find(node_index); | 
| 6148 | 		if (mesh_instance_element) { | 
| 6149 | 			mesh_instance_node_path = root->get_path_to(mesh_instance_element->value); | 
| 6150 | 		} else { | 
| 6151 | 			mesh_instance_node_path = node_path; | 
| 6152 | 		} | 
| 6153 |  | 
| 6154 | 		if (gltf_node->skeleton >= 0) { | 
| 6155 | 			const Skeleton3D *sk = p_state->skeletons[gltf_node->skeleton]->godot_skeleton; | 
| 6156 | 			ERR_FAIL_COND(sk == nullptr); | 
| 6157 |  | 
| 6158 | 			const String path = p_animation_player->get_parent()->get_path_to(sk); | 
| 6159 | 			const String bone = gltf_node->get_name(); | 
| 6160 | 			transform_node_path = path + ":"  + bone; | 
| 6161 | 		} else { | 
| 6162 | 			transform_node_path = node_path; | 
| 6163 | 		} | 
| 6164 |  | 
| 6165 | 		if (p_trimming) { | 
| 6166 | 			for (int i = 0; i < track.rotation_track.times.size(); i++) { | 
| 6167 | 				anim_start = MIN(anim_start, track.rotation_track.times[i]); | 
| 6168 | 				anim_end = MAX(anim_end, track.rotation_track.times[i]); | 
| 6169 | 			} | 
| 6170 | 			for (int i = 0; i < track.position_track.times.size(); i++) { | 
| 6171 | 				anim_start = MIN(anim_start, track.position_track.times[i]); | 
| 6172 | 				anim_end = MAX(anim_end, track.position_track.times[i]); | 
| 6173 | 			} | 
| 6174 | 			for (int i = 0; i < track.scale_track.times.size(); i++) { | 
| 6175 | 				anim_start = MIN(anim_start, track.scale_track.times[i]); | 
| 6176 | 				anim_end = MAX(anim_end, track.scale_track.times[i]); | 
| 6177 | 			} | 
| 6178 | 			for (int i = 0; i < track.weight_tracks.size(); i++) { | 
| 6179 | 				for (int j = 0; j < track.weight_tracks[i].times.size(); j++) { | 
| 6180 | 					anim_start = MIN(anim_start, track.weight_tracks[i].times[j]); | 
| 6181 | 					anim_end = MAX(anim_end, track.weight_tracks[i].times[j]); | 
| 6182 | 				} | 
| 6183 | 			} | 
| 6184 | 		} else { | 
| 6185 | 			// If you don't use trimming and the first key time is not at 0.0, fake keys will be inserted. | 
| 6186 | 			for (int i = 0; i < track.rotation_track.times.size(); i++) { | 
| 6187 | 				anim_end = MAX(anim_end, track.rotation_track.times[i]); | 
| 6188 | 			} | 
| 6189 | 			for (int i = 0; i < track.position_track.times.size(); i++) { | 
| 6190 | 				anim_end = MAX(anim_end, track.position_track.times[i]); | 
| 6191 | 			} | 
| 6192 | 			for (int i = 0; i < track.scale_track.times.size(); i++) { | 
| 6193 | 				anim_end = MAX(anim_end, track.scale_track.times[i]); | 
| 6194 | 			} | 
| 6195 | 			for (int i = 0; i < track.weight_tracks.size(); i++) { | 
| 6196 | 				for (int j = 0; j < track.weight_tracks[i].times.size(); j++) { | 
| 6197 | 					anim_end = MAX(anim_end, track.weight_tracks[i].times[j]); | 
| 6198 | 				} | 
| 6199 | 			} | 
| 6200 | 		} | 
| 6201 |  | 
| 6202 | 		// Animated TRS properties will not affect a skinned mesh. | 
| 6203 | 		const bool transform_affects_skinned_mesh_instance = gltf_node->skeleton < 0 && gltf_node->skin >= 0; | 
| 6204 | 		if ((track.rotation_track.values.size() || track.position_track.values.size() || track.scale_track.values.size()) && !transform_affects_skinned_mesh_instance) { | 
| 6205 | 			//make transform track | 
| 6206 | 			int base_idx = animation->get_track_count(); | 
| 6207 | 			int position_idx = -1; | 
| 6208 | 			int rotation_idx = -1; | 
| 6209 | 			int scale_idx = -1; | 
| 6210 |  | 
| 6211 | 			if (track.position_track.values.size()) { | 
| 6212 | 				bool is_default = true; //discard the track if all it contains is default values | 
| 6213 | 				if (p_remove_immutable_tracks) { | 
| 6214 | 					Vector3 base_pos = p_state->nodes[track_i.key]->position; | 
| 6215 | 					for (int i = 0; i < track.position_track.times.size(); i++) { | 
| 6216 | 						Vector3 value = track.position_track.values[track.position_track.interpolation == GLTFAnimation::INTERP_CUBIC_SPLINE ? (1 + i * 3) : i]; | 
| 6217 | 						if (!value.is_equal_approx(base_pos)) { | 
| 6218 | 							is_default = false; | 
| 6219 | 							break; | 
| 6220 | 						} | 
| 6221 | 					} | 
| 6222 | 				} | 
| 6223 | 				if (!p_remove_immutable_tracks || !is_default) { | 
| 6224 | 					position_idx = base_idx; | 
| 6225 | 					animation->add_track(Animation::TYPE_POSITION_3D); | 
| 6226 | 					animation->track_set_path(position_idx, transform_node_path); | 
| 6227 | 					animation->track_set_imported(position_idx, true); //helps merging later | 
| 6228 | 					base_idx++; | 
| 6229 | 				} | 
| 6230 | 			} | 
| 6231 | 			if (track.rotation_track.values.size()) { | 
| 6232 | 				bool is_default = true; //discard the track if all it contains is default values | 
| 6233 | 				if (p_remove_immutable_tracks) { | 
| 6234 | 					Quaternion base_rot = p_state->nodes[track_i.key]->rotation.normalized(); | 
| 6235 | 					for (int i = 0; i < track.rotation_track.times.size(); i++) { | 
| 6236 | 						Quaternion value = track.rotation_track.values[track.rotation_track.interpolation == GLTFAnimation::INTERP_CUBIC_SPLINE ? (1 + i * 3) : i].normalized(); | 
| 6237 | 						if (!value.is_equal_approx(base_rot)) { | 
| 6238 | 							is_default = false; | 
| 6239 | 							break; | 
| 6240 | 						} | 
| 6241 | 					} | 
| 6242 | 				} | 
| 6243 | 				if (!p_remove_immutable_tracks || !is_default) { | 
| 6244 | 					rotation_idx = base_idx; | 
| 6245 | 					animation->add_track(Animation::TYPE_ROTATION_3D); | 
| 6246 | 					animation->track_set_path(rotation_idx, transform_node_path); | 
| 6247 | 					animation->track_set_imported(rotation_idx, true); //helps merging later | 
| 6248 | 					base_idx++; | 
| 6249 | 				} | 
| 6250 | 			} | 
| 6251 | 			if (track.scale_track.values.size()) { | 
| 6252 | 				bool is_default = true; //discard the track if all it contains is default values | 
| 6253 | 				if (p_remove_immutable_tracks) { | 
| 6254 | 					Vector3 base_scale = p_state->nodes[track_i.key]->scale; | 
| 6255 | 					for (int i = 0; i < track.scale_track.times.size(); i++) { | 
| 6256 | 						Vector3 value = track.scale_track.values[track.scale_track.interpolation == GLTFAnimation::INTERP_CUBIC_SPLINE ? (1 + i * 3) : i]; | 
| 6257 | 						if (!value.is_equal_approx(base_scale)) { | 
| 6258 | 							is_default = false; | 
| 6259 | 							break; | 
| 6260 | 						} | 
| 6261 | 					} | 
| 6262 | 				} | 
| 6263 | 				if (!p_remove_immutable_tracks || !is_default) { | 
| 6264 | 					scale_idx = base_idx; | 
| 6265 | 					animation->add_track(Animation::TYPE_SCALE_3D); | 
| 6266 | 					animation->track_set_path(scale_idx, transform_node_path); | 
| 6267 | 					animation->track_set_imported(scale_idx, true); //helps merging later | 
| 6268 | 					base_idx++; | 
| 6269 | 				} | 
| 6270 | 			} | 
| 6271 |  | 
| 6272 | 			const double increment = 1.0 / p_bake_fps; | 
| 6273 | 			double time = anim_start; | 
| 6274 |  | 
| 6275 | 			Vector3 base_pos; | 
| 6276 | 			Quaternion base_rot; | 
| 6277 | 			Vector3 base_scale = Vector3(1, 1, 1); | 
| 6278 |  | 
| 6279 | 			if (rotation_idx == -1) { | 
| 6280 | 				base_rot = p_state->nodes[track_i.key]->rotation.normalized(); | 
| 6281 | 			} | 
| 6282 |  | 
| 6283 | 			if (position_idx == -1) { | 
| 6284 | 				base_pos = p_state->nodes[track_i.key]->position; | 
| 6285 | 			} | 
| 6286 |  | 
| 6287 | 			if (scale_idx == -1) { | 
| 6288 | 				base_scale = p_state->nodes[track_i.key]->scale; | 
| 6289 | 			} | 
| 6290 |  | 
| 6291 | 			bool last = false; | 
| 6292 | 			while (true) { | 
| 6293 | 				Vector3 pos = base_pos; | 
| 6294 | 				Quaternion rot = base_rot; | 
| 6295 | 				Vector3 scale = base_scale; | 
| 6296 |  | 
| 6297 | 				if (position_idx >= 0) { | 
| 6298 | 					pos = _interpolate_track<Vector3>(track.position_track.times, track.position_track.values, time, track.position_track.interpolation); | 
| 6299 | 					animation->position_track_insert_key(position_idx, time - anim_start, pos); | 
| 6300 | 				} | 
| 6301 |  | 
| 6302 | 				if (rotation_idx >= 0) { | 
| 6303 | 					rot = _interpolate_track<Quaternion>(track.rotation_track.times, track.rotation_track.values, time, track.rotation_track.interpolation); | 
| 6304 | 					animation->rotation_track_insert_key(rotation_idx, time - anim_start, rot); | 
| 6305 | 				} | 
| 6306 |  | 
| 6307 | 				if (scale_idx >= 0) { | 
| 6308 | 					scale = _interpolate_track<Vector3>(track.scale_track.times, track.scale_track.values, time, track.scale_track.interpolation); | 
| 6309 | 					animation->scale_track_insert_key(scale_idx, time - anim_start, scale); | 
| 6310 | 				} | 
| 6311 |  | 
| 6312 | 				if (last) { | 
| 6313 | 					break; | 
| 6314 | 				} | 
| 6315 | 				time += increment; | 
| 6316 | 				if (time >= anim_end) { | 
| 6317 | 					last = true; | 
| 6318 | 					time = anim_end; | 
| 6319 | 				} | 
| 6320 | 			} | 
| 6321 | 		} | 
| 6322 |  | 
| 6323 | 		for (int i = 0; i < track.weight_tracks.size(); i++) { | 
| 6324 | 			ERR_CONTINUE(gltf_node->mesh < 0 || gltf_node->mesh >= p_state->meshes.size()); | 
| 6325 | 			Ref<GLTFMesh> mesh = p_state->meshes[gltf_node->mesh]; | 
| 6326 | 			ERR_CONTINUE(mesh.is_null()); | 
| 6327 | 			ERR_CONTINUE(mesh->get_mesh().is_null()); | 
| 6328 | 			ERR_CONTINUE(mesh->get_mesh()->get_mesh().is_null()); | 
| 6329 |  | 
| 6330 | 			const String blend_path = String(mesh_instance_node_path) + ":"  + String(mesh->get_mesh()->get_blend_shape_name(i)); | 
| 6331 |  | 
| 6332 | 			const int track_idx = animation->get_track_count(); | 
| 6333 | 			animation->add_track(Animation::TYPE_BLEND_SHAPE); | 
| 6334 | 			animation->track_set_path(track_idx, blend_path); | 
| 6335 | 			animation->track_set_imported(track_idx, true); //helps merging later | 
| 6336 |  | 
| 6337 | 			// Only LINEAR and STEP (NEAREST) can be supported out of the box by Godot's Animation, | 
| 6338 | 			// the other modes have to be baked. | 
| 6339 | 			GLTFAnimation::Interpolation gltf_interp = track.weight_tracks[i].interpolation; | 
| 6340 | 			if (gltf_interp == GLTFAnimation::INTERP_LINEAR || gltf_interp == GLTFAnimation::INTERP_STEP) { | 
| 6341 | 				animation->track_set_interpolation_type(track_idx, gltf_interp == GLTFAnimation::INTERP_STEP ? Animation::INTERPOLATION_NEAREST : Animation::INTERPOLATION_LINEAR); | 
| 6342 | 				for (int j = 0; j < track.weight_tracks[i].times.size(); j++) { | 
| 6343 | 					const float t = track.weight_tracks[i].times[j]; | 
| 6344 | 					const float attribs = track.weight_tracks[i].values[j]; | 
| 6345 | 					animation->blend_shape_track_insert_key(track_idx, t, attribs); | 
| 6346 | 				} | 
| 6347 | 			} else { | 
| 6348 | 				// CATMULLROMSPLINE or CUBIC_SPLINE have to be baked, apologies. | 
| 6349 | 				const double increment = 1.0 / p_bake_fps; | 
| 6350 | 				double time = 0.0; | 
| 6351 | 				bool last = false; | 
| 6352 | 				while (true) { | 
| 6353 | 					real_t blend = _interpolate_track<real_t>(track.weight_tracks[i].times, track.weight_tracks[i].values, time, gltf_interp); | 
| 6354 | 					animation->blend_shape_track_insert_key(track_idx, time - anim_start, blend); | 
| 6355 | 					if (last) { | 
| 6356 | 						break; | 
| 6357 | 					} | 
| 6358 | 					time += increment; | 
| 6359 | 					if (time >= anim_end) { | 
| 6360 | 						last = true; | 
| 6361 | 						time = anim_end; | 
| 6362 | 					} | 
| 6363 | 				} | 
| 6364 | 			} | 
| 6365 | 		} | 
| 6366 | 	} | 
| 6367 |  | 
| 6368 | 	animation->set_length(anim_end - anim_start); | 
| 6369 |  | 
| 6370 | 	Ref<AnimationLibrary> library; | 
| 6371 | 	if (!p_animation_player->has_animation_library("" )) { | 
| 6372 | 		library.instantiate(); | 
| 6373 | 		p_animation_player->add_animation_library("" , library); | 
| 6374 | 	} else { | 
| 6375 | 		library = p_animation_player->get_animation_library("" ); | 
| 6376 | 	} | 
| 6377 | 	library->add_animation(anim_name, animation); | 
| 6378 | } | 
| 6379 |  | 
| 6380 | void GLTFDocument::_convert_mesh_instances(Ref<GLTFState> p_state) { | 
| 6381 | 	for (GLTFNodeIndex mi_node_i = 0; mi_node_i < p_state->nodes.size(); ++mi_node_i) { | 
| 6382 | 		Ref<GLTFNode> node = p_state->nodes[mi_node_i]; | 
| 6383 |  | 
| 6384 | 		if (node->mesh < 0) { | 
| 6385 | 			continue; | 
| 6386 | 		} | 
| 6387 | 		HashMap<GLTFNodeIndex, Node *>::Iterator mi_element = p_state->scene_nodes.find(mi_node_i); | 
| 6388 | 		if (!mi_element) { | 
| 6389 | 			continue; | 
| 6390 | 		} | 
| 6391 | 		MeshInstance3D *mi = Object::cast_to<MeshInstance3D>(mi_element->value); | 
| 6392 | 		if (!mi) { | 
| 6393 | 			continue; | 
| 6394 | 		} | 
| 6395 | 		Transform3D mi_xform = mi->get_transform(); | 
| 6396 | 		node->scale = mi_xform.basis.get_scale(); | 
| 6397 | 		node->rotation = mi_xform.basis.get_rotation_quaternion(); | 
| 6398 | 		node->position = mi_xform.origin; | 
| 6399 |  | 
| 6400 | 		Node *skel_node = mi->get_node_or_null(mi->get_skeleton_path()); | 
| 6401 | 		Skeleton3D *godot_skeleton = Object::cast_to<Skeleton3D>(skel_node); | 
| 6402 | 		if (!godot_skeleton || godot_skeleton->get_bone_count() == 0) { | 
| 6403 | 			continue; | 
| 6404 | 		} | 
| 6405 | 		// At this point in the code, we know we have a Skeleton3D with at least one bone. | 
| 6406 | 		Ref<Skin> skin = mi->get_skin(); | 
| 6407 | 		Ref<GLTFSkin> gltf_skin; | 
| 6408 | 		gltf_skin.instantiate(); | 
| 6409 | 		Array json_joints; | 
| 6410 | 		if (p_state->skeleton3d_to_gltf_skeleton.has(godot_skeleton->get_instance_id())) { | 
| 6411 | 			// This is a skinned mesh. If the mesh has no ARRAY_WEIGHTS or ARRAY_BONES, it will be invisible. | 
| 6412 | 			const GLTFSkeletonIndex skeleton_gltf_i = p_state->skeleton3d_to_gltf_skeleton[godot_skeleton->get_instance_id()]; | 
| 6413 | 			Ref<GLTFSkeleton> gltf_skeleton = p_state->skeletons[skeleton_gltf_i]; | 
| 6414 | 			int bone_cnt = godot_skeleton->get_bone_count(); | 
| 6415 | 			ERR_FAIL_COND(bone_cnt != gltf_skeleton->joints.size()); | 
| 6416 |  | 
| 6417 | 			ObjectID gltf_skin_key; | 
| 6418 | 			if (skin.is_valid()) { | 
| 6419 | 				gltf_skin_key = skin->get_instance_id(); | 
| 6420 | 			} | 
| 6421 | 			ObjectID gltf_skel_key = godot_skeleton->get_instance_id(); | 
| 6422 | 			GLTFSkinIndex skin_gltf_i = -1; | 
| 6423 | 			GLTFNodeIndex root_gltf_i = -1; | 
| 6424 | 			if (!gltf_skeleton->roots.is_empty()) { | 
| 6425 | 				root_gltf_i = gltf_skeleton->roots[0]; | 
| 6426 | 			} | 
| 6427 | 			if (p_state->skin_and_skeleton3d_to_gltf_skin.has(gltf_skin_key) && p_state->skin_and_skeleton3d_to_gltf_skin[gltf_skin_key].has(gltf_skel_key)) { | 
| 6428 | 				skin_gltf_i = p_state->skin_and_skeleton3d_to_gltf_skin[gltf_skin_key][gltf_skel_key]; | 
| 6429 | 			} else { | 
| 6430 | 				if (skin.is_null()) { | 
| 6431 | 					// Note that gltf_skin_key should remain null, so these can share a reference. | 
| 6432 | 					skin = godot_skeleton->create_skin_from_rest_transforms(); | 
| 6433 | 				} | 
| 6434 | 				gltf_skin.instantiate(); | 
| 6435 | 				gltf_skin->godot_skin = skin; | 
| 6436 | 				gltf_skin->set_name(skin->get_name()); | 
| 6437 | 				gltf_skin->skeleton = skeleton_gltf_i; | 
| 6438 | 				gltf_skin->skin_root = root_gltf_i; | 
| 6439 | 				//gltf_state->godot_to_gltf_node[skel_node] | 
| 6440 | 				HashMap<StringName, int> bone_name_to_idx; | 
| 6441 | 				for (int bone_i = 0; bone_i < bone_cnt; bone_i++) { | 
| 6442 | 					bone_name_to_idx[godot_skeleton->get_bone_name(bone_i)] = bone_i; | 
| 6443 | 				} | 
| 6444 | 				for (int bind_i = 0, cnt = skin->get_bind_count(); bind_i < cnt; bind_i++) { | 
| 6445 | 					int bone_i = skin->get_bind_bone(bind_i); | 
| 6446 | 					Transform3D bind_pose = skin->get_bind_pose(bind_i); | 
| 6447 | 					StringName bind_name = skin->get_bind_name(bind_i); | 
| 6448 | 					if (bind_name != StringName()) { | 
| 6449 | 						bone_i = bone_name_to_idx[bind_name]; | 
| 6450 | 					} | 
| 6451 | 					ERR_CONTINUE(bone_i < 0 || bone_i >= bone_cnt); | 
| 6452 | 					if (bind_name == StringName()) { | 
| 6453 | 						bind_name = godot_skeleton->get_bone_name(bone_i); | 
| 6454 | 					} | 
| 6455 | 					GLTFNodeIndex skeleton_bone_i = gltf_skeleton->joints[bone_i]; | 
| 6456 | 					gltf_skin->joints_original.push_back(skeleton_bone_i); | 
| 6457 | 					gltf_skin->joints.push_back(skeleton_bone_i); | 
| 6458 | 					gltf_skin->inverse_binds.push_back(bind_pose); | 
| 6459 | 					if (godot_skeleton->get_bone_parent(bone_i) == -1) { | 
| 6460 | 						gltf_skin->roots.push_back(skeleton_bone_i); | 
| 6461 | 					} | 
| 6462 | 					gltf_skin->joint_i_to_bone_i[bind_i] = bone_i; | 
| 6463 | 					gltf_skin->joint_i_to_name[bind_i] = bind_name; | 
| 6464 | 				} | 
| 6465 | 				skin_gltf_i = p_state->skins.size(); | 
| 6466 | 				p_state->skins.push_back(gltf_skin); | 
| 6467 | 				p_state->skin_and_skeleton3d_to_gltf_skin[gltf_skin_key][gltf_skel_key] = skin_gltf_i; | 
| 6468 | 			} | 
| 6469 | 			node->skin = skin_gltf_i; | 
| 6470 | 			node->skeleton = skeleton_gltf_i; | 
| 6471 | 		} | 
| 6472 | 	} | 
| 6473 | } | 
| 6474 |  | 
| 6475 | float GLTFDocument::solve_metallic(float p_dielectric_specular, float p_diffuse, float p_specular, float p_one_minus_specular_strength) { | 
| 6476 | 	if (p_specular <= p_dielectric_specular) { | 
| 6477 | 		return 0.0f; | 
| 6478 | 	} | 
| 6479 |  | 
| 6480 | 	const float a = p_dielectric_specular; | 
| 6481 | 	const float b = p_diffuse * p_one_minus_specular_strength / (1.0f - p_dielectric_specular) + p_specular - 2.0f * p_dielectric_specular; | 
| 6482 | 	const float c = p_dielectric_specular - p_specular; | 
| 6483 | 	const float D = b * b - 4.0f * a * c; | 
| 6484 | 	return CLAMP((-b + Math::sqrt(D)) / (2.0f * a), 0.0f, 1.0f); | 
| 6485 | } | 
| 6486 |  | 
| 6487 | float GLTFDocument::get_perceived_brightness(const Color p_color) { | 
| 6488 | 	const Color coeff = Color(R_BRIGHTNESS_COEFF, G_BRIGHTNESS_COEFF, B_BRIGHTNESS_COEFF); | 
| 6489 | 	const Color value = coeff * (p_color * p_color); | 
| 6490 |  | 
| 6491 | 	const float r = value.r; | 
| 6492 | 	const float g = value.g; | 
| 6493 | 	const float b = value.b; | 
| 6494 |  | 
| 6495 | 	return Math::sqrt(r + g + b); | 
| 6496 | } | 
| 6497 |  | 
| 6498 | float GLTFDocument::get_max_component(const Color &p_color) { | 
| 6499 | 	const float r = p_color.r; | 
| 6500 | 	const float g = p_color.g; | 
| 6501 | 	const float b = p_color.b; | 
| 6502 |  | 
| 6503 | 	return MAX(MAX(r, g), b); | 
| 6504 | } | 
| 6505 |  | 
| 6506 | void GLTFDocument::_process_mesh_instances(Ref<GLTFState> p_state) { | 
| 6507 | 	for (GLTFNodeIndex node_i = 0; node_i < p_state->nodes.size(); ++node_i) { | 
| 6508 | 		Ref<GLTFNode> node = p_state->nodes[node_i]; | 
| 6509 |  | 
| 6510 | 		if (node->skin >= 0 && node->mesh >= 0) { | 
| 6511 | 			const GLTFSkinIndex skin_i = node->skin; | 
| 6512 |  | 
| 6513 | 			ImporterMeshInstance3D *mi = nullptr; | 
| 6514 | 			HashMap<GLTFNodeIndex, ImporterMeshInstance3D *>::Iterator mi_element = p_state->scene_mesh_instances.find(node_i); | 
| 6515 | 			if (mi_element) { | 
| 6516 | 				mi = mi_element->value; | 
| 6517 | 			} else { | 
| 6518 | 				HashMap<GLTFNodeIndex, Node *>::Iterator si_element = p_state->scene_nodes.find(node_i); | 
| 6519 | 				ERR_CONTINUE_MSG(!si_element, vformat("Unable to find node %d" , node_i)); | 
| 6520 | 				mi = Object::cast_to<ImporterMeshInstance3D>(si_element->value); | 
| 6521 | 				ERR_CONTINUE_MSG(mi == nullptr, vformat("Unable to cast node %d of type %s to ImporterMeshInstance3D" , node_i, si_element->value->get_class_name())); | 
| 6522 | 			} | 
| 6523 |  | 
| 6524 | 			const GLTFSkeletonIndex skel_i = p_state->skins.write[node->skin]->skeleton; | 
| 6525 | 			Ref<GLTFSkeleton> gltf_skeleton = p_state->skeletons.write[skel_i]; | 
| 6526 | 			Skeleton3D *skeleton = gltf_skeleton->godot_skeleton; | 
| 6527 | 			ERR_CONTINUE_MSG(skeleton == nullptr, vformat("Unable to find Skeleton for node %d skin %d" , node_i, skin_i)); | 
| 6528 |  | 
| 6529 | 			mi->get_parent()->remove_child(mi); | 
| 6530 | 			skeleton->add_child(mi, true); | 
| 6531 | 			mi->set_owner(skeleton->get_owner()); | 
| 6532 |  | 
| 6533 | 			mi->set_skin(p_state->skins.write[skin_i]->godot_skin); | 
| 6534 | 			mi->set_skeleton_path(mi->get_path_to(skeleton)); | 
| 6535 | 			mi->set_transform(Transform3D()); | 
| 6536 | 		} | 
| 6537 | 	} | 
| 6538 | } | 
| 6539 |  | 
| 6540 | GLTFAnimation::Track GLTFDocument::_convert_animation_track(Ref<GLTFState> p_state, GLTFAnimation::Track p_track, Ref<Animation> p_animation, int32_t p_track_i, GLTFNodeIndex p_node_i) { | 
| 6541 | 	Animation::InterpolationType interpolation = p_animation->track_get_interpolation_type(p_track_i); | 
| 6542 |  | 
| 6543 | 	GLTFAnimation::Interpolation gltf_interpolation = GLTFAnimation::INTERP_LINEAR; | 
| 6544 | 	if (interpolation == Animation::InterpolationType::INTERPOLATION_LINEAR) { | 
| 6545 | 		gltf_interpolation = GLTFAnimation::INTERP_LINEAR; | 
| 6546 | 	} else if (interpolation == Animation::InterpolationType::INTERPOLATION_NEAREST) { | 
| 6547 | 		gltf_interpolation = GLTFAnimation::INTERP_STEP; | 
| 6548 | 	} else if (interpolation == Animation::InterpolationType::INTERPOLATION_CUBIC) { | 
| 6549 | 		gltf_interpolation = GLTFAnimation::INTERP_CUBIC_SPLINE; | 
| 6550 | 	} | 
| 6551 | 	Animation::TrackType track_type = p_animation->track_get_type(p_track_i); | 
| 6552 | 	int32_t key_count = p_animation->track_get_key_count(p_track_i); | 
| 6553 | 	Vector<real_t> times; | 
| 6554 | 	times.resize(key_count); | 
| 6555 | 	String path = p_animation->track_get_path(p_track_i); | 
| 6556 | 	for (int32_t key_i = 0; key_i < key_count; key_i++) { | 
| 6557 | 		times.write[key_i] = p_animation->track_get_key_time(p_track_i, key_i); | 
| 6558 | 	} | 
| 6559 | 	double anim_end = p_animation->get_length(); | 
| 6560 | 	if (track_type == Animation::TYPE_SCALE_3D) { | 
| 6561 | 		if (gltf_interpolation == GLTFAnimation::INTERP_CUBIC_SPLINE) { | 
| 6562 | 			gltf_interpolation = GLTFAnimation::INTERP_LINEAR; | 
| 6563 | 			p_track.scale_track.times.clear(); | 
| 6564 | 			p_track.scale_track.values.clear(); | 
| 6565 | 			// CATMULLROMSPLINE or CUBIC_SPLINE have to be baked, apologies. | 
| 6566 | 			const double increment = 1.0 / BAKE_FPS; | 
| 6567 | 			double time = 0.0; | 
| 6568 | 			bool last = false; | 
| 6569 | 			while (true) { | 
| 6570 | 				Vector3 scale; | 
| 6571 | 				Error err = p_animation->try_scale_track_interpolate(p_track_i, time, &scale); | 
| 6572 | 				ERR_CONTINUE(err != OK); | 
| 6573 | 				p_track.scale_track.values.push_back(scale); | 
| 6574 | 				p_track.scale_track.times.push_back(time); | 
| 6575 | 				if (last) { | 
| 6576 | 					break; | 
| 6577 | 				} | 
| 6578 | 				time += increment; | 
| 6579 | 				if (time >= anim_end) { | 
| 6580 | 					last = true; | 
| 6581 | 					time = anim_end; | 
| 6582 | 				} | 
| 6583 | 			} | 
| 6584 | 		} else { | 
| 6585 | 			p_track.scale_track.times = times; | 
| 6586 | 			p_track.scale_track.interpolation = gltf_interpolation; | 
| 6587 | 			p_track.scale_track.values.resize(key_count); | 
| 6588 | 			for (int32_t key_i = 0; key_i < key_count; key_i++) { | 
| 6589 | 				Vector3 scale; | 
| 6590 | 				Error err = p_animation->scale_track_get_key(p_track_i, key_i, &scale); | 
| 6591 | 				ERR_CONTINUE(err != OK); | 
| 6592 | 				p_track.scale_track.values.write[key_i] = scale; | 
| 6593 | 			} | 
| 6594 | 		} | 
| 6595 | 	} else if (track_type == Animation::TYPE_POSITION_3D) { | 
| 6596 | 		if (gltf_interpolation == GLTFAnimation::INTERP_CUBIC_SPLINE) { | 
| 6597 | 			gltf_interpolation = GLTFAnimation::INTERP_LINEAR; | 
| 6598 | 			p_track.position_track.times.clear(); | 
| 6599 | 			p_track.position_track.values.clear(); | 
| 6600 | 			// CATMULLROMSPLINE or CUBIC_SPLINE have to be baked, apologies. | 
| 6601 | 			const double increment = 1.0 / BAKE_FPS; | 
| 6602 | 			double time = 0.0; | 
| 6603 | 			bool last = false; | 
| 6604 | 			while (true) { | 
| 6605 | 				Vector3 scale; | 
| 6606 | 				Error err = p_animation->try_position_track_interpolate(p_track_i, time, &scale); | 
| 6607 | 				ERR_CONTINUE(err != OK); | 
| 6608 | 				p_track.position_track.values.push_back(scale); | 
| 6609 | 				p_track.position_track.times.push_back(time); | 
| 6610 | 				if (last) { | 
| 6611 | 					break; | 
| 6612 | 				} | 
| 6613 | 				time += increment; | 
| 6614 | 				if (time >= anim_end) { | 
| 6615 | 					last = true; | 
| 6616 | 					time = anim_end; | 
| 6617 | 				} | 
| 6618 | 			} | 
| 6619 | 		} else { | 
| 6620 | 			p_track.position_track.times = times; | 
| 6621 | 			p_track.position_track.values.resize(key_count); | 
| 6622 | 			p_track.position_track.interpolation = gltf_interpolation; | 
| 6623 | 			for (int32_t key_i = 0; key_i < key_count; key_i++) { | 
| 6624 | 				Vector3 position; | 
| 6625 | 				Error err = p_animation->position_track_get_key(p_track_i, key_i, &position); | 
| 6626 | 				ERR_CONTINUE(err != OK); | 
| 6627 | 				p_track.position_track.values.write[key_i] = position; | 
| 6628 | 			} | 
| 6629 | 		} | 
| 6630 | 	} else if (track_type == Animation::TYPE_ROTATION_3D) { | 
| 6631 | 		if (gltf_interpolation == GLTFAnimation::INTERP_CUBIC_SPLINE) { | 
| 6632 | 			gltf_interpolation = GLTFAnimation::INTERP_LINEAR; | 
| 6633 | 			p_track.rotation_track.times.clear(); | 
| 6634 | 			p_track.rotation_track.values.clear(); | 
| 6635 | 			// CATMULLROMSPLINE or CUBIC_SPLINE have to be baked, apologies. | 
| 6636 | 			const double increment = 1.0 / BAKE_FPS; | 
| 6637 | 			double time = 0.0; | 
| 6638 | 			bool last = false; | 
| 6639 | 			while (true) { | 
| 6640 | 				Quaternion rotation; | 
| 6641 | 				Error err = p_animation->try_rotation_track_interpolate(p_track_i, time, &rotation); | 
| 6642 | 				ERR_CONTINUE(err != OK); | 
| 6643 | 				p_track.rotation_track.values.push_back(rotation); | 
| 6644 | 				p_track.rotation_track.times.push_back(time); | 
| 6645 | 				if (last) { | 
| 6646 | 					break; | 
| 6647 | 				} | 
| 6648 | 				time += increment; | 
| 6649 | 				if (time >= anim_end) { | 
| 6650 | 					last = true; | 
| 6651 | 					time = anim_end; | 
| 6652 | 				} | 
| 6653 | 			} | 
| 6654 | 		} else { | 
| 6655 | 			p_track.rotation_track.times = times; | 
| 6656 | 			p_track.rotation_track.values.resize(key_count); | 
| 6657 | 			p_track.rotation_track.interpolation = gltf_interpolation; | 
| 6658 | 			for (int32_t key_i = 0; key_i < key_count; key_i++) { | 
| 6659 | 				Quaternion rotation; | 
| 6660 | 				Error err = p_animation->rotation_track_get_key(p_track_i, key_i, &rotation); | 
| 6661 | 				ERR_CONTINUE(err != OK); | 
| 6662 | 				p_track.rotation_track.values.write[key_i] = rotation; | 
| 6663 | 			} | 
| 6664 | 		} | 
| 6665 | 	} else if (track_type == Animation::TYPE_VALUE) { | 
| 6666 | 		if (path.contains(":position" )) { | 
| 6667 | 			p_track.position_track.interpolation = gltf_interpolation; | 
| 6668 | 			p_track.position_track.times = times; | 
| 6669 | 			p_track.position_track.values.resize(key_count); | 
| 6670 |  | 
| 6671 | 			if (gltf_interpolation == GLTFAnimation::INTERP_CUBIC_SPLINE) { | 
| 6672 | 				gltf_interpolation = GLTFAnimation::INTERP_LINEAR; | 
| 6673 | 				p_track.position_track.times.clear(); | 
| 6674 | 				p_track.position_track.values.clear(); | 
| 6675 | 				// CATMULLROMSPLINE or CUBIC_SPLINE have to be baked, apologies. | 
| 6676 | 				const double increment = 1.0 / BAKE_FPS; | 
| 6677 | 				double time = 0.0; | 
| 6678 | 				bool last = false; | 
| 6679 | 				while (true) { | 
| 6680 | 					Vector3 position; | 
| 6681 | 					Error err = p_animation->try_position_track_interpolate(p_track_i, time, &position); | 
| 6682 | 					ERR_CONTINUE(err != OK); | 
| 6683 | 					p_track.position_track.values.push_back(position); | 
| 6684 | 					p_track.position_track.times.push_back(time); | 
| 6685 | 					if (last) { | 
| 6686 | 						break; | 
| 6687 | 					} | 
| 6688 | 					time += increment; | 
| 6689 | 					if (time >= anim_end) { | 
| 6690 | 						last = true; | 
| 6691 | 						time = anim_end; | 
| 6692 | 					} | 
| 6693 | 				} | 
| 6694 | 			} else { | 
| 6695 | 				for (int32_t key_i = 0; key_i < key_count; key_i++) { | 
| 6696 | 					Vector3 position = p_animation->track_get_key_value(p_track_i, key_i); | 
| 6697 | 					p_track.position_track.values.write[key_i] = position; | 
| 6698 | 				} | 
| 6699 | 			} | 
| 6700 | 		} else if (path.contains(":rotation" )) { | 
| 6701 | 			p_track.rotation_track.interpolation = gltf_interpolation; | 
| 6702 | 			p_track.rotation_track.times = times; | 
| 6703 | 			p_track.rotation_track.values.resize(key_count); | 
| 6704 | 			if (gltf_interpolation == GLTFAnimation::INTERP_CUBIC_SPLINE) { | 
| 6705 | 				gltf_interpolation = GLTFAnimation::INTERP_LINEAR; | 
| 6706 | 				p_track.rotation_track.times.clear(); | 
| 6707 | 				p_track.rotation_track.values.clear(); | 
| 6708 | 				// CATMULLROMSPLINE or CUBIC_SPLINE have to be baked, apologies. | 
| 6709 | 				const double increment = 1.0 / BAKE_FPS; | 
| 6710 | 				double time = 0.0; | 
| 6711 | 				bool last = false; | 
| 6712 | 				while (true) { | 
| 6713 | 					Quaternion rotation; | 
| 6714 | 					Error err = p_animation->try_rotation_track_interpolate(p_track_i, time, &rotation); | 
| 6715 | 					ERR_CONTINUE(err != OK); | 
| 6716 | 					p_track.rotation_track.values.push_back(rotation); | 
| 6717 | 					p_track.rotation_track.times.push_back(time); | 
| 6718 | 					if (last) { | 
| 6719 | 						break; | 
| 6720 | 					} | 
| 6721 | 					time += increment; | 
| 6722 | 					if (time >= anim_end) { | 
| 6723 | 						last = true; | 
| 6724 | 						time = anim_end; | 
| 6725 | 					} | 
| 6726 | 				} | 
| 6727 | 			} else { | 
| 6728 | 				for (int32_t key_i = 0; key_i < key_count; key_i++) { | 
| 6729 | 					Vector3 rotation_radian = p_animation->track_get_key_value(p_track_i, key_i); | 
| 6730 | 					p_track.rotation_track.values.write[key_i] = Quaternion::from_euler(rotation_radian); | 
| 6731 | 				} | 
| 6732 | 			} | 
| 6733 | 		} else if (path.contains(":scale" )) { | 
| 6734 | 			p_track.scale_track.times = times; | 
| 6735 | 			p_track.scale_track.interpolation = gltf_interpolation; | 
| 6736 |  | 
| 6737 | 			p_track.scale_track.values.resize(key_count); | 
| 6738 | 			p_track.scale_track.interpolation = gltf_interpolation; | 
| 6739 |  | 
| 6740 | 			if (gltf_interpolation == GLTFAnimation::INTERP_CUBIC_SPLINE) { | 
| 6741 | 				gltf_interpolation = GLTFAnimation::INTERP_LINEAR; | 
| 6742 | 				p_track.scale_track.times.clear(); | 
| 6743 | 				p_track.scale_track.values.clear(); | 
| 6744 | 				// CATMULLROMSPLINE or CUBIC_SPLINE have to be baked, apologies. | 
| 6745 | 				const double increment = 1.0 / BAKE_FPS; | 
| 6746 | 				double time = 0.0; | 
| 6747 | 				bool last = false; | 
| 6748 | 				while (true) { | 
| 6749 | 					Vector3 scale; | 
| 6750 | 					Error err = p_animation->try_scale_track_interpolate(p_track_i, time, &scale); | 
| 6751 | 					ERR_CONTINUE(err != OK); | 
| 6752 | 					p_track.scale_track.values.push_back(scale); | 
| 6753 | 					p_track.scale_track.times.push_back(time); | 
| 6754 | 					if (last) { | 
| 6755 | 						break; | 
| 6756 | 					} | 
| 6757 | 					time += increment; | 
| 6758 | 					if (time >= anim_end) { | 
| 6759 | 						last = true; | 
| 6760 | 						time = anim_end; | 
| 6761 | 					} | 
| 6762 | 				} | 
| 6763 | 			} else { | 
| 6764 | 				for (int32_t key_i = 0; key_i < key_count; key_i++) { | 
| 6765 | 					Vector3 scale_track = p_animation->track_get_key_value(p_track_i, key_i); | 
| 6766 | 					p_track.scale_track.values.write[key_i] = scale_track; | 
| 6767 | 				} | 
| 6768 | 			} | 
| 6769 | 		} | 
| 6770 | 	} else if (track_type == Animation::TYPE_BEZIER) { | 
| 6771 | 		const int32_t keys = anim_end * BAKE_FPS; | 
| 6772 | 		if (path.contains(":scale" )) { | 
| 6773 | 			if (!p_track.scale_track.times.size()) { | 
| 6774 | 				p_track.scale_track.interpolation = gltf_interpolation; | 
| 6775 | 				Vector<real_t> new_times; | 
| 6776 | 				new_times.resize(keys); | 
| 6777 | 				for (int32_t key_i = 0; key_i < keys; key_i++) { | 
| 6778 | 					new_times.write[key_i] = key_i / BAKE_FPS; | 
| 6779 | 				} | 
| 6780 | 				p_track.scale_track.times = new_times; | 
| 6781 |  | 
| 6782 | 				p_track.scale_track.values.resize(keys); | 
| 6783 |  | 
| 6784 | 				for (int32_t key_i = 0; key_i < keys; key_i++) { | 
| 6785 | 					p_track.scale_track.values.write[key_i] = Vector3(1.0f, 1.0f, 1.0f); | 
| 6786 | 				} | 
| 6787 |  | 
| 6788 | 				for (int32_t key_i = 0; key_i < keys; key_i++) { | 
| 6789 | 					Vector3 bezier_track = p_track.scale_track.values[key_i]; | 
| 6790 | 					if (path.contains(":scale:x" )) { | 
| 6791 | 						bezier_track.x = p_animation->bezier_track_interpolate(p_track_i, key_i / BAKE_FPS); | 
| 6792 | 					} else if (path.contains(":scale:y" )) { | 
| 6793 | 						bezier_track.y = p_animation->bezier_track_interpolate(p_track_i, key_i / BAKE_FPS); | 
| 6794 | 					} else if (path.contains(":scale:z" )) { | 
| 6795 | 						bezier_track.z = p_animation->bezier_track_interpolate(p_track_i, key_i / BAKE_FPS); | 
| 6796 | 					} | 
| 6797 | 					p_track.scale_track.values.write[key_i] = bezier_track; | 
| 6798 | 				} | 
| 6799 | 			} | 
| 6800 | 		} else if (path.contains(":position" )) { | 
| 6801 | 			if (!p_track.position_track.times.size()) { | 
| 6802 | 				p_track.position_track.interpolation = gltf_interpolation; | 
| 6803 | 				Vector<real_t> new_times; | 
| 6804 | 				new_times.resize(keys); | 
| 6805 | 				for (int32_t key_i = 0; key_i < keys; key_i++) { | 
| 6806 | 					new_times.write[key_i] = key_i / BAKE_FPS; | 
| 6807 | 				} | 
| 6808 | 				p_track.position_track.times = new_times; | 
| 6809 |  | 
| 6810 | 				p_track.position_track.values.resize(keys); | 
| 6811 | 			} | 
| 6812 |  | 
| 6813 | 			for (int32_t key_i = 0; key_i < keys; key_i++) { | 
| 6814 | 				Vector3 bezier_track = p_track.position_track.values[key_i]; | 
| 6815 | 				if (path.contains(":position:x" )) { | 
| 6816 | 					bezier_track.x = p_animation->bezier_track_interpolate(p_track_i, key_i / BAKE_FPS); | 
| 6817 | 				} else if (path.contains(":position:y" )) { | 
| 6818 | 					bezier_track.y = p_animation->bezier_track_interpolate(p_track_i, key_i / BAKE_FPS); | 
| 6819 | 				} else if (path.contains(":position:z" )) { | 
| 6820 | 					bezier_track.z = p_animation->bezier_track_interpolate(p_track_i, key_i / BAKE_FPS); | 
| 6821 | 				} | 
| 6822 | 				p_track.position_track.values.write[key_i] = bezier_track; | 
| 6823 | 			} | 
| 6824 | 		} else if (path.contains(":rotation" )) { | 
| 6825 | 			if (!p_track.rotation_track.times.size()) { | 
| 6826 | 				p_track.rotation_track.interpolation = gltf_interpolation; | 
| 6827 | 				Vector<real_t> new_times; | 
| 6828 | 				new_times.resize(keys); | 
| 6829 | 				for (int32_t key_i = 0; key_i < keys; key_i++) { | 
| 6830 | 					new_times.write[key_i] = key_i / BAKE_FPS; | 
| 6831 | 				} | 
| 6832 | 				p_track.rotation_track.times = new_times; | 
| 6833 |  | 
| 6834 | 				p_track.rotation_track.values.resize(keys); | 
| 6835 | 			} | 
| 6836 | 			for (int32_t key_i = 0; key_i < keys; key_i++) { | 
| 6837 | 				Quaternion bezier_track = p_track.rotation_track.values[key_i]; | 
| 6838 | 				if (path.contains(":rotation:x" )) { | 
| 6839 | 					bezier_track.x = p_animation->bezier_track_interpolate(p_track_i, key_i / BAKE_FPS); | 
| 6840 | 				} else if (path.contains(":rotation:y" )) { | 
| 6841 | 					bezier_track.y = p_animation->bezier_track_interpolate(p_track_i, key_i / BAKE_FPS); | 
| 6842 | 				} else if (path.contains(":rotation:z" )) { | 
| 6843 | 					bezier_track.z = p_animation->bezier_track_interpolate(p_track_i, key_i / BAKE_FPS); | 
| 6844 | 				} else if (path.contains(":rotation:w" )) { | 
| 6845 | 					bezier_track.w = p_animation->bezier_track_interpolate(p_track_i, key_i / BAKE_FPS); | 
| 6846 | 				} | 
| 6847 | 				p_track.rotation_track.values.write[key_i] = bezier_track; | 
| 6848 | 			} | 
| 6849 | 		} | 
| 6850 | 	} | 
| 6851 | 	return p_track; | 
| 6852 | } | 
| 6853 |  | 
| 6854 | void GLTFDocument::_convert_animation(Ref<GLTFState> p_state, AnimationPlayer *p_animation_player, String p_animation_track_name) { | 
| 6855 | 	Ref<Animation> animation = p_animation_player->get_animation(p_animation_track_name); | 
| 6856 | 	Ref<GLTFAnimation> gltf_animation; | 
| 6857 | 	gltf_animation.instantiate(); | 
| 6858 | 	gltf_animation->set_name(_gen_unique_name(p_state, p_animation_track_name)); | 
| 6859 | 	for (int32_t track_i = 0; track_i < animation->get_track_count(); track_i++) { | 
| 6860 | 		if (!animation->track_is_enabled(track_i)) { | 
| 6861 | 			continue; | 
| 6862 | 		} | 
| 6863 | 		String final_track_path = animation->track_get_path(track_i); | 
| 6864 | 		Node *animation_base_node = p_animation_player->get_parent(); | 
| 6865 | 		ERR_CONTINUE_MSG(!animation_base_node, "Cannot get the parent of the animation player." ); | 
| 6866 | 		if (String(final_track_path).contains(":position" )) { | 
| 6867 | 			const Vector<String> node_suffix = String(final_track_path).split(":position" ); | 
| 6868 | 			const NodePath path = node_suffix[0]; | 
| 6869 | 			const Node *node = animation_base_node->get_node_or_null(path); | 
| 6870 | 			ERR_CONTINUE_MSG(!node, "Cannot get the node from a position path." ); | 
| 6871 | 			for (const KeyValue<GLTFNodeIndex, Node *> &position_scene_node_i : p_state->scene_nodes) { | 
| 6872 | 				if (position_scene_node_i.value == node) { | 
| 6873 | 					GLTFNodeIndex node_index = position_scene_node_i.key; | 
| 6874 | 					HashMap<int, GLTFAnimation::Track>::Iterator position_track_i = gltf_animation->get_tracks().find(node_index); | 
| 6875 | 					GLTFAnimation::Track track; | 
| 6876 | 					if (position_track_i) { | 
| 6877 | 						track = position_track_i->value; | 
| 6878 | 					} | 
| 6879 | 					track = _convert_animation_track(p_state, track, animation, track_i, node_index); | 
| 6880 | 					gltf_animation->get_tracks().insert(node_index, track); | 
| 6881 | 				} | 
| 6882 | 			} | 
| 6883 | 		} else if (String(final_track_path).contains(":rotation_degrees" )) { | 
| 6884 | 			const Vector<String> node_suffix = String(final_track_path).split(":rotation_degrees" ); | 
| 6885 | 			const NodePath path = node_suffix[0]; | 
| 6886 | 			const Node *node = animation_base_node->get_node_or_null(path); | 
| 6887 | 			ERR_CONTINUE_MSG(!node, "Cannot get the node from a rotation degrees path." ); | 
| 6888 | 			for (const KeyValue<GLTFNodeIndex, Node *> &rotation_degree_scene_node_i : p_state->scene_nodes) { | 
| 6889 | 				if (rotation_degree_scene_node_i.value == node) { | 
| 6890 | 					GLTFNodeIndex node_index = rotation_degree_scene_node_i.key; | 
| 6891 | 					HashMap<int, GLTFAnimation::Track>::Iterator rotation_degree_track_i = gltf_animation->get_tracks().find(node_index); | 
| 6892 | 					GLTFAnimation::Track track; | 
| 6893 | 					if (rotation_degree_track_i) { | 
| 6894 | 						track = rotation_degree_track_i->value; | 
| 6895 | 					} | 
| 6896 | 					track = _convert_animation_track(p_state, track, animation, track_i, node_index); | 
| 6897 | 					gltf_animation->get_tracks().insert(node_index, track); | 
| 6898 | 				} | 
| 6899 | 			} | 
| 6900 | 		} else if (String(final_track_path).contains(":scale" )) { | 
| 6901 | 			const Vector<String> node_suffix = String(final_track_path).split(":scale" ); | 
| 6902 | 			const NodePath path = node_suffix[0]; | 
| 6903 | 			const Node *node = animation_base_node->get_node_or_null(path); | 
| 6904 | 			ERR_CONTINUE_MSG(!node, "Cannot get the node from a scale path." ); | 
| 6905 | 			for (const KeyValue<GLTFNodeIndex, Node *> &scale_scene_node_i : p_state->scene_nodes) { | 
| 6906 | 				if (scale_scene_node_i.value == node) { | 
| 6907 | 					GLTFNodeIndex node_index = scale_scene_node_i.key; | 
| 6908 | 					HashMap<int, GLTFAnimation::Track>::Iterator scale_track_i = gltf_animation->get_tracks().find(node_index); | 
| 6909 | 					GLTFAnimation::Track track; | 
| 6910 | 					if (scale_track_i) { | 
| 6911 | 						track = scale_track_i->value; | 
| 6912 | 					} | 
| 6913 | 					track = _convert_animation_track(p_state, track, animation, track_i, node_index); | 
| 6914 | 					gltf_animation->get_tracks().insert(node_index, track); | 
| 6915 | 				} | 
| 6916 | 			} | 
| 6917 | 		} else if (String(final_track_path).contains(":transform" )) { | 
| 6918 | 			const Vector<String> node_suffix = String(final_track_path).split(":transform" ); | 
| 6919 | 			const NodePath path = node_suffix[0]; | 
| 6920 | 			const Node *node = animation_base_node->get_node_or_null(path); | 
| 6921 | 			ERR_CONTINUE_MSG(!node, "Cannot get the node from a transform path." ); | 
| 6922 | 			for (const KeyValue<GLTFNodeIndex, Node *> &transform_track_i : p_state->scene_nodes) { | 
| 6923 | 				if (transform_track_i.value == node) { | 
| 6924 | 					GLTFAnimation::Track track; | 
| 6925 | 					track = _convert_animation_track(p_state, track, animation, track_i, transform_track_i.key); | 
| 6926 | 					gltf_animation->get_tracks().insert(transform_track_i.key, track); | 
| 6927 | 				} | 
| 6928 | 			} | 
| 6929 | 		} else if (String(final_track_path).contains(":" ) && animation->track_get_type(track_i) == Animation::TYPE_BLEND_SHAPE) { | 
| 6930 | 			const Vector<String> node_suffix = String(final_track_path).split(":" ); | 
| 6931 | 			const NodePath path = node_suffix[0]; | 
| 6932 | 			const String suffix = node_suffix[1]; | 
| 6933 | 			Node *node = animation_base_node->get_node_or_null(path); | 
| 6934 | 			ERR_CONTINUE_MSG(!node, "Cannot get the node from a blend shape path." ); | 
| 6935 | 			MeshInstance3D *mi = cast_to<MeshInstance3D>(node); | 
| 6936 | 			if (!mi) { | 
| 6937 | 				continue; | 
| 6938 | 			} | 
| 6939 | 			Ref<Mesh> mesh = mi->get_mesh(); | 
| 6940 | 			ERR_CONTINUE(mesh.is_null()); | 
| 6941 | 			int32_t mesh_index = -1; | 
| 6942 | 			for (const KeyValue<GLTFNodeIndex, Node *> &mesh_track_i : p_state->scene_nodes) { | 
| 6943 | 				if (mesh_track_i.value == node) { | 
| 6944 | 					mesh_index = mesh_track_i.key; | 
| 6945 | 				} | 
| 6946 | 			} | 
| 6947 | 			ERR_CONTINUE(mesh_index == -1); | 
| 6948 | 			HashMap<int, GLTFAnimation::Track> &tracks = gltf_animation->get_tracks(); | 
| 6949 | 			GLTFAnimation::Track track = gltf_animation->get_tracks().has(mesh_index) ? gltf_animation->get_tracks()[mesh_index] : GLTFAnimation::Track(); | 
| 6950 | 			if (!tracks.has(mesh_index)) { | 
| 6951 | 				for (int32_t shape_i = 0; shape_i < mesh->get_blend_shape_count(); shape_i++) { | 
| 6952 | 					String shape_name = mesh->get_blend_shape_name(shape_i); | 
| 6953 | 					NodePath shape_path = String(path) + ":"  + shape_name; | 
| 6954 | 					int32_t shape_track_i = animation->find_track(shape_path, Animation::TYPE_BLEND_SHAPE); | 
| 6955 | 					if (shape_track_i == -1) { | 
| 6956 | 						GLTFAnimation::Channel<real_t> weight; | 
| 6957 | 						weight.interpolation = GLTFAnimation::INTERP_LINEAR; | 
| 6958 | 						weight.times.push_back(0.0f); | 
| 6959 | 						weight.times.push_back(0.0f); | 
| 6960 | 						weight.values.push_back(0.0f); | 
| 6961 | 						weight.values.push_back(0.0f); | 
| 6962 | 						track.weight_tracks.push_back(weight); | 
| 6963 | 						continue; | 
| 6964 | 					} | 
| 6965 | 					Animation::InterpolationType interpolation = animation->track_get_interpolation_type(track_i); | 
| 6966 | 					GLTFAnimation::Interpolation gltf_interpolation = GLTFAnimation::INTERP_LINEAR; | 
| 6967 | 					if (interpolation == Animation::InterpolationType::INTERPOLATION_LINEAR) { | 
| 6968 | 						gltf_interpolation = GLTFAnimation::INTERP_LINEAR; | 
| 6969 | 					} else if (interpolation == Animation::InterpolationType::INTERPOLATION_NEAREST) { | 
| 6970 | 						gltf_interpolation = GLTFAnimation::INTERP_STEP; | 
| 6971 | 					} else if (interpolation == Animation::InterpolationType::INTERPOLATION_CUBIC) { | 
| 6972 | 						gltf_interpolation = GLTFAnimation::INTERP_CUBIC_SPLINE; | 
| 6973 | 					} | 
| 6974 | 					int32_t key_count = animation->track_get_key_count(shape_track_i); | 
| 6975 | 					GLTFAnimation::Channel<real_t> weight; | 
| 6976 | 					weight.interpolation = gltf_interpolation; | 
| 6977 | 					weight.times.resize(key_count); | 
| 6978 | 					for (int32_t time_i = 0; time_i < key_count; time_i++) { | 
| 6979 | 						weight.times.write[time_i] = animation->track_get_key_time(shape_track_i, time_i); | 
| 6980 | 					} | 
| 6981 | 					weight.values.resize(key_count); | 
| 6982 | 					for (int32_t value_i = 0; value_i < key_count; value_i++) { | 
| 6983 | 						weight.values.write[value_i] = animation->track_get_key_value(shape_track_i, value_i); | 
| 6984 | 					} | 
| 6985 | 					track.weight_tracks.push_back(weight); | 
| 6986 | 				} | 
| 6987 | 				tracks[mesh_index] = track; | 
| 6988 | 			} | 
| 6989 | 		} else if (String(final_track_path).contains(":" )) { | 
| 6990 | 			//Process skeleton | 
| 6991 | 			const Vector<String> node_suffix = String(final_track_path).split(":" ); | 
| 6992 | 			const String node = node_suffix[0]; | 
| 6993 | 			const NodePath node_path = node; | 
| 6994 | 			const String suffix = node_suffix[1]; | 
| 6995 | 			Node *godot_node = animation_base_node->get_node_or_null(node_path); | 
| 6996 | 			if (!godot_node) { | 
| 6997 | 				continue; | 
| 6998 | 			} | 
| 6999 | 			Skeleton3D *skeleton = cast_to<Skeleton3D>(animation_base_node->get_node_or_null(node)); | 
| 7000 | 			if (!skeleton) { | 
| 7001 | 				continue; | 
| 7002 | 			} | 
| 7003 | 			GLTFSkeletonIndex skeleton_gltf_i = -1; | 
| 7004 | 			for (GLTFSkeletonIndex skeleton_i = 0; skeleton_i < p_state->skeletons.size(); skeleton_i++) { | 
| 7005 | 				if (p_state->skeletons[skeleton_i]->godot_skeleton == cast_to<Skeleton3D>(godot_node)) { | 
| 7006 | 					skeleton = p_state->skeletons[skeleton_i]->godot_skeleton; | 
| 7007 | 					skeleton_gltf_i = skeleton_i; | 
| 7008 | 					ERR_CONTINUE(!skeleton); | 
| 7009 | 					Ref<GLTFSkeleton> skeleton_gltf = p_state->skeletons[skeleton_gltf_i]; | 
| 7010 | 					int32_t bone = skeleton->find_bone(suffix); | 
| 7011 | 					ERR_CONTINUE_MSG(bone == -1, vformat("Cannot find the bone %s." , suffix)); | 
| 7012 | 					if (!skeleton_gltf->godot_bone_node.has(bone)) { | 
| 7013 | 						continue; | 
| 7014 | 					} | 
| 7015 | 					GLTFNodeIndex node_i = skeleton_gltf->godot_bone_node[bone]; | 
| 7016 | 					HashMap<int, GLTFAnimation::Track>::Iterator property_track_i = gltf_animation->get_tracks().find(node_i); | 
| 7017 | 					GLTFAnimation::Track track; | 
| 7018 | 					if (property_track_i) { | 
| 7019 | 						track = property_track_i->value; | 
| 7020 | 					} | 
| 7021 | 					track = _convert_animation_track(p_state, track, animation, track_i, node_i); | 
| 7022 | 					gltf_animation->get_tracks()[node_i] = track; | 
| 7023 | 				} | 
| 7024 | 			} | 
| 7025 | 		} else if (!String(final_track_path).contains(":" )) { | 
| 7026 | 			ERR_CONTINUE(!animation_base_node); | 
| 7027 | 			Node *godot_node = animation_base_node->get_node_or_null(final_track_path); | 
| 7028 | 			ERR_CONTINUE_MSG(!godot_node, vformat("Cannot get the node from a skeleton path %s." , final_track_path)); | 
| 7029 | 			for (const KeyValue<GLTFNodeIndex, Node *> &scene_node_i : p_state->scene_nodes) { | 
| 7030 | 				if (scene_node_i.value == godot_node) { | 
| 7031 | 					GLTFNodeIndex node_i = scene_node_i.key; | 
| 7032 | 					HashMap<int, GLTFAnimation::Track>::Iterator node_track_i = gltf_animation->get_tracks().find(node_i); | 
| 7033 | 					GLTFAnimation::Track track; | 
| 7034 | 					if (node_track_i) { | 
| 7035 | 						track = node_track_i->value; | 
| 7036 | 					} | 
| 7037 | 					track = _convert_animation_track(p_state, track, animation, track_i, node_i); | 
| 7038 | 					gltf_animation->get_tracks()[node_i] = track; | 
| 7039 | 					break; | 
| 7040 | 				} | 
| 7041 | 			} | 
| 7042 | 		} | 
| 7043 | 	} | 
| 7044 | 	if (gltf_animation->get_tracks().size()) { | 
| 7045 | 		p_state->animations.push_back(gltf_animation); | 
| 7046 | 	} | 
| 7047 | } | 
| 7048 |  | 
| 7049 | Error GLTFDocument::_parse(Ref<GLTFState> p_state, String p_path, Ref<FileAccess> p_file) { | 
| 7050 | 	Error err; | 
| 7051 | 	if (p_file.is_null()) { | 
| 7052 | 		return FAILED; | 
| 7053 | 	} | 
| 7054 | 	p_file->seek(0); | 
| 7055 | 	uint32_t magic = p_file->get_32(); | 
| 7056 | 	if (magic == 0x46546C67) { | 
| 7057 | 		//binary file | 
| 7058 | 		//text file | 
| 7059 | 		p_file->seek(0); | 
| 7060 | 		err = _parse_glb(p_file, p_state); | 
| 7061 | 		if (err != OK) { | 
| 7062 | 			return err; | 
| 7063 | 		} | 
| 7064 | 	} else { | 
| 7065 | 		p_file->seek(0); | 
| 7066 | 		String text = p_file->get_as_utf8_string(); | 
| 7067 | 		JSON json; | 
| 7068 | 		err = json.parse(text); | 
| 7069 | 		if (err != OK) { | 
| 7070 | 			_err_print_error("" , "" , json.get_error_line(), json.get_error_message().utf8().get_data(), false, ERR_HANDLER_SCRIPT); | 
| 7071 | 		} | 
| 7072 | 		ERR_FAIL_COND_V(err != OK, ERR_PARSE_ERROR); | 
| 7073 | 		p_state->json = json.get_data(); | 
| 7074 | 	} | 
| 7075 |  | 
| 7076 | 	err = _parse_asset_header(p_state); | 
| 7077 | 	ERR_FAIL_COND_V(err != OK, err); | 
| 7078 |  | 
| 7079 | 	document_extensions.clear(); | 
| 7080 | 	for (Ref<GLTFDocumentExtension> ext : all_document_extensions) { | 
| 7081 | 		ERR_CONTINUE(ext.is_null()); | 
| 7082 | 		err = ext->import_preflight(p_state, p_state->json["extensionsUsed" ]); | 
| 7083 | 		if (err == OK) { | 
| 7084 | 			document_extensions.push_back(ext); | 
| 7085 | 		} | 
| 7086 | 	} | 
| 7087 |  | 
| 7088 | 	err = _parse_gltf_state(p_state, p_path); | 
| 7089 | 	ERR_FAIL_COND_V(err != OK, err); | 
| 7090 |  | 
| 7091 | 	return OK; | 
| 7092 | } | 
| 7093 |  | 
| 7094 | Dictionary _serialize_texture_transform_uv(Vector2 p_offset, Vector2 p_scale) { | 
| 7095 | 	Dictionary texture_transform; | 
| 7096 | 	bool is_offset = p_offset != Vector2(0.0, 0.0); | 
| 7097 | 	if (is_offset) { | 
| 7098 | 		Array offset; | 
| 7099 | 		offset.resize(2); | 
| 7100 | 		offset[0] = p_offset.x; | 
| 7101 | 		offset[1] = p_offset.y; | 
| 7102 | 		texture_transform["offset" ] = offset; | 
| 7103 | 	} | 
| 7104 | 	bool is_scaled = p_scale != Vector2(1.0, 1.0); | 
| 7105 | 	if (is_scaled) { | 
| 7106 | 		Array scale; | 
| 7107 | 		scale.resize(2); | 
| 7108 | 		scale[0] = p_scale.x; | 
| 7109 | 		scale[1] = p_scale.y; | 
| 7110 | 		texture_transform["scale" ] = scale; | 
| 7111 | 	} | 
| 7112 | 	Dictionary extension; | 
| 7113 | 	// Note: Godot doesn't support texture rotation. | 
| 7114 | 	if (is_offset || is_scaled) { | 
| 7115 | 		extension["KHR_texture_transform" ] = texture_transform; | 
| 7116 | 	} | 
| 7117 | 	return extension; | 
| 7118 | } | 
| 7119 |  | 
| 7120 | Dictionary GLTFDocument::_serialize_texture_transform_uv1(Ref<BaseMaterial3D> p_material) { | 
| 7121 | 	ERR_FAIL_NULL_V(p_material, Dictionary()); | 
| 7122 | 	Vector3 offset = p_material->get_uv1_offset(); | 
| 7123 | 	Vector3 scale = p_material->get_uv1_scale(); | 
| 7124 | 	return _serialize_texture_transform_uv(Vector2(offset.x, offset.y), Vector2(scale.x, scale.y)); | 
| 7125 | } | 
| 7126 |  | 
| 7127 | Dictionary GLTFDocument::_serialize_texture_transform_uv2(Ref<BaseMaterial3D> p_material) { | 
| 7128 | 	ERR_FAIL_NULL_V(p_material, Dictionary()); | 
| 7129 | 	Vector3 offset = p_material->get_uv2_offset(); | 
| 7130 | 	Vector3 scale = p_material->get_uv2_scale(); | 
| 7131 | 	return _serialize_texture_transform_uv(Vector2(offset.x, offset.y), Vector2(scale.x, scale.y)); | 
| 7132 | } | 
| 7133 |  | 
| 7134 | Error GLTFDocument::(Ref<GLTFState> p_state) { | 
| 7135 | 	const String version = "2.0" ; | 
| 7136 | 	p_state->major_version = version.get_slice("." , 0).to_int(); | 
| 7137 | 	p_state->minor_version = version.get_slice("." , 1).to_int(); | 
| 7138 | 	Dictionary asset; | 
| 7139 | 	asset["version" ] = version; | 
| 7140 | 	if (!p_state->copyright.is_empty()) { | 
| 7141 | 		asset["copyright" ] = p_state->copyright; | 
| 7142 | 	} | 
| 7143 | 	String hash = String(VERSION_HASH); | 
| 7144 | 	asset["generator" ] = String(VERSION_FULL_NAME) + String("@" ) + (hash.is_empty() ? String("unknown" ) : hash); | 
| 7145 | 	p_state->json["asset" ] = asset; | 
| 7146 | 	ERR_FAIL_COND_V(!asset.has("version" ), Error::FAILED); | 
| 7147 | 	ERR_FAIL_COND_V(!p_state->json.has("asset" ), Error::FAILED); | 
| 7148 | 	return OK; | 
| 7149 | } | 
| 7150 |  | 
| 7151 | Error GLTFDocument::_serialize_file(Ref<GLTFState> p_state, const String p_path) { | 
| 7152 | 	Error err = FAILED; | 
| 7153 | 	if (p_path.to_lower().ends_with("glb" )) { | 
| 7154 | 		err = _encode_buffer_glb(p_state, p_path); | 
| 7155 | 		ERR_FAIL_COND_V(err != OK, err); | 
| 7156 | 		Ref<FileAccess> file = FileAccess::open(p_path, FileAccess::WRITE, &err); | 
| 7157 | 		ERR_FAIL_COND_V(file.is_null(), FAILED); | 
| 7158 |  | 
| 7159 | 		String json = Variant(p_state->json).to_json_string(); | 
| 7160 |  | 
| 7161 | 		const uint32_t magic = 0x46546C67; // GLTF | 
| 7162 | 		const int32_t  = 12; | 
| 7163 | 		const int32_t  = 8; | 
| 7164 | 		CharString cs = json.utf8(); | 
| 7165 | 		const uint32_t text_data_length = cs.length(); | 
| 7166 | 		const uint32_t text_chunk_length = ((text_data_length + 3) & (~3)); | 
| 7167 | 		const uint32_t text_chunk_type = 0x4E4F534A; //JSON | 
| 7168 |  | 
| 7169 | 		uint32_t binary_data_length = 0; | 
| 7170 | 		if (p_state->buffers.size()) { | 
| 7171 | 			binary_data_length = p_state->buffers[0].size(); | 
| 7172 | 		} | 
| 7173 | 		const uint32_t binary_chunk_length = ((binary_data_length + 3) & (~3)); | 
| 7174 | 		const uint32_t binary_chunk_type = 0x004E4942; //BIN | 
| 7175 |  | 
| 7176 | 		file->create(FileAccess::ACCESS_RESOURCES); | 
| 7177 | 		file->store_32(magic); | 
| 7178 | 		file->store_32(p_state->major_version); // version | 
| 7179 | 		file->store_32(header_size + chunk_header_size + text_chunk_length + chunk_header_size + binary_chunk_length); // length | 
| 7180 | 		file->store_32(text_chunk_length); | 
| 7181 | 		file->store_32(text_chunk_type); | 
| 7182 | 		file->store_buffer((uint8_t *)&cs[0], cs.length()); | 
| 7183 | 		for (uint32_t pad_i = text_data_length; pad_i < text_chunk_length; pad_i++) { | 
| 7184 | 			file->store_8(' '); | 
| 7185 | 		} | 
| 7186 | 		if (binary_chunk_length) { | 
| 7187 | 			file->store_32(binary_chunk_length); | 
| 7188 | 			file->store_32(binary_chunk_type); | 
| 7189 | 			file->store_buffer(p_state->buffers[0].ptr(), binary_data_length); | 
| 7190 | 		} | 
| 7191 | 		for (uint32_t pad_i = binary_data_length; pad_i < binary_chunk_length; pad_i++) { | 
| 7192 | 			file->store_8(0); | 
| 7193 | 		} | 
| 7194 | 	} else { | 
| 7195 | 		err = _encode_buffer_bins(p_state, p_path); | 
| 7196 | 		ERR_FAIL_COND_V(err != OK, err); | 
| 7197 | 		Ref<FileAccess> file = FileAccess::open(p_path, FileAccess::WRITE, &err); | 
| 7198 | 		ERR_FAIL_COND_V(file.is_null(), FAILED); | 
| 7199 |  | 
| 7200 | 		file->create(FileAccess::ACCESS_RESOURCES); | 
| 7201 | 		String json = Variant(p_state->json).to_json_string(); | 
| 7202 | 		file->store_string(json); | 
| 7203 | 	} | 
| 7204 | 	return err; | 
| 7205 | } | 
| 7206 |  | 
| 7207 | void GLTFDocument::_bind_methods() { | 
| 7208 | 	ClassDB::bind_method(D_METHOD("append_from_file" , "path" , "state" , "flags" , "base_path" ), | 
| 7209 | 			&GLTFDocument::append_from_file, DEFVAL(0), DEFVAL(String())); | 
| 7210 | 	ClassDB::bind_method(D_METHOD("append_from_buffer" , "bytes" , "base_path" , "state" , "flags" ), | 
| 7211 | 			&GLTFDocument::append_from_buffer, DEFVAL(0)); | 
| 7212 | 	ClassDB::bind_method(D_METHOD("append_from_scene" , "node" , "state" , "flags" ), | 
| 7213 | 			&GLTFDocument::append_from_scene, DEFVAL(0)); | 
| 7214 | 	ClassDB::bind_method(D_METHOD("generate_scene" , "state" , "bake_fps" , "trimming" , "remove_immutable_tracks" ), | 
| 7215 | 			&GLTFDocument::generate_scene, DEFVAL(30), DEFVAL(false), DEFVAL(true)); | 
| 7216 | 	ClassDB::bind_method(D_METHOD("generate_buffer" , "state" ), | 
| 7217 | 			&GLTFDocument::generate_buffer); | 
| 7218 | 	ClassDB::bind_method(D_METHOD("write_to_filesystem" , "state" , "path" ), | 
| 7219 | 			&GLTFDocument::write_to_filesystem); | 
| 7220 |  | 
| 7221 | 	ClassDB::bind_method(D_METHOD("set_image_format" , "image_format" ), &GLTFDocument::set_image_format); | 
| 7222 | 	ClassDB::bind_method(D_METHOD("get_image_format" ), &GLTFDocument::get_image_format); | 
| 7223 | 	ClassDB::bind_method(D_METHOD("set_lossy_quality" , "lossy_quality" ), &GLTFDocument::set_lossy_quality); | 
| 7224 | 	ClassDB::bind_method(D_METHOD("get_lossy_quality" ), &GLTFDocument::get_lossy_quality); | 
| 7225 |  | 
| 7226 | 	ADD_PROPERTY(PropertyInfo(Variant::STRING, "image_format" ), "set_image_format" , "get_image_format" ); | 
| 7227 | 	ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "lossy_quality" ), "set_lossy_quality" , "get_lossy_quality" ); | 
| 7228 |  | 
| 7229 | 	ClassDB::bind_static_method("GLTFDocument" , D_METHOD("register_gltf_document_extension" , "extension" , "first_priority" ), | 
| 7230 | 			&GLTFDocument::register_gltf_document_extension, DEFVAL(false)); | 
| 7231 | 	ClassDB::bind_static_method("GLTFDocument" , D_METHOD("unregister_gltf_document_extension" , "extension" ), | 
| 7232 | 			&GLTFDocument::unregister_gltf_document_extension); | 
| 7233 | } | 
| 7234 |  | 
| 7235 | void GLTFDocument::_build_parent_hierachy(Ref<GLTFState> p_state) { | 
| 7236 | 	// build the hierarchy | 
| 7237 | 	for (GLTFNodeIndex node_i = 0; node_i < p_state->nodes.size(); node_i++) { | 
| 7238 | 		for (int j = 0; j < p_state->nodes[node_i]->children.size(); j++) { | 
| 7239 | 			GLTFNodeIndex child_i = p_state->nodes[node_i]->children[j]; | 
| 7240 | 			ERR_FAIL_INDEX(child_i, p_state->nodes.size()); | 
| 7241 | 			if (p_state->nodes.write[child_i]->parent != -1) { | 
| 7242 | 				continue; | 
| 7243 | 			} | 
| 7244 | 			p_state->nodes.write[child_i]->parent = node_i; | 
| 7245 | 		} | 
| 7246 | 	} | 
| 7247 | } | 
| 7248 |  | 
| 7249 | Vector<Ref<GLTFDocumentExtension>> GLTFDocument::all_document_extensions; | 
| 7250 |  | 
| 7251 | void GLTFDocument::register_gltf_document_extension(Ref<GLTFDocumentExtension> p_extension, bool p_first_priority) { | 
| 7252 | 	if (all_document_extensions.find(p_extension) == -1) { | 
| 7253 | 		if (p_first_priority) { | 
| 7254 | 			all_document_extensions.insert(0, p_extension); | 
| 7255 | 		} else { | 
| 7256 | 			all_document_extensions.push_back(p_extension); | 
| 7257 | 		} | 
| 7258 | 	} | 
| 7259 | } | 
| 7260 |  | 
| 7261 | void GLTFDocument::unregister_gltf_document_extension(Ref<GLTFDocumentExtension> p_extension) { | 
| 7262 | 	all_document_extensions.erase(p_extension); | 
| 7263 | } | 
| 7264 |  | 
| 7265 | void GLTFDocument::unregister_all_gltf_document_extensions() { | 
| 7266 | 	all_document_extensions.clear(); | 
| 7267 | } | 
| 7268 |  | 
| 7269 | PackedByteArray GLTFDocument::_serialize_glb_buffer(Ref<GLTFState> p_state, Error *r_err) { | 
| 7270 | 	Error err = _encode_buffer_glb(p_state, "" ); | 
| 7271 | 	if (r_err) { | 
| 7272 | 		*r_err = err; | 
| 7273 | 	} | 
| 7274 | 	ERR_FAIL_COND_V(err != OK, PackedByteArray()); | 
| 7275 | 	String json = Variant(p_state->json).to_json_string(); | 
| 7276 |  | 
| 7277 | 	const uint32_t magic = 0x46546C67; // GLTF | 
| 7278 | 	const int32_t  = 12; | 
| 7279 | 	const int32_t  = 8; | 
| 7280 |  | 
| 7281 | 	int32_t padding = (chunk_header_size + json.utf8().length()) % 4; | 
| 7282 | 	json += String(" " ).repeat(padding); | 
| 7283 |  | 
| 7284 | 	CharString cs = json.utf8(); | 
| 7285 | 	const uint32_t text_chunk_length = cs.length(); | 
| 7286 |  | 
| 7287 | 	const uint32_t text_chunk_type = 0x4E4F534A; //JSON | 
| 7288 | 	int32_t binary_data_length = 0; | 
| 7289 | 	if (p_state->buffers.size()) { | 
| 7290 | 		binary_data_length = p_state->buffers[0].size(); | 
| 7291 | 	} | 
| 7292 | 	const int32_t binary_chunk_length = binary_data_length; | 
| 7293 | 	const int32_t binary_chunk_type = 0x004E4942; //BIN | 
| 7294 |  | 
| 7295 | 	Ref<StreamPeerBuffer> buffer; | 
| 7296 | 	buffer.instantiate(); | 
| 7297 | 	buffer->put_32(magic); | 
| 7298 | 	buffer->put_32(p_state->major_version); // version | 
| 7299 | 	buffer->put_32(header_size + chunk_header_size + text_chunk_length + chunk_header_size + binary_data_length); // length | 
| 7300 | 	buffer->put_32(text_chunk_length); | 
| 7301 | 	buffer->put_32(text_chunk_type); | 
| 7302 | 	buffer->put_data((uint8_t *)&cs[0], cs.length()); | 
| 7303 | 	if (binary_chunk_length) { | 
| 7304 | 		buffer->put_32(binary_chunk_length); | 
| 7305 | 		buffer->put_32(binary_chunk_type); | 
| 7306 | 		buffer->put_data(p_state->buffers[0].ptr(), binary_data_length); | 
| 7307 | 	} | 
| 7308 | 	return buffer->get_data_array(); | 
| 7309 | } | 
| 7310 |  | 
| 7311 | PackedByteArray GLTFDocument::generate_buffer(Ref<GLTFState> p_state) { | 
| 7312 | 	ERR_FAIL_NULL_V(p_state, PackedByteArray()); | 
| 7313 | 	// For buffers, set the state filename to an empty string, but | 
| 7314 | 	// don't touch the base path, in case the user set it manually. | 
| 7315 | 	p_state->filename = "" ; | 
| 7316 | 	Error err = _serialize(p_state); | 
| 7317 | 	ERR_FAIL_COND_V(err != OK, PackedByteArray()); | 
| 7318 | 	PackedByteArray bytes = _serialize_glb_buffer(p_state, &err); | 
| 7319 | 	return bytes; | 
| 7320 | } | 
| 7321 |  | 
| 7322 | Error GLTFDocument::write_to_filesystem(Ref<GLTFState> p_state, const String &p_path) { | 
| 7323 | 	ERR_FAIL_NULL_V(p_state, ERR_INVALID_PARAMETER); | 
| 7324 | 	p_state->base_path = p_path.get_base_dir(); | 
| 7325 | 	p_state->filename = p_path.get_file(); | 
| 7326 | 	Error err = _serialize(p_state); | 
| 7327 | 	if (err != OK) { | 
| 7328 | 		return err; | 
| 7329 | 	} | 
| 7330 | 	err = _serialize_file(p_state, p_path); | 
| 7331 | 	if (err != OK) { | 
| 7332 | 		return Error::FAILED; | 
| 7333 | 	} | 
| 7334 | 	return OK; | 
| 7335 | } | 
| 7336 |  | 
| 7337 | Node *GLTFDocument::_generate_scene_node_tree(Ref<GLTFState> p_state) { | 
| 7338 | 	Node *single_root = memnew(Node3D); | 
| 7339 | 	for (int32_t root_i = 0; root_i < p_state->root_nodes.size(); root_i++) { | 
| 7340 | 		_generate_scene_node(p_state, p_state->root_nodes[root_i], single_root, single_root); | 
| 7341 | 	} | 
| 7342 | 	// Assign the scene name and single root name to each other | 
| 7343 | 	// if one is missing, or do nothing if both are already set. | 
| 7344 | 	if (unlikely(p_state->scene_name.is_empty())) { | 
| 7345 | 		p_state->scene_name = single_root->get_name(); | 
| 7346 | 	} else if (single_root->get_name() == StringName()) { | 
| 7347 | 		single_root->set_name(_gen_unique_name(p_state, p_state->scene_name)); | 
| 7348 | 	} | 
| 7349 | 	return single_root; | 
| 7350 | } | 
| 7351 |  | 
| 7352 | Node *GLTFDocument::generate_scene(Ref<GLTFState> p_state, float p_bake_fps, bool p_trimming, bool p_remove_immutable_tracks) { | 
| 7353 | 	ERR_FAIL_NULL_V(p_state, nullptr); | 
| 7354 | 	ERR_FAIL_INDEX_V(0, p_state->root_nodes.size(), nullptr); | 
| 7355 | 	Error err = OK; | 
| 7356 | 	Node *root = _generate_scene_node_tree(p_state); | 
| 7357 | 	ERR_FAIL_NULL_V(root, nullptr); | 
| 7358 | 	_process_mesh_instances(p_state); | 
| 7359 | 	if (p_state->get_create_animations() && p_state->animations.size()) { | 
| 7360 | 		AnimationPlayer *ap = memnew(AnimationPlayer); | 
| 7361 | 		root->add_child(ap, true); | 
| 7362 | 		ap->set_owner(root); | 
| 7363 | 		for (int i = 0; i < p_state->animations.size(); i++) { | 
| 7364 | 			_import_animation(p_state, ap, i, p_bake_fps, p_trimming, p_remove_immutable_tracks); | 
| 7365 | 		} | 
| 7366 | 	} | 
| 7367 | 	for (KeyValue<GLTFNodeIndex, Node *> E : p_state->scene_nodes) { | 
| 7368 | 		ERR_CONTINUE(!E.value); | 
| 7369 | 		for (Ref<GLTFDocumentExtension> ext : document_extensions) { | 
| 7370 | 			ERR_CONTINUE(ext.is_null()); | 
| 7371 | 			ERR_CONTINUE(!p_state->json.has("nodes" )); | 
| 7372 | 			Array nodes = p_state->json["nodes" ]; | 
| 7373 | 			ERR_CONTINUE(E.key >= nodes.size()); | 
| 7374 | 			ERR_CONTINUE(E.key < 0); | 
| 7375 | 			Dictionary node_json = nodes[E.key]; | 
| 7376 | 			Ref<GLTFNode> gltf_node = p_state->nodes[E.key]; | 
| 7377 | 			err = ext->import_node(p_state, gltf_node, node_json, E.value); | 
| 7378 | 			ERR_CONTINUE(err != OK); | 
| 7379 | 		} | 
| 7380 | 	} | 
| 7381 | 	for (Ref<GLTFDocumentExtension> ext : document_extensions) { | 
| 7382 | 		ERR_CONTINUE(ext.is_null()); | 
| 7383 | 		err = ext->import_post(p_state, root); | 
| 7384 | 		ERR_CONTINUE(err != OK); | 
| 7385 | 	} | 
| 7386 | 	ERR_FAIL_NULL_V(root, nullptr); | 
| 7387 | 	return root; | 
| 7388 | } | 
| 7389 |  | 
| 7390 | Error GLTFDocument::append_from_scene(Node *p_node, Ref<GLTFState> p_state, uint32_t p_flags) { | 
| 7391 | 	ERR_FAIL_COND_V(p_state.is_null(), FAILED); | 
| 7392 | 	p_state->use_named_skin_binds = p_flags & GLTF_IMPORT_USE_NAMED_SKIN_BINDS; | 
| 7393 | 	p_state->discard_meshes_and_materials = p_flags & GLTF_IMPORT_DISCARD_MESHES_AND_MATERIALS; | 
| 7394 | 	if (!p_state->buffers.size()) { | 
| 7395 | 		p_state->buffers.push_back(Vector<uint8_t>()); | 
| 7396 | 	} | 
| 7397 | 	// Perform export preflight for document extensions. Only extensions that | 
| 7398 | 	// return OK will be used for the rest of the export steps. | 
| 7399 | 	document_extensions.clear(); | 
| 7400 | 	for (Ref<GLTFDocumentExtension> ext : all_document_extensions) { | 
| 7401 | 		ERR_CONTINUE(ext.is_null()); | 
| 7402 | 		Error err = ext->export_preflight(p_state, p_node); | 
| 7403 | 		if (err == OK) { | 
| 7404 | 			document_extensions.push_back(ext); | 
| 7405 | 		} | 
| 7406 | 	} | 
| 7407 | 	// Add the root node(s) and their descendants to the state. | 
| 7408 | 	_convert_scene_node(p_state, p_node, -1, -1); | 
| 7409 | 	return OK; | 
| 7410 | } | 
| 7411 |  | 
| 7412 | Error GLTFDocument::append_from_buffer(PackedByteArray p_bytes, String p_base_path, Ref<GLTFState> p_state, uint32_t p_flags) { | 
| 7413 | 	ERR_FAIL_COND_V(p_state.is_null(), FAILED); | 
| 7414 | 	// TODO Add missing texture and missing .bin file paths to r_missing_deps 2021-09-10 fire | 
| 7415 | 	Error err = FAILED; | 
| 7416 | 	p_state->use_named_skin_binds = p_flags & GLTF_IMPORT_USE_NAMED_SKIN_BINDS; | 
| 7417 | 	p_state->discard_meshes_and_materials = p_flags & GLTF_IMPORT_DISCARD_MESHES_AND_MATERIALS; | 
| 7418 |  | 
| 7419 | 	Ref<FileAccessMemory> file_access; | 
| 7420 | 	file_access.instantiate(); | 
| 7421 | 	file_access->open_custom(p_bytes.ptr(), p_bytes.size()); | 
| 7422 | 	p_state->base_path = p_base_path.get_base_dir(); | 
| 7423 | 	err = _parse(p_state, p_state->base_path, file_access); | 
| 7424 | 	ERR_FAIL_COND_V(err != OK, err); | 
| 7425 | 	for (Ref<GLTFDocumentExtension> ext : document_extensions) { | 
| 7426 | 		ERR_CONTINUE(ext.is_null()); | 
| 7427 | 		err = ext->import_post_parse(p_state); | 
| 7428 | 		ERR_FAIL_COND_V(err != OK, err); | 
| 7429 | 	} | 
| 7430 | 	return OK; | 
| 7431 | } | 
| 7432 |  | 
| 7433 | Error GLTFDocument::(Ref<GLTFState> p_state) { | 
| 7434 | 	if (!p_state->json.has("asset" )) { | 
| 7435 | 		return ERR_PARSE_ERROR; | 
| 7436 | 	} | 
| 7437 | 	Dictionary asset = p_state->json["asset" ]; | 
| 7438 | 	if (!asset.has("version" )) { | 
| 7439 | 		return ERR_PARSE_ERROR; | 
| 7440 | 	} | 
| 7441 | 	String version = asset["version" ]; | 
| 7442 | 	p_state->major_version = version.get_slice("." , 0).to_int(); | 
| 7443 | 	p_state->minor_version = version.get_slice("." , 1).to_int(); | 
| 7444 | 	if (asset.has("copyright" )) { | 
| 7445 | 		p_state->copyright = asset["copyright" ]; | 
| 7446 | 	} | 
| 7447 | 	return OK; | 
| 7448 | } | 
| 7449 |  | 
| 7450 | Error GLTFDocument::_parse_gltf_state(Ref<GLTFState> p_state, const String &p_search_path) { | 
| 7451 | 	Error err; | 
| 7452 |  | 
| 7453 | 	/* PARSE EXTENSIONS */ | 
| 7454 | 	err = _parse_gltf_extensions(p_state); | 
| 7455 | 	ERR_FAIL_COND_V(err != OK, ERR_PARSE_ERROR); | 
| 7456 |  | 
| 7457 | 	/* PARSE SCENE */ | 
| 7458 | 	err = _parse_scenes(p_state); | 
| 7459 | 	ERR_FAIL_COND_V(err != OK, ERR_PARSE_ERROR); | 
| 7460 |  | 
| 7461 | 	/* PARSE NODES */ | 
| 7462 | 	err = _parse_nodes(p_state); | 
| 7463 | 	ERR_FAIL_COND_V(err != OK, ERR_PARSE_ERROR); | 
| 7464 |  | 
| 7465 | 	/* PARSE BUFFERS */ | 
| 7466 | 	err = _parse_buffers(p_state, p_search_path); | 
| 7467 |  | 
| 7468 | 	ERR_FAIL_COND_V(err != OK, ERR_PARSE_ERROR); | 
| 7469 |  | 
| 7470 | 	/* PARSE BUFFER VIEWS */ | 
| 7471 | 	err = _parse_buffer_views(p_state); | 
| 7472 |  | 
| 7473 | 	ERR_FAIL_COND_V(err != OK, ERR_PARSE_ERROR); | 
| 7474 |  | 
| 7475 | 	/* PARSE ACCESSORS */ | 
| 7476 | 	err = _parse_accessors(p_state); | 
| 7477 |  | 
| 7478 | 	ERR_FAIL_COND_V(err != OK, ERR_PARSE_ERROR); | 
| 7479 |  | 
| 7480 | 	if (!p_state->discard_meshes_and_materials) { | 
| 7481 | 		/* PARSE IMAGES */ | 
| 7482 | 		err = _parse_images(p_state, p_search_path); | 
| 7483 |  | 
| 7484 | 		ERR_FAIL_COND_V(err != OK, ERR_PARSE_ERROR); | 
| 7485 |  | 
| 7486 | 		/* PARSE TEXTURE SAMPLERS */ | 
| 7487 | 		err = _parse_texture_samplers(p_state); | 
| 7488 |  | 
| 7489 | 		ERR_FAIL_COND_V(err != OK, ERR_PARSE_ERROR); | 
| 7490 |  | 
| 7491 | 		/* PARSE TEXTURES */ | 
| 7492 | 		err = _parse_textures(p_state); | 
| 7493 |  | 
| 7494 | 		ERR_FAIL_COND_V(err != OK, ERR_PARSE_ERROR); | 
| 7495 |  | 
| 7496 | 		/* PARSE TEXTURES */ | 
| 7497 | 		err = _parse_materials(p_state); | 
| 7498 |  | 
| 7499 | 		ERR_FAIL_COND_V(err != OK, ERR_PARSE_ERROR); | 
| 7500 | 	} | 
| 7501 |  | 
| 7502 | 	/* PARSE SKINS */ | 
| 7503 | 	err = _parse_skins(p_state); | 
| 7504 |  | 
| 7505 | 	ERR_FAIL_COND_V(err != OK, ERR_PARSE_ERROR); | 
| 7506 |  | 
| 7507 | 	/* DETERMINE SKELETONS */ | 
| 7508 | 	err = _determine_skeletons(p_state); | 
| 7509 | 	ERR_FAIL_COND_V(err != OK, ERR_PARSE_ERROR); | 
| 7510 |  | 
| 7511 | 	/* CREATE SKELETONS */ | 
| 7512 | 	err = _create_skeletons(p_state); | 
| 7513 | 	ERR_FAIL_COND_V(err != OK, ERR_PARSE_ERROR); | 
| 7514 |  | 
| 7515 | 	/* CREATE SKINS */ | 
| 7516 | 	err = _create_skins(p_state); | 
| 7517 | 	ERR_FAIL_COND_V(err != OK, ERR_PARSE_ERROR); | 
| 7518 |  | 
| 7519 | 	/* PARSE MESHES (we have enough info now) */ | 
| 7520 | 	err = _parse_meshes(p_state); | 
| 7521 | 	ERR_FAIL_COND_V(err != OK, ERR_PARSE_ERROR); | 
| 7522 |  | 
| 7523 | 	/* PARSE LIGHTS */ | 
| 7524 | 	err = _parse_lights(p_state); | 
| 7525 | 	ERR_FAIL_COND_V(err != OK, ERR_PARSE_ERROR); | 
| 7526 |  | 
| 7527 | 	/* PARSE CAMERAS */ | 
| 7528 | 	err = _parse_cameras(p_state); | 
| 7529 | 	ERR_FAIL_COND_V(err != OK, ERR_PARSE_ERROR); | 
| 7530 |  | 
| 7531 | 	/* PARSE ANIMATIONS */ | 
| 7532 | 	err = _parse_animations(p_state); | 
| 7533 | 	ERR_FAIL_COND_V(err != OK, ERR_PARSE_ERROR); | 
| 7534 |  | 
| 7535 | 	/* ASSIGN SCENE NAMES */ | 
| 7536 | 	_assign_node_names(p_state); | 
| 7537 |  | 
| 7538 | 	return OK; | 
| 7539 | } | 
| 7540 |  | 
| 7541 | Error GLTFDocument::append_from_file(String p_path, Ref<GLTFState> p_state, uint32_t p_flags, String p_base_path) { | 
| 7542 | 	// TODO Add missing texture and missing .bin file paths to r_missing_deps 2021-09-10 fire | 
| 7543 | 	if (p_state == Ref<GLTFState>()) { | 
| 7544 | 		p_state.instantiate(); | 
| 7545 | 	} | 
| 7546 | 	p_state->filename = p_path.get_file().get_basename(); | 
| 7547 | 	p_state->use_named_skin_binds = p_flags & GLTF_IMPORT_USE_NAMED_SKIN_BINDS; | 
| 7548 | 	p_state->discard_meshes_and_materials = p_flags & GLTF_IMPORT_DISCARD_MESHES_AND_MATERIALS; | 
| 7549 | 	Error err; | 
| 7550 | 	Ref<FileAccess> file = FileAccess::open(p_path, FileAccess::READ, &err); | 
| 7551 | 	ERR_FAIL_COND_V(err != OK, ERR_FILE_CANT_OPEN); | 
| 7552 | 	ERR_FAIL_NULL_V(file, ERR_FILE_CANT_OPEN); | 
| 7553 | 	String base_path = p_base_path; | 
| 7554 | 	if (base_path.is_empty()) { | 
| 7555 | 		base_path = p_path.get_base_dir(); | 
| 7556 | 	} | 
| 7557 | 	p_state->base_path = base_path; | 
| 7558 | 	err = _parse(p_state, base_path, file); | 
| 7559 | 	ERR_FAIL_COND_V(err != OK, err); | 
| 7560 | 	for (Ref<GLTFDocumentExtension> ext : document_extensions) { | 
| 7561 | 		ERR_CONTINUE(ext.is_null()); | 
| 7562 | 		err = ext->import_post_parse(p_state); | 
| 7563 | 		ERR_FAIL_COND_V(err != OK, err); | 
| 7564 | 	} | 
| 7565 | 	return OK; | 
| 7566 | } | 
| 7567 |  | 
| 7568 | Error GLTFDocument::_parse_gltf_extensions(Ref<GLTFState> p_state) { | 
| 7569 | 	ERR_FAIL_NULL_V(p_state, ERR_PARSE_ERROR); | 
| 7570 | 	if (p_state->json.has("extensionsUsed" )) { | 
| 7571 | 		Vector<String> ext_array = p_state->json["extensionsUsed" ]; | 
| 7572 | 		p_state->extensions_used = ext_array; | 
| 7573 | 	} | 
| 7574 | 	if (p_state->json.has("extensionsRequired" )) { | 
| 7575 | 		Vector<String> ext_array = p_state->json["extensionsRequired" ]; | 
| 7576 | 		p_state->extensions_required = ext_array; | 
| 7577 | 	} | 
| 7578 | 	HashSet<String> supported_extensions; | 
| 7579 | 	supported_extensions.insert("KHR_lights_punctual" ); | 
| 7580 | 	supported_extensions.insert("KHR_materials_pbrSpecularGlossiness" ); | 
| 7581 | 	supported_extensions.insert("KHR_texture_transform" ); | 
| 7582 | 	supported_extensions.insert("KHR_materials_unlit" ); | 
| 7583 | 	supported_extensions.insert("KHR_materials_emissive_strength" ); | 
| 7584 | 	for (Ref<GLTFDocumentExtension> ext : document_extensions) { | 
| 7585 | 		ERR_CONTINUE(ext.is_null()); | 
| 7586 | 		Vector<String> ext_supported_extensions = ext->get_supported_extensions(); | 
| 7587 | 		for (int i = 0; i < ext_supported_extensions.size(); ++i) { | 
| 7588 | 			supported_extensions.insert(ext_supported_extensions[i]); | 
| 7589 | 		} | 
| 7590 | 	} | 
| 7591 | 	Error ret = OK; | 
| 7592 | 	for (int i = 0; i < p_state->extensions_required.size(); i++) { | 
| 7593 | 		if (!supported_extensions.has(p_state->extensions_required[i])) { | 
| 7594 | 			ERR_PRINT("GLTF: Can't import file '"  + p_state->filename + "', required extension '"  + String(p_state->extensions_required[i]) + "' is not supported. Are you missing a GLTFDocumentExtension plugin?" ); | 
| 7595 | 			ret = ERR_UNAVAILABLE; | 
| 7596 | 		} | 
| 7597 | 	} | 
| 7598 | 	return ret; | 
| 7599 | } | 
| 7600 |  |