159b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartapackage com.jme3.scene.plugins.blender.modifiers; 259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 359b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport com.jme3.math.Vector3f; 459b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport com.jme3.scene.Geometry; 559b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport com.jme3.scene.Mesh; 659b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport com.jme3.scene.Node; 759b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport com.jme3.scene.Spatial; 859b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport com.jme3.scene.VertexBuffer.Type; 959b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport com.jme3.scene.plugins.blender.BlenderContext; 1059b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport com.jme3.scene.plugins.blender.exceptions.BlenderFileException; 1159b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport com.jme3.scene.plugins.blender.file.Pointer; 1259b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport com.jme3.scene.plugins.blender.file.Structure; 1359b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport com.jme3.scene.plugins.blender.objects.ObjectHelper; 1459b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport java.nio.FloatBuffer; 1559b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport java.nio.IntBuffer; 1659b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport java.util.ArrayList; 1759b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport java.util.HashMap; 1859b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport java.util.List; 1959b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport java.util.Map; 2059b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport java.util.logging.Level; 2159b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport java.util.logging.Logger; 2259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 2359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta/** 2459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * This modifier allows to array modifier to the object. 2559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * 2659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @author Marcin Roguski (Kaelthas) 2759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta */ 2859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta/*package*/ class MirrorModifier extends Modifier { 2959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta private static final Logger LOGGER = Logger.getLogger(MirrorModifier.class.getName()); 3059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 3159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta /** Parameters of the modifier. */ 3259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta private Map<String, Object> modifierData = new HashMap<String, Object>(); 3359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 3459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta /** 3559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * This constructor reads mirror data from the modifier structure. The 3659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * stored data is a map of parameters for mirror modifier. No additional data 3759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * is loaded. 3859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * When the modifier is applied it is necessary to get the newly created node. 3959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * 4059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @param objectStructure 4159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * the structure of the object 4259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @param modifierStructure 4359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * the structure of the modifier 4459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @param blenderContext 4559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * the blender context 4659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @throws BlenderFileException 4759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * this exception is thrown when the blender file is somehow 4859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * corrupted 4959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta */ 5059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta public MirrorModifier(Structure modifierStructure, BlenderContext blenderContext) { 5159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if(this.validate(modifierStructure, blenderContext)) { 5259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta modifierData.put("flag", modifierStructure.getFieldValue("flag")); 5359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta modifierData.put("tolerance", modifierStructure.getFieldValue("tolerance")); 5459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta Pointer pMirrorOb = (Pointer) modifierStructure.getFieldValue("mirror_ob"); 5559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (pMirrorOb.isNotNull()) { 5659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta modifierData.put("mirrorob", pMirrorOb); 5759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 5859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 5959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 6059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 6159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta @Override 6259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta public Node apply(Node node, BlenderContext blenderContext) { 6359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if(invalid) { 6459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta LOGGER.log(Level.WARNING, "Mirror modifier is invalid! Cannot be applied to: {0}", node.getName()); 6559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta return node; 6659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 6759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 6859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta int flag = ((Number) modifierData.get("flag")).intValue(); 6959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta float[] mirrorFactor = new float[]{ 7059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta (flag & 0x08) != 0 ? -1.0f : 1.0f, 7159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta (flag & 0x10) != 0 ? -1.0f : 1.0f, 7259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta (flag & 0x20) != 0 ? -1.0f : 1.0f 7359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta }; 7459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta float[] center = new float[]{0.0f, 0.0f, 0.0f}; 7559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta Pointer pObject = (Pointer) modifierData.get("mirrorob"); 7659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (pObject != null) { 7759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta Structure objectStructure; 7859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta try { 7959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta objectStructure = pObject.fetchData(blenderContext.getInputStream()).get(0); 8059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta ObjectHelper objectHelper = blenderContext.getHelper(ObjectHelper.class); 8159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta Node object = (Node) objectHelper.toObject(objectStructure, blenderContext); 8259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (object != null) { 8359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta Vector3f translation = object.getWorldTranslation(); 8459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta center[0] = translation.x; 8559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta center[1] = translation.y; 8659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta center[2] = translation.z; 8759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 8859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } catch (BlenderFileException e) { 8959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta LOGGER.log(Level.SEVERE, "Cannot load mirror''s reference object. Cause: {0}", e.getLocalizedMessage()); 9059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 9159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 9259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta float tolerance = ((Number) modifierData.get("tolerance")).floatValue(); 9359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta boolean mirrorU = (flag & 0x01) != 0; 9459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta boolean mirrorV = (flag & 0x02) != 0; 9559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta// boolean mirrorVGroup = (flag & 0x20) != 0; 9659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 9759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta List<Geometry> geometriesToAdd = new ArrayList<Geometry>(); 9859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta for (int mirrorIndex = 0; mirrorIndex < 3; ++mirrorIndex) { 9959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (mirrorFactor[mirrorIndex] == -1.0f) { 10059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta for (Spatial spatial : node.getChildren()) { 10159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (spatial instanceof Geometry) { 10259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta Mesh mesh = ((Geometry) spatial).getMesh(); 10359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta Mesh clone = mesh.deepClone(); 10459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 10559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta // getting buffers 10659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta FloatBuffer position = mesh.getFloatBuffer(Type.Position); 10759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta FloatBuffer bindPosePosition = mesh.getFloatBuffer(Type.BindPosePosition); 10859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 10959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta FloatBuffer clonePosition = clone.getFloatBuffer(Type.Position); 11059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta FloatBuffer cloneBindPosePosition = clone.getFloatBuffer(Type.BindPosePosition); 11159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta FloatBuffer cloneNormals = clone.getFloatBuffer(Type.Normal); 11259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta FloatBuffer cloneBindPoseNormals = clone.getFloatBuffer(Type.BindPoseNormal); 11359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta IntBuffer cloneIndexes = (IntBuffer) clone.getBuffer(Type.Index).getData(); 11459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 11559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta // modyfying data 11659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta for (int i = mirrorIndex; i < clonePosition.limit(); i += 3) { 11759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta float value = clonePosition.get(i); 11859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta float d = center[mirrorIndex] - value; 11959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 12059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (Math.abs(d) <= tolerance) { 12159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta clonePosition.put(i, center[mirrorIndex]); 12259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta cloneBindPosePosition.put(i, center[mirrorIndex]); 12359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta position.put(i, center[mirrorIndex]); 12459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta bindPosePosition.put(i, center[mirrorIndex]); 12559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } else { 12659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta clonePosition.put(i, value + 2.0f * d); 12759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta cloneBindPosePosition.put(i, value + 2.0f * d); 12859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 12959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta cloneNormals.put(i, -cloneNormals.get(i)); 13059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta cloneBindPoseNormals.put(i, -cloneNormals.get(i)); 13159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 13259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta //modifying clone indexes 13359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta int vertexIndex = (i - mirrorIndex) / 3; 13459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (vertexIndex % 3 == 0 && vertexIndex<cloneIndexes.limit()) { 13559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta int index = cloneIndexes.get(vertexIndex + 2); 13659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta cloneIndexes.put(vertexIndex + 2, cloneIndexes.get(vertexIndex + 1)); 13759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta cloneIndexes.put(vertexIndex + 1, index); 13859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 13959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 14059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 14159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (mirrorU) { 14259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta FloatBuffer cloneUVs = (FloatBuffer) clone.getBuffer(Type.TexCoord).getData(); 14359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta for (int i = 0; i < cloneUVs.limit(); i += 2) { 14459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta cloneUVs.put(i, 1.0f - cloneUVs.get(i)); 14559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 14659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 14759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (mirrorV) { 14859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta FloatBuffer cloneUVs = (FloatBuffer) clone.getBuffer(Type.TexCoord).getData(); 14959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta for (int i = 1; i < cloneUVs.limit(); i += 2) { 15059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta cloneUVs.put(i, 1.0f - cloneUVs.get(i)); 15159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 15259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 15359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 15459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta Geometry geometry = new Geometry(null, clone); 15559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta geometry.setMaterial(((Geometry) spatial).getMaterial()); 15659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta geometriesToAdd.add(geometry); 15759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 15859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 15959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 16059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta // adding meshes to node 16159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta for (Geometry geometry : geometriesToAdd) { 16259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta node.attachChild(geometry); 16359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 16459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta geometriesToAdd.clear(); 16559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 16659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 16759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta return node; 16859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 16959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 17059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta @Override 17159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta public String getType() { 17259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta return Modifier.MIRROR_MODIFIER_DATA; 17359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 17459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta} 175