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;
}
