UNPKG

11.6 kBJavaScriptView Raw
1import { Observable } from "@babylonjs/core/Misc/observable";
2import { Deferred } from "@babylonjs/core/Misc/deferred";
3import { GLTFLoader, ArrayItem } from "../glTFLoader";
4var NAME = "MSFT_lod";
5/**
6 * [Specification](https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Vendor/MSFT_lod)
7 */
8var MSFT_lod = /** @class */ (function () {
9 /** @hidden */
10 function MSFT_lod(loader) {
11 /** The name of this extension. */
12 this.name = NAME;
13 /** Defines whether this extension is enabled. */
14 this.enabled = true;
15 /**
16 * Maximum number of LODs to load, starting from the lowest LOD.
17 */
18 this.maxLODsToLoad = Number.MAX_VALUE;
19 /**
20 * Observable raised when all node LODs of one level are loaded.
21 * The event data is the index of the loaded LOD starting from zero.
22 * Dispose the loader to cancel the loading of the next level of LODs.
23 */
24 this.onNodeLODsLoadedObservable = new Observable();
25 /**
26 * Observable raised when all material LODs of one level are loaded.
27 * The event data is the index of the loaded LOD starting from zero.
28 * Dispose the loader to cancel the loading of the next level of LODs.
29 */
30 this.onMaterialLODsLoadedObservable = new Observable();
31 this._nodeIndexLOD = null;
32 this._nodeSignalLODs = new Array();
33 this._nodePromiseLODs = new Array();
34 this._materialIndexLOD = null;
35 this._materialSignalLODs = new Array();
36 this._materialPromiseLODs = new Array();
37 this._loader = loader;
38 }
39 /** @hidden */
40 MSFT_lod.prototype.dispose = function () {
41 delete this._loader;
42 this._nodeIndexLOD = null;
43 this._nodeSignalLODs.length = 0;
44 this._nodePromiseLODs.length = 0;
45 this._materialIndexLOD = null;
46 this._materialSignalLODs.length = 0;
47 this._materialPromiseLODs.length = 0;
48 this.onMaterialLODsLoadedObservable.clear();
49 this.onNodeLODsLoadedObservable.clear();
50 };
51 /** @hidden */
52 MSFT_lod.prototype.onReady = function () {
53 var _this = this;
54 var _loop_1 = function (indexLOD) {
55 var promise = Promise.all(this_1._nodePromiseLODs[indexLOD]).then(function () {
56 if (indexLOD !== 0) {
57 _this._loader.endPerformanceCounter("Node LOD " + indexLOD);
58 }
59 _this._loader.log("Loaded node LOD " + indexLOD);
60 _this.onNodeLODsLoadedObservable.notifyObservers(indexLOD);
61 if (indexLOD !== _this._nodePromiseLODs.length - 1) {
62 _this._loader.startPerformanceCounter("Node LOD " + (indexLOD + 1));
63 if (_this._nodeSignalLODs[indexLOD]) {
64 _this._nodeSignalLODs[indexLOD].resolve();
65 }
66 }
67 });
68 this_1._loader._completePromises.push(promise);
69 };
70 var this_1 = this;
71 for (var indexLOD = 0; indexLOD < this._nodePromiseLODs.length; indexLOD++) {
72 _loop_1(indexLOD);
73 }
74 var _loop_2 = function (indexLOD) {
75 var promise = Promise.all(this_2._materialPromiseLODs[indexLOD]).then(function () {
76 if (indexLOD !== 0) {
77 _this._loader.endPerformanceCounter("Material LOD " + indexLOD);
78 }
79 _this._loader.log("Loaded material LOD " + indexLOD);
80 _this.onMaterialLODsLoadedObservable.notifyObservers(indexLOD);
81 if (indexLOD !== _this._materialPromiseLODs.length - 1) {
82 _this._loader.startPerformanceCounter("Material LOD " + (indexLOD + 1));
83 if (_this._materialSignalLODs[indexLOD]) {
84 _this._materialSignalLODs[indexLOD].resolve();
85 }
86 }
87 });
88 this_2._loader._completePromises.push(promise);
89 };
90 var this_2 = this;
91 for (var indexLOD = 0; indexLOD < this._materialPromiseLODs.length; indexLOD++) {
92 _loop_2(indexLOD);
93 }
94 };
95 /** @hidden */
96 MSFT_lod.prototype.loadNodeAsync = function (context, node, assign) {
97 var _this = this;
98 return GLTFLoader.LoadExtensionAsync(context, node, this.name, function (extensionContext, extension) {
99 var firstPromise;
100 var nodeLODs = _this._getLODs(extensionContext, node, _this._loader.gltf.nodes, extension.ids);
101 _this._loader.logOpen("" + extensionContext);
102 var _loop_3 = function (indexLOD) {
103 var nodeLOD = nodeLODs[indexLOD];
104 if (indexLOD !== 0) {
105 _this._nodeIndexLOD = indexLOD;
106 _this._nodeSignalLODs[indexLOD] = _this._nodeSignalLODs[indexLOD] || new Deferred();
107 }
108 var assign_1 = function (babylonTransformNode) { babylonTransformNode.setEnabled(false); };
109 var promise = _this._loader.loadNodeAsync("#/nodes/" + nodeLOD.index, nodeLOD, assign_1).then(function (babylonMesh) {
110 if (indexLOD !== 0) {
111 // TODO: should not rely on _babylonMesh
112 var previousNodeLOD = nodeLODs[indexLOD - 1];
113 if (previousNodeLOD._babylonTransformNode) {
114 previousNodeLOD._babylonTransformNode.dispose();
115 delete previousNodeLOD._babylonTransformNode;
116 _this._disposeUnusedMaterials();
117 }
118 }
119 babylonMesh.setEnabled(true);
120 return babylonMesh;
121 });
122 if (indexLOD === 0) {
123 firstPromise = promise;
124 }
125 else {
126 _this._nodeIndexLOD = null;
127 }
128 _this._nodePromiseLODs[indexLOD] = _this._nodePromiseLODs[indexLOD] || [];
129 _this._nodePromiseLODs[indexLOD].push(promise);
130 };
131 for (var indexLOD = 0; indexLOD < nodeLODs.length; indexLOD++) {
132 _loop_3(indexLOD);
133 }
134 _this._loader.logClose();
135 return firstPromise;
136 });
137 };
138 /** @hidden */
139 MSFT_lod.prototype._loadMaterialAsync = function (context, material, babylonMesh, babylonDrawMode, assign) {
140 var _this = this;
141 // Don't load material LODs if already loading a node LOD.
142 if (this._nodeIndexLOD) {
143 return null;
144 }
145 return GLTFLoader.LoadExtensionAsync(context, material, this.name, function (extensionContext, extension) {
146 var firstPromise;
147 var materialLODs = _this._getLODs(extensionContext, material, _this._loader.gltf.materials, extension.ids);
148 _this._loader.logOpen("" + extensionContext);
149 var _loop_4 = function (indexLOD) {
150 var materialLOD = materialLODs[indexLOD];
151 if (indexLOD !== 0) {
152 _this._materialIndexLOD = indexLOD;
153 }
154 var promise = _this._loader._loadMaterialAsync("#/materials/" + materialLOD.index, materialLOD, babylonMesh, babylonDrawMode, function (babylonMaterial) {
155 if (indexLOD === 0) {
156 assign(babylonMaterial);
157 }
158 }).then(function (babylonMaterial) {
159 if (indexLOD !== 0) {
160 assign(babylonMaterial);
161 // TODO: should not rely on _data
162 var previousDataLOD = materialLODs[indexLOD - 1]._data;
163 if (previousDataLOD[babylonDrawMode]) {
164 previousDataLOD[babylonDrawMode].babylonMaterial.dispose();
165 delete previousDataLOD[babylonDrawMode];
166 }
167 }
168 return babylonMaterial;
169 });
170 if (indexLOD === 0) {
171 firstPromise = promise;
172 }
173 else {
174 _this._materialIndexLOD = null;
175 }
176 _this._materialPromiseLODs[indexLOD] = _this._materialPromiseLODs[indexLOD] || [];
177 _this._materialPromiseLODs[indexLOD].push(promise);
178 };
179 for (var indexLOD = 0; indexLOD < materialLODs.length; indexLOD++) {
180 _loop_4(indexLOD);
181 }
182 _this._loader.logClose();
183 return firstPromise;
184 });
185 };
186 /** @hidden */
187 MSFT_lod.prototype._loadUriAsync = function (context, property, uri) {
188 var _this = this;
189 // Defer the loading of uris if loading a material or node LOD.
190 if (this._materialIndexLOD !== null) {
191 this._loader.log("deferred");
192 var previousIndexLOD = this._materialIndexLOD - 1;
193 this._materialSignalLODs[previousIndexLOD] = this._materialSignalLODs[previousIndexLOD] || new Deferred();
194 return this._materialSignalLODs[previousIndexLOD].promise.then(function () {
195 return _this._loader.loadUriAsync(context, property, uri);
196 });
197 }
198 else if (this._nodeIndexLOD !== null) {
199 this._loader.log("deferred");
200 var previousIndexLOD = this._nodeIndexLOD - 1;
201 this._nodeSignalLODs[previousIndexLOD] = this._nodeSignalLODs[previousIndexLOD] || new Deferred();
202 return this._nodeSignalLODs[this._nodeIndexLOD - 1].promise.then(function () {
203 return _this._loader.loadUriAsync(context, property, uri);
204 });
205 }
206 return null;
207 };
208 /**
209 * Gets an array of LOD properties from lowest to highest.
210 */
211 MSFT_lod.prototype._getLODs = function (context, property, array, ids) {
212 if (this.maxLODsToLoad <= 0) {
213 throw new Error("maxLODsToLoad must be greater than zero");
214 }
215 var properties = new Array();
216 for (var i = ids.length - 1; i >= 0; i--) {
217 properties.push(ArrayItem.Get(context + "/ids/" + ids[i], array, ids[i]));
218 if (properties.length === this.maxLODsToLoad) {
219 return properties;
220 }
221 }
222 properties.push(property);
223 return properties;
224 };
225 MSFT_lod.prototype._disposeUnusedMaterials = function () {
226 // TODO: should not rely on _data
227 var materials = this._loader.gltf.materials;
228 if (materials) {
229 for (var _i = 0, materials_1 = materials; _i < materials_1.length; _i++) {
230 var material = materials_1[_i];
231 if (material._data) {
232 for (var drawMode in material._data) {
233 var data = material._data[drawMode];
234 if (data.babylonMeshes.length === 0) {
235 data.babylonMaterial.dispose(false, true);
236 delete material._data[drawMode];
237 }
238 }
239 }
240 }
241 }
242 };
243 return MSFT_lod;
244}());
245export { MSFT_lod };
246GLTFLoader.RegisterExtension(NAME, function (loader) { return new MSFT_lod(loader); });
247//# sourceMappingURL=MSFT_lod.js.map
\No newline at end of file