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
This commit is contained in:
parent
ec4486d5eb
commit
8deba71f8d
@ -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,6 +61,7 @@ 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;
|
||||||
@ -460,6 +464,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
|
||||||
* converted data.
|
* converted data.
|
||||||
|
@ -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…
x
Reference in New Issue
Block a user