|
@@ -1,4 +1,5 @@
|
|
|
package hrt.prefab.fx;
|
|
|
+import hrt.prefab.l3d.Polygon;
|
|
|
import hrt.prefab.Curve;
|
|
|
import hrt.prefab.fx.BaseFX.ShaderAnimation;
|
|
|
using Lambda;
|
|
@@ -28,15 +29,26 @@ enum Orientation {
|
|
|
Random;
|
|
|
}
|
|
|
|
|
|
+enum EmitType {
|
|
|
+ Infinity;
|
|
|
+ Burst;
|
|
|
+ Duration;
|
|
|
+}
|
|
|
+
|
|
|
typedef ParamDef = {
|
|
|
> hrt.prefab.Props.PropDef,
|
|
|
?animate: Bool,
|
|
|
- ?instance: Bool
|
|
|
+ ?instance: Bool,
|
|
|
+ ?groupName: String
|
|
|
}
|
|
|
|
|
|
typedef InstanceDef = {
|
|
|
localSpeed: Value,
|
|
|
worldSpeed: Value,
|
|
|
+ startSpeed: Value,
|
|
|
+ startWorldSpeed: Value,
|
|
|
+ acceleration: Value,
|
|
|
+ worldAcceleration: Value,
|
|
|
localOffset: Value,
|
|
|
scale: Value,
|
|
|
stretch: Value,
|
|
@@ -133,6 +145,7 @@ private class ParticleInstance {
|
|
|
public var lifeTime = 0.0;
|
|
|
public var color = new h3d.Vector();
|
|
|
public var startFrame : Int;
|
|
|
+ public var speedAccumulation = new h3d.Vector();
|
|
|
|
|
|
public var orientation = new h3d.Quat();
|
|
|
|
|
@@ -147,6 +160,7 @@ private class ParticleInstance {
|
|
|
life = 0;
|
|
|
lifeTime = 0;
|
|
|
startFrame = 0;
|
|
|
+ speedAccumulation.set(0,0,0);
|
|
|
orientation.identity();
|
|
|
|
|
|
switch(emitter.simulationSpace){
|
|
@@ -179,6 +193,8 @@ private class ParticleInstance {
|
|
|
static var tmpScale = new h3d.Vector();
|
|
|
static var tmpLocalSpeed = new h3d.Vector();
|
|
|
static var tmpWorldSpeed = new h3d.Vector();
|
|
|
+ static var tmpSpeedAccumulation = new h3d.Vector();
|
|
|
+ static var tmpGroundNormal = new h3d.Vector(0,0,1);
|
|
|
static var tmpSpeed = new h3d.Vector();
|
|
|
static var tmpMat = new h3d.Matrix();
|
|
|
var tmpColor = new h3d.Vector();
|
|
@@ -187,37 +203,65 @@ private class ParticleInstance {
|
|
|
|
|
|
var t = hxd.Math.clamp(life / lifeTime, 0.0, 1.0);
|
|
|
|
|
|
+ if( life == 0 ) {
|
|
|
+ // START LOCAL SPEED
|
|
|
+ evaluator.getVector(def.startSpeed, 0.0, tmpSpeedAccumulation);
|
|
|
+ if(tmpSpeedAccumulation.length() > 0.001)
|
|
|
+ tmpSpeedAccumulation.transform3x3(orientation.toMatrix(tmpMat));
|
|
|
+ speedAccumulation = speedAccumulation.add(tmpSpeedAccumulation);
|
|
|
+ // START WORLD SPEED
|
|
|
+ evaluator.getVector(def.startWorldSpeed, 0.0, tmpSpeedAccumulation);
|
|
|
+ if(tmpSpeedAccumulation.length() > 0.001)
|
|
|
+ tmpSpeedAccumulation.transform3x3(emitter.invTransform);
|
|
|
+ speedAccumulation = speedAccumulation.add(tmpSpeedAccumulation);
|
|
|
+ }
|
|
|
+
|
|
|
+ // ACCELERATION
|
|
|
+ evaluator.getVector(def.acceleration, t, tmpSpeedAccumulation);
|
|
|
+ tmpSpeedAccumulation.scale3(dt);
|
|
|
+ if(tmpSpeedAccumulation.length() > 0.001)
|
|
|
+ tmpSpeedAccumulation.transform3x3(orientation.toMatrix(tmpMat));
|
|
|
+ speedAccumulation = speedAccumulation.add(tmpSpeedAccumulation);
|
|
|
+ // WORLD ACCELERATION
|
|
|
+ evaluator.getVector(def.worldAcceleration, t, tmpSpeedAccumulation);
|
|
|
+ tmpSpeedAccumulation.scale3(dt);
|
|
|
+ if(tmpSpeedAccumulation.length() > 0.001 && emitter.simulationSpace == Local)
|
|
|
+ tmpSpeedAccumulation.transform3x3(emitter.invTransform);
|
|
|
+ speedAccumulation = speedAccumulation.add(tmpSpeedAccumulation);
|
|
|
+ // SPEED
|
|
|
evaluator.getVector(def.localSpeed, t, tmpLocalSpeed);
|
|
|
if(tmpLocalSpeed.length() > 0.001)
|
|
|
tmpLocalSpeed.transform3x3(orientation.toMatrix(tmpMat));
|
|
|
-
|
|
|
+ // WORLD SPEED
|
|
|
evaluator.getVector(def.worldSpeed, t, tmpWorldSpeed);
|
|
|
if(emitter.simulationSpace == Local)
|
|
|
tmpWorldSpeed.transform3x3(emitter.invTransform);
|
|
|
|
|
|
- tmpSpeed.load(tmpLocalSpeed.add(tmpWorldSpeed));
|
|
|
- if(emitter.emitOrientation == Speed && tmpSpeed.lengthSq() > 0.01)
|
|
|
- transform.qRot.initDirection(tmpSpeed);
|
|
|
-
|
|
|
+ tmpSpeed.load(tmpLocalSpeed.add(tmpWorldSpeed).add(speedAccumulation));
|
|
|
transform.x += tmpSpeed.x * dt;
|
|
|
transform.y += tmpSpeed.y * dt;
|
|
|
transform.z += tmpSpeed.z * dt;
|
|
|
|
|
|
+ // SPEED ORIENTATION
|
|
|
+ if(emitter.emitOrientation == Speed && tmpSpeed.lengthSq() > 0.01)
|
|
|
+ transform.qRot.initDirection(tmpSpeed);
|
|
|
+
|
|
|
+ // ROTATION
|
|
|
var rot = evaluator.getVector(def.rotation, t, tmpRot);
|
|
|
rot.scale3(Math.PI / 180.0);
|
|
|
var offset = evaluator.getVector(def.localOffset, t, tmpOffset);
|
|
|
var scaleVec = evaluator.getVector(def.stretch, t, tmpScale);
|
|
|
scaleVec.scale3(evaluator.getFloat(def.scale, t));
|
|
|
|
|
|
+ // TRANSFORM
|
|
|
childMat.initScale(scaleVec.x, scaleVec.y, scaleVec.z);
|
|
|
childMat.rotate(rot.x, rot.y, rot.z);
|
|
|
childMat.translate(offset.x, offset.y, offset.z);
|
|
|
-
|
|
|
if( baseMat != null )
|
|
|
childMat.multiply(baseMat, childMat);
|
|
|
-
|
|
|
childTransform.setTransform(childMat);
|
|
|
|
|
|
+ // COLOR
|
|
|
if( def.color != null ) {
|
|
|
switch( def.color ) {
|
|
|
case VCurve(a): color.a = evaluator.getFloat(def.color, t);
|
|
@@ -225,6 +269,7 @@ private class ParticleInstance {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ // ALIGNMENT
|
|
|
switch( emitter.alignMode ) {
|
|
|
case Screen:
|
|
|
tmpMat.load(emitter.getScene().camera.mcam);
|
|
@@ -282,6 +327,25 @@ private class ParticleInstance {
|
|
|
absPos.multiply(childTransform.absPos, transform.absPos);
|
|
|
}
|
|
|
|
|
|
+ // COLLISION
|
|
|
+ if( emitter.useCollision ) {
|
|
|
+ var worldPos = absPos.getPosition();
|
|
|
+ if( worldPos.z < 0 ) {
|
|
|
+ if( emitter.killOnCollision == 1 || hxd.Math.random() < emitter.killOnCollision )
|
|
|
+ life = lifeTime;
|
|
|
+ else {
|
|
|
+ var speedAmount = speedAccumulation.length();
|
|
|
+ speedAccumulation.normalize();
|
|
|
+ var newDir = speedAccumulation.reflect(tmpGroundNormal);
|
|
|
+ newDir.scale3(emitter.elasticity);
|
|
|
+ newDir.scale3(speedAmount);
|
|
|
+ speedAccumulation.set(newDir.x, newDir.y, newDir.z);
|
|
|
+ transform.z = 0;
|
|
|
+ absPos.multiply(childTransform.absPos, transform.absPos);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
life += dt;
|
|
|
}
|
|
|
}
|
|
@@ -297,42 +361,61 @@ class EmitterObject extends h3d.scene.Object {
|
|
|
poolSize = 0;
|
|
|
}
|
|
|
|
|
|
+ public var instDef : InstanceDef;
|
|
|
+
|
|
|
public var batch : h3d.scene.MeshBatch;
|
|
|
public var particles : ParticleInstance;
|
|
|
public var shaderAnims : ShaderAnims;
|
|
|
|
|
|
+ public var isSubEmitter : Bool = false;
|
|
|
+ public var parentEmitter : EmitterObject = null;
|
|
|
public var enable : Bool;
|
|
|
public var particleVisibility(default, null) : Bool;
|
|
|
|
|
|
- public var particleTemplate : hrt.prefab.Object3D;
|
|
|
- public var maxCount = 20;
|
|
|
+ public var catchupSpeed = 4; // Use larger ticks when catching-up to save calculations
|
|
|
+ public var maxCatchupWindow = 0.5; // How many seconds max to simulate when catching up
|
|
|
+ public var nextBurstTime : Float = 0.0; // Keep tack of burst timing
|
|
|
+ public var totalBurstCount : Int = 0; // Keep tack of burst count
|
|
|
+
|
|
|
+ // RANDOM
|
|
|
public var seedGroup = 0;
|
|
|
+ // OBJECTS
|
|
|
+ public var particleTemplate : hrt.prefab.Object3D;
|
|
|
+ public var subEmitterTemplate : Emitter;
|
|
|
+ public var subEmitters : Array<EmitterObject> = [];
|
|
|
+ // LIFE
|
|
|
public var lifeTime = 2.0;
|
|
|
public var lifeTimeRand = 0.0;
|
|
|
- public var emitShape : EmitShape = Cylinder;
|
|
|
+ // EMIT PARAMS
|
|
|
public var emitOrientation : Orientation = Forward;
|
|
|
public var simulationSpace : SimulationSpace = Local;
|
|
|
+ public var emitType : EmitType = Infinity;
|
|
|
+ public var burstCount : Int = 1;
|
|
|
+ public var burstParticleCount : Int = 5;
|
|
|
+ public var burstDelay : Float = 1.0;
|
|
|
+ public var emitDuration : Float = 1.0;
|
|
|
+ public var emitRate : Value;
|
|
|
+ public var maxCount = 20;
|
|
|
+ // EMIT SHAPE
|
|
|
+ public var emitShape : EmitShape = Cylinder;
|
|
|
public var emitAngle : Float = 0.0;
|
|
|
public var emitRad1 : Float = 1.0;
|
|
|
public var emitRad2 : Float = 1.0;
|
|
|
public var emitSurface : Bool = false;
|
|
|
-
|
|
|
- public var catchupSpeed = 4; // Use larger ticks when catching-up to save calculations
|
|
|
- public var maxCatchupWindow = 0.5; // How many seconds max to simulate when catching up
|
|
|
-
|
|
|
+ // ANIMATION
|
|
|
public var frameCount : Int = 0;
|
|
|
public var frameDivisionX : Int = 1;
|
|
|
public var frameDivisionY : Int = 1;
|
|
|
public var animationRepeat : Float = 1;
|
|
|
public var animationLoop : Bool = true;
|
|
|
-
|
|
|
+ // ALIGNMENT
|
|
|
public var alignMode : AlignMode;
|
|
|
public var alignAxis : h3d.Vector;
|
|
|
public var alignLockAxis : h3d.Vector;
|
|
|
-
|
|
|
- public var emitRate : Value;
|
|
|
-
|
|
|
- public var instDef : InstanceDef;
|
|
|
+ // COLLISION
|
|
|
+ public var elasticity : Float = 1.0;
|
|
|
+ public var killOnCollision : Float = 0.0;
|
|
|
+ public var useCollision : Bool = false;
|
|
|
|
|
|
public var invTransform : h3d.Matrix;
|
|
|
|
|
@@ -363,6 +446,8 @@ class EmitterObject extends h3d.scene.Object {
|
|
|
curTime = 0.0;
|
|
|
lastTime = 0.0;
|
|
|
emitCount = 0;
|
|
|
+ totalBurstCount = 0;
|
|
|
+ nextBurstTime = 0.0;
|
|
|
|
|
|
var p = particles;
|
|
|
while(p != null) {
|
|
@@ -394,6 +479,7 @@ class EmitterObject extends h3d.scene.Object {
|
|
|
return p;
|
|
|
}
|
|
|
|
|
|
+ var tmpPos = new h3d.Vector();
|
|
|
function disposeInstance(p: ParticleInstance) {
|
|
|
p.next = pool;
|
|
|
p.dispose();
|
|
@@ -402,6 +488,19 @@ class EmitterObject extends h3d.scene.Object {
|
|
|
++poolSize;
|
|
|
if(numInstances < 0)
|
|
|
throw "assert";
|
|
|
+
|
|
|
+ // SUB EMITTER
|
|
|
+ if( subEmitterTemplate != null ) {
|
|
|
+ var ctx = new hrt.prefab.Context();
|
|
|
+ ctx.local3d = this.getScene();
|
|
|
+ ctx.shared = new ContextShared();
|
|
|
+ var emitter : EmitterObject = cast subEmitterTemplate.makeInstance(ctx).local3d;
|
|
|
+ var pos = p.absPos.getPosition(tmpPos);
|
|
|
+ emitter.setPosition(pos.x, pos.y, pos.z);
|
|
|
+ emitter.isSubEmitter = true;
|
|
|
+ emitter.parentEmitter = this;
|
|
|
+ subEmitters.push(emitter);
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
static var tmpQuat = new h3d.Quat();
|
|
@@ -598,17 +697,56 @@ class EmitterObject extends h3d.scene.Object {
|
|
|
}
|
|
|
|
|
|
function tick( dt : Float, full=true) {
|
|
|
+
|
|
|
+ // Auto remove of sub emitters
|
|
|
+ if( !enable && particles == null && isSubEmitter ) {
|
|
|
+ parentEmitter.subEmitters.remove(this);
|
|
|
+ remove();
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ for( se in subEmitters ) {
|
|
|
+ se.tick(dt);
|
|
|
+ }
|
|
|
+
|
|
|
if( emitRate == null || emitRate == VZero )
|
|
|
return;
|
|
|
|
|
|
- invTransform.load(parent.getAbsPos());
|
|
|
- invTransform.invert();
|
|
|
+ if( parent != null ) {
|
|
|
+ invTransform.load(parent.getAbsPos());
|
|
|
+ invTransform.invert();
|
|
|
+ }
|
|
|
vecPool.begin();
|
|
|
|
|
|
- var emitTarget = evaluator.getSum(emitRate, curTime);
|
|
|
- var delta = hxd.Math.ceil(hxd.Math.min(maxCount - numInstances, emitTarget - emitCount));
|
|
|
- if(enable)
|
|
|
- doEmit(delta);
|
|
|
+ if( enable ) {
|
|
|
+ switch emitType {
|
|
|
+ case Infinity:
|
|
|
+ var emitTarget = evaluator.getSum(emitRate, curTime);
|
|
|
+ var delta = hxd.Math.ceil(hxd.Math.min(maxCount - numInstances, emitTarget - emitCount));
|
|
|
+ doEmit(delta);
|
|
|
+ if( isSubEmitter && (parentEmitter == null || parentEmitter.parent == null) )
|
|
|
+ enable = false;
|
|
|
+ case Burst:
|
|
|
+ if( burstDelay > 0 ) {
|
|
|
+ var needBurst = totalBurstCount < burstCount && curTime > nextBurstTime;
|
|
|
+ while( needBurst ) {
|
|
|
+ var delta = hxd.Math.ceil(hxd.Math.min(maxCount - numInstances, burstParticleCount));
|
|
|
+ doEmit(delta);
|
|
|
+ nextBurstTime += burstDelay;
|
|
|
+ totalBurstCount++;
|
|
|
+ needBurst = totalBurstCount < burstCount && curTime > nextBurstTime;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if( isSubEmitter && totalBurstCount == burstCount )
|
|
|
+ enable = false;
|
|
|
+ case Duration:
|
|
|
+ var emitTarget = evaluator.getSum(emitRate, hxd.Math.min(curTime, emitDuration));
|
|
|
+ var delta = hxd.Math.ceil(hxd.Math.min(maxCount - numInstances, emitTarget - emitCount));
|
|
|
+ doEmit(delta);
|
|
|
+ if( isSubEmitter && curTime >= emitDuration )
|
|
|
+ enable = false;
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
updateParticles(dt);
|
|
|
|
|
@@ -695,7 +833,6 @@ class EmitterObject extends h3d.scene.Object {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-
|
|
|
class Emitter extends Object3D {
|
|
|
|
|
|
public function new(?parent) {
|
|
@@ -708,37 +845,54 @@ class Emitter extends Object3D {
|
|
|
}
|
|
|
|
|
|
public static var emitterParams : Array<ParamDef> = [
|
|
|
- { name: "simulationSpace", t: PEnum(SimulationSpace), def: SimulationSpace.Local, disp: "Simulation Space", },
|
|
|
- { name: "emitRate", t: PInt(0, 100), def: 5, disp: "Rate", animate: true },
|
|
|
- { name: "lifeTime", t: PFloat(0, 10), def: 1.0 },
|
|
|
- { name: "lifeTimeRand", t: PFloat(0, 1), def: 0.0 },
|
|
|
- { name: "maxCount", t: PInt(0, 100), def: 20, },
|
|
|
- { name: "seedGroup", t: PInt(0, 100), def: 0, },
|
|
|
- { name: "emitShape", t: PEnum(EmitShape), def: EmitShape.Sphere, disp: "Emit Shape", },
|
|
|
- { name: "emitAngle", t: PFloat(0, 360.0), disp: "Angle", },
|
|
|
- { name: "emitRad1", t: PFloat(0, 1.0), def: 1.0, disp: "Radius 1", },
|
|
|
- { name: "emitRad2", t: PFloat(0, 1.0), def: 1.0, disp: "Radius 2", },
|
|
|
- { name: "emitSurface", t: PBool, def: false, disp: "Surface" },
|
|
|
-
|
|
|
- { name: "emitOrientation", t: PEnum(Orientation), def: Orientation.Forward, disp: "Orientation", },
|
|
|
- { name: "alignMode", t: PEnum(AlignMode), def: AlignMode.None, disp: "Alignment" },
|
|
|
- { name: "alignAxis", t: PVec(3, -1.0, 1.0), def: [0.,0.,0.], disp: "Axis" },
|
|
|
- { name: "alignLockAxis", t: PVec(3, -1.0, 1.0), def: [0.,0.,0.], disp: "Lock Axis" },
|
|
|
-
|
|
|
- { name: "frameCount", t: PInt(0), def: 0 },
|
|
|
- { name: "frameDivisionX", t: PInt(1), def: 1 },
|
|
|
- { name: "frameDivisionY", t: PInt(1), def: 1 },
|
|
|
- { name: "animationRepeat", t: PFloat(0, 2.0), def: 1.0 },
|
|
|
- { name: "animationLoop", t: PBool, def: true },
|
|
|
+ // RANDOM
|
|
|
+ { name: "seedGroup", t: PInt(0, 100), def: 0, groupName : "Random"},
|
|
|
+ // LIFE
|
|
|
+ { name: "lifeTime", t: PFloat(0, 10), def: 1.0, groupName : "Life" },
|
|
|
+ { name: "lifeTimeRand", t: PFloat(0, 1), def: 0.0, groupName : "Life" },
|
|
|
+ // EMIT PARAMS
|
|
|
+ { name: "emitType", t: PEnum(EmitType), def: EmitType.Infinity, disp: "Type", groupName : "Emit Params" },
|
|
|
+ { name: "emitDuration", t: PFloat(0, 10.0), disp: "Duration", def : 1.0, groupName : "Emit Params" },
|
|
|
+ { name: "emitRate", t: PInt(0, 100), def: 5, disp: "Rate", animate: true, groupName : "Emit Params" },
|
|
|
+ { name: "burstCount", t: PInt(1, 10), disp: "Count", def : 1, groupName : "Emit Params" },
|
|
|
+ { name: "burstDelay", t: PFloat(0, 1.0), disp: "Delay", def : 1.0, groupName : "Emit Params" },
|
|
|
+ { name: "burstParticleCount", t: PInt(1, 10), disp: "Particle Count", def : 1, groupName : "Emit Params" },
|
|
|
+ { name: "simulationSpace", t: PEnum(SimulationSpace), def: SimulationSpace.Local, disp: "Simulation Space", groupName : "Emit Params" },
|
|
|
+ { name: "emitOrientation", t: PEnum(Orientation), def: Orientation.Forward, disp: "Orientation", groupName : "Emit Params" },
|
|
|
+ { name: "maxCount", t: PInt(0, 100), def: 20, groupName : "Emit Params" },
|
|
|
+ // EMIT SHAPE
|
|
|
+ { name: "emitShape", t: PEnum(EmitShape), def: EmitShape.Sphere, disp: "Shape", groupName : "Emit Shape" },
|
|
|
+ { name: "emitAngle", t: PFloat(0, 360.0), disp: "Angle", groupName : "Emit Shape" },
|
|
|
+ { name: "emitRad1", t: PFloat(0, 1.0), def: 1.0, disp: "Radius 1", groupName : "Emit Shape" },
|
|
|
+ { name: "emitRad2", t: PFloat(0, 1.0), def: 1.0, disp: "Radius 2", groupName : "Emit Shape" },
|
|
|
+ { name: "emitSurface", t: PBool, def: false, disp: "Surface", groupName : "Emit Shape" },
|
|
|
+ // ALIGNMENT
|
|
|
+ { name: "alignMode", t: PEnum(AlignMode), def: AlignMode.None, disp: "Mode", groupName : "Alignment" },
|
|
|
+ { name: "alignAxis", t: PVec(3, -1.0, 1.0), def: [0.,0.,0.], disp: "Axis", groupName : "Alignment" },
|
|
|
+ { name: "alignLockAxis", t: PVec(3, -1.0, 1.0), def: [0.,0.,0.], disp: "Lock Axis", groupName : "Alignment" },
|
|
|
+ // ANIMATION
|
|
|
+ { name: "frameCount", t: PInt(0), def: 0, groupName : "Animation" },
|
|
|
+ { name: "frameDivisionX", t: PInt(1), def: 1, groupName : "Animation" },
|
|
|
+ { name: "frameDivisionY", t: PInt(1), def: 1, groupName : "Animation" },
|
|
|
+ { name: "animationRepeat", t: PFloat(0, 2.0), def: 1.0, groupName : "Animation" },
|
|
|
+ { name: "animationLoop", t: PBool, def: true, groupName : "Animation" },
|
|
|
+ // COLLISION
|
|
|
+ { name: "useCollision", t: PBool, def: false, groupName : "Ground Collision" },
|
|
|
+ { name: "elasticity", t: PFloat(0, 1.0), disp: "Elasticity", def : 1.0, groupName : "Collision" },
|
|
|
+ { name: "killOnCollision", t: PFloat(0, 1.0), disp: "Kill On Collision", def : 0.0, groupName : "Collision" },
|
|
|
];
|
|
|
|
|
|
public static var instanceParams : Array<ParamDef> = [
|
|
|
- { name: "instSpeed", t: PVec(3, -10, 10), def: [0.,0.,0.], disp: "Speed" },
|
|
|
- { name: "instWorldSpeed", t: PVec(3, -10, 10), def: [0.,0.,0.], disp: "World Speed" },
|
|
|
- { name: "instScale", t: PFloat(0, 2.0), def: 1., disp: "Scale" },
|
|
|
- { name: "instStretch", t: PVec(3, 0.0, 2.0), def: [1.,1.,1.], disp: "Stretch" },
|
|
|
- { name: "instRotation", t: PVec(3, 0, 360), def: [0.,0.,0.], disp: "Rotation" },
|
|
|
- { name: "instOffset", t: PVec(3, -10, 10), def: [0.,0.,0.], disp: "Offset" }
|
|
|
+ { name: "instSpeed", t: PVec(3, -10, 10), def: [0.,0.,0.], disp: "Fixed Speed" },
|
|
|
+ { name: "instWorldSpeed", t: PVec(3, -10, 10), def: [0.,0.,0.], disp: "Fixed World Speed" },
|
|
|
+ { name: "instStartSpeed", t: PVec(3, -10, 10), def: [0.,0.,0.], disp: "Start Speed" },
|
|
|
+ { name: "instStartWorldSpeed", t: PVec(3, -10, 10), def: [0.,0.,0.], disp: "Start World Speed" },
|
|
|
+ { name: "instAcceleration", t: PVec(3, -10, 10), def: [0.,0.,0.], disp: "Acceleration" },
|
|
|
+ { name: "instWorldAcceleration", t: PVec(3, -10, 10), def: [0.,0.,0.], disp: "World Acceleration" },
|
|
|
+ { name: "instScale", t: PFloat(0, 2.0), def: 1., disp: "Scale" },
|
|
|
+ { name: "instStretch", t: PVec(3, 0.0, 2.0), def: [1.,1.,1.], disp: "Stretch" },
|
|
|
+ { name: "instRotation", t: PVec(3, 0, 360), def: [0.,0.,0.], disp: "Rotation" },
|
|
|
+ { name: "instOffset", t: PVec(3, -10, 10), def: [0.,0.,0.], disp: "Offset" }
|
|
|
];
|
|
|
|
|
|
public static var PARAMS : Array<ParamDef> = {
|
|
@@ -830,7 +984,7 @@ class Emitter extends Object3D {
|
|
|
var emitterObj = Std.downcast(ctx.local3d, EmitterObject);
|
|
|
|
|
|
var randIdx = 0;
|
|
|
- var template = children[0] != null ? children[0].to(Object3D) : null;
|
|
|
+ var template : Object3D = cast children.find( c -> c.enabled && (c.name == null || c.name.indexOf("collision") == -1) && c.to(Object3D) != null && c.to(Object3D).visible );
|
|
|
|
|
|
function makeParam(scope: Prefab, name: String): Value {
|
|
|
var getCurve = hrt.prefab.Curve.getCurve.bind(scope);
|
|
@@ -890,6 +1044,10 @@ class Emitter extends Object3D {
|
|
|
emitterObj.instDef = {
|
|
|
localSpeed: makeParam(this, "instSpeed"),
|
|
|
worldSpeed: makeParam(this, "instWorldSpeed"),
|
|
|
+ startSpeed: makeParam(this, "instStartSpeed"),
|
|
|
+ startWorldSpeed: makeParam(this, "instStartWorldSpeed"),
|
|
|
+ acceleration: makeParam(this, "instAcceleration"),
|
|
|
+ worldAcceleration: makeParam(this, "instWorldAcceleration"),
|
|
|
localOffset: makeParam(this, "instOffset"),
|
|
|
scale: makeParam(this, "instScale"),
|
|
|
stretch: makeParam(this, "instStretch"),
|
|
@@ -900,26 +1058,44 @@ class Emitter extends Object3D {
|
|
|
emitterObj.particleTemplate = template;
|
|
|
}
|
|
|
|
|
|
- emitterObj.simulationSpace = getParamVal("simulationSpace");
|
|
|
- emitterObj.lifeTime = getParamVal("lifeTime");
|
|
|
- emitterObj.lifeTimeRand = getParamVal("lifeTimeRand");
|
|
|
- emitterObj.maxCount = getParamVal("maxCount");
|
|
|
- emitterObj.seedGroup = getParamVal("seedGroup");
|
|
|
- emitterObj.emitRate = makeParam(this, "emitRate");
|
|
|
- emitterObj.emitShape = getParamVal("emitShape");
|
|
|
- emitterObj.emitOrientation = getParamVal("emitOrientation");
|
|
|
- emitterObj.emitAngle = getParamVal("emitAngle");
|
|
|
- emitterObj.emitRad1 = getParamVal("emitRad1");
|
|
|
- emitterObj.emitRad2 = getParamVal("emitRad2");
|
|
|
- emitterObj.emitSurface = getParamVal("emitSurface");
|
|
|
- emitterObj.alignMode = getParamVal("alignMode");
|
|
|
- emitterObj.alignAxis = getParamVal("alignAxis");
|
|
|
- emitterObj.alignLockAxis = getParamVal("alignLockAxis");
|
|
|
- emitterObj.frameCount = getParamVal("frameCount");
|
|
|
- emitterObj.frameDivisionX = getParamVal("frameDivisionX");
|
|
|
- emitterObj.frameDivisionY = getParamVal("frameDivisionY");
|
|
|
- emitterObj.animationRepeat = getParamVal("animationRepeat");
|
|
|
- emitterObj.animationLoop = getParamVal("animationLoop");
|
|
|
+ // SUB-EMITTER
|
|
|
+ var subEmitterTemplate : Emitter = cast children.find( p -> p.enabled && Std.downcast(p, Emitter) != null && p.to(Object3D).visible);
|
|
|
+ emitterObj.subEmitterTemplate = subEmitterTemplate;
|
|
|
+ // RANDOM
|
|
|
+ emitterObj.seedGroup = getParamVal("seedGroup");
|
|
|
+ // LIFE
|
|
|
+ emitterObj.lifeTime = getParamVal("lifeTime");
|
|
|
+ emitterObj.lifeTimeRand = getParamVal("lifeTimeRand");
|
|
|
+ // EMIT PARAMS
|
|
|
+ emitterObj.emitType = getParamVal("emitType");
|
|
|
+ emitterObj.burstCount = getParamVal("burstCount");
|
|
|
+ emitterObj.burstDelay = getParamVal("burstDelay");
|
|
|
+ emitterObj.burstParticleCount = getParamVal("burstParticleCount");
|
|
|
+ emitterObj.emitDuration = getParamVal("emitDuration");
|
|
|
+ emitterObj.simulationSpace = getParamVal("simulationSpace");
|
|
|
+ emitterObj.emitOrientation = getParamVal("emitOrientation");
|
|
|
+ emitterObj.maxCount = getParamVal("maxCount");
|
|
|
+ emitterObj.emitRate = makeParam(this, "emitRate");
|
|
|
+ emitterObj.emitShape = getParamVal("emitShape");
|
|
|
+ // EMIT SHAPE
|
|
|
+ emitterObj.emitAngle = getParamVal("emitAngle");
|
|
|
+ emitterObj.emitRad1 = getParamVal("emitRad1");
|
|
|
+ emitterObj.emitRad2 = getParamVal("emitRad2");
|
|
|
+ emitterObj.emitSurface = getParamVal("emitSurface");
|
|
|
+ // ALIGNMENT
|
|
|
+ emitterObj.alignMode = getParamVal("alignMode");
|
|
|
+ emitterObj.alignAxis = getParamVal("alignAxis");
|
|
|
+ emitterObj.alignLockAxis = getParamVal("alignLockAxis");
|
|
|
+ // ANIMATION
|
|
|
+ emitterObj.frameCount = getParamVal("frameCount");
|
|
|
+ emitterObj.frameDivisionX = getParamVal("frameDivisionX");
|
|
|
+ emitterObj.frameDivisionY = getParamVal("frameDivisionY");
|
|
|
+ emitterObj.animationRepeat = getParamVal("animationRepeat");
|
|
|
+ emitterObj.animationLoop = getParamVal("animationLoop");
|
|
|
+ // COLLISION
|
|
|
+ emitterObj.useCollision = getParamVal("useCollision");
|
|
|
+ emitterObj.killOnCollision = getParamVal("killOnCollision");
|
|
|
+ emitterObj.elasticity = getParamVal("elasticity");
|
|
|
|
|
|
var startTime = 0.0;
|
|
|
var scene = ctx.local3d.getScene();
|
|
@@ -962,7 +1138,7 @@ class Emitter extends Object3D {
|
|
|
function onChange(?pname: String) {
|
|
|
ctx.onChange(this, pname);
|
|
|
|
|
|
- if(pname == "emitShape" || pname == "alignMode")
|
|
|
+ if( pname == "emitShape" || pname == "alignMode" || pname == "useCollision" || pname == "emitType" )
|
|
|
refresh();
|
|
|
}
|
|
|
|
|
@@ -987,11 +1163,45 @@ class Emitter extends Object3D {
|
|
|
default:
|
|
|
}
|
|
|
|
|
|
+ var useCollision = getParamVal("useCollision");
|
|
|
+ if( !useCollision ) {
|
|
|
+ removeParam("elasticity");
|
|
|
+ removeParam("killOnCollision");
|
|
|
+ }
|
|
|
+
|
|
|
+ var emitType : EmitType = getParamVal("emitType");
|
|
|
+ switch (emitType) {
|
|
|
+ case Infinity:
|
|
|
+ removeParam("burstCount");
|
|
|
+ removeParam("burstDelay");
|
|
|
+ removeParam("burstParticleCount");
|
|
|
+ removeParam("emitDuration");
|
|
|
+ case Burst:
|
|
|
+ removeParam("emitDuration");
|
|
|
+ removeParam("emitRate");
|
|
|
+ case Duration:
|
|
|
+ removeParam("burstCount");
|
|
|
+ removeParam("burstDelay");
|
|
|
+ removeParam("burstParticleCount");
|
|
|
+ }
|
|
|
+
|
|
|
// Emitter
|
|
|
{
|
|
|
- var emGroup = new Element('<div class="group" name="Emitter"></div>');
|
|
|
- emGroup.append(hide.comp.PropsEditor.makePropsList(params));
|
|
|
- var props = ctx.properties.add(emGroup, this.props, onChange);
|
|
|
+ // Sort by groupName
|
|
|
+ var groupNames : Array<String> = [];
|
|
|
+ for( p in params ) {
|
|
|
+ if( p.groupName == null && groupNames.indexOf("Emitter") == -1 )
|
|
|
+ groupNames.push("Emitter");
|
|
|
+ else if( p.groupName != null && groupNames.indexOf(p.groupName) == -1 )
|
|
|
+ groupNames.push(p.groupName);
|
|
|
+ }
|
|
|
+
|
|
|
+ for( gn in groupNames ) {
|
|
|
+ var params = params.filter( p -> p.groupName == (gn == "Emitter" ? null : gn) );
|
|
|
+ var group = new Element('<div class="group" name="$gn"></div>');
|
|
|
+ group.append(hide.comp.PropsEditor.makePropsList(params));
|
|
|
+ ctx.properties.add(group, this.props, onChange);
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
// Instances
|