public override void Update(ParticleEffect fx, ParticleEffectInstance instance, TimeSpan delta, ref Matrix4 transform, float sparam) { if (!fx.Pairs.ContainsKey(this)) { return; } var maxCount = MaxParticles == null ? int.MaxValue : (int)Math.Ceiling(MaxParticles.GetValue(sparam, 0f)); var freq = Frequency == null ? 0f : Frequency.GetValue(sparam, 0f); var spawnMs = freq <= 0 ? 0 : 1 / (double)freq; var state = instance.GetEmitterState(this); if (state.ParticleCount >= maxCount) { return; } if (spawnMs > 0) { //Spawn lots of particles var dt = Math.Min(delta.TotalSeconds, 1); //don't go crazy during debug pauses while (true) { if (state.SpawnTimer < dt) { dt -= state.SpawnTimer; state.SpawnTimer = spawnMs; } else { state.SpawnTimer -= dt; break; } if (state.ParticleCount + 1 <= maxCount) { var idx = instance.GetNextFreeParticle(); if (idx == -1) { return; } state.ParticleCount++; SpawnParticle(idx, fx, instance, ref transform, sparam); instance.Particles[idx].Appearance.OnParticleSpawned(idx, instance); } } } }
public ParticleEffectInstance(ParticleEffect fx) { Effect = fx; int emitterCount = 0; foreach (var node in fx.References) { if (node.Node is FLBeamAppearance) { BeamAppearances.Add(node, new LineBuffer(512)); } if (node.Node is FxEmitter) { emitterCount++; } } Particles = new Particle[PARTICLES_PER_EMITTER * emitterCount]; }
protected override void SetParticle(int idx, ParticleEffect fx, ParticleEffectInstance instance, ref Matrix4 transform, float sparam) { var r_min = MinRadius.GetValue(sparam, 0); var r_max = MaxRadius.GetValue(sparam, 0); var radius = instance.Random.NextFloat(r_min, r_max); float s_min = MathHelper.DegreesToRadians(MinSpread.GetValue(sparam, 0)); float s_max = MathHelper.DegreesToRadians(MaxSpread.GetValue(sparam, 0)); var direction = RandomInCone(instance.Random, s_min, s_max); var tr = Transform.GetMatrix(sparam, 0); var n = (tr * new Vector4(direction.Normalized(), 0)).Xyz.Normalized(); var p = n * radius; n *= Pressure.GetValue(sparam, 0); instance.Particles[idx].Position = p; instance.Particles[idx].Normal = n; }
public ParticleLibrary(ResourceManager res, AleFile ale) { Resources = res; foreach (var effect in ale.FxLib.Effects) { var fx = new ParticleEffect(this); fx.CRC = effect.CRC; fx.Name = effect.Name; Dictionary <uint, NodeReference> nodesByIndex = new Dictionary <uint, NodeReference>(); foreach (var noderef in effect.Fx) { FxNode node = null; if (!noderef.IsAttachmentNode) { node = NodeFromAle(ale.NodeLib.Nodes.Where((arg) => arg.CRC == noderef.CRC).First()); } var reference = new NodeReference(); reference.Node = node; reference.IsAttachmentNode = noderef.IsAttachmentNode; nodesByIndex.Add(noderef.Index, reference); } foreach (var noderef in effect.Fx) { var nd = nodesByIndex[noderef.Index]; if (noderef.Parent != 32768) { var parent = nodesByIndex[noderef.Parent]; parent.Children.Add(nd); nd.Parent = parent; } } foreach (var pair in effect.Pairs) { var n1 = nodesByIndex[pair.Item1]; var n2 = nodesByIndex[pair.Item2]; n1.Paired.Add(n2); } fx.References = new List <NodeReference>(nodesByIndex.Values); Effects.Add(fx); } }
public Matrix4 GetTranslation(ParticleEffect effect, Matrix4 attachment, float sparam, float time) { Matrix4 mat = Matrix4.Identity; if (Transform != null) { mat = Transform.GetMatrix(sparam, time); } if (effect.AttachmentNodes.Contains(this)) { return(mat * attachment); } else if (effect.Parents[this] is FxRootNode) { return(mat); } else { return(mat * effect.Parents [this].GetTranslation(effect, attachment, sparam, time)); } }
public override void Draw(ref Particle particle, float globaltime, ParticleEffect effect, ResourceManager res, Billboards billboards, ref Matrix4 transform, float sparam) { var time = particle.TimeAlive / particle.LifeSpan; var node_tr = GetTranslation(effect, transform, sparam, time); var p = node_tr.Transform(particle.Position); Texture2D tex; Vector2 tl, tr, bl, br; HandleTexture(res, globaltime, sparam, ref particle, out tex, out tl, out tr, out bl, out br); var c = Color.GetValue(sparam, time); var a = Alpha.GetValue(sparam, time); var p2 = node_tr.Transform(particle.Position + particle.Normal); var n = (p - p2).Normalized(); billboards.DrawPerspective( tex, p, new Vector2(Size.GetValue(sparam, time)), new Color4(c, a), tl, tr, bl, br, n, Rotate == null ? 0f : Rotate.GetValue(sparam, time), SortLayers.OBJECT, BlendInfo ); if (DrawNormals) { Debug.DrawLine(p - (n * 8), p + (n * 8)); } }
public virtual void Update(ParticleEffect fx, ParticleEffectInstance instance, TimeSpan delta, ref Matrix4 transform, float sparam) { }
public unsafe void DrawBeamApp(PolylineRender poly, LineBuffer points, float globalTime, ParticleEffect effect, ParticleEffectInstance instance, ResourceManager res, Billboards billboards, ref Matrix4 transform, float sparam) { //TODO: Cross-plane not showing //TODO: In some cases particles are going backwards? (Broken emitter or LineBuffer) //TODO: See if z sorting can be better for Polyline //TODO: Implement FLBeamAppearance properties if (points.Count < 2) { return; } int lastIndex = 0; while (points[lastIndex].Active == false) { lastIndex++; if (lastIndex >= points.Count) { return; } } //Get only active indices, alloc on stack for 0 GC pressure int *indices = stackalloc int[256]; int ptCount = 0; for (int i = lastIndex; i < points.Count; i++) { if (points[i].Active) { indices[ptCount++] = points[i].ParticleIndex; } } var node_tr = GetTranslation(effect, transform, sparam, 0); Texture2D tex; Vector2 tl, tr, bl, br; HandleTexture(res, globalTime, sparam, ref instance.Particles[points[lastIndex].ParticleIndex], out tex, out tl, out tr, out bl, out br); //Sorting hack kinda var z = RenderHelpers.GetZ(billboards.Camera.Position, node_tr.Transform(Vector3.Zero)); for (int j = 0; j < 2; j++) //two planes { poly.StartLine(tex, BlendInfo); bool odd = true; Vector3 dir = Vector3.Zero; for (int i = 0; i < ptCount; i++) { var pos = node_tr.Transform(instance.Particles[indices[i]].Position); if (i + 1 < ptCount) { var pos2 = node_tr.Transform(instance.Particles[indices[i + 1]].Position); var forward = (pos2 - pos).Normalized(); var toCamera = (billboards.Camera.Position - pos).Normalized(); var up = Vector3.Cross(toCamera, forward); up.Normalize(); dir = up; if (j == 1) { //Broken? Doesn't show up var right = Vector3.Cross(forward, up).Normalized(); dir = right; } } var time = instance.Particles[indices[i]].TimeAlive / instance.Particles[indices[i]].LifeSpan; var w = Width.GetValue(sparam, time); poly.AddPoint( pos + (dir * w / 2), pos - (dir * w / 2), odd ? tl : bl, odd ? tr : br, new Color4( Color.GetValue(sparam, time), Alpha.GetValue(sparam, time) ) ); odd = !odd; } poly.FinishLine(z); } }
public override void Draw(ref Particle particle, float globaltime, ParticleEffect effect, ResourceManager res, Billboards billboards, ref Matrix4 transform, float sparam) { //Empty on purpose. Individual particles don't draw }
public ParticleLibrary(ResourceManager res, AleFile ale) { Resources = res; foreach (var effect in ale.FxLib.Effects) { var fx = new ParticleEffect(this); var root = new FxRootNode(); fx.CRC = effect.CRC; fx.Name = effect.Name; List <FxNode> nodes = new List <FxNode>(); Dictionary <uint, FxNode> nodesByIndex = new Dictionary <uint, FxNode>(); foreach (var noderef in effect.Fx) { FxNode node; if (noderef.IsAttachmentNode) { node = new FxNode("Attachment_0x" + noderef.CRC.ToString("X"), "Empty") { CRC = noderef.CRC }; } else { node = NodeFromAle(ale.NodeLib.Nodes.Where((arg) => arg.CRC == noderef.CRC).First()); } nodes.Add(node); nodesByIndex.Add(noderef.Index, node); } foreach (var noderef in effect.Fx) { var nd = nodesByIndex[noderef.Index]; //var nd = FindNode(noderef.CRC); if (noderef.Parent != 32768) { fx.Parents.Add(nd, nodesByIndex[noderef.Parent]); } else { fx.Parents.Add(nd, root); } if (noderef.IsAttachmentNode) { fx.AttachmentNodes.Add(nd); } } foreach (var pair in effect.Pairs) { var n1 = nodesByIndex[pair.Item1]; var n2 = nodesByIndex[pair.Item2]; List <Fx.FxNode> pairedTo; if (!fx.Pairs.TryGetValue(n1, out pairedTo)) { pairedTo = new List <FxNode>(); fx.Pairs.Add(n1, pairedTo); } pairedTo.Add(n2); } fx.SetNodes(nodes); Effects.Add(fx); } }
public virtual void Draw(ref Particle particle, float globaltime, ParticleEffect effect, ResourceManager res, Billboards billboards, ref Matrix4 transform, float sparam) { }
public ParticleLibrary(ResourceManager res, AleFile ale) { Resources = res; foreach (var effect in ale.FxLib.Effects) { var fx = new ParticleEffect(this); fx.CRC = effect.CRC; fx.Name = effect.Name; Dictionary <uint, NodeReference> nodesByIndex = new Dictionary <uint, NodeReference>(); foreach (var noderef in effect.Fx) { FxNode node = null; if (!noderef.IsAttachmentNode) { var nd = ale.NodeLib.Nodes.FirstOrDefault((arg) => arg.CRC == noderef.CRC); if (nd == null) { node = new FxNode("error node", "error node"); FLLog.Error("Fx", fx.Name + " bad node CRC 0x" + noderef.CRC.ToString("x")); } else { node = NodeFromAle(ale.NodeLib.Nodes.Where((arg) => arg.CRC == noderef.CRC).First()); } } var reference = new NodeReference(); reference.Node = node; reference.IsAttachmentNode = noderef.IsAttachmentNode; nodesByIndex.Add(noderef.Index, reference); } foreach (var noderef in effect.Fx) { var nd = nodesByIndex[noderef.Index]; if (noderef.Parent != 32768) { var parent = nodesByIndex[noderef.Parent]; parent.Children.Add(nd); nd.Parent = parent; } } foreach (var pair in effect.Pairs) { var n1 = nodesByIndex[pair.Item1]; var n2 = nodesByIndex[pair.Item2]; n1.Paired.Add(n2); } int emitterIndex = 0; int beamIndex = 0; fx.References = new List <NodeReference>(nodesByIndex.Values); for (int i = 0; i < fx.References.Count; i++) { fx.References[i].Index = i; fx.References[i].EmitterIndex = emitterIndex; fx.References[i].BeamIndex = beamIndex; if (fx.References[i].Node is FxEmitter) { emitterIndex++; } if (fx.References[i].Node is FLBeamAppearance) { beamIndex++; } } fx.EmitterCount = emitterIndex; fx.BeamCount = beamIndex; Effects.Add(fx); } }
public override void Draw(ref Particle particle, float globaltime, ParticleEffect effect, ResourceManager res, Billboards billboards, ref Matrix4 transform, float sparam) { var time = particle.TimeAlive / particle.LifeSpan; var node_tr = GetTranslation(effect, transform, sparam, time); var src_pos = particle.Position; var l = Length.GetValue(sparam, time); var w = Width.GetValue(sparam, time); var sc = Scale.GetValue(sparam, time); if (!CenterOnPos) { var nd = particle.Normal.Normalized(); src_pos += nd * (l * sc * 0.25f); } var p = node_tr.Transform(src_pos); Texture2D tex; Vector2 tl, tr, bl, br; HandleTexture(res, globaltime, sparam, ref particle, out tex, out tl, out tr, out bl, out br); var c = Color.GetValue(sparam, time); var a = Alpha.GetValue(sparam, time); var p2 = node_tr.Transform(src_pos + (particle.Normal * 20)); var n = (p2 - p).Normalized(); billboards.DrawRectAppearance( tex, p, new Vector2(l, w) * sc * 0.5f, new Color4(c, a), tl, tr, bl, br, n, Rotate == null ? 0f : Rotate.GetValue(sparam, time), SortLayers.OBJECT, BlendInfo ); /*var p1_proj = Project(billboards, p); * var p2_proj = Project(billboards, p2); * * var px1 = new Vector2( * (p1_proj.X + 1) / 2 * 1024, * (1 - p1_proj.Y) / 2 * 768); * var px2 = new Vector2( * (p2_proj.X + 1) / 2 * 1024, * (1 - p2_proj.Y) / 2 * 1024 * ); * * var angle = (float)Math.Atan2(px2.Y - px1.Y, px2.X - px1.X);*/ /*var src_pos2 = src_pos + (particle.Normal * 20); * var angle = (float)Math.Atan2(src_pos2.Y - src_pos.Y, src_pos2.Z - src_pos.Z); * var angle_deg = MathHelper.RadiansToDegrees(angle); * billboards.Draw( * tex, * p, * new Vector2(l, w) * sc * 0.5f, * new Color4(c, a), * tl, * tr, * bl, * br, * angle, //Rotate == null ? 0f : Rotate.GetValue(sparam, time), * SortLayers.OBJECT, * BlendInfo * );*/ if (DrawNormals) { Debug.DrawLine(p - (n * 8), p + (n * 8)); } }
protected virtual void SetParticle(int idx, ParticleEffect fx, ParticleEffectInstance instance, ref Matrix4 transform, float sparam) { }