Browse Source

Bugfix: fix to importing blend files with linked content.

jmekaelthas 10 years ago
parent
commit
b34649d399

+ 4 - 0
jme3-blender/src/main/java/com/jme3/asset/BlenderKey.java

@@ -230,18 +230,22 @@ public class BlenderKey extends ModelKey {
     }
 
     /**
+     * Not used any more.
      * This method sets the asset root path.
      * @param assetRootPath
      *            the assets root path
      */
+    @Deprecated
     public void setAssetRootPath(String assetRootPath) {
         this.assetRootPath = assetRootPath;
     }
 
     /**
+     * Not used any more.
      * This method returns the asset root path.
      * @return the asset root path
      */
+    @Deprecated
     public String getAssetRootPath() {
         return assetRootPath;
     }

+ 9 - 78
jme3-blender/src/main/java/com/jme3/scene/plugins/blender/AbstractBlenderHelper.java

@@ -31,8 +31,6 @@
  */
 package com.jme3.scene.plugins.blender;
 
-import java.io.File;
-import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
 import java.util.Map;
@@ -40,25 +38,17 @@ import java.util.Map.Entry;
 import java.util.logging.Level;
 import java.util.logging.Logger;
 
-import com.jme3.animation.Animation;
 import com.jme3.asset.AssetNotFoundException;
 import com.jme3.asset.BlenderKey;
 import com.jme3.export.Savable;
-import com.jme3.light.Light;
 import com.jme3.math.FastMath;
 import com.jme3.math.Quaternion;
-import com.jme3.post.Filter;
-import com.jme3.renderer.Camera;
-import com.jme3.scene.Node;
 import com.jme3.scene.Spatial;
 import com.jme3.scene.plugins.blender.BlenderContext.LoadedDataType;
 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.materials.MaterialContext;
-import com.jme3.scene.plugins.blender.meshes.TemporalMesh;
 import com.jme3.scene.plugins.blender.objects.Properties;
-import com.jme3.texture.Texture;
 
 /**
  * A purpose of the helper class is to split calculation code into several classes. Each helper after use should be cleared because it can
@@ -157,7 +147,6 @@ public abstract class AbstractBlenderHelper {
      * @throws BlenderFileException
      *             and exception is throw when problems with reading a blend file occur
      */
