/* * Copyright (c) 2003-2009 jMonkeyEngine * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * * Neither the name of 'jMonkeyEngine' nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ //import com.jmex.effects.particles.*; import com.jme.math.FastMath; import java.io.IOException; import com.jme.math.Vector2f; import com.jme.math.Vector3f; import com.jme.renderer.Camera; //import com.jme.renderer.Renderer; //import com.jme.scene.TexCoords; //import com.jme.scene.TriMesh; import com.jme.util.export.InputCapsule; import com.jme.util.export.JMEExporter; import com.jme.util.export.JMEImporter; import com.jme.util.export.OutputCapsule; import com.jme.util.geom.BufferUtils; //import com.jmex.effects.particles.Particle.Status; // import com.jme.scene.TexCoords; /** * ParticleMesh is a particle system that uses TriMesh as its underlying * geometric data. * * @author Joshua Slack * @version $Id: ParticleMesh.java 4133 2009-03-19 20:40:11Z blaine.dev $ */ public class ParticleNode extends ParticleSystem { static final long serialVersionUID = 0; boolean IsStatic() { return false; } // private static final long serialVersionUID = 2L; private boolean useMeshTexCoords = true; private boolean useTriangleNormalEmit = true; // public ParticleMesh() // { // } cVector minima; cVector maxima; public ParticleNode(String name, int numParticles) { super(name, numParticles); //minima = LA.newVector(-0.5, 0, -0.5); //maxima = LA.newVector(0.5, 1, 0.5); CreateMaterial(); live = true; rewind = true; //setRenderQueueMode(Renderer.QUEUE_TRANSPARENT); //setLightCombineMode(LightCombineMode.Off); //setTextureCombineMode(TextureCombineMode.Replace); } public ParticleNode(String name, int numParticles, com.jmex.effects.particles.ParticleSystem.ParticleType type) { super(name, numParticles, type); //setRenderQueueMode(Renderer.QUEUE_TRANSPARENT); //setLightCombineMode(LightCombineMode.Off); //setTextureCombineMode(TextureCombineMode.Replace); } public ParticleNode(String name, TriMesh geom) { super(name, 0, com.jmex.effects.particles.ParticleSystem.ParticleType.GeomMesh); numParticles = geom.getTriangleCount(); psGeom = geom; //setRenderQueueMode(Renderer.QUEUE_TRANSPARENT); //setLightCombineMode(LightCombineMode.Off); //setTextureCombineMode(TextureCombineMode.Replace); initializeParticles(geom.getTriangleCount()); } @Override protected void initializeParticles(int numParticles) { if (particleGeom != null) { //detachChild(particleGeom); } TriMesh mesh = new TriMesh(name + "_mesh"); // { // // private static final long serialVersionUID = 1L; // // @Override // public void updateWorldVectors() // { // ; // Do nothing. // } // }; particleGeom = mesh; //attachChild(mesh); particles = new Particle[numParticles]; if (numParticles == 0) { return; } Vector2f[] sharedTextureData; // setup texture coords switch (getParticleType()) { case GeomMesh: case Triangle: sharedTextureData = new Vector2f[]{ new Vector2f(0.0f, 0.0f), new Vector2f(0.0f, 2.0f), new Vector2f(2.0f, 0.0f) }; break; case Quad: sharedTextureData = new Vector2f[]{ new Vector2f(0.0f, 0.0f), new Vector2f(0.0f, 1.0f), new Vector2f(1.0f, 0.0f), new Vector2f(1.0f, 1.0f) }; break; case Point: sharedTextureData = null; break; default: throw new IllegalStateException("Particle Mesh may only have particle type of ParticleType.Quad, ParticleType.GeomMesh or ParticleType.Triangle"); } int verts = getVertsForParticleType(getParticleType()); geometryCoordinates = FloatBuffer.allocate(numParticles * verts * 3); //BufferUtils.createVector3Buffer(numParticles * verts); // setup indices int[] indices; switch (getParticleType()) { case Triangle: case GeomMesh: indices = new int[numParticles * 3]; for (int j = 0; j < numParticles; j++) { indices[0 + j * 3] = j * 3 + 2; indices[1 + j * 3] = j * 3 + 1; indices[2 + j * 3] = j * 3 + 0; } break; case Quad: indices = new int[numParticles * 6]; for (int j = 0; j < numParticles; j++) { indices[0 + j * 6] = j * 4 + 2; indices[1 + j * 6] = j * 4 + 1; indices[2 + j * 6] = j * 4 + 0; indices[3 + j * 6] = j * 4 + 2; indices[4 + j * 6] = j * 4 + 3; indices[5 + j * 6] = j * 4 + 1; } break; case Point: indices = new int[numParticles]; for (int j = 0; j < numParticles; j++) { indices[j] = j; } break; default: throw new IllegalStateException("Particle Mesh may only have particle type of ParticleType.Quad, ParticleType.GeomMesh or ParticleType.Triangle"); } appearanceColors = FloatBuffer.allocate(numParticles * verts * 4); //BufferUtils.createColorBuffer(numParticles * verts); sizesBuffer = FloatBuffer.allocate(numParticles * verts * 3); //BufferUtils.createVector3Buffer(numParticles * verts); mesh.setVertexBuffer(geometryCoordinates); mesh.setColorBuffer(appearanceColors); mesh.setSizeBuffer(sizesBuffer); mesh.setTextureCoords(new TexCoords(BufferUtils.createVector2Buffer(numParticles * verts)), 0); mesh.setIndexBuffer(BufferUtils.createIntBuffer(indices)); invScale = new Vector3f(); for (int k = 0; k < numParticles; k++) { particles[k] = new Particle(this); particles[k].init(); particles[k].setStartIndex(k * verts); for (int a = verts - 1; a >= 0; a--) { int ind = (k * verts) + a; if (verts > 1) { if (particleType == com.jmex.effects.particles.ParticleSystem.ParticleType.GeomMesh && useMeshTexCoords) { int index = ((TriMesh) psGeom).getIndexBuffer().get(ind); BufferUtils.populateFromBuffer(workVect2, psGeom.getTextureCoords(0).coords, index); BufferUtils.setInBuffer(workVect2, mesh.getTextureCoords(0).coords, ind); } else { BufferUtils.setInBuffer(sharedTextureData[a], mesh.getTextureCoords(0).coords, ind); } } //BufferUtils.setInBuffer(particles[k].getCurrentColor(), appearanceColors, (ind)); appearanceColors.set(ind, particles[k].getCurrentColor()); } } // updateRenderState(); // particleGeom.setCastsShadows(false); } /** * Stop emiting particles * Kill all available particles. (status=dead) * @author clovis teixeira */ // public void stopEmitting() // { // //for (int k = 0; k < numParticles; k++) // for (int k = 0; k < particles.length; k++) // { // if (particles[k].getStatus() == Particle.Status0.Available) // { // particles[k].setStatus(Particle.Status0.Dead); // } // } // } // public void draw(Renderer r) // { // Camera camera = r.getCamera(); // for (int i = 0; i < particles.length; i++) // { // Particle particle = particles[i]; // if (particle.getStatus() == com.jmex.effects.particles.Particle.Status.Alive) // { // particle.updateVerts(camera); // } // } // // if (!particlesInWorldCoords) // { // getParticleGeometry().getWorldTranslation().set(getWorldTranslation()); // getParticleGeometry().getWorldRotation().set(getWorldRotation()); // } else // { // getParticleGeometry().getWorldTranslation().zero(); // getParticleGeometry().getWorldRotation().loadIdentity(); // } // getParticleGeometry().getWorldScale().set(getWorldScale()); // getParticleGeometry().draw(r); // } static Sphere test = new Sphere(); static { test.material = null; test.GenUVs(); test.bRep.Stripify(); test.bRep.colors = null; } void linkVerticesThis(Object3D other) { support = other; link2master = support != null; } void resetMasterNode(boolean smooth) { } void Reset() { initAllParticlesLocation(); forceRespawn(); } void Step() { if (isAllParticleInactive()) { if (FastMath.nextRandomFloat() > standby) Reset(); } int step = 1; if (CameraPane.FAST) { step *= CameraPane.STEP; } getParticleController().update(step); for (int i = 0; i < particles.length; i++) { Particle particle = particles[i]; if (i > getNumParticles()) // aout 2013 particle.setStatus(Particle.Status0.Hidden); //if (particle.getStatus() == Particle.Status0.Alive) { particle.updateVerts(null); } } } void DrawNode(iCameraPane display, Object3D /*Composite*/ root, boolean selected) // ?? { if (display.DrawMode() == display.SELECTION || display.IsBoxMode()) return; // hum... Object3D geo = test; if (support != null && link2master) geo = support; if (live && Globals.isLIVE() && (display.DrawMode() == display.SHADOW || !Globals.RENDERSHADOW)) // june 2013 { Step(); } getParticleGeometry().DrawParticles(display,geo,selected, random); } public void resetParticleVelocity(int i) { if (particleType == com.jmex.effects.particles.ParticleSystem.ParticleType.GeomMesh && useTriangleNormalEmit) { particles[i].getVelocity().set(particles[i].getTriangleModel().getNormal()); particles[i].getVelocity().multLocal(emissionDirection); particles[i].getVelocity().multLocal(getInitialVelocity()); } else { super.resetParticleVelocity(i); } } public boolean isUseMeshTexCoords() { return useMeshTexCoords; } public void setUseMeshTexCoords(boolean useMeshTexCoords) { this.useMeshTexCoords = useMeshTexCoords; } public boolean isUseTriangleNormalEmit() { return useTriangleNormalEmit; } public void setUseTriangleNormalEmit(boolean useTriangleNormalEmit) { this.useTriangleNormalEmit = useTriangleNormalEmit; } // // /** // * determines if a collision between this trimesh and a given spatial occurs // * if it has true is returned, otherwise false is returned. // */ // public boolean hasCollision(Spatial scene, boolean checkTriangles) { // if (this == scene || !isCollidable || !scene.isCollidable()) { // return false; // } // if (getWorldBound().intersects(scene.getWorldBound())) { // if (scene instanceof Node) { // Node parent = (Node) scene; // for (int i = 0; i < parent.getQuantity(); i++) { // if (hasCollision(parent.getChild(i), checkTriangles)) { // return true; // } // } // // return false; // } // // if (!checkTriangles) { // return true; // } // // return hasTriangleCollision((TriMesh) scene); // } // // return false; // } // // /** // * determines if this TriMesh has made contact with the give scene. The // * scene is recursively transversed until a trimesh is found, at which time // * the two trimesh OBBTrees are then compared to find the triangles that // * hit. // */ // public void findCollisions(Spatial scene, CollisionResults results) { // if (this == scene || !isCollidable || !scene.isCollidable()) { // return; // } // // if (getWorldBound().intersects(scene.getWorldBound())) { // if (scene instanceof Node) { // Node parent = (Node) scene; // for (int i = 0; i < parent.getQuantity(); i++) { // findCollisions(parent.getChild(i), results); // } // } else { // results.addCollision(getParticleGeometry(), (Geometry) scene); // } // } // } // // /** // * This function checks for intersection between this trimesh and the given // * one. On the first intersection, true is returned. // * // * @param toCheck // * The intersection testing mesh. // * @return True if they intersect. // */ // public boolean hasTriangleCollision(TriMesh toCheck) { // TriMesh a,b; // for (int x = 0; x < getBatchCount(); x++) { // a = getBatch(x); // if (a == null || !a.isEnabled()) continue; // for (int y = 0; y < toCheck.getBatchCount(); y++) { // b = toCheck.getBatch(y); // if (b == null || !b.isEnabled()) continue; // if (hasTriangleCollision(toCheck, x, y)) // return true; // } // } // return false; // } // // /** // * This function checks for intersection between this trimesh and the given // * one. On the first intersection, true is returned. // * // * @param toCheck // * The intersection testing mesh. // * @return True if they intersect. // */ // public boolean hasTriangleCollision(TriMesh toCheck, int thisBatch, int checkBatch) { // CollisionTree thisCT = CollisionTreeManager.getInstance().getCollisionTree(getBatch(thisBatch)); // CollisionTree toCheckCT = CollisionTreeManager.getInstance().getCollisionTree(toCheck.getBatch(checkBatch)); // // if (thisCT == null // || toCheckCT == null // || !isCollidable || !toCheck.isCollidable()) // return false; // // thisCT.getBounds().transform( // worldRotation, worldTranslation, worldScale, // thisCT.getWorldBounds()); // return thisCT.intersect(toCheckCT); // } public void write(JMEExporter e) throws IOException { super.write(e); OutputCapsule capsule = null; // e.getCapsule(this); capsule.write(useMeshTexCoords, "useMeshTexCoords", true); capsule.write(useTriangleNormalEmit, "useTriangleNormalEmit", true); } public void read(JMEImporter e) throws IOException { super.read(e); InputCapsule capsule = null; // e.getCapsule(this); useMeshTexCoords = capsule.readBoolean("useMeshTexCoords", true); useTriangleNormalEmit = capsule.readBoolean("useTriangleNormalEmit", true); } // @Override // public TriMesh getParticleGeometry() // { // return (TriMesh) particleGeom; // } void Invariants() { } }