@woosh/meep-engine
Version:
Pure JavaScript game engine. Fully featured and production ready.
214 lines (162 loc) • 6.92 kB
JavaScript
import { noop } from "../../../../../src/core/function/noop.js";
import ObservedValue from "../../../../../src/core/model/ObservedValue.js";
import {
ParticleEmitterFlag
} from "../../../../../src/engine/graphics/particles/particular/engine/emitter/ParticleEmitterFlag.js";
import { ParticleLayer } from "../../../../../src/engine/graphics/particles/particular/engine/emitter/ParticleLayer.js";
import {
SimulationStepDefinition
} from "../../../../../src/engine/graphics/particles/particular/engine/simulator/SimulationStepDefinition.js";
import {
SimulationStepType
} from "../../../../../src/engine/graphics/particles/particular/engine/simulator/SimulationStepType.js";
import { BlendingType } from "../../../../../src/engine/graphics/texture/sampler/BlendingType.js";
import { NativeListController } from "../../../../../src/view/controller/controls/NativeListController.js";
import EmptyView from "../../../../../src/view/elements/EmptyView.js";
import DatGuiController from "../DatGuiController.js";
import ParticleLayerController from "./ParticleLayerController.js";
/**
*
* @param {*} value
* @param {Object} enumerable
* @returns {string}
*/
export function enumNameByValue(value, enumerable) {
return Object.keys(enumerable)[Object.values(enumerable).indexOf(value)];
}
/**
*
* @param {ParticleEmitter} emitter
* @param {ParticleEmitterSystem} system
* @param {function} op
* @param {*} [arg0]
*/
function applyEmitterChanges(emitter, system, op, arg0) {
const particleEngine = system.particleEngine;
const isSleeping = emitter.getFlag(ParticleEmitterFlag.Sleeping);
//re-add the emitter
particleEngine.remove(emitter);
if (system.renderLayer.visibleSet.contains(emitter.mesh)) {
//remove from visible layer if present
system.renderLayer.visibleSet.forceRemove(emitter.mesh);
}
//execute operation
op(emitter, arg0);
//clear flags
emitter.clearFlag(ParticleEmitterFlag.Built | ParticleEmitterFlag.Initialized);
//update internal state
emitter.registerLayerParameters();
emitter.build();
emitter.initialize();
emitter.computeBoundingBox();
particleEngine.add(emitter);
emitter.writeFlag(ParticleEmitterFlag.Sleeping, isSleeping);
}
export class ParticleEmitterController extends EmptyView {
/**
*
* @param {ParticleEmitterSystem} particleEmitterSystem
* @constructor
*/
constructor(particleEmitterSystem) {
super();
this.model = new ObservedValue(null);
const self = this;
function applyChanges() {
const emitter = self.model.getValue();
if (emitter !== null) {
applyEmitterChanges(emitter, particleEmitterSystem, noop);
}
}
/**
*
* @param {function(ParticleEmitter)} op
* @param {v} [v]
*/
function makeChange(op, v) {
const emitter = self.model.getValue();
if (emitter !== null) {
applyEmitterChanges(emitter, particleEmitterSystem, op, v);
}
}
/**
*
* @param {function(ParticleEmitter)} op
* @returns {function(...[*]=)}
*/
function mutator(op) {
return function (arg0) {
makeChange(op, arg0);
}
}
/**
*
* @param {ParticleEmitter} emitter
* @param oldEmitter
*/
function modelSet(emitter, oldEmitter) {
self.removeAllChildren();
if (emitter !== null) {
const emitterSurrogate = {
preWarm: emitter.getFlag(ParticleEmitterFlag.PreWarm),
depthRead: !emitter.getFlag(ParticleEmitterFlag.DepthReadDisabled),
depthSoft: !emitter.getFlag(ParticleEmitterFlag.DepthSoftDisabled),
velocityAlign: emitter.getFlag(ParticleEmitterFlag.AlignOnVelocity),
blendingMode: enumNameByValue(emitter.blendingMode, BlendingType),
update: function () {
applyChanges();
}
};
const dat = new DatGuiController();
self.addChild(dat);
dat.addControl(emitterSurrogate, 'preWarm').onChange(mutator((emitter, value) => {
/**
* @type {ParticleEmitter}
*/
emitter.writeFlag(ParticleEmitterFlag.PreWarm, value);
}));
dat.addControl(emitterSurrogate, 'depthRead').onChange(mutator((emitter, value) => {
/**
* @type {ParticleEmitter}
*/
emitter.writeFlag(ParticleEmitterFlag.DepthReadDisabled, !value);
}));
dat.addControl(emitterSurrogate, 'depthSoft').onChange(mutator((emitter, value) => {
/**
* @type {ParticleEmitter}
*/
emitter.writeFlag(ParticleEmitterFlag.DepthSoftDisabled, !value);
}));
dat.addControl(emitterSurrogate, 'velocityAlign').onChange(mutator((emitter, value) => {
/**
* @type {ParticleEmitter}
*/
emitter.writeFlag(ParticleEmitterFlag.AlignOnVelocity, value);
}));
dat.addControl(emitterSurrogate, 'blendingMode', Object.keys(BlendingType)).onChange(mutator((emitter, blendModeName) => {
emitter.blendingMode = BlendingType[blendModeName];
}));
dat.addControl(emitterSurrogate, 'update').name('Apply Changes');
self.addChild(new NativeListController({
model: emitter.layers,
elementViewFactory(layer) {
const c = new ParticleLayerController(makeChange);
c.model.set(layer);
return c;
},
elementFactory() {
const r = new ParticleLayer();
r.steps.add(SimulationStepDefinition.from(SimulationStepType.FixedPhysics, []))
return r;
},
operationAdd(list, layer) {
makeChange(emitter => {
emitter.addLayer(layer);
});
}
}))
}
}
this.model.onChanged.add(modelSet);
}
}