mirror of
https://github.com/Heretek-AI/GDevelop.git
synced 2026-07-22 10:05:37 -04:00
1f852648ef
* Only the first scene and global objects resources (images, sounds, 3D models etc...) will be downloaded during launch of the game. This usually allows for a very fast loading time. * Other scenes resources will continue to load in the background. It has no impact on the game performance as this is done on other threads by the browser or the engine running the game. * Scenes are loaded in the order they are listed in the project manager. * You can also use actions and expressions to prioritize a scene (if it's known that a level will be needed soon for example) or read the current loading progress. This allows to create lightweight scenes that can act as custom loading screens. Otherwise, the launch loading screen will be shown if a scene is still loading when launched. * Read more about this on https://wiki.gdevelop.io/gdevelop5/all-features/resources-loading/.
151 lines
4.5 KiB
TypeScript
151 lines
4.5 KiB
TypeScript
/*
|
|
* GDevelop JS Platform
|
|
* Copyright 2013-present Florian Rival (Florian.Rival@gmail.com). All rights reserved.
|
|
* This project is released under the MIT License.
|
|
*/
|
|
namespace gdjs {
|
|
const logger = new gdjs.Logger('Model3DManager');
|
|
|
|
const resourceKinds: Array<ResourceKind> = ['model3D'];
|
|
|
|
/**
|
|
* Load GLB files (using `Three.js`), using the "model3D" resources
|
|
* registered in the game resources.
|
|
*/
|
|
export class Model3DManager implements gdjs.ResourceManager {
|
|
/**
|
|
* Map associating a resource name to the loaded Three.js model.
|
|
*/
|
|
private _loadedThreeModels = new gdjs.ResourceCache<THREE_ADDONS.GLTF>();
|
|
private _downloadedArrayBuffers = new gdjs.ResourceCache<ArrayBuffer>();
|
|
|
|
_resourceLoader: gdjs.ResourceLoader;
|
|
|
|
_loader: THREE_ADDONS.GLTFLoader | null = null;
|
|
_dracoLoader: THREE_ADDONS.DRACOLoader | null = null;
|
|
|
|
//@ts-ignore Can only be null if THREE is not loaded.
|
|
_invalidModel: THREE_ADDONS.GLTF;
|
|
|
|
/**
|
|
* @param resourceDataArray The resources data of the game.
|
|
* @param resourceLoader The resources loader of the game.
|
|
*/
|
|
constructor(resourceLoader: gdjs.ResourceLoader) {
|
|
this._resourceLoader = resourceLoader;
|
|
|
|
if (typeof THREE !== 'undefined') {
|
|
this._loader = new THREE_ADDONS.GLTFLoader();
|
|
|
|
this._dracoLoader = new THREE_ADDONS.DRACOLoader();
|
|
this._dracoLoader.setDecoderPath('./pixi-renderers/draco/gltf/');
|
|
this._loader.setDRACOLoader(this._dracoLoader);
|
|
|
|
/**
|
|
* The invalid model is a box with magenta (#ff00ff) faces, to be
|
|
* easily spotted if rendered on screen.
|
|
*/
|
|
const group = new THREE.Group();
|
|
group.add(
|
|
new THREE.Mesh(
|
|
new THREE.BoxGeometry(1, 1, 1),
|
|
new THREE.MeshBasicMaterial({ color: '#ff00ff' })
|
|
)
|
|
);
|
|
this._invalidModel = {
|
|
scene: group,
|
|
animations: [],
|
|
cameras: [],
|
|
scenes: [],
|
|
asset: {},
|
|
userData: {},
|
|
//@ts-ignore
|
|
parser: null,
|
|
};
|
|
}
|
|
}
|
|
|
|
getResourceKinds(): ResourceKind[] {
|
|
return resourceKinds;
|
|
}
|
|
|
|
async processResource(resourceName: string): Promise<void> {
|
|
const resource = this._resourceLoader.getResource(resourceName);
|
|
if (!resource) {
|
|
logger.warn(
|
|
'Unable to find texture for resource "' + resourceName + '".'
|
|
);
|
|
return;
|
|
}
|
|
const loader = this._loader;
|
|
if (!loader) {
|
|
return;
|
|
}
|
|
const data = this._downloadedArrayBuffers.get(resource);
|
|
if (!data) {
|
|
return;
|
|
}
|
|
this._downloadedArrayBuffers.delete(resource);
|
|
try {
|
|
const gltf: THREE_ADDONS.GLTF = await loader.parseAsync(data, '');
|
|
this._loadedThreeModels.set(resource, gltf);
|
|
} catch (error) {
|
|
logger.error(
|
|
"Can't fetch the 3D model file " + resource.file + ', error: ' + error
|
|
);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Load all the 3D models.
|
|
*
|
|
* Note that even if a file is already loaded, it will be reloaded (useful for hot-reloading,
|
|
* as files can have been modified without the editor knowing).
|
|
*/
|
|
async loadResource(resourceName: string): Promise<void> {
|
|
const resource = this._resourceLoader.getResource(resourceName);
|
|
if (!resource) {
|
|
logger.warn(
|
|
'Unable to find texture for resource "' + resourceName + '".'
|
|
);
|
|
return;
|
|
}
|
|
const loader = this._loader;
|
|
if (!loader) {
|
|
return;
|
|
}
|
|
const url = this._resourceLoader.getFullUrl(resource.file);
|
|
try {
|
|
const response = await fetch(url, {
|
|
credentials: this._resourceLoader.checkIfCredentialsRequired(url)
|
|
? 'include'
|
|
: 'omit',
|
|
});
|
|
if (!response.ok) {
|
|
throw new Error('Network response was not ok');
|
|
}
|
|
const data = await response.arrayBuffer();
|
|
this._downloadedArrayBuffers.set(resource, data);
|
|
} catch (error) {
|
|
logger.error(
|
|
"Can't fetch the 3D model file " + resource.file + ', error: ' + error
|
|
);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Return a 3D model.
|
|
*
|
|
* Caller should not modify the object but clone it.
|
|
*
|
|
* @param resourceName The name of the json resource.
|
|
* @returns a 3D model if it exists.
|
|
*/
|
|
getModel(resourceName: string): THREE_ADDONS.GLTF {
|
|
return (
|
|
this._loadedThreeModels.getFromName(resourceName) || this._invalidModel
|
|
);
|
|
}
|
|
}
|
|
}
|