You've already forked Nitro_Render_V3
mirror of
https://github.com/duckietm/Nitro_Render_V3.git
synced 2026-06-19 15:06:20 +00:00
335 lines
12 KiB
TypeScript
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);
|
|
}
|
|
}
|
|
}
|