Files
Nitro_Render_V3/packages/room/src/object/visualization/furniture/FurnitureParticleSystem.ts
T
2024-09-13 08:04:35 +02:00

335 lines
12 KiB
TypeScript

import { IAdvancedMap, IGraphicAsset, IParticleSystem, IRoomObjectSprite } from '@nitrots/api';
import { AdvancedMap, TextureUtils, Vector3d } from '@nitrots/utils';
import { AlphaFilter, Graphics, Matrix, Point, Sprite, Texture } from 'pixi.js';
import { FurnitureAnimatedVisualization } from './FurnitureAnimatedVisualization';
import { FurnitureParticleSystemEmitter } from './FurnitureParticleSystemEmitter';
export class FurnitureParticleSystem
{
private _emitters: IAdvancedMap<number, FurnitureParticleSystemEmitter>;
private _visualization: FurnitureAnimatedVisualization;
private _size: number;
private _canvasId: number = -1;
private _offsetY: number;
private _currentEmitter: FurnitureParticleSystemEmitter;
private _canvasTexture: Texture;
private _roomSprite: IRoomObjectSprite;
private _hasIgnited: boolean = false;
private _centerX: number = 0;
private _centerY: number = 0;
private _scaleMultiplier: number = 1;
private _blackOverlay: Graphics;
private _blackOverlayAlphaTransform: AlphaFilter;
private _particleColorTransform: AlphaFilter;
private _identityMatrix: Matrix;
private _translationMatrix: Matrix;
private _blend: number = 1;
private _bgColor: number = 0xFF000000;
private _emptySprite: Sprite;
private _particleSprite: Sprite;
private _isDone: boolean = false;
constructor(visualization: FurnitureAnimatedVisualization)
{
this._emitters = new AdvancedMap();
this._visualization = visualization;
this._blackOverlayAlphaTransform = new AlphaFilter();
this._blackOverlayAlphaTransform.alpha = 1;
this._particleColorTransform = new AlphaFilter();
this._identityMatrix = new Matrix();
this._translationMatrix = new Matrix();
this._particleSprite = new Sprite();
}
public dispose(): void
{
for(const emitter of this._emitters.getValues()) emitter.dispose();
this._emitters = null;
if(this._canvasTexture)
{
this._canvasTexture.destroy();
this._canvasTexture = null;
}
if(this._blackOverlay)
{
this._blackOverlay.destroy();
this._blackOverlay = null;
}
if(this._emptySprite)
{
this._emptySprite.destroy();
this._emptySprite = null;
}
if (this._particleSprite)
{
this._particleSprite.destroy();
this._particleSprite = null;
}
this._blackOverlayAlphaTransform = null;
this._particleColorTransform = null;
this._identityMatrix = null;
this._translationMatrix = null;
}
public reset(): void
{
if(this._currentEmitter) this._currentEmitter.reset();
this._currentEmitter = null;
this._hasIgnited = false;
this._isDone = false;
this.updateCanvas();
}
public setAnimation(id: number): void
{
if(this._currentEmitter) this._currentEmitter.reset();
this._currentEmitter = this._emitters.getValue(id);
this._hasIgnited = false;
this._isDone = false;
this.updateCanvas();
}
private updateCanvas(): void
{
if(!this._currentEmitter || (this._canvasId === -1)) return;
this._roomSprite = this._visualization.getSprite(this._canvasId);
if(this._roomSprite && this._roomSprite.texture)
{
if((this._roomSprite.width <= 1) || (this._roomSprite.height <= 1)) return;
if(this._canvasTexture && ((this._canvasTexture.width !== this._roomSprite.width) || (this._canvasTexture.height !== this._roomSprite.height)))
{
this._canvasTexture.destroy();
this._canvasTexture = null;
}
this.clearCanvas();
this._centerX = -(this._roomSprite.offsetX);
this._centerY = -(this._roomSprite.offsetY);
this._roomSprite.texture = this._canvasTexture;
}
}
public getLayerYOffset(scale: number, direction: number, layerId: number): number
{
if(this._currentEmitter && (this._currentEmitter.roomObjectSpriteId === layerId))
{
return this._currentEmitter.y * this._scaleMultiplier;
}
return 0;
}
public controlsSprite(k: number): boolean
{
if(this._currentEmitter) return this._currentEmitter.roomObjectSpriteId == k;
return false;
}
public updateSprites(): void
{
if(!this._currentEmitter || !this._roomSprite) return;
if(this._canvasTexture && (this._roomSprite.texture !== this._canvasTexture))
{
this._roomSprite.texture = this._canvasTexture;
}
if(this._hasIgnited)
{
if(this._currentEmitter.roomObjectSpriteId >= 0) this._visualization.getSprite(this._currentEmitter.roomObjectSpriteId).visible = false;
}
}
public updateAnimation(): void
{
if(!this._currentEmitter || !this._roomSprite || this._isDone) return;
const k = 10;
if(!this._hasIgnited && this._currentEmitter.hasIgnited) this._hasIgnited = true;
const offsetY = (this._offsetY * this._scaleMultiplier);
this._currentEmitter.update();
if(this._hasIgnited)
{
if(this._currentEmitter.roomObjectSpriteId >= 0)
{
this._visualization.getSprite(this._currentEmitter.roomObjectSpriteId).visible = false;
}
if(!this._canvasTexture) this.updateCanvas();
this.clearCanvas();
for(const particle of this._currentEmitter.particles)
{
const tx = (this._centerX + ((((particle.x - particle.z) * k) / 10) * this._scaleMultiplier));
const ty = ((this._centerY - offsetY) + ((((particle.y + ((particle.x + particle.z) / 2)) * k) / 10) * this._scaleMultiplier));
const asset = particle.getAsset();
this._particleSprite.texture = null;
this._particleSprite.tint = 0xFFFFFF;
this._particleSprite.width = 1;
this._particleSprite.height = 1;
this._particleSprite.x = 0;
this._particleSprite.y = 0;
this._particleSprite.filters = [];
if(asset && asset.texture)
{
this._particleSprite.texture = asset.texture;
this._particleSprite.width = asset.texture.width;
this._particleSprite.height = asset.texture.height;
if(particle.fade && (particle.alphaMultiplier < 1))
{
this._translationMatrix.identity();
this._translationMatrix.translate((tx + asset.offsetX), (ty + asset.offsetY));
this._particleColorTransform.alpha = particle.alphaMultiplier;
this._particleSprite.filters = [this._particleColorTransform];
TextureUtils.writeToTexture(this._particleSprite, this._canvasTexture, false, this._translationMatrix);
}
else
{
const point = new Point((tx + asset.offsetX), (ty + asset.offsetY));
this._particleSprite.x = point.x;
this._particleSprite.y = point.y;
TextureUtils.writeToTexture(this._particleSprite, this._canvasTexture, false);
}
}
else
{
this._particleSprite.tint = 0xFFFFFF;
this._particleSprite.x = (tx - 1);
this._particleSprite.y = (ty - 1);
this._particleSprite.width = 2;
this._particleSprite.height = 2;
TextureUtils.writeToTexture(this._particleSprite, this._canvasTexture, false);
}
}
if(!this._currentEmitter.particles.length)
{
this._isDone = true;
return;
}
}
}
public parseData(particleSystem: IParticleSystem): void
{
this._size = particleSystem.size;
this._canvasId = ((particleSystem.canvasId !== undefined) ? particleSystem.canvasId : -1);
this._offsetY = ((particleSystem.offsetY !== undefined) ? particleSystem.offsetY : 10);
this._scaleMultiplier = (this._size / 64);
this._blend = ((particleSystem.blend !== undefined) ? particleSystem.blend : 1);
this._blend = Math.min(this._blend, 1);
this._blackOverlayAlphaTransform.alpha = this._blend;
const bgColor = ((particleSystem.bgColor !== undefined) ? particleSystem.bgColor : '0');
this._bgColor = (parseInt(bgColor, 16) || 0x000000);
if(!particleSystem.emitters || !particleSystem.emitters.length) return;
for(const emitter of particleSystem.emitters)
{
const emitterId = emitter.id;
const emitterName = emitter.name;
const emitterSpriteId = emitter.spriteId;
const particleEmitter = new FurnitureParticleSystemEmitter(emitterName, emitterSpriteId);
this._emitters.add(emitterId, particleEmitter);
const maxNumParticles = emitter.maxNumParticles;
const particlesPerFrame = emitter.particlesPerFrame;
const burstPulse = ((emitter.burstPulse !== undefined) ? emitter.burstPulse : 1);
const fuseTime = emitter.fuseTime;
const simulationForce = emitter.simulation.force;
const simulationDirection = emitter.simulation.direction;
const simulationGravity = emitter.simulation.gravity;
const simulationAirFriction = emitter.simulation.airFriction;
const simulationShape = emitter.simulation.shape;
const simulationEnergy = emitter.simulation.energy;
for(const particle of emitter.particles)
{
const lifeTime = particle.lifeTime;
const isEmitter = (particle.isEmitter || false);
const fade = (particle.fade || false);
const frames: IGraphicAsset[] = [];
for(const name of particle.frames) frames.push(this._visualization.asset.getAsset(name));
particleEmitter.configureParticle(lifeTime, isEmitter, frames, fade);
}
particleEmitter.setup(maxNumParticles, particlesPerFrame, simulationForce, new Vector3d(0, simulationDirection, 0), simulationGravity, simulationAirFriction, simulationShape, simulationEnergy, fuseTime, burstPulse);
}
}
public copyStateFrom(particleSystem: FurnitureParticleSystem): void
{
let emitterId = 0;
if(particleSystem._emitters && particleSystem._currentEmitter)
{
emitterId = particleSystem._emitters.getKey(particleSystem._emitters.getValues().indexOf(particleSystem._currentEmitter));
}
this.setAnimation(emitterId);
if(this._currentEmitter) this._currentEmitter.copyStateFrom(particleSystem._currentEmitter, (particleSystem._size / this._size));
if (this._canvasTexture) {
this._canvasTexture.destroy();
this._canvasTexture = null;
}
}
private clearCanvas(): void
{
if(!this._emptySprite)
{
this._emptySprite = new Sprite(Texture.EMPTY);
this._emptySprite.alpha = 0;
}
if(!this._canvasTexture)
{
this._canvasTexture = TextureUtils.createRenderTexture(this._roomSprite.width, this._roomSprite.height);
}
else
{
TextureUtils.writeToTexture(this._emptySprite, this._canvasTexture, true);
}
}
}