Home | History | Annotate | Download | only in shapes
      1 package com.jme3.effect.shapes;
      2 
      3 import com.jme3.export.InputCapsule;
      4 import com.jme3.export.JmeExporter;
      5 import com.jme3.export.JmeImporter;
      6 import com.jme3.export.OutputCapsule;
      7 import com.jme3.math.FastMath;
      8 import com.jme3.math.Vector3f;
      9 import com.jme3.scene.Mesh;
     10 import com.jme3.scene.VertexBuffer.Type;
     11 import com.jme3.util.BufferUtils;
     12 import java.io.IOException;
     13 import java.util.ArrayList;
     14 import java.util.HashMap;
     15 import java.util.List;
     16 import java.util.Map;
     17 import java.util.Map.Entry;
     18 
     19 /**
     20  * This emiter shape emits the particles from the given shape's vertices
     21  * @author Marcin Roguski (Kaelthas)
     22  */
     23 public class EmitterMeshVertexShape implements EmitterShape {
     24 
     25     protected List<List<Vector3f>> vertices;
     26     protected List<List<Vector3f>> normals;
     27 
     28     /**
     29      * Empty constructor. Sets nothing.
     30      */
     31     public EmitterMeshVertexShape() {
     32     }
     33 
     34     /**
     35      * Constructor. It stores a copy of vertex list of all meshes.
     36      * @param meshes
     37      *        a list of meshes that will form the emitter's shape
     38      */
     39     public EmitterMeshVertexShape(List<Mesh> meshes) {
     40         this.setMeshes(meshes);
     41     }
     42 
     43     /**
     44      * This method sets the meshes that will form the emiter's shape.
     45      * @param meshes
     46      *        a list of meshes that will form the emitter's shape
     47      */
     48     public void setMeshes(List<Mesh> meshes) {
     49         Map<Vector3f, Vector3f> vertToNormalMap = new HashMap<Vector3f, Vector3f>();
     50 
     51         this.vertices = new ArrayList<List<Vector3f>>(meshes.size());
     52         this.normals = new ArrayList<List<Vector3f>>(meshes.size());
     53         for (Mesh mesh : meshes) {
     54             // fetching the data
     55             float[] vertexTable = BufferUtils.getFloatArray(mesh.getFloatBuffer(Type.Position));
     56             float[] normalTable = BufferUtils.getFloatArray(mesh.getFloatBuffer(Type.Normal));
     57 
     58             // unifying normals
     59             for (int i = 0; i < vertexTable.length; i += 3) {// the tables should have the same size and be dividable by 3
     60                 Vector3f vert = new Vector3f(vertexTable[i], vertexTable[i + 1], vertexTable[i + 2]);
     61                 Vector3f norm = vertToNormalMap.get(vert);
     62                 if (norm == null) {
     63                     norm = new Vector3f(normalTable[i], normalTable[i + 1], normalTable[i + 2]);
     64                     vertToNormalMap.put(vert, norm);
     65                 } else {
     66                     norm.addLocal(normalTable[i], normalTable[i + 1], normalTable[i + 2]);
     67                 }
     68             }
     69 
     70             // adding data to vertices and normals
     71             List<Vector3f> vertices = new ArrayList<Vector3f>(vertToNormalMap.size());
     72             List<Vector3f> normals = new ArrayList<Vector3f>(vertToNormalMap.size());
     73             for (Entry<Vector3f, Vector3f> entry : vertToNormalMap.entrySet()) {
     74                 vertices.add(entry.getKey());
     75                 normals.add(entry.getValue().normalizeLocal());
     76             }
     77             this.vertices.add(vertices);
     78             this.normals.add(normals);
     79         }
     80     }
     81 
     82     /**
     83      * This method fills the point with coordinates of randomly selected mesh vertex.
     84      * @param store
     85      *        the variable to store with coordinates of randomly selected mesh vertex
     86      */
     87     @Override
     88     public void getRandomPoint(Vector3f store) {
     89         int meshIndex = FastMath.nextRandomInt(0, vertices.size() - 1);
     90         int vertIndex = FastMath.nextRandomInt(0, vertices.get(meshIndex).size() - 1);
     91         store.set(vertices.get(meshIndex).get(vertIndex));
     92     }
     93 
     94     /**
     95      * This method fills the point with coordinates of randomly selected mesh vertex.
     96      * The normal param is filled with selected vertex's normal.
     97      * @param store
     98      *        the variable to store with coordinates of randomly selected mesh vertex
     99      * @param normal
    100      *        filled with selected vertex's normal
    101      */
    102     @Override
    103     public void getRandomPointAndNormal(Vector3f store, Vector3f normal) {
    104         int meshIndex = FastMath.nextRandomInt(0, vertices.size() - 1);
    105         int vertIndex = FastMath.nextRandomInt(0, vertices.get(meshIndex).size() - 1);
    106         store.set(vertices.get(meshIndex).get(vertIndex));
    107         normal.set(normals.get(meshIndex).get(vertIndex));
    108     }
    109 
    110     @Override
    111     public EmitterShape deepClone() {
    112         try {
    113             EmitterMeshVertexShape clone = (EmitterMeshVertexShape) super.clone();
    114             if (this.vertices != null) {
    115                 clone.vertices = new ArrayList<List<Vector3f>>(vertices.size());
    116                 for (List<Vector3f> list : vertices) {
    117                     List<Vector3f> vectorList = new ArrayList<Vector3f>(list.size());
    118                     for (Vector3f vector : list) {
    119                         vectorList.add(vector.clone());
    120                     }
    121                     clone.vertices.add(vectorList);
    122                 }
    123             }
    124             if (this.normals != null) {
    125                 clone.normals = new ArrayList<List<Vector3f>>(normals.size());
    126                 for (List<Vector3f> list : normals) {
    127                     List<Vector3f> vectorList = new ArrayList<Vector3f>(list.size());
    128                     for (Vector3f vector : list) {
    129                         vectorList.add(vector.clone());
    130                     }
    131                     clone.normals.add(vectorList);
    132                 }
    133             }
    134             return clone;
    135         } catch (CloneNotSupportedException e) {
    136             throw new AssertionError();
    137         }
    138     }
    139 
    140     @Override
    141     public void write(JmeExporter ex) throws IOException {
    142         OutputCapsule oc = ex.getCapsule(this);
    143         oc.writeSavableArrayList((ArrayList<List<Vector3f>>) vertices, "vertices", null);
    144         oc.writeSavableArrayList((ArrayList<List<Vector3f>>) normals, "normals", null);
    145     }
    146 
    147     @Override
    148     @SuppressWarnings("unchecked")
    149     public void read(JmeImporter im) throws IOException {
    150         InputCapsule ic = im.getCapsule(this);
    151         this.vertices = ic.readSavableArrayList("vertices", null);
    152 
    153         List<List<Vector3f>> tmpNormals = ic.readSavableArrayList("normals", null);
    154         if (tmpNormals != null){
    155             this.normals = tmpNormals;
    156         }
    157     }
    158 }
    159