/** * update position (using current position and velocity), color (interpolating between start and * end color), size (interpolating between start and end size), spin (using parent's spin speed) * and current age of particle. If this particle's age is greater than its lifespan, it is set to * status DEAD. * * <p>Note that this only changes the parameters of the Particle, not the geometry the particle is * associated with. * * @param secondsPassed number of seconds passed since last update. * @return true if this particle is not ALIVE (in other words, if it is ready to be reused.) */ public boolean updateAndCheck(final double secondsPassed) { if (status != Status.Alive) { return true; } currentAge += secondsPassed * 1000; // add ms time to age if (currentAge > lifeSpan) { killParticle(); return true; } final Vector3 temp = Vector3.fetchTempInstance(); _position.addLocal(_velocity.multiply(secondsPassed * 1000f, temp)); Vector3.releaseTempInstance(temp); // get interpolated values from appearance ramp: parent.getRamp().getValuesAtAge(currentAge, lifeSpan, currColor, values, parent); // interpolate colors final int verts = ParticleSystem.getVertsForParticleType(type); for (int x = 0; x < verts; x++) { BufferUtils.setInBuffer( currColor, parent.getParticleGeometry().getMeshData().getColorBuffer(), startIndex + x); } // check for tex animation final int newTexIndex = parent.getTexAnimation().getTexIndexAtAge(currentAge, lifeSpan, parent); // Update tex coords if applicable if (currentTexIndex != newTexIndex) { // Only supported in Quad type for now. if (ParticleType.Quad.equals(parent.getParticleType())) { // determine side final float side = (float) Math.sqrt(parent.getTexQuantity()); int index = newTexIndex; if (index >= parent.getTexQuantity()) { index %= parent.getTexQuantity(); } // figure row / col final float row = side - (int) (index / side) - 1; final float col = index % side; // set texcoords final float sU = col / side, eU = (col + 1) / side; final float sV = row / side, eV = (row + 1) / side; final FloatBuffer texs = parent.getParticleGeometry().getMeshData().getTextureCoords(0).getBuffer(); texs.position(startIndex * 2); texs.put(eU).put(sV); texs.put(eU).put(eV); texs.put(sU).put(eV); texs.put(sU).put(sV); texs.clear(); } currentTexIndex = newTexIndex; } return false; }
public void killParticle() { setStatus(Status.Dead); final Vector3 tempVec3 = Vector3.fetchTempInstance(); final FloatBuffer vertexBuffer = parent.getParticleGeometry().getMeshData().getVertexBuffer(); BufferUtils.populateFromBuffer(tempVec3, vertexBuffer, startIndex); final int verts = ParticleSystem.getVertsForParticleType(type); for (int x = 1; x < verts; x++) { BufferUtils.setInBuffer(tempVec3, vertexBuffer, startIndex + x); } Vector3.releaseTempInstance(tempVec3); }
/** * Reset particle conditions. Besides the passed lifespan, we also reset color, size, and spin * angle to their starting values (as given by parent.) Status is set to Status.Available. * * @param lifeSpan the recreated particle's new lifespan */ public void recreateParticle(final double lifeSpan) { this.lifeSpan = lifeSpan; final int verts = ParticleSystem.getVertsForParticleType(type); currColor.set(parent.getStartColor()); for (int x = 0; x < verts; x++) { BufferUtils.setInBuffer( currColor, parent.getParticleGeometry().getMeshData().getColorBuffer(), startIndex + x); } values[VAL_CURRENT_SIZE] = parent.getStartSize(); currentAge = 0; values[VAL_CURRENT_MASS] = 1; status = Status.Available; }
/** * Update the vertices for this particle, taking size, spin and viewer into consideration. In the * case of particle type ParticleType.GeomMesh, the original triangle normal is maintained rather * than rotating it to face the camera or parent vectors. * * @param cam Camera to use in determining viewer aspect. If null, or if parent is not set to * camera facing, parent's left and up vectors are used. */ public void updateVerts(final Camera cam) { final double orient = parent.getParticleOrientation() + values[VAL_CURRENT_SPIN]; final double currSize = values[VAL_CURRENT_SIZE]; if (type == ParticleSystem.ParticleType.GeomMesh || type == ParticleSystem.ParticleType.Point) {; // nothing to do } else if (cam != null && parent.isCameraFacing()) { final ReadOnlyVector3 camUp = cam.getUp(); final ReadOnlyVector3 camLeft = cam.getLeft(); final ReadOnlyVector3 camDir = cam.getDirection(); if (parent.isVelocityAligned()) { bbX.set(_velocity).normalizeLocal().multiplyLocal(currSize); camDir.cross(bbX, bbY).normalizeLocal().multiplyLocal(currSize); } else if (orient == 0) { bbX.set(camLeft).multiplyLocal(currSize); bbY.set(camUp).multiplyLocal(currSize); } else { final double cA = MathUtils.cos(orient) * currSize; final double sA = MathUtils.sin(orient) * currSize; bbX.set(camLeft) .multiplyLocal(cA) .addLocal(camUp.getX() * sA, camUp.getY() * sA, camUp.getZ() * sA); bbY.set(camLeft) .multiplyLocal(-sA) .addLocal(camUp.getX() * cA, camUp.getY() * cA, camUp.getZ() * cA); } } else { bbX.set(parent.getLeftVector()).multiplyLocal(0); bbY.set(parent.getUpVector()).multiplyLocal(0); } final Vector3 tempVec3 = Vector3.fetchTempInstance(); final FloatBuffer vertexBuffer = parent.getParticleGeometry().getMeshData().getVertexBuffer(); switch (type) { case Quad: { _position.subtract(bbX, tempVec3).subtractLocal(bbY); BufferUtils.setInBuffer(tempVec3, vertexBuffer, startIndex + 0); _position.subtract(bbX, tempVec3).addLocal(bbY); BufferUtils.setInBuffer(tempVec3, vertexBuffer, startIndex + 1); _position.add(bbX, tempVec3).addLocal(bbY); BufferUtils.setInBuffer(tempVec3, vertexBuffer, startIndex + 2); _position.add(bbX, tempVec3).subtractLocal(bbY); BufferUtils.setInBuffer(tempVec3, vertexBuffer, startIndex + 3); break; } case GeomMesh: { final Quaternion tempQuat = Quaternion.fetchTempInstance(); final ReadOnlyVector3 norm = triModel.getNormal(); if (orient != 0) { tempQuat.fromAngleNormalAxis(orient, norm); } for (int x = 0; x < 3; x++) { if (orient != 0) { tempQuat.apply(triModel.get(x), tempVec3); } else { tempVec3.set(triModel.get(x)); } tempVec3.multiplyLocal(currSize).addLocal(_position); BufferUtils.setInBuffer(tempVec3, vertexBuffer, startIndex + x); } Quaternion.releaseTempInstance(tempQuat); break; } case Triangle: { _position .subtract(3 * bbX.getX(), 3 * bbX.getY(), 3 * bbX.getZ(), tempVec3) .subtractLocal(bbY); BufferUtils.setInBuffer(tempVec3, vertexBuffer, startIndex + 0); _position.add(bbX, tempVec3).addLocal(3 * bbY.getX(), 3 * bbY.getY(), 3 * bbY.getZ()); BufferUtils.setInBuffer(tempVec3, vertexBuffer, startIndex + 1); _position.add(bbX, tempVec3).subtractLocal(bbY); BufferUtils.setInBuffer(tempVec3, vertexBuffer, startIndex + 2); break; } case Line: { _position.subtract(bbX, tempVec3); BufferUtils.setInBuffer(tempVec3, vertexBuffer, startIndex); _position.add(bbX, tempVec3); BufferUtils.setInBuffer(tempVec3, vertexBuffer, startIndex + 1); break; } case Point: { BufferUtils.setInBuffer(_position, vertexBuffer, startIndex); break; } } Vector3.releaseTempInstance(tempVec3); }