diff --git a/engine/src/blender/com/jme3/scene/plugins/blender/JmeConverter.java b/engine/src/blender/com/jme3/scene/plugins/blender/AbstractBlenderLoader.java similarity index 79% rename from engine/src/blender/com/jme3/scene/plugins/blender/JmeConverter.java rename to engine/src/blender/com/jme3/scene/plugins/blender/AbstractBlenderLoader.java index 799dee732..bdad3b30e 100644 --- a/engine/src/blender/com/jme3/scene/plugins/blender/JmeConverter.java +++ b/engine/src/blender/com/jme3/scene/plugins/blender/AbstractBlenderLoader.java @@ -32,7 +32,10 @@ package com.jme3.scene.plugins.blender; import java.util.List; +import java.util.logging.Level; +import java.util.logging.Logger; +import com.jme3.asset.AssetLoader; import com.jme3.asset.BlenderKey.FeaturesToLoad; import com.jme3.asset.BlenderKey.WorldData; import com.jme3.light.AmbientLight; @@ -42,8 +45,10 @@ import com.jme3.math.ColorRGBA; import com.jme3.renderer.Camera; import com.jme3.scene.Geometry; import com.jme3.scene.Node; +import com.jme3.scene.Spatial; import com.jme3.scene.plugins.blender.cameras.CameraHelper; import com.jme3.scene.plugins.blender.exceptions.BlenderFileException; +import com.jme3.scene.plugins.blender.file.Pointer; import com.jme3.scene.plugins.blender.file.Structure; import com.jme3.scene.plugins.blender.lights.LightHelper; import com.jme3.scene.plugins.blender.materials.MaterialHelper; @@ -52,37 +57,12 @@ import com.jme3.scene.plugins.blender.objects.ObjectHelper; /** * This class converts blender file blocks into jMonkeyEngine data structures. - * @author Marcin Roguski + * @author Marcin Roguski (Kaelthas) */ -/* package */class JmeConverter { - - private final BlenderContext blenderContext; - - /** - * Constructor. Creates the loader and checks if the given data is correct. - * @param blenderContext - * the blender context; it should have the following field set: - asset manager - blender key - dna block - * data - blender input stream Otherwise IllegalArgumentException will be thrown. - * @param featuresToLoad - * bitwise flag describing what features are to be loaded - * @see FeaturesToLoad FeaturesToLoad - */ - public JmeConverter(BlenderContext blenderContext) { - // validating the given data first - if (blenderContext.getAssetManager() == null) { - throw new IllegalArgumentException("Cannot find asset manager!"); - } - if (blenderContext.getBlenderKey() == null) { - throw new IllegalArgumentException("Cannot find blender key!"); - } - if (blenderContext.getDnaBlockData() == null) { - throw new IllegalArgumentException("Cannot find dna block!"); - } - if (blenderContext.getInputStream() == null) { - throw new IllegalArgumentException("Cannot find blender file stream!"); - } - this.blenderContext = blenderContext; - } +/* package */ abstract class AbstractBlenderLoader implements AssetLoader { + private static final Logger LOGGER = Logger.getLogger(AbstractBlenderLoader.class.getName()); + + protected BlenderContext blenderContext; /** * This method converts the given structure to a scene node. @@ -90,11 +70,29 @@ import com.jme3.scene.plugins.blender.objects.ObjectHelper; * structure of a scene * @return scene's node */ - public Node toScene(Structure structure) {// TODO: import the scene + public Node toScene(Structure structure) { if ((blenderContext.getBlenderKey().getFeaturesToLoad() & FeaturesToLoad.SCENES) == 0) { return null; } - return new Node(structure.getName()); + Node result = new Node(structure.getName()); + try { + List base = ((Structure)structure.getFieldValue("base")).evaluateListBase(blenderContext); + for(Structure b : base) { + Pointer pObject = (Pointer) b.getFieldValue("object"); + if(pObject.isNotNull()) { + Structure objectStructure = pObject.fetchData(blenderContext.getInputStream()).get(0); + Object object = this.toObject(objectStructure); + if(object instanceof Spatial) { + result.attachChild((Spatial) object); + } else if(object instanceof Light) { + result.addLight((Light)object); + } + } + } + } catch (BlenderFileException e) { + LOGGER.log(Level.SEVERE, e.getLocalizedMessage(), e); + } + return result; } /** diff --git a/engine/src/blender/com/jme3/scene/plugins/blender/BlenderContext.java b/engine/src/blender/com/jme3/scene/plugins/blender/BlenderContext.java index 424201af3..b008199fa 100644 --- a/engine/src/blender/com/jme3/scene/plugins/blender/BlenderContext.java +++ b/engine/src/blender/com/jme3/scene/plugins/blender/BlenderContext.java @@ -31,12 +31,15 @@ */ package com.jme3.scene.plugins.blender; +import java.io.IOException; import java.util.ArrayList; import java.util.EmptyStackException; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Stack; +import java.util.logging.Level; +import java.util.logging.Logger; import com.jme3.asset.AssetManager; import com.jme3.asset.BlenderKey; @@ -58,7 +61,8 @@ import com.jme3.scene.plugins.blender.modifiers.Modifier; * @author Marcin Roguski (Kaelthas) */ public class BlenderContext { - + private static final Logger LOGGER = Logger.getLogger(BlenderContext.class.getName()); + /** The blender key. */ private BlenderKey blenderKey; /** The header of the file block. */ @@ -459,6 +463,16 @@ public class BlenderContext { } return blenderKey.getDefaultMaterial(); } + + public void dispose() { + try { + inputStream.close(); + } catch (IOException e) { + LOGGER.log(Level.SEVERE, e.getLocalizedMessage(), e); + } + loadedFeatures.clear(); + loadedFeaturesByName.clear(); + } /** * This enum defines what loaded data type user wants to retreive. It can be either filled structure or already diff --git a/engine/src/blender/com/jme3/scene/plugins/blender/BlenderLoader.java b/engine/src/blender/com/jme3/scene/plugins/blender/BlenderLoader.java index 2d8a1580d..7cf159660 100644 --- a/engine/src/blender/com/jme3/scene/plugins/blender/BlenderLoader.java +++ b/engine/src/blender/com/jme3/scene/plugins/blender/BlenderLoader.java @@ -38,7 +38,6 @@ import java.util.logging.Level; import java.util.logging.Logger; import com.jme3.asset.AssetInfo; -import com.jme3.asset.AssetLoader; import com.jme3.asset.BlenderKey; import com.jme3.asset.BlenderKey.FeaturesToLoad; import com.jme3.asset.BlenderKey.LoadingResults; @@ -67,38 +66,31 @@ import com.jme3.scene.plugins.blender.textures.TextureHelper; /** * This is the main loading class. Have in notice that asset manager needs to have loaders for resources like textures. - * @author Marcin Roguski + * @author Marcin Roguski (Kaelthas) */ -public class BlenderLoader implements AssetLoader { +public class BlenderLoader extends AbstractBlenderLoader { private static final Logger LOGGER = Logger.getLogger(BlenderLoader.class.getName()); - /** Converter for blender structures. */ - protected JmeConverter converter; - /** The blender context. */ - protected BlenderContext blenderContext; - /** The blender key to use. */ - protected BlenderKey blenderKey; /** The blocks read from the file. */ protected List blocks; - /** Blender input stream. */ - protected BlenderInputStream inputStream; @Override public Spatial load(AssetInfo assetInfo) throws IOException { try { this.setup(assetInfo); + BlenderKey blenderKey = blenderContext.getBlenderKey(); LoadingResults loadingResults = blenderKey.prepareLoadingResults(); WorldData worldData = null;// a set of data used in different scene aspects for (FileBlockHeader block : blocks) { switch (block.getCode()) { case FileBlockHeader.BLOCK_OB00:// Object - Object object = converter.toObject(block.getStructure(blenderContext)); + Object object = this.toObject(block.getStructure(blenderContext)); if (object instanceof Node) { if ((blenderKey.getFeaturesToLoad() & FeaturesToLoad.OBJECTS) != 0) { LOGGER.log(Level.INFO, "{0}: {1}--> {2}", new Object[] { ((Node) object).getName(), ((Node) object).getLocalTranslation().toString(), ((Node) object).getParent() == null ? "null" : ((Node) object).getParent().getName() }); - if (((Node) object).getParent() == null) { + if (this.isRootObject(loadingResults, (Node)object)) { loadingResults.addObject((Node) object); } } @@ -114,12 +106,12 @@ public class BlenderLoader implements AssetLoader { break; case FileBlockHeader.BLOCK_MA00:// Material if (blenderKey.isLoadUnlinkedAssets() && (blenderKey.getFeaturesToLoad() & FeaturesToLoad.MATERIALS) != 0) { - loadingResults.addMaterial(converter.toMaterial(block.getStructure(blenderContext))); + loadingResults.addMaterial(this.toMaterial(block.getStructure(blenderContext))); } break; case FileBlockHeader.BLOCK_SC00:// Scene if ((blenderKey.getFeaturesToLoad() & FeaturesToLoad.SCENES) != 0) { - loadingResults.addScene(converter.toScene(block.getStructure(blenderContext))); + loadingResults.addScene(this.toScene(block.getStructure(blenderContext))); } break; case FileBlockHeader.BLOCK_WO00:// World @@ -127,7 +119,7 @@ public class BlenderLoader implements AssetLoader { Structure worldStructure = block.getStructure(blenderContext); String worldName = worldStructure.getName(); if (blenderKey.getUsedWorld() == null || blenderKey.getUsedWorld().equals(worldName)) { - worldData = converter.toWorldData(worldStructure); + worldData = this.toWorldData(worldStructure); if ((blenderKey.getFeaturesToLoad() & FeaturesToLoad.LIGHTS) != 0) { loadingResults.addLight(worldData.getAmbientLight()); } @@ -136,11 +128,7 @@ public class BlenderLoader implements AssetLoader { break; } } - try { - inputStream.close(); - } catch (IOException e) { - LOGGER.log(Level.SEVERE, e.getMessage(), e); - } + blenderContext.dispose(); return loadingResults; } catch (BlenderFileException e) { LOGGER.log(Level.SEVERE, e.getMessage(), e); @@ -148,6 +136,30 @@ public class BlenderLoader implements AssetLoader { return null; } + /** + * This method indicates if the given spatial is a root object. It means it + * has no parent or is directly attached to one of the already loaded scene + * nodes. + * + * @param loadingResults + * loading results containing the scene nodes + * @param spatial + * spatial object + * @return true if the given spatial is a root object and + * false otherwise + */ + protected boolean isRootObject(LoadingResults loadingResults, Spatial spatial) { + if(spatial.getParent() == null) { + return true; + } + for(Node scene : loadingResults.getScenes()) { + if(spatial.getParent().equals(scene)) { + return true; + } + } + return false; + } + /** * This method sets up the loader. * @param assetInfo @@ -158,6 +170,7 @@ public class BlenderLoader implements AssetLoader { protected void setup(AssetInfo assetInfo) throws BlenderFileException { // registering loaders ModelKey modelKey = (ModelKey) assetInfo.getKey(); + BlenderKey blenderKey; if (modelKey instanceof BlenderKey) { blenderKey = (BlenderKey) modelKey; } else { @@ -166,7 +179,7 @@ public class BlenderLoader implements AssetLoader { } // opening stream - inputStream = new BlenderInputStream(assetInfo.openStream(), assetInfo.getManager()); + BlenderInputStream inputStream = new BlenderInputStream(assetInfo.openStream(), assetInfo.getManager()); // reading blocks blocks = new ArrayList(); @@ -217,7 +230,5 @@ public class BlenderLoader implements AssetLoader { int lay = ((Number) sceneFileBlock.getStructure(blenderContext).getFieldValue("lay")).intValue(); blenderContext.getBlenderKey().setLayersToLoad(lay);// load only current layer } - - converter = new JmeConverter(blenderContext); } } diff --git a/engine/src/blender/com/jme3/scene/plugins/blender/BlenderModelLoader.java b/engine/src/blender/com/jme3/scene/plugins/blender/BlenderModelLoader.java index 8ec24e5e5..09e9cb72f 100644 --- a/engine/src/blender/com/jme3/scene/plugins/blender/BlenderModelLoader.java +++ b/engine/src/blender/com/jme3/scene/plugins/blender/BlenderModelLoader.java @@ -32,12 +32,11 @@ package com.jme3.scene.plugins.blender; import java.io.IOException; -import java.util.List; import java.util.logging.Level; import java.util.logging.Logger; import com.jme3.asset.AssetInfo; -import com.jme3.asset.BlenderKey.LoadingResults; +import com.jme3.asset.BlenderKey; import com.jme3.light.Light; import com.jme3.scene.Node; import com.jme3.scene.Spatial; @@ -55,13 +54,14 @@ public class BlenderModelLoader extends BlenderLoader { @Override public Spatial load(AssetInfo assetInfo) throws IOException { try { - setup(assetInfo); + this.setup(assetInfo); + BlenderKey blenderKey = blenderContext.getBlenderKey(); Node modelRoot = new Node(blenderKey.getName()); for (FileBlockHeader block : blocks) { if (block.getCode() == FileBlockHeader.BLOCK_OB00) { - Object object = converter.toObject(block.getStructure(blenderContext)); + Object object = this.toObject(block.getStructure(blenderContext)); if (object instanceof Node) { LOGGER.log(Level.INFO, "{0}: {1}--> {2}", new Object[]{((Node) object).getName(), ((Node) object).getLocalTranslation().toString(), ((Node) object).getParent() == null ? "null" : ((Node) object).getParent().getName()}); if (((Node) object).getParent() == null) { @@ -72,13 +72,7 @@ public class BlenderModelLoader extends BlenderLoader { } } } - - try { - inputStream.close(); - } catch(IOException e) { - LOGGER.warning(e.getLocalizedMessage()); - } - + blenderContext.dispose(); return modelRoot; } catch (BlenderFileException e) { LOGGER.log(Level.SEVERE, e.getMessage(), e);