-    @SuppressWarnings("unchecked")
     protected Object loadLibrary(Structure id) throws BlenderFileException {
         Pointer pLib = (Pointer) id.getFieldValue("lib");
         if (pLib.isNotNull()) {
@@ -167,79 +156,21 @@ public abstract class AbstractBlenderHelper {
             String path = library.getFieldValue("filepath").toString();
 
             if (!blenderContext.getLinkedFeatures().keySet().contains(path)) {
-                File file = new File(path);
-                List<String> pathsToCheck = new ArrayList<String>();
-                String currentPath = file.getName();
-                do {
-                    pathsToCheck.add(currentPath);
-                    file = file.getParentFile();
-                    if (file != null) {
-                        currentPath = file.getName() + '/' + currentPath;
-                    }
-                } while (file != null);
-
                 Spatial loadedAsset = null;
-                BlenderKey blenderKey = null;
-                for (String p : pathsToCheck) {
-                    blenderKey = new BlenderKey(p);
-                    blenderKey.setLoadUnlinkedAssets(true);
-                    try {
-                        loadedAsset = blenderContext.getAssetManager().loadAsset(blenderKey);
-                        break;// break if no exception was thrown
-                    } catch (AssetNotFoundException e) {
-                        LOGGER.log(Level.FINEST, "Cannot locate linked resource at path: {0}.", p);
-                    }
+                BlenderKey blenderKey = new BlenderKey(path);
+                blenderKey.setLoadUnlinkedAssets(true);
+                try {
+                    loadedAsset = blenderContext.getAssetManager().loadAsset(blenderKey);
+                } catch (AssetNotFoundException e) {
+                    LOGGER.log(Level.FINEST, "Cannot locate linked resource at path: {0}.", path);
                 }
-
+                
                 if (loadedAsset != null) {
                     Map<String, Map<String, Object>> linkedData = loadedAsset.getUserData("linkedData");
+                    
                     for (Entry<String, Map<String, Object>> entry : linkedData.entrySet()) {
                         String linkedDataFilePath = "this".equals(entry.getKey()) ? path : entry.getKey();
-
-                        List<Node> scenes = (List<Node>) entry.getValue().get("scenes");
-                        for (Node scene : scenes) {
-                            blenderContext.addLinkedFeature(linkedDataFilePath, "SC" + scene.getName(), scene);
-                        }
-                        List<Node> objects = (List<Node>) entry.getValue().get("objects");
-                        for (Node object : objects) {
-                            blenderContext.addLinkedFeature(linkedDataFilePath, "OB" + object.getName(), object);
-                        }
-                        List<TemporalMesh> meshes = (List<TemporalMesh>) entry.getValue().get("meshes");
-                        for (TemporalMesh mesh : meshes) {
-                            blenderContext.addLinkedFeature(linkedDataFilePath, "ME" + mesh.getName(), mesh);
-                        }
-                        List<MaterialContext> materials = (List<MaterialContext>) entry.getValue().get("materials");
-                        for (MaterialContext materialContext : materials) {
-                            blenderContext.addLinkedFeature(linkedDataFilePath, "MA" + materialContext.getName(), materialContext);
-                        }
-                        List<Texture> textures = (List<Texture>) entry.getValue().get("textures");
-                        for (Texture texture : textures) {
-                            blenderContext.addLinkedFeature(linkedDataFilePath, "TE" + texture.getName(), texture);
-                        }
-                        List<Texture> images = (List<Texture>) entry.getValue().get("images");
-                        for (Texture image : images) {
-                            blenderContext.addLinkedFeature(linkedDataFilePath, "IM" + image.getName(), image);
-                        }
-                        List<Animation> animations = (List<Animation>) entry.getValue().get("animations");
-                        for (Animation animation : animations) {
-                            blenderContext.addLinkedFeature(linkedDataFilePath, "AC" + animation.getName(), animation);
-                        }
-                        List<Camera> cameras = (List<Camera>) entry.getValue().get("cameras");
-                        for (Camera camera : cameras) {
-                            blenderContext.addLinkedFeature(linkedDataFilePath, "CA" + camera.getName(), camera);
-                        }
-                        List<Light> lights = (List<Light>) entry.getValue().get("lights");
-                        for (Light light : lights) {
-                            blenderContext.addLinkedFeature(linkedDataFilePath, "LA" + light.getName(), light);
-                        }
-                        Spatial sky = (Spatial) entry.getValue().get("sky");
-                        if (sky != null) {
-                            blenderContext.addLinkedFeature(linkedDataFilePath, sky.getName(), sky);
-                        }
-                        List<Filter> filters = (List<Filter>) entry.getValue().get("filters");
-                        for (Filter filter : filters) {
-                            blenderContext.addLinkedFeature(linkedDataFilePath, filter.getName(), filter);
-                        }
+                        blenderContext.getLinkedFeatures().put(linkedDataFilePath, entry.getValue());
                     }
                 } else {
                     LOGGER.log(Level.WARNING, "No features loaded from path: {0}.", path);

+ 122 - 15
jme3-blender/src/main/java/com/jme3/scene/plugins/blender/BlenderContext.java

@@ -44,8 +44,11 @@ import com.jme3.animation.Bone;
 import com.jme3.animation.Skeleton;
 import com.jme3.asset.AssetManager;
 import com.jme3.asset.BlenderKey;
+import com.jme3.light.Light;
 import com.jme3.material.Material;
 import com.jme3.math.ColorRGBA;
+import com.jme3.post.Filter;
+import com.jme3.renderer.Camera;
 import com.jme3.scene.Node;
 import com.jme3.scene.plugins.blender.animations.BlenderAction;
 import com.jme3.scene.plugins.blender.animations.BoneContext;
@@ -55,6 +58,8 @@ import com.jme3.scene.plugins.blender.file.DnaBlockData;
 import com.jme3.scene.plugins.blender.file.FileBlockHeader;
 import com.jme3.scene.plugins.blender.file.FileBlockHeader.BlockCode;
 import com.jme3.scene.plugins.blender.file.Structure;
+import com.jme3.scene.plugins.blender.materials.MaterialContext;
+import com.jme3.texture.Texture;
 
 /**
  * The class that stores temporary data and manages it during loading the belnd
@@ -77,7 +82,7 @@ public class BlenderContext {
     /** The asset manager. */
     private AssetManager                           assetManager;
     /** The blocks read from the file. */
-    protected List<FileBlockHeader>                blocks;
+    protected List<FileBlockHeader>                blocks                 = new ArrayList<FileBlockHeader>();
     /**
      * A map containing the file block headers. The key is the old memory address.
      */
@@ -233,6 +238,7 @@ public class BlenderContext {
      *            the block header to store
      */
     public void addFileBlockHeader(Long oldMemoryAddress, FileBlockHeader fileBlockHeader) {
+        blocks.add(fileBlockHeader);
         fileBlockHeadersByOma.put(oldMemoryAddress, fileBlockHeader);
         List<FileBlockHeader> headers = fileBlockHeadersByCode.get(fileBlockHeader.getCode());
         if (headers == null) {
@@ -242,6 +248,13 @@ public class BlenderContext {
         headers.add(fileBlockHeader);
     }
 
+    /**
+     * @return the block headers
+     */
+    public List<FileBlockHeader> getBlocks() {
+        return blocks;
+    }
+
     /**
      * This method returns the block header of a given memory address. If the
      * header is not present then null is returned.
@@ -332,22 +345,14 @@ public class BlenderContext {
      * The method adds linked content to the blender context.
      * @param blenderFilePath
      *            the path of linked blender file
-     * @param featureName
-     *            the linked feature name
+     * @param featureGroup
+     *            the linked feature group (ie. scenes, materials, meshes, etc.)
      * @param feature
      *            the linked feature
      */
-    public void addLinkedFeature(String blenderFilePath, String featureName, Object feature) {
-        if (feature != null) {
-            Map<String, Object> linkedFeatures = this.linkedFeatures.get(blenderFilePath);
-            if (linkedFeatures == null) {
-                linkedFeatures = new HashMap<String, Object>();
-                this.linkedFeatures.put(blenderFilePath, linkedFeatures);
-            }
-            if (!linkedFeatures.containsKey(featureName)) {
-                linkedFeatures.put(featureName, feature);
-            }
-        }
+    @Deprecated
+    public void addLinkedFeature(String blenderFilePath, String featureGroup, Object feature) {
+        // the method is deprecated and empty at the moment
     }
 
     /**
@@ -358,9 +363,106 @@ public class BlenderContext {
      *            the feature name we want to get
      * @return linked feature or null if none was found
      */
+    @SuppressWarnings("unchecked")
     public Object getLinkedFeature(String blenderFilePath, String featureName) {
         Map<String, Object> linkedFeatures = this.linkedFeatures.get(blenderFilePath);
-        return linkedFeatures != null ? linkedFeatures.get(featureName) : null;
+        if(linkedFeatures != null) {
+            String namePrefix = (featureName.charAt(0) + "" + featureName.charAt(1)).toUpperCase();
+            featureName = featureName.substring(2);
+            
+            if("SC".equals(namePrefix)) {
+                List<Node> scenes = (List<Node>) linkedFeatures.get("scenes");
+                if(scenes != null) {
+                    for(Node scene : scenes) {
+                        if(featureName.equals(scene.getName())) {
+                            return scene;
+                        }
+                    }
+                }
+            } else if("OB".equals(namePrefix)) {
+                List<Node> features = (List<Node>) linkedFeatures.get("objects");
+                if(features != null) {
+                    for(Node feature : features) {
+                        if(featureName.equals(feature.getName())) {
+                            return feature;
+                        }
+                    }
+                }
+            } else if("ME".equals(namePrefix)) {
+                List<Node> features = (List<Node>) linkedFeatures.get("meshes");
+                if(features != null) {
+                    for(Node feature : features) {
+                        if(featureName.equals(feature.getName())) {
+                            return feature;
+                        }
+                    }
+                }
+            } else if("MA".equals(namePrefix)) {
+                List<MaterialContext> features = (List<MaterialContext>) linkedFeatures.get("materials");
+                if(features != null) {
+                    for(MaterialContext feature : features) {
+                        if(featureName.equals(feature.getName())) {
+                            return feature;
+                        }
+                    }
+                }
+            } else if("TX".equals(namePrefix)) {
+                List<Texture> features = (List<Texture>) linkedFeatures.get("textures");
+                if(features != null) {
+                    for(Texture feature : features) {
+                        if(featureName.equals(feature.getName())) {
+                            return feature;
+                        }
+                    }
+                }
+            } else if("IM".equals(namePrefix)) {
+                List<Texture> features = (List<Texture>) linkedFeatures.get("images");
+                if(features != null) {
+                    for(Texture feature : features) {
+                        if(featureName.equals(feature.getName())) {
+                            return feature;
+                        }
+                    }
+                }
+            } else if("AC".equals(namePrefix)) {
+                List<Animation> features = (List<Animation>) linkedFeatures.get("animations");
+                if(features != null) {
+                    for(Animation feature : features) {
+                        if(featureName.equals(feature.getName())) {
+                            return feature;
+                        }
+                    }
+                }
+            } else if("CA".equals(namePrefix)) {
+                List<Camera> features = (List<Camera>) linkedFeatures.get("cameras");
+                if(features != null) {
+                    for(Camera feature : features) {
+                        if(featureName.equals(feature.getName())) {
+                            return feature;
+                        }
+                    }
+                }
+            } else if("LA".equals(namePrefix)) {
+                List<Light> features = (List<Light>) linkedFeatures.get("lights");
+                if(features != null) {
+                    for(Light feature : features) {
+                        if(featureName.equals(feature.getName())) {
+                            return feature;
+                        }
+                    }
+                }
+            } else if("FI".equals(featureName)) {
+                List<Filter> features = (List<Filter>) linkedFeatures.get("lights");
+                if(features != null) {
+                    for(Filter feature : features) {
+                        if(featureName.equals(feature.getName())) {
+                            return feature;
+                        }
+                    }
+                }
+            }
+        }
+        return null;
     }
 
     /**
@@ -659,4 +761,9 @@ public class BlenderContext {
     public static enum LoadedDataType {
         STRUCTURE, FEATURE, TEMPORAL_MESH;
     }
+    
+    @Override
+    public String toString() {
+        return blenderKey == null ? "BlenderContext [key = null]" : "BlenderContext [ key = " + blenderKey.toString() + " ]";
+    }
 }

+ 69 - 17
jme3-blender/src/main/java/com/jme3/scene/plugins/blender/BlenderLoader.java

@@ -31,6 +31,9 @@
  */
 package com.jme3.scene.plugins.blender;
 
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.HashMap;
@@ -41,9 +44,13 @@ import java.util.logging.Logger;
 
 import com.jme3.animation.Animation;
 import com.jme3.asset.AssetInfo;
+import com.jme3.asset.AssetKey;
 import com.jme3.asset.AssetLoader;
+import com.jme3.asset.AssetLocator;
+import com.jme3.asset.AssetManager;
 import com.jme3.asset.BlenderKey;
 import com.jme3.asset.ModelKey;
+import com.jme3.asset.StreamAssetInfo;
 import com.jme3.light.Light;
 import com.jme3.math.ColorRGBA;
 import com.jme3.post.Filter;
@@ -81,22 +88,17 @@ import com.jme3.texture.Texture;
 public class BlenderLoader implements AssetLoader {
     private static final Logger     LOGGER = Logger.getLogger(BlenderLoader.class.getName());
 
-    /** The blocks read from the file. */
-    protected List<FileBlockHeader> blocks;
-    /** The blender context. */
-    protected BlenderContext        blenderContext;
-
     @Override
     public Spatial load(AssetInfo assetInfo) throws IOException {
         try {
-            this.setup(assetInfo);
+            BlenderContext blenderContext = this.setup(assetInfo);
 
             AnimationHelper animationHelper = blenderContext.getHelper(AnimationHelper.class);
             animationHelper.loadAnimations();
 
             BlenderKey blenderKey = blenderContext.getBlenderKey();
             LoadedFeatures loadedFeatures = new LoadedFeatures();
-            for (FileBlockHeader block : blocks) {
+            for (FileBlockHeader block : blenderContext.getBlocks()) {
                 switch (block.getCode()) {
                     case BLOCK_OB00:
                         ObjectHelper objectHelper = blenderContext.getHelper(ObjectHelper.class);
@@ -181,7 +183,7 @@ public class BlenderLoader implements AssetLoader {
 
             LOGGER.fine("Loading scenes and attaching them to the root object.");
             for (FileBlockHeader sceneBlock : loadedFeatures.sceneBlocks) {
-                loadedFeatures.scenes.add(this.toScene(sceneBlock.getStructure(blenderContext)));
+                loadedFeatures.scenes.add(this.toScene(sceneBlock.getStructure(blenderContext), blenderContext));
             }
 
             LOGGER.fine("Creating the root node of the model and applying loaded nodes of the scene and loaded features to it.");
@@ -220,7 +222,7 @@ public class BlenderLoader implements AssetLoader {
         } catch (Exception e) {
             throw new IOException("Unexpected importer exception occured: " + e.getLocalizedMessage(), e);
         } finally {
-            this.clear();
+            this.clear(assetInfo);
         }
     }
 
@@ -228,11 +230,12 @@ public class BlenderLoader implements AssetLoader {
      * This method converts the given structure to a scene node.
      * @param structure
      *            structure of a scene
+     *            @param blenderContext the blender context
      * @return scene's node
      * @throws BlenderFileException
      *             an exception throw when problems with blender file occur
      */
-    private Node toScene(Structure structure) throws BlenderFileException {
+    private Node toScene(Structure structure, BlenderContext blenderContext) throws BlenderFileException {
         ObjectHelper objectHelper = blenderContext.getHelper(ObjectHelper.class);
         Node result = new Node(structure.getName());
         List<Structure> base = ((Structure) structure.getFieldValue("base")).evaluateListBase();
@@ -265,7 +268,7 @@ public class BlenderLoader implements AssetLoader {
      * @throws BlenderFileException
      *             an exception is throw when something wrong happens with blender file
      */
-    protected void setup(AssetInfo assetInfo) throws BlenderFileException {
+    protected BlenderContext setup(AssetInfo assetInfo) throws BlenderFileException {
         // registering loaders
         ModelKey modelKey = (ModelKey) assetInfo.getKey();
         BlenderKey blenderKey;
@@ -273,16 +276,15 @@ public class BlenderLoader implements AssetLoader {
             blenderKey = (BlenderKey) modelKey;
         } else {
             blenderKey = new BlenderKey(modelKey.getName());
-            blenderKey.setAssetRootPath(modelKey.getFolder());
         }
 
         // opening stream
         BlenderInputStream inputStream = new BlenderInputStream(assetInfo.openStream());
 
         // reading blocks
-        blocks = new ArrayList<FileBlockHeader>();
+        List<FileBlockHeader> blocks = new ArrayList<FileBlockHeader>();
         FileBlockHeader fileBlock;
-        blenderContext = new BlenderContext();
+        BlenderContext blenderContext = new BlenderContext();
         blenderContext.setBlenderVersion(inputStream.getVersionNumber());
         blenderContext.setAssetManager(assetInfo.getManager());
         blenderContext.setInputStream(inputStream);
@@ -317,15 +319,19 @@ public class BlenderLoader implements AssetLoader {
         if (sceneFileBlock != null) {
             blenderContext.setSceneStructure(sceneFileBlock.getStructure(blenderContext));
         }
+        
+        // adding locator for linked content
+        assetInfo.getManager().registerLocator(assetInfo.getKey().getName(), LinkedContentLocator.class);
+        
+        return blenderContext;
     }
 
     /**
      * The internal data is only needed during loading so make it unreachable so that the GC can release
      * that memory (which can be quite large amount).
      */
-    protected void clear() {
-        blenderContext = null;
-        blocks = null;
+    protected void clear(AssetInfo assetInfo) {
+        assetInfo.getManager().unregisterLocator(assetInfo.getKey().getName(), LinkedContentLocator.class);
     }
 
     /**
@@ -362,4 +368,50 @@ public class BlenderLoader implements AssetLoader {
          */
         private ColorRGBA             backgroundColor = ColorRGBA.Gray;
     }
+    
+    public static class LinkedContentLocator implements AssetLocator {
+        private File rootFolder;
+        
+        @Override
+        public void setRootPath(String rootPath) {
+            rootFolder = new File(rootPath);
+            if(rootFolder.isFile()) {
+                rootFolder = rootFolder.getParentFile();
+            }
+        }
+
+        @SuppressWarnings("rawtypes")
+        @Override
+        public AssetInfo locate(AssetManager manager, AssetKey key) {
+            if(key instanceof BlenderKey) {
+                File linkedAbsoluteFile = new File(key.getName());
+                if(linkedAbsoluteFile.exists() && linkedAbsoluteFile.isFile()) {
+                    try {
+                        return new StreamAssetInfo(manager, key, new FileInputStream(linkedAbsoluteFile));
+                    } catch (FileNotFoundException e) {
+                        return null;
+                    }
+                }
+                
+                File linkedFileInCurrentAssetFolder = new File(rootFolder, linkedAbsoluteFile.getName());
+                if(linkedFileInCurrentAssetFolder.exists() && linkedFileInCurrentAssetFolder.isFile()) {
+                    try {
+                        return new StreamAssetInfo(manager, key, new FileInputStream(linkedFileInCurrentAssetFolder));
+                    } catch (FileNotFoundException e) {
+                        return null;
+                    }
+                }
+                
+                File linkedFileInCurrentFolder = new File(".", linkedAbsoluteFile.getName());
+                if(linkedFileInCurrentFolder.exists() && linkedFileInCurrentFolder.isFile()) {
+                    try {
+                        return new StreamAssetInfo(manager, key, new FileInputStream(linkedFileInCurrentFolder));
+                    } catch (FileNotFoundException e) {
+                        return null;
+                    }
+                }
+            }
+            return null;
+        }
+    }
 }

+ 1 - 0
jme3-blender/src/main/java/com/jme3/scene/plugins/blender/landscape/LandscapeHelper.java

@@ -81,6 +81,7 @@ public class LandscapeHelper extends AbstractBlenderHelper {
         if ((mode & MODE_MIST) != 0) {
             LOGGER.fine("Loading fog.");
             result = new FogFilter();
+            result.setName("FIfog");
             result.setFogColor(this.toBackgroundColor(worldStructure));
         }
         return result;