{"version":3,"file":"effectsMixin.mjs","sources":["../../../../src/scene/container/container-mixins/effectsMixin.ts"],"sourcesContent":["import { FilterEffect } from '../../../filters/FilterEffect';\nimport { MaskEffectManager } from '../../../rendering/mask/MaskEffectManager';\n\nimport type { Filter } from '../../../filters/Filter';\nimport type { Rectangle } from '../../../maths/shapes/Rectangle';\nimport type { MaskEffect } from '../../../rendering/mask/MaskEffectManager';\nimport type { Container } from '../Container';\nimport type { Effect } from '../Effect';\n\n/** @ignore */\nexport interface EffectsMixinConstructor\n{\n    /**\n     * The mask to apply, which can be a Container or null.\n     *\n     * If null, it clears the existing mask.\n     * @example\n     * ```ts\n     * // Set a mask\n     * sprite.setMask({\n     *     mask: graphics,\n     *     inverse: false,\n     * });\n     */\n    mask?: Mask;\n    setMask?: (options: Partial<MaskOptionsAndMask>) => void;\n    /**\n     * Sets the filters for the displayObject.\n     * Filters are visual effects that can be applied to any display object and its children.\n     *\n     * > [!IMPORTANT] This is a WebGL/WebGPU only feature and will be ignored by the canvas renderer.\n     * @example\n     * ```ts\n     * new Container({\n     *     filters: [new BlurFilter(2), new ColorMatrixFilter()],\n     * });\n     * ```\n     * @see {@link Filter} For filter base class\n     */\n    filters?: Filter | readonly Filter[];\n}\n\n/**\n * The Mask type represents different ways to mask a display object.\n * - A number represents a mask ID.\n * - A Container represents a mask object, such as a Graphics or Sprite.\n * - null indicates that no mask is applied.\n * @example\n * ```ts\n * // Using a Container as a mask\n * const maskContainer: Mask = new Graphics();\n * // Using a mask ID\n * const maskId: Mask = 123;\n * // No mask applied\n * const noMask: Mask = null;\n * ```\n * @category scene\n * @standard\n */\nexport type Mask = number | Container | null;\n\n/**\n * Options for configuring mask behavior on a display object.\n * @example\n * ```ts\n * // Basic mask inversion\n * sprite.setMask({\n *     mask: graphics,\n *     inverse: true\n * });\n * ```\n * @see {@link Container#setMask} For applying masks with options\n * @see {@link Container#mask} For basic masking\n * @category scene\n * @standard\n */\nexport interface MaskOptions\n{\n    /**\n     * Whether the mask should be inverted.\n     * When true, the masked area becomes transparent and the unmasked area becomes visible.\n     * @default false\n     * @example\n     * ```ts\n     * // Invert the mask\n     * sprite.setMask({\n     *     mask: graphics,\n     *     inverse: true\n     * });\n     * ```\n     */\n    inverse: boolean;\n}\n\n/**\n * MaskOptionsAndMask combines MaskOptions with a Mask for configuring masking behavior.\n * Used when setting up complex masking effects with additional options.\n * @example\n * ```ts\n * sprite.setMask({\n *     mask: graphics,\n *     inverse: true,\n * });\n *\n * // Clear existing mask\n * sprite.setMask({\n *     mask: null,\n *     inverse: false,\n * });\n * ```\n * @category scene\n * @standard\n * @see {@link Container#setMask} For applying masks\n * @see {@link MaskOptions} For base options\n */\nexport interface MaskOptionsAndMask extends MaskOptions\n{\n    /**\n     * The mask to apply, which can be a Container or null.\n     *\n     * If null, it clears the existing mask.\n     * @example\n     * ```ts\n     * // Set a mask\n     * sprite.setMask({\n     *     mask: graphics,\n     *     inverse: false,\n     * });\n     */\n    mask: Mask;\n}\n\n/**\n * The EffectsMixin interface provides methods and properties for managing effects\n * such as masks and filters on a display object.\n * It allows for adding, removing, and configuring effects, as well as setting a mask for the display object.\n * @category scene\n * @advanced\n */\nexport interface EffectsMixin extends Required<EffectsMixinConstructor>\n{\n    /** @private */\n    _maskEffect?: MaskEffect;\n    /** @private */\n    _maskOptions?: MaskOptions;\n    /** @private */\n    _filterEffect?: FilterEffect,\n    /** @private */\n    _markStructureAsChanged(): void;\n\n    /**\n     * The area the filter is applied to. This is used as an optimization to define a specific region\n     * for filter effects instead of calculating the display object bounds each frame.\n     *\n     * > [!NOTE]\n     * > Setting this to a custom Rectangle allows you to define a specific area for filter effects,\n     * > which can improve performance by avoiding expensive bounds calculations.\n     * @example\n     * ```ts\n     * // Set specific filter area\n     * container.filterArea = new Rectangle(0, 0, 100, 100);\n     *\n     * // Optimize filter region\n     * const screen = app.screen;\n     * container.filterArea = new Rectangle(\n     *     screen.x,\n     *     screen.y,\n     *     screen.width,\n     *     screen.height\n     * );\n     * ```\n     * @see {@link Container#filters} For applying filters\n     * @see {@link Rectangle} For area definition\n     */\n    filterArea?: Rectangle,\n    /**\n     * todo Needs docs\n     * @advanced\n     */\n    effects?: Effect[];\n    /**\n     * todo Needs docs.\n     * @param {Effect} effect - The effect to add.\n     * @ignore\n     */\n    addEffect(effect: Effect): void;\n    /**\n     * todo Needs docs.\n     * @param {Effect} effect - The effect to remove.\n     * @ignore\n     */\n    removeEffect(effect: Effect): void;\n    /**\n     * Used to set mask and control mask options on a display object.\n     * Allows for more detailed control over masking behavior compared to the mask property.\n     * @example\n     * ```ts\n     * import { Graphics, Sprite } from 'pixi.js';\n     *\n     * // Create a circular mask\n     * const graphics = new Graphics()\n     *     .beginFill(0xFF3300)\n     *     .drawCircle(100, 100, 50)\n     *     .endFill();\n     *\n     * // Apply mask with options\n     * sprite.setMask({\n     *     mask: graphics,\n     *     inverse: true, // Create a hole effect\n     * });\n     *\n     * // Clear existing mask\n     * sprite.setMask({ mask: null });\n     * ```\n     * @param {Partial<MaskOptionsAndMask>} options - Configuration options for the mask\n     * @see {@link Container#mask} For simple masking\n     * @see {@link MaskOptionsAndMask} For full options API\n     */\n    setMask(options: Partial<MaskOptionsAndMask>): void;\n    /**\n     * Sets a mask for the displayObject. A mask is an object that limits the visibility of an\n     * object to the shape of the mask applied to it.\n     *\n     * > [!IMPORTANT] In PixiJS a regular mask must be a {@link Graphics} or a {@link Sprite} object.\n     * > This allows for much faster masking in canvas as it utilities shape clipping.\n     * > Furthermore, a mask of an object must be in the subtree of its parent.\n     * > Otherwise, `getLocalBounds` may calculate incorrect bounds, which makes the container's width and height wrong.\n     *\n     * For sprite mask both alpha and red channel are used. Black mask is the same as transparent mask.\n     * @example\n     * ```ts\n     * // Apply mask to sprite\n     * const sprite = new Sprite(texture);\n     * sprite.mask = graphics;\n     *\n     * // Remove mask\n     * sprite.mask = null;\n     * ```\n     * @see {@link Graphics} For creating mask shapes\n     * @see {@link Sprite} For texture-based masks\n     * @see {@link Container#setMask} For advanced mask options\n     */\n    mask: Mask;\n    /**\n     * Sets the filters for the displayObject.\n     * Filters are visual effects that can be applied to any display object and its children.\n     *\n     * > [!IMPORTANT] This is a WebGL/WebGPU only feature and will be ignored by the canvas renderer.\n     * @example\n     * ```ts\n     * // Add a single filter\n     * sprite.filters = new BlurFilter(2);\n     *\n     * // Apply multiple filters\n     * container.filters = [\n     *     new BlurFilter(2),\n     *     new ColorMatrixFilter(),\n     * ];\n     *\n     * // Remove filters\n     * sprite.filters = null;\n     * ```\n     * @see {@link Filter} For filter base class\n     */\n    set filters(value: Filter | Filter[] | null | undefined);\n    get filters(): readonly Filter[];\n}\n\n/** @internal */\nexport const effectsMixin: Partial<Container> = {\n    _maskEffect: null,\n    _maskOptions: {\n        inverse: false,\n    },\n    _filterEffect: null,\n\n    effects: [],\n\n    _markStructureAsChanged()\n    {\n        const renderGroup = this.renderGroup || this.parentRenderGroup;\n\n        if (renderGroup)\n        {\n            renderGroup.structureDidChange = true;\n        }\n    },\n\n    addEffect(effect: Effect)\n    {\n        const index = this.effects.indexOf(effect);\n\n        if (index !== -1) return; // already exists!\n\n        this.effects.push(effect);\n\n        this.effects.sort((a, b) => a.priority - b.priority);\n\n        this._markStructureAsChanged();\n\n        // if (this.renderGroup)\n        // {\n        //     this.renderGroup.structureDidChange = true;\n        // }\n\n        this._updateIsSimple();\n    },\n\n    removeEffect(effect: Effect)\n    {\n        const index = this.effects.indexOf(effect);\n\n        if (index === -1) return; // already exists!\n\n        this.effects.splice(index, 1);\n\n        this._markStructureAsChanged();\n\n        this._updateIsSimple();\n    },\n\n    set mask(value: Mask)\n    {\n        const effect = this._maskEffect;\n\n        if (effect?.mask === value) return;\n\n        if (effect)\n        {\n            this.removeEffect(effect);\n\n            MaskEffectManager.returnMaskEffect(effect);\n\n            this._maskEffect = null;\n        }\n\n        if (value === null || value === undefined) return;\n\n        this._maskEffect = MaskEffectManager.getMaskEffect(value);\n\n        this.addEffect(this._maskEffect);\n    },\n    get mask(): unknown\n    {\n        return this._maskEffect?.mask;\n    },\n\n    setMask(options: Partial<MaskOptionsAndMask>)\n    {\n        this._maskOptions = {\n            ...this._maskOptions,\n            ...options,\n        };\n\n        if (options.mask)\n        {\n            this.mask = options.mask;\n        }\n\n        this._markStructureAsChanged();\n    },\n\n    set filters(value: Filter | readonly Filter[] | null | undefined)\n    {\n        if (!Array.isArray(value) && value) value = ([value] as Filter[]);\n\n        const effect = this._filterEffect ||= new FilterEffect();\n\n        // Ignore the Filter type\n        value = value as Filter[] | null | undefined;\n\n        const hasFilters = value?.length > 0;\n        const hadFilters = effect.filters?.length > 0;\n\n        const didChange = hasFilters !== hadFilters;\n\n        // Clone the filters array so we don't freeze the user-input\n        value = Array.isArray(value) ? value.slice(0) : value;\n\n        // Ensure filters are immutable via filters getter\n        effect.filters = Object.freeze(value);\n\n        if (didChange)\n        {\n            if (hasFilters)\n            {\n                this.addEffect(effect);\n            }\n            else\n            {\n                this.removeEffect(effect);\n\n                // sets the empty array...\n                effect.filters = value ?? null;\n            }\n        }\n    },\n    get filters(): readonly Filter[]\n    {\n        return this._filterEffect?.filters;\n    },\n\n    set filterArea(value: Rectangle)\n    {\n        this._filterEffect ||= new FilterEffect();\n\n        this._filterEffect.filterArea = value;\n    },\n    get filterArea(): Rectangle\n    {\n        return this._filterEffect?.filterArea;\n    },\n\n} as Container;\n"],"names":[],"mappings":"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"}