Ver Fonte

Updated meshoptimizer.

Бранимир Караџић há 6 anos atrás
pai
commit
f450d227c0

+ 3 - 0
3rdparty/meshoptimizer/.travis.yml

@@ -6,6 +6,9 @@ matrix:
       compiler: gcc
       compiler: gcc
     - os: linux
     - os: linux
       compiler: clang
       compiler: clang
+    - os: linux
+      compiler: gcc
+      arch: arm64
     - os: osx
     - os: osx
       compiler: clang
       compiler: clang
     - os: windows
     - os: windows

+ 13 - 10
3rdparty/meshoptimizer/CMakeLists.txt

@@ -57,24 +57,27 @@ if(BUILD_TOOLS)
     target_link_libraries(gltfpack meshoptimizer)
     target_link_libraries(gltfpack meshoptimizer)
     list(APPEND TARGETS gltfpack)
     list(APPEND TARGETS gltfpack)
 
 
-    set_target_properties(gltfpack PROPERTIES INSTALL_RPATH "$ORIGIN/../lib")
+    string(CONCAT RPATH "$ORIGIN/../" ${CMAKE_INSTALL_LIBDIR})
+    set_target_properties(gltfpack PROPERTIES INSTALL_RPATH ${RPATH})
 endif()
 endif()
 
 
