You've already forked godot
mirror of
https://github.com/godotengine/godot.git
synced 2025-11-06 12:20:30 +00:00
[HTML5] Refactor JS, threads support, closures.
- Refactored the Engine code, splitted across files. - Use MODULARIZE option to build emscripten code into it's own closure. - Optional closure compiler run for JS and generated code. - Enable lto support (saves ~2MiB in release). - Can now build with tools=yes (not much to see yet). - Dropped some deprecated code for older toolchains. - Add onExit, and onExecute JS function. - Add files drag and drop support. - Add support for low precessor usage mode (via offscreen render, swap).
This commit is contained in:
139
platform/javascript/engine/preloader.js
Normal file
139
platform/javascript/engine/preloader.js
Normal file
@@ -0,0 +1,139 @@
|
||||
var Preloader = /** @constructor */ function() {
|
||||
|
||||
var DOWNLOAD_ATTEMPTS_MAX = 4;
|
||||
var progressFunc = null;
|
||||
var lastProgress = { loaded: 0, total: 0 };
|
||||
|
||||
var loadingFiles = {};
|
||||
this.preloadedFiles = [];
|
||||
|
||||
function loadXHR(resolve, reject, file, tracker) {
|
||||
var xhr = new XMLHttpRequest;
|
||||
xhr.open('GET', file);
|
||||
if (!file.endsWith('.js')) {
|
||||
xhr.responseType = 'arraybuffer';
|
||||
}
|
||||
['loadstart', 'progress', 'load', 'error', 'abort'].forEach(function(ev) {
|
||||
xhr.addEventListener(ev, onXHREvent.bind(xhr, resolve, reject, file, tracker));
|
||||
});
|
||||
xhr.send();
|
||||
}
|
||||
|
||||
function onXHREvent(resolve, reject, file, tracker, ev) {
|
||||
|
||||
if (this.status >= 400) {
|
||||
|
||||
if (this.status < 500 || ++tracker[file].attempts >= DOWNLOAD_ATTEMPTS_MAX) {
|
||||
reject(new Error("Failed loading file '" + file + "': " + this.statusText));
|
||||
this.abort();
|
||||
return;
|
||||
} else {
|
||||
setTimeout(loadXHR.bind(null, resolve, reject, file, tracker), 1000);
|
||||
}
|
||||
}
|
||||
|
||||
switch (ev.type) {
|
||||
case 'loadstart':
|
||||
if (tracker[file] === undefined) {
|
||||
tracker[file] = {
|
||||
total: ev.total,
|
||||
loaded: ev.loaded,
|
||||
attempts: 0,
|
||||
final: false,
|
||||
};
|
||||
}
|
||||
break;
|
||||
|
||||
case 'progress':
|
||||
tracker[file].loaded = ev.loaded;
|
||||
tracker[file].total = ev.total;
|
||||
break;
|
||||
|
||||
case 'load':
|
||||
tracker[file].final = true;
|
||||
resolve(this);
|
||||
break;
|
||||
|
||||
case 'error':
|
||||
if (++tracker[file].attempts >= DOWNLOAD_ATTEMPTS_MAX) {
|
||||
tracker[file].final = true;
|
||||
reject(new Error("Failed loading file '" + file + "'"));
|
||||
} else {
|
||||
setTimeout(loadXHR.bind(null, resolve, reject, file, tracker), 1000);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'abort':
|
||||
tracker[file].final = true;
|
||||
reject(new Error("Loading file '" + file + "' was aborted."));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
this.loadPromise = function(file) {
|
||||
return new Promise(function(resolve, reject) {
|
||||
loadXHR(resolve, reject, file, loadingFiles);
|
||||
});
|
||||
}
|
||||
|
||||
this.preload = function(pathOrBuffer, destPath) {
|
||||
if (pathOrBuffer instanceof ArrayBuffer) {
|
||||
pathOrBuffer = new Uint8Array(pathOrBuffer);
|
||||
} else if (ArrayBuffer.isView(pathOrBuffer)) {
|
||||
pathOrBuffer = new Uint8Array(pathOrBuffer.buffer);
|
||||
}
|
||||
if (pathOrBuffer instanceof Uint8Array) {
|
||||
this.preloadedFiles.push({
|
||||
path: destPath,
|
||||
buffer: pathOrBuffer
|
||||
});
|
||||
return Promise.resolve();
|
||||
} else if (typeof pathOrBuffer === 'string') {
|
||||
var me = this;
|
||||
return this.loadPromise(pathOrBuffer).then(function(xhr) {
|
||||
me.preloadedFiles.push({
|
||||
path: destPath || pathOrBuffer,
|
||||
buffer: xhr.response
|
||||
});
|
||||
return Promise.resolve();
|
||||
});
|
||||
} else {
|
||||
throw Promise.reject("Invalid object for preloading");
|
||||
}
|
||||
};
|
||||
|
||||
var animateProgress = function() {
|
||||
|
||||
var loaded = 0;
|
||||
var total = 0;
|
||||
var totalIsValid = true;
|
||||
var progressIsFinal = true;
|
||||
|
||||
Object.keys(loadingFiles).forEach(function(file) {
|
||||
const stat = loadingFiles[file];
|
||||
if (!stat.final) {
|
||||
progressIsFinal = false;
|
||||
}
|
||||
if (!totalIsValid || stat.total === 0) {
|
||||
totalIsValid = false;
|
||||
total = 0;
|
||||
} else {
|
||||
total += stat.total;
|
||||
}
|
||||
loaded += stat.loaded;
|
||||
});
|
||||
if (loaded !== lastProgress.loaded || total !== lastProgress.total) {
|
||||
lastProgress.loaded = loaded;
|
||||
lastProgress.total = total;
|
||||
if (typeof progressFunc === 'function')
|
||||
progressFunc(loaded, total);
|
||||
}
|
||||
if (!progressIsFinal)
|
||||
requestAnimationFrame(animateProgress);
|
||||
}
|
||||
this.animateProgress = animateProgress; // Also exposed to start it.
|
||||
|
||||
this.setProgressFunc = function(callback) {
|
||||
progressFunc = callback;
|
||||
}
|
||||
};
|
||||
Reference in New Issue
Block a user