Search in sources :

Example 6 with Structure

use of com.jme3.scene.plugins.blender.file.Structure in project jmonkeyengine by jMonkeyEngine.

the class MirrorModifier method apply.

@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) {
            LOGGER.log(Level.FINE, "Applying mirror modifier to: {0}", temporalMesh);
            Vector3f mirrorPlaneCenter = new Vector3f();
            if (pMirrorObject.isNotNull()) {
                Structure objectStructure;
                try {
                    objectStructure = pMirrorObject.fetchData().get(0);
                    ObjectHelper objectHelper = blenderContext.getHelper(ObjectHelper.class);
                    Node object = (Node) objectHelper.toObject(objectStructure, blenderContext);
                    if (object != null) {
                        // compute the mirror object coordinates in node's local space
                        mirrorPlaneCenter = this.getWorldMatrix(node).invertLocal().mult(object.getWorldTranslation());
                    }
                } catch (BlenderFileException e) {
                    LOGGER.log(Level.SEVERE, "Cannot load mirror''s reference object. Cause: {0}", e.getLocalizedMessage());
                    LOGGER.log(Level.SEVERE, "Mirror modifier will not be applied to node named: {0}", node.getName());
                    return;
                }
            }
            LOGGER.finest("Allocating temporal variables.");
            float d;
            Vector3f mirrorPlaneNormal = new Vector3f();
            Vector3f shiftVector = new Vector3f();
            LOGGER.fine("Mirroring mesh.");
            for (int mirrorIndex = 0; mirrorIndex < 3; ++mirrorIndex) {
                if (isMirrored[mirrorIndex]) {
                    boolean mirrorAtPoint0 = mirrorPlaneCenter.get(mirrorIndex) == 0;
                    if (!mirrorAtPoint0) {
                        // compute mirror's plane normal vector in node's space
                        mirrorPlaneNormal.set(0, 0, 0).set(mirrorIndex, Math.signum(mirrorPlaneCenter.get(mirrorIndex)));
                    }
                    TemporalMesh mirror = temporalMesh.clone();
                    for (int i = 0; i < mirror.getVertexCount(); ++i) {
                        Vector3f vertex = mirror.getVertices().get(i);
                        Vector3f normal = mirror.getNormals().get(i);
                        if (mirrorAtPoint0) {
                            d = Math.abs(vertex.get(mirrorIndex));
                            shiftVector.set(0, 0, 0).set(mirrorIndex, -vertex.get(mirrorIndex));
                        } else {
                            d = this.computeDistanceFromPlane(vertex, mirrorPlaneCenter, mirrorPlaneNormal);
                            mirrorPlaneNormal.mult(d, shiftVector);
                        }
                        if (merge && d <= tolerance) {
                            vertex.addLocal(shiftVector);
                            normal.set(mirrorIndex, 0);
                            temporalMesh.getVertices().get(i).addLocal(shiftVector);
                            temporalMesh.getNormals().get(i).set(mirrorIndex, 0);
                        } else {
                            vertex.addLocal(shiftVector.multLocal(2));
                            normal.set(mirrorIndex, -normal.get(mirrorIndex));
                        }
                    }
                    // flipping the indexes
                    for (Face face : mirror.getFaces()) {
                        face.flipIndexes();
                    }
                    for (Edge edge : mirror.getEdges()) {
                        edge.flipIndexes();
                    }
                    Collections.reverse(mirror.getPoints());
                    if (mirrorU || mirrorV) {
                        for (Face face : mirror.getFaces()) {
                            face.flipUV(mirrorU, mirrorV);
                        }
                    }
                    temporalMesh.append(mirror);
                }
            }
        } else {
            LOGGER.log(Level.WARNING, "Cannot find temporal mesh for node: {0}. The modifier will NOT be applied!", node);
        }
    }
}
Also used : TemporalMesh(com.jme3.scene.plugins.blender.meshes.TemporalMesh) ObjectHelper(com.jme3.scene.plugins.blender.objects.ObjectHelper) Vector3f(com.jme3.math.Vector3f) Node(com.jme3.scene.Node) BlenderFileException(com.jme3.scene.plugins.blender.file.BlenderFileException) Structure(com.jme3.scene.plugins.blender.file.Structure) Face(com.jme3.scene.plugins.blender.meshes.Face) Edge(com.jme3.scene.plugins.blender.meshes.Edge)

