parent
b39772c401
commit
e18ffccf8a
@ -0,0 +1,138 @@ |
|||||||
|
package com.jme3.scene.plugins.blender.modifiers; |
||||||
|
|
||||||
|
import java.util.ArrayList; |
||||||
|
import java.util.Collection; |
||||||
|
import java.util.Collections; |
||||||
|
import java.util.List; |
||||||
|
import java.util.Map; |
||||||
|
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.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<String> vertexGroupsToRemove = new ArrayList<String>(); |
||||||
|
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<Structure> 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
|
||||||
|
Collection<String> vertexGroupNames = temporalMesh.getVertexGroupNames(); |
||||||
|
if (vertexGroupNames.size() == 0 && !invertMask || vertexGroupNames.size() > 0 && invertMask) { |
||||||
|
temporalMesh.clear(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
if (vertexGroupsToRemove.size() > 0) { |
||||||
|
List<Integer> vertsToBeRemoved = new ArrayList<Integer>(); |
||||||
|
for (int i = 0; i < temporalMesh.getVertexCount(); ++i) { |
||||||
|
Map<String, Float> vertexGroups = temporalMesh.getVertexGroups(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) { |
||||||
|
temporalMesh.removeVertexAt(vertexIndex); |
||||||
|
} |
||||||
|
} |
||||||
|
} else { |
||||||
|
LOGGER.log(Level.WARNING, "Cannot find temporal mesh for node: {0}. The modifier will NOT be applied!", node); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 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<String> readBoneNames(List<Structure> boneBase) throws BlenderFileException { |
||||||
|
List<String> result = new ArrayList<String>(); |
||||||
|
for (Structure boneStructure : boneBase) { |
||||||
|
int flag = ((Number) boneStructure.getFieldValue("flag")).intValue(); |
||||||
|
if ((flag & BoneContext.SELECTED) != 0) { |
||||||
|
result.add(boneStructure.getFieldValue("name").toString()); |
||||||
|
} |
||||||
|
List<Structure> childbase = ((Structure) boneStructure.getFieldValue("childbase")).evaluateListBase(); |
||||||
|
result.addAll(this.readBoneNames(childbase)); |
||||||
|
} |
||||||
|
return result; |
||||||
|
} |
||||||
|
} |
Loading…
Reference in new issue