import type { Material } from "@babylonjs/core/Materials/material";
import type { Mesh } from "@babylonjs/core/Meshes/mesh";
import type { MorphTarget } from "@babylonjs/core/Morph/morphTarget";
import type { MorphTargetManager } from "@babylonjs/core/Morph/morphTargetManager";
import type { DeepImmutable, Nullable } from "@babylonjs/core/types";
import type { MmdModelMetadata } from "../Loader/mmdModelMetadata";
import type { Vec3, Vec4 } from "../Loader/Parser/mmdTypes";
import { PmxObject } from "../Loader/Parser/pmxObject";
import type { IMmdMaterialProxyConstructor } from "./IMmdMaterialProxy";
import type { MmdRuntimeBone } from "./mmdRuntimeBone";
/**
 * Represents a material morph element in MMD runtime
 *
 * This information is used to induce material recompilation
 */
export interface RuntimeMaterialMorphElement {
    index: number;
    type: PmxObject.Morph.MaterialMorph.Type;
    diffuse: Nullable<Vec4>;
    specular: Nullable<Vec3>;
    shininess: Nullable<number>;
    ambient: Nullable<Vec3>;
    edgeColor: Nullable<Vec4>;
    edgeSize: Nullable<number>;
    textureColor: Nullable<Vec4>;
    sphereTextureColor: Nullable<Vec4>;
    toonTextureColor: Nullable<Vec4>;
}
/**
 * @internal
 * Represents a morph in MMD runtime
 */
export interface RuntimeMorph {
    readonly name: string;
    readonly type: PmxObject.Morph.Type;
    readonly materialElements: Nullable<readonly RuntimeMaterialMorphElement[]>;
    readonly elements: Nullable<Int32Array | MorphTarget[]>;
    readonly elements2: Nullable<Float32Array>;
    readonly elements3: Nullable<Float32Array>;
}
/**
 * Morph information exposed to the user
 *
 * Only material morphs data are exposed
 */
export interface ReadonlyRuntimeMorph {
    /**
     * Name of the morph
     */
    readonly name: string;
    /**
     * Type of the morph
     */
    readonly type: PmxObject.Morph.Type;
    /**
     * Material morph elements
     */
    readonly materialElements: Nullable<readonly DeepImmutable<RuntimeMaterialMorphElement>[]>;
    /**
     * Group morph / bone morph / uv morph / vertex morph bindings
     */
    readonly elements: Nullable<ArrayLike<number> | readonly MorphTarget[]>;
}
/**
 * The MmdMorphControllerBase uses `MorphTargetManager` to handle position uv morphs, while the material, bone, and group morphs are handled by CPU bound
 *
 * As a result, it reproduces the behavior of the MMD morph system
 */
export declare abstract class MmdMorphControllerBase {
    protected readonly _runtimeBones: readonly MmdRuntimeBone[];
    private readonly _materials;
    protected readonly _morphs: readonly RuntimeMorph[];
    protected readonly _morphIndexMap: Map<string, number[]>;
    protected readonly _morphWeights: Float32Array;
    protected readonly _activeMorphs: Set<string>;
    /**
     * MorphTargetManagers used to handle position uv morphs
     */
    readonly morphTargetManagers: readonly MorphTargetManager[];
    /**
     * Creates a new MmdMorphController
     * @param runtimeBones MMD runtime bones which are original order
     * @param materials MMD materials which are order of mmd metadata
     * @param meshes MMD meshes which are order of mmd metadata
     * @param materialProxyConstructor The constructor of `IMmdMaterialProxy`
     * @param morphsMetadata Morphs metadata
     * @param morphTargetManagers MorphTargetManagers
     * @param logger Logger
     */
    constructor(runtimeBones: Nullable<readonly MmdRuntimeBone[]>, materials: readonly Material[], meshes: readonly Mesh[], materialProxyConstructor: Nullable<IMmdMaterialProxyConstructor<Material>>, morphsMetadata: readonly MmdModelMetadata.Morph[], morphTargetManagers: MorphTargetManager[]);
    /**
     * Sets the weight of the morph
     *
     * If there are multiple morphs with the same name, all of them will be set to the same weight, this is the behavior of MMD
     * @param morphName Name of the morph
     * @param weight Weight of the morph
     */
    abstract setMorphWeight(morphName: string, weight: number): void;
    /**
     * Gets the weight of the morph
     *
     * If there are multiple morphs with the same name, the weight of the first one will be returned
     * @param morphName Name of the morph
     * @returns Weight of the morph
     */
    getMorphWeight(morphName: string): number;
    /**
     * Gets the indices of the morph with the given name
     *
     * The index array is returned because multiple morphs can have the same name
     * @param morphName Name of the morph
     * @returns Indices of the morph
     */
    getMorphIndices(morphName: string): readonly number[] | undefined;
    /**
     * Sets the weight of the morph from the index
     *
     * This method is faster than `setMorphWeight` because it does not need to search the morphs with the given name
     * @param morphIndex Index of the morph
     * @param weight Weight of the morph
     */
    abstract setMorphWeightFromIndex(morphIndex: number, weight: number): void;
    /**
     * Gets the weight of the morph from the index
     * @param morphIndex Index of the morph
     * @returns Weight of the morph
     */
    getMorphWeightFromIndex(morphIndex: number): number;
    /**
     * Gets the weights of all morphs
     * @returns Weights of all morphs
     */
    getMorphWeights(): Readonly<ArrayLike<number>>;
    /**
     * Set the weights of all morphs to 0
     */
    resetMorphWeights(): void;
    private readonly _updatedMaterials;
    /**
     * Apply the morphs to mesh
     */
    update(): void;
    /**
     * Gets the morph data
     */
    get morphs(): readonly ReadonlyRuntimeMorph[];
    private _createRuntimeMorphData;
    private _groupMorphForeach;
    private _resetMorph;
    protected abstract _resetBoneMorph(morph: RuntimeMorph): void;
    private _applyMorph;
    protected abstract _applyBoneMorph(morph: RuntimeMorph, weight: number): void;
    private _applyMaterialMorph;
}
