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;
/**
* ParticleSystem - 粒子系统
*
* 用于创建和管理粒子系统对象,实现烟雾、火焰、雨雪等粒子特效。
* @class ParticleSystem
* @memberof THING
* @extends THING.BaseTickableObject3D
* @public
* @example
const data = await THING.Utils.loadJSONFileAsync('https://model.3dmomoda.com/models/19061018snbajhvuzrheq9sbgwdoefuk/0/particles/index.json');
const fire = new THING.ParticleSystem({
id: 'fire01',
data
});
*/
class ParticleSystem extends BaseTickableObject3D {
/**
粒子系统对象构造函数。
* @param {object} param 初始参数。
* @param {string} [param.url] 粒子系统资源的URL路径。
* @param {object} [param.data] 粒子系统数据对象,包含粒子系统的配置和属性。
* 其他参数与 {@link THING.BaseTickableObject3D} 的构造函数相同。
* 请在 {@link THING.BaseTickableObject3D} 的文档中查看构造函数部分以获取详细参数列表。
* @constructor
* @public
*/
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) {
super.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;
}
/**
添加粒子组。
* @param {ParticleGroup} group 粒子组。
* @returns {ParticleGroup|undefined} 返回添加的粒子组。
* @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];
}
/**
移除粒子组。
* @param {ParticleGroup} 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();
}
/**
获取当前粒子系统的数据。
* @param {object} param { dataVersion2:false } 当dataVersion2为true时,获取ThingJS 2.0的数据。
* @returns {object} 粒子系统的数据
* @public
* @example
* const data = particleSystem.getParticleData({ dataVersion2:false });
*/
getParticleData(param) {
return this.node.getParticleData(param);
}
/**
Set root path.
* @param {string} value 根路径。
* @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) {
if (!this.isDynamicLoad) {
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) => {
if (this.destroyed) {
return false;
}
else {
this.body && 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 && this.body.setNode(node);
resolve();
}
else {
reject(`Parse particle data failed`);
}
}
else {
// Create default particle
const node = Utils.createObject('ParticleSystem', { app: this.app });
const particleGroup = Utils.createObject('ParticleGroup', { app: this.app });
const particleEmitter = Utils.createObject('ParticleEmitter', { app: this.app });
node.addGroup(particleGroup);
particleGroup.addEmitter(particleEmitter);
this.body.setNode(node);
resolve();
}
}
else {
resolve();
}
}
// #endregion
// #region Accessor
/**
获取粒子组
* @type {Array<ParticleGroup>}
* @public
*/
get groups() {
if (!this._groups) {
this._updateGroups();
}
return this._groups;
}
// #endregion
/**
检查是否为粒子系统类型或继承自粒子系统类型
* @type {boolean}
* @public
*/
get isParticleSystem() {
return true;
}
}
export { ParticleSystem }