1package com.jme3.scene.plugins.blender.modifiers;
2
3import com.jme3.effect.ParticleEmitter;
4import com.jme3.effect.shapes.EmitterMeshVertexShape;
5import com.jme3.effect.shapes.EmitterShape;
6import com.jme3.material.Material;
7import com.jme3.scene.Geometry;
8import com.jme3.scene.Mesh;
9import com.jme3.scene.Node;
10import com.jme3.scene.Spatial;
11import com.jme3.scene.plugins.blender.BlenderContext;
12import com.jme3.scene.plugins.blender.exceptions.BlenderFileException;
13import com.jme3.scene.plugins.blender.file.Pointer;
14import com.jme3.scene.plugins.blender.file.Structure;
15import com.jme3.scene.plugins.blender.materials.MaterialHelper;
16import com.jme3.scene.plugins.blender.particles.ParticlesHelper;
17import java.util.ArrayList;
18import java.util.List;
19import java.util.logging.Level;
20import java.util.logging.Logger;
21
22/**
23 * This modifier allows to add particles to the object.
24 *
25 * @author Marcin Roguski (Kaelthas)
26 */
27/* package */class ParticlesModifier extends Modifier {
28	private static final Logger LOGGER = Logger.getLogger(MirrorModifier.class.getName());
29
30	/** Loaded particles emitter. */
31	private ParticleEmitter particleEmitter;
32
33	/**
34	 * This constructor reads the particles system structure and stores it in
35	 * order to apply it later to the node.
36	 *
37	 * @param modifierStructure
38	 *            the structure of the modifier
39	 * @param blenderContext
40	 *            the blender context
41	 * @throws BlenderFileException
42	 *             an exception is throw wneh there are problems with the
43	 *             blender file
44	 */
45	public ParticlesModifier(Structure modifierStructure, BlenderContext blenderContext) throws BlenderFileException {
46		if(this.validate(modifierStructure, blenderContext)) {
47			Pointer pParticleSystem = (Pointer) modifierStructure.getFieldValue("psys");
48			if (pParticleSystem.isNotNull()) {
49				ParticlesHelper particlesHelper = blenderContext.getHelper(ParticlesHelper.class);
50				Structure particleSystem = pParticleSystem.fetchData(blenderContext.getInputStream()).get(0);
51				particleEmitter = particlesHelper.toParticleEmitter(particleSystem, blenderContext);
52			}
53		}
54	}
55
56	@Override
57	public Node apply(Node node, BlenderContext blenderContext) {
58		if(invalid) {
59			LOGGER.log(Level.WARNING, "Particles modifier is invalid! Cannot be applied to: {0}", node.getName());
60			return node;
61		}
62
63		MaterialHelper materialHelper = blenderContext.getHelper(MaterialHelper.class);
64		ParticleEmitter emitter = particleEmitter.clone();
65
66		// veryfying the alpha function for particles' texture
67		Integer alphaFunction = MaterialHelper.ALPHA_MASK_HYPERBOLE;
68		char nameSuffix = emitter.getName().charAt(emitter.getName().length() - 1);
69		if (nameSuffix == 'B' || nameSuffix == 'N') {
70			alphaFunction = MaterialHelper.ALPHA_MASK_NONE;
71		}
72		// removing the type suffix from the name
73		emitter.setName(emitter.getName().substring(0, emitter.getName().length() - 1));
74
75		// applying emitter shape
76		EmitterShape emitterShape = emitter.getShape();
77		List<Mesh> meshes = new ArrayList<Mesh>();
78		for (Spatial spatial : node.getChildren()) {
79			if (spatial instanceof Geometry) {
80				Mesh mesh = ((Geometry) spatial).getMesh();
81				if (mesh != null) {
82					meshes.add(mesh);
83					Material material = materialHelper.getParticlesMaterial(
84							((Geometry) spatial).getMaterial(), alphaFunction, blenderContext);
85					emitter.setMaterial(material);// TODO: divide into several pieces
86				}
87			}
88		}
89		if (meshes.size() > 0 && emitterShape instanceof EmitterMeshVertexShape) {
90			((EmitterMeshVertexShape) emitterShape).setMeshes(meshes);
91		}
92
93		node.attachChild(emitter);
94		return node;
95	}
96
97	@Override
98	public String getType() {
99		return Modifier.PARTICLE_MODIFIER_DATA;
100	}
101}
102