define(["kick/core/Constants", "kick/core/Util", "kick/math/Vec3", "kick/texture/Texture", "kick/texture/RenderTexture", "kick/core/EngineSingleton"],
function (Constants, Util, Vec3, Texture, RenderTexture, EngineSingleton) {
"use strict";
var ASSERT = Constants._ASSERT,
Light;
/**
* A light object.<br>
* Note that each scene can only have one ambient light and one directional light.
* The directional light points in (0,0,1) direction (transformed by the GameObject transform)
* @example
* var lightGameObject = engine.activeScene.createGameObject();
* lightGameObject.transform.position = [0,0,10];
*
* // add point light
* var lightComponent = new kick.scene.Light({type:kick.scene.Light.TYPE_POINT});
* lightGameObject.addComponent(lightComponent);
*
* // add ambient light (only one per scene)
* var ambientLightComponent = new kick.scene.Light({type:kick.scene.Light.TYPE_AMBIENT, colorIntensity: [0.1,0.1,0.1] });
* lightGameObject.addComponent(ambientLightComponent);
*
* @class Light
* @namespace kick.scene
* @extends kick.scene.Component
* @constructor
* @param {Object} config
* @final
*/
Light = function (config) {
var thisObj = this,
color = Vec3.clone([1.0, 1.0, 1.0]),
engine = EngineSingleton.engine,
type = 3, // point light
_shadow = false,
_shadowStrength = 1.0,
_shadowBias = 0.05,
_shadowTexture = null,
_shadowRenderTexture = null,
attenuation = Vec3.clone([1, 0, 0]),
intensity = 1,
transform,
colorIntensity = Vec3.clone([1.0, 1.0, 1.0]),
updateIntensity = function () {
Vec3.copy(colorIntensity, [color[0] * intensity, color[1] * intensity, color[2] * intensity]);
},
gameObject,
initialized = false,
scriptPriority,
updateShadowTexture = function () {
if (_shadow) {
if (!_shadowTexture) {
_shadowTexture = new Texture({
minFilter: Constants.GL_NEAREST,
magFilter: Constants.GL_NEAREST,
wrapS: Constants.GL_CLAMP_TO_EDGE,
wrapT: Constants.GL_CLAMP_TO_EDGE,
flipY: false,
generateMipmaps: false
});
var maxTextureSize = Math.min(engine.gl.getParameter(Constants.GL_MAX_RENDERBUFFER_SIZE),
engine.gl.getParameter(Constants.GL_MAX_TEXTURE_SIZE));
maxTextureSize = Math.min(maxTextureSize, 4096) * engine.config.shadowMapQuality;
_shadowTexture.setImageData(maxTextureSize, maxTextureSize, 0, Constants.GL_UNSIGNED_BYTE, null, "");
_shadowRenderTexture = new RenderTexture({
colorTexture: _shadowTexture
});
}
} else if (_shadowRenderTexture) {
_shadowRenderTexture.destroy();
_shadowTexture.destroy();
_shadowRenderTexture = null;
_shadowTexture = null;
}
};
Object.defineProperties(this, {
/**
* Short for lightObj.gameObject.transform
* @property transform
* @type kick.scene.Transform
*/
transform: {
get: function () {
return transform;
}
},
/**
* @property shadowRenderTexture
* @type kick.texture.RenderTexture
*/
shadowRenderTexture: {
get: function () {
return _shadowRenderTexture;
}
},
/**
* @property shadowTexture
* @type kick.texture.Texture
*/
shadowTexture: {
get: function () {
return _shadowTexture;
}
},
/**
* Default value is false.
* Only directional light supports shadows.
* @property shadow
* @type boolean
* @default false
*/
shadow: {
get: function () {
return _shadow;
},
set: function (value) {
if (value !== _shadow) {
_shadow = value;
if (initialized) {
updateShadowTexture();
}
}
},
enumerable: true
},
/**
* Shadow strength (between 0.0 and 1.0).
* @property shadowStrength
* @type Number
* @default 1.0
*/
shadowStrength: {
get: function () {
return _shadowStrength;
},
set: function (value) {
_shadowStrength = value;
},
enumerable: true
},
/**
* Shadow bias.
* @property shadowBias
* @type Number
* @default 0.05
*/
shadowBias: {
get: function () {
return _shadowBias;
},
set: function (value) {
_shadowBias = value;
},
enumerable: true
},
/**
* Color intensity of the light (RGB).
* @property color
* @type kick.math.Vec3
* @default [1,1,1]
*/
color: {
get: function () {
return Vec3.clone(color);
},
set: function (value) {
if (ASSERT) {
if (value.length !== 3) {
Util.fail("Light color must be vec3");
}
}
Vec3.copy(color, value);
updateIntensity();
},
enumerable: true
},
/**
* Color type. Must be either:<br>
* Light.TYPE\_AMBIENT,
* Light.TYPE\_DIRECTIONAL,
* Light.TYPE\_POINT <br>
* Note that this value is readonly after initialization. To change it create a new Light component and replace the current light
* component of its gameObject.
* @property type
* @type Enum
* @final
* @default Light.TYPE_POINT
*/
type: {
get: function () {
return type;
},
set: function (newValue) {
if (!initialized) {
type = newValue;
} else {
if (ASSERT) {
Util.fail("Light type cannot be changed after initialization");
}
}
},
enumerable: true
},
/**
* Light intensity (a multiplier to color)
* @property intensity
* @type Number
* @default 1
*/
intensity: {
get: function () {
return intensity;
},
set: function (value) {
intensity = value;
updateIntensity();
},
enumerable: true
},
/**
* Specifies the light falloff.<br>
* attenuation[0] is constant attenuation,<br>
* attenuation[1] is linear attenuation,<br>
* attenuation[2] is quadratic attenuation.<br>
* @property attenuation
* @type kick.math.Vec3
* @default [1,0,0]
*/
attenuation: {
get: function () {
return attenuation;
},
set: function (newValue) {
Vec3.copy(attenuation, newValue);
},
enumerable: true
},
/**
* color RGB multiplied with intensity (plus color A).<br>
* This property exposes a internal value. This value should not be modified.
* Instead use the intensity and color property.
* @property colorIntensity
* @type kick.math.Vec3
* @final
*/
colorIntensity: {
get: function () {
return colorIntensity;
},
set: function (newValue) {
colorIntensity = newValue;
},
enumerable: true
},
// inherited interface from component
gameObject: {
get: function () {
return gameObject;
},
set: function (value) {
gameObject = value;
}
},
// inherited interface from component
scriptPriority: {
get: function () {
return scriptPriority;
},
set: function (value) {
scriptPriority = value;
},
enumerable: true
},
/**
* Name of the component componentType = "meshRenderer".
* @example
* var light = gameObject.light;
* @property componentType
* @type String
* @final
*/
componentType: {value:"light"}
});
this.activated = function () {
var gameObject = thisObj.gameObject;
initialized = true;
transform = gameObject.transform;
updateShadowTexture();
};
/**
* @method toJSON
* @return {JSON}
*/
this.toJSON = function () {
return Util.componentToJSON(this, "kick.scene.Light");
};
Util.applyConfig(this, config);
Util.copyStaticPropertiesToObject(this, Light);
};
/**
* Used to define ambient color in the scene (indirect lightening)
* @property TYPE_AMBIENT
* @type Number
* @static
*/
Light.TYPE_AMBIENT = 1;
/**
* Used to define directional light in the scene (such as sunlight)
* @property TYPE_DIRECTIONAL
* @type Number
* @static
*/
Light.TYPE_DIRECTIONAL = 2;
/**
* Used to define point light in the scene
* @property TYPE_POINT
* @type Number
* @static
*/
Light.TYPE_POINT = 3;
Object.freeze(Light);
return Light;
});