@babylonjs/loaders
Version:
The Babylon.js file loaders library is an extension you can use to load different 3D file types into a Babylon scene.
247 lines • 11.6 kB
JavaScript
import { Observable } from "@babylonjs/core/Misc/observable";
import { Deferred } from "@babylonjs/core/Misc/deferred";
import { GLTFLoader, ArrayItem } from "../glTFLoader";
var NAME = "MSFT_lod";
/**
* [Specification](https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Vendor/MSFT_lod)
*/
var MSFT_lod = /** @class */ (function () {
/** @hidden */
function MSFT_lod(loader) {
/** The name of this extension. */
this.name = NAME;
/** Defines whether this extension is enabled. */
this.enabled = true;
/**
* Maximum number of LODs to load, starting from the lowest LOD.
*/
this.maxLODsToLoad = Number.MAX_VALUE;
/**
* Observable raised when all node LODs of one level are loaded.
* The event data is the index of the loaded LOD starting from zero.
* Dispose the loader to cancel the loading of the next level of LODs.
*/
this.onNodeLODsLoadedObservable = new Observable();
/**
* Observable raised when all material LODs of one level are loaded.
* The event data is the index of the loaded LOD starting from zero.
* Dispose the loader to cancel the loading of the next level of LODs.
*/
this.onMaterialLODsLoadedObservable = new Observable();
this._nodeIndexLOD = null;
this._nodeSignalLODs = new Array();
this._nodePromiseLODs = new Array();
this._materialIndexLOD = null;
this._materialSignalLODs = new Array();
this._materialPromiseLODs = new Array();
this._loader = loader;
}
/** @hidden */
MSFT_lod.prototype.dispose = function () {
delete this._loader;
this._nodeIndexLOD = null;
this._nodeSignalLODs.length = 0;
this._nodePromiseLODs.length = 0;
this._materialIndexLOD = null;
this._materialSignalLODs.length = 0;
this._materialPromiseLODs.length = 0;
this.onMaterialLODsLoadedObservable.clear();
this.onNodeLODsLoadedObservable.clear();
};
/** @hidden */
MSFT_lod.prototype.onReady = function () {
var _this = this;
var _loop_1 = function (indexLOD) {
var promise = Promise.all(this_1._nodePromiseLODs[indexLOD]).then(function () {
if (indexLOD !== 0) {
_this._loader.endPerformanceCounter("Node LOD " + indexLOD);
}
_this._loader.log("Loaded node LOD " + indexLOD);
_this.onNodeLODsLoadedObservable.notifyObservers(indexLOD);
if (indexLOD !== _this._nodePromiseLODs.length - 1) {
_this._loader.startPerformanceCounter("Node LOD " + (indexLOD + 1));
if (_this._nodeSignalLODs[indexLOD]) {
_this._nodeSignalLODs[indexLOD].resolve();
}
}
});
this_1._loader._completePromises.push(promise);
};
var this_1 = this;
for (var indexLOD = 0; indexLOD < this._nodePromiseLODs.length; indexLOD++) {
_loop_1(indexLOD);
}
var _loop_2 = function (indexLOD) {
var promise = Promise.all(this_2._materialPromiseLODs[indexLOD]).then(function () {
if (indexLOD !== 0) {
_this._loader.endPerformanceCounter("Material LOD " + indexLOD);
}
_this._loader.log("Loaded material LOD " + indexLOD);
_this.onMaterialLODsLoadedObservable.notifyObservers(indexLOD);
if (indexLOD !== _this._materialPromiseLODs.length - 1) {
_this._loader.startPerformanceCounter("Material LOD " + (indexLOD + 1));
if (_this._materialSignalLODs[indexLOD]) {
_this._materialSignalLODs[indexLOD].resolve();
}
}
});
this_2._loader._completePromises.push(promise);
};
var this_2 = this;
for (var indexLOD = 0; indexLOD < this._materialPromiseLODs.length; indexLOD++) {
_loop_2(indexLOD);
}
};
/** @hidden */
MSFT_lod.prototype.loadNodeAsync = function (context, node, assign) {
var _this = this;
return GLTFLoader.LoadExtensionAsync(context, node, this.name, function (extensionContext, extension) {
var firstPromise;
var nodeLODs = _this._getLODs(extensionContext, node, _this._loader.gltf.nodes, extension.ids);
_this._loader.logOpen("" + extensionContext);
var _loop_3 = function (indexLOD) {
var nodeLOD = nodeLODs[indexLOD];
if (indexLOD !== 0) {
_this._nodeIndexLOD = indexLOD;
_this._nodeSignalLODs[indexLOD] = _this._nodeSignalLODs[indexLOD] || new Deferred();
}
var assign_1 = function (babylonTransformNode) { babylonTransformNode.setEnabled(false); };
var promise = _this._loader.loadNodeAsync("#/nodes/" + nodeLOD.index, nodeLOD, assign_1).then(function (babylonMesh) {
if (indexLOD !== 0) {
// TODO: should not rely on _babylonMesh
var previousNodeLOD = nodeLODs[indexLOD - 1];
if (previousNodeLOD._babylonTransformNode) {
previousNodeLOD._babylonTransformNode.dispose();
delete previousNodeLOD._babylonTransformNode;
_this._disposeUnusedMaterials();
}
}
babylonMesh.setEnabled(true);
return babylonMesh;
});
if (indexLOD === 0) {
firstPromise = promise;
}
else {
_this._nodeIndexLOD = null;
}
_this._nodePromiseLODs[indexLOD] = _this._nodePromiseLODs[indexLOD] || [];
_this._nodePromiseLODs[indexLOD].push(promise);
};
for (var indexLOD = 0; indexLOD < nodeLODs.length; indexLOD++) {
_loop_3(indexLOD);
}
_this._loader.logClose();
return firstPromise;
});
};
/** @hidden */
MSFT_lod.prototype._loadMaterialAsync = function (context, material, babylonMesh, babylonDrawMode, assign) {
var _this = this;
// Don't load material LODs if already loading a node LOD.
if (this._nodeIndexLOD) {
return null;
}
return GLTFLoader.LoadExtensionAsync(context, material, this.name, function (extensionContext, extension) {
var firstPromise;
var materialLODs = _this._getLODs(extensionContext, material, _this._loader.gltf.materials, extension.ids);
_this._loader.logOpen("" + extensionContext);
var _loop_4 = function (indexLOD) {
var materialLOD = materialLODs[indexLOD];
if (indexLOD !== 0) {
_this._materialIndexLOD = indexLOD;
}
var promise = _this._loader._loadMaterialAsync("#/materials/" + materialLOD.index, materialLOD, babylonMesh, babylonDrawMode, function (babylonMaterial) {
if (indexLOD === 0) {
assign(babylonMaterial);
}
}).then(function (babylonMaterial) {
if (indexLOD !== 0) {
assign(babylonMaterial);
// TODO: should not rely on _data
var previousDataLOD = materialLODs[indexLOD - 1]._data;
if (previousDataLOD[babylonDrawMode]) {
previousDataLOD[babylonDrawMode].babylonMaterial.dispose();
delete previousDataLOD[babylonDrawMode];
}
}
return babylonMaterial;
});
if (indexLOD === 0) {
firstPromise = promise;
}
else {
_this._materialIndexLOD = null;
}
_this._materialPromiseLODs[indexLOD] = _this._materialPromiseLODs[indexLOD] || [];
_this._materialPromiseLODs[indexLOD].push(promise);
};
for (var indexLOD = 0; indexLOD < materialLODs.length; indexLOD++) {
_loop_4(indexLOD);
}
_this._loader.logClose();
return firstPromise;
});
};
/** @hidden */
MSFT_lod.prototype._loadUriAsync = function (context, property, uri) {
var _this = this;
// Defer the loading of uris if loading a material or node LOD.
if (this._materialIndexLOD !== null) {
this._loader.log("deferred");
var previousIndexLOD = this._materialIndexLOD - 1;
this._materialSignalLODs[previousIndexLOD] = this._materialSignalLODs[previousIndexLOD] || new Deferred();
return this._materialSignalLODs[previousIndexLOD].promise.then(function () {
return _this._loader.loadUriAsync(context, property, uri);
});
}
else if (this._nodeIndexLOD !== null) {
this._loader.log("deferred");
var previousIndexLOD = this._nodeIndexLOD - 1;
this._nodeSignalLODs[previousIndexLOD] = this._nodeSignalLODs[previousIndexLOD] || new Deferred();
return this._nodeSignalLODs[this._nodeIndexLOD - 1].promise.then(function () {
return _this._loader.loadUriAsync(context, property, uri);
});
}
return null;
};
/**
* Gets an array of LOD properties from lowest to highest.
*/
MSFT_lod.prototype._getLODs = function (context, property, array, ids) {
if (this.maxLODsToLoad <= 0) {
throw new Error("maxLODsToLoad must be greater than zero");
}
var properties = new Array();
for (var i = ids.length - 1; i >= 0; i--) {
properties.push(ArrayItem.Get(context + "/ids/" + ids[i], array, ids[i]));
if (properties.length === this.maxLODsToLoad) {
return properties;
}
}
properties.push(property);
return properties;
};
MSFT_lod.prototype._disposeUnusedMaterials = function () {
// TODO: should not rely on _data
var materials = this._loader.gltf.materials;
if (materials) {
for (var _i = 0, materials_1 = materials; _i < materials_1.length; _i++) {
var material = materials_1[_i];
if (material._data) {
for (var drawMode in material._data) {
var data = material._data[drawMode];
if (data.babylonMeshes.length === 0) {
data.babylonMaterial.dispose(false, true);
delete material._data[drawMode];
}
}
}
}
}
};
return MSFT_lod;
}());
export { MSFT_lod };
GLTFLoader.RegisterExtension(NAME, function (loader) { return new MSFT_lod(loader); });
//# sourceMappingURL=MSFT_lod.js.map