• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 package com.jme3.scene.plugins.blender.modifiers;
2 
3 import com.jme3.math.Vector3f;
4 import com.jme3.scene.Geometry;
5 import com.jme3.scene.Mesh;
6 import com.jme3.scene.Node;
7 import com.jme3.scene.Spatial;
8 import com.jme3.scene.VertexBuffer.Type;
9 import com.jme3.scene.plugins.blender.BlenderContext;
10 import com.jme3.scene.plugins.blender.exceptions.BlenderFileException;
11 import com.jme3.scene.plugins.blender.file.Pointer;
12 import com.jme3.scene.plugins.blender.file.Structure;
13 import com.jme3.scene.plugins.blender.objects.ObjectHelper;
14 import java.nio.FloatBuffer;
15 import java.nio.IntBuffer;
16 import java.util.ArrayList;
17 import java.util.HashMap;
18 import java.util.List;
19 import java.util.Map;
20 import java.util.logging.Level;
21 import java.util.logging.Logger;
22 
23 /**
24  * This modifier allows to array modifier to the object.
25  *
26  * @author Marcin Roguski (Kaelthas)
27  */
28 /*package*/ class MirrorModifier extends Modifier {
29 	private static final Logger LOGGER = Logger.getLogger(MirrorModifier.class.getName());
30 
31 	/** Parameters of the modifier. */
32 	private Map<String, Object> modifierData = new HashMap<String, Object>();
33 
34 	/**
35 	 * This constructor reads mirror data from the modifier structure. The
36 	 * stored data is a map of parameters for mirror modifier. No additional data
37 	 * is loaded.
38 	 * When the modifier is applied it is necessary to get the newly created node.
39 	 *
40 	 * @param objectStructure
41 	 *            the structure of the object
42 	 * @param modifierStructure
43 	 *            the structure of the modifier
44 	 * @param blenderContext
45 	 *            the blender context
46 	 * @throws BlenderFileException
47 	 *             this exception is thrown when the blender file is somehow
48 	 *             corrupted
49 	 */
MirrorModifier(Structure modifierStructure, BlenderContext blenderContext)50 	public MirrorModifier(Structure modifierStructure, BlenderContext blenderContext) {
51 		if(this.validate(modifierStructure, blenderContext)) {
52 			modifierData.put("flag", modifierStructure.getFieldValue("flag"));
53 			modifierData.put("tolerance", modifierStructure.getFieldValue("tolerance"));
54 	        Pointer pMirrorOb = (Pointer) modifierStructure.getFieldValue("mirror_ob");
55 	        if (pMirrorOb.isNotNull()) {
56 	        	modifierData.put("mirrorob", pMirrorOb);
57 	        }
58 		}
59 	}
60 
61 	@Override
apply(Node node, BlenderContext blenderContext)62 	public Node apply(Node node, BlenderContext blenderContext) {
63 		if(invalid) {
64 			LOGGER.log(Level.WARNING, "Mirror modifier is invalid! Cannot be applied to: {0}", node.getName());
65 			return node;
66 		}
67 
68         int flag = ((Number) modifierData.get("flag")).intValue();
69         float[] mirrorFactor = new float[]{
70             (flag & 0x08) != 0 ? -1.0f : 1.0f,
71             (flag & 0x10) != 0 ? -1.0f : 1.0f,
72             (flag & 0x20) != 0 ? -1.0f : 1.0f
73         };
74         float[] center = new float[]{0.0f, 0.0f, 0.0f};
75         Pointer pObject = (Pointer) modifierData.get("mirrorob");
76         if (pObject != null) {
77             Structure objectStructure;
78             try {
79                 objectStructure = pObject.fetchData(blenderContext.getInputStream()).get(0);
80                 ObjectHelper objectHelper = blenderContext.getHelper(ObjectHelper.class);
81                 Node object = (Node) objectHelper.toObject(objectStructure, blenderContext);
82                 if (object != null) {
83                     Vector3f translation = object.getWorldTranslation();
84                     center[0] = translation.x;
85                     center[1] = translation.y;
86                     center[2] = translation.z;
87                 }
88             } catch (BlenderFileException e) {
89                 LOGGER.log(Level.SEVERE, "Cannot load mirror''s reference object. Cause: {0}", e.getLocalizedMessage());
90             }
91         }
92         float tolerance = ((Number) modifierData.get("tolerance")).floatValue();
93         boolean mirrorU = (flag & 0x01) != 0;
94         boolean mirrorV = (flag & 0x02) != 0;
95 //		boolean mirrorVGroup = (flag & 0x20) != 0;
96 
97         List<Geometry> geometriesToAdd = new ArrayList<Geometry>();
98         for (int mirrorIndex = 0; mirrorIndex < 3; ++mirrorIndex) {
99             if (mirrorFactor[mirrorIndex] == -1.0f) {
100                 for (Spatial spatial : node.getChildren()) {
101                     if (spatial instanceof Geometry) {
102                         Mesh mesh = ((Geometry) spatial).getMesh();
103                         Mesh clone = mesh.deepClone();
104 
105                         // getting buffers
106                         FloatBuffer position = mesh.getFloatBuffer(Type.Position);
107                         FloatBuffer bindPosePosition = mesh.getFloatBuffer(Type.BindPosePosition);
108 
109                         FloatBuffer clonePosition = clone.getFloatBuffer(Type.Position);
110                         FloatBuffer cloneBindPosePosition = clone.getFloatBuffer(Type.BindPosePosition);
111                         FloatBuffer cloneNormals = clone.getFloatBuffer(Type.Normal);
112                         FloatBuffer cloneBindPoseNormals = clone.getFloatBuffer(Type.BindPoseNormal);
113                         IntBuffer cloneIndexes = (IntBuffer) clone.getBuffer(Type.Index).getData();
114 
115                         // modyfying data
116                         for (int i = mirrorIndex; i < clonePosition.limit(); i += 3) {
117                             float value = clonePosition.get(i);
118                             float d = center[mirrorIndex] - value;
119 
120                             if (Math.abs(d) <= tolerance) {
121                                 clonePosition.put(i, center[mirrorIndex]);
122                                 cloneBindPosePosition.put(i, center[mirrorIndex]);
123                                 position.put(i, center[mirrorIndex]);
124                                 bindPosePosition.put(i, center[mirrorIndex]);
125                             } else {
126                                 clonePosition.put(i, value + 2.0f * d);
127                                 cloneBindPosePosition.put(i, value + 2.0f * d);
128                             }
129                             cloneNormals.put(i, -cloneNormals.get(i));
130                             cloneBindPoseNormals.put(i, -cloneNormals.get(i));
131 
132                             //modifying clone indexes
133                             int vertexIndex = (i - mirrorIndex) / 3;
134                             if (vertexIndex % 3 == 0 && vertexIndex<cloneIndexes.limit()) {
135                                 int index = cloneIndexes.get(vertexIndex + 2);
136                                 cloneIndexes.put(vertexIndex + 2, cloneIndexes.get(vertexIndex + 1));
137                                 cloneIndexes.put(vertexIndex + 1, index);
138                             }
139                         }
140 
141                         if (mirrorU) {
142                             FloatBuffer cloneUVs = (FloatBuffer) clone.getBuffer(Type.TexCoord).getData();
143                             for (int i = 0; i < cloneUVs.limit(); i += 2) {
144                                 cloneUVs.put(i, 1.0f - cloneUVs.get(i));
145                             }
146                         }
147                         if (mirrorV) {
148                             FloatBuffer cloneUVs = (FloatBuffer) clone.getBuffer(Type.TexCoord).getData();
149                             for (int i = 1; i < cloneUVs.limit(); i += 2) {
150                                 cloneUVs.put(i, 1.0f - cloneUVs.get(i));
151                             }
152                         }
153 
154                         Geometry geometry = new Geometry(null, clone);
155                         geometry.setMaterial(((Geometry) spatial).getMaterial());
156                         geometriesToAdd.add(geometry);
157                     }
158                 }
159 
160                 // adding meshes to node
161                 for (Geometry geometry : geometriesToAdd) {
162                     node.attachChild(geometry);
163                 }
164                 geometriesToAdd.clear();
165             }
166         }
167         return node;
168 	}
169 
170 	@Override
getType()171 	public String getType() {
172 		return Modifier.MIRROR_MODIFIER_DATA;
173 	}
174 }
175