UNPKG

@wonderlandengine/api

Version:

Wonderland Engine's JavaScript API.

546 lines (545 loc) 18 kB
import { ComponentManagers, NativeComponents } from './component.js'; import { WonderlandEngine } from './engine.js'; import { ResourceManager, SceneResource } from './resources/resource.js'; import { AnimationGraphManager } from './resources/animation-graph-manager.js'; import { ProgressCallback } from './types.js'; import { Animation, CollisionCallback, Component, ComponentConstructor, Object3D, Skin } from './wonderland.js'; /** Scene loading options. */ export interface SceneLoadOptions { /** An in-memory buffer, containing the bytes of a `.bin` file. */ buffer: ArrayBuffer; /** Path from which resources are resolved (images, languages, etc...). */ baseURL: string; /** If `true`, dispatches a ready event in the document. */ dispatchReadyEvent?: boolean; } /** Loading options for in-memory data. */ export interface InMemoryLoadOptions { /** An in-memory buffer, containing the bytes of a `.bin` file. */ buffer: ArrayBuffer; /** Path from which resources are resolved (images, languages, etc...). */ baseURL: string; /** Name of the file. This is the same that will be retrieved via {@link Scene#filename} */ filename?: string; /** * Force to re-download the components bundle, and not use the version from cache. * * If not set, defaults to `false`. * * @note For now, this setting only affects the main scene loading. */ nocache?: boolean; } /** * Options used with {@link Prefab.destroyResources}. */ export interface DestroyResourcesOptions { /** Destroy resources **loaded** alongside the prefab */ loaded: boolean; } /** * Loading options for streamed data. * * @hidden */ export interface StreamLoadOptions { /** Stream that transfers the bytes of a `.bin` file. */ stream: ReadableStream<Uint8Array>; /** Path from which resources are resolved (images, languages, etc...). */ baseURL: string; /** Name of the file. This is the same that will be retrieved via {@link Scene#filename} */ filename?: string; } /** Options for loading files from a URL. */ export interface UrlLoadOptions { /** URL to load. */ url: string; /** Signal to abort the file fetch request. */ signal?: AbortSignal; /** * Whether to load the file as parts of it are fetched. If `false`, * fetches the entire file first before loading. Streamed loading reduces * memory usage. If not set, defaults to `true`. */ streamed?: boolean; /** * Force to re-download the components bundle, and not use the version from cache. * * If not set, defaults to `false`. * * @note For now, this setting only affects the main scene loading. */ nocache?: boolean; } /** Options used during loading. */ export type LoadOptions<Extra = {}> = string | (UrlLoadOptions & Partial<Extra>); /** * Base class for prefabs, scenes, and glTF. * * For more information have a look at the derived types: * - {@link Scene} for Wonderland Engine activatable scenes (.bin) * - {@link PrefabGLTF} for glTF scenes * * #### Resources * * While **meshes**, **textures**, and **materials** are shared * on the {@link WonderlandEngine} instance, a scene comes with: * - Animations: Managed using {@link Prefab.animations} * - Skins: Managed using {@link Prefab.skins} * * Those resources are bound to the object hierarchy and are thus required to be * per-scene. * * #### Destruction * * For now, destroying a scene doesn't automatically remove the resources it * references in the engine. For more information, have a look at the * {@link Scene.destroy} method. * * #### Isolation * * It's forbidden to mix objects and components from different scenes, e.g., * * ```js * const objA = sceneA.addChild(); * const objB = sceneB.addChild(); * objA.parent = objB; // Throws * ``` * * @category scene * * @since 1.2.0 */ export declare class Prefab { /** * Create an object with shape `{url: string}`. * * - If the parameter is a string, a new object is returned * - If the parameter is an object, the same reference is returned * * @param options The url or options object. * @returns An object of the form `{url: string, ...}`. * * @hidden */ static makeUrlLoadOptions<E>(options: LoadOptions<E>): UrlLoadOptions & Partial<E>; /** * Load an `ArrayBuffer` using fetch. * * @param opts The url or options. * @param progress Progress callback * @returns An {@link InMemoryLoadOptions} object. * * @hidden */ static loadBuffer(options: LoadOptions, progress?: ProgressCallback): Promise<InMemoryLoadOptions>; /** * Load a `ReadableStream` using fetch. * * @param opts The url or options. * @param progress Progress callback * @returns A {@link StreamLoadOptions} object. * * @hidden */ static loadStream(options: LoadOptions, progress?: ProgressCallback): Promise<StreamLoadOptions>; /** * Validate the in-memory load options. * * @param options Options to validate. * @returns Validated options object. * * @hidden */ static validateBufferOptions(options: InMemoryLoadOptions): { buffer: ArrayBuffer; baseURL: string; url: string; }; /** * Validate the stream load options. * * @param options Options to validate. * @returns Validated options object. * * @hidden */ static validateStreamOptions(options: StreamLoadOptions): { stream: ReadableStream<Uint8Array>; baseURL: string; url: string; }; /** Index in the scene manager. @hidden */ readonly _index: number; /** @hidden */ protected _engine: WonderlandEngine; /** * Component manager caching to avoid GC. * * @hidden */ readonly _components: ComponentManagers; /** * JavaScript components for this scene. * * This array is moved into the WASM instance upon activation. * * @hidden */ readonly _jsComponents: Component[]; /** * The map is indexed using the physx component id. * * @hidden */ readonly _pxCallbacks: Map<number, CollisionCallback[]>; /** @hidden */ private readonly _animations; /** @hidden */ private readonly _animationGraphs; /** @hidden */ private readonly _skins; /** * Object class instances to avoid GC. * * @hidden */ private readonly _objectCache; /** * `onDestroy()` depth. * * Multiple components can stack `onDestroy()` calls. */ private _pendingDestroy; /** * @note This api is meant to be used internally. * * @hidden */ constructor(engine: WonderlandEngine, index: number); /** * Add a new {@link Object3D} to the root object. * * See {@link Object3D.addChild} for more information. * * @returns A new {@link Object3D}. */ addChild(): Object3D; /** * Add an object to the scene. * * Alternatively, you can use {@link Prefab.addChild} to add the object * to the root, or {@link Object3D.addChild} to add the object to a given parent: * * ```js * const parent = scene.addChild(); * const child = parent.addChild(); * // Equivalent using scene.addObject * const sibling = scene.addObject(parent); * ``` * * @param parent Parent object or `null`. * @returns A newly created object. */ addObject(parent?: Object3D | null): Object3D; /** * Batch-add objects to the scene. * * Will provide better performance for adding multiple objects (e.g. > 16) * than calling {@link Scene#addObject} repeatedly in a loop. * * By providing upfront information of how many objects will be required, * the engine is able to batch-allocate the required memory rather than * convervatively grow the memory in small steps. * * @experimental This API might change in upcoming versions. * * @param count Number of objects to add. * @param parent Parent object or `null`, default `null`. * @param componentCountHint Hint for how many components in total will * be added to the created objects afterwards, default `0`. * @returns Newly created objects */ addObjects(count: number, parent?: Object3D | null, componentCountHint?: number): Object3D[]; /** * Pre-allocate memory for a given amount of objects and components. * * Will provide better performance for adding objects later with {@link Scene#addObject} * and {@link Scene#addObjects}. * * By providing upfront information of how many objects will be required, * the engine is able to batch-allocate the required memory rather than * conservatively grow the memory in small steps. * * **Experimental:** This API might change in upcoming versions. * * @param objectCount Number of objects to add. * @param componentCountPerType Amount of components to * allocate for {@link Object3D.addComponent}, e.g. `{mesh: 100, collision: 200, "my-comp": 100}`. * @since 0.8.10 */ reserveObjects(objectCount: number, componentCountPerType: Record<string, number>): void; /** * Root object's children. * * See {@link Object3D.getChildren} for more information. * * @param out Destination array, expected to have at least `this.childrenCount` elements. * @returns The `out` parameter. */ getChildren(out?: Object3D[]): Object3D[]; /** @overload */ getComponents<K extends keyof NativeComponents>(typeOrClass: K): NativeComponents[K][]; /** @overload */ getComponents(typeOrClass: string): Component[]; /** * Get all the components of a given type. * * #### Usage * * ```js * const meshes = scene.getComponents('mesh'); * const zombies = scene.getComponents(ZombieComponent); * ``` * * @param typeOrClass Typename to create a component of. Can be native or * custom JavaScript component type. It's also possible to give a class definition. * In this case, the method will use the `class.TypeName` field. * @returns An array containing all components in this scene. * Returns an empty array if the component isn't registered. */ getComponents<T extends Component>(typeOrClass: ComponentConstructor<T>): T[]; /** @overload */ getActiveComponents<K extends keyof NativeComponents>(typeOrClass: K): NativeComponents[K][]; /** @overload */ getActiveComponents(typeOrClass: string): Component[]; /** * Get all the **active** components of a given type. * * ```js * const zombies = scene.getActiveComponents(ZombieComponent); * for(const zombie of zombies) zombie.active = false; * * const list = scene.getActiveComponents(ZombieComponent); * console.log(list.length); // Prints `0` * ``` * * @param typeOrClass Typename to create a component of. Can be native or * custom JavaScript component type. It's also possible to give a class definition. * In this case, the method will use the `class.TypeName` field. * @returns An array containing all components in this scene. * Returns an empty array if the component isn't registered. */ getActiveComponents<T extends Component>(typeOrClass: ComponentConstructor<T>): T[]; /** * Top-level objects of this scene. * * See {@link Object3D.children} for more information. * * @since 1.2.0 */ get children(): Object3D[]; /** The number of children of the root object. */ get childrenCount(): number; /** * Search for objects matching the name. * * See {@link Object3D.findByName} for more information. * * @param name The name to search for. * @param recursive If `true`, the method will look at all the objects of * this scene. If `false`, this method will only perform the search in * root objects. * @returns An array of {@link Object3D} matching the name. * * @since 1.2.0 */ findByName(name: string, recursive?: boolean): Object3D[]; /** * Search for all **top-level** objects matching the name. * * See {@link Object3D.findByNameDirect} for more information. * * @param name The name to search for. * @returns An array of {@link Object3D} matching the name. * * @since 1.2.0 */ findByNameDirect(name: string): Object3D[]; /** * Search for **all objects** matching the name. * * See {@link Object3D.findByNameRecursive} for more information. * * @param name The name to search for. * @returns An array of {@link Object3D} matching the name. * * @since 1.2.0 */ findByNameRecursive(name: string): Object3D[]; /** * Wrap an object ID using {@link Object}. * * @note This method performs caching and will return the same * instance on subsequent calls. * * @param objectId ID of the object to create. * * @returns The object */ wrap(objectId: number): Object3D; /** * Destroy the scene. * * For now, destroying a scene doesn't remove the resources it references. Thus, * you will need to reload a main scene to free the memory. * * For more information about destruction, have a look at the {@link Scene.destroy} method. */ destroy(): void; /** * Destroy resources based on selected `options`. * * * Destroying loaded resources is achieved using * {@link ResourceManager.loadedFromScene} for each type of resource * * #### Example: Loaded Resources * * Destroy resources loaded alongside this prefab: * * ```ts * // Destroy resources loaded alongside this prefab. * prefab.destroyResources({loaded: true}); * ``` * * @note Resources that are referenced later by the prefab will **not** * be destroyed, e.g., * * ```ts * const prefab = await engine.loadScene('Prefab.bin'); * const overrideMesh = engine.meshes.create({ * vertexCount: 3, * indexData: [0, 1, 2] * }); * for (const component of prefab.getComponents('mesh')) { * component.mesh = overrideMesh; * } * * prefab.destroyResources(); * * // `overrideMesh` wasn't loaded alongside prefab, * // and is thus not destroyed * console.log(overrideMesh.isDestroyed); // 'false' * ``` * * @param options Destroy options. * @since 1.5.0 */ destroyResources(options?: Partial<DestroyResourcesOptions>): void; /** * `true` if the scene is active, `false` otherwise. * * Always false for {@link Prefab} and {@link PrefabGLTF}. */ get isActive(): boolean; /** * Relative directory of the scene that was loaded. * * This is used for loading any files relative to the scene. */ get baseURL(): string; /** * Filename used when loading the file. * * If the scenes was loaded from memory and no filename was provided, * this accessor will return an empty string. */ get filename(): string; /** Animation resources */ get animations(): ResourceManager<Animation>; /** * Animation graph resources. * * See {@link AnimationGraphManager}. * * @since 1.4.6 */ get animationsGraphs(): AnimationGraphManager; /** Skin resources */ get skins(): ResourceManager<Skin>; /** Hosting engine instance. */ get engine(): WonderlandEngine; /** * `true` if the object is destroyed, `false` otherwise. * * If {@link WonderlandEngine.erasePrototypeOnDestroy} is `true`, * reading a class attribute / method will throw. */ get isDestroyed(): boolean; toString(): string; /** * Checks that the input's scene is the same as this instance. * * It is forbidden to mix objects and components from different scenes, e.g., * * ```js * const objA = sceneA.addObject(); * const objB = sceneA.addObject(); * objA.parent = objB; // Throws * ``` * * @param other Object / component to check. * * @throws If other's scene isn't the same reference as this. */ assertOrigin(other: Object3D | Component | SceneResource | undefined | null): void; /** * Download components and initialize the scene. * * @hidden */ _initialize(): void; /** * Perform cleanup upon object destruction. * * @param localId The id to destroy. * * @hidden */ _destroyObject(localId: number): void; /** * Performs JavaScript component creation. * * @param index Component index. * @param id Component id. * @param type Registration index. * @param objectId Owning object id. * * @hidden */ _createComponentJs(index: number, id: number, type: number, objectId: number): void; /** * Performs JavaScript only destrution of a component. * * @note Prefer to use this method to manually calling the destruction code, * to protect the user from illegal method calls in {@link Component.onDestroy}. * * @param manager The component manager index. * @param id The component id. * * @hidden */ _destroyComponent(manager: number, id: number): void; /** * Triggered right after the component is created. * * @hidden */ protected _onComponentCreated(component: Component, type: number): void; /** * Triggered right before the component is destroyed. * * @hidden */ protected _onComponentDestroyed(component: Component): void; }