{"version":3,"file":"filter-glitch.mjs","sources":["../src/GlitchFilter.ts"],"sourcesContent":["import { vertex } from '@tools/fragments';\nimport fragment from './glitch.frag';\nimport { Filter, Texture, SCALE_MODES, DEG_TO_RAD, Rectangle } from '@pixi/core';\nimport type { IPoint, CLEAR_MODES, FilterSystem, RenderTexture } from '@pixi/core';\n\ntype PointLike = IPoint | number[];\n\ninterface GlitchFilterOptions\n{\n    slices: number;\n    offset: number;\n    direction: number;\n    fillMode: number;\n    seed: number;\n    average: boolean;\n    minSize: number;\n    sampleSize: number;\n    red: PointLike;\n    green: PointLike;\n    blue: PointLike;\n}\n\n/**\n * The GlitchFilter applies a glitch effect to an object.<br>\n * ![original](../tools/screenshots/dist/original.png)![filter](../tools/screenshots/dist/glitch.png)\n *\n * @class\n * @extends PIXI.Filter\n * @see {@link https://www.npmjs.com/package/@pixi/filter-glitch|@pixi/filter-glitch}\n * @see {@link https://www.npmjs.com/package/pixi-filters|pixi-filters}\n */\nclass GlitchFilter extends Filter\n{\n    /** Default constructor options. */\n    public static readonly defaults: GlitchFilterOptions = {\n        slices: 5,\n        offset: 100,\n        direction: 0,\n        fillMode: 0,\n        average: false,\n        seed: 0,\n        red: [0, 0],\n        green: [0, 0],\n        blue: [0, 0],\n        minSize: 8,\n        sampleSize: 512,\n    };\n\n    /** Fill mode as transparent */\n    static readonly TRANSPARENT = 0;\n\n    /** Fill mode as original */\n    static readonly ORIGINAL = 1;\n\n    /** Fill mode as loop */\n    static readonly LOOP = 2;\n\n    /** Fill mode as clamp */\n    static readonly CLAMP = 3;\n\n    /** Fill mode as mirror */\n    static readonly MIRROR = 4;\n\n    /** The maximum offset value for each of the slices. */\n    public offset = 100;\n\n    /** The fill mode of the space after the offset. */\n    public fillMode: number = GlitchFilter.TRANSPARENT;\n\n    /**\n     * `true` will divide the bands roughly based on equal amounts\n     * where as setting to `false` will vary the band sizes dramatically (more random looking).\n     */\n    public average = false;\n\n    /**\n     * A seed value for randomizing color offset. Animating\n     * this value to `Math.random()` produces a twitching effect.\n     */\n    public seed = 0;\n\n    /** Minimum size of slices as a portion of the `sampleSize` */\n    public minSize = 8;\n\n    /** Height of the displacement map canvas. */\n    public sampleSize = 512;\n\n    /** Internally generated canvas. */\n    private _canvas: HTMLCanvasElement;\n\n    /**\n     * The displacement map is used to generate the bands.\n     * If using your own texture, `slices` will be ignored.\n     *\n     * @member {PIXI.Texture}\n     * @readonly\n     */\n    public texture: Texture;\n\n    /** Internal number of slices */\n    private _slices = 0;\n\n    private _offsets: Float32Array = new Float32Array(1);\n    private _sizes: Float32Array = new Float32Array(1);\n\n    /** direction is actually a setter for uniform.cosDir and uniform.sinDir.\n     * Must be initialized to something different than the default value.\n    */\n    private _direction = -1;\n\n    /**\n     * @param {object} [options] - The more optional parameters of the filter.\n     * @param {number} [options.slices=5] - The maximum number of slices.\n     * @param {number} [options.offset=100] - The maximum offset amount of slices.\n     * @param {number} [options.direction=0] - The angle in degree of the offset of slices.\n     * @param {number} [options.fillMode=0] - The fill mode of the space after the offset. Acceptable values:\n     *  - `0` {@link GlitchFilter.TRANSPARENT TRANSPARENT}\n     *  - `1` {@link GlitchFilter.ORIGINAL ORIGINAL}\n     *  - `2` {@link GlitchFilter.LOOP LOOP}\n     *  - `3` {@link GlitchFilter.CLAMP CLAMP}\n     *  - `4` {@link GlitchFilter.MIRROR MIRROR}\n     * @param {number} [options.seed=0] - A seed value for randomizing glitch effect.\n     * @param {boolean} [options.average=false] - `true` will divide the bands roughly based on equal amounts\n     *                 where as setting to `false` will vary the band sizes dramatically (more random looking).\n     * @param {number} [options.minSize=8] - Minimum size of individual slice. Segment of total `sampleSize`\n     * @param {number} [options.sampleSize=512] - The resolution of the displacement map texture.\n     * @param {number[]} [options.red=[0,0]] - Red channel offset\n     * @param {number[]} [options.green=[0,0]] - Green channel offset.\n     * @param {number[]} [options.blue=[0,0]] - Blue channel offset.\n     */\n    constructor(options?: Partial<GlitchFilterOptions>)\n    {\n        super(vertex, fragment);\n        this.uniforms.dimensions = new Float32Array(2);\n\n        this._canvas = document.createElement('canvas');\n        this._canvas.width = 4;\n        this._canvas.height = this.sampleSize;\n        this.texture = Texture.from(this._canvas, { scaleMode: SCALE_MODES.NEAREST });\n\n        Object.assign(this, GlitchFilter.defaults, options);\n    }\n\n    /**\n     * Override existing apply method in PIXI.Filter\n     * @private\n     */\n    apply(filterManager: FilterSystem, input: RenderTexture, output: RenderTexture, clear: CLEAR_MODES): void\n    {\n        const { width, height } = input.filterFrame as Rectangle;\n\n        this.uniforms.dimensions[0] = width;\n        this.uniforms.dimensions[1] = height;\n        this.uniforms.aspect = height / width;\n\n        this.uniforms.seed = this.seed;\n        this.uniforms.offset = this.offset;\n        this.uniforms.fillMode = this.fillMode;\n\n        filterManager.applyFilter(this, input, output, clear);\n    }\n\n    /**\n     * Randomize the slices size (heights).\n     *\n     * @private\n     */\n    private _randomizeSizes()\n    {\n        const arr = this._sizes;\n        const last = this._slices - 1;\n        const size = this.sampleSize;\n        const min = Math.min(this.minSize / size, 0.9 / this._slices);\n\n        if (this.average)\n        {\n            const count = this._slices;\n            let rest = 1;\n\n            for (let i = 0; i < last; i++)\n            {\n                const averageWidth = rest / (count - i);\n                const w =  Math.max(averageWidth * (1 - (Math.random() * 0.6)), min);\n\n                arr[i] = w;\n                rest -= w;\n            }\n            arr[last] = rest;\n        }\n        else\n        {\n            let rest = 1;\n            const ratio = Math.sqrt(1 / this._slices);\n\n            for (let i = 0; i < last; i++)\n            {\n                const w = Math.max(ratio * rest * Math.random(), min);\n\n                arr[i] = w;\n                rest -= w;\n            }\n            arr[last] = rest;\n        }\n\n        this.shuffle();\n    }\n\n    /**\n     * Shuffle the sizes of the slices, advanced usage.\n     */\n    shuffle(): void\n    {\n        const arr = this._sizes;\n        const last = this._slices - 1;\n\n        // shuffle\n        for (let i = last; i > 0; i--)\n        {\n            const rand = (Math.random() * i) >> 0;\n            const temp = arr[i];\n\n            arr[i] = arr[rand];\n            arr[rand] = temp;\n        }\n    }\n\n    /**\n     * Randomize the values for offset from -1 to 1\n     *\n     * @private\n     */\n    private _randomizeOffsets(): void\n    {\n        for (let i = 0; i < this._slices; i++)\n        {\n            this._offsets[i] = Math.random() * (Math.random() < 0.5 ? -1 : 1);\n        }\n    }\n\n    /**\n     * Regenerating random size, offsets for slices.\n     */\n    refresh(): void\n    {\n        this._randomizeSizes();\n        this._randomizeOffsets();\n        this.redraw();\n    }\n\n    /**\n     * Redraw displacement bitmap texture, advanced usage.\n     */\n    redraw(): void\n    {\n        const size = this.sampleSize;\n        const texture = this.texture;\n        const ctx = this._canvas.getContext('2d') as CanvasRenderingContext2D;\n\n        ctx.clearRect(0, 0, 8, size);\n\n        let offset;\n        let y = 0;\n\n        for (let i = 0; i < this._slices; i++)\n        {\n            offset = Math.floor(this._offsets[i] * 256);\n            const height = this._sizes[i] * size;\n            const red = offset > 0 ? offset : 0;\n            const green = offset < 0 ? -offset : 0;\n\n            ctx.fillStyle = `rgba(${red}, ${green}, 0, 1)`;\n            ctx.fillRect(0, y >> 0, size, height + 1 >> 0);\n            y += height;\n        }\n\n        texture.baseTexture.update();\n        this.uniforms.displacementMap = texture;\n    }\n\n    /**\n     * Manually custom slices size (height) of displacement bitmap\n     *\n     * @member {number[]|Float32Array}\n     */\n    set sizes(sizes: Float32Array)\n    {\n        const len = Math.min(this._slices, sizes.length);\n\n        for (let i = 0; i < len; i++)\n        {\n            this._sizes[i] = sizes[i];\n        }\n    }\n    get sizes(): Float32Array\n    {\n        return this._sizes;\n    }\n\n    /**\n     * Manually set custom slices offset of displacement bitmap, this is\n     * a collection of values from -1 to 1. To change the max offset value\n     * set `offset`.\n     *\n     * @member {number[]|Float32Array}\n     */\n    set offsets(offsets: Float32Array)\n    {\n        const len = Math.min(this._slices, offsets.length);\n\n        for (let i = 0; i < len; i++)\n        {\n            this._offsets[i] = offsets[i];\n        }\n    }\n    get offsets(): Float32Array\n    {\n        return this._offsets;\n    }\n\n    /**\n     * The count of slices.\n     * @default 5\n     */\n    get slices(): number\n    {\n        return this._slices;\n    }\n    set slices(value: number)\n    {\n        if (this._slices === value)\n        {\n            return;\n        }\n        this._slices = value;\n        this.uniforms.slices = value;\n        this._sizes = this.uniforms.slicesWidth = new Float32Array(value);\n        this._offsets = this.uniforms.slicesOffset = new Float32Array(value);\n        this.refresh();\n    }\n\n    /**\n     * The angle in degree of the offset of slices.\n     * @default 0\n     */\n    get direction(): number\n    {\n        return this._direction;\n    }\n    set direction(value: number)\n    {\n        if (this._direction === value)\n        {\n            return;\n        }\n        this._direction = value;\n\n        const radians = value * DEG_TO_RAD;\n\n        this.uniforms.sinDir = Math.sin(radians);\n        this.uniforms.cosDir = Math.cos(radians);\n    }\n\n    /**\n     * Red channel offset.\n     *\n     * @member {PIXI.Point|number[]}\n     */\n    get red(): PointLike\n    {\n        return this.uniforms.red;\n    }\n    set red(value: PointLike)\n    {\n        this.uniforms.red = value;\n    }\n\n    /**\n     * Green channel offset.\n     *\n     * @member {PIXI.Point|number[]}\n     */\n    get green(): PointLike\n    {\n        return this.uniforms.green;\n    }\n    set green(value: PointLike)\n    {\n        this.uniforms.green = value;\n    }\n\n    /**\n     * Blue offset.\n     *\n     * @member {PIXI.Point|number[]}\n     */\n    get blue(): PointLike\n    {\n        return this.uniforms.blue;\n    }\n    set blue(value: PointLike)\n    {\n        this.uniforms.blue = value;\n    }\n\n    /**\n     * Removes all references\n     */\n    destroy(): void\n    {\n        this.texture?.destroy(true);\n        this.texture\n        = this._canvas\n        = this.red\n        = this.green\n        = this.blue\n        = this._sizes\n        = this._offsets = null as any;\n    }\n}\n\nexport { GlitchFilter };\nexport type { GlitchFilterOptions };\n"],"names":["_GlitchFilter","Filter","options","vertex","fragment","Texture","SCALE_MODES","filterManager","input","output","clear","width","height","arr","last","size","min","count","rest","i","averageWidth","w","ratio","rand","temp","texture","ctx","offset","y","red","green","sizes","len","offsets","value","radians","DEG_TO_RAD","_a","GlitchFilter"],"mappings":"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"}