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 */ 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 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 171 public String getType() { 172 return Modifier.MIRROR_MODIFIER_DATA; 173 } 174 } 175