import type { Material } from "@babylonjs/core/Materials/material";
import type { Mesh } from "@babylonjs/core/Meshes/mesh";
import { Observable } from "@babylonjs/core/Misc/observable";
import type { Scene } from "@babylonjs/core/scene";
import type { Nullable } from "@babylonjs/core/types";
import type { IPlayer } from "../Audio/IAudioPlayer";
import type { IMmdRuntime } from "../IMmdRuntime";
import type { IMmdLinkedBoneContainer } from "../IMmdRuntimeLinkedBone";
import type { MmdCamera } from "../mmdCamera";
import type { MmdSkinnedMesh } from "../mmdMesh";
import type { CreateMmdModelOptions } from "../mmdRuntime";
import type { IMmdPhysics } from "../Physics/IMmdPhysics";
import type { MmdWasmInstance } from "./mmdWasmInstance";
import { MmdWasmModel } from "./mmdWasmModel";
import { WasmSpinlock } from "./wasmSpinlock";
/**
 * MMD WASM runtime animation evaluation type
 */
export declare enum MmdWasmRuntimeAnimationEvaluationType {
    /**
     * Immediate animation evaluation for the current frame
     */
    Immediate = 0,
    /**
     * Buffered animation evaluation for the next frame
     *
     * Asynchronous Multi-thread optimization applies when possible
     *
     * If you are using havok or ammo.js physics, only beforePhysics process is asynchronous
     */
    Buffered = 1
}
/**
 * MMD WASM runtime orchestrates several MMD components (models, camera, audio)
 *
 * MMD WASM runtime handles updates and synchronization of MMD components
 *
 * It can also create and remove runtime components
 */