+include(GNUInstallDirs)
+
 install(TARGETS ${TARGETS} EXPORT meshoptimizerTargets
 install(TARGETS ${TARGETS} EXPORT meshoptimizerTargets
-    RUNTIME DESTINATION bin
-    LIBRARY DESTINATION lib
-    ARCHIVE DESTINATION lib
-    INCLUDES DESTINATION include)
+    RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
+    LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
+    ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
+    INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
 
 
-install(FILES src/meshoptimizer.h DESTINATION include)
-install(EXPORT meshoptimizerTargets DESTINATION lib/cmake/meshoptimizer NAMESPACE meshoptimizer::)
+install(FILES src/meshoptimizer.h DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
+install(EXPORT meshoptimizerTargets DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/meshoptimizer NAMESPACE meshoptimizer::)
 
 
 # TARGET_PDB_FILE is available since 3.1
 # TARGET_PDB_FILE is available since 3.1
 if(MSVC AND NOT (CMAKE_VERSION VERSION_LESS "3.1"))
 if(MSVC AND NOT (CMAKE_VERSION VERSION_LESS "3.1"))
     foreach(TARGET ${TARGETS})
     foreach(TARGET ${TARGETS})
         get_target_property(TARGET_TYPE ${TARGET} TYPE)
         get_target_property(TARGET_TYPE ${TARGET} TYPE)
         if(NOT ${TARGET_TYPE} STREQUAL "STATIC_LIBRARY")
         if(NOT ${TARGET_TYPE} STREQUAL "STATIC_LIBRARY")
-            install(FILES $<TARGET_PDB_FILE:${TARGET}> DESTINATION bin OPTIONAL)
+            install(FILES $<TARGET_PDB_FILE:${TARGET}> DESTINATION ${CMAKE_INSTALL_BINDIR} OPTIONAL)
         endif()
         endif()
     endforeach(TARGET)
     endforeach(TARGET)
 endif()
 endif()
@@ -83,11 +86,11 @@ include(CMakePackageConfigHelpers)
 
 
 configure_package_config_file(config.cmake.in
 configure_package_config_file(config.cmake.in
     ${CMAKE_CURRENT_BINARY_DIR}/meshoptimizerConfig.cmake
     ${CMAKE_CURRENT_BINARY_DIR}/meshoptimizerConfig.cmake
-    INSTALL_DESTINATION lib/cmake/meshoptimizer NO_SET_AND_CHECK_MACRO)
+    INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/meshoptimizer NO_SET_AND_CHECK_MACRO)
 
 
 write_basic_package_version_file(${CMAKE_CURRENT_BINARY_DIR}/meshoptimizerConfigVersion.cmake COMPATIBILITY ExactVersion)
 write_basic_package_version_file(${CMAKE_CURRENT_BINARY_DIR}/meshoptimizerConfigVersion.cmake COMPATIBILITY ExactVersion)
 
 
 install(FILES
 install(FILES
     ${CMAKE_CURRENT_BINARY_DIR}/meshoptimizerConfig.cmake
     ${CMAKE_CURRENT_BINARY_DIR}/meshoptimizerConfig.cmake
     ${CMAKE_CURRENT_BINARY_DIR}/meshoptimizerConfigVersion.cmake
     ${CMAKE_CURRENT_BINARY_DIR}/meshoptimizerConfigVersion.cmake
-    DESTINATION lib/cmake/meshoptimizer)
+    DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/meshoptimizer)

+ 2 - 1
3rdparty/meshoptimizer/README.md

@@ -290,10 +290,11 @@ gltfpack -i scene.gltf -o scene.glb
 
 
 gltfpack substantially changes the glTF data by optimizing the meshes for vertex fetch and transform cache, quantizing the geometry to reduce the memory consumption and size, merging meshes to reduce the draw call count, quantizing and resampling animations to reduce animation size and simplify playback, and pruning the node tree by removing or collapsing redundant nodes. It will also simplify the meshes when requested to do so.
 gltfpack substantially changes the glTF data by optimizing the meshes for vertex fetch and transform cache, quantizing the geometry to reduce the memory consumption and size, merging meshes to reduce the draw call count, quantizing and resampling animations to reduce animation size and simplify playback, and pruning the node tree by removing or collapsing redundant nodes. It will also simplify the meshes when requested to do so.
 
 
-gltfpack can produce two types of output files:
+gltfpack can produce three types of output files:
 
 
 - By default gltfpack outputs regular `.glb`/`.gltf` files that have been optimized for GPU consumption using various cache optimizers and quantization. These files can be loaded by standard GLTF loaders present in frameworks such as [three.js](https://threejs.org/) (r107+) and [Babylon.js](https://www.babylonjs.com/) (4.1+).
 - By default gltfpack outputs regular `.glb`/`.gltf` files that have been optimized for GPU consumption using various cache optimizers and quantization. These files can be loaded by standard GLTF loaders present in frameworks such as [three.js](https://threejs.org/) (r107+) and [Babylon.js](https://www.babylonjs.com/) (4.1+).
 - When using `-c` option, gltfpack outputs compressed `.glb`/`.gltf` files that use meshoptimizer codecs to reduce the download size further. Loading these files requires extending GLTF loaders with custom decompression support; `demo/GLTFLoader.js` contains a custom version of three.js loader that can be used to load them.
 - When using `-c` option, gltfpack outputs compressed `.glb`/`.gltf` files that use meshoptimizer codecs to reduce the download size further. Loading these files requires extending GLTF loaders with custom decompression support; `demo/GLTFLoader.js` contains a custom version of three.js loader that can be used to load them.
+- When using `-cf` option, gltfpack outputs compressed files and an extra `.fallback.bin` file with uncompressed data. These files can be loaded by standard glTF loaders; loaders with decompression support don't need to load the fallback.
 
 
 > Note: files produced by gltfpack use `MESHOPT_quantized_geometry` and `MESHOPT_compression` pseudo-extensions; both of these have *not* been standardized yet but eventually will be. glTF validator doesn't recognize these extensions and produces a large number of validation errors because of this.
 > Note: files produced by gltfpack use `MESHOPT_quantized_geometry` and `MESHOPT_compression` pseudo-extensions; both of these have *not* been standardized yet but eventually will be. glTF validator doesn't recognize these extensions and produces a large number of validation errors because of this.
 
 

+ 119 - 169
3rdparty/meshoptimizer/demo/GLTFLoader.js

@@ -10,29 +10,29 @@ THREE.GLTFLoader = ( function () {
 
 
 	function GLTFLoader( manager ) {
 	function GLTFLoader( manager ) {
 
 
-		this.manager = ( manager !== undefined ) ? manager : THREE.DefaultLoadingManager;
+		THREE.Loader.call( this, manager );
+
 		this.dracoLoader = null;
 		this.dracoLoader = null;
+		this.ddsLoader = null;
 		this.meshoptDecoder = null;
 		this.meshoptDecoder = null;
 
 
 	}
 	}
 
 
-	GLTFLoader.prototype = {
+	GLTFLoader.prototype = Object.assign( Object.create( THREE.Loader.prototype ), {
 
 
 		constructor: GLTFLoader,
 		constructor: GLTFLoader,
 
 
-		crossOrigin: 'anonymous',
-
 		load: function ( url, onLoad, onProgress, onError ) {
 		load: function ( url, onLoad, onProgress, onError ) {
 
 
 			var scope = this;
 			var scope = this;
 
 
 			var resourcePath;
 			var resourcePath;
 
 
-			if ( this.resourcePath !== undefined ) {
+			if ( this.resourcePath !== '' ) {
 
 
 				resourcePath = this.resourcePath;
 				resourcePath = this.resourcePath;
 
 
-			} else if ( this.path !== undefined ) {
+			} else if ( this.path !== '' ) {
 
 
 				resourcePath = this.path;
 				resourcePath = this.path;
 
 
@@ -69,6 +69,12 @@ THREE.GLTFLoader = ( function () {
 			loader.setPath( this.path );
 			loader.setPath( this.path );
 			loader.setResponseType( 'arraybuffer' );
 			loader.setResponseType( 'arraybuffer' );
 
 
+			if ( scope.crossOrigin === 'use-credentials' ) {
+
+				loader.setWithCredentials( true );
+
+			}
+
 			loader.load( url, function ( data ) {
 			loader.load( url, function ( data ) {
 
 
 				try {
 				try {
@@ -91,30 +97,16 @@ THREE.GLTFLoader = ( function () {
 
 
 		},
 		},
 
 
-		setCrossOrigin: function ( value ) {
-
-			this.crossOrigin = value;
-			return this;
-
-		},
-
-		setPath: function ( value ) {
-
-			this.path = value;
-			return this;
-
-		},
-
-		setResourcePath: function ( value ) {
+		setDRACOLoader: function ( dracoLoader ) {
 
 
-			this.resourcePath = value;
+			this.dracoLoader = dracoLoader;
 			return this;
 			return this;
 
 
 		},
 		},
 
 
-		setDRACOLoader: function ( dracoLoader ) {
+		setDDSLoader: function ( ddsLoader ) {
 
 
-			this.dracoLoader = dracoLoader;
+			this.ddsLoader = ddsLoader;
 			return this;
 			return this;
 
 
 		},
 		},
@@ -185,11 +177,11 @@ THREE.GLTFLoader = ( function () {
 							break;
 							break;
 
 
 						case EXTENSIONS.KHR_MATERIALS_UNLIT:
 						case EXTENSIONS.KHR_MATERIALS_UNLIT:
-							extensions[ extensionName ] = new GLTFMaterialsUnlitExtension( json );
+							extensions[ extensionName ] = new GLTFMaterialsUnlitExtension();
 							break;
 							break;
 
 
 						case EXTENSIONS.KHR_MATERIALS_PBR_SPECULAR_GLOSSINESS:
 						case EXTENSIONS.KHR_MATERIALS_PBR_SPECULAR_GLOSSINESS:
-							extensions[ extensionName ] = new GLTFMaterialsPbrSpecularGlossinessExtension( json );
+							extensions[ extensionName ] = new GLTFMaterialsPbrSpecularGlossinessExtension();
 							break;
 							break;
 
 
 						case EXTENSIONS.KHR_DRACO_MESH_COMPRESSION:
 						case EXTENSIONS.KHR_DRACO_MESH_COMPRESSION:
@@ -197,15 +189,15 @@ THREE.GLTFLoader = ( function () {
 							break;
 							break;
 
 
 						case EXTENSIONS.MSFT_TEXTURE_DDS:
 						case EXTENSIONS.MSFT_TEXTURE_DDS:
-							extensions[ EXTENSIONS.MSFT_TEXTURE_DDS ] = new GLTFTextureDDSExtension();
+							extensions[ EXTENSIONS.MSFT_TEXTURE_DDS ] = new GLTFTextureDDSExtension( this.ddsLoader );
 							break;
 							break;
 
 
 						case EXTENSIONS.KHR_TEXTURE_TRANSFORM:
 						case EXTENSIONS.KHR_TEXTURE_TRANSFORM:
-							extensions[ EXTENSIONS.KHR_TEXTURE_TRANSFORM ] = new GLTFTextureTransformExtension( json );
+							extensions[ EXTENSIONS.KHR_TEXTURE_TRANSFORM ] = new GLTFTextureTransformExtension();
 							break;
 							break;
 
 
 						case EXTENSIONS.MESHOPT_COMPRESSION:
 						case EXTENSIONS.MESHOPT_COMPRESSION:
-							extensions[ extensionName ] = new GLTFMeshoptCompressionExtension( json, this.meshoptDecoder );
+							extensions[ extensionName ] = new GLTFMeshoptCompressionExtension( this.meshoptDecoder );
 							break;
 							break;
 
 
 						default:
 						default:
@@ -234,7 +226,7 @@ THREE.GLTFLoader = ( function () {
 
 
 		}
 		}
 
 
-	};
+	} );
 
 
 	/* GLTFREGISTRY */
 	/* GLTFREGISTRY */
 
 
@@ -290,27 +282,26 @@ THREE.GLTFLoader = ( function () {
 	/**
 	/**
 	 * DDS Texture Extension
 	 * DDS Texture Extension
 	 *
 	 *
-	 * Specification:
-	 * https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Vendor/MSFT_texture_dds
+	 * Specification: https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Vendor/MSFT_texture_dds
 	 *
 	 *
 	 */
 	 */
-	function GLTFTextureDDSExtension() {
+	function GLTFTextureDDSExtension( ddsLoader ) {
 
 
-		if ( ! THREE.DDSLoader ) {
+		if ( ! ddsLoader ) {
 
 
 			throw new Error( 'THREE.GLTFLoader: Attempting to load .dds texture without importing THREE.DDSLoader' );
 			throw new Error( 'THREE.GLTFLoader: Attempting to load .dds texture without importing THREE.DDSLoader' );
 
 
 		}
 		}
 
 
 		this.name = EXTENSIONS.MSFT_TEXTURE_DDS;
 		this.name = EXTENSIONS.MSFT_TEXTURE_DDS;
-		this.ddsLoader = new THREE.DDSLoader();
+		this.ddsLoader = ddsLoader;
 
 
 	}
 	}
 
 
 	/**
 	/**
-	 * Lights Extension
+	 * Punctual Lights Extension
 	 *
 	 *
-	 * Specification: PENDING
+	 * Specification: https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Khronos/KHR_lights_punctual
 	 */
 	 */
 	function GLTFLightsExtension( json ) {
 	function GLTFLightsExtension( json ) {
 
 
@@ -377,9 +368,9 @@ THREE.GLTFLoader = ( function () {
 	};
 	};
 
 
 	/**
 	/**
-	 * Unlit Materials Extension (pending)
+	 * Unlit Materials Extension
 	 *
 	 *
-	 * PR: https://github.com/KhronosGroup/glTF/pull/1163
+	 * Specification: https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Khronos/KHR_materials_unlit
 	 */
 	 */
 	function GLTFMaterialsUnlitExtension() {
 	function GLTFMaterialsUnlitExtension() {
 
 
@@ -426,8 +417,6 @@ THREE.GLTFLoader = ( function () {
 	};
 	};
 
 
 	/* BINARY EXTENSION */
 	/* BINARY EXTENSION */
-
-	var BINARY_EXTENSION_BUFFER_NAME = 'binary_glTF';
 	var BINARY_EXTENSION_HEADER_MAGIC = 'glTF';
 	var BINARY_EXTENSION_HEADER_MAGIC = 'glTF';
 	var BINARY_EXTENSION_HEADER_LENGTH = 12;
 	var BINARY_EXTENSION_HEADER_LENGTH = 12;
 	var BINARY_EXTENSION_CHUNK_TYPES = { JSON: 0x4E4F534A, BIN: 0x004E4942 };
 	var BINARY_EXTENSION_CHUNK_TYPES = { JSON: 0x4E4F534A, BIN: 0x004E4942 };
@@ -496,7 +485,7 @@ THREE.GLTFLoader = ( function () {
 	/**
 	/**
 	 * DRACO Mesh Compression Extension
 	 * DRACO Mesh Compression Extension
 	 *
 	 *
-	 * Specification: https://github.com/KhronosGroup/glTF/pull/874
+	 * Specification: https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Khronos/KHR_draco_mesh_compression
 	 */
 	 */
 	function GLTFDracoMeshCompressionExtension( json, dracoLoader ) {
 	function GLTFDracoMeshCompressionExtension( json, dracoLoader ) {
 
 
@@ -574,7 +563,7 @@ THREE.GLTFLoader = ( function () {
 	/**
 	/**
 	 * Texture Transform Extension
 	 * Texture Transform Extension
 	 *
 	 *
-	 * Specification:
+	 * Specification: https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Khronos/KHR_texture_transform
 	 */
 	 */
 	function GLTFTextureTransformExtension() {
 	function GLTFTextureTransformExtension() {
 
 
@@ -864,7 +853,7 @@ THREE.GLTFLoader = ( function () {
 			},
 			},
 
 
 			// Here's based on refreshUniformsCommon() and refreshUniformsStandard() in WebGLRenderer.
 			// Here's based on refreshUniformsCommon() and refreshUniformsStandard() in WebGLRenderer.
-			refreshUniforms: function ( renderer, scene, camera, geometry, material, group ) {
+			refreshUniforms: function ( renderer, scene, camera, geometry, material ) {
 
 
 				if ( material.isGLTFSpecularGlossinessMaterial !== true ) {
 				if ( material.isGLTFSpecularGlossinessMaterial !== true ) {
 
 
@@ -1008,7 +997,7 @@ THREE.GLTFLoader = ( function () {
 	/**
 	/**
 	 * meshoptimizer Compression Extension
 	 * meshoptimizer Compression Extension
 	 */
 	 */
-	function GLTFMeshoptCompressionExtension( json, meshoptDecoder ) {
+	function GLTFMeshoptCompressionExtension( meshoptDecoder ) {
 
 
 		if ( ! meshoptDecoder ) {
 		if ( ! meshoptDecoder ) {
 
 
@@ -1017,21 +1006,18 @@ THREE.GLTFLoader = ( function () {
 		}
 		}
 
 
 		this.name = EXTENSIONS.MESHOPT_COMPRESSION;
 		this.name = EXTENSIONS.MESHOPT_COMPRESSION;
-		this.json = json;
 		this.meshoptDecoder = meshoptDecoder;
 		this.meshoptDecoder = meshoptDecoder;
 
 
 	}
 	}
 
 
-	GLTFMeshoptCompressionExtension.prototype.decodeBufferView = function ( bufferViewDef, buffer ) {
+	GLTFMeshoptCompressionExtension.prototype.decodeBufferView = function ( extensionDef, buffer ) {
 
 
 		var decoder = this.meshoptDecoder;
 		var decoder = this.meshoptDecoder;
 
 
 		return decoder.ready.then( function () {
 		return decoder.ready.then( function () {
 
 
-			var extensionDef = bufferViewDef.extensions[ EXTENSIONS.MESHOPT_COMPRESSION ];
-
-			var byteOffset = bufferViewDef.byteOffset || 0;
-			var byteLength = bufferViewDef.byteLength || 0;
+			var byteOffset = extensionDef.byteOffset || 0;
+			var byteLength = extensionDef.byteLength || 0;
 
 
 			var count = extensionDef.count;
 			var count = extensionDef.count;
 			var stride = extensionDef.byteStride;
 			var stride = extensionDef.byteStride;
@@ -1058,7 +1044,7 @@ THREE.GLTFLoader = ( function () {
 
 
 		} );
 		} );
 
 
-	}
+	};
 
 
 	/*********************************/
 	/*********************************/
 	/********** INTERPOLATION ********/
 	/********** INTERPOLATION ********/
@@ -1167,17 +1153,6 @@ THREE.GLTFLoader = ( function () {
 		UNSIGNED_SHORT: 5123
 		UNSIGNED_SHORT: 5123
 	};
 	};
 
 
-	var WEBGL_TYPE = {
-		5126: Number,
-		//35674: THREE.Matrix2,
-		35675: THREE.Matrix3,
-		35676: THREE.Matrix4,
-		35664: THREE.Vector2,
-		35665: THREE.Vector3,
-		35666: THREE.Vector4,
-		35678: THREE.Texture
-	};
-
 	var WEBGL_COMPONENT_TYPES = {
 	var WEBGL_COMPONENT_TYPES = {
 		5120: Int8Array,
 		5120: Int8Array,
 		5121: Uint8Array,
 		5121: Uint8Array,
@@ -1190,10 +1165,10 @@ THREE.GLTFLoader = ( function () {
 	var WEBGL_FILTERS = {
 	var WEBGL_FILTERS = {
 		9728: THREE.NearestFilter,
 		9728: THREE.NearestFilter,
 		9729: THREE.LinearFilter,
 		9729: THREE.LinearFilter,
-		9984: THREE.NearestMipMapNearestFilter,
-		9985: THREE.LinearMipMapNearestFilter,
-		9986: THREE.NearestMipMapLinearFilter,
-		9987: THREE.LinearMipMapLinearFilter
+		9984: THREE.NearestMipmapNearestFilter,
+		9985: THREE.LinearMipmapNearestFilter,
+		9986: THREE.NearestMipmapLinearFilter,
+		9987: THREE.LinearMipmapLinearFilter
 	};
 	};
 
 
 	var WEBGL_WRAPPINGS = {
 	var WEBGL_WRAPPINGS = {
@@ -1202,48 +1177,6 @@ THREE.GLTFLoader = ( function () {
 		10497: THREE.RepeatWrapping
 		10497: THREE.RepeatWrapping
 	};
 	};
 
 
-	var WEBGL_SIDES = {
-		1028: THREE.BackSide, // Culling front
-		1029: THREE.FrontSide // Culling back
-		//1032: THREE.NoSide   // Culling front and back, what to do?
-	};
-
-	var WEBGL_DEPTH_FUNCS = {
-		512: THREE.NeverDepth,
-		513: THREE.LessDepth,
-		514: THREE.EqualDepth,
-		515: THREE.LessEqualDepth,
-		516: THREE.GreaterEqualDepth,
-		517: THREE.NotEqualDepth,
-		518: THREE.GreaterEqualDepth,
-		519: THREE.AlwaysDepth
-	};
-
-	var WEBGL_BLEND_EQUATIONS = {
-		32774: THREE.AddEquation,
-		32778: THREE.SubtractEquation,
-		32779: THREE.ReverseSubtractEquation
-	};
-
-	var WEBGL_BLEND_FUNCS = {
-		0: THREE.ZeroFactor,
-		1: THREE.OneFactor,
-		768: THREE.SrcColorFactor,
-		769: THREE.OneMinusSrcColorFactor,
-		770: THREE.SrcAlphaFactor,
-		771: THREE.OneMinusSrcAlphaFactor,
-		772: THREE.DstAlphaFactor,
-		773: THREE.OneMinusDstAlphaFactor,
-		774: THREE.DstColorFactor,
-		775: THREE.OneMinusDstColorFactor,
-		776: THREE.SrcAlphaSaturateFactor
-		// The followings are not supported by Three.js yet
-		//32769: CONSTANT_COLOR,
-		//32770: ONE_MINUS_CONSTANT_COLOR,
-		//32771: CONSTANT_ALPHA,
-		//32772: ONE_MINUS_CONSTANT_COLOR
-	};
-
 	var WEBGL_TYPE_SIZES = {
 	var WEBGL_TYPE_SIZES = {
 		'SCALAR': 1,
 		'SCALAR': 1,
 		'VEC2': 2,
 		'VEC2': 2,
@@ -1279,15 +1212,6 @@ THREE.GLTFLoader = ( function () {
 		STEP: THREE.InterpolateDiscrete
 		STEP: THREE.InterpolateDiscrete
 	};
 	};
 
 
-	var STATES_ENABLES = {
-		2884: 'CULL_FACE',
-		2929: 'DEPTH_TEST',
-		3042: 'BLEND',
-		3089: 'SCISSOR_TEST',
-		32823: 'POLYGON_OFFSET_FILL',
-		32926: 'SAMPLE_ALPHA_TO_COVERAGE'
-	};
-
 	var ALPHA_MODES = {
 	var ALPHA_MODES = {
 		OPAQUE: 'OPAQUE',
 		OPAQUE: 'OPAQUE',
 		MASK: 'MASK',
 		MASK: 'MASK',
@@ -1306,6 +1230,13 @@ THREE.GLTFLoader = ( function () {
 		// Invalid URL
 		// Invalid URL
 		if ( typeof url !== 'string' || url === '' ) return '';
 		if ( typeof url !== 'string' || url === '' ) return '';
 
 
+		// Host Relative URL
+		if ( /^https?:\/\//i.test( path ) && /^\//.test( url ) ) {
+
+			path = path.replace( /(^https?:\/\/[^\/]+).*/i, '$1' );
+
+		}
+
 		// Absolute URL http://,https://,//
 		// Absolute URL http://,https://,//
 		if ( /^(https?:)?\/\//i.test( url ) ) return url;
 		if ( /^(https?:)?\/\//i.test( url ) ) return url;
 
 
@@ -1580,19 +1511,6 @@ THREE.GLTFLoader = ( function () {
 
 
 		}
 		}
 
 
-	}
-	function isObjectEqual( a, b ) {
-
-		if ( Object.keys( a ).length !== Object.keys( b ).length ) return false;
-
-		for ( var key in a ) {
-
-			if ( a[ key ] !== b[ key ] ) return false;
-
-		}
-
-		return true;
-
 	}
 	}
 
 
 	function createPrimitiveKey( primitiveDef ) {
 	function createPrimitiveKey( primitiveDef ) {
@@ -1677,6 +1595,12 @@ THREE.GLTFLoader = ( function () {
 		this.fileLoader = new THREE.FileLoader( this.options.manager );
 		this.fileLoader = new THREE.FileLoader( this.options.manager );
 		this.fileLoader.setResponseType( 'arraybuffer' );
 		this.fileLoader.setResponseType( 'arraybuffer' );
 
 
+		if ( this.options.crossOrigin === 'use-credentials' ) {
+
+			this.fileLoader.setWithCredentials( true );
+
+		}
+
 	}
 	}
 
 
 	GLTFParser.prototype.parse = function ( onLoad, onError ) {
 	GLTFParser.prototype.parse = function ( onLoad, onError ) {
@@ -1711,6 +1635,8 @@ THREE.GLTFLoader = ( function () {
 
 
 			addUnknownExtensionsToUserData( extensions, result, json );
 			addUnknownExtensionsToUserData( extensions, result, json );
 
 
+			assignExtrasToUserData( result, json );
+
 			onLoad( result );
 			onLoad( result );
 
 
 		} ).catch( onError );
 		} ).catch( onError );
@@ -1933,26 +1859,25 @@ THREE.GLTFLoader = ( function () {
 		if ( bufferViewDef.extensions && bufferViewDef.extensions[ EXTENSIONS.MESHOPT_COMPRESSION ] ) {
 		if ( bufferViewDef.extensions && bufferViewDef.extensions[ EXTENSIONS.MESHOPT_COMPRESSION ] ) {
 
 
 			var extension = this.extensions[ EXTENSIONS.MESHOPT_COMPRESSION ];
 			var extension = this.extensions[ EXTENSIONS.MESHOPT_COMPRESSION ];
+			var extensionDef = bufferViewDef.extensions[ EXTENSIONS.MESHOPT_COMPRESSION ];
 
 
-			return this.getDependency( 'buffer', bufferViewDef.buffer ).then( function ( buffer ) {
+			return this.getDependency( 'buffer', extensionDef.buffer ).then( function ( buffer ) {
 
 
-				return extension.decodeBufferView( bufferViewDef, buffer );
+				return extension.decodeBufferView( extensionDef, buffer );
 
 
 			} );
 			} );
 
 
-		} else {
-
-			return this.getDependency( 'buffer', bufferViewDef.buffer ).then( function ( buffer ) {
+		}
 
 
-				var byteLength = bufferViewDef.byteLength || 0;
-				var byteOffset = bufferViewDef.byteOffset || 0;
-				return buffer.slice( byteOffset, byteOffset + byteLength );
+		return this.getDependency( 'buffer', bufferViewDef.buffer ).then( function ( buffer ) {
 
 
-			} );
+			var byteLength = bufferViewDef.byteLength || 0;
+			var byteOffset = bufferViewDef.byteOffset || 0;
+			return buffer.slice( byteOffset, byteOffset + byteLength );
 
 
-		}
+		} );
 
 
-	}
+	};
 
 
 	/**
 	/**
 	 * Specification: https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/README.md#accessors
 	 * Specification: https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/README.md#accessors
@@ -2029,7 +1954,7 @@ THREE.GLTFLoader = ( function () {
 
 
 				}
 				}
 
 
-				bufferAttribute = new THREE.InterleavedBufferAttribute( ib, itemSize, (byteOffset % byteStride) / elementBytes, normalized );
+				bufferAttribute = new THREE.InterleavedBufferAttribute( ib, itemSize, ( byteOffset % byteStride ) / elementBytes, normalized );
 
 
 			} else {
 			} else {
 
 
@@ -2062,7 +1987,7 @@ THREE.GLTFLoader = ( function () {
 				if ( bufferView !== null ) {
 				if ( bufferView !== null ) {
 
 
 					// Avoid modifying the original ArrayBuffer, if the bufferView wasn't initialized with zeroes.
 					// Avoid modifying the original ArrayBuffer, if the bufferView wasn't initialized with zeroes.
-					bufferAttribute.setArray( bufferAttribute.array.slice() );
+					bufferAttribute = new THREE.BufferAttribute( bufferAttribute.array.slice(), bufferAttribute.itemSize, bufferAttribute.normalized );
 
 
 				}
 				}
 
 
@@ -2138,7 +2063,7 @@ THREE.GLTFLoader = ( function () {
 
 
 			// Load Texture resource.
 			// Load Texture resource.
 
 
-			var loader = THREE.Loader.Handlers.get( sourceURI );
+			var loader = options.manager.getHandler( sourceURI );
 
 
 			if ( ! loader ) {
 			if ( ! loader ) {
 
 
@@ -2179,7 +2104,7 @@ THREE.GLTFLoader = ( function () {
 			var sampler = samplers[ textureDef.sampler ] || {};
 			var sampler = samplers[ textureDef.sampler ] || {};
 
 
 			texture.magFilter = WEBGL_FILTERS[ sampler.magFilter ] || THREE.LinearFilter;
 			texture.magFilter = WEBGL_FILTERS[ sampler.magFilter ] || THREE.LinearFilter;
-			texture.minFilter = WEBGL_FILTERS[ sampler.minFilter ] || THREE.LinearMipMapLinearFilter;
+			texture.minFilter = WEBGL_FILTERS[ sampler.minFilter ] || THREE.LinearMipmapLinearFilter;
 			texture.wrapS = WEBGL_WRAPPINGS[ sampler.wrapS ] || THREE.RepeatWrapping;
 			texture.wrapS = WEBGL_WRAPPINGS[ sampler.wrapS ] || THREE.RepeatWrapping;
 			texture.wrapT = WEBGL_WRAPPINGS[ sampler.wrapT ] || THREE.RepeatWrapping;
 			texture.wrapT = WEBGL_WRAPPINGS[ sampler.wrapT ] || THREE.RepeatWrapping;
 
 
@@ -2269,7 +2194,6 @@ THREE.GLTFLoader = ( function () {
 				THREE.Material.prototype.copy.call( pointsMaterial, material );
 				THREE.Material.prototype.copy.call( pointsMaterial, material );
 				pointsMaterial.color.copy( material.color );
 				pointsMaterial.color.copy( material.color );
 				pointsMaterial.map = material.map;
 				pointsMaterial.map = material.map;
-				pointsMaterial.lights = false; // PointsMaterial doesn't support lights yet
 				pointsMaterial.sizeAttenuation = false; // glTF spec says points should be 1px
 				pointsMaterial.sizeAttenuation = false; // glTF spec says points should be 1px
 
 
 				this.cache.add( cacheKey, pointsMaterial );
 				this.cache.add( cacheKey, pointsMaterial );
@@ -2289,7 +2213,6 @@ THREE.GLTFLoader = ( function () {
 				lineMaterial = new THREE.LineBasicMaterial();
 				lineMaterial = new THREE.LineBasicMaterial();
 				THREE.Material.prototype.copy.call( lineMaterial, material );
 				THREE.Material.prototype.copy.call( lineMaterial, material );
 				lineMaterial.color.copy( material.color );
 				lineMaterial.color.copy( material.color );
-				lineMaterial.lights = false; // LineBasicMaterial doesn't support lights yet
 
 
 				this.cache.add( cacheKey, lineMaterial );
 				this.cache.add( cacheKey, lineMaterial );
 
 
@@ -2654,7 +2577,6 @@ THREE.GLTFLoader = ( function () {
 
 
 		var parser = this;
 		var parser = this;
 		var json = this.json;
 		var json = this.json;
-		var extensions = this.extensions;
 
 
 		var meshDef = json.meshes[ meshIndex ];
 		var meshDef = json.meshes[ meshIndex ];
 		var primitives = meshDef.primitives;
 		var primitives = meshDef.primitives;
@@ -2698,7 +2620,7 @@ THREE.GLTFLoader = ( function () {
 							? new THREE.SkinnedMesh( geometry, material )
 							? new THREE.SkinnedMesh( geometry, material )
 							: new THREE.Mesh( geometry, material );
 							: new THREE.Mesh( geometry, material );
 
 
-						if ( mesh.isSkinnedMesh === true && !mesh.geometry.attributes.skinWeight.normalized ) {
+						if ( mesh.isSkinnedMesh === true && ! mesh.geometry.attributes.skinWeight.normalized ) {
 
 
 							// we normalize floating point skin weight array to fix malformed assets (see #15319)
 							// we normalize floating point skin weight array to fix malformed assets (see #15319)
 							// it's important to skip this for non-float32 data since normalizeSkinWeights assumes non-normalized inputs
 							// it's important to skip this for non-float32 data since normalizeSkinWeights assumes non-normalized inputs
@@ -2986,7 +2908,7 @@ THREE.GLTFLoader = ( function () {
 
 
 					for ( var j = 0, jl = outputArray.length; j < jl; j ++ ) {
 					for ( var j = 0, jl = outputArray.length; j < jl; j ++ ) {
 
 
-						scaled[j] = outputArray[j] * scale;
+						scaled[ j ] = outputArray[ j ] * scale;
 
 
 					}
 					}
 
 
@@ -3053,14 +2975,11 @@ THREE.GLTFLoader = ( function () {
 
 
 		return ( function () {
 		return ( function () {
 
 
-			// .isBone isn't in glTF spec. See .markDefs
-			if ( nodeDef.isBone === true ) {
-
-				return Promise.resolve( new THREE.Bone() );
+			var pending = [];
 
 
-			} else if ( nodeDef.mesh !== undefined ) {
+			if ( nodeDef.mesh !== undefined ) {
 
 
-				return parser.getDependency( 'mesh', nodeDef.mesh ).then( function ( mesh ) {
+				pending.push( parser.getDependency( 'mesh', nodeDef.mesh ).then( function ( mesh ) {
 
 
 					var node;
 					var node;
 
 
@@ -3106,25 +3025,58 @@ THREE.GLTFLoader = ( function () {
 
 
 					return node;
 					return node;
 
 
-				} );
+				} ) );
 
 
-			} else if ( nodeDef.camera !== undefined ) {
+			}
 
 
-				return parser.getDependency( 'camera', nodeDef.camera );
+			if ( nodeDef.camera !== undefined ) {
 
 
-			} else if ( nodeDef.extensions
+				pending.push( parser.getDependency( 'camera', nodeDef.camera ) );
+
+			}
+
+			if ( nodeDef.extensions
 				&& nodeDef.extensions[ EXTENSIONS.KHR_LIGHTS_PUNCTUAL ]
 				&& nodeDef.extensions[ EXTENSIONS.KHR_LIGHTS_PUNCTUAL ]
 				&& nodeDef.extensions[ EXTENSIONS.KHR_LIGHTS_PUNCTUAL ].light !== undefined ) {
 				&& nodeDef.extensions[ EXTENSIONS.KHR_LIGHTS_PUNCTUAL ].light !== undefined ) {
 
 
-				return parser.getDependency( 'light', nodeDef.extensions[ EXTENSIONS.KHR_LIGHTS_PUNCTUAL ].light );
+				pending.push( parser.getDependency( 'light', nodeDef.extensions[ EXTENSIONS.KHR_LIGHTS_PUNCTUAL ].light ) );
+
+			}
+
+			return Promise.all( pending );
+
+		}() ).then( function ( objects ) {
+
+			var node;
+
+			// .isBone isn't in glTF spec. See .markDefs
+			if ( nodeDef.isBone === true ) {
+
+				node = new THREE.Bone();
+
+			} else if ( objects.length > 1 ) {
+
+				node = new THREE.Group();
+
+			} else if ( objects.length === 1 ) {
+
+				node = objects[ 0 ];
 
 
 			} else {
 			} else {
 
 
-				return Promise.resolve( new THREE.Object3D() );
+				node = new THREE.Object3D();
 
 
 			}
 			}
 
 
-		}() ).then( function ( node ) {
+			if ( node !== objects[ 0 ] ) {
+
+				for ( var i = 0, il = objects.length; i < il; i ++ ) {
+
+					node.add( objects[ i ] );
+
+				}
+
+			}
 
 
 			if ( nodeDef.name !== undefined ) {
 			if ( nodeDef.name !== undefined ) {
 
 
@@ -3208,11 +3160,9 @@ THREE.GLTFLoader = ( function () {
 
 
 				} ).then( function ( jointNodes ) {
 				} ).then( function ( jointNodes ) {
 
 
-					var meshes = node.isGroup === true ? node.children : [ node ];
+					node.traverse( function ( mesh ) {
 
 
-					for ( var i = 0, il = meshes.length; i < il; i ++ ) {
-
-						var mesh = meshes[ i ];
+						if ( ! mesh.isMesh ) return;
 
 
 						var bones = [];
 						var bones = [];
 						var boneInverses = [];
 						var boneInverses = [];
@@ -3245,7 +3195,7 @@ THREE.GLTFLoader = ( function () {
 
 
 						mesh.bind( new THREE.Skeleton( bones, boneInverses ), mesh.matrixWorld );
 						mesh.bind( new THREE.Skeleton( bones, boneInverses ), mesh.matrixWorld );
 
 
-					}
+					} );
 
 
 					return node;
 					return node;
 
 

+ 50 - 50
3rdparty/meshoptimizer/demo/babylon.MESHOPT_compression.js

@@ -1,50 +1,50 @@
-/* Babylon.js extension for MESHOPT_compression; requires Babylon.js 4.1 */
-var NAME = "MESHOPT_compression";
-var MESHOPT_compression = /** @class */ (function () {
-    /** @hidden */
-    function MESHOPT_compression(loader, decoder) {
-        /** The name of this extension. */
-        this.name = NAME;
-        /** Defines whether this extension is enabled. */
-        this.enabled = true;
-        this._loader = loader;
-        this._decoder = decoder;
-    }
-    /** @hidden */
-    MESHOPT_compression.prototype.dispose = function () {
-        delete this._loader;
-    };
-    /** @hidden */
-    MESHOPT_compression.prototype.loadBufferViewAsync = function (context, bufferView) {
-        if (bufferView.extensions && bufferView.extensions[NAME]) {
-            if (bufferView._decoded) {
-                return bufferView._decoded;
-            }
-            var view = this._loader.loadBufferViewAsync(context, bufferView);
-            var decoder = this._decoder;
-            bufferView._decoded = Promise.all([view, decoder.ready]).then(function (res) {
-                var source = res[0];
-                var extensionDef = bufferView.extensions[NAME];
-                var count = extensionDef.count;
-                var stride = extensionDef.byteStride;
-                var result = new Uint8Array(new ArrayBuffer(count * stride));
-                switch (extensionDef.mode) {
-                    case 0:
-                        decoder.decodeVertexBuffer(result, count, stride, source);
-                        break;
-                    case 1:
-                        decoder.decodeIndexBuffer(result, count, stride, source);
-                        break;
-                    default:
-                        throw new Error("GLTFLoader: Unrecognized meshopt compression mode.");
-                }
-                return Promise.resolve(result);
-            });
-            return bufferView._decoded;
-        } else {
-            return null;
-        }
-    };
-    return MESHOPT_compression;
-}());
-/* BABYLON.GLTF2.GLTFLoader.RegisterExtension("MESHOPT_compression", (loader) => new MESHOPT_compression(loader, MeshoptDecoder)); */
+/* Babylon.js extension for MESHOPT_compression; requires Babylon.js 4.1 */
+var NAME = "MESHOPT_compression";
+var MESHOPT_compression = /** @class */ (function () {
+    /** @hidden */
+    function MESHOPT_compression(loader, decoder) {
+        /** The name of this extension. */
+        this.name = NAME;
+        /** Defines whether this extension is enabled. */
+        this.enabled = true;
+        this._loader = loader;
+        this._decoder = decoder;
+    }
+    /** @hidden */
+    MESHOPT_compression.prototype.dispose = function () {
+        delete this._loader;
+    };
+    /** @hidden */
+    MESHOPT_compression.prototype.loadBufferViewAsync = function (context, bufferView) {
+        if (bufferView.extensions && bufferView.extensions[NAME]) {
+            var extensionDef = bufferView.extensions[NAME];
+            if (extensionDef._decoded) {
+                return extensionDef._decoded;
+            }
+            var view = this._loader.loadBufferViewAsync(context, extensionDef);
+            var decoder = this._decoder;
+            extensionDef._decoded = Promise.all([view, decoder.ready]).then(function (res) {
+                var source = res[0];
+                var count = extensionDef.count;
+                var stride = extensionDef.byteStride;
+                var result = new Uint8Array(new ArrayBuffer(count * stride));
+                switch (extensionDef.mode) {
+                    case 0:
+                        decoder.decodeVertexBuffer(result, count, stride, source);
+                        break;
+                    case 1:
+                        decoder.decodeIndexBuffer(result, count, stride, source);
+                        break;
+                    default:
+                        throw new Error("GLTFLoader: Unrecognized meshopt compression mode.");
+                }
+                return Promise.resolve(result);
+            });
+            return extensionDef._decoded;
+        } else {
+            return null;
+        }
+    };
+    return MESHOPT_compression;
+}());
+/* BABYLON.GLTF2.GLTFLoader.RegisterExtension("MESHOPT_compression", (loader) => new MESHOPT_compression(loader, MeshoptDecoder)); */

+ 68 - 70
3rdparty/meshoptimizer/demo/demo.html

@@ -1,70 +1,68 @@
-<!DOCTYPE html>
-<html>
-    <head>
-        <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
-
-        <title>meshoptimizer - demo</title>
-
-        <script src="https://preview.babylonjs.com/babylon.js"></script>
-        <script src="https://preview.babylonjs.com/loaders/babylon.glTF2FileLoader.js"></script>
-
-        <script src="babylon.MESHOPT_compression.js"></script>
-        <script src="../js/meshopt_decoder.js"></script>
-
-        <style>
-            html, body {
-                overflow: hidden;
-                width: 100%;
-                height: 100%;
-                margin: 0;
-                padding: 0;
-            }
-
-            #renderCanvas {
-                width: 100%;
-                height: 100%;
-                touch-action: none;
-            }
-        </style>
-    </head>
-<body>
-    <canvas id="renderCanvas"></canvas>
-    <script>
-        var canvas = document.getElementById("renderCanvas");
-
-        BABYLON.GLTF2.GLTFLoader.RegisterExtension("MESHOPT_compression", (loader) => new MESHOPT_compression(loader, MeshoptDecoder)); 
-
-        var createScene = function () {
-            var scene = new BABYLON.Scene(engine);
-        
-            var light = new BABYLON.HemisphericLight();
-        
-            var camera = new BABYLON.ArcRotateCamera("Camera", 0, 0.8, 10, BABYLON.Vector3.Zero(), scene);
-            camera.attachControl(canvas, false);
-        
-            BABYLON.SceneLoader.Append("", "pirate.glb", scene, function (newMeshes) {
-                scene.activeCamera = null;
-                scene.createDefaultCameraOrLight(true);
-                scene.activeCamera.attachControl(canvas, false);
-                scene.activeCamera.alpha = Math.PI / 2;
-            });
-        
-            return scene;
-        }
-
-        var engine = new BABYLON.Engine(canvas, true, { preserveDrawingBuffer: true, stencil: true });
-        var scene = createScene();
-
-        engine.runRenderLoop(function () {
-            if (scene) {
-                scene.render();
-            }
-        });
-
-        // Resize
-        window.addEventListener("resize", function () {
-            engine.resize();
-        });
-    </script>
-</body>
-</html>
+<!DOCTYPE html>
+<html>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+
+        <title>meshoptimizer - demo</title>
+
+        <script src="https://preview.babylonjs.com/babylon.js"></script>
+        <script src="https://preview.babylonjs.com/loaders/babylon.glTF2FileLoader.js"></script>
+
+        <script src="babylon.MESHOPT_compression.js"></script>
+        <script src="../js/meshopt_decoder.js"></script>
+
+        <style>
+            html, body {
+                overflow: hidden;
+                width: 100%;
+                height: 100%;
+                margin: 0;
+                padding: 0;
+            }
+
+            #renderCanvas {
+                width: 100%;
+                height: 100%;
+                touch-action: none;
+            }
+        </style>
+    </head>
+<body>
+    <canvas id="renderCanvas"></canvas>
+    <script>
+        var canvas = document.getElementById("renderCanvas");
+
+        BABYLON.GLTF2.GLTFLoader.RegisterExtension("MESHOPT_compression", (loader) => new MESHOPT_compression(loader, MeshoptDecoder));
+
+        var createScene = function () {
+            var scene = new BABYLON.Scene(engine);
+
+            var camera = new BABYLON.ArcRotateCamera("Camera", 0, 0.8, 10, BABYLON.Vector3.Zero(), scene);
+            camera.attachControl(canvas, false);
+
+            BABYLON.SceneLoader.Append("", "pirate.glb", scene, function (newMeshes) {
+                scene.activeCamera = null;
+                scene.createDefaultCameraOrLight(true);
+                scene.activeCamera.attachControl(canvas, false);
+                scene.activeCamera.alpha = Math.PI / 2;
+            });
+
+            return scene;
+        }
+
+        var engine = new BABYLON.Engine(canvas, true, { preserveDrawingBuffer: true, stencil: true });
+        var scene = createScene();
+
+        engine.runRenderLoop(function () {
+            if (scene) {
+                scene.render();
+            }
+        });
+
+        // Resize
+        window.addEventListener("resize", function () {
+            engine.resize();
+        });
+    </script>
+</body>
+</html>

+ 3 - 3
3rdparty/meshoptimizer/demo/index.html

@@ -30,7 +30,7 @@
 		<a href="https://github.com/zeux/meshoptimizer" target="_blank" rel="noopener">meshoptimizer</a>
 		<a href="https://github.com/zeux/meshoptimizer" target="_blank" rel="noopener">meshoptimizer</a>
 		</div>
 		</div>
 
 
-		<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/105/three.min.js"></script>
+		<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/109/three.min.js"></script>
 
 
 		<script src="../js/meshopt_decoder.js"></script>
 		<script src="../js/meshopt_decoder.js"></script>
 		<script src="GLTFLoader.js"></script>
 		<script src="GLTFLoader.js"></script>
@@ -71,8 +71,8 @@
 					console.log(e);
 					console.log(e);
 				};
 				};
 
 
-				var loader = new THREE.GLTFLoader()
-				loader.setMeshoptDecoder(MeshoptDecoder)
+				var loader = new THREE.GLTFLoader();
+				loader.setMeshoptDecoder(MeshoptDecoder);
 				loader.load('pirate.glb', function (gltf) {
 				loader.load('pirate.glb', function (gltf) {
 					var bbox = new THREE.Box3().setFromObject(gltf.scene);
 					var bbox = new THREE.Box3().setFromObject(gltf.scene);
 					var scale = 2 / (bbox.max.y - bbox.min.y);
 					var scale = 2 / (bbox.max.y - bbox.min.y);

BIN
3rdparty/meshoptimizer/demo/pirate.glb


Diff do ficheiro suprimidas por serem muito extensas
+ 0 - 0
3rdparty/meshoptimizer/js/meshopt_decoder.js


+ 1 - 1
3rdparty/meshoptimizer/src/meshoptimizer.h

@@ -1,5 +1,5 @@
 /**
 /**
- * meshoptimizer - version 0.11
+ * meshoptimizer - version 0.12
  *
  *
  * Copyright (C) 2016-2019, by Arseny Kapoulkine ([email protected])
  * Copyright (C) 2016-2019, by Arseny Kapoulkine ([email protected])
  * Report bugs and download new versions at https://github.com/zeux/meshoptimizer
  * Report bugs and download new versions at https://github.com/zeux/meshoptimizer

+ 67 - 11
3rdparty/meshoptimizer/tools/cgltf.h

@@ -58,7 +58,16 @@
  * `cgltf_node_transform_world` calls `cgltf_node_transform_local` on every ancestor in order
  * `cgltf_node_transform_world` calls `cgltf_node_transform_local` on every ancestor in order
  * to compute the root-to-node transformation.
  * to compute the root-to-node transformation.
  *
  *
- * `cgltf_accessor_read_float` reads a certain element from an accessor and converts it to
+ * `cgltf_accessor_unpack_floats` reads in the data from an accessor, applies sparse data (if any),
+ * and converts them to floating point. Assumes that `cgltf_load_buffers` has already been called.
+ * By passing null for the output pointer, users can find out how many floats are required in the
+ * output buffer.
+ *
+ * `cgltf_accessor_num_components` is a tiny utility that tells you the dimensionality of
+ * a certain accessor type. This can be used before `cgltf_accessor_unpack_floats` to help allocate
+ * the necessary amount of memory.
+ *
+ * `cgltf_accessor_read_float` reads a certain element from a non-sparse accessor and converts it to
  * floating point, assuming that `cgltf_load_buffers` has already been called. The passed-in element
  * floating point, assuming that `cgltf_load_buffers` has already been called. The passed-in element
  * size is the number of floats in the output buffer, which should be in the range [1, 16]. Returns
  * size is the number of floats in the output buffer, which should be in the range [1, 16]. Returns
  * false if the passed-in element_size is too small, or if the accessor is sparse.
  * false if the passed-in element_size is too small, or if the accessor is sparse.
@@ -67,7 +76,7 @@
  * and only works with single-component data types.
  * and only works with single-component data types.
  *
  *
  * `cgltf_result cgltf_copy_extras_json(const cgltf_data*, const cgltf_extras*,
  * `cgltf_result cgltf_copy_extras_json(const cgltf_data*, const cgltf_extras*,
- * char* dest, cgltf_size* dest_size)` allows to retrieve the "extras" data that
+ * char* dest, cgltf_size* dest_size)` allows users to retrieve the "extras" data that
  * can be attached to many glTF objects (which can be arbitrary JSON data). The
  * can be attached to many glTF objects (which can be arbitrary JSON data). The
  * `cgltf_extras` struct stores the offsets of the start and end of the extras JSON data
  * `cgltf_extras` struct stores the offsets of the start and end of the extras JSON data
  * as it appears in the complete glTF JSON data. This function copies the extras data
  * as it appears in the complete glTF JSON data. This function copies the extras data
@@ -267,7 +276,7 @@ typedef struct cgltf_attribute
 	cgltf_accessor* data;
 	cgltf_accessor* data;
 } cgltf_attribute;
 } cgltf_attribute;
 
 
-typedef struct cgltf_image 
+typedef struct cgltf_image
 {
 {
 	char* name;
 	char* name;
 	char* uri;
 	char* uri;
@@ -302,7 +311,7 @@ typedef struct cgltf_texture_transform
 } cgltf_texture_transform;
 } cgltf_texture_transform;
 
 
 typedef struct cgltf_texture_view
 typedef struct cgltf_texture_view
-{	
+{
 	cgltf_texture* texture;
 	cgltf_texture* texture;
 	cgltf_int texcoord;
 	cgltf_int texcoord;
 	cgltf_float scale; /* equivalent to strength for occlusion_texture */
 	cgltf_float scale; /* equivalent to strength for occlusion_texture */
@@ -573,8 +582,7 @@ cgltf_result cgltf_load_buffers(
 
 
 cgltf_result cgltf_load_buffer_base64(const cgltf_options* options, cgltf_size size, const char* base64, void** out_data);
 cgltf_result cgltf_load_buffer_base64(const cgltf_options* options, cgltf_size size, const char* base64, void** out_data);
 
 
-cgltf_result cgltf_validate(
-		cgltf_data* data);
+cgltf_result cgltf_validate(cgltf_data* data);
 
 
 void cgltf_free(cgltf_data* data);
 void cgltf_free(cgltf_data* data);
 
 
@@ -584,6 +592,10 @@ void cgltf_node_transform_world(const cgltf_node* node, cgltf_float* out_matrix)
 cgltf_bool cgltf_accessor_read_float(const cgltf_accessor* accessor, cgltf_size index, cgltf_float* out, cgltf_size element_size);
 cgltf_bool cgltf_accessor_read_float(const cgltf_accessor* accessor, cgltf_size index, cgltf_float* out, cgltf_size element_size);
 cgltf_size cgltf_accessor_read_index(const cgltf_accessor* accessor, cgltf_size index);
 cgltf_size cgltf_accessor_read_index(const cgltf_accessor* accessor, cgltf_size index);
 
 
+cgltf_size cgltf_num_components(cgltf_type type);
+
+cgltf_size cgltf_accessor_unpack_floats(const cgltf_accessor* accessor, cgltf_float* out, cgltf_size float_count);
+
 cgltf_result cgltf_copy_extras_json(const cgltf_data* data, const cgltf_extras* extras, char* dest, cgltf_size* dest_size);
 cgltf_result cgltf_copy_extras_json(const cgltf_data* data, const cgltf_extras* extras, char* dest, cgltf_size* dest_size);
 
 
 #ifdef __cplusplus
 #ifdef __cplusplus
@@ -1563,7 +1575,6 @@ static cgltf_float cgltf_component_read_float(const void* in, cgltf_component_ty
 	return (cgltf_float)cgltf_component_read_index(in, component_type);
 	return (cgltf_float)cgltf_component_read_index(in, component_type);
 }
 }
 
 
-static cgltf_size cgltf_num_components(cgltf_type type);
 static cgltf_size cgltf_component_size(cgltf_component_type component_type);
 static cgltf_size cgltf_component_size(cgltf_component_type component_type);
 
 
 static cgltf_bool cgltf_element_read_float(const uint8_t* element, cgltf_type type, cgltf_component_type component_type, cgltf_bool normalized, cgltf_float* out, cgltf_size element_size)
 static cgltf_bool cgltf_element_read_float(const uint8_t* element, cgltf_type type, cgltf_component_type component_type, cgltf_bool normalized, cgltf_float* out, cgltf_size element_size)
@@ -1622,20 +1633,65 @@ static cgltf_bool cgltf_element_read_float(const uint8_t* element, cgltf_type ty
 	return 1;
 	return 1;
 }
 }
 
 
-
 cgltf_bool cgltf_accessor_read_float(const cgltf_accessor* accessor, cgltf_size index, cgltf_float* out, cgltf_size element_size)
 cgltf_bool cgltf_accessor_read_float(const cgltf_accessor* accessor, cgltf_size index, cgltf_float* out, cgltf_size element_size)
 {
 {
-	if (accessor->is_sparse || accessor->buffer_view == NULL)
+	if (accessor->is_sparse)
 	{
 	{
 		return 0;
 		return 0;
 	}
 	}
-
+	if (accessor->buffer_view == NULL)
+	{
+		memset(out, 0, element_size * sizeof(cgltf_float));
+		return 1;
+	}
 	cgltf_size offset = accessor->offset + accessor->buffer_view->offset;
 	cgltf_size offset = accessor->offset + accessor->buffer_view->offset;
 	const uint8_t* element = (const uint8_t*) accessor->buffer_view->buffer->data;
 	const uint8_t* element = (const uint8_t*) accessor->buffer_view->buffer->data;
 	element += offset + accessor->stride * index;
 	element += offset + accessor->stride * index;
 	return cgltf_element_read_float(element, accessor->type, accessor->component_type, accessor->normalized, out, element_size);
 	return cgltf_element_read_float(element, accessor->type, accessor->component_type, accessor->normalized, out, element_size);
 }
 }
 
 
+cgltf_size cgltf_accessor_unpack_floats(const cgltf_accessor* accessor, cgltf_float* out, cgltf_size float_count)
+{
+	cgltf_size floats_per_element = cgltf_num_components(accessor->type);
+	cgltf_size available_floats = accessor->count * floats_per_element;
+	if (out == NULL)
+	{
+		return available_floats;
+	}
+
+	float_count = available_floats < float_count ? available_floats : float_count;
+	cgltf_size element_count = float_count / floats_per_element;
+
+	// First pass: convert each element in the base accessor.
+	cgltf_float* dest = out;
+	cgltf_accessor dense = *accessor;
+	dense.is_sparse = 0;
+	for (cgltf_size index = 0; index < element_count; index++, dest += floats_per_element)
+	{
+		cgltf_accessor_read_float(&dense, index, dest, floats_per_element);
+	}
+
+	// Second pass: write out each element in the sparse accessor.
+	if (accessor->is_sparse)
+	{
+		const cgltf_accessor_sparse* sparse = &dense.sparse;
+		const uint8_t* index_data = (const uint8_t*) sparse->indices_buffer_view->buffer->data;
+		index_data += sparse->indices_byte_offset + sparse->indices_buffer_view->offset;
+		cgltf_size index_stride = cgltf_component_size(sparse->indices_component_type);
+		const uint8_t* reader_head = (const uint8_t*) sparse->values_buffer_view->buffer->data;
+		reader_head += sparse->values_byte_offset + sparse->values_buffer_view->offset;
+		for (cgltf_size reader_index = 0; reader_index < sparse->count; reader_index++, index_data += index_stride)
+		{
+			size_t writer_index = cgltf_component_read_index(index_data, sparse->indices_component_type);
+			float* writer_head = out + writer_index * floats_per_element;
+			cgltf_element_read_float(reader_head, dense.type, dense.component_type, dense.normalized, writer_head, floats_per_element);
+			reader_head += dense.stride;
+		}
+	}
+
+	return element_count * floats_per_element;
+}
+
 cgltf_size cgltf_accessor_read_index(const cgltf_accessor* accessor, cgltf_size index)
 cgltf_size cgltf_accessor_read_index(const cgltf_accessor* accessor, cgltf_size index)
 {
 {
 	if (accessor->buffer_view)
 	if (accessor->buffer_view)
@@ -3996,7 +4052,7 @@ static int cgltf_parse_json_asset(cgltf_options* options, jsmntok_t const* token
 	return i;
 	return i;
 }
 }
 
 
-static cgltf_size cgltf_num_components(cgltf_type type) {
+cgltf_size cgltf_num_components(cgltf_type type) {
 	switch (type)
 	switch (type)
 	{
 	{
 	case cgltf_type_vec2:
 	case cgltf_type_vec2:

+ 282 - 107
3rdparty/meshoptimizer/tools/gltfpack.cpp

@@ -84,6 +84,8 @@ struct Settings
 	bool simplify_aggressive;
 	bool simplify_aggressive;
 
 
 	bool compress;
 	bool compress;
+	bool fallback;
+
 	int verbose;
 	int verbose;
 };
 };
 
 
@@ -180,6 +182,30 @@ cgltf_accessor* getAccessor(const cgltf_attribute* attributes, size_t attribute_
 	return 0;
 	return 0;
 }
 }
 
 
+void readAccessor(std::vector<float>& data, const cgltf_accessor* accessor)
+{
+	assert(accessor->type == cgltf_type_scalar);
+
+	data.resize(accessor->count);
+	cgltf_accessor_unpack_floats(accessor, &data[0], data.size());
+}
+
+void readAccessor(std::vector<Attr>& data, const cgltf_accessor* accessor)
+{
+	size_t components = cgltf_num_components(accessor->type);
+
+	std::vector<float> temp(accessor->count * components);
+	cgltf_accessor_unpack_floats(accessor, &temp[0], temp.size());
+
+	data.resize(accessor->count);
+
+	for (size_t i = 0; i < accessor->count; ++i)
+	{
+		for (size_t k = 0; k < components && k < 4; ++k)
+			data[i].f[k] = temp[i * components + k];
+	}
+}
+
 void transformPosition(float* ptr, const float* transform)
 void transformPosition(float* ptr, const float* transform)
 {
 {
 	float x = ptr[0] * transform[0] + ptr[1] * transform[4] + ptr[2] * transform[8] + transform[12];
 	float x = ptr[0] * transform[0] + ptr[1] * transform[4] + ptr[2] * transform[8] + transform[12];
@@ -291,10 +317,7 @@ void parseMeshesGltf(cgltf_data* data, std::vector<Mesh>& meshes)
 				}
 				}
 
 
 				Stream s = {attr.type, attr.index};
 				Stream s = {attr.type, attr.index};
-				s.data.resize(attr.data->count);
-
-				for (size_t i = 0; i < attr.data->count; ++i)
-					cgltf_accessor_read_float(attr.data, i, s.data[i].f, 4);
+				readAccessor(s.data, attr.data);
 
 
 				result.streams.push_back(s);
 				result.streams.push_back(s);
 			}
 			}
@@ -314,10 +337,7 @@ void parseMeshesGltf(cgltf_data* data, std::vector<Mesh>& meshes)
 					}
 					}
 
 
 					Stream s = {attr.type, attr.index, int(ti + 1)};
 					Stream s = {attr.type, attr.index, int(ti + 1)};
-					s.data.resize(attr.data->count);
-
-					for (size_t i = 0; i < attr.data->count; ++i)
-						cgltf_accessor_read_float(attr.data, i, s.data[i].f, 4);
+					readAccessor(s.data, attr.data);
 
 
 					result.streams.push_back(s);
 					result.streams.push_back(s);
 				}
 				}
@@ -821,10 +841,10 @@ void reindexMesh(Mesh& mesh)
 	}
 	}
 }
 }
 
 
-const Stream* getPositionStream(const Mesh& mesh)
+Stream* getStream(Mesh& mesh, cgltf_attribute_type type)
 {
 {
 	for (size_t i = 0; i < mesh.streams.size(); ++i)
 	for (size_t i = 0; i < mesh.streams.size(); ++i)
-		if (mesh.streams[i].type == cgltf_attribute_type_position)
+		if (mesh.streams[i].type == type)
 			return &mesh.streams[i];
 			return &mesh.streams[i];
 
 
 	return 0;
 	return 0;
@@ -835,7 +855,7 @@ void simplifyMesh(Mesh& mesh, float threshold, bool aggressive)
 	if (threshold >= 1)
 	if (threshold >= 1)
 		return;
 		return;
 
 
-	const Stream* positions = getPositionStream(mesh);
+	const Stream* positions = getStream(mesh, cgltf_attribute_type_position);
 	if (!positions)
 	if (!positions)
 		return;
 		return;
 
 
@@ -883,12 +903,59 @@ void optimizeMesh(Mesh& mesh)
 	}
 	}
 }
 }
 
 
+struct BoneInfluence
+{
+	float i;
+	float w;
+
+	bool operator<(const BoneInfluence& other) const
+	{
+		return i < other.i;
+	}
+};
+
+void sortBoneInfluences(Mesh& mesh)
+{
+	Stream* joints = getStream(mesh, cgltf_attribute_type_joints);
+	Stream* weights = getStream(mesh, cgltf_attribute_type_weights);
+
+	if (!joints || !weights)
+		return;
+
+	size_t vertex_count = mesh.streams[0].data.size();
+
+	for (size_t i = 0; i < vertex_count; ++i)
+	{
+		Attr& ja = joints->data[i];
+		Attr& wa = weights->data[i];
+
+		BoneInfluence inf[4] = {};
+		int count = 0;
+
+		for (int k = 0; k < 4; ++k)
+			if (wa.f[k] > 0.f)
+			{
+				inf[count].i = ja.f[k];
+				inf[count].w = wa.f[k];
+				count++;
+			}
+
+		std::sort(inf, inf + count);
+
+		for (int k = 0; k < 4; ++k)
+		{
+			ja.f[k] = inf[k].i;
+			wa.f[k] = inf[k].w;
+		}
+	}
+}
+
 void simplifyPointMesh(Mesh& mesh, float threshold)
 void simplifyPointMesh(Mesh& mesh, float threshold)
 {
 {
 	if (threshold >= 1)
 	if (threshold >= 1)
 		return;
 		return;
 
 
-	const Stream* positions = getPositionStream(mesh);
+	const Stream* positions = getStream(mesh, cgltf_attribute_type_position);
 	if (!positions)
 	if (!positions)
 		return;
 		return;
 
 
@@ -919,7 +986,7 @@ void simplifyPointMesh(Mesh& mesh, float threshold)
 
 
 void sortPointMesh(Mesh& mesh)
 void sortPointMesh(Mesh& mesh)
 {
 {
-	const Stream* positions = getPositionStream(mesh);
+	const Stream* positions = getStream(mesh, cgltf_attribute_type_position);
 	if (!positions)
 	if (!positions)
 		return;
 		return;
 
 
@@ -1870,13 +1937,20 @@ size_t getBufferView(std::vector<BufferView>& views, BufferView::Kind kind, int
 	return views.size() - 1;
 	return views.size() - 1;
 }
 }
 
 
-void writeBufferView(std::string& json, BufferView::Kind kind, size_t count, size_t stride, size_t bin_offset, size_t bin_size, int compression)
+void writeBufferView(std::string& json, BufferView::Kind kind, size_t count, size_t stride, size_t bin_offset, size_t bin_size, int compression, size_t compressed_offset, size_t compressed_size)
 {
 {
-	append(json, "{\"buffer\":0");
-	append(json, ",\"byteLength\":");
-	append(json, bin_size);
+	assert(bin_size == count * stride);
+
+	// when compression is enabled, we store uncompressed data in buffer 1 and compressed data in buffer 0
+	// when compression is disabled, we store uncompressed data in buffer 0
+	size_t buffer = compression >= 0 ? 1 : 0;
+
+	append(json, "{\"buffer\":");
+	append(json, buffer);
 	append(json, ",\"byteOffset\":");
 	append(json, ",\"byteOffset\":");
 	append(json, bin_offset);
 	append(json, bin_offset);
+	append(json, ",\"byteLength\":");
+	append(json, bin_size);
 	if (kind == BufferView::Kind_Vertex)
 	if (kind == BufferView::Kind_Vertex)
 	{
 	{
 		append(json, ",\"byteStride\":");
 		append(json, ",\"byteStride\":");
@@ -1891,12 +1965,17 @@ void writeBufferView(std::string& json, BufferView::Kind kind, size_t count, siz
 	{
 	{
 		append(json, ",\"extensions\":{");
 		append(json, ",\"extensions\":{");
 		append(json, "\"MESHOPT_compression\":{");
 		append(json, "\"MESHOPT_compression\":{");
-		append(json, "\"mode\":");
+		append(json, "\"buffer\":0");
+		append(json, ",\"byteOffset\":");
+		append(json, size_t(compressed_offset));
+		append(json, ",\"byteLength\":");
+		append(json, size_t(compressed_size));
+		append(json, ",\"byteStride\":");
+		append(json, stride);
+		append(json, ",\"mode\":");
 		append(json, size_t(compression));
 		append(json, size_t(compression));
 		append(json, ",\"count\":");
 		append(json, ",\"count\":");
 		append(json, count);
 		append(json, count);
-		append(json, ",\"byteStride\":");
-		append(json, stride);
 		append(json, "}}");
 		append(json, "}}");
 	}
 	}
 	append(json, "}");
 	append(json, "}");
@@ -1961,7 +2040,7 @@ float getDelta(const Attr& l, const Attr& r, cgltf_animation_path_type type)
 	}
 	}
 }
 }
 
 
-bool isTrackConstant(const cgltf_animation_sampler& sampler, cgltf_animation_path_type type, cgltf_node* target_node)
+bool isTrackConstant(const cgltf_animation_sampler& sampler, cgltf_animation_path_type type, cgltf_node* target_node, Attr* out_first = 0)
 {
 {
 	const float tolerance = 1e-3f;
 	const float tolerance = 1e-3f;
 
 
@@ -1972,15 +2051,16 @@ bool isTrackConstant(const cgltf_animation_sampler& sampler, cgltf_animation_pat
 
 
 	assert(sampler.input->count * value_stride * components == sampler.output->count);
 	assert(sampler.input->count * value_stride * components == sampler.output->count);
 
 
+	std::vector<Attr> output;
+	readAccessor(output, sampler.output);
+
 	for (size_t j = 0; j < components; ++j)
 	for (size_t j = 0; j < components; ++j)
 	{
 	{
-		Attr first = {};
-		cgltf_accessor_read_float(sampler.output, j * value_stride + value_offset, first.f, 4);
+		Attr first = output[j * value_stride + value_offset];
 
 
 		for (size_t i = 1; i < sampler.input->count; ++i)
 		for (size_t i = 1; i < sampler.input->count; ++i)
 		{
 		{
-			Attr attr = {};
-			cgltf_accessor_read_float(sampler.output, (i * components + j) * value_stride + value_offset, attr.f, 4);
+			const Attr& attr = output[(i * components + j) * value_stride + value_offset];
 
 
 			if (getDelta(first, attr, type) > tolerance)
 			if (getDelta(first, attr, type) > tolerance)
 				return false;
 				return false;
@@ -1992,8 +2072,7 @@ bool isTrackConstant(const cgltf_animation_sampler& sampler, cgltf_animation_pat
 			{
 			{
 				for (int k = 0; k < 2; ++k)
 				for (int k = 0; k < 2; ++k)
 				{
 				{
-					Attr t = {};
-					cgltf_accessor_read_float(sampler.output, (i * components + j) * 3 + k * 2, t.f, 4);
+					const Attr& t = output[(i * components + j) * 3 + k * 2];
 
 
 					float error = fabsf(t.f[0]) + fabsf(t.f[1]) + fabsf(t.f[2]) + fabsf(t.f[3]);
 					float error = fabsf(t.f[0]) + fabsf(t.f[1]) + fabsf(t.f[2]) + fabsf(t.f[3]);
 
 
@@ -2004,6 +2083,9 @@ bool isTrackConstant(const cgltf_animation_sampler& sampler, cgltf_animation_pat
 		}
 		}
 	}
 	}
 
 
+	if (out_first)
+		*out_first = output[value_offset];
+
 	return true;
 	return true;
 }
 }
 
 
@@ -2093,6 +2175,11 @@ void resampleKeyframes(std::vector<Attr>& data, const cgltf_animation_sampler& s
 {
 {
 	size_t components = (type == cgltf_animation_path_type_weights) ? target_node->mesh->primitives[0].targets_count : 1;
 	size_t components = (type == cgltf_animation_path_type_weights) ? target_node->mesh->primitives[0].targets_count : 1;
 
 
+	std::vector<float> input;
+	readAccessor(input, sampler.input);
+	std::vector<Attr> output;
+	readAccessor(output, sampler.output);
+
 	size_t cursor = 0;
 	size_t cursor = 0;
 
 
 	for (int i = 0; i < frames; ++i)
 	for (int i = 0; i < frames; ++i)
@@ -2101,8 +2188,7 @@ void resampleKeyframes(std::vector<Attr>& data, const cgltf_animation_sampler& s
 
 
 		while (cursor + 1 < sampler.input->count)
 		while (cursor + 1 < sampler.input->count)
 		{
 		{
-			float next_time = 0;
-			cgltf_accessor_read_float(sampler.input, cursor + 1, &next_time, 1);
+			float next_time = input[cursor + 1];
 
 
 			if (next_time > time)
 			if (next_time > time)
 				break;
 				break;
@@ -2112,10 +2198,8 @@ void resampleKeyframes(std::vector<Attr>& data, const cgltf_animation_sampler& s
 
 
 		if (cursor + 1 < sampler.input->count)
 		if (cursor + 1 < sampler.input->count)
 		{
 		{
-			float cursor_time = 0;
-			float next_time = 0;
-			cgltf_accessor_read_float(sampler.input, cursor + 0, &cursor_time, 1);
-			cgltf_accessor_read_float(sampler.input, cursor + 1, &next_time, 1);
+			float cursor_time = input[cursor + 0];
+			float next_time = input[cursor + 1];
 
 
 			float range = next_time - cursor_time;
 			float range = next_time - cursor_time;
 			float inv_range = (range == 0.f) ? 0.f : 1.f / (next_time - cursor_time);
 			float inv_range = (range == 0.f) ? 0.f : 1.f / (next_time - cursor_time);
@@ -2127,32 +2211,25 @@ void resampleKeyframes(std::vector<Attr>& data, const cgltf_animation_sampler& s
 				{
 				{
 				case cgltf_interpolation_type_linear:
 				case cgltf_interpolation_type_linear:
 				{
 				{
-					Attr v0 = {};
-					Attr v1 = {};
-					cgltf_accessor_read_float(sampler.output, (cursor + 0) * components + j, v0.f, 4);
-					cgltf_accessor_read_float(sampler.output, (cursor + 1) * components + j, v1.f, 4);
+					const Attr& v0 = output[(cursor + 0) * components + j];
+					const Attr& v1 = output[(cursor + 1) * components + j];
 					data.push_back(interpolateLinear(v0, v1, t, type));
 					data.push_back(interpolateLinear(v0, v1, t, type));
 				}
 				}
 				break;
 				break;
 
 
 				case cgltf_interpolation_type_step:
 				case cgltf_interpolation_type_step:
 				{
 				{
-					Attr v = {};
-					cgltf_accessor_read_float(sampler.output, cursor * components + j, v.f, 4);
+					const Attr& v = output[cursor * components + j];
 					data.push_back(v);
 					data.push_back(v);
 				}
 				}
 				break;
 				break;
 
 
 				case cgltf_interpolation_type_cubic_spline:
 				case cgltf_interpolation_type_cubic_spline:
 				{
 				{
-					Attr v0 = {};
-					Attr b0 = {};
-					Attr a1 = {};
-					Attr v1 = {};
-					cgltf_accessor_read_float(sampler.output, (cursor * 3 + 1) * components + j, v0.f, 4);
-					cgltf_accessor_read_float(sampler.output, (cursor * 3 + 2) * components + j, b0.f, 4);
-					cgltf_accessor_read_float(sampler.output, (cursor * 3 + 3) * components + j, a1.f, 4);
-					cgltf_accessor_read_float(sampler.output, (cursor * 3 + 4) * components + j, v1.f, 4);
+					const Attr& v0 = output[(cursor * 3 + 1) * components + j];
+					const Attr& b0 = output[(cursor * 3 + 2) * components + j];
+					const Attr& a1 = output[(cursor * 3 + 3) * components + j];
+					const Attr& v1 = output[(cursor * 3 + 4) * components + j];
 					data.push_back(interpolateHermite(v0, b0, v1, a1, t, range, type));
 					data.push_back(interpolateHermite(v0, b0, v1, a1, t, range, type));
 				}
 				}
 				break;
 				break;
@@ -2168,8 +2245,7 @@ void resampleKeyframes(std::vector<Attr>& data, const cgltf_animation_sampler& s
 
 
 			for (size_t j = 0; j < components; ++j)
 			for (size_t j = 0; j < components; ++j)
 			{
 			{
-				Attr v = {};
-				cgltf_accessor_read_float(sampler.output, offset * components + j, v.f, 4);
+				const Attr& v = output[offset * components + j];
 				data.push_back(v);
 				data.push_back(v);
 			}
 			}
 		}
 		}
@@ -2193,8 +2269,15 @@ void markAnimated(cgltf_data* data, std::vector<NodeInfo>& nodes)
 			NodeInfo& ni = nodes[channel.target_node - data->nodes];
 			NodeInfo& ni = nodes[channel.target_node - data->nodes];
 
 
 			// mark nodes that have animation tracks that change their base transform as animated
 			// mark nodes that have animation tracks that change their base transform as animated
-			if (!isTrackConstant(sampler, channel.target_path, channel.target_node))
+			Attr first = {};
+			if (!isTrackConstant(sampler, channel.target_path, channel.target_node, &first))
+			{
+				ni.animated_paths |= (1 << channel.target_path);
+			}
+			else if (channel.target_path == cgltf_animation_path_type_weights)
 			{
 			{
+				// we currently preserve constant weight tracks because the usecase is very rare and
+				// isTrackConstant doesn't return the full set of weights to compare against
 				ni.animated_paths |= (1 << channel.target_path);
 				ni.animated_paths |= (1 << channel.target_path);
 			}
 			}
 			else
 			else
@@ -2212,12 +2295,10 @@ void markAnimated(cgltf_data* data, std::vector<NodeInfo>& nodes)
 				case cgltf_animation_path_type_scale:
 				case cgltf_animation_path_type_scale:
 					memcpy(base.f, channel.target_node->scale, 3 * sizeof(float));
 					memcpy(base.f, channel.target_node->scale, 3 * sizeof(float));
 					break;
 					break;
-				default:;
+				default:
+					assert(!"Unknown target path");
 				}
 				}
 
 
-				Attr first = {};
-				cgltf_accessor_read_float(sampler.output, 0, first.f, 4);
-
 				const float tolerance = 1e-3f;
 				const float tolerance = 1e-3f;
 
 
 				if (getDelta(base, first, channel.target_path) > tolerance)
 				if (getDelta(base, first, channel.target_path) > tolerance)
@@ -2896,6 +2977,53 @@ void writeLight(std::string& json, const cgltf_light& light)
 	append(json, "}");
 	append(json, "}");
 }
 }
 
 
+void finalizeBufferViews(std::string& json, std::vector<BufferView>& views, std::string& bin, std::string& fallback)
+{
+	for (size_t i = 0; i < views.size(); ++i)
+	{
+		BufferView& view = views[i];
+
+		size_t bin_offset = bin.size();
+		size_t fallback_offset = fallback.size();
+
+		size_t count = view.data.size() / view.stride;
+
+		int compression = -1;
+
+		if (view.compressed)
+		{
+			if (view.kind == BufferView::Kind_Index)
+			{
+				compressIndexStream(bin, view.data, count, view.stride);
+				compression = 1;
+			}
+			else
+			{
+				compressVertexStream(bin, view.data, count, view.stride);
+				compression = 0;
+			}
+
+			fallback += view.data;
+		}
+		else
+		{
+			bin += view.data;
+		}
+
+		size_t raw_offset = (compression >= 0) ? fallback_offset : bin_offset;
+
+		comma(json);
+		writeBufferView(json, view.kind, count, view.stride, raw_offset, view.data.size(), compression, bin_offset, bin.size() - bin_offset);
+
+		// record written bytes for statistics
+		view.bytes = bin.size() - bin_offset;
+
+		// align each bufferView by 4 bytes
+		bin.resize((bin.size() + 3) & ~3);
+		fallback.resize((fallback.size() + 3) & ~3);
+	}
+}
+
 void printMeshStats(const std::vector<Mesh>& meshes, const char* name)
 void printMeshStats(const std::vector<Mesh>& meshes, const char* name)
 {
 {
 	size_t triangles = 0;
 	size_t triangles = 0;
@@ -2952,7 +3080,7 @@ void printAttributeStats(const std::vector<BufferView>& views, BufferView::Kind
 	}
 	}
 }
 }
 
 
-void process(cgltf_data* data, std::vector<Mesh>& meshes, const Settings& settings, std::string& json, std::string& bin)
+void process(cgltf_data* data, std::vector<Mesh>& meshes, const Settings& settings, std::string& json, std::string& bin, std::string& fallback)
 {
 {
 	if (settings.verbose)
 	if (settings.verbose)
 	{
 	{
@@ -3017,6 +3145,7 @@ void process(cgltf_data* data, std::vector<Mesh>& meshes, const Settings& settin
 			reindexMesh(mesh);
 			reindexMesh(mesh);
 			simplifyMesh(mesh, settings.simplify_threshold, settings.simplify_aggressive);
 			simplifyMesh(mesh, settings.simplify_threshold, settings.simplify_aggressive);
 			optimizeMesh(mesh);
 			optimizeMesh(mesh);
+			sortBoneInfluences(mesh);
 			break;
 			break;
 
 
 		default:
 		default:
@@ -3342,7 +3471,7 @@ void process(cgltf_data* data, std::vector<Mesh>& meshes, const Settings& settin
 		append(json, "\"KHR_lights_punctual\"");
 		append(json, "\"KHR_lights_punctual\"");
 	}
 	}
 	append(json, "]");
 	append(json, "]");
-	if (settings.compress)
+	if (settings.compress && !settings.fallback)
 	{
 	{
 		append(json, ",\"extensionsRequired\":[");
 		append(json, ",\"extensionsRequired\":[");
 		// Note: ideally we should include MESHOPT_quantized_geometry in the required extension list (regardless of compression)
 		// Note: ideally we should include MESHOPT_quantized_geometry in the required extension list (regardless of compression)
@@ -3353,47 +3482,13 @@ void process(cgltf_data* data, std::vector<Mesh>& meshes, const Settings& settin
 		append(json, "]");
 		append(json, "]");
 	}
 	}
 
 
-	size_t bytes[BufferView::Kind_Count] = {};
-
 	if (!views.empty())
 	if (!views.empty())
 	{
 	{
-		append(json, ",\"bufferViews\":[");
-		for (size_t i = 0; i < views.size(); ++i)
-		{
-			BufferView& view = views[i];
-
-			size_t offset = bin.size();
-			size_t count = view.data.size() / view.stride;
-
-			int compression = -1;
-
-			if (view.compressed)
-			{
-				if (view.kind == BufferView::Kind_Index)
-				{
-					compressIndexStream(bin, view.data, count, view.stride);
-					compression = 1;
-				}
-				else
-				{
-					compressVertexStream(bin, view.data, count, view.stride);
-					compression = 0;
-				}
-			}
-			else
-			{
-				bin += view.data;
-			}
+		std::string json_views;
+		finalizeBufferViews(json_views, views, bin, fallback);
 
 
-			comma(json);
-			writeBufferView(json, view.kind, count, view.stride, offset, bin.size() - offset, compression);
-
-			view.bytes = bin.size() - offset;
-			bytes[view.kind] += view.bytes;
-
-			// align each bufferView by 4 bytes
-			bin.resize((bin.size() + 3) & ~3);
-		}
+		append(json, ",\"bufferViews\":[");
+		append(json, json_views);
 		append(json, "]");
 		append(json, "]");
 	}
 	}
 	if (!json_accessors.empty())
 	if (!json_accessors.empty())
@@ -3466,6 +3561,14 @@ void process(cgltf_data* data, std::vector<Mesh>& meshes, const Settings& settin
 
 
 	if (settings.verbose)
 	if (settings.verbose)
 	{
 	{
+		size_t bytes[BufferView::Kind_Count] = {};
+
+		for (size_t i = 0; i < views.size(); ++i)
+		{
+			BufferView& view = views[i];
+			bytes[view.kind] += view.bytes;
+		}
+
 		printf("output: %d nodes, %d meshes (%d primitives), %d materials\n", int(node_offset), int(mesh_offset), int(meshes.size()), int(material_offset));
 		printf("output: %d nodes, %d meshes (%d primitives), %d materials\n", int(node_offset), int(mesh_offset), int(meshes.size()), int(material_offset));
 		printf("output: JSON %d bytes, buffers %d bytes\n", int(json.size()), int(bin.size()));
 		printf("output: JSON %d bytes, buffers %d bytes\n", int(json.size()), int(bin.size()));
 		printf("output: buffers: vertex %d bytes, index %d bytes, skin %d bytes, time %d bytes, keyframe %d bytes, image %d bytes\n",
 		printf("output: buffers: vertex %d bytes, index %d bytes, skin %d bytes, time %d bytes, keyframe %d bytes, image %d bytes\n",
@@ -3495,6 +3598,56 @@ bool requiresExtension(cgltf_data* data, const char* name)
 	return false;
 	return false;
 }
 }
 
 
+const char* getBaseName(const char* path)
+{
+	const char* slash = strrchr(path, '/');
+	const char* backslash = strrchr(path, '\\');
+
+	const char* rs = slash ? slash + 1 : path;
+	const char* bs = backslash ? backslash + 1 : path;
+
+	return std::max(rs, bs);
+}
+
+std::string getBufferSpec(const char* bin_path, size_t bin_size, const char* fallback_path, size_t fallback_size, bool fallback_ref)
+{
+	std::string json;
+	append(json, "\"buffers\":[");
+	append(json, "{");
+	if (bin_path)
+	{
+		append(json, "\"uri\":\"");
+		append(json, bin_path);
+		append(json, "\"");
+	}
+	comma(json);
+	append(json, "\"byteLength\":");
+	append(json, bin_size);
+	append(json, "}");
+	if (fallback_ref)
+	{
+		comma(json);
+		append(json, "{");
+		if (fallback_path)
+		{
+			append(json, "\"uri\":\"");
+			append(json, fallback_path);
+			append(json, "\"");
+		}
+		comma(json);
+		append(json, "\"byteLength\":");
+		append(json, fallback_size);
+		append(json, ",\"extensions\":{");
+		append(json, "\"MESHOPT_compression\":{");
+		append(json, "\"fallback\":true");
+		append(json, "}}");
+		append(json, "}");
+	}
+	append(json, "]");
+
+	return json;
+}
+
 int gltfpack(const char* input, const char* output, const Settings& settings)
 int gltfpack(const char* input, const char* output, const Settings& settings)
 {
 {
 	cgltf_data* data = 0;
 	cgltf_data* data = 0;
@@ -3549,8 +3702,8 @@ int gltfpack(const char* input, const char* output, const Settings& settings)
 		return 2;
 		return 2;
 	}
 	}
 
 
-	std::string json, bin;
-	process(data, meshes, settings, json, bin);
+	std::string json, bin, fallback;
+	process(data, meshes, settings, json, bin, fallback);
 
 
 	cgltf_free(data);
 	cgltf_free(data);
 
 
@@ -3566,41 +3719,52 @@ int gltfpack(const char* input, const char* output, const Settings& settings)
 		std::string binpath = output;
 		std::string binpath = output;
 		binpath.replace(binpath.size() - 5, 5, ".bin");
 		binpath.replace(binpath.size() - 5, 5, ".bin");
 
 
-		std::string binname = binpath;
-		std::string::size_type slash = binname.find_last_of("/\\");
-		if (slash != std::string::npos)
-			binname.erase(0, slash + 1);
+		std::string fbpath = output;
+		fbpath.replace(fbpath.size() - 5, 5, ".fallback.bin");
 
 
 		FILE* outjson = fopen(output, "wb");
 		FILE* outjson = fopen(output, "wb");
 		FILE* outbin = fopen(binpath.c_str(), "wb");
 		FILE* outbin = fopen(binpath.c_str(), "wb");
-		if (!outjson || !outbin)
+		FILE* outfb = settings.fallback ? fopen(fbpath.c_str(), "wb") : NULL;
+		if (!outjson || !outbin || (!outfb && settings.fallback))
 		{
 		{
 			fprintf(stderr, "Error saving %s\n", output);
 			fprintf(stderr, "Error saving %s\n", output);
 			return 4;
 			return 4;
 		}
 		}
 
 
-		fprintf(outjson, "{\"buffers\":[{\"uri\":\"%s\",\"byteLength\":%zu}],", binname.c_str(), bin.size());
+		std::string bufferspec = getBufferSpec(getBaseName(binpath.c_str()), bin.size(), settings.fallback ? getBaseName(fbpath.c_str()) : NULL, fallback.size(), settings.compress);
+
+		fprintf(outjson, "{");
+		fwrite(bufferspec.c_str(), bufferspec.size(), 1, outjson);
+		fprintf(outjson, ",");
 		fwrite(json.c_str(), json.size(), 1, outjson);
 		fwrite(json.c_str(), json.size(), 1, outjson);
 		fprintf(outjson, "}");
 		fprintf(outjson, "}");
 
 
 		fwrite(bin.c_str(), bin.size(), 1, outbin);
 		fwrite(bin.c_str(), bin.size(), 1, outbin);
 
 
+		if (settings.fallback)
+			fwrite(fallback.c_str(), fallback.size(), 1, outfb);
+
 		fclose(outjson);
 		fclose(outjson);
 		fclose(outbin);
 		fclose(outbin);
+		if (outfb)
+			fclose(outfb);
 	}
 	}
 	else if (oext && (strcmp(oext, ".glb") == 0 || strcmp(oext, ".GLB") == 0))
 	else if (oext && (strcmp(oext, ".glb") == 0 || strcmp(oext, ".GLB") == 0))
 	{
 	{
+		std::string fbpath = output;
+		fbpath.replace(fbpath.size() - 4, 4, ".fallback.bin");
+
 		FILE* out = fopen(output, "wb");
 		FILE* out = fopen(output, "wb");
-		if (!out)
+		FILE* outfb = settings.fallback ? fopen(fbpath.c_str(), "wb") : NULL;
+		if (!out || (!outfb && settings.fallback))
 		{
 		{
 			fprintf(stderr, "Error saving %s\n", output);
 			fprintf(stderr, "Error saving %s\n", output);
 			return 4;
 			return 4;
 		}
 		}
 
 
-		char bufferspec[64];
-		sprintf(bufferspec, "{\"buffers\":[{\"byteLength\":%zu}],", bin.size());
+		std::string bufferspec = getBufferSpec(NULL, bin.size(), settings.fallback ? getBaseName(fbpath.c_str()) : NULL, fallback.size(), settings.compress);
 
 
-		json.insert(0, bufferspec);
+		json.insert(0, "{" + bufferspec + ",");
 		json.push_back('}');
 		json.push_back('}');
 
 
 		while (json.size() % 4)
 		while (json.size() % 4)
@@ -3621,7 +3785,12 @@ int gltfpack(const char* input, const char* output, const Settings& settings)
 		writeU32(out, 0x004E4942);
 		writeU32(out, 0x004E4942);
 		fwrite(bin.c_str(), bin.size(), 1, out);
 		fwrite(bin.c_str(), bin.size(), 1, out);
 
 
+		if (settings.fallback)
+			fwrite(fallback.c_str(), fallback.size(), 1, outfb);
+
 		fclose(out);
 		fclose(out);
+		if (outfb)
+			fclose(outfb);
 	}
 	}
 	else
 	else
 	{
 	{
@@ -3698,6 +3867,11 @@ int main(int argc, char** argv)
 		{
 		{
 			settings.compress = true;
 			settings.compress = true;
 		}
 		}
+		else if (strcmp(arg, "-cf") == 0)
+		{
+			settings.compress = true;
+			settings.fallback = true;
+		}
 		else if (strcmp(arg, "-v") == 0)
 		else if (strcmp(arg, "-v") == 0)
 		{
 		{
 			settings.verbose = 1;
 			settings.verbose = 1;
@@ -3749,7 +3923,8 @@ int main(int argc, char** argv)
 		fprintf(stderr, "-kn: keep named nodes and meshes attached to named nodes so that named nodes can be transformed externally\n");
 		fprintf(stderr, "-kn: keep named nodes and meshes attached to named nodes so that named nodes can be transformed externally\n");
 		fprintf(stderr, "-si R: simplify meshes to achieve the ratio R (default: 1; R should be between 0 and 1)\n");
 		fprintf(stderr, "-si R: simplify meshes to achieve the ratio R (default: 1; R should be between 0 and 1)\n");
 		fprintf(stderr, "-sa: aggressively simplify to the target ratio disregarding quality\n");
 		fprintf(stderr, "-sa: aggressively simplify to the target ratio disregarding quality\n");
-		fprintf(stderr, "-c: produce compressed glb files\n");
+		fprintf(stderr, "-c: produce compressed gltf/glb files\n");
+		fprintf(stderr, "-cf: produce compressed gltf/glb files with fallback for loaders that don't support compression\n");
 		fprintf(stderr, "-v: verbose output\n");
 		fprintf(stderr, "-v: verbose output\n");
 		fprintf(stderr, "-h: display this help and exit\n");
 		fprintf(stderr, "-h: display this help and exit\n");
 
 

Alguns ficheiros não foram mostrados porque muitos ficheiros mudaram neste diff