[
  {
    "path": ".editorconfig",
    "content": "# This file is for unifying the coding style for different editors and IDEs.\n# More information at http://EditorConfig.org\n\nroot = true\n\n# General Options\n[*]\nend_of_line = lf\nindent_size = 4\nindent_style = space\ninsert_final_newline = true\ntrim_trailing_whitespace = true\n\n# Markdown\n[*.md]\ntrim_trailing_whitespace = false\n\n# Special Files\n[{package.json,.travis.yml}]\nindent_size = 2\n"
  },
  {
    "path": ".github/CONTRIBUTING.md",
    "content": "# How to contribute\n\nPlease read this short guide to contributing before performing pull requests or reporting issues. The purpose\nof this guide is to ensure the best experience for all involved and make development as smooth as possible.\n\n\n## Reporting issues\n\nTo report a bug, request a feature, or even ask a question, make use of the [GitHub Issues][10] in this repo.\nWhen submitting an issue please take the following steps:\n\n**1. Search for existing issues.** Your bug may have already been fixed or addressed in an unreleased version, so\nbe sure to search the issues first before putting in a duplicate issue.\n\n**2. Create an isolated and reproducible test case.** If you are reporting a bug, make sure you also have a minimal,\nrunnable, code example that reproduces the problem you have.\n\n**3. Include a live example.** After narrowing your code down to only the problem areas, make use of [jsFiddle][11],\n[jsBin][12], or a link to your live site so that we can view a live example of the problem.\n\n**4. Share as much information as possible.** Include browser/node version affected, your OS, version of the library,\nsteps to reproduce, etc. \"X isn't working!!!1!\" will probably just be closed.\n\n[10]: https://github.com/pixijs/lights/issues\n[11]: http://jsfiddle.net\n[12]: http://jsbin.com/\n\n\n## Making Changes\n\nTo build the library you will need to download node.js from [nodejs.org][20]. After it has been installed open a\nconsole and run `npm install -g gulp` to install the global `gulp` executable.\n\nAfter that you can clone the repository and run `npm install` inside the cloned folder. This will install\ndependencies necessary for building the project. You can rebuild the project by running `gulp` in the cloned\nfolder.\n\nOnce that is ready, you can make your changes and submit a Pull Request:\n\n- **Send Pull Requests to the `master` branch.** All Pull Requests must be sent to the `master` branch, which is where\nall \"bleeding-edge\" development takes place.\n\n- **Ensure changes are jshint validated.** Our JSHint configuration file is provided in the repository and you\nshould check against it before submitting. This should happen automatically when running `gulp` in the repo directory.\n\n- **Never commit new builds.** When making a code change you should always run `gulp` which will rebuild the project\nso you can test, *however* please do not commit the new builds placed in `dist/` or your PR will be closed. By default\nthe build process will output to an ignored folder (`build/`) you should be fine.\n\n- **Only commit relevant changes.** Don't include changes that are not directly relevant to the fix you are making.\nThe more focused a PR is, the faster it will get attention and be merged. Extra files changing only whitespace or\ntrash files will likely get your PR closed.\n\n[20]: http://nodejs.org\n\n\n## Quickie Code Style Guide\n\nUse EditorConfig and JSHint! Both tools will ensure your code is in the required styles! Either way, here are some tips:\n\n- Use 4 spaces for tabs, never tab characters.\n\n- No trailing whitespace, blank lines should have no whitespace.\n\n- Always favor strict equals `===` unless you *need* to use type coercion.\n\n- Follow conventions already in the code, and listen to jshint. Our config is set-up for a reason.\n"
  },
  {
    "path": ".github/workflows/build.yml",
    "content": "name: Build CI\non:\n  push:\n    branches: [ '**' ]\n    tags: [ '**' ]\n  release:\n    types: [ 'created' ]\n  pull_request:\n    branches: [ '**' ]\njobs:\n  build:\n    runs-on: ubuntu-latest\n    steps:\n    - uses: actions/checkout@v3\n    - name: Use Node.js 16.x\n      uses: actions/setup-node@v3\n      with:\n        node-version: 16\n    - name: Install npm\n      run: npm install -g npm@8\n    - name: Install dependencies\n      run: npm ci\n    - name: Test\n      run: npm test"
  },
  {
    "path": ".gitignore",
    "content": "# sublime text files\n*.sublime*\n*.*~*.TMP\n\n# temp files\n.DS_Store\nThumbs.db\nDesktop.ini\nnpm-debug.log\n\n# project files\n.project\n\n# vim swap files\n*.sw*\n\n# emacs temp files\n*~\n\\#*#\n\n# project ignores\n!.gitkeep\n*__temp\nnode_modules\ndocs/\n\n# jetBrains IDE ignores\n.idea\n\n# tsc output\ncompile\ndist\nlib\nindex.d.ts\nexample.api.json\nexample.api.json.md5"
  },
  {
    "path": ".npmrc",
    "content": "engine-strict = true\n"
  },
  {
    "path": "LICENSE",
    "content": "The MIT License (MIT)\n\nCopyright (c) 2015 Ivan Popelyshev\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n\n"
  },
  {
    "path": "README.md",
    "content": "# PixiJS Lights\n\n[![Build CI](https://github.com/pixijs-userland/lights/actions/workflows/build.yml/badge.svg)](https://github.com/pixijs-userland/lights/actions/workflows/build.yml) [![npm version](https://badge.fury.io/js/@pixi%2Flights.svg)](https://badge.fury.io/js/@pixi%2Flights)\n\nA plugin that adds deferred lighting to PixiJS.\n\n**Note**: This modules *requires* v7.0.0+ of [PixiJS](https://github.com/pixijs/pixijs) and v2.0.1+ of [@pixi/layers](https://github.com/pixijs-userland/layers).\n\n* [Demo](https://userland.pixijs.io/lights/examples/)\n\n## Usage\n\nYou have to create three layers: one for sprites, one for their normals and one for lights. Sprites and normals are rendered to temporary RenderTexture, and lights have those two textures as an input.\n\n```js\n// Get class references\nimport {Application, Sprite, Container, lights} from 'pixi.js';\nimport {Layer, Stage} from '@pixi/layers';\nimport {diffuseGroup, normalGroup, lightGroup, PointLight} from '@pixi/lights';\n\n// Create new application\nconst app = new Application({\n    backgroundColor: 0x000000, // Black is required!\n    width: 800,\n    height: 600\n});\ndocument.body.appendChild(app.view);\n\n// Use the pixi-layers Stage instead of default Container\napp.stage = new Stage();\n\n// Add the background diffuse color\nconst diffuse = Sprite.fromImage('images/BGTextureTest.jpg');\ndiffuse.parentGroup = diffuseGroup;\n\n// Add the background normal map\nconst normals = Sprite.fromImage('images/BGTextureNORM.jpg');\nnormals.parentGroup = normalGroup;\n\n// Create the point light\nconst light = new PointLight(0xffffff, 1);\nlight.x = app.screen.width / 2;\nlight.y = app.screen.height / 2;\n\n// Create a background container \nconst background = new Container();\nbackground.addChild(\n    normals,\n    diffuse,\n    light\n);\n\napp.stage.addChild(\n    // put all layers for deferred rendering of normals\n    new Layer(diffuseGroup),\n    new Layer(normalGroup),\n    new Layer(lightGroup),\n    // Add the lights and images\n    background\n);\n```\n\n* [Run This](https://userland.pixijs.io/lights/examples/usage.html)\n\n### Filters\n\nIf you want to use light shaders inside a filter, make sure its full-screen:\n\n```js\napp.stage.filters = [new BlurFilter()];\napp.stage.filterArea = app.screen;\n```\n\n## Vanilla JS\n\nNavigate `pixi-lights` npm package, take `dist/pixi-lights.js` file.\n\n```html\n<script src='lib/pixi.js'></script>\n<script src='lib/pixi-lights.umd.js'></script>\n```\n\nall classes can be accessed through `PIXI.lights` global namespace.\n\n## Building\n\nYou normally don't need to build this module, you can just download a release from the releases page.\n\nThen you can install dependencies and build:\n\n```js\nnpm i && npm run build\n```\n\nThat will output the built distributables to `./lib` and `./dist`.\n\n## Roadmap\n\n1. More lighting types, left are:\n - Spot lights\n - Hemisphere lights\n - Area lights\n2. Add dynamic shadows\n3. Write tests!\n"
  },
  {
    "path": "examples/index.html",
    "content": "<!DOCTYPE html>\n<html>\n    <head>\n        <meta charset=\"utf8\" />\n        <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\" />\n        <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no, minimal-ui\" />\n        <title>PixiJS Lights - Demo</title>\n        <style>\n            body {\n                margin:0;\n                padding:0;\n                background:black;\n            }\n            canvas {\n                display: block;\n                position:absolute;\n                top: 50%;\n                left: 50%;\n                transform: translate(-50%, -50%);\n            }\n        </style>\n    </head>\n    <body>\n        <script src=\"https://pixijs.download/v7.x/pixi.js\"></script>\n        <script src=\"https://unpkg.com/@pixi/layers/dist/pixi-layers.js\"></script>\n        <script src=\"../dist/pixi-lights.js\"></script>\n        <script>\n\n            const app = new PIXI.Application({ width: 1024, height: 512 });\n            document.body.appendChild(app.view);\n\n            const stage = app.stage = new PIXI.layers.Stage();\n            const light = new PIXI.lights.PointLight(0xffffff, 1);\n\n            // put all layers for deferred rendering of normals\n            stage.addChild(new PIXI.layers.Layer(PIXI.lights.diffuseGroup));\n            stage.addChild(new PIXI.layers.Layer(PIXI.lights.normalGroup));\n            stage.addChild(new PIXI.layers.Layer(PIXI.lights.lightGroup));\n\n            PIXI.Assets.addBundle('textures', {\n                bg_diffuse: 'images/BGTextureTest.jpg',\n                bg_normal: 'images/BGTextureNORM.jpg',\n                block_diffuse: 'images/block.png',\n                block_normal: 'images/blockNormalMap.png',\n            });\n\n            function createPair(diffuseTex, normalTex) {\n                const container = new PIXI.Container();\n                const diffuseSprite = new PIXI.Sprite(diffuseTex);\n                diffuseSprite.parentGroup = PIXI.lights.diffuseGroup;\n                const normalSprite = new PIXI.Sprite(normalTex);\n                normalSprite.parentGroup = PIXI.lights.normalGroup;\n                container.addChild(diffuseSprite);\n                container.addChild(normalSprite);\n                return container;\n            }\n\n            PIXI.Assets.loadBundle('textures').then((res) => {\n\n                const bg = createPair(res.bg_diffuse, res.bg_normal);\n                const block = createPair(res.block_diffuse, res.block_normal);\n                const block1 = createPair(res.block_diffuse, res.block_normal);\n                const block2 = createPair(res.block_diffuse, res.block_normal);\n\n                block.position.set(100, 100);\n                block1.position.set(500, 100);\n                block2.position.set(300, 400);\n\n                light.position.set(525, 160);\n                stage.addChild(bg);\n                stage.addChild(block);\n                stage.addChild(block1);\n                stage.addChild(block2);\n\n                stage.addChild(new PIXI.lights.AmbientLight(0x4d4d59, 0.4));\n                stage.addChild(new PIXI.lights.DirectionalLight(0x4d4d59, 1, block1));\n                stage.addChild(light);\n\n                bg.interactive = true;\n                bg.on('pointermove', function (event) {\n                    light.position.copyFrom(event.data.global);\n                });\n\n                bg.on('pointerdown', function (event) {\n                    const clickLight = new PIXI.lights.PointLight(0xffffff);\n                    clickLight.position.copyFrom(event.data.global);\n                    stage.addChild(clickLight);\n                });\n            });\n\n        </script>\n    </body>\n</html>\n"
  },
  {
    "path": "examples/usage.html",
    "content": "<!DOCTYPE html>\n<html>\n    <head>\n        <meta charset=\"utf8\" />\n        <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\" />\n        <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no, minimal-ui\" />\n        <title>PixiJS Lights - Usage Example</title>\n        <style>\n            body {\n                margin:0;\n                padding:0;\n                background:black;\n            }\n            canvas {\n                display: block;\n                position:absolute;\n                top: 50%;\n                left: 50%;\n                transform: translate(-50%, -50%);\n            }\n        </style>\n    </head>\n    <body>\n        <script src=\"https://pixijs.download/v7.x/pixi.js\"></script>\n        <script src=\"https://unpkg.com/@pixi/layers/dist/pixi-layers.js\"></script>\n        <script src=\"../dist/pixi-lights.js\"></script>\n        <script>\n            const {Application, Sprite, Container, lights, layers} = PIXI;\n            const {diffuseGroup, normalGroup, lightGroup} = lights;\n            const {Layer, Stage} = layers;\n\n            const app = new Application({\n                backgroundColor: 0x000000, // Black is required!\n                width: 800,\n                height: 600\n            });\n            document.body.appendChild(app.view);\n\n            // Use the pixi-layers Stage\n            app.stage = new Stage();\n\n            // Add the background diffuse color\n            const diffuse = Sprite.from('images/BGTextureTest.jpg');\n            diffuse.parentGroup = diffuseGroup;\n\n            // Add the background normal map\n            const normals = Sprite.from('images/BGTextureNORM.jpg');\n            normals.parentGroup = normalGroup;\n\n            // Create the point light\n            const light = new PIXI.lights.PointLight(0xffffff, 1, 200);\n            light.x = app.screen.width / 2;\n            light.y = app.screen.height / 2;\n\n            // Create a background container\n            const background = new Container();\n            background.addChild(\n                normals,\n                diffuse,\n                light\n            );\n\n            app.stage.addChild(\n                // put all layers for deferred rendering of normals\n                new Layer(diffuseGroup),\n                new Layer(normalGroup),\n                new Layer(lightGroup),\n                // Add the lights and images\n                background\n            );\n\n        </script>\n    </body>\n</html>\n"
  },
  {
    "path": "package.json",
    "content": "{\n  \"name\": \"@pixi/lights\",\n  \"version\": \"4.1.0\",\n  \"description\": \"A plugin that adds deferred lighting to PixiJS v6\",\n  \"author\": \"Ivan Popelyshev\",\n  \"contributors\": [\n    \"Ivan Popelyshev <ivan.popelyshev@gmail.com>\",\n    \"Matt Karl <matt@mattkarl.com>\"\n  ],\n  \"extensionConfig\": {\n    \"namespace\": \"PIXI.lights\",\n    \"lint\": [\n      \"src\"\n    ],\n    \"globals\": {\n      \"@pixi/layers\": \"PIXI.layers\"\n    },\n    \"docsName\": \"PixiJS Lights\",\n    \"docsCopyright\": \"Copyright &copy; 2015 - 2022 Ivan Popelyshev\",\n    \"docsTitle\": \"PixiJS Lights API Documentation\",\n    \"docsDescription\": \"Documentation for PixiJS Lights library\",\n    \"docsKeyword\": \"docs, documentation, pixi, pixijs, rendering, pixi-lights, display, pixi-display, javascript\"\n  },\n  \"main\": \"./lib/index.js\",\n  \"module\": \"./lib/index.mjs\",\n  \"types\": \"./lib/index.d.ts\",\n  \"exports\": {\n    \".\": {\n      \"import\": \"./lib/index.mjs\",\n      \"require\": \"./lib/index.js\",\n      \"types\": \"./lib/index.d.ts\"\n    }\n  },\n  \"homepage\": \"http://www.pixijs.com/\",\n  \"bugs\": \"https://github.com/pixijs/lights/issues\",\n  \"license\": \"MIT\",\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/pixijs/lights.git\"\n  },\n  \"scripts\": {\n    \"clean\": \"xs clean\",\n    \"start\": \"xs serve\",\n    \"watch\": \"xs watch\",\n    \"build\": \"xs build\",\n    \"lint\": \"xs lint\",\n    \"lint:fix\": \"xs lint --fix\",\n    \"types\": \"xs types\",\n    \"release\": \"xs release\",\n    \"docs\": \"xs docs\",\n    \"deploy\": \"xs deploy\",\n    \"test\": \"xs build,docs\"\n  },\n  \"publishConfig\": {\n    \"access\": \"public\"\n  },\n  \"engines\": {\n    \"node\": \">=16\",\n    \"npm\": \">=8\"\n  },\n  \"files\": [\n    \"dist/\",\n    \"lib/\"\n  ],\n  \"peerDependencies\": {\n    \"@pixi/core\": \"^7.0.0\",\n    \"@pixi/display\": \"^7.0.0\",\n    \"@pixi/layers\": \"^2.0.1\",\n    \"@pixi/mesh\": \"^7.0.0\"\n  },\n  \"devDependencies\": {\n    \"@pixi/core\": \"^7.0.0\",\n    \"@pixi/display\": \"^7.0.0\",\n    \"@pixi/extension-scripts\": \"^1.8.1\",\n    \"@pixi/layers\": \"^2.0.1\",\n    \"@pixi/mesh\": \"^7.0.0\"\n  }\n}\n"
  },
  {
    "path": "src/LayerFinder.ts",
    "content": "import { Texture } from '@pixi/core';\nimport { Group, Layer } from '@pixi/layers';\n\n/**\n * @memberof PIXI.lights\n * @static\n * @type {PIXI.layers.Group}\n */\nexport const diffuseGroup = new Group(0, false);\n\n/**\n * @memberof PIXI.lights\n * @static\n * @type {PIXI.layers.Group}\n */\nexport const normalGroup = new Group(0, false);\n\n/**\n * @memberof PIXI.lights\n * @static\n * @type {PIXI.layers.Group}\n */\nexport const lightGroup = new Group(0, false);\n\ndiffuseGroup.useRenderTexture = true;\nnormalGroup.useRenderTexture = true;\n\n/**\n * @memberof PIXI.lights\n */\nexport class LayerFinder\n{\n    /**\n     * Last layer\n     * @type {PIXI.layers.Layer}\n     */\n    lastLayer: Layer | null = null;\n    /**\n     * Diffuse texture\n     * @type {PIXI.Texture}\n     */\n    diffuseTexture: Texture | null = null;\n    /**\n     * Normal texture\n     * @type {PIXI.Texture}\n     */\n    normalTexture: Texture | null = null;\n\n    /**\n     * Check\n     * @param {PIXI.layers.Layer} layer -\n     */\n    check(layer: Layer): void\n    {\n        if (this.lastLayer === layer)\n        {\n            return;\n        }\n        this.lastLayer = layer;\n\n        const stage = layer._activeStageParent;\n        const layerAny = layer as any;\n\n        this.diffuseTexture = Texture.WHITE;\n        this.normalTexture = Texture.WHITE;\n\n        if (layerAny.diffuseTexture && layerAny.normalTexture)\n        {\n            this.diffuseTexture = layerAny.diffuseTexture;\n            this.normalTexture = layerAny.normalTexture;\n        }\n        else\n        {\n            for (let j = 0; j < stage._activeLayers.length; j++)\n            {\n                const texLayer = stage._activeLayers[j];\n\n                if (texLayer.group === normalGroup)\n                {\n                    this.normalTexture = texLayer.getRenderTexture();\n                }\n                if (texLayer.group === diffuseGroup)\n                {\n                    this.diffuseTexture = texLayer.getRenderTexture();\n                }\n            }\n        }\n    }\n\n    static _instance = new LayerFinder();\n}\n"
  },
  {
    "path": "src/index.ts",
    "content": "import './mixins/Circle';\nexport * from './lights/light';\nexport * from './lights/ambientLight';\nexport * from './lights/pointLight';\nexport * from './lights/directionalLight';\nexport * from './LayerFinder';\n"
  },
  {
    "path": "src/lights/ambientLight/AmbientLight.ts",
    "content": "import { Light } from '../light/Light';\nimport { AmbientLightShader } from './AmbientLightShader';\n\n/**\n * Ambient light is drawn using a full-screen quad.\n * @memberof PIXI.lights\n */\nexport class AmbientLight extends Light\n{\n    /**\n     * @param {number} [color=0xFFFFFF] - The color of the light.\n     * @param {number} [brightness=0.5] - The brightness of the light.\n     */\n    constructor(color = 0xFFFFFF, brightness = 0.5)\n    {\n        super(color, brightness, new AmbientLightShader());\n    }\n}\n"
  },
  {
    "path": "src/lights/ambientLight/AmbientLightShader.ts",
    "content": "import { Program } from '@pixi/core';\nimport { LightShader } from '../light/LightShader';\nimport { ambientFrag } from './ambient.frag';\n\n/**\n * @memberof PIXI.lights\n */\nexport class AmbientLightShader extends LightShader\n{\n    constructor()\n    {\n        super({\n            program: AmbientLightShader._program\n        });\n    }\n\n    static _program = new Program(LightShader.defaultVertexSrc, ambientFrag);\n}\n"
  },
  {
    "path": "src/lights/ambientLight/ambient.frag.ts",
    "content": "import { commonUniforms, computeVertexPosition, loadNormals } from '../shared';\n\nexport const ambientFrag = `precision highp float;\n\n${commonUniforms}\n\nvoid main(void)\n{\n${computeVertexPosition}\n${loadNormals}\n    // simplified lambert shading that makes assumptions for ambient color\n    vec3 diffuse = uColor.rgb * uBrightness;\n    vec4 diffuseColor = texture2D(uSampler, texCoord);\n    vec3 finalColor = diffuseColor.rgb * diffuse;\n\n    gl_FragColor = vec4(finalColor, diffuseColor.a);\n}\n`;\n"
  },
  {
    "path": "src/lights/ambientLight/index.ts",
    "content": "export * from './AmbientLight';\nexport * from './AmbientLightShader';\n"
  },
  {
    "path": "src/lights/directionalLight/DirectionalLight.ts",
    "content": "import { Light } from '../light/Light';\nimport { Point, Renderer } from '@pixi/core';\nimport { DisplayObject } from '@pixi/display';\nimport { DirectionalLightShader } from './DirectionalLightShader';\n\n/**\n * Directional light is drawn using a full-screen quad.\n * @memberof PIXI.lights\n */\nexport class DirectionalLight extends Light\n{\n    target: DisplayObject | Point;\n\n    /**\n     * @param {number} [color=0xFFFFFF] - The color of the light.\n     * @param {number} [brightness=1] - The intensity of the light.\n     * @param {PIXI.DisplayObject|PIXI.Point} [target] - The object in the scene to target.\n     */\n    constructor(color = 0xFFFFFF, brightness = 1, target: DisplayObject | Point)\n    {\n        super(color, brightness, new DirectionalLightShader());\n\n        this.target = target;\n    }\n\n    /**\n     * Sync shader\n     * @param {PIXI.Renderer} renderer - Renderer\n     */\n    override syncShader(renderer: Renderer): void\n    {\n        super.syncShader(renderer);\n\n        const shader = this.material;\n\n        const vec = shader.uniforms.uLightDirection;\n        const wt = this.worldTransform;\n        const twt = (this.target as any).worldTransform;\n\n        let tx: number;\n        let ty: number;\n\n        if (twt)\n        {\n            tx = twt.tx;\n            ty = twt.ty;\n        }\n        else\n        {\n            tx = this.target.x;\n            ty = this.target.y;\n        }\n\n        // calculate direction from this light to the target\n        vec.x = wt.tx - tx;\n        vec.y = wt.ty - ty;\n\n        // normalize\n        const len = Math.sqrt((vec.x * vec.x) + (vec.y * vec.y));\n\n        vec.x /= len;\n        vec.y /= len;\n    }\n}\n"
  },
  {
    "path": "src/lights/directionalLight/DirectionalLightShader.ts",
    "content": "import { Program, Point } from '@pixi/core';\nimport { LightShader } from '../light/LightShader';\nimport { directionalFrag } from './directional.frag';\n\n/**\n * @memberof PIXI.lights\n */\nexport class DirectionalLightShader extends LightShader\n{\n    constructor()\n    {\n        super({\n            program: DirectionalLightShader._program,\n            uniforms: {\n                uLightRadius: 1.0,\n                uLightDirection: new Point()\n            }\n        });\n    }\n\n    static _program = new Program(LightShader.defaultVertexSrc, directionalFrag);\n}\n"
  },
  {
    "path": "src/lights/directionalLight/directional.frag.ts",
    "content": "import { combine, commonUniforms, computeDiffuse, computeVertexPosition, loadNormals } from '../shared';\n\nexport const directionalFrag = `precision highp float;\n\n// imports the common uniforms like samplers, and ambient/light color\n${commonUniforms}\n\nuniform vec2 uLightDirection;\n\nvoid main()\n{\n${computeVertexPosition}\n${loadNormals}\n\n    // the directional vector of the light\n    vec3 lightVector = vec3(uLightDirection, uLightHeight);\n\n    // compute Distance\n    float D = length(lightVector);\n\n${computeDiffuse}\n\n    // calculate attenuation\n    float attenuation = 1.0;\n\n${combine}\n}\n`;\n"
  },
  {
    "path": "src/lights/directionalLight/index.ts",
    "content": "export * from './DirectionalLight';\nexport * from './DirectionalLightShader';\n"
  },
  {
    "path": "src/lights/light/Light.ts",
    "content": "import { Geometry, Renderer, BLEND_MODES, DRAW_MODES } from '@pixi/core';\nimport { Layer } from '@pixi/layers';\nimport { Mesh } from '@pixi/mesh';\nimport { LayerFinder, lightGroup } from '../../LayerFinder';\nimport { LightShader } from './LightShader';\nimport { ViewportQuad } from './ViewportQuad';\n\n/**\n * Base light class.\n * @extends PIXI.Mesh\n * @memberof PIXI.lights\n */\nexport class Light extends Mesh\n{\n    /** Light height */\n    lightHeight: number;\n    /** Brightness */\n    brightness: number;\n    /** Shader name */\n    shaderName: string | null = null;\n    /** Use Viewport Quad */\n    readonly useViewportQuad: boolean;\n\n    /**\n     * @param {number} [color=0xFFFFFF] - The color of the light.\n     * @param {number} [brightness=1] - The brightness of the light, in range [0, 1].\n     * @param {PIXI.lights.LightShader} [material] -\n     * @param {Float32Array} [vertices] -\n     * @param {Uint16Array} [indices] -\n     */\n    constructor(color = 0x4d4d59, brightness = 0.8, material: LightShader,\n        vertices? : Float32Array, indices?: Uint16Array)\n    {\n        super(!vertices ? ViewportQuad._instance : new Geometry()\n            .addAttribute('aVertexPosition', vertices).addIndex(indices), material);\n\n        this.blendMode = BLEND_MODES.ADD;\n        const useViewportQuad = !vertices;\n\n        this.drawMode = useViewportQuad ? DRAW_MODES.TRIANGLE_STRIP : DRAW_MODES.TRIANGLES;\n\n        /**\n         * The height of the light from the viewport.\n         *\n         * @default 0.075\n         */\n        this.lightHeight = 0.075;\n\n        /**\n         * The falloff attenuation coeficients.\n         *\n         * @member {number[]}\n         * @default [0.75, 3, 20]\n         */\n        this.falloff = [0.75, 3, 20];\n\n        /**\n         * By default the light uses a viewport sized quad as the mesh.\n         *\n         * @member {boolean}\n         */\n        this.useViewportQuad = useViewportQuad;\n\n        // color and brightness are exposed through setters\n        this.tint = color ?? 0x4d4d59;\n        this.brightness = brightness;\n        this.parentGroup = lightGroup;\n    }\n\n    /**\n     * The color of the lighting.\n     */\n    get color(): number\n    {\n        return this.tint;\n    }\n    set color(val: number)\n    {\n        this.tint = val;\n    }\n\n    /**\n     * Falloff\n     * @member {number[]}\n     */\n    get falloff(): ArrayLike<number>\n    {\n        return this.material.uniforms.uLightFalloff;\n    }\n\n    set falloff(value: ArrayLike<number>)\n    {\n        this.material.uniforms.uLightFalloff[0] = value[0];\n        this.material.uniforms.uLightFalloff[1] = value[1];\n        this.material.uniforms.uLightFalloff[2] = value[2];\n    }\n\n    /**\n     * Last layer\n     * @type {PIXI.layers.Layer}\n     */\n    lastLayer: Layer | null = null;\n\n    /**\n     * Sync Shader\n     * @param {PIXI.Renderer} renderer - Renderer\n     */\n    syncShader(renderer: Renderer): void\n    {\n        const { uniforms } = this.shader;\n\n        // TODO: actually pass UV's of screen instead of size\n        uniforms.uViewSize[0] = renderer.screen.width;\n        uniforms.uViewSize[1] = renderer.screen.height;\n        uniforms.uViewPixels[0] = renderer.view.width;\n        uniforms.uViewPixels[1] = renderer.view.height;\n        uniforms.uFlipY = !renderer.framebuffer.current;\n        uniforms.uSampler = LayerFinder._instance.diffuseTexture;\n        uniforms.uNormalSampler = LayerFinder._instance.normalTexture;\n        uniforms.uUseViewportQuad = this.useViewportQuad;\n        uniforms.uBrightness = this.brightness;\n    }\n\n    _renderDefault(renderer: Renderer): void\n    {\n        if (!this._activeParentLayer)\n        {\n            return;\n        }\n        LayerFinder._instance.check(this._activeParentLayer);\n\n        const shader = this.shader as unknown as LightShader;\n\n        shader.alpha = this.worldAlpha;\n        if (shader.update)\n        {\n            shader.update();\n        }\n\n        renderer.batch.flush();\n\n        shader.uniforms.translationMatrix = this.transform.worldTransform.toArray(true);\n        if (this.useViewportQuad)\n        {\n            // TODO: pass the viewport (translated screen) instead\n            (this.geometry as ViewportQuad).update(renderer.screen);\n        }\n\n        this.syncShader(renderer);\n\n        renderer.shader.bind(shader);\n\n        renderer.state.set(this.state);\n\n        renderer.geometry.bind(this.geometry, shader);\n\n        renderer.geometry.draw(this.drawMode, this.size, this.start, this.geometry.instanceCount);\n    }\n}\n"
  },
  {
    "path": "src/lights/light/LightShader.ts",
    "content": "import { Texture, utils, Matrix } from '@pixi/core';\nimport { IMeshMaterialOptions, MeshMaterial } from '@pixi/mesh';\nimport { vert } from '../shared';\n\n/**\n * @extends PIXI.MeshMaterial\n * @memberof PIXI.lights\n */\nexport class LightShader extends MeshMaterial\n{\n    /**\n     * @param {PIXI.lights.IMeshMaterialOptions} [options] - Options to use.\n     */\n    constructor(options?: IMeshMaterialOptions)\n    {\n        const uniforms: utils.Dict<any> = {\n            translationMatrix: Matrix.IDENTITY.toArray(true),\n            // textures from the previously rendered FBOs\n            uNormalSampler: Texture.WHITE,\n            // size of the renderer viewport, CSS\n            uViewSize: new Float32Array(2),\n            // same, in PIXELS\n            uViewPixels: new Float32Array(2),\n            // light falloff attenuation coefficients\n            uLightFalloff: new Float32Array([0, 0, 0]),\n            // height of the light above the viewport\n            uLightHeight: 0.075,\n            uBrightness: 1.0,\n            uUseViewportQuad: true,\n        };\n\n        Object.assign(uniforms, options?.uniforms);\n\n        super(Texture.WHITE, { ...options, uniforms });\n    }\n\n    static defaultVertexSrc: string = vert;\n}\n"
  },
  {
    "path": "src/lights/light/ViewportQuad.ts",
    "content": "import { Rectangle, Quad } from '@pixi/core';\n\n/**\n * @extends PIXI.Quad\n * @memberof PIXI.lights\n */\nexport class ViewportQuad extends Quad\n{\n    /**\n     * Update\n     * @param {PIXI.Rectangle} viewport -\n     */\n    update(viewport: Rectangle): void\n    {\n        const b = this.buffers[0].data as Float32Array;\n\n        const x1 = viewport.x;\n        const y1 = viewport.y;\n        const x2 = viewport.x + viewport.width;\n        const y2 = viewport.y + viewport.height;\n\n        if (b[0] !== x1 || b[1] !== y1\n            || b[4] !== x2 || b[5] !== y2)\n        {\n            b[0] = b[6] = x1;\n            b[1] = b[3] = y1;\n            b[2] = b[4] = x2;\n            b[5] = b[7] = y2;\n            this.buffers[0].update();\n        }\n    }\n\n    static _instance: ViewportQuad = new ViewportQuad();\n}\n"
  },
  {
    "path": "src/lights/light/index.ts",
    "content": "export * from './Light';\nexport * from './LightShader';\nexport * from './ViewportQuad';\n"
  },
  {
    "path": "src/lights/pointLight/PointLight.ts",
    "content": "import { Light } from '../light/Light';\nimport { Circle, DRAW_MODES } from '@pixi/core';\nimport { getCircleMesh } from '../../mixins/Circle';\nimport { PointLightShader } from './PointLightShader';\n\n/**\n * @memberof PIXI.lights\n */\nexport class PointLight extends Light\n{\n    /**\n     * @param {number} [color=0xFFFFFF] - The color of the light.\n     * @param {number} [brightness=1] - The intensity of the light.\n     * @param {number} [radius=Infinity] - The distance the light reaches. You will likely need\n     *  to change the falloff of the light as well if you change this value. Infinity will\n     *  use the entire viewport as the drawing surface.\n     */\n    constructor(color = 0xFFFFFF, brightness = 1, radius = Infinity)\n    {\n        if (radius !== Infinity)\n        {\n            const shape = new Circle(0, 0, radius);\n            const { vertices, indices } = getCircleMesh(shape);\n\n            super(color, brightness, new PointLightShader(), vertices, indices);\n\n            this.drawMode = DRAW_MODES.TRIANGLE_FAN;\n        }\n        else\n        {\n            super(color, brightness, new PointLightShader());\n        }\n        this.shaderName = 'pointLightShader';\n        this.radius = radius;\n    }\n\n    /** Radius */\n    get radius(): number\n    {\n        return this.material.uniforms.uLightRadius;\n    }\n\n    set radius(value: number)\n    {\n        this.material.uniforms.uLightRadius = value;\n    }\n}\n"
  },
  {
    "path": "src/lights/pointLight/PointLightShader.ts",
    "content": "import { Program } from '@pixi/core';\nimport { LightShader } from '../light/LightShader';\nimport { pointFrag } from './point.frag';\n\n/**\n * @memberof PIXI.lights\n */\nexport class PointLightShader extends LightShader\n{\n    constructor()\n    {\n        super({\n            program: PointLightShader._program,\n            uniforms: {\n                uLightRadius: 1.0\n            }\n        });\n    }\n\n    static _program = new Program(LightShader.defaultVertexSrc, pointFrag);\n}\n"
  },
  {
    "path": "src/lights/pointLight/index.ts",
    "content": "export * from './PointLight';\nexport * from './PointLightShader';\n"
  },
  {
    "path": "src/lights/pointLight/point.frag.ts",
    "content": "import { combine, commonUniforms, computeDiffuse, computeVertexPosition, loadNormals } from '../shared';\n\nexport const pointFrag = `precision highp float;\n\n// imports the common uniforms like samplers, and ambient color\n${commonUniforms}\n\nuniform float uLightRadius;\n\nvoid main()\n{\n${computeVertexPosition}\n${loadNormals}\n\n    vec2 lightPosition = translationMatrix[2].xy / uViewSize;\n\n    // the directional vector of the light\n    vec3 lightVector = vec3(lightPosition - texCoord, uLightHeight);\n\n    // correct for aspect ratio\n    lightVector.x *= uViewSize.x / uViewSize.y;\n\n    // compute Distance\n    float D = length(lightVector);\n\n    // bail out early when pixel outside of light sphere\n    if (D > uLightRadius) discard;\n\n${computeDiffuse}\n\n    // calculate attenuation\n    float attenuation = 1.0 / (uLightFalloff.x + (uLightFalloff.y * D) + (uLightFalloff.z * D * D));\n\n${combine}\n}\n`;\n"
  },
  {
    "path": "src/lights/shared.ts",
    "content": "/* eslint-disable @typescript-eslint/no-inferrable-types */\nexport const combine: string = `vec3 intensity = diffuse * attenuation;\nvec4 diffuseColor = texture2D(uSampler, texCoord);\nvec3 finalColor = diffuseColor.rgb * intensity;\n\ngl_FragColor = vec4(finalColor, diffuseColor.a);\n`;\n\nexport const commonUniforms: string = `uniform sampler2D uSampler;\nuniform sampler2D uNormalSampler;\n\nuniform mat3 translationMatrix;\n\nuniform vec2 uViewPixels;   // size of the viewport, in pixels\nuniform vec2 uViewSize;     // size of the viewport, in CSS\n\nuniform vec4 uColor;   // light color, alpha channel used for intensity.\nuniform float uBrightness;\nuniform vec3 uLightFalloff; // light attenuation coefficients (constant, linear, quadratic)\nuniform float uLightHeight; // light height above the viewport\nuniform float uFlipY;             // whether we use renderTexture, FBO is flipped\n`;\n\nexport const computeDiffuse: string = `// normalize vectors\nvec3 N = normalize(normalColor.xyz * 2.0 - 1.0);\nvec3 L = normalize(lightVector);\n\n// pre-multiply light color with intensity\n// then perform \"N dot L\" to determine our diffuse\nvec3 diffuse = uColor.rgb * uBrightness * max(dot(N, L), 0.0);\n`;\n\nexport const computeVertexPosition: string = `vec2 texCoord = gl_FragCoord.xy / uViewPixels;\ntexCoord.y = (1.0 - texCoord.y) * uFlipY + texCoord.y * (1.0 - uFlipY); // FBOs positions are flipped.\n`;\n\nexport const loadNormals: string = `vec4 normalColor = texture2D(uNormalSampler, texCoord);\nnormalColor.g = 1.0 - normalColor.g; // Green layer is flipped Y coords.\n\n// bail out early when normal has no data\nif (normalColor.a == 0.0) discard;\n`;\n\nexport const vert: string = `attribute vec2 aVertexPosition;\n\nuniform bool uUseViewportQuad;\nuniform mat3 translationMatrix;\nuniform mat3 projectionMatrix;\n\nvoid main(void) {\n    if (uUseViewportQuad) {\n        gl_Position = vec4((projectionMatrix * vec3(aVertexPosition, 1.0)).xy, 0.0, 1.0);\n    }\n    else\n    {\n        gl_Position = vec4((projectionMatrix * translationMatrix * vec3(aVertexPosition, 1.0)).xy, 0.0, 1.0);\n    }\n}\n`;\n"
  },
  {
    "path": "src/mixins/Circle.ts",
    "content": "import { Circle } from '@pixi/core';\n\n/**\n * PixiJS namespace.\n * @namespace PIXI\n */\n\n/**\n * PixiJS Lights namespace.\n * @namespace PIXI.lights\n */\n\n/**\n * Circle class from PixiJS.\n * @class PIXI.Circle\n */\n\n/**\n * Creates vertices and indices arrays to describe this circle.\n * @method PIXI.Circle#getMesh\n * @param {PIXI.Circle} shape -\n * @param {number} [totalSegments=40] - Total segments to build for the circle mesh.\n * @param vertices -\n * @param indices -\n *  `((totalSegments + 2) * 2)` or more. If not passed it is created for you.\n *  be `(totalSegments + 3)` or more. If not passed it is created for you.\n * @return {PIXI.lights.CircleMeshData} Object with verticies and indices arrays\n */\n// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types\nexport function getCircleMesh(shape: Circle, totalSegments = 40, vertices?: Float32Array, indices?: Uint16Array)\n{\n    vertices = vertices || new Float32Array((totalSegments + 1) * 2);\n    indices = indices || new Uint16Array(totalSegments + 1);\n\n    const seg = (Math.PI * 2) / totalSegments;\n    let indicesIndex = -1;\n\n    indices[++indicesIndex] = indicesIndex;\n\n    for (let i = 0; i <= totalSegments; ++i)\n    {\n        const index = i * 2;\n        const angle = seg * i;\n\n        vertices[index] = Math.cos(angle) * shape.radius;\n        vertices[index + 1] = Math.sin(angle) * shape.radius;\n\n        indices[++indicesIndex] = indicesIndex;\n    }\n\n    indices[indicesIndex] = 1;\n\n    return { vertices, indices };\n}\n\n/**\n * @memberof PIXI.lights\n * @property {Float32Array} vertices - Vertices data\n * @property {Uint16Array} indices - Indices data\n */\nexport interface CircleMeshData\n{\n    vertices: Float32Array;\n    indices: Uint16Array;\n}\n"
  },
  {
    "path": "tsconfig.json",
    "content": "{\n    \"extends\": \"@pixi/extension-scripts/lib/configs/tsconfig.json\",\n    \"include\": [\n        \"src/**/*\"\n    ]\n}\n"
  }
]