com.jme3.scene.plugins.blender.modifiers.MaskModifier Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jme3-blender Show documentation
Show all versions of jme3-blender Show documentation
jMonkeyEngine is a 3D game engine for adventurous Java developers
The newest version!
package com.jme3.scene.plugins.blender.modifiers;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
import com.jme3.scene.Node;
import com.jme3.scene.plugins.blender.BlenderContext;
import com.jme3.scene.plugins.blender.animations.BoneContext;
import com.jme3.scene.plugins.blender.file.BlenderFileException;
import com.jme3.scene.plugins.blender.file.Pointer;
import com.jme3.scene.plugins.blender.file.Structure;
import com.jme3.scene.plugins.blender.meshes.Edge;
import com.jme3.scene.plugins.blender.meshes.Face;
import com.jme3.scene.plugins.blender.meshes.IndexesLoop.IndexPredicate;
import com.jme3.scene.plugins.blender.meshes.Point;
import com.jme3.scene.plugins.blender.meshes.TemporalMesh;
/**
* This modifier allows to use mask modifier on the object.
*
* @author Marcin Roguski (Kaelthas)
*/
/* package */class MaskModifier extends Modifier {
private static final Logger LOGGER = Logger.getLogger(MaskModifier.class.getName());
private static final int FLAG_INVERT_MASK = 0x01;
private static final int MODE_VERTEX_GROUP = 0;
private static final int MODE_ARMATURE = 1;
private Pointer pArmatureObject;
private String vertexGroupName;
private boolean invertMask;
public MaskModifier(Structure modifierStructure, BlenderContext blenderContext) {
if (this.validate(modifierStructure, blenderContext)) {
int flag = ((Number) modifierStructure.getFieldValue("flag")).intValue();
invertMask = (flag & FLAG_INVERT_MASK) != 0;
int mode = ((Number) modifierStructure.getFieldValue("mode")).intValue();
if (mode == MODE_VERTEX_GROUP) {
vertexGroupName = modifierStructure.getFieldValue("vgroup").toString();
if (vertexGroupName != null && vertexGroupName.length() == 0) {
vertexGroupName = null;
}
} else if (mode == MODE_ARMATURE) {
pArmatureObject = (Pointer) modifierStructure.getFieldValue("ob_arm");
} else {
LOGGER.log(Level.SEVERE, "Unknown mode type: {0}. Cannot apply modifier: {1}.", new Object[] { mode, modifierStructure.getName() });
invalid = true;
}
}
}
@Override
public void apply(Node node, BlenderContext blenderContext) {
if (invalid) {
LOGGER.log(Level.WARNING, "Mirror modifier is invalid! Cannot be applied to: {0}", node.getName());
} else {
TemporalMesh temporalMesh = this.getTemporalMesh(node);
if (temporalMesh != null) {
List vertexGroupsToRemove = new ArrayList();
if (vertexGroupName != null) {
vertexGroupsToRemove.add(vertexGroupName);
} else if (pArmatureObject != null && pArmatureObject.isNotNull()) {
try {
Structure armatureObject = pArmatureObject.fetchData().get(0);
Structure armatureStructure = ((Pointer) armatureObject.getFieldValue("data")).fetchData().get(0);
List bonebase = ((Structure) armatureStructure.getFieldValue("bonebase")).evaluateListBase();
vertexGroupsToRemove.addAll(this.readBoneNames(bonebase));
} catch (BlenderFileException e) {
LOGGER.log(Level.SEVERE, "Cannot load armature object for the mask modifier. Cause: {0}", e.getLocalizedMessage());
LOGGER.log(Level.SEVERE, "Mask modifier will NOT be applied to node named: {0}", node.getName());
}
} else {
// if the mesh has no vertex groups then remove all verts
// if the mesh has at least one vertex group - then do nothing
// I have no idea why we should do that, but blender works this way
Set vertexGroupNames = new HashSet();
for (Map groups : temporalMesh.getVertexGroups()) {
vertexGroupNames.addAll(groups.keySet());
}
if (vertexGroupNames.size() == 0 && !invertMask || vertexGroupNames.size() > 0 && invertMask) {
temporalMesh.clear();
}
}
if (vertexGroupsToRemove.size() > 0) {
List vertsToBeRemoved = new ArrayList();
for (int i = 0; i < temporalMesh.getVertexCount(); ++i) {
Map vertexGroups = temporalMesh.getVertexGroups().get(i);
boolean hasVertexGroup = false;
if (vertexGroups != null) {
for (String groupName : vertexGroupsToRemove) {
Float weight = vertexGroups.get(groupName);
if (weight != null && weight > 0) {
hasVertexGroup = true;
break;
}
}
}
if (!hasVertexGroup && !invertMask || hasVertexGroup && invertMask) {
vertsToBeRemoved.add(i);
}
}
Collections.reverse(vertsToBeRemoved);
for (Integer vertexIndex : vertsToBeRemoved) {
this.removeVertexAt(vertexIndex, temporalMesh);
}
}
} else {
LOGGER.log(Level.WARNING, "Cannot find temporal mesh for node: {0}. The modifier will NOT be applied!", node);
}
}
}
/**
* Every face, edge and point that contains
* the vertex will be removed.
* @param index
* the index of a vertex to be removed
* @throws IndexOutOfBoundsException
* thrown when given index is negative or beyond the count of vertices
*/
private void removeVertexAt(final int index, TemporalMesh temporalMesh) {
if (index < 0 || index >= temporalMesh.getVertexCount()) {
throw new IndexOutOfBoundsException("The given index is out of bounds: " + index);
}
temporalMesh.getVertices().remove(index);
temporalMesh.getNormals().remove(index);
if (temporalMesh.getVertexGroups().size() > 0) {
temporalMesh.getVertexGroups().remove(index);
}
if (temporalMesh.getVerticesColors().size() > 0) {
temporalMesh.getVerticesColors().remove(index);
}
IndexPredicate shiftPredicate = new IndexPredicate() {
@Override
public boolean execute(Integer i) {
return i > index;
}
};
for (int i = temporalMesh.getFaces().size() - 1; i >= 0; --i) {
Face face = temporalMesh.getFaces().get(i);
if (face.getIndexes().indexOf(index) >= 0) {
temporalMesh.getFaces().remove(i);
} else {
face.getIndexes().shiftIndexes(-1, shiftPredicate);
}
}
for (int i = temporalMesh.getEdges().size() - 1; i >= 0; --i) {
Edge edge = temporalMesh.getEdges().get(i);
if (edge.getFirstIndex() == index || edge.getSecondIndex() == index) {
temporalMesh.getEdges().remove(i);
} else {
edge.shiftIndexes(-1, shiftPredicate);
}
}
for (int i = temporalMesh.getPoints().size() - 1; i >= 0; --i) {
Point point = temporalMesh.getPoints().get(i);
if (point.getIndex() == index) {
temporalMesh.getPoints().remove(i);
} else {
point.shiftIndexes(-1, shiftPredicate);
}
}
}
/**
* Reads the names of the bones from the given bone base.
* @param boneBase
* the list of bone base structures
* @return a list of bones' names
* @throws BlenderFileException
* is thrown if problems with reading the child bones' bases occur
*/
private List readBoneNames(List boneBase) throws BlenderFileException {
List result = new ArrayList();
for (Structure boneStructure : boneBase) {
int flag = ((Number) boneStructure.getFieldValue("flag")).intValue();
if ((flag & BoneContext.SELECTED) != 0) {
result.add(boneStructure.getFieldValue("name").toString());
}
List childbase = ((Structure) boneStructure.getFieldValue("childbase")).evaluateListBase();
result.addAll(this.readBoneNames(childbase));
}
return result;
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy