Blender loading logic refactoring:

- JmeConverter replaced by AbstractBlenderLoader
- scene loading implemented (now all objects are attached to the scene node)

git-svn-id: https://jmonkeyengine.googlecode.com/svn/trunk@8252 75d07b2b-3a1a-0410-a2c5-0572b91ccdca
3.0
Kae..pl 13 years ago
parent ec4486d5eb
commit 8deba71f8d
  1. 62
      engine/src/blender/com/jme3/scene/plugins/blender/AbstractBlenderLoader.java
  2. 16
      engine/src/blender/com/jme3/scene/plugins/blender/BlenderContext.java
  3. 59
      engine/src/blender/com/jme3/scene/plugins/blender/BlenderLoader.java
  4. 16
      engine/src/blender/com/jme3/scene/plugins/blender/BlenderModelLoader.java

@ -32,7 +32,10 @@
package com.jme3.scene.plugins.blender; package com.jme3.scene.plugins.blender;
import java.util.List; 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.FeaturesToLoad;
import com.jme3.asset.BlenderKey.WorldData; import com.jme3.asset.BlenderKey.WorldData;
import com.jme3.light.AmbientLight; import com.jme3.light.AmbientLight;
@ -42,8 +45,10 @@ import com.jme3.math.ColorRGBA;
import com.jme3.renderer.Camera; import com.jme3.renderer.Camera;
import com.jme3.scene.Geometry; import com.jme3.scene.Geometry;
import com.jme3.scene.Node; import com.jme3.scene.Node;
import com.jme3.scene.Spatial;
import com.jme3.scene.plugins.blender.cameras.CameraHelper; import com.jme3.scene.plugins.blender.cameras.CameraHelper;
import com.jme3.scene.plugins.blender.exceptions.BlenderFileException; 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.file.Structure;
import com.jme3.scene.plugins.blender.lights.LightHelper; import com.jme3.scene.plugins.blender.lights.LightHelper;
import com.jme3.scene.plugins.blender.materials.MaterialHelper; 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. * This class converts blender file blocks into jMonkeyEngine data structures.
* @author Marcin Roguski * @author Marcin Roguski (Kaelthas)
*/ */
/* package */class JmeConverter { /* package */ abstract class AbstractBlenderLoader implements AssetLoader {
private static final Logger LOGGER = Logger.getLogger(AbstractBlenderLoader.class.getName());
private final BlenderContext blenderContext;
protected 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;
}
/** /**
* This method converts the given structure to a scene node. * 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 * structure of a scene
* @return scene's node * @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) { if ((blenderContext.getBlenderKey().getFeaturesToLoad() & FeaturesToLoad.SCENES) == 0) {
return null; return null;
} }
return new Node(structure.getName()); Node result = new Node(structure.getName());
try {
List<Structure> 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;
} }
/** /**

@ -31,12 +31,15 @@
*/ */
package com.jme3.scene.plugins.blender; package com.jme3.scene.plugins.blender;
import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.EmptyStackException; import java.util.EmptyStackException;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Stack; import java.util.Stack;
import java.util.logging.Level;
import java.util.logging.Logger;
import com.jme3.asset.AssetManager; import com.jme3.asset.AssetManager;
import com.jme3.asset.BlenderKey; import com.jme3.asset.BlenderKey;
@ -58,7 +61,8 @@ import com.jme3.scene.plugins.blender.modifiers.Modifier;
* @author Marcin Roguski (Kaelthas) * @author Marcin Roguski (Kaelthas)
*/ */
public class BlenderContext { public class BlenderContext {
private static final Logger LOGGER = Logger.getLogger(BlenderContext.class.getName());
/** The blender key. */ /** The blender key. */
private BlenderKey blenderKey; private BlenderKey blenderKey;
/** The header of the file block. */ /** The header of the file block. */
@ -459,6 +463,16 @@ public class BlenderContext {
} }
return blenderKey.getDefaultMaterial(); 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 * This enum defines what loaded data type user wants to retreive. It can be either filled structure or already

@ -38,7 +38,6 @@ import java.util.logging.Level;
import java.util.logging.Logger; import java.util.logging.Logger;
import com.jme3.asset.AssetInfo; import com.jme3.asset.AssetInfo;
import com.jme3.asset.AssetLoader;
import com.jme3.asset.BlenderKey; import com.jme3.asset.BlenderKey;
import com.jme3.asset.BlenderKey.FeaturesToLoad; import com.jme3.asset.BlenderKey.FeaturesToLoad;
import com.jme3.asset.BlenderKey.LoadingResults; 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. * 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()); 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. */ /** The blocks read from the file. */
protected List<FileBlockHeader> blocks; protected List<FileBlockHeader> blocks;
/** Blender input stream. */
protected BlenderInputStream inputStream;
@Override @Override
public Spatial load(AssetInfo assetInfo) throws IOException { public Spatial load(AssetInfo assetInfo) throws IOException {
try { try {
this.setup(assetInfo); this.setup(assetInfo);
BlenderKey blenderKey = blenderContext.getBlenderKey();
LoadingResults loadingResults = blenderKey.prepareLoadingResults(); LoadingResults loadingResults = blenderKey.prepareLoadingResults();
WorldData worldData = null;// a set of data used in different scene aspects WorldData worldData = null;// a set of data used in different scene aspects
for (FileBlockHeader block : blocks) { for (FileBlockHeader block : blocks) {
switch (block.getCode()) { switch (block.getCode()) {
case FileBlockHeader.BLOCK_OB00:// Object case FileBlockHeader.BLOCK_OB00:// Object
Object object = converter.toObject(block.getStructure(blenderContext)); Object object = this.toObject(block.getStructure(blenderContext));
if (object instanceof Node) { if (object instanceof Node) {
if ((blenderKey.getFeaturesToLoad() & FeaturesToLoad.OBJECTS) != 0) { 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() }); 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); loadingResults.addObject((Node) object);
} }
} }
@ -114,12 +106,12 @@ public class BlenderLoader implements AssetLoader {
break; break;
case FileBlockHeader.BLOCK_MA00:// Material case FileBlockHeader.BLOCK_MA00:// Material
if (blenderKey.isLoadUnlinkedAssets() && (blenderKey.getFeaturesToLoad() & FeaturesToLoad.MATERIALS) != 0) { if (blenderKey.isLoadUnlinkedAssets() && (blenderKey.getFeaturesToLoad() & FeaturesToLoad.MATERIALS) != 0) {
loadingResults.addMaterial(converter.toMaterial(block.getStructure(blenderContext))); loadingResults.addMaterial(this.toMaterial(block.getStructure(blenderContext)));
} }
break; break;
case FileBlockHeader.BLOCK_SC00:// Scene case FileBlockHeader.BLOCK_SC00:// Scene
if ((blenderKey.getFeaturesToLoad() & FeaturesToLoad.SCENES) != 0) { if ((blenderKey.getFeaturesToLoad() & FeaturesToLoad.SCENES) != 0) {
loadingResults.addScene(converter.toScene(block.getStructure(blenderContext))); loadingResults.addScene(this.toScene(block.getStructure(blenderContext)));
} }
break; break;
case FileBlockHeader.BLOCK_WO00:// World case FileBlockHeader.BLOCK_WO00:// World
@ -127,7 +119,7 @@ public class BlenderLoader implements AssetLoader {
Structure worldStructure = block.getStructure(blenderContext); Structure worldStructure = block.getStructure(blenderContext);
String worldName = worldStructure.getName(); String worldName = worldStructure.getName();
if (blenderKey.getUsedWorld() == null || blenderKey.getUsedWorld().equals(worldName)) { if (blenderKey.getUsedWorld() == null || blenderKey.getUsedWorld().equals(worldName)) {
worldData = converter.toWorldData(worldStructure); worldData = this.toWorldData(worldStructure);
if ((blenderKey.getFeaturesToLoad() & FeaturesToLoad.LIGHTS) != 0) { if ((blenderKey.getFeaturesToLoad() & FeaturesToLoad.LIGHTS) != 0) {
loadingResults.addLight(worldData.getAmbientLight()); loadingResults.addLight(worldData.getAmbientLight());
} }
@ -136,11 +128,7 @@ public class BlenderLoader implements AssetLoader {
break; break;
} }
} }
try { blenderContext.dispose();
inputStream.close();
} catch (IOException e) {
LOGGER.log(Level.SEVERE, e.getMessage(), e);
}
return loadingResults; return loadingResults;
} catch (BlenderFileException e) { } catch (BlenderFileException e) {
LOGGER.log(Level.SEVERE, e.getMessage(), e); LOGGER.log(Level.SEVERE, e.getMessage(), e);
@ -148,6 +136,30 @@ public class BlenderLoader implements AssetLoader {
return null; 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 <b>true</b> if the given spatial is a root object and
* <b>false</b> 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. * This method sets up the loader.
* @param assetInfo * @param assetInfo
@ -158,6 +170,7 @@ public class BlenderLoader implements AssetLoader {
protected void setup(AssetInfo assetInfo) throws BlenderFileException { protected void setup(AssetInfo assetInfo) throws BlenderFileException {
// registering loaders // registering loaders
ModelKey modelKey = (ModelKey) assetInfo.getKey(); ModelKey modelKey = (ModelKey) assetInfo.getKey();
BlenderKey blenderKey;
if (modelKey instanceof BlenderKey) { if (modelKey instanceof BlenderKey) {
blenderKey = (BlenderKey) modelKey; blenderKey = (BlenderKey) modelKey;
} else { } else {
@ -166,7 +179,7 @@ public class BlenderLoader implements AssetLoader {
} }
// opening stream // opening stream
inputStream = new BlenderInputStream(assetInfo.openStream(), assetInfo.getManager()); BlenderInputStream inputStream = new BlenderInputStream(assetInfo.openStream(), assetInfo.getManager());
// reading blocks // reading blocks
blocks = new ArrayList<FileBlockHeader>(); blocks = new ArrayList<FileBlockHeader>();
@ -217,7 +230,5 @@ public class BlenderLoader implements AssetLoader {
int lay = ((Number) sceneFileBlock.getStructure(blenderContext).getFieldValue("lay")).intValue(); int lay = ((Number) sceneFileBlock.getStructure(blenderContext).getFieldValue("lay")).intValue();
blenderContext.getBlenderKey().setLayersToLoad(lay);// load only current layer blenderContext.getBlenderKey().setLayersToLoad(lay);// load only current layer
} }
converter = new JmeConverter(blenderContext);
} }
} }

@ -32,12 +32,11 @@
package com.jme3.scene.plugins.blender; package com.jme3.scene.plugins.blender;
import java.io.IOException; import java.io.IOException;
import java.util.List;
import java.util.logging.Level; import java.util.logging.Level;
import java.util.logging.Logger; import java.util.logging.Logger;
import com.jme3.asset.AssetInfo; import com.jme3.asset.AssetInfo;
import com.jme3.asset.BlenderKey.LoadingResults; import com.jme3.asset.BlenderKey;
import com.jme3.light.Light; import com.jme3.light.Light;
import com.jme3.scene.Node; import com.jme3.scene.Node;
import com.jme3.scene.Spatial; import com.jme3.scene.Spatial;
@ -55,13 +54,14 @@ public class BlenderModelLoader extends BlenderLoader {
@Override @Override
public Spatial load(AssetInfo assetInfo) throws IOException { public Spatial load(AssetInfo assetInfo) throws IOException {
try { try {
setup(assetInfo); this.setup(assetInfo);
BlenderKey blenderKey = blenderContext.getBlenderKey();
Node modelRoot = new Node(blenderKey.getName()); Node modelRoot = new Node(blenderKey.getName());
for (FileBlockHeader block : blocks) { for (FileBlockHeader block : blocks) {
if (block.getCode() == FileBlockHeader.BLOCK_OB00) { if (block.getCode() == FileBlockHeader.BLOCK_OB00) {
Object object = converter.toObject(block.getStructure(blenderContext)); Object object = this.toObject(block.getStructure(blenderContext));
if (object instanceof Node) { 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()}); 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 (((Node) object).getParent() == null) {
@ -72,13 +72,7 @@ public class BlenderModelLoader extends BlenderLoader {
} }
} }
} }
blenderContext.dispose();
try {
inputStream.close();
} catch(IOException e) {
LOGGER.warning(e.getLocalizedMessage());
}
return modelRoot; return modelRoot;
} catch (BlenderFileException e) { } catch (BlenderFileException e) {
LOGGER.log(Level.SEVERE, e.getMessage(), e); LOGGER.log(Level.SEVERE, e.getMessage(), e);

Loading…
Cancel
Save