Source: components/CameraDynamicSkyComponent.js

import { CubeTexture, DirectionalLight, HemisphereLight, ImageWrapType, MathUtils, Utils } from "../main";
import { BaseComponent } from "./BaseComponent";

const __ = {
	private: Symbol('private'),
}

let _tempArray = [];

/**
 * @class DynamicSky
 * The dynamic sky.
 * @memberof THING
 * @extends THING.BaseComponent
 */
class CameraDynamicSkyComponent extends BaseComponent {

	constructor() {
		super();

		this[__.private] = {};
		let _private = this[__.private];


		_private.enable = false;
	}

	// #region Private Functions

	/**
	 * Load the stars data
	 * @param {String | Float32Array} data
	 * @private
	 */
	async _loadStarsData(data) {
		if (Utils.isString(data)) {
			let _buffer = await Utils.loadBinaryFile(data);
			let starsData = new Float32Array(_buffer);
			return starsData;
		}
		if (!(data instanceof Float32Array)) {
			return null;
		}
	}

	/**
	 * Update the lights.
	 * @param {String | Float32Array} data
	 * @private
	 */
	_updateLights() {
		let _private = this[__.private];

		_private._dynamicSky.getSunPhiAndTheta(_tempArray);
		_private.sunLight.adapter.vertAngle = MathUtils.radToDeg(_tempArray[1]);
		_private.sunLight.adapter.horzAngle = MathUtils.radToDeg(_tempArray[0]);
		_private.sunLight.color = _private._dynamicSky.getSunLightColor(_tempArray);


		_private._dynamicSky.getMoonPhiAndTheta(_tempArray);
		_private.moonLight.adapter.vertAngle = MathUtils.radToDeg(_tempArray[1]);
		_private.moonLight.adapter.horzAngle = MathUtils.radToDeg(_tempArray[0]);
		_private.moonLight.color = _private._dynamicSky.getMoonLightColor(_tempArray);

		_private.hemisphereLight.color = _private._dynamicSky.getHemisphereLightColor(_tempArray);
		_private.hemisphereLight.groundColor = _private._dynamicSky.getHemisphereLightGroundColor(_tempArray);
	}

	// #endregion

	// #region BaseComponent Overrides

	onRemove() {
		let _private = this[__.private];
		if (_private._dynamicSky) {
			_private._dynamicSky.dispose();
		}

		super.onRemove();
	}

	onUpdate(deltaTime) {
		let _private = this[__.private];


		if (_private._dynamicSky && this.enable) {
			_private._dynamicSky.update(deltaTime);
		}
	}

	/**
	 * Get/Set enable of sky.
	 * @type {Boolean}
	 * @public
	 */
	async init(options) {
		let _private = this[__.private];
		if (!_private._dynamicSky) {
			_private.envMap = new CubeTexture();

			_private.sunLight = THING.App.current.scene.mainLight;
			_private.moonLight = new DirectionalLight({
				intensity: 0.2
			});
			_private.moonLight.adapter.bind(THING.App.current.scene.mainLight.adapter.bindingObject);
			_private.hemisphereLight = new HemisphereLight({
				intensity: 0.2
			});

			_private._dynamicSky = Utils.createObject('DynamicSky', {
				sunLight: _private.sunLight.node,
				moonLight: _private.moonLight.node,
				hemisphereLight: _private.hemisphereLight.node,
				cubeTexture: _private.envMap.getTextureResource()
			});
		}

		let nightSkyTexture = options.nightSkyTexture;
		if (nightSkyTexture) {
			_private._dynamicSky.setNightSkyTexture(nightSkyTexture.getTextureResource());
		}

		let moonTexture = options.moonTexture;
		if (moonTexture) {
			moonTexture.wrapTypeT = ImageWrapType.ClampToEdge;
			moonTexture.wrapTypeS = ImageWrapType.ClampToEdge;
			_private._dynamicSky.setMoonTexture(moonTexture.getTextureResource());
		}

		let cloudsTexture = options.cloudsTexture;
		if (cloudsTexture) {
			_private._dynamicSky.setCloudsTexture(cloudsTexture.getTextureResource());
		}

		let starsData = await this._loadStarsData(options.starsData);
		_private._dynamicSky.setStarsData(starsData);

		if (_private.enable) {
			this.object.background = _private.envMap;
		}
	}

	// #endregion

	/**
	 * Get/Set enable of sky.
	 * @type {Boolean}
	 * @public
	 */
	get enable() {
		let _private = this[__.private];

		return _private.enable;
	}

	set enable(value) {
		let _private = this[__.private];

		if (_private.enable == value) {
			return;
		}

		if (value) {
			this.object.background = _private.envMap;
		}
		else {
			if (_private.enable) {
				this.object.background = null;
			}
		}

		_private.enable = value;
	}

	/**
	 * Set map of sky.
	 * @type {CubeTextureResource}
	 * @public
	 */
	set map(value) {
		if (!value) {
			return;
		}

		let _private = this[__.private];

		_private._dynamicSky.setNightSkyTexture(value.getTextureResource());
	}

	/**
	 * Set clouds texture of sky.
	 * @type {ImageTextureResource}
	 * @public
	 */
	set cloudsTexture(value) {
		if (!value) {
			return;
		}
		let _private = this[__.private];

		_private._dynamicSky.setCloudsTexture(value.getTextureResource());
	}

	/**
	 * Set moon texture of sky.
	 * @type {ImageTextureResource}
	 * @public
	 */
	set moonTexture(value) {
		if (!value) {
			return;
		}
		let _private = this[__.private];

		_private._dynamicSky.setMoonTexture(value.getTextureResource());
	}

	/**
	 * Set stars data of sky.
	 * @type {String | Float32Array}
	 * @public
	 */
	set starsData(value) {
		if (!value) {
			return;
		}
		let _private = this[__.private];

		this._loadStarsData(value).then((data) => {
			_private._dynamicSky.setStarsData(data);
		})
	}

	/**
	 * Get the texture of sky.
	 * @type {CubeTextureResource}
	 * @public
	 */
	get envMap() {
		let _private = this[__.private];

		return _private.envMap;
	}

	/**
	 * Set/Get size of texture.
	 * @type {Array<Number>}
	 * @default - [1024,1024]
	 * @public
	 */
	set textureSize(value) {
		let _private = this[__.private];

		return _private._dynamicSky.setTextureSize(value);
	}
	get textureSize() {
		let _private = this[__.private];

		return _private._dynamicSky.getTextureSize(_tempArray);
	}

	/**
	 * Set/Get exposure of sky.
	 * @type {Number}
	 * @default 0.8
	 * @public
	 */
	get exposure() {
		let _private = this[__.private];

		return _private._dynamicSky.getExposure();
	}

	set exposure(value) {
		let _private = this[__.private];

		_private._dynamicSky.setExposure(value);
	}

	/**
	 * Set/Get light exposure of sky.
	 * @type {Number}
	 * @default 1.0
	 * @public
	 */
	get lightExposure() {
		let _private = this[__.private];

		return _private._dynamicSky.getLightExposure();
	}

	set lightExposure(value) {
		let _private = this[__.private];

		_private._dynamicSky.setLightExposure(value);
	}

	/**
	 * Set/Get timeline.
	 * @type {Number}
	 * @default 13
	 * @public
	 */
	get timeline() {
		let _private = this[__.private];

		return _private._dynamicSky.getTimeline();
	}

	set timeline(value) {
		let _private = this[__.private];

		_private._dynamicSky.setTimeline(value);

		this._updateLights();
	}

	/**
	 * Set/Get sun equator offset.
	 * @type {Number}
	 * @default -40
	 * @public
	 */
	get sunEquatorOffset() {
		let _private = this[__.private];

		return _private._dynamicSky.getSunEquatorOffset();
	}

	set sunEquatorOffset(value) {
		let _private = this[__.private];

		_private._dynamicSky.setSunEquatorOffset(value);

		this._updateLights();
	}

	/**
	 * Get moon light.
	 * @type {DirectionalLight}
	 * @public
	 */
	get moonLight() {
		let _private = this[__.private];

		return _private.moonLight;
	}

	/**
	 * Get hemisphere light.
	 * @type {HemisphereLight}
	 * @public
	 */
	get hemisphereLight() {
		let _private = this[__.private];

		return _private.hemisphereLight;
	}

}

export { CameraDynamicSkyComponent }