Example 7 with Structure

use of com.jme3.scene.plugins.blender.file.Structure in project jmonkeyengine by jMonkeyEngine.

the class ModifierHelper method readModifiers.

/**
     * This method reads the given object's modifiers.
     * 
     * @param objectStructure
     *            the object structure
     * @param blenderContext
     *            the blender context
     * @throws BlenderFileException
     *             this exception is thrown when the blender file is somehow
     *             corrupted
     */
public Collection<Modifier> readModifiers(Structure objectStructure, BlenderContext blenderContext) throws BlenderFileException {
    Set<String> alreadyReadModifiers = new HashSet<String>();
    Collection<Modifier> result = new ArrayList<Modifier>();
    Structure modifiersListBase = (Structure) objectStructure.getFieldValue("modifiers");
    List<Structure> modifiers = modifiersListBase.evaluateListBase();
    for (Structure modifierStructure : modifiers) {
        String modifierType = modifierStructure.getType();
        if (!Modifier.canBeAppliedMultipleTimes(modifierType) && alreadyReadModifiers.contains(modifierType)) {
            LOGGER.log(Level.WARNING, "Modifier {0} can only be applied once to object: {1}", new Object[] { modifierType, objectStructure.getName() });
        } else {
            Modifier modifier = null;
            if (Modifier.ARRAY_MODIFIER_DATA.equals(modifierStructure.getType())) {
                modifier = new ArrayModifier(modifierStructure, blenderContext);
            } else if (Modifier.MIRROR_MODIFIER_DATA.equals(modifierStructure.getType())) {
                modifier = new MirrorModifier(modifierStructure, blenderContext);
            } else if (Modifier.ARMATURE_MODIFIER_DATA.equals(modifierStructure.getType())) {
                modifier = new ArmatureModifier(objectStructure, modifierStructure, blenderContext);
            } else if (Modifier.PARTICLE_MODIFIER_DATA.equals(modifierStructure.getType())) {
                modifier = new ParticlesModifier(modifierStructure, blenderContext);
            } else if (Modifier.SUBSURF_MODIFIER_DATA.equals(modifierStructure.getType())) {
                modifier = new SubdivisionSurfaceModifier(modifierStructure, blenderContext);
            }
            if (modifier != null) {
                if (modifier.isModifying()) {
                    result.add(modifier);
                    alreadyReadModifiers.add(modifierType);
                } else {
                    LOGGER.log(Level.WARNING, "The modifier {0} will cause no changes in the model. It will be ignored!", modifierStructure.getName());
                }
            } else {
                LOGGER.log(Level.WARNING, "Unsupported modifier type: {0}", modifierStructure.getType());
            }
        }
    }
    return result;
}
Also used : ArrayList(java.util.ArrayList) Structure(com.jme3.scene.plugins.blender.file.Structure) HashSet(java.util.HashSet)

Example 8 with Structure

use of com.jme3.scene.plugins.blender.file.Structure in project jmonkeyengine by jMonkeyEngine.

the class Face method loadAll.

/**
     * Loads all faces of a given mesh.
     * @param meshStructure
     *            the mesh structure we read the faces from
     * @param userUVGroups
     *            UV groups defined by the user
     * @param verticesColors
     *            the vertices colors of the mesh
     * @param temporalMesh
     *            the temporal mesh the faces will belong to
     * @param blenderContext
     *            the blender context
     * @return list of faces read from the given mesh structure
     * @throws BlenderFileException
     *             an exception is thrown when problems with file reading occur
     */