export declare class MmdWasmRuntime implements IMmdRuntime<MmdWasmModel> {
    /**
     * @internal
     */
    readonly wasmInstance: MmdWasmInstance;
    /**
     * @internal
     */
    readonly wasmInternal: InstanceType<MmdWasmInstance["MmdRuntime"]>;
    /**
     * Spinlock for MMD WASM runtime to synchronize animation evaluation
     * @internal
     */
    readonly lock: WasmSpinlock;
    private _usingWasmBackBuffer;
    private _lastRequestAnimationFrameTime;
    private _needToSyncEvaluate;
    private readonly _mmdMetadataEncoder;
    private readonly _physics;
    private readonly _models;
    private _camera;
    private _audioPlayer;
    private _loggingEnabled;
    /** @internal */
    log: (message: string) => void;
    /** @internal */
    warn: (message: string) => void;
    /** @internal */
    error: (message: string) => void;
    private _isRegistered;
    /**
     * This observable is notified when animation duration is changed
     */
    readonly onAnimationDurationChangedObservable: Observable<void>;
    /**
     * This observable is notified when animation is played
     */
    readonly onPlayAnimationObservable: Observable<void>;
    /**
     * This observable is notified when animation is paused
     */
    readonly onPauseAnimationObservable: Observable<void>;
    /**
     * This observable is notified when animation is seeked
     */
    readonly onSeekAnimationObservable: Observable<void>;
    /**
     * This observable is notified when animation is evaluated (usually every frame)
     */
    readonly onAnimationTickObservable: Observable<void>;
    private _evaluationType;
    private _currentFrameTime;
    private _animationTimeScale;
    private _animationPaused;
    private _animationFrameTimeDuration;
    private _useManualAnimationDuration;
    private readonly _needToInitializePhysicsModels;
    private readonly _needToInitializePhysicsModelsBuffer;
    private _beforePhysicsBinded;
    private readonly _afterPhysicsBinded;
    private readonly _bindedDispose;
    private readonly _disposeObservableObject;
    /**
     * Creates a new MMD web assembly runtime
     *
     * For use external physics engine like ammo.js or havok, you need to set `physics` to instance of `IMmdPhysics`
     * @param wasmInstance MMD WASM instance
     * @param scene Objects that limit the lifetime of this instance
     * @param physics MMD physics
     */
    constructor(wasmInstance: MmdWasmInstance, scene?: Nullable<Scene>, physics?: Nullable<IMmdPhysics>);
    /**
     * Dispose MMD WASM runtime
     *
     * Destroy all MMD models and unregister this runtime from scene
     * @param scene Scene
     */
    dispose(scene: Scene): void;
    /**
     * Create MMD model from mesh that has MMD metadata
     *
     * The skeletons in the mesh where the MmdModel was created no longer follow the usual matrix update policy
     * @param mmdSkinnedMesh MmdSkinnedMesh
     * @param options Creation options
     * @returns MMD model
     * @throws {Error} if mesh is not `MmdSkinnedMesh`
     */
    createMmdModel<TMaterial extends Material>(mmdSkinnedMesh: Mesh, options?: CreateMmdModelOptions<TMaterial>): MmdWasmModel;
    /**
     * Create MMD model from humanoid mesh and virtual skeleton
     *
     * this method is useful for supporting humanoid models, usually used by `HumanoidMmd`
     * @param mmdMesh MmdSkinnedMesh
     * @param skeleton Skeleton or Virtualized skeleton
     * @param options Creation options
     */
    createMmdModelFromSkeleton<TMaterial extends Material>(mmdMesh: MmdSkinnedMesh, skeleton: IMmdLinkedBoneContainer, options?: CreateMmdModelOptions<TMaterial>): MmdWasmModel;
    /**
     * Destroy MMD model
     *
     * Dispose all resources used at MMD runtime and restores the skeleton to the usual matrix update policy
     *
     * After calling the `destroyMmdModel` once, the mesh is no longer able to `createMmdModel` because the metadata is lost
     * @param mmdModel MMD model to destroy
     * @throws {Error} if model is not found
     */
    destroyMmdModel(mmdModel: MmdWasmModel): void;
    /**
     * Set camera to animate
     * @param camera MMD camera
     */
    setCamera(camera: Nullable<MmdCamera>): void;
    private _setAudioPlayerLastValue;
    /**
     * Set audio player to sync with animation
     *
     * If you set up audio Player while playing an animation, it try to play the audio from the current animation time
     * And returns Promise because this operation is asynchronous. In most cases, you don't have to await this Promise
     * @param audioPlayer Audio player
     * @returns Promise
     */
    setAudioPlayer(audioPlayer: Nullable<IPlayer>): Promise<void>;
    /**
     * Register MMD runtime to scene
     *
     * register `beforePhysics` and `afterPhysics` to scene Observables
     *
     * If you need a more complex update method you can call `beforePhysics` and `afterPhysics` manually
     * @param scene Scene
     */
    register(scene: Scene): void;
    /**
     * Unregister MMD runtime from scene
     * @param scene Scene
     */
    unregister(scene: Scene): void;
    /**
     * Before the physics stage, update animations and run MMD runtime solvers
     *
     * @param deltaTime Delta time in milliseconds
     */
    beforePhysics(deltaTime: number): void;
    /**
     * After the physics stage, update physics and run MMD runtime solvers
     */
    afterPhysics(): void;
    private readonly _onAnimationChanged;
    private _computeAnimationDuration;
    private readonly _onAudioDurationChanged;
    private readonly _onAudioPlaybackRateChanged;
    private readonly _onAudioPlay;
    private readonly _onAudioPause;
    private readonly _onAudioSeek;
    private _playAnimationInternal;
    /**
     * Play animation from the current animation time
     *
     * If audio player is set, it try to play the audio from the current animation time
     *
     * It returns Promise because playing audio is asynchronous
     * @returns Promise
     */
    playAnimation(): Promise<void>;
    /**
     * Pause animation
     */
    pauseAnimation(): void;
    private _seekAnimationInternal;
    /**
     * Seek animation to the specified frame time
     *
     * If you set forceEvaluate true, the animation is evaluated even if the animation is not playing
     *
     * If audio player is set and not paused, it try to play the audio from the seek time so it returns Promise
     * @param frameTime Time in 30fps frame
     * @param forceEvaluate Whether to force evaluate animation
     * @returns Promise
     */
    seekAnimation(frameTime: number, forceEvaluate?: boolean): Promise<void>;
    /**
     * Whether animation is playing
     */
    get isAnimationPlaying(): boolean;
    /**
     * MMD models created by this runtime
     */
    get models(): readonly MmdWasmModel[];
    /**
     * MMD camera
     */
    get camera(): Nullable<MmdCamera>;
    /**
     * Audio player
     */
    get audioPlayer(): Nullable<IPlayer>;
    /**
     * Current animation time scale (default: 1)
     */
    get timeScale(): number;
    set timeScale(value: number);
    /**
     * Current animation time in 30fps frame
     */
    get currentFrameTime(): number;
    /**
     * Current animation time in seconds
     */
    get currentTime(): number;
    /**
     * Current animation duration in 30fps frame
     */
    get animationFrameTimeDuration(): number;
    /**
     * Current animation duration in seconds
     */
    get animationDuration(): number;
    /**
     * Set animation duration manually
     *
     * When the difference between the length of the song and the length of the animation is large, it can be helpful to adjust the animation duration manually
     * @param frameTimeDuration Time in 30fps frame
     */
    setManualAnimationDuration(frameTimeDuration: Nullable<number>): void;
    /**
     * Animation evaluation type
     */
    get evaluationType(): MmdWasmRuntimeAnimationEvaluationType;
    set evaluationType(value: MmdWasmRuntimeAnimationEvaluationType);
    /**
     * Enable or disable debug logging (default: false)
     */
    get loggingEnabled(): boolean;
    set loggingEnabled(value: boolean);
    private _logEnabled;
    private _logDisabled;
    private _warnEnabled;
    private _warnDisabled;
    private _errorEnabled;
    private _errorDisabled;
}
