API Docs for: 0.5.5
Show:

File: kick/scene/SceneLights.js

define(["kick/core/Constants", "kick/core/Util", "kick/math/Mat3", "kick/math/Mat4", "kick/math/Vec3", "kick/math/Quat"],
    function (Constants, Util, Mat3, Mat4, Vec3, Quat) {
        "use strict";

        var ASSERT = Constants._ASSERT;

        /**
         * Datastructure used pass light information
         * @class SceneLights
         * @namespace kick.scene
         * @constructor
         * @param {Number} maxNumerOfLights (value from config)
         */
        return function (maxNumerOfLights) {
            var ambientLight = null,
                directionalLight = null,
                directionalLightData = new Float32Array(9), // column matrix with the columns lightDirection,colorIntensity,halfVector
                directionalLightEyeSpace = directionalLightData.subarray(0, 3),
                directionalLightColorIntensity = directionalLightData.subarray(3, 6),
                directionalHalfVector = directionalLightData.subarray(6, 9),
                directionalLightDirectionWorld = Vec3.clone([1, 0, 0]),
                directionalLightTransform = null,
                pointLightData = new Float32Array(9 * maxNumerOfLights), // mat3*maxNumerOfLights
                pointLightDataVec3 = Vec3.wrapArray(pointLightData),
                pointLights = [],
                lightDirection = [0, 0, -1],
                viewDirection = lightDirection,
                /**
                 * Set the point light to have not contribution this means setting the position 1,1,1, the color to 0,0,0
                 * and attenuation to 1,0,0.<br>
                 * This is needed since the ecLight position would otherwise be in 0,0,0 which is invalid
                 * @method resetPointLight
                 * @param {Number} index of point light
                 * @private
                 */
                resetPointLight = function (index) {
                    var i;
                    for (i = 0; i < 3; i++) {
                        Vec3.copy(pointLightDataVec3[index * 3 + i], [0, 0, 0]);
                    }
                };
            Object.defineProperties(this, {
                /**
                 * The ambient light in the scene.
                 * @property ambientLight
                 * @type kick.scene.Light
                 */
                ambientLight: {
                    get: function () {
                        return ambientLight;
                    },
                    set: function (value) {
                        if (ASSERT) {
                            if (value && ambientLight) {
                                throw new Error("Cannot have multiple ambient lights in the scene");
                            }
                        }
                        ambientLight = value;
                    }
                },
                /**
                 * The directional light in the scene.
                 * @property directionalLight
                 * @type kick.scene.Light
                 */
                directionalLight: {
                    get: function () {
                        return directionalLight;
                    },
                    set: function (value) {
                        if (ASSERT) {
                            if (value && directionalLight) {
                                throw new Error("Cannot have multiple directional lights in the scene");
                            }
                        }
                        directionalLight = value;
                        if (value !== null) {
                            directionalLightTransform = directionalLight.gameObject.transform;
                        } else {
                            directionalLightTransform = null;
                            Mat3.copy(directionalLightData, [0, 0, 0, 0, 0, 0, 0, 0, 0]);
                        }
                    }
                },
                /**
                 * Matrix of directional light data. Column 1 contains the light-direction in eye space,
                 * column 2 color intensity and column 3 half vector
                 * @property directionalLightData
                 * @type kick.math.Mat3
                 */
                directionalLightData: {
                    get: function () {
                        return directionalLightData;
                    }
                },
                /**
                 * Return the directional light in world space
                 * @property directionalLightWorld
                 * @type kick.math.Vec3
                 */
                directionalLightWorld: {
                    get: function () {
                        return directionalLightDirectionWorld;
                    }
                },
                /**
                 * Matrices of point light data. Each matrix (mat3) contains:<br>
                 * Column 1 vector: point light position in eye coordinates<br>
                 * Column 2 vector: color intensity<br>
                 * Column 3 vector: attenuation vector
                 * @property pointLightData
                 * @type Array of Mat3
                 */
                pointLightData: {
                    get: function () {
                        return pointLightData;
                    }
                }
            });

            /**
             * @method addPointLight
             * @param {kick.scene.Light} pointLight
             */
            this.addPointLight = function (pointLight) {
                if (!Util.contains(pointLights, pointLight)) {
                    if (pointLights.length === maxNumerOfLights) {
                        if (ASSERT) {
                            Util.fail("Only " + maxNumerOfLights + " point lights allowed in scene");
                        }
                    } else {
                        pointLights.push(pointLight);
                    }
                }
            };

            /**
             * @method removePointLight
             * @param {kick.scene.Light} pointLight
             */
            this.removePointLight = function (pointLight) {
                var index = pointLights.indexOf(pointLight);
                if (index >= 0) {
                    // remove element at position index
                    pointLights.splice(index, 1);
                } else {
                    if (ASSERT) {
                        Util.fail("Error removing point light");
                    }
                }
                resetPointLight(pointLights.length);
            };

            /**
             * Recompute the light based on the view-matrix. This method is called from the camera when the scene is
             * rendered, to transform the light into eye coordinates and compute the half vector for directional light
             * @method recomputeLight
             * @param {kick.math.Mat4} viewMatrix
             */
            this.recomputeLight = function (viewMatrix) {
                if (directionalLight !== null) {
                    // compute light direction
                    Quat.multiplyVec3(directionalLightDirectionWorld, directionalLightTransform.rotation, lightDirection);

                    // transform to eye space
                    Mat4.multiplyVec3Vector(directionalLightEyeSpace, viewMatrix, directionalLightDirectionWorld);
                    Vec3.normalize(directionalLightEyeSpace, directionalLightEyeSpace);

                    // compute half vector
                    Vec3.add(directionalHalfVector, viewDirection, directionalLightEyeSpace);
                    Vec3.normalize(directionalHalfVector, directionalHalfVector);

                    Vec3.copy(directionalLightColorIntensity, directionalLight.colorIntensity);
                }
                if (maxNumerOfLights) { // only run if max number of lights are 1 or above (otherwise JIT compiler will skip it)
                    var index = 0,
                        i,
                        pointLight,
                        pointLightPosition;
                    for (i = pointLights.length - 1; i >= 0; i--) {
                        pointLight = pointLights[i];
                        pointLightPosition = pointLight.transform.position;

                        Mat4.multiplyVec3(pointLightDataVec3[index], viewMatrix, pointLightPosition);
                        Vec3.copy(pointLightDataVec3[index + 1], pointLight.colorIntensity);
                        Vec3.copy(pointLightDataVec3[index + 2], pointLight.attenuation);
                        index += 3;
                    }
                }
            };

            (function init() {
                var i;
                for (i = 0; i < maxNumerOfLights; i++) {
                    resetPointLight(i);
                }
            }());
        };
    });