public static List<Face> loadAll(Structure meshStructure, Map<String, List<Vector2f>> userUVGroups, List<byte[]> verticesColors, TemporalMesh temporalMesh, BlenderContext blenderContext) throws BlenderFileException {
    LOGGER.log(Level.FINE, "Loading all faces from mesh: {0}", meshStructure.getName());
    List<Face> result = new ArrayList<Face>();
    MeshHelper meshHelper = blenderContext.getHelper(MeshHelper.class);
    if (meshHelper.isBMeshCompatible(meshStructure)) {
        LOGGER.fine("Reading BMesh.");
        Pointer pMLoop = (Pointer) meshStructure.getFieldValue("mloop");
        Pointer pMPoly = (Pointer) meshStructure.getFieldValue("mpoly");
        if (pMPoly.isNotNull() && pMLoop.isNotNull()) {
            List<Structure> polys = pMPoly.fetchData();
            List<Structure> loops = pMLoop.fetchData();
            for (Structure poly : polys) {
                int materialNumber = ((Number) poly.getFieldValue("mat_nr")).intValue();
                int loopStart = ((Number) poly.getFieldValue("loopstart")).intValue();
                int totLoop = ((Number) poly.getFieldValue("totloop")).intValue();
                boolean smooth = (((Number) poly.getFieldValue("flag")).byteValue() & 0x01) != 0x00;
                Integer[] vertexIndexes = new Integer[totLoop];
                for (int i = loopStart; i < loopStart + totLoop; ++i) {
                    vertexIndexes[i - loopStart] = ((Number) loops.get(i).getFieldValue("v")).intValue();
                }
                // uvs always must be added wheater we have texture or not
                Map<String, List<Vector2f>> uvCoords = new HashMap<String, List<Vector2f>>();
                for (Entry<String, List<Vector2f>> entry : userUVGroups.entrySet()) {
                    List<Vector2f> uvs = entry.getValue().subList(loopStart, loopStart + totLoop);
                    uvCoords.put(entry.getKey(), new ArrayList<Vector2f>(uvs));
                }
                List<byte[]> vertexColors = null;
                if (verticesColors != null && verticesColors.size() > 0) {
                    vertexColors = new ArrayList<byte[]>(totLoop);
                    for (int i = loopStart; i < loopStart + totLoop; ++i) {
                        vertexColors.add(verticesColors.get(i));
                    }
                }
                result.add(new Face(vertexIndexes, smooth, materialNumber, uvCoords, vertexColors, temporalMesh));
            }
        }
    } else {
        LOGGER.fine("Reading traditional faces.");
        Pointer pMFace = (Pointer) meshStructure.getFieldValue("mface");
        List<Structure> mFaces = pMFace.isNotNull() ? pMFace.fetchData() : null;
        if (mFaces != null && mFaces.size() > 0) {
            // indicates if the material with the specified number should have a texture attached
            for (int i = 0; i < mFaces.size(); ++i) {
                Structure mFace = mFaces.get(i);
                int materialNumber = ((Number) mFace.getFieldValue("mat_nr")).intValue();
                boolean smooth = (((Number) mFace.getFieldValue("flag")).byteValue() & 0x01) != 0x00;
                int v1 = ((Number) mFace.getFieldValue("v1")).intValue();
                int v2 = ((Number) mFace.getFieldValue("v2")).intValue();
                int v3 = ((Number) mFace.getFieldValue("v3")).intValue();
                int v4 = ((Number) mFace.getFieldValue("v4")).intValue();
                int vertCount = v4 == 0 ? 3 : 4;
                // uvs always must be added wheater we have texture or not
                Map<String, List<Vector2f>> faceUVCoords = new HashMap<String, List<Vector2f>>();
                for (Entry<String, List<Vector2f>> entry : userUVGroups.entrySet()) {
                    List<Vector2f> uvCoordsForASingleFace = new ArrayList<Vector2f>(vertCount);
                    for (int j = 0; j < vertCount; ++j) {
                        uvCoordsForASingleFace.add(entry.getValue().get(i * 4 + j));
                    }
                    faceUVCoords.put(entry.getKey(), uvCoordsForASingleFace);
                }
                List<byte[]> vertexColors = null;
                if (verticesColors != null && verticesColors.size() > 0) {
                    vertexColors = new ArrayList<byte[]>(vertCount);
                    vertexColors.add(verticesColors.get(v1));
                    vertexColors.add(verticesColors.get(v2));
                    vertexColors.add(verticesColors.get(v3));
                    if (vertCount == 4) {
                        vertexColors.add(verticesColors.get(v4));
                    }
                }
                result.add(new Face(vertCount == 4 ? new Integer[] { v1, v2, v3, v4 } : new Integer[] { v1, v2, v3 }, smooth, materialNumber, faceUVCoords, vertexColors, temporalMesh));
            }
        }
    }
    LOGGER.log(Level.FINE, "Loaded {0} faces.", result.size());
    return result;
}
Also used : HashMap(java.util.HashMap) ArrayList(java.util.ArrayList) Pointer(com.jme3.scene.plugins.blender.file.Pointer) Vector2f(com.jme3.math.Vector2f) ArrayList(java.util.ArrayList) List(java.util.List) Structure(com.jme3.scene.plugins.blender.file.Structure)

Example 9 with Structure

use of com.jme3.scene.plugins.blender.file.Structure in project jmonkeyengine by jMonkeyEngine.

the class MeshHelper method loadUVCoordinates.

/**
     * The method loads the UV coordinates. The result is a map where the key is the user's UV set name and the values are UV coordinates.
     * But depending on the mesh type (triangle/quads or bmesh) the lists in the map have different meaning.
     * For bmesh they are enlisted just like they are stored in the blend file (in loops).
     * For traditional faces every 4 UV's should be assigned for a single face.
     * @param meshStructure
     *            the mesh structure
     * @return a map that sorts UV coordinates between different UV sets
     * @throws BlenderFileException
     *             an exception is thrown when problems with blend file occur
     */
@SuppressWarnings("unchecked")
public LinkedHashMap<String, List<Vector2f>> loadUVCoordinates(Structure meshStructure) throws BlenderFileException {
    LOGGER.log(Level.FINE, "Loading UV coordinates from mesh: {0}.", meshStructure.getName());
    LinkedHashMap<String, List<Vector2f>> result = new LinkedHashMap<String, List<Vector2f>>();
    if (this.isBMeshCompatible(meshStructure)) {
        // in this case the UV's are assigned to vertices (an array is the same length as the vertex array)
        Structure loopData = (Structure) meshStructure.getFieldValue("ldata");
        Pointer pLoopDataLayers = (Pointer) loopData.getFieldValue("layers");
        List<Structure> loopDataLayers = pLoopDataLayers.fetchData();
        for (Structure structure : loopDataLayers) {
            Pointer p = (Pointer) structure.getFieldValue("data");
            if (p.isNotNull() && ((Number) structure.getFieldValue("type")).intValue() == MeshHelper.UV_DATA_LAYER_TYPE_BMESH) {
                String uvSetName = structure.getFieldValue("name").toString();
                List<Structure> uvsStructures = p.fetchData();
                List<Vector2f> uvs = new ArrayList<Vector2f>(uvsStructures.size());
                for (Structure uvStructure : uvsStructures) {
                    DynamicArray<Number> loopUVS = (DynamicArray<Number>) uvStructure.getFieldValue("uv");
                    uvs.add(new Vector2f(loopUVS.get(0).floatValue(), loopUVS.get(1).floatValue()));
                }
                result.put(uvSetName, uvs);
            }
        }
    } else {
        // in this case UV's are assigned to faces (the array has the same legnth as the faces count)
        Structure facesData = (Structure) meshStructure.getFieldValue("fdata");
        Pointer pFacesDataLayers = (Pointer) facesData.getFieldValue("layers");
        if (pFacesDataLayers.isNotNull()) {
            List<Structure> facesDataLayers = pFacesDataLayers.fetchData();
            for (Structure structure : facesDataLayers) {
                Pointer p = (Pointer) structure.getFieldValue("data");
                if (p.isNotNull() && ((Number) structure.getFieldValue("type")).intValue() == MeshHelper.UV_DATA_LAYER_TYPE_FMESH) {
                    String uvSetName = structure.getFieldValue("name").toString();
                    List<Structure> uvsStructures = p.fetchData();
                    List<Vector2f> uvs = new ArrayList<Vector2f>(uvsStructures.size());
                    for (Structure uvStructure : uvsStructures) {
                        DynamicArray<Number> mFaceUVs = (DynamicArray<Number>) uvStructure.getFieldValue("uv");
                        uvs.add(new Vector2f(mFaceUVs.get(0).floatValue(), mFaceUVs.get(1).floatValue()));
                        uvs.add(new Vector2f(mFaceUVs.get(2).floatValue(), mFaceUVs.get(3).floatValue()));
                        uvs.add(new Vector2f(mFaceUVs.get(4).floatValue(), mFaceUVs.get(5).floatValue()));
                        uvs.add(new Vector2f(mFaceUVs.get(6).floatValue(), mFaceUVs.get(7).floatValue()));
                    }
                    result.put(uvSetName, uvs);
                }
            }
        }
    }
    return result;
}
Also used : ArrayList(java.util.ArrayList) Pointer(com.jme3.scene.plugins.blender.file.Pointer) LinkedHashMap(java.util.LinkedHashMap) Vector2f(com.jme3.math.Vector2f) DynamicArray(com.jme3.scene.plugins.blender.file.DynamicArray) ArrayList(java.util.ArrayList) List(java.util.List) Structure(com.jme3.scene.plugins.blender.file.Structure)

Example 10 with Structure

use of com.jme3.scene.plugins.blender.file.Structure in project jmonkeyengine by jMonkeyEngine.

the class MeshHelper method isBMeshCompatible.

/**
     * Tells if the given mesh structure supports BMesh.
     * 
     * @param meshStructure
     *            the mesh structure
     * @return <b>true</b> if BMesh is supported and <b>false</b> otherwise
     */
public boolean isBMeshCompatible(Structure meshStructure) {
    Pointer pMLoop = (Pointer) meshStructure.getFieldValue("mloop");
    Pointer pMPoly = (Pointer) meshStructure.getFieldValue("mpoly");
    return pMLoop != null && pMPoly != null && pMLoop.isNotNull() && pMPoly.isNotNull();
}
Also used : Pointer(com.jme3.scene.plugins.blender.file.Pointer)

Aggregations

Structure (com.jme3.scene.plugins.blender.file.Structure)34 Pointer (com.jme3.scene.plugins.blender.file.Pointer)30 ArrayList (java.util.ArrayList)16 Vector3f (com.jme3.math.Vector3f)8 BlenderFileException (com.jme3.scene.plugins.blender.file.BlenderFileException)7 DynamicArray (com.jme3.scene.plugins.blender.file.DynamicArray)7 FileBlockHeader (com.jme3.scene.plugins.blender.file.FileBlockHeader)7 List (java.util.List)6 Map (java.util.Map)6 TemporalMesh (com.jme3.scene.plugins.blender.meshes.TemporalMesh)5 ObjectHelper (com.jme3.scene.plugins.blender.objects.ObjectHelper)5 HashMap (java.util.HashMap)5 ColorRGBA (com.jme3.math.ColorRGBA)4 Node (com.jme3.scene.Node)4 Texture (com.jme3.texture.Texture)4 CameraNode (com.jme3.scene.CameraNode)3 LightNode (com.jme3.scene.LightNode)3 Spatial (com.jme3.scene.Spatial)3 AnimationHelper (com.jme3.scene.plugins.blender.animations.AnimationHelper)3 ConstIpo (com.jme3.scene.plugins.blender.animations.Ipo.ConstIpo)3