{"version":3,"file":"ScissorSystem.mjs","sources":["../../src/mask/ScissorSystem.ts"],"sourcesContent":["import { extensions, ExtensionType } from 'pixijs/extensions';\nimport { Matrix, Rectangle } from 'pixijs/math';\nimport { settings } from 'pixijs/settings';\nimport { AbstractMaskSystem } from './AbstractMaskSystem';\n\nimport type { ExtensionMetadata } from 'pixijs/extensions';\nimport type { Renderer } from '../Renderer';\nimport type { MaskData } from './MaskData';\n\nconst tempMatrix = new Matrix();\nconst rectPool: Rectangle[] = [];\n\n/**\n * System plugin to the renderer to manage scissor masking.\n *\n * Scissor masking discards pixels outside of a rectangle called the scissor box. The scissor box is in the framebuffer\n * viewport's space; however, the mask's rectangle is projected from world-space to viewport space automatically\n * by this system.\n * @memberof PIXI\n */\nexport class ScissorSystem extends AbstractMaskSystem\n{\n    /** @ignore */\n    static extension: ExtensionMetadata = {\n        type: ExtensionType.RendererSystem,\n        name: 'scissor',\n    };\n\n    /**\n     * @param {PIXI.Renderer} renderer - The renderer this System works for.\n     */\n    constructor(renderer: Renderer)\n    {\n        super(renderer);\n\n        this.glConst = settings.ADAPTER.getWebGLRenderingContext().SCISSOR_TEST;\n    }\n\n    getStackLength(): number\n    {\n        const maskData = this.maskStack[this.maskStack.length - 1];\n\n        if (maskData)\n        {\n            return maskData._scissorCounter;\n        }\n\n        return 0;\n    }\n\n    /**\n     * evaluates _boundsTransformed, _scissorRect for MaskData\n     * @param maskData\n     */\n    calcScissorRect(maskData: MaskData): void\n    {\n        if (maskData._scissorRectLocal)\n        {\n            return;\n        }\n\n        const prevData = maskData._scissorRect;\n        const { maskObject } = maskData;\n        const { renderer } = this;\n        const renderTextureSystem = renderer.renderTexture;\n        const rect = maskObject.getBounds(true, rectPool.pop() ?? new Rectangle());\n\n        this.roundFrameToPixels(rect,\n            renderTextureSystem.current ? renderTextureSystem.current.resolution : renderer.resolution,\n            renderTextureSystem.sourceFrame,\n            renderTextureSystem.destinationFrame,\n            renderer.projection.transform);\n\n        if (prevData)\n        {\n            rect.fit(prevData);\n        }\n        maskData._scissorRectLocal = rect;\n    }\n\n    private static isMatrixRotated(matrix: Matrix)\n    {\n        if (!matrix)\n        {\n            return false;\n        }\n        const { a, b, c, d } = matrix;\n\n        // Skip if skew/rotation present in matrix, except for multiple of 90° rotation. If rotation\n        // is a multiple of 90°, then either pair of (b,c) or (a,d) will be (0,0).\n        return ((Math.abs(b) > 1e-4 || Math.abs(c) > 1e-4)\n            && (Math.abs(a) > 1e-4 || Math.abs(d) > 1e-4));\n    }\n\n    /**\n     * Test, whether the object can be scissor mask with current renderer projection.\n     * Calls \"calcScissorRect()\" if its true.\n     * @param maskData - mask data\n     * @returns whether Whether the object can be scissor mask\n     */\n    public testScissor(maskData: MaskData): boolean\n    {\n        const { maskObject } = maskData;\n\n        if (!maskObject.isFastRect || !maskObject.isFastRect())\n        {\n            return false;\n        }\n        if (ScissorSystem.isMatrixRotated(maskObject.worldTransform))\n        {\n            return false;\n        }\n        if (ScissorSystem.isMatrixRotated(this.renderer.projection.transform))\n        {\n            return false;\n        }\n\n        this.calcScissorRect(maskData);\n\n        const rect = maskData._scissorRectLocal;\n\n        return rect.width > 0 && rect.height > 0;\n    }\n\n    private roundFrameToPixels(\n        frame: Rectangle,\n        resolution: number,\n        bindingSourceFrame: Rectangle,\n        bindingDestinationFrame: Rectangle,\n        transform?: Matrix,\n    )\n    {\n        if (ScissorSystem.isMatrixRotated(transform))\n        {\n            return;\n        }\n\n        transform = transform ? tempMatrix.copyFrom(transform) : tempMatrix.identity();\n\n        // Get forward transform from world space to screen space\n        transform\n            .translate(-bindingSourceFrame.x, -bindingSourceFrame.y)\n            .scale(\n                bindingDestinationFrame.width / bindingSourceFrame.width,\n                bindingDestinationFrame.height / bindingSourceFrame.height)\n            .translate(bindingDestinationFrame.x, bindingDestinationFrame.y);\n\n        // Convert frame to screen space\n        (this.renderer.filter as any).transformAABB(transform, frame);\n\n        frame.fit(bindingDestinationFrame);\n        frame.x = Math.round(frame.x * resolution);\n        frame.y = Math.round(frame.y * resolution);\n        frame.width = Math.round(frame.width * resolution);\n        frame.height = Math.round(frame.height * resolution);\n    }\n\n    /**\n     * Applies the Mask and adds it to the current stencil stack.\n     * @author alvin\n     * @param maskData - The mask data.\n     */\n    push(maskData: MaskData): void\n    {\n        if (!maskData._scissorRectLocal)\n        {\n            this.calcScissorRect(maskData);\n        }\n\n        const { gl } = this.renderer;\n\n        if (!maskData._scissorRect)\n        {\n            gl.enable(gl.SCISSOR_TEST);\n        }\n\n        maskData._scissorCounter++;\n        maskData._scissorRect = maskData._scissorRectLocal;\n        this._useCurrent();\n    }\n\n    /**\n     * This should be called after a mask is popped off the mask stack. It will rebind the scissor box to be latest with the\n     * last mask in the stack.\n     *\n     * This can also be called when you directly modify the scissor box and want to restore PixiJS state.\n     * @param maskData - The mask data.\n     */\n    pop(maskData?: MaskData): void\n    {\n        const { gl } = this.renderer;\n\n        if (maskData)\n        {\n            rectPool.push(maskData._scissorRectLocal);\n        }\n\n        if (this.getStackLength() > 0)\n        {\n            this._useCurrent();\n        }\n        else\n        {\n            gl.disable(gl.SCISSOR_TEST);\n        }\n    }\n\n    /**\n     * Setup renderer to use the current scissor data.\n     * @private\n     */\n    _useCurrent(): void\n    {\n        const rect = this.maskStack[this.maskStack.length - 1]._scissorRect;\n        let y: number;\n\n        if (this.renderer.renderTexture.current)\n        {\n            y = rect.y;\n        }\n        else\n        {\n            // flipY. In future we'll have it over renderTextures as an option\n            y = this.renderer.height - rect.height - rect.y;\n        }\n\n        this.renderer.gl.scissor(rect.x, y, rect.width, rect.height);\n    }\n}\n\nextensions.add(ScissorSystem);\n"],"names":[],"mappings":";;;;;AASA,MAAM,UAAA,GAAa,IAAI,MAAO,EAAA,CAAA;AAC9B,MAAM,WAAwB,EAAC,CAAA;AAUxB,MAAM,cAAA,GAAN,cAA4B,kBACnC,CAAA;AAAA,EAUI,YAAY,QACZ,EAAA;AACI,IAAA,KAAA,CAAM,QAAQ,CAAA,CAAA;AAEd,IAAA,IAAA,CAAK,OAAU,GAAA,QAAA,CAAS,OAAQ,CAAA,wBAAA,EAA2B,CAAA,YAAA,CAAA;AAAA,GAC/D;AAAA,EAEA,cACA,GAAA;AACI,IAAA,MAAM,QAAW,GAAA,IAAA,CAAK,SAAU,CAAA,IAAA,CAAK,UAAU,MAAS,GAAA,CAAA,CAAA,CAAA;AAExD,IAAA,IAAI,QACJ,EAAA;AACI,MAAA,OAAO,QAAS,CAAA,eAAA,CAAA;AAAA,KACpB;AAEA,IAAO,OAAA,CAAA,CAAA;AAAA,GACX;AAAA,EAMA,gBAAgB,QAChB,EAAA;AACI,IAAA,IAAI,SAAS,iBACb,EAAA;AACI,MAAA,OAAA;AAAA,KACJ;AAEA,IAAA,MAAM,WAAW,QAAS,CAAA,YAAA,CAAA;AAC1B,IAAA,MAAM,EAAE,UAAe,EAAA,GAAA,QAAA,CAAA;AACvB,IAAA,MAAM,EAAE,QAAa,EAAA,GAAA,IAAA,CAAA;AACrB,IAAA,MAAM,sBAAsB,QAAS,CAAA,aAAA,CAAA;AACrC,IAAM,MAAA,IAAA,GAAO,WAAW,SAAU,CAAA,IAAA,EAAM,SAAS,GAAI,EAAA,IAAK,IAAI,SAAA,EAAW,CAAA,CAAA;AAEzE,IAAA,IAAA,CAAK,kBAAmB,CAAA,IAAA,EACpB,mBAAoB,CAAA,OAAA,GAAU,oBAAoB,OAAQ,CAAA,UAAA,GAAa,QAAS,CAAA,UAAA,EAChF,oBAAoB,WACpB,EAAA,mBAAA,CAAoB,gBACpB,EAAA,QAAA,CAAS,WAAW,SAAS,CAAA,CAAA;AAEjC,IAAA,IAAI,QACJ,EAAA;AACI,MAAA,IAAA,CAAK,IAAI,QAAQ,CAAA,CAAA;AAAA,KACrB;AACA,IAAA,QAAA,CAAS,iBAAoB,GAAA,IAAA,CAAA;AAAA,GACjC;AAAA,EAEA,OAAe,gBAAgB,MAC/B,EAAA;AACI,IAAA,IAAI,CAAC,MACL,EAAA;AACI,MAAO,OAAA,KAAA,CAAA;AAAA,KACX;AACA,IAAA,MAAM,EAAE,CAAA,EAAG,CAAG,EAAA,CAAA,EAAG,CAAM,EAAA,GAAA,MAAA,CAAA;AAIvB,IAAA,OAAS,MAAK,GAAI,CAAA,CAAC,IAAI,IAAQ,IAAA,IAAA,CAAK,IAAI,CAAC,CAAA,GAAI,IACrC,MAAA,IAAA,CAAK,IAAI,CAAC,CAAA,GAAI,QAAQ,IAAK,CAAA,GAAA,CAAI,CAAC,CAAI,GAAA,IAAA,CAAA,CAAA;AAAA,GAChD;AAAA,EAQO,YAAY,QACnB,EAAA;AACI,IAAA,MAAM,EAAE,UAAe,EAAA,GAAA,QAAA,CAAA;AAEvB,IAAA,IAAI,CAAC,UAAW,CAAA,UAAA,IAAc,CAAC,UAAA,CAAW,YAC1C,EAAA;AACI,MAAO,OAAA,KAAA,CAAA;AAAA,KACX;AACA,IAAA,IAAI,cAAc,CAAA,eAAA,CAAgB,UAAW,CAAA,cAAc,CAC3D,EAAA;AACI,MAAO,OAAA,KAAA,CAAA;AAAA,KACX;AACA,IAAA,IAAI,eAAc,eAAgB,CAAA,IAAA,CAAK,QAAS,CAAA,UAAA,CAAW,SAAS,CACpE,EAAA;AACI,MAAO,OAAA,KAAA,CAAA;AAAA,KACX;AAEA,IAAA,IAAA,CAAK,gBAAgB,QAAQ,CAAA,CAAA;AAE7B,IAAA,MAAM,OAAO,QAAS,CAAA,iBAAA,CAAA;AAEtB,IAAA,OAAO,IAAK,CAAA,KAAA,GAAQ,CAAK,IAAA,IAAA,CAAK,MAAS,GAAA,CAAA,CAAA;AAAA,GAC3C;AAAA,EAEA,kBACI,CAAA,KAAA,EACA,UACA,EAAA,kBAAA,EACA,yBACA,SAEJ,EAAA;AACI,IAAI,IAAA,cAAA,CAAc,eAAgB,CAAA,SAAS,CAC3C,EAAA;AACI,MAAA,OAAA;AAAA,KACJ;AAEA,IAAA,SAAA,GAAY,YAAY,UAAW,CAAA,QAAA,CAAS,SAAS,CAAA,GAAI,WAAW,QAAS,EAAA,CAAA;AAG7E,IACK,SAAA,CAAA,SAAA,CAAU,CAAC,kBAAmB,CAAA,CAAA,EAAG,CAAC,kBAAmB,CAAA,CAAC,CACtD,CAAA,KAAA,CACG,uBAAwB,CAAA,KAAA,GAAQ,mBAAmB,KACnD,EAAA,uBAAA,CAAwB,SAAS,kBAAmB,CAAA,MAAM,EAC7D,SAAU,CAAA,uBAAA,CAAwB,CAAG,EAAA,uBAAA,CAAwB,CAAC,CAAA,CAAA;AAGnE,IAAC,IAAK,CAAA,QAAA,CAAS,MAAe,CAAA,aAAA,CAAc,WAAW,KAAK,CAAA,CAAA;AAE5D,IAAA,KAAA,CAAM,IAAI,uBAAuB,CAAA,CAAA;AACjC,IAAA,KAAA,CAAM,CAAI,GAAA,IAAA,CAAK,KAAM,CAAA,KAAA,CAAM,IAAI,UAAU,CAAA,CAAA;AACzC,IAAA,KAAA,CAAM,CAAI,GAAA,IAAA,CAAK,KAAM,CAAA,KAAA,CAAM,IAAI,UAAU,CAAA,CAAA;AACzC,IAAA,KAAA,CAAM,KAAQ,GAAA,IAAA,CAAK,KAAM,CAAA,KAAA,CAAM,QAAQ,UAAU,CAAA,CAAA;AACjD,IAAA,KAAA,CAAM,MAAS,GAAA,IAAA,CAAK,KAAM,CAAA,KAAA,CAAM,SAAS,UAAU,CAAA,CAAA;AAAA,GACvD;AAAA,EAOA,KAAK,QACL,EAAA;AACI,IAAI,IAAA,CAAC,SAAS,iBACd,EAAA;AACI,MAAA,IAAA,CAAK,gBAAgB,QAAQ,CAAA,CAAA;AAAA,KACjC;AAEA,IAAM,MAAA,EAAE,OAAO,IAAK,CAAA,QAAA,CAAA;AAEpB,IAAI,IAAA,CAAC,SAAS,YACd,EAAA;AACI,MAAG,EAAA,CAAA,MAAA,CAAO,GAAG,YAAY,CAAA,CAAA;AAAA,KAC7B;AAEA,IAAS,QAAA,CAAA,eAAA,EAAA,CAAA;AACT,IAAA,QAAA,CAAS,eAAe,QAAS,CAAA,iBAAA,CAAA;AACjC,IAAA,IAAA,CAAK,WAAY,EAAA,CAAA;AAAA,GACrB;AAAA,EASA,IAAI,QACJ,EAAA;AACI,IAAM,MAAA,EAAE,OAAO,IAAK,CAAA,QAAA,CAAA;AAEpB,IAAA,IAAI,QACJ,EAAA;AACI,MAAS,QAAA,CAAA,IAAA,CAAK,SAAS,iBAAiB,CAAA,CAAA;AAAA,KAC5C;AAEA,IAAI,IAAA,IAAA,CAAK,cAAe,EAAA,GAAI,CAC5B,EAAA;AACI,MAAA,IAAA,CAAK,WAAY,EAAA,CAAA;AAAA,KAGrB,MAAA;AACI,MAAG,EAAA,CAAA,OAAA,CAAQ,GAAG,YAAY,CAAA,CAAA;AAAA,KAC9B;AAAA,GACJ;AAAA,EAMA,WACA,GAAA;AACI,IAAA,MAAM,OAAO,IAAK,CAAA,SAAA,CAAU,IAAK,CAAA,SAAA,CAAU,SAAS,CAAG,CAAA,CAAA,YAAA,CAAA;AACvD,IAAI,IAAA,CAAA,CAAA;AAEJ,IAAI,IAAA,IAAA,CAAK,QAAS,CAAA,aAAA,CAAc,OAChC,EAAA;AACI,MAAA,CAAA,GAAI,IAAK,CAAA,CAAA,CAAA;AAAA,KAGb,MAAA;AAEI,MAAA,CAAA,GAAI,IAAK,CAAA,QAAA,CAAS,MAAS,GAAA,IAAA,CAAK,SAAS,IAAK,CAAA,CAAA,CAAA;AAAA,KAClD;AAEA,IAAK,IAAA,CAAA,QAAA,CAAS,GAAG,OAAQ,CAAA,IAAA,CAAK,GAAG,CAAG,EAAA,IAAA,CAAK,KAAO,EAAA,IAAA,CAAK,MAAM,CAAA,CAAA;AAAA,GAC/D;AACJ,CAAA,CAAA;AAhNO,IAAM,aAAN,GAAA,eAAA;AAAM,cAGF,SAA+B,GAAA;AAAA,EAClC,MAAM,aAAc,CAAA,cAAA;AAAA,EACpB,IAAM,EAAA,SAAA;AACV,CAAA,CAAA;AA4MJ,UAAA,CAAW,IAAI,aAAa,CAAA;;;;"}