Source: objects/ParticleSystem.js

import { Utils } from '../common/Utils';
import { BaseTickableObject3D } from './BaseTickableObject3D';
import { ParticleGroup } from './ParticleGroup';
import { Object3D } from './Object3D';
import { StyleModifier } from '../resources/StyleModifier';
import { Style } from '../resources/Style';

let dummyStyle;

/**
 * @class ParticleSystem
 * The particle system object.
 * @memberof THING
 * @extends THING.BaseTickableObject3D
 * @public
 */
class ParticleSystem extends BaseTickableObject3D {

	/**
	 * The particle system object in scene.
	 * @param {Object} param The initial parameters.
	 */
	constructor(param = {}) {
		super(param);
		const gl = this.app.camera.bodyNode.$uAppView._renderer.context;
		const sizeMax = gl.getParameter(gl.ALIASED_POINT_SIZE_RANGE)[1];
		if (sizeMax < 1024) {
			console.warn("The maximum settable gl_pointSize supported by the current browser is " + sizeMax + ", when the calculated value exceeds this value, the display may be incorrect.");
		}
	}

	// #region BaseObject Interface

	onUpdate(deltaTime) {
		if (this.loaded) {
			this.bodyNode.update(deltaTime, this.app.camera.node);
		}
	}

	getStyle() {
		dummyStyle = dummyStyle || new Style(new StyleModifier(new Object3D({ parent: null })));

		console.warn("This interface cannot be used for particle!");
		return dummyStyle;
	}

	/**
	 * Add group.
	 * @param {ParticleGroup} group The group.
	 * @returns {ParticleGroup}
	 * @public
	 * @example
	 * 	const group = new THING.ParticleGroup();
	 * 	particleSystem.addGroup(group);
	 */
	addGroup(group) {
		let node = group.node;

		if (!this.node) {
			return;
		}

		this.node.addGroup(node);

		this._updateGroups();

		return this.groups[this.groups.length - 1];
	}

	/**
	 * Remove group.
	 * @param {ParticleGroup} group The group.
	 * @public
	 * @example
	 * 	const groups = particleSystem.getGroups();
	 * 	particleSystem.removeGroup(groups[0]);
	 */
	removeGroup(group) {
		if (!this.node) {
			return;
		}

		if (this.groups.length == 0) {
			return;
		}

		this.node.removeGroup(group.node);
		this._updateGroups();
	}

	_updateGroups() {
		this._groups = [];

		const that = this;
		this.getGroups().forEach(node => {
			const group = new ParticleGroup({ node });
			that._groups.push(group);
		})
	}

	/**
	 * Get group.
	 * @returns {Array<ParticleGroup>}
	 * @private
	 * @example
	 * 	const groups = particleSystem.getGroups();
	 */
	getGroups() {
		return this.node.getGroups();
	}

	/**
	 * Get current ParticleSystem data.
	 * @param {Object} param { dataVersion2:false } Get data for thingjs2.0 when dataVersion2 is true.
	 * @returns {Object} ParticleSystem data
	 * @public
	 * @example
	 * 	const data = particleSystem.getParticleData({ dataVersion2:false });
	 */
	getParticleData(param) {
		return this.node.getParticleData(param);
	}

	/**
	 * Set root path.
	 * @param {String} The root path.
	 * @private
	 */
	setRootPath(value) {
		this.node.setRootPath(value);
	}

	/**
	 * Get root path.
	 * @returns {String}
	 * @private
	 */
	getRootPath() {
		return this.node.getRootPath();
	}

	// #endregion

	// #region Resources

	/**
	 * When load reosurce.
	 * @param {Object} options The options to load.
	 * @param {Function} resolve The promise resolve callback function.
	 * @param {Function} reject The promise reject callback function.
	 * @private
	 */
	onLoadResource(options, resolve, reject) {
		let dynamic = Utils.parseValue(options['dynamic'], false);
		if (!dynamic) {
			let app = this.app;
			options['screenSize'] = options['screenSize'] || app.size;
			options['maxVaryings'] = options['maxVaryings'] || app.renderCapabilities.maxVaryings;

			// Start to load particle resource
			let url = this.resource.url;
			if (url) {
				app.resourceManager.loadParticle(
					this.resource.url,
					(ev) => {
						this.body.setNode(ev.node);

						resolve();
					},
					(ev) => {
					},
					(ev) => {
						reject(ev);
					},
					options
				);
			}
			// Load from data
			else if (options['data']) {
				let node = app.resourceManager.parseParticle(options['data'], options);
				if (node) {
					this.body.setNode(node);

					resolve();
				}
				else {
					reject(`Parse particle data failed`);
				}
			}
			else {
				// Create default particle
				const node = Utils.createObject('ParticleSystem');
				const particleGroup = Utils.createObject('ParticleGroup');
				const particleEmitter = Utils.createObject('ParticleEmitter');
				node.addGroup(particleGroup);
				particleGroup.addEmitter(particleEmitter);
				this.body.setNode(node);

				resolve();
			}
		}
		else {
			resolve();
		}
	}

	// #endregion

	// #region Accessor

	/**
	 * Get groups.
	 * @type {Array<ParticleGroup>}
	 * @public
	 */
	get groups() {
		if (!this._groups) {
			this._updateGroups();
		}

		return this._groups;
	}

	// #endregion

	/**
	 * Check whether it's ParticleSystem type or inherit from it.
	 * @type {Boolean}
	 * @public
	 */
	get isParticleSystem() {
		return true;
	}

}

export { ParticleSystem }