Skip to content

Commit

Permalink
added support for dynamic capacity
Browse files Browse the repository at this point in the history
  • Loading branch information
codex128 committed Jan 6, 2024
1 parent da559ef commit cbd1bbc
Show file tree
Hide file tree
Showing 10 changed files with 241 additions and 56 deletions.
3 changes: 3 additions & 0 deletions src/codex/vfx/mesh/MeshPrototype.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@
*/
public class MeshPrototype {

/**
* Prototype of a 1x1 quad consisting of two triangles.
*/
public static final MeshPrototype QUAD = new MeshPrototype().setVerts(
new Vector3f(-1, 1, 0),
new Vector3f(1, 1, 0),
Expand Down
39 changes: 39 additions & 0 deletions src/codex/vfx/mesh/Quad.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/*
* Click nbfs://nbhost/SystemFileSystem/Templates/Licenses/license-default.txt to change this license
* Click nbfs://nbhost/SystemFileSystem/Templates/Classes/Class.java to edit this template
*/
package codex.vfx.mesh;

import com.jme3.math.Vector3f;
import com.jme3.scene.Mesh;
import com.jme3.scene.VertexBuffer.Type;
import com.jme3.util.BufferUtils;

/**
*
* @author codex
*/
public class Quad extends Mesh {

private static final float[] uvs = {1, 1, 1, 0, 0, 0, 0, 1};
private static final int[] index = {0, 2, 1, 0, 3, 2};

public Quad(Vector3f normal, Vector3f up, float width, float height, float originX, float originY) {
Vector3f across = normal.cross(up);
Vector3f climb = normal.cross(across);
Vector3f[] verts = {
across.mult(-width*originX).addLocal(climb.mult(-height*originY)),
across.mult(-width*originX).addLocal(climb.mult(height*originY)),
across.mult(width*originX).addLocal(climb.mult(height*originY)),
across.mult(width*originX).addLocal(climb.mult(-height*originY)),
};
Vector3f[] normals = {normal, normal, normal, normal};
setBuffer(Type.Position, 3, BufferUtils.createFloatBuffer(verts));
setBuffer(Type.Normal, 3, BufferUtils.createFloatBuffer(normals));
setBuffer(Type.TexCoord, 2, BufferUtils.createFloatBuffer(uvs));
setBuffer(Type.Index, 3, BufferUtils.createIntBuffer(index));
updateCounts();
updateBound();
}

}
135 changes: 127 additions & 8 deletions src/codex/vfx/particles/ParticleGroup.java
Original file line number Diff line number Diff line change
Expand Up @@ -32,20 +32,40 @@ public class ParticleGroup <T extends Particle> extends Node implements VirtualE
private OverflowStrategy<T> overflow = OverflowStrategy.CullNew;
private EmissionVolume volume = new EmissionPoint();
private int capacity;
private int dynamicSizingStep = -1;
private float updateSpeed = 1f, decay = 1f;
private float time = 0f, delay = 0f;
private boolean playing = true, worldPlayState = true;
private boolean inheritDecayRate = false;

/**
* Creates a particle group with zero capacity.
*/
public ParticleGroup() {
this(ParticleGroup.class.getSimpleName(), 0);
}
/**
* Creates a particle group with zero capacity.
*
* @param name name of this spatial
*/
public ParticleGroup(String name) {
this(name, 0);
}
/**
* Creates a particle group with the given capacity.
*
* @param capacity
*/
public ParticleGroup(int capacity) {
this(ParticleGroup.class.getSimpleName(), capacity);
}
/**
* Creates a particle group with the given capacity.
*
* @param name name of this spatial
* @param capacity
*/
public ParticleGroup(String name, int capacity) {
super(name);
assert capacity >= 0 : "Group capacity must be greater than or equal to zero.";
Expand Down Expand Up @@ -95,7 +115,9 @@ protected void update(boolean update, float tpf, float decay) {
if (worldPlayState) {
time += t;
}
t *= (inDelayZone() ? 0 : 1);
if (inDelayZone()) {
t = 0;
}
decay *= this.decay;
if (worldPlayState) {
updateParticles(t, (inheritDecayRate ? decay : this.decay));
Expand All @@ -122,8 +144,12 @@ protected void updateParticles(float tpf, float decay) {

protected boolean addParticle(T particle) {
if (capacity > 0 && worldPlayState && particles.add(particle)) {
if (particles.size() > capacity && overflow.removeParticle(this, particle)) {
return false;
if (particles.size() > capacity) {
if (dynamicSizingStep >= 0) {
capacity = particles.size()+dynamicSizingStep;
} else if (overflow.removeParticle(this, particle)) {
return false;
}
}
for (ParticleDriver<T> d : drivers) {
d.particleAdded(this, particle);
Expand All @@ -135,7 +161,7 @@ protected boolean addParticle(T particle) {
protected boolean validateGroupSize(boolean exception) {
if (particles.size() > capacity) {
if (exception) {
throw new IllegalStateException("Number of particles cannot exceed the group capacity.");
throw new IllegalStateException("Internal Error: number of particles exceeded the group capacity.");
}
return false;
}
Expand Down Expand Up @@ -174,8 +200,12 @@ public int addAll(Collection<T> particles) {
}
int c = 0;
for (T p : particles) {
if (this.particles.size() >= capacity && !overflow.removeParticle(this, p)) {
continue;
if (this.particles.size() >= capacity) {
if (dynamicSizingStep >= 0) {
capacity = this.particles.size()+dynamicSizingStep;
} else if (!overflow.removeParticle(this, p)) {
continue;
}
}
if (addParticle(p)) c++;
}
Expand Down Expand Up @@ -351,6 +381,30 @@ public void setInitialDelay(float delay) {
public void setInheritDecayRate(boolean inheritDecayRate) {
this.inheritDecayRate = inheritDecayRate;
}
/**
* Sets this group to dynamically resize its capacity to accept more particles.
* <p>
* The integer value indicates how much above the necessary capacity
* the group's capacity is set to. A dynamic sizing step of 3 would resize
* the group to be 3 greater than the current number of particles. Resizing
* only occurs when the number of particles would exceed the group's capacity.
* <p>
* This feature can potentially put more strain on the system, because particle
* geometries have to create new buffers to match the changing capacity. It is
* recommended to set the dynamic resizing step as high as reasonably possible
* in order to cut down of the number of reallocations the geometries must do.
* That is, if this feature must be used at all.
* <p>
* To disable this feature, set the dynamic sizing step to less than zero.
* <p>
* default={@code -1} (disabled)
*
* @param step
*/
@VfxAttribute(name="dynamicSizingStep")
public void setDynamicSizingStep(int step) {
this.dynamicSizingStep = step;
}

/**
* Sets this group's play state to true.
Expand Down Expand Up @@ -396,19 +450,35 @@ public boolean flipPlayState() {
return (playing = !playing);
}
/**
* Resets the group by removing all particles and reseting the simulation time.
* Resets the group by removing all particles, reseting the simulation time,
* and reseting child particle groups.
* <p>
* Drivers are also notified, so they can reset themselves accordingly.
* <br>Will not reset if paused.
*/
@VfxCommand(name="reset")
public void reset() {
reset(true);
}
/**
* Resets the group by removing all particles, reseting the simulation time,
* and (optionally) reseting child particle groups.
* <p>
* Drivers are also notified, so they can reset themselves accordingly.
* <br>Will not reset if paused.
*
* @param resetChildren if true, child particle groups will also be reset
*/
public void reset(boolean resetChildren) {
if (worldPlayState) {
particles.clear();
time = 0;
for (ParticleDriver<T> d : drivers) {
d.groupReset(this);
}
if (resetChildren) for (ParticleGroup g : childGroups) {
g.reset(true);
}
}
}

Expand All @@ -424,17 +494,27 @@ public T get(int i) {
/**
* Gets the list of particles this group controls.
* <p>
* Note: {@code ParticleGroup} is iterable in this respect.
* <p>
* <em>Do not modify the returned list!</em>
*
* @return
*/
public ArrayList<T> getParticleList() {
return particles;
}
/**
*
* @return
*/
@VfxAttribute(name="overflowStrategy", input=false)
public OverflowStrategy<T> getOverflowStrategy() {
return overflow;
}
/**
*
* @return
*/
@VfxAttribute(name="volume", input=false)
public EmissionVolume getVolume() {
return volume;
Expand All @@ -449,6 +529,16 @@ public EmissionVolume getVolume() {
public LinkedList<ParticleGroup> getChildGroupList() {
return childGroups;
}
/**
* Gets the list of drivers controlling this particle group.
* <p>
* <em>Do not modify the returned list!</em>
*
* @return
*/
public LinkedList<ParticleDriver<T>> getDriverList() {
return drivers;
}
/**
* Get the parent particle group of this group.
*
Expand All @@ -468,7 +558,7 @@ public boolean isEmpty() {
}
/**
* Returns true if the number of particles in this group is
* greater than or equal to the capacity.
* equal to its capacity.
*
* @return
*/
Expand All @@ -487,6 +577,11 @@ public boolean isFull() {
public boolean getLocalPlayState() {
return playing;
}
/**
* Returns true if the current time is within this group's delay zone.
*
* @return
*/
public boolean inDelayZone() {
return time < delay;
}
Expand All @@ -508,22 +603,46 @@ public int size() {
public int capacity() {
return capacity;
}
/**
*
* @return
*/
@Override
public float getUpdateSpeed() {
return updateSpeed;
}
/**
*
* @return
*/
@VfxAttribute(name="decayRate", input=false)
public float getDecayRate() {
return decay;
}
/**
*
* @return
*/
@Override
public float getInitialDelay() {
return delay;
}
/**
*
* @return
*/
@VfxAttribute(name="inheritDecayRate", input=false)
public boolean isInheritDecayRate() {
return inheritDecayRate;
}
/**
*
* @return
*/
@VfxAttribute(name="dynamicSizingStep", input=false)
public int getDynamicSizingStep() {
return dynamicSizingStep;
}
/**
* Fetches the world update speed of this group.
*
Expand Down
24 changes: 24 additions & 0 deletions src/codex/vfx/particles/drivers/BehaviorDriver.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/*
* Click nbfs://nbhost/SystemFileSystem/Templates/Licenses/license-default.txt to change this license
* Click nbfs://nbhost/SystemFileSystem/Templates/Classes/Class.java to edit this template
*/
package codex.vfx.particles.drivers;

import codex.vfx.particles.Particle;
import codex.vfx.particles.ParticleGroup;

/**
*
* @author codex
* @param <T>
*/
public abstract class BehaviorDriver <T extends Particle> implements ParticleDriver<T> {

@Override
public void updateGroup(ParticleGroup<T> group, float tpf) {}
@Override
public void particleAdded(ParticleGroup<T> group, T particle) {}
@Override
public void groupReset(ParticleGroup<T> group) {}

}
6 changes: 6 additions & 0 deletions src/codex/vfx/particles/geometry/TriParticleGeometry.java
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,12 @@ public class TriParticleGeometry extends ParticleGeometry<ParticleData> {
private final MeshPrototype prototype;
private int size = -1;

/**
* Creates a geometry displaying the particle group with the mesh prototype.
*
* @param group
* @param prototype
*/
public TriParticleGeometry(ParticleGroup group, MeshPrototype prototype) {
super(group);
this.prototype = prototype;
Expand Down
12 changes: 12 additions & 0 deletions src/codex/vfx/utils/VfxUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,18 @@ public static Vector3f random(Vector3f a, Vector3f b) {
);
}

/**
* Constructs a random unit vector with its magnitude between
* the minimum and maximum distances.
*
* @param minDist
* @param maxDist
* @return
*/
public static Vector3f random(float minDist, float maxDist) {
return gen.nextUnitVector3f().multLocal(gen.nextFloat(minDist, maxDist));
}

/**
* Generates a random vector within a box.
*
Expand Down
Loading

0 comments on commit cbd1bbc

Please sign in to comment.