import { ColorTransform } from '@awayjs/core'; import { ShaderRegisterCache, ShaderRegisterElement } from '@awayjs/stage'; import { ShaderBase, AnimationRegisterData } from '@awayjs/renderer'; import { ParticlePropertiesMode } from '../data/ParticlePropertiesMode'; import { ColorSegmentPoint } from '../data/ColorSegmentPoint'; import { ParticleSegmentedColorState } from '../states/ParticleSegmentedColorState'; import { ParticleAnimationSet } from '../ParticleAnimationSet'; import { ParticleNodeBase } from './ParticleNodeBase'; /** * */ export class ParticleSegmentedColorNode extends ParticleNodeBase { /** @private */ public _iUsesMultiplier: boolean; /** @private */ public _iUsesOffset: boolean; /** @private */ public _iStartColor: ColorTransform; /** @private */ public _iEndColor: ColorTransform; /** @private */ public _iNumSegmentPoint: number; /** @private */ public _iSegmentPoints: Array; constructor(usesMultiplier: boolean, usesOffset: boolean, numSegmentPoint: number, startColor: ColorTransform, endColor: ColorTransform, segmentPoints: Array) { //because of the stage3d register limitation, it only support the global mode super('ParticleSegmentedColor', ParticlePropertiesMode.GLOBAL, 0, ParticleAnimationSet.COLOR_PRIORITY); this._pStateClass = ParticleSegmentedColorState; if (numSegmentPoint > 4) throw (new Error('the numSegmentPoint must be less or equal 4')); this._iUsesMultiplier = usesMultiplier; this._iUsesOffset = usesOffset; this._iNumSegmentPoint = numSegmentPoint; this._iStartColor = startColor; this._iEndColor = endColor; this._iSegmentPoints = segmentPoints; } /** * @inheritDoc */ public _iProcessAnimationSetting(particleAnimationSet: ParticleAnimationSet): void { if (this._iUsesMultiplier) particleAnimationSet.hasColorMulNode = true; if (this._iUsesOffset) particleAnimationSet.hasColorAddNode = true; } /** * @inheritDoc */ public getAGALVertexCode(shader: ShaderBase, animationSet: ParticleAnimationSet, registerCache: ShaderRegisterCache, animationRegisterData: AnimationRegisterData): string { let code: string = ''; if (shader.usesFragmentAnimation) { let accMultiplierColor: ShaderRegisterElement; //var accOffsetColor:ShaderRegisterElement; if (this._iUsesMultiplier) { accMultiplierColor = registerCache.getFreeVertexVectorTemp(); registerCache.addVertexTempUsages(accMultiplierColor, 1); } const tempColor: ShaderRegisterElement = registerCache.getFreeVertexVectorTemp(); registerCache.addVertexTempUsages(tempColor, 1); const temp: ShaderRegisterElement = registerCache.getFreeVertexVectorTemp(); const accTime: ShaderRegisterElement = new ShaderRegisterElement(temp.regName, temp.index, 0); let tempTime: ShaderRegisterElement = new ShaderRegisterElement(temp.regName, temp.index, 1); if (this._iUsesMultiplier) registerCache.removeVertexTempUsage(accMultiplierColor); registerCache.removeVertexTempUsage(tempColor); //for saving all the life values (at most 4) const lifeTimeRegister: ShaderRegisterElement = registerCache.getFreeVertexConstant(); animationRegisterData.setRegisterIndex(this, ParticleSegmentedColorState.TIME_DATA_INDEX, lifeTimeRegister.index); let i: number; let startMulValue: ShaderRegisterElement; let deltaMulValues: Array; if (this._iUsesMultiplier) { startMulValue = registerCache.getFreeVertexConstant(); animationRegisterData.setRegisterIndex(this, ParticleSegmentedColorState.START_MULTIPLIER_INDEX, startMulValue.index); deltaMulValues = new Array(); for (i = 0; i < this._iNumSegmentPoint + 1; i++) deltaMulValues.push(registerCache.getFreeVertexConstant()); } let startOffsetValue: ShaderRegisterElement; let deltaOffsetValues: Array; if (this._iUsesOffset) { startOffsetValue = registerCache.getFreeVertexConstant(); animationRegisterData.setRegisterIndex(this, ParticleSegmentedColorState.START_OFFSET_INDEX, startOffsetValue.index); deltaOffsetValues = new Array(); for (i = 0; i < this._iNumSegmentPoint + 1; i++) deltaOffsetValues.push(registerCache.getFreeVertexConstant()); } if (this._iUsesMultiplier) code += 'mov ' + accMultiplierColor + ',' + startMulValue + '\n'; if (this._iUsesOffset) code += 'add ' + animationRegisterData.colorAddTarget + ',' + animationRegisterData.colorAddTarget + ',' + startOffsetValue + '\n'; for (i = 0; i < this._iNumSegmentPoint; i++) { switch (i) { case 0: code += 'min ' + tempTime + ',' + animationRegisterData.vertexLife + ',' + lifeTimeRegister + '.x\n'; break; case 1: code += 'sub ' + accTime + ',' + animationRegisterData.vertexLife + ',' + lifeTimeRegister + '.x\n'; code += 'max ' + tempTime + ',' + accTime + ',' + animationRegisterData.vertexZeroConst + '\n'; code += 'min ' + tempTime + ',' + tempTime + ',' + lifeTimeRegister + '.y\n'; break; case 2: code += 'sub ' + accTime + ',' + accTime + ',' + lifeTimeRegister + '.y\n'; code += 'max ' + tempTime + ',' + accTime + ',' + animationRegisterData.vertexZeroConst + '\n'; code += 'min ' + tempTime + ',' + tempTime + ',' + lifeTimeRegister + '.z\n'; break; case 3: code += 'sub ' + accTime + ',' + accTime + ',' + lifeTimeRegister + '.z\n'; code += 'max ' + tempTime + ',' + accTime + ',' + animationRegisterData.vertexZeroConst + '\n'; code += 'min ' + tempTime + ',' + tempTime + ',' + lifeTimeRegister + '.w\n'; break; } if (this._iUsesMultiplier) { code += 'mul ' + tempColor + ',' + tempTime + ',' + deltaMulValues[i] + '\n'; code += 'add ' + accMultiplierColor + ',' + accMultiplierColor + ',' + tempColor + '\n'; } if (this._iUsesOffset) { code += 'mul ' + tempColor + ',' + tempTime + ',' + deltaOffsetValues[i] + '\n'; code += 'add ' + animationRegisterData.colorAddTarget + ',' + animationRegisterData.colorAddTarget + ',' + tempColor + '\n'; } } //for the last segment: if (this._iNumSegmentPoint == 0) tempTime = animationRegisterData.vertexLife; else { switch (this._iNumSegmentPoint) { case 1: code += 'sub ' + accTime + ',' + animationRegisterData.vertexLife + ',' + lifeTimeRegister + '.x\n'; break; case 2: code += 'sub ' + accTime + ',' + accTime + ',' + lifeTimeRegister + '.y\n'; break; case 3: code += 'sub ' + accTime + ',' + accTime + ',' + lifeTimeRegister + '.z\n'; break; case 4: code += 'sub ' + accTime + ',' + accTime + ',' + lifeTimeRegister + '.w\n'; break; } code += 'max ' + tempTime + ',' + accTime + ',' + animationRegisterData.vertexZeroConst + '\n'; } if (this._iUsesMultiplier) { code += 'mul ' + tempColor + ',' + tempTime + ',' + deltaMulValues[this._iNumSegmentPoint] + '\n'; code += 'add ' + accMultiplierColor + ',' + accMultiplierColor + ',' + tempColor + '\n'; code += 'mul ' + animationRegisterData.colorMulTarget + ',' + animationRegisterData.colorMulTarget + ',' + accMultiplierColor + '\n'; } if (this._iUsesOffset) { code += 'mul ' + tempColor + ',' + tempTime + ',' + deltaOffsetValues[this._iNumSegmentPoint] + '\n'; code += 'add ' + animationRegisterData.colorAddTarget + ',' + animationRegisterData.colorAddTarget + ',' + tempColor + '\n'; } } return code; } }