Source: shaders/light_shader.js

/* 
 * File: light_shader.js
 *      Subclass from SpriteShader
 *      Supports light illumination
 */
"use strict";

import SpriteShader from "./sprite_shader.js";
import ShaderLightAt from "./shader_light_at.js";

class LightShader extends SpriteShader {
    /**
     * @classdesc Supports light illumination of sprites
     * <p>Found in Chapter 8, page 417 of the textbook</p>
     * Examples:
     * {@link https://mylesacd.github.io/build-your-own-2d-game-engine-2e-doc/BookSourceCode/chapter8/8.2.simple_light_shader/index.html 8.2 Simple Light Shader},
     * {@link https://mylesacd.github.io/build-your-own-2d-game-engine-2e-doc/BookSourceCode/chapter8/8.3.multiple_lights/index.html 8.3 Multiple Lights},
     * {@link https://mylesacd.github.io/build-your-own-2d-game-engine-2e-doc/BookSourceCode/chapter8/8.6.directional_and_spotlights/index.html 8.6 Directional and Spot Lights}
     * @extends SpriteShader
     * @constructor
     * @param {string} vertexShaderPath -  path to the vertex shader file
     * @param {string} fragmentShaderPath - path to the fragment shader file
     * @returns {LightShader} a new LightShader instance
     */
    constructor(vertexShaderPath, fragmentShaderPath) {
        // Call super class constructor
        super(vertexShaderPath, fragmentShaderPath);  // call super class constructor

        this.mLights = null;  // lights from the Renderable
        this.mCamera = null;  // the camera to draw for, required for WC to DC transform

        //*******WARNING***************
        // this number MUST correspond to the GLSL uLight[] array size (for LightFS.glsl and IllumFS.glsl)
        //*******WARNING********************
        this.kGLSLuLightArraySize = 8;  // <-- make sure this is the same as LightFS.glsl and IllumFS.glsl
        this.mShaderLights = [];
        let i, ls;
        for (i = 0; i < this.kGLSLuLightArraySize; i++) {
            ls = new ShaderLightAt(this.mCompiledShader, i);
            this.mShaderLights.push(ls);
        }
    }

    // Overriding the activation of the shader for rendering
    /**
     * Overrides shader activation to support 
     * @method
     * @param {vec4} pixelColor - [R,G,B,A] color array for the pixels
     * @param {mat4} trsMatrix - translation, rotation, and scaling matrix for the object being rendered
     * @param {mat4} cameraMatrix - translation, rotation, and scaling matrix for the Camera
     */
    activate(pixelColor, trsMatrix, cameraMatrix) {
        // first call the super class' activate
        super.activate(pixelColor, trsMatrix, cameraMatrix);

        // now push the light information to the shader
        let numLight = 0;
        if (this.mLights !== null) {
            while (numLight < this.mLights.length) {
                    this.mShaderLights[numLight].loadToShader(this.mCamera, this.mLights[numLight]);
                numLight++;
            }
        }
        // switch off the left over ones.
        while (numLight < this.kGLSLuLightArraySize) {
            this.mShaderLights[numLight].switchOffLight(); // switch off unused lights
            numLight++;
        }
    }

    /**
     * Set the Camera and list of Lights for this LightShader, the length of argument l can not be greater than GLSL light array size
     * @method
     * @param {Camera} c - the Camera this LightShader illuminates
     * @param {Lights[]} l -  List of Light objects for this LightShader
     */
    setCameraAndLights(c, l) {
        this.mCamera = c;
        this.mLights = l;
        if (this.mLights.length > this.kGLSLuLightArraySize)
            throw new Error ("Error: " + this.mLights.length + " lights requested. Current max light source supported is: " + this.kGLSLuLightArraySize + " update kGLSLuLightArraySize variable in light_shader.js  AND  light_fs.glsl to the proper number.");
    }
}

export default LightShader;