import { Matrix3D, Vector3D } from '@awayjs/core'; import { ContextGLVertexBufferFormat } from '@awayjs/stage'; import { ShaderBase, _Render_RenderableBase, AnimationRegisterData } from '@awayjs/renderer'; import { AnimationElements } from '../data/AnimationElements'; import { ParticlePropertiesMode } from '../data/ParticlePropertiesMode'; import { ParticleOrbitNode } from '../nodes/ParticleOrbitNode'; import { ParticleAnimator } from '../ParticleAnimator'; import { ParticleStateBase } from './ParticleStateBase'; /** * ... */ export class ParticleOrbitState extends ParticleStateBase { /** @private */ public static ORBIT_INDEX: number = 0; /** @private */ public static EULERS_INDEX: number = 1; private _particleOrbitNode: ParticleOrbitNode; private _usesEulers: boolean; private _usesCycle: boolean; private _usesPhase: boolean; private _radius: number; private _cycleDuration: number; private _cyclePhase: number; private _eulers: Vector3D; private _orbitData: Vector3D; private _eulersMatrix: Matrix3D; /** * Defines the radius of the orbit when in global mode. Defaults to 100. */ public get radius(): number { return this._radius; } public set radius(value: number) { this._radius = value; this.updateOrbitData(); } /** * Defines the duration of the orbit in seconds, used as a period independent of particle duration when in global mode. Defaults to 1. */ public get cycleDuration(): number { return this._cycleDuration; } public set cycleDuration(value: number) { this._cycleDuration = value; this.updateOrbitData(); } /** * Defines the phase of the orbit in degrees, used as the starting offset of the cycle when in global mode. Defaults to 0. */ public get cyclePhase(): number { return this._cyclePhase; } public set cyclePhase(value: number) { this._cyclePhase = value; this.updateOrbitData(); } /** * Defines the euler rotation in degrees, applied to the orientation of the orbit when in global mode. */ public get eulers(): Vector3D { return this._eulers; } public set eulers(value: Vector3D) { this._eulers = value; this.updateOrbitData(); } constructor(animator: ParticleAnimator, particleOrbitNode: ParticleOrbitNode) { super(animator, particleOrbitNode); this._particleOrbitNode = particleOrbitNode; this._usesEulers = this._particleOrbitNode._iUsesEulers; this._usesCycle = this._particleOrbitNode._iUsesCycle; this._usesPhase = this._particleOrbitNode._iUsesPhase; this._eulers = this._particleOrbitNode._iEulers; this._radius = this._particleOrbitNode._iRadius; this._cycleDuration = this._particleOrbitNode._iCycleDuration; this._cyclePhase = this._particleOrbitNode._iCyclePhase; this.updateOrbitData(); } public setRenderState(shader: ShaderBase, renderable: _Render_RenderableBase, animationElements: AnimationElements, animationRegisterData: AnimationRegisterData): void { const index: number = animationRegisterData.getRegisterIndex(this._pAnimationNode, ParticleOrbitState.ORBIT_INDEX); if (this._particleOrbitNode.mode == ParticlePropertiesMode.LOCAL_STATIC) { if (this._usesPhase) animationElements.activateVertexBuffer(index, this._particleOrbitNode._iDataOffset, shader.stage, ContextGLVertexBufferFormat.FLOAT_4); else animationElements.activateVertexBuffer(index, this._particleOrbitNode._iDataOffset, shader.stage, ContextGLVertexBufferFormat.FLOAT_3); } else shader.setVertexConst(index, this._orbitData.x, this._orbitData.y, this._orbitData.z, this._orbitData.w); if (this._usesEulers) shader.setVertexConstFromMatrix(animationRegisterData.getRegisterIndex(this._pAnimationNode, ParticleOrbitState.EULERS_INDEX), this._eulersMatrix); } private updateOrbitData(): void { if (this._usesEulers) { this._eulersMatrix = new Matrix3D(); this._eulersMatrix.appendRotation(this._eulers.x, Vector3D.X_AXIS); this._eulersMatrix.appendRotation(this._eulers.y, Vector3D.Y_AXIS); this._eulersMatrix.appendRotation(this._eulers.z, Vector3D.Z_AXIS); } if (this._particleOrbitNode.mode == ParticlePropertiesMode.GLOBAL) { this._orbitData = new Vector3D(this._radius, 0, this._radius * Math.PI * 2, this._cyclePhase * Math.PI / 180); if (this._usesCycle) { if (this._cycleDuration <= 0) throw (new Error('the cycle duration must be greater than zero')); this._orbitData.y = Math.PI * 2 / this._cycleDuration; } else this._orbitData.y = Math.PI * 2; } } }