aboutsummaryrefslogtreecommitdiff
path: root/engine/src/core/com/jme3/effect/shapes/EmitterMeshVertexShape.java
blob: 28ee8b4f7a3eeccb69a6c996d4db64f97a27edd8 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
package com.jme3.effect.shapes;

import com.jme3.export.InputCapsule;
import com.jme3.export.JmeExporter;
import com.jme3.export.JmeImporter;
import com.jme3.export.OutputCapsule;
import com.jme3.math.FastMath;
import com.jme3.math.Vector3f;
import com.jme3.scene.Mesh;
import com.jme3.scene.VertexBuffer.Type;
import com.jme3.util.BufferUtils;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

/**
 * This emiter shape emits the particles from the given shape's vertices
 * @author Marcin Roguski (Kaelthas)
 */
public class EmitterMeshVertexShape implements EmitterShape {

    protected List<List<Vector3f>> vertices;
    protected List<List<Vector3f>> normals;

    /**
     * Empty constructor. Sets nothing.
     */
    public EmitterMeshVertexShape() {
    }

    /**
     * Constructor. It stores a copy of vertex list of all meshes.
     * @param meshes
     *        a list of meshes that will form the emitter's shape
     */
    public EmitterMeshVertexShape(List<Mesh> meshes) {
        this.setMeshes(meshes);
    }

    /**
     * This method sets the meshes that will form the emiter's shape.
     * @param meshes
     *        a list of meshes that will form the emitter's shape
     */
    public void setMeshes(List<Mesh> meshes) {
        Map<Vector3f, Vector3f> vertToNormalMap = new HashMap<Vector3f, Vector3f>();

        this.vertices = new ArrayList<List<Vector3f>>(meshes.size());
        this.normals = new ArrayList<List<Vector3f>>(meshes.size());
        for (Mesh mesh : meshes) {
            // fetching the data
            float[] vertexTable = BufferUtils.getFloatArray(mesh.getFloatBuffer(Type.Position));
            float[] normalTable = BufferUtils.getFloatArray(mesh.getFloatBuffer(Type.Normal));

            // unifying normals
            for (int i = 0; i < vertexTable.length; i += 3) {// the tables should have the same size and be dividable by 3
                Vector3f vert = new Vector3f(vertexTable[i], vertexTable[i + 1], vertexTable[i + 2]);
                Vector3f norm = vertToNormalMap.get(vert);
                if (norm == null) {
                    norm = new Vector3f(normalTable[i], normalTable[i + 1], normalTable[i + 2]);
                    vertToNormalMap.put(vert, norm);
                } else {
                    norm.addLocal(normalTable[i], normalTable[i + 1], normalTable[i + 2]);
                }
            }

            // adding data to vertices and normals
            List<Vector3f> vertices = new ArrayList<Vector3f>(vertToNormalMap.size());
            List<Vector3f> normals = new ArrayList<Vector3f>(vertToNormalMap.size());
            for (Entry<Vector3f, Vector3f> entry : vertToNormalMap.entrySet()) {
                vertices.add(entry.getKey());
                normals.add(entry.getValue().normalizeLocal());
            }
            this.vertices.add(vertices);
            this.normals.add(normals);
        }
    }

    /**
     * This method fills the point with coordinates of randomly selected mesh vertex.
     * @param store
     *        the variable to store with coordinates of randomly selected mesh vertex
     */
    @Override
    public void getRandomPoint(Vector3f store) {
        int meshIndex = FastMath.nextRandomInt(0, vertices.size() - 1);
        int vertIndex = FastMath.nextRandomInt(0, vertices.get(meshIndex).size() - 1);
        store.set(vertices.get(meshIndex).get(vertIndex));
    }

    /**
     * This method fills the point with coordinates of randomly selected mesh vertex.
     * The normal param is filled with selected vertex's normal.
     * @param store
     *        the variable to store with coordinates of randomly selected mesh vertex
     * @param normal
     *        filled with selected vertex's normal
     */
    @Override
    public void getRandomPointAndNormal(Vector3f store, Vector3f normal) {
        int meshIndex = FastMath.nextRandomInt(0, vertices.size() - 1);
        int vertIndex = FastMath.nextRandomInt(0, vertices.get(meshIndex).size() - 1);
        store.set(vertices.get(meshIndex).get(vertIndex));
        normal.set(normals.get(meshIndex).get(vertIndex));
    }

    @Override
    public EmitterShape deepClone() {
        try {
            EmitterMeshVertexShape clone = (EmitterMeshVertexShape) super.clone();
            if (this.vertices != null) {
                clone.vertices = new ArrayList<List<Vector3f>>(vertices.size());
                for (List<Vector3f> list : vertices) {
                    List<Vector3f> vectorList = new ArrayList<Vector3f>(list.size());
                    for (Vector3f vector : list) {
                        vectorList.add(vector.clone());
                    }
                    clone.vertices.add(vectorList);
                }
            }
            if (this.normals != null) {
                clone.normals = new ArrayList<List<Vector3f>>(normals.size());
                for (List<Vector3f> list : normals) {
                    List<Vector3f> vectorList = new ArrayList<Vector3f>(list.size());
                    for (Vector3f vector : list) {
                        vectorList.add(vector.clone());
                    }
                    clone.normals.add(vectorList);
                }
            }
            return clone;
        } catch (CloneNotSupportedException e) {
            throw new AssertionError();
        }
    }

    @Override
    public void write(JmeExporter ex) throws IOException {
        OutputCapsule oc = ex.getCapsule(this);
        oc.writeSavableArrayList((ArrayList<List<Vector3f>>) vertices, "vertices", null);
        oc.writeSavableArrayList((ArrayList<List<Vector3f>>) normals, "normals", null);
    }

    @Override
    @SuppressWarnings("unchecked")
    public void read(JmeImporter im) throws IOException {
        InputCapsule ic = im.getCapsule(this);
        this.vertices = ic.readSavableArrayList("vertices", null);
        
        List<List<Vector3f>> tmpNormals = ic.readSavableArrayList("normals", null);
        if (tmpNormals != null){
            this.normals = tmpNormals;
        }
    }
}