Home | History | Annotate | Download | only in modifiers
      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