/*
- * Copyright (c) 2009-2010 jMonkeyEngine
+ * Copyright (c) 2009-2012 jMonkeyEngine
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-
package com.jme3.scene.plugins.ogre;
import com.jme3.animation.Animation;
/*
- * Copyright (c) 2009-2010 jMonkeyEngine
+ * Copyright (c) 2009-2012 jMonkeyEngine
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-
package com.jme3.scene.plugins.ogre;
-import com.jme3.asset.AssetInfo;
-import com.jme3.asset.AssetKey;
-import com.jme3.asset.AssetLoader;
-import com.jme3.asset.AssetManager;
-import com.jme3.asset.AssetNotFoundException;
-import com.jme3.asset.TextureKey;
+import com.jme3.asset.*;
import com.jme3.material.Material;
import com.jme3.material.MaterialList;
import com.jme3.material.RenderState;
import com.jme3.scene.plugins.ogre.matext.MaterialExtensionLoader;
import com.jme3.scene.plugins.ogre.matext.MaterialExtensionSet;
import com.jme3.scene.plugins.ogre.matext.OgreMaterialKey;
-import com.jme3.texture.Image;
-import com.jme3.texture.Image.Format;
import com.jme3.texture.Texture;
import com.jme3.texture.Texture.WrapMode;
import com.jme3.texture.Texture2D;
-import com.jme3.util.BufferUtils;
+import com.jme3.util.PlaceholderAssets;
import com.jme3.util.blockparser.BlockLanguageParser;
import com.jme3.util.blockparser.Statement;
import java.io.IOException;
import java.io.InputStream;
-import java.nio.ByteBuffer;
import java.util.Arrays;
import java.util.List;
import java.util.Scanner;
private int texUnit = 0;
private ColorRGBA readColor(String content){
- String[] split = content.split(" ");
+ String[] split = content.split("\\s");
ColorRGBA color = new ColorRGBA();
color.r = Float.parseFloat(split[0]);
cubic = true;
}
- TextureKey key = new TextureKey(folderName + path, false);
- key.setGenerateMips(genMips);
- key.setAsCube(cubic);
+ TextureKey texKey = new TextureKey(folderName + path, false);
+ texKey.setGenerateMips(genMips);
+ texKey.setAsCube(cubic);
- Texture loadedTexture;
try {
- loadedTexture = assetManager.loadTexture(key);
- } catch (AssetNotFoundException ex){
- logger.log(Level.WARNING, "Failed to load texture " + key + " for material " + matName, ex);
- loadedTexture = null;
- }
- if (loadedTexture == null){
- ByteBuffer tempData = BufferUtils.createByteBuffer(3);
- tempData.put((byte)0xFF).put((byte)0x00).put((byte)0x00);
- textures[texUnit].setImage(new Image(Format.RGB8, 1,1,tempData));
- logger.log(Level.WARNING, "Using RED texture instead of {0}", path);
- }else{
+ Texture loadedTexture = assetManager.loadTexture(texKey);
+
textures[texUnit].setImage(loadedTexture.getImage());
textures[texUnit].setMinFilter(loadedTexture.getMinFilter());
textures[texUnit].setKey(loadedTexture.getKey());
textures[texUnit].setName(texName);
texName = null;
}else{
- textures[texUnit].setName(key.getName());
+ textures[texUnit].setName(texKey.getName());
}
+ } catch (AssetNotFoundException ex){
+ logger.log(Level.WARNING, "Cannot locate {0} for material {1}", new Object[]{texKey, matName});
+ textures[texUnit].setImage(PlaceholderAssets.getPlaceholderImage());
}
}
}else if (keyword.equals("emissive")){
emissive = readColor(split[1]);
}else if (keyword.equals("specular")){
- String[] subsplit = split[1].split(" ");
+ String[] subsplit = split[1].split("\\s");
specular = new ColorRGBA();
specular.r = Float.parseFloat(subsplit[0]);
specular.g = Float.parseFloat(subsplit[1]);
if (statement.getLine().startsWith("technique")){
readTechnique(statement);
}else if (statement.getLine().startsWith("receive_shadows")){
- String isOn = statement.getLine().split(" ")[1];
+ String isOn = statement.getLine().split("\\s")[1];
if (isOn != null && isOn.equals("true")){
}
}
rs.setAlphaTest(true);
rs.setAlphaFallOff(0.01f);
rs.setBlendMode(RenderState.BlendMode.Alpha);
- if (twoSide)
+
+ if (twoSide){
rs.setFaceCullMode(RenderState.FaceCullMode.Off);
+ }
+
// rs.setDepthWrite(false);
mat.setTransparent(true);
- if (!noLight)
+ if (!noLight){
mat.setBoolean("UseAlpha", true);
+ }
}else{
if (twoSide){
RenderState rs = mat.getAdditionalRenderState();
"Ogre3D materials with extended materials");
}
- list = new MaterialExtensionLoader().load(assetManager, matExts, statements);
+ list = new MaterialExtensionLoader().load(assetManager, key, matExts, statements);
break;
}else if (statement.getLine().startsWith("material")){
if (list == null){
/*
- * Copyright (c) 2009-2010 jMonkeyEngine
+ * Copyright (c) 2009-2012 jMonkeyEngine
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-
package com.jme3.scene.plugins.ogre;
//import static com.jmex.model.XMLUtil.getAttribute;
/*
- * Copyright (c) 2009-2010 jMonkeyEngine
+ * Copyright (c) 2009-2012 jMonkeyEngine
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
*/
package com.jme3.scene.plugins.ogre;
-import com.jme3.animation.Animation;
-import com.jme3.scene.plugins.ogre.matext.OgreMaterialKey;
import com.jme3.animation.AnimControl;
+import com.jme3.animation.Animation;
import com.jme3.animation.SkeletonControl;
-import com.jme3.asset.AssetInfo;
-import com.jme3.asset.AssetKey;
-import com.jme3.asset.AssetLoader;
-import com.jme3.asset.AssetManager;
-import com.jme3.asset.AssetNotFoundException;
+import com.jme3.asset.*;
import com.jme3.material.Material;
import com.jme3.material.MaterialList;
import com.jme3.math.ColorRGBA;
import com.jme3.renderer.queue.RenderQueue.Bucket;
-import com.jme3.scene.Geometry;
-import com.jme3.scene.Mesh;
-import com.jme3.scene.Node;
-import com.jme3.scene.UserData;
-import com.jme3.scene.VertexBuffer;
+import com.jme3.scene.*;
import com.jme3.scene.VertexBuffer.Format;
import com.jme3.scene.VertexBuffer.Type;
import com.jme3.scene.VertexBuffer.Usage;
+import com.jme3.scene.plugins.ogre.matext.OgreMaterialKey;
import com.jme3.util.BufferUtils;
import com.jme3.util.IntMap;
import com.jme3.util.IntMap.Entry;
+import com.jme3.util.PlaceholderAssets;
+import static com.jme3.util.xml.SAXUtil.*;
import java.io.IOException;
import java.io.InputStreamReader;
-import java.nio.Buffer;
-import java.nio.ByteBuffer;
-import java.nio.FloatBuffer;
-import java.nio.IntBuffer;
-import java.nio.ShortBuffer;
+import java.nio.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
-
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParserFactory;
-
import org.xml.sax.Attributes;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.DefaultHandler;
-import static com.jme3.util.xml.SAXUtil.*;
-
/**
* Loads Ogre3D mesh.xml files.
*/
private static final Logger logger = Logger.getLogger(MeshLoader.class.getName());
public static boolean AUTO_INTERLEAVE = true;
- public static boolean HARDWARE_SKINNING = false;
private static final Type[] TEXCOORD_TYPES =
new Type[]{
Type.TexCoord,
Type.TexCoord6,
Type.TexCoord7,
Type.TexCoord8,};
+ private AssetKey key;
private String meshName;
private String folderName;
private AssetManager assetManager;
private Geometry geom;
private ByteBuffer indicesData;
private FloatBuffer weightsFloatData;
+ private boolean actuallyHasWeights = false;
private int vertCount;
private boolean usesSharedVerts;
private boolean usesBigIndices;
+ private boolean submeshNamesHack;
// Global data
private Mesh sharedMesh;
private int meshIndex = 0;
private int texCoordIndex = 0;
private String ignoreUntilEnd = null;
private List<Geometry> geoms = new ArrayList<Geometry>();
+ private ArrayList<Boolean> usesSharedMesh = new ArrayList<Boolean>();
private IntMap<List<VertexBuffer>> lodLevels = new IntMap<List<VertexBuffer>>();
private AnimData animData;
geom = null;
sharedMesh = null;
+ usesSharedMesh.clear();
usesSharedVerts = false;
vertCount = 0;
meshIndex = 0;
animData = null;
+ actuallyHasWeights = false;
+ submeshNamesHack = false;
indicesData = null;
weightsFloatData = null;
}
public void endDocument() {
}
- private void pushFace(String v1, String v2, String v3) throws SAXException {
- int i1 = parseInt(v1);
-
- // TODO: fan/strip support
- int i2 = parseInt(v2);
- int i3 = parseInt(v3);
+ private void pushIndex(int index) {
if (ib != null) {
- ib.put(i1).put(i2).put(i3);
+ ib.put(index);
} else {
- sb.put((short) i1).put((short) i2).put((short) i3);
+ sb.put((short) index);
}
}
- private boolean isUsingSharedVerts(Geometry geom) {
- return geom.getUserData(UserData.JME_SHAREDMESH) != null;
+ private void pushFace(String v1, String v2, String v3) throws SAXException {
+ // TODO: fan/strip support
+ switch (mesh.getMode()) {
+ case Triangles:
+ pushIndex(parseInt(v1));
+ pushIndex(parseInt(v2));
+ pushIndex(parseInt(v3));
+ break;
+ case Lines:
+ pushIndex(parseInt(v1));
+ pushIndex(parseInt(v2));
+ break;
+ case Points:
+ pushIndex(parseInt(v1));
+ break;
+ }
}
+// private boolean isUsingSharedVerts(Geometry geom) {
+ // Old code for buffer sharer
+ //return geom.getUserData(UserData.JME_SHAREDMESH) != null;
+// }
private void startFaces(String count) throws SAXException {
int numFaces = parseInt(count);
- int numIndices;
+ int indicesPerFace = 0;
- if (mesh.getMode() == Mesh.Mode.Triangles) {
- numIndices = numFaces * 3;
- } else {
- throw new SAXException("Triangle strip or fan not supported!");
+ switch (mesh.getMode()) {
+ case Triangles:
+ indicesPerFace = 3;
+ break;
+ case Lines:
+ indicesPerFace = 2;
+ break;
+ case Points:
+ indicesPerFace = 1;
+ break;
+ default:
+ throw new SAXException("Strips or fans not supported!");
}
+ int numIndices = indicesPerFace * numFaces;
+
vb = new VertexBuffer(VertexBuffer.Type.Index);
if (!usesBigIndices) {
sb = BufferUtils.createShortBuffer(numIndices);
ib = null;
- vb.setupData(Usage.Static, 3, Format.UnsignedShort, sb);
+ vb.setupData(Usage.Static, indicesPerFace, Format.UnsignedShort, sb);
} else {
ib = BufferUtils.createIntBuffer(numIndices);
sb = null;
- vb.setupData(Usage.Static, 3, Format.UnsignedInt, ib);
+ vb.setupData(Usage.Static, indicesPerFace, Format.UnsignedInt, ib);
}
mesh.setBuffer(vb);
}
Material mat = null;
if (matName.endsWith(".j3m")) {
// load as native jme3 material instance
- mat = assetManager.loadMaterial(matName);
+ try {
+ mat = assetManager.loadMaterial(matName);
+ } catch (AssetNotFoundException ex) {
+ // Warning will be raised (see below)
+ if (!ex.getMessage().equals(matName)) {
+ throw ex;
+ }
+ }
} else {
if (materialList != null) {
mat = materialList.get(matName);
}
- if (mat == null) {
- logger.log(Level.WARNING, "Material {0} not found. Applying default material", matName);
- mat = (Material) assetManager.loadMaterial("Common/Materials/RedColor.j3m");
- }
}
if (mat == null) {
- throw new RuntimeException("Cannot locate material named " + matName);
+ logger.log(Level.WARNING, "Cannot locate {0} for model {1}", new Object[]{matName, key});
+ mat = PlaceholderAssets.getPlaceholderMaterial(assetManager);
+ //mat.setKey(new MaterialKey(matName));
}
if (mat.isTransparent()) {
mesh = new Mesh();
if (opType == null || opType.equals("triangle_list")) {
mesh.setMode(Mesh.Mode.Triangles);
- } else if (opType.equals("triangle_strip")) {
- mesh.setMode(Mesh.Mode.TriangleStrip);
- } else if (opType.equals("triangle_fan")) {
- mesh.setMode(Mesh.Mode.TriangleFan);
+ //} else if (opType.equals("triangle_strip")) {
+ // mesh.setMode(Mesh.Mode.TriangleStrip);
+ //} else if (opType.equals("triangle_fan")) {
+ // mesh.setMode(Mesh.Mode.TriangleFan);
+ } else if (opType.equals("line_list")) {
+ mesh.setMode(Mesh.Mode.Lines);
+ } else {
+ throw new SAXException("Unsupported operation type: " + opType);
}
usesBigIndices = parseBool(use32bitIndices, false);
usesSharedVerts = parseBool(usesharedvertices, false);
if (usesSharedVerts) {
+ usesSharedMesh.add(true);
+
+ // Old code for buffer sharer
// import vertexbuffers from shared geom
- IntMap<VertexBuffer> sharedBufs = sharedMesh.getBuffers();
- for (Entry<VertexBuffer> entry : sharedBufs) {
- mesh.setBuffer(entry.getValue());
- }
+// IntMap<VertexBuffer> sharedBufs = sharedMesh.getBuffers();
+// for (Entry<VertexBuffer> entry : sharedBufs) {
+// mesh.setBuffer(entry.getValue());
+// }
+ } else {
+ usesSharedMesh.add(false);
}
if (meshName == null) {
}
if (usesSharedVerts) {
+ // Old code for buffer sharer
// this mesh is shared!
- geom.setUserData(UserData.JME_SHAREDMESH, sharedMesh);
+ //geom.setUserData(UserData.JME_SHAREDMESH, sharedMesh);
}
applyMaterial(geom, matName);
}
/**
- * Normalizes weights if needed and finds largest amount of weights used
- * for all vertices in the buffer.
+ * Normalizes weights if needed and finds largest amount of weights used for
+ * all vertices in the buffer.
*/
private void endBoneAssigns() {
- if (mesh != sharedMesh && isUsingSharedVerts(geom)) {
+// if (mesh != sharedMesh && isUsingSharedVerts(geom)) {
+// return;
+// }
+
+ if (!actuallyHasWeights) {
+ // No weights were actually written (the tag didn't have any entries)
+ // remove those buffers
+ mesh.clearBuffer(Type.BoneIndex);
+ mesh.clearBuffer(Type.BoneWeight);
+
+ weightsFloatData = null;
+ indicesData = null;
+
return;
}
if (sum != 1f) {
weightsFloatData.position(weightsFloatData.position() - 4);
// compute new vals based on sum
- float sumToB = 1f / sum;
+ float sumToB = sum == 0 ? 0 : 1f / sum;
weightsFloatData.put(w0 * sumToB);
weightsFloatData.put(w1 * sumToB);
weightsFloatData.put(w2 * sumToB);
}
weightsFloatData.rewind();
+ actuallyHasWeights = false;
weightsFloatData = null;
indicesData = null;
// each vertex has
// - 4 bone weights
// - 4 bone indices
- if (HARDWARE_SKINNING) {
- weightsFloatData = BufferUtils.createFloatBuffer(vertCount * 4);
- indicesData = BufferUtils.createByteBuffer(vertCount * 4);
- } else {
- // create array-backed buffers if software skinning for access speed
- weightsFloatData = FloatBuffer.allocate(vertCount * 4);
- indicesData = ByteBuffer.allocate(vertCount * 4);
- }
+ // create array-backed buffers for software skinning for access speed
+ weightsFloatData = FloatBuffer.allocate(vertCount * 4);
+ indicesData = ByteBuffer.allocate(vertCount * 4);
VertexBuffer weights = new VertexBuffer(Type.BoneWeight);
VertexBuffer indices = new VertexBuffer(Type.BoneIndex);
- Usage usage = HARDWARE_SKINNING ? Usage.Static : Usage.CpuOnly;
- weights.setupData(usage, 4, Format.Float, weightsFloatData);
- indices.setupData(usage, 4, Format.UnsignedByte, indicesData);
-
+ weights.setupData(Usage.CpuOnly, 4, Format.Float, weightsFloatData);
+ indices.setupData(Usage.CpuOnly, 4, Format.UnsignedByte, indicesData);
+
mesh.setBuffer(weights);
mesh.setBuffer(indices);
+
+ //creating empty buffers for HW skinning
+ //the buffers will be setup if ever used.
+ VertexBuffer weightsHW = new VertexBuffer(Type.HWBoneWeight);
+ VertexBuffer indicesHW = new VertexBuffer(Type.HWBoneIndex);
+ //setting usage to cpuOnly so that the buffer is not send empty to the GPU
+ indicesHW.setUsage(Usage.CpuOnly);
+ weightsHW.setUsage(Usage.CpuOnly);
+ mesh.setBuffer(weightsHW);
+ mesh.setBuffer(indicesHW);
}
private void startVertexBuffer(Attributes attribs) throws SAXException {
private void pushColor(Attributes attribs) throws SAXException {
FloatBuffer buf = (FloatBuffer) mesh.getBuffer(Type.Color).getData();
String value = parseString(attribs.getValue("value"));
- String[] vals = value.split(" ");
+ String[] vals = value.split("\\s");
if (vals.length != 3 && vals.length != 4) {
throw new SAXException("Color value must contain 3 or 4 components");
}
private void startLodFaceList(String submeshindex, String numfaces) {
int index = Integer.parseInt(submeshindex);
+ mesh = geoms.get(index).getMesh();
int faceCount = Integer.parseInt(numfaces);
+ VertexBuffer originalIndexBuffer = mesh.getBuffer(Type.Index);
vb = new VertexBuffer(VertexBuffer.Type.Index);
- sb = BufferUtils.createShortBuffer(faceCount * 3);
- ib = null;
- vb.setupData(Usage.Static, 3, Format.UnsignedShort, sb);
+ if (originalIndexBuffer.getFormat() == Format.UnsignedInt) {
+ // LOD buffer should also be integer
+ ib = BufferUtils.createIntBuffer(faceCount * 3);
+ sb = null;
+ vb.setupData(Usage.Static, 3, Format.UnsignedInt, ib);
+ } else {
+ sb = BufferUtils.createShortBuffer(faceCount * 3);
+ ib = null;
+ vb.setupData(Usage.Static, 3, Format.UnsignedShort, sb);
+ }
List<VertexBuffer> levels = lodLevels.get(index);
if (levels == null) {
+ // Create the LOD levels list
levels = new ArrayList<VertexBuffer>();
- Mesh submesh = geoms.get(index).getMesh();
- levels.add(submesh.getBuffer(Type.Index));
+
+ // Add the first LOD level (always the original index buffer)
+ levels.add(originalIndexBuffer);
lodLevels.put(index, levels);
}
-
levels.add(vb);
}
weightsFloatData.put(i, w);
indicesData.put(i, bone);
+ actuallyHasWeights = true;
}
private void startSkeleton(String name) {
- animData = (AnimData) assetManager.loadAsset(folderName + name + ".xml");
+ AssetKey assetKey = new AssetKey(folderName + name + ".xml");
+ try {
+ animData = (AnimData) assetManager.loadAsset(assetKey);
+ } catch (AssetNotFoundException ex) {
+ logger.log(Level.WARNING, "Cannot locate {0} for model {1}", new Object[]{assetKey, key});
+ animData = null;
+ }
}
private void startSubmeshName(String indexStr, String nameStr) {
int index = Integer.parseInt(indexStr);
- geoms.get(index).setName(nameStr);
+ if (index >= geoms.size()) {
+ logger.log(Level.WARNING, "Submesh name index is larger than number of geometries: {0} >= {1}",
+ new Object[]{index, geoms.size()});
+ } else {
+ geoms.get(index).setName(nameStr);
+ }
}
@Override
} else if (qName.equals("boneassignments")) {
startBoneAssigns();
} else if (qName.equals("submesh")) {
- startSubMesh(attribs.getValue("material"),
- attribs.getValue("usesharedvertices"),
- attribs.getValue("use32bitindexes"),
- attribs.getValue("operationtype"));
+ if (submeshNamesHack) {
+ // Hack for blender2ogre only
+ startSubmeshName(attribs.getValue("index"), attribs.getValue("name"));
+ } else {
+ startSubMesh(attribs.getValue("material"),
+ attribs.getValue("usesharedvertices"),
+ attribs.getValue("use32bitindexes"),
+ attribs.getValue("operationtype"));
+ }
} else if (qName.equals("sharedgeometry")) {
String count = attribs.getValue("vertexcount");
if (count == null) {
startSkeleton(attribs.getValue("name"));
} else if (qName.equals("submeshnames")) {
// ok
+ // setting submeshNamesHack to true will make "submesh" tag be interpreted
+ // as a "submeshname" tag.
+ submeshNamesHack = true;
} else if (qName.equals("submeshname")) {
startSubmeshName(attribs.getValue("index"), attribs.getValue("name"));
} else if (qName.equals("mesh")) {
return;
}
- if (qName.equals("submesh")) {
+
+ // If submesh hack is enabled, ignore any submesh/submeshes
+ // end tags.
+ if (qName.equals("submesh") && !submeshNamesHack) {
usesBigIndices = false;
geom = null;
mesh = null;
- } else if (qName.equals("submeshes")) {
+ } else if (qName.equals("submeshes") && !submeshNamesHack) {
// IMPORTANT: restore sharedmesh, for use with shared boneweights
geom = null;
mesh = sharedMesh;
} else if (qName.equals("geometry")
|| qName.equals("sharedgeometry")) {
// finish writing to buffers
- IntMap<VertexBuffer> bufs = mesh.getBuffers();
- for (Entry<VertexBuffer> entry : bufs) {
- Buffer data = entry.getValue().getData();
+ for (VertexBuffer buf : mesh.getBufferList().getArray()) {
+ Buffer data = buf.getData();
if (data.position() != 0) {
data.flip();
}
endLevelOfDetail();
} else if (qName.equals("boneassignments")) {
endBoneAssigns();
+ } else if (qName.equals("submeshnames")) {
+ // Restore default handling for "submesh" tag.
+ submeshNamesHack = false;
}
}
for (int i = 0; i < geoms.size(); i++) {
Geometry g = geoms.get(i);
Mesh m = g.getMesh();
- if (sharedMesh != null && isUsingSharedVerts(g)) {
- m.setBound(sharedMesh.getBound().clone());
+
+ // New code for buffer extract
+ if (sharedMesh != null && usesSharedMesh.get(i)) {
+ m.extractVertexData(sharedMesh);
}
+
model.attachChild(geoms.get(i));
}
if (animData != null) {
// This model uses animation
- // generate bind pose for mesh
- // ONLY if not using shared geometry
- // This includes the shared geoemtry itself actually
- if (sharedMesh != null) {
- sharedMesh.generateBindPose(!HARDWARE_SKINNING);
- }
-
for (int i = 0; i < geoms.size(); i++) {
Geometry g = geoms.get(i);
Mesh m = geoms.get(i).getMesh();
- boolean useShared = isUsingSharedVerts(g);
-
-
- if (!useShared) {
- // create bind pose
- m.generateBindPose(!HARDWARE_SKINNING);
-// } else {
- // Inherit animation data from shared mesh
-// VertexBuffer bindPos = sharedMesh.getBuffer(Type.BindPosePosition);
-// VertexBuffer bindNorm = sharedMesh.getBuffer(Type.BindPoseNormal);
-// VertexBuffer boneIndex = sharedMesh.getBuffer(Type.BoneIndex);
-// VertexBuffer boneWeight = sharedMesh.getBuffer(Type.BoneWeight);
-//
-// if (bindPos != null) {
-// m.setBuffer(bindPos);
-// }
-//
-// if (bindNorm != null) {
-// m.setBuffer(bindNorm);
-// }
-//
-// if (boneIndex != null) {
-// m.setBuffer(boneIndex);
-// }
-//
-// if (boneWeight != null) {
-// m.setBuffer(boneWeight);
-// }
- }
+
+ //FIXME the parameter is now useless.
+ //It was !HADWARE_SKINNING before, but since toggleing
+ //HW skinning does not happen at load time it was always true.
+ //We should use something similar as for the HWBoneIndex and
+ //HWBoneWeight : create the vertex buffers empty so that they
+ //are put in the cache, and really populate them the first time
+ //software skinning is used on the mesh.
+ m.generateBindPose(true);
+
}
// Put the animations in the AnimControl
public Object load(AssetInfo info) throws IOException {
try {
- AssetKey key = info.getKey();
+ key = info.getKey();
meshName = key.getName();
folderName = key.getFolder();
String ext = key.getExtension();
}
assetManager = info.getManager();
- OgreMeshKey meshKey = null;
if (key instanceof OgreMeshKey) {
- meshKey = (OgreMeshKey) key;
+ // OgreMeshKey is being used, try getting the material list
+ // from it
+ OgreMeshKey meshKey = (OgreMeshKey) key;
materialList = meshKey.getMaterialList();
String materialName = meshKey.getMaterialName();
- if (materialList == null) {
- if (materialName != null) {
- try {
- materialList = (MaterialList) assetManager.loadAsset(new OgreMaterialKey(folderName + materialName + ".material"));
- } catch (AssetNotFoundException e) {
- logger.log(Level.WARNING, "Cannot locate {0}{1}.material for model {2}{3}.{4}", new Object[]{folderName, materialName, folderName, meshName, ext});
- logger.log(Level.WARNING, "", e);
- }
- } else {
- try {
- materialList = (MaterialList) assetManager.loadAsset(new OgreMaterialKey(folderName + meshName + ".material"));
- } catch (AssetNotFoundException e) {
- logger.log(Level.WARNING, "Cannot locate {0}{1}.material for model {2}{3}.{4}", new Object[]{folderName, meshName, folderName, meshName, ext});
- logger.log(Level.WARNING, "", e);
- }
+
+ // Material list not set but material name is available
+ if (materialList == null && materialName != null) {
+ OgreMaterialKey materialKey = new OgreMaterialKey(folderName + materialName + ".material");
+ try {
+ materialList = (MaterialList) assetManager.loadAsset(materialKey);
+ } catch (AssetNotFoundException e) {
+ logger.log(Level.WARNING, "Cannot locate {0} for model {1}", new Object[]{materialKey, key});
}
}
} else {
+ // Make sure to reset it to null so that previous state
+ // doesn't leak onto this one
+ materialList = null;
+ }
+
+ // If for some reason material list could not be found through
+ // OgreMeshKey, or if regular ModelKey specified, load using
+ // default method.
+ if (materialList == null) {
+ OgreMaterialKey materialKey = new OgreMaterialKey(folderName + meshName + ".material");
try {
- materialList = (MaterialList) assetManager.loadAsset(new OgreMaterialKey(folderName + meshName + ".material"));
+ materialList = (MaterialList) assetManager.loadAsset(materialKey);
} catch (AssetNotFoundException e) {
- logger.log(Level.WARNING, "Cannot locate {0}{1}.material for model {2}{3}.{4}", new Object[]{folderName, meshName, folderName, meshName, ext});
- logger.log(Level.WARNING, "", e);
- }
-
+ logger.log(Level.WARNING, "Cannot locate {0} for model {1}", new Object[]{materialKey, key});
+ }
}
// Added by larynx 25.06.2011
// checking with JmeSystem.
SAXParserFactory factory = SAXParserFactory.newInstance();
factory.setNamespaceAware(true);
-
+
XMLReader xr = factory.newSAXParser().getXMLReader();
xr.setContentHandler(this);
xr.setErrorHandler(this);
-
+
InputStreamReader r = null;
try {
r = new InputStreamReader(info.openStream());
xr.parse(new InputSource(r));
} finally {
- if (r != null){
+ if (r != null) {
r.close();
}
}
-
+
return compileModel();
} catch (SAXException ex) {
IOException ioEx = new IOException("Error while parsing Ogre3D mesh.xml");
/*
- * Copyright (c) 2009-2010 jMonkeyEngine
+ * Copyright (c) 2009-2012 jMonkeyEngine
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-
package com.jme3.scene.plugins.ogre;
import com.jme3.asset.ModelKey;
import com.jme3.material.MaterialList;
+/**
+ * OgreMeshKey is used to load Ogre3D mesh.xml models with a specific
+ * material file or list. This allows customizing from where the materials
+ * are retrieved, instead of loading the material file as the same
+ * name as the model (the default).
+ *
+ * @author Kirill Vainer
+ */
public class OgreMeshKey extends ModelKey {
private MaterialList materialList;
this.materialName = materialName;
}
+ @Override
+ public boolean equals(Object obj) {
+ if (obj == null) {
+ return false;
+ }
+ if (getClass() != obj.getClass()) {
+ return false;
+ }
+ final OgreMeshKey other = (OgreMeshKey) obj;
+ if (!super.equals(other)) {
+ return false;
+ }
+ if (this.materialList != other.materialList && (this.materialList == null || !this.materialList.equals(other.materialList))) {
+ return false;
+ }
+ if ((this.materialName == null) ? (other.materialName != null) : !this.materialName.equals(other.materialName)) {
+ return false;
+ }
+ return true;
+ }
+
+ @Override
+ public int hashCode() {
+ int hash = 5;
+ hash = 31 * hash + (super.hashCode());
+ hash = 31 * hash + (this.materialList != null ? this.materialList.hashCode() : 0);
+ hash = 31 * hash + (this.materialName != null ? this.materialName.hashCode() : 0);
+ return hash;
+ }
+
public MaterialList getMaterialList() {
return materialList;
}
+ public void setMaterialList(MaterialList materialList){
+ this.materialList = materialList;
+ }
+
public String getMaterialName() {
return materialName;
}
-/*\r
- * Copyright (c) 2009-2010 jMonkeyEngine\r
- * All rights reserved.\r
- *\r
- * Redistribution and use in source and binary forms, with or without\r
- * modification, are permitted provided that the following conditions are\r
- * met:\r
- *\r
- * * Redistributions of source code must retain the above copyright\r
- * notice, this list of conditions and the following disclaimer.\r
- *\r
- * * Redistributions in binary form must reproduce the above copyright\r
- * notice, this list of conditions and the following disclaimer in the\r
- * documentation and/or other materials provided with the distribution.\r
- *\r
- * * Neither the name of 'jMonkeyEngine' nor the names of its contributors\r
- * may be used to endorse or promote products derived from this software\r
- * without specific prior written permission.\r
- *\r
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\r
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED\r
- * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\r
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR\r
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\r
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\r
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\r
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\r
- * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\r
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\r
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
- */\r
-\r
-package com.jme3.scene.plugins.ogre;\r
-\r
-import com.jme3.scene.plugins.ogre.matext.OgreMaterialKey;\r
-import com.jme3.material.MaterialList;\r
-import com.jme3.asset.AssetInfo;\r
-import com.jme3.asset.AssetLoader;\r
-import com.jme3.asset.AssetManager;\r
-import com.jme3.asset.AssetNotFoundException;\r
-import com.jme3.light.DirectionalLight;\r
-import com.jme3.light.Light;\r
-import com.jme3.light.PointLight;\r
-import com.jme3.light.SpotLight;\r
-import com.jme3.math.FastMath;\r
-import com.jme3.math.Quaternion;\r
-import com.jme3.math.Vector3f;\r
-import com.jme3.scene.Node;\r
-import com.jme3.scene.Spatial;\r
-import com.jme3.util.xml.SAXUtil;\r
-import java.io.IOException;\r
-import java.io.InputStreamReader;\r
-import java.util.Stack;\r
-import java.util.logging.Level;\r
-import java.util.logging.Logger;\r
-\r
-import javax.xml.parsers.ParserConfigurationException;\r
-import javax.xml.parsers.SAXParserFactory;\r
-\r
-import org.xml.sax.Attributes;\r
-import org.xml.sax.InputSource;\r
-import org.xml.sax.SAXException;\r
-import org.xml.sax.XMLReader;\r
-import org.xml.sax.helpers.DefaultHandler;\r
-\r
-import static com.jme3.util.xml.SAXUtil.*;\r
-\r
-public class SceneLoader extends DefaultHandler implements AssetLoader {\r
-\r
- private static final Logger logger = Logger.getLogger(SceneLoader.class.getName());\r
-\r
- private Stack<String> elementStack = new Stack<String>();\r
- private String sceneName;\r
- private String folderName;\r
- private AssetManager assetManager;\r
- private MaterialList materialList;\r
- private Node root;\r
- private Node node;\r
- private Node entityNode;\r
- private Light light;\r
- private int nodeIdx = 0;\r
- private static volatile int sceneIdx = 0;\r
-\r
- public SceneLoader(){\r
- super();\r
- }\r
-\r
- @Override\r
- public void startDocument() {\r
- }\r
-\r
- @Override\r
- public void endDocument() {\r
- }\r
- \r
- private void reset(){\r
- elementStack.clear();\r
- nodeIdx = 0;\r
- \r
- // NOTE: Setting some of those to null is only needed\r
- // if the parsed file had an error e.g. startElement was called\r
- // but not endElement\r
- root = null;\r
- node = null;\r
- entityNode = null;\r
- light = null;\r
- }\r
-\r
- private void checkTopNode(String topNode) throws SAXException{\r
- if (!elementStack.peek().equals(topNode)){\r
- throw new SAXException("dotScene parse error: Expected parent node to be " + topNode);\r
- }\r
- }\r
- \r
- private Quaternion parseQuat(Attributes attribs) throws SAXException{\r
- if (attribs.getValue("x") != null){\r
- // defined as quaternion\r
- float x = parseFloat(attribs.getValue("x"));\r
- float y = parseFloat(attribs.getValue("y"));\r
- float z = parseFloat(attribs.getValue("z"));\r
- float w = parseFloat(attribs.getValue("w"));\r
- return new Quaternion(x,y,z,w);\r
- }else if (attribs.getValue("qx") != null){\r
- // defined as quaternion with prefix "q"\r
- float x = parseFloat(attribs.getValue("qx"));\r
- float y = parseFloat(attribs.getValue("qy"));\r
- float z = parseFloat(attribs.getValue("qz"));\r
- float w = parseFloat(attribs.getValue("qw"));\r
- return new Quaternion(x,y,z,w);\r
- }else if (attribs.getValue("angle") != null){\r
- // defined as angle + axis\r
- float angle = parseFloat(attribs.getValue("angle"));\r
- float axisX = parseFloat(attribs.getValue("axisX"));\r
- float axisY = parseFloat(attribs.getValue("axisY"));\r
- float axisZ = parseFloat(attribs.getValue("axisZ"));\r
- Quaternion q = new Quaternion();\r
- q.fromAngleAxis(angle, new Vector3f(axisX, axisY, axisZ));\r
- return q;\r
- }else{\r
- // defines as 3 angles along XYZ axes\r
- float angleX = parseFloat(attribs.getValue("angleX"));\r
- float angleY = parseFloat(attribs.getValue("angleY"));\r
- float angleZ = parseFloat(attribs.getValue("angleZ"));\r
- Quaternion q = new Quaternion();\r
- q.fromAngles(angleX, angleY, angleZ);\r
- return q;\r
- }\r
- }\r
-\r
- private void parseLightNormal(Attributes attribs) throws SAXException {\r
- checkTopNode("light");\r
- \r
- // SpotLight will be supporting a direction-normal, too.\r
- if (light instanceof DirectionalLight)\r
- ((DirectionalLight) light).setDirection(parseVector3(attribs));\r
- else if (light instanceof SpotLight){\r
- ((SpotLight) light).setDirection(parseVector3(attribs));\r
- }\r
- }\r
-\r
- private void parseLightAttenuation(Attributes attribs) throws SAXException {\r
- // NOTE: Derives range based on "linear" if it is used solely\r
- // for the attenuation. Otherwise derives it from "range"\r
- checkTopNode("light");\r
-\r
- if (light instanceof PointLight || light instanceof SpotLight){\r
- float range = parseFloat(attribs.getValue("range"));\r
- float constant = parseFloat(attribs.getValue("constant"));\r
- float linear = parseFloat(attribs.getValue("linear"));\r
-\r
- String quadraticStr = attribs.getValue("quadratic");\r
- if (quadraticStr == null)\r
- quadraticStr = attribs.getValue("quadric");\r
-\r
- float quadratic = parseFloat(quadraticStr);\r
- \r
- if (constant == 1 && quadratic == 0 && linear > 0){\r
- range = 1f / linear;\r
- }\r
- \r
- if (light instanceof PointLight){\r
- ((PointLight) light).setRadius(range);\r
- }else{\r
- ((SpotLight)light).setSpotRange(range);\r
- }\r
- }\r
- }\r
-\r
- private void parseLightSpotLightRange(Attributes attribs) throws SAXException{\r
- checkTopNode("light");\r
- \r
- float outer = SAXUtil.parseFloat(attribs.getValue("outer"));\r
- float inner = SAXUtil.parseFloat(attribs.getValue("inner"));\r
- \r
- if (!(light instanceof SpotLight)){\r
- throw new SAXException("dotScene parse error: spotLightRange "\r
- + "can only appear under 'spot' light elements");\r
- }\r
- \r
- SpotLight sl = (SpotLight) light;\r
- sl.setSpotInnerAngle(inner * 0.5f);\r
- sl.setSpotOuterAngle(outer * 0.5f);\r
- }\r
- \r
- private void parseLight(Attributes attribs) throws SAXException {\r
- if (node == null || node.getParent() == null)\r
- throw new SAXException("dotScene parse error: light can only appear under a node");\r
- \r
- checkTopNode("node");\r
- \r
- String lightType = parseString(attribs.getValue("type"), "point");\r
- if(lightType.equals("point")) {\r
- light = new PointLight();\r
- } else if(lightType.equals("directional") || lightType.equals("sun")) {\r
- light = new DirectionalLight();\r
- // Assuming "normal" property is not provided\r
- ((DirectionalLight)light).setDirection(Vector3f.UNIT_Z);\r
- } else if(lightType.equals("spotLight") || lightType.equals("spot")) {\r
- light = new SpotLight();\r
- } else {\r
- logger.log(Level.WARNING, "No matching jME3 LightType found for OGRE LightType: {0}", lightType);\r
- }\r
- logger.log(Level.FINEST, "{0} created.", light);\r
-\r
- if (!parseBool(attribs.getValue("visible"), true)){\r
- // set to disabled\r
- }\r
-\r
- // "attach" it to the parent of this node\r
- if (light != null)\r
- node.getParent().addLight(light);\r
- }\r
-\r
- @Override\r
- public void startElement(String uri, String localName, String qName, Attributes attribs) throws SAXException{\r
- if (qName.equals("scene")){\r
- if (elementStack.size() != 0){\r
- throw new SAXException("dotScene parse error: 'scene' element must be the root XML element");\r
- }\r
- \r
- String version = attribs.getValue("formatVersion");\r
- if (version == null && !version.equals("1.0.0") && !version.equals("1.0.1"))\r
- logger.log(Level.WARNING, "Unrecognized version number"\r
- + " in dotScene file: {0}", version);\r
- \r
- }else if (qName.equals("nodes")){\r
- if (root != null){\r
- throw new SAXException("dotScene parse error: nodes element was specified twice");\r
- }\r
- if (sceneName == null)\r
- root = new Node("OgreDotScene"+(++sceneIdx));\r
- else\r
- root = new Node(sceneName+"-scene_node");\r
- \r
- node = root;\r
- }else if (qName.equals("externals")){\r
- checkTopNode("scene");\r
- // Not loaded currently\r
- }else if (qName.equals("item")){\r
- checkTopNode("externals");\r
- }else if (qName.equals("file")){\r
- checkTopNode("item");\r
- \r
- // XXX: Currently material file name is based\r
- // on the scene's filename. THIS IS NOT CORRECT.\r
- // To solve, port SceneLoader to use DOM instead of SAX\r
- \r
- //String matFile = folderName+attribs.getValue("name");\r
- //try {\r
- // materialList = (MaterialList) assetManager.loadAsset(new OgreMaterialKey(matFile));\r
- //} catch (AssetNotFoundException ex){\r
- // materialList = null;\r
- // logger.log(Level.WARNING, "Cannot locate material file: {0}", matFile);\r
- //}\r
- }else if (qName.equals("node")){\r
- String curElement = elementStack.peek();\r
- if (!curElement.equals("node") && !curElement.equals("nodes")){\r
- throw new SAXException("dotScene parse error: "\r
- + "node element can only appear under 'node' or 'nodes'");\r
- }\r
- \r
- String name = attribs.getValue("name");\r
- if (name == null)\r
- name = "OgreNode-" + (++nodeIdx);\r
-\r
- Node newNode = new Node(name);\r
- if (node != null){\r
- node.attachChild(newNode);\r
- }\r
- node = newNode;\r
- }else if (qName.equals("property")){\r
- if (node != null){\r
- String type = attribs.getValue("type");\r
- String name = attribs.getValue("name");\r
- String data = attribs.getValue("data");\r
- if (type.equals("BOOL")){\r
- node.setUserData(name, Boolean.parseBoolean(data)||data.equals("1"));\r
- }else if (type.equals("FLOAT")){\r
- node.setUserData(name, Float.parseFloat(data));\r
- }else if (type.equals("STRING")){\r
- node.setUserData(name, data);\r
- }else if (type.equals("INT")){\r
- node.setUserData(name, Integer.parseInt(data));\r
- }\r
- }\r
- }else if (qName.equals("entity")){\r
- checkTopNode("node");\r
- \r
- String name = attribs.getValue("name");\r
- if (name == null)\r
- name = "OgreEntity-" + (++nodeIdx);\r
- else\r
- name += "-entity";\r
-\r
- String meshFile = attribs.getValue("meshFile");\r
- if (meshFile == null) {\r
- throw new SAXException("Required attribute 'meshFile' missing for 'entity' node");\r
- }\r
-\r
- // TODO: Not currently used\r
- String materialName = attribs.getValue("materialName");\r
-\r
- if (folderName != null) {\r
- meshFile = folderName + meshFile;\r
- }\r
- \r
- // NOTE: append "xml" since its assumed mesh files are binary in dotScene\r
- meshFile += ".xml";\r
- \r
- entityNode = new Node(name);\r
- OgreMeshKey key = new OgreMeshKey(meshFile, materialList);\r
- Spatial ogreMesh = assetManager.loadModel(key);\r
- \r
- entityNode.attachChild(ogreMesh);\r
- node.attachChild(entityNode);\r
- node = null;\r
- }else if (qName.equals("position")){\r
- if (elementStack.peek().equals("node")){\r
- node.setLocalTranslation(SAXUtil.parseVector3(attribs));\r
- }\r
- }else if (qName.equals("quaternion") || qName.equals("rotation")){\r
- node.setLocalRotation(parseQuat(attribs));\r
- }else if (qName.equals("scale")){\r
- node.setLocalScale(SAXUtil.parseVector3(attribs));\r
- } else if (qName.equals("light")) {\r
- parseLight(attribs);\r
- } else if (qName.equals("colourDiffuse") || qName.equals("colorDiffuse")) {\r
- if (elementStack.peek().equals("light")){\r
- if (light != null){\r
- light.setColor(parseColor(attribs));\r
- }\r
- }else{\r
- checkTopNode("environment");\r
- }\r
- } else if (qName.equals("normal") || qName.equals("direction")) {\r
- checkTopNode("light");\r
- parseLightNormal(attribs);\r
- } else if (qName.equals("lightAttenuation")) {\r
- parseLightAttenuation(attribs);\r
- } else if (qName.equals("spotLightRange") || qName.equals("lightRange")) {\r
- parseLightSpotLightRange(attribs);\r
- }\r
-\r
- elementStack.push(qName);\r
- }\r
-\r
- @Override\r
- public void endElement(String uri, String name, String qName) throws SAXException {\r
- if (qName.equals("node")){\r
- node = node.getParent();\r
- }else if (qName.equals("nodes")){\r
- node = null;\r
- }else if (qName.equals("entity")){\r
- node = entityNode.getParent();\r
- entityNode = null;\r
- }else if (qName.equals("light")){\r
- // apply the node's world transform on the light..\r
- root.updateGeometricState();\r
- if (light != null){\r
- if (light instanceof DirectionalLight){\r
- DirectionalLight dl = (DirectionalLight) light;\r
- Quaternion q = node.getWorldRotation();\r
- Vector3f dir = dl.getDirection();\r
- q.multLocal(dir);\r
- dl.setDirection(dir);\r
- }else if (light instanceof PointLight){\r
- PointLight pl = (PointLight) light;\r
- Vector3f pos = node.getWorldTranslation();\r
- pl.setPosition(pos);\r
- }else if (light instanceof SpotLight){\r
- SpotLight sl = (SpotLight) light;\r
- \r
- Vector3f pos = node.getWorldTranslation();\r
- sl.setPosition(pos);\r
- \r
- Quaternion q = node.getWorldRotation();\r
- Vector3f dir = sl.getDirection();\r
- q.multLocal(dir);\r
- sl.setDirection(dir);\r
- }\r
- }\r
- light = null;\r
- }\r
- checkTopNode(qName);\r
- elementStack.pop();\r
- }\r
-\r
- @Override\r
- public void characters(char ch[], int start, int length) {\r
- }\r
-\r
- public Object load(AssetInfo info) throws IOException {\r
- try{\r
- assetManager = info.getManager();\r
- sceneName = info.getKey().getName();\r
- String ext = info.getKey().getExtension();\r
- folderName = info.getKey().getFolder();\r
- sceneName = sceneName.substring(0, sceneName.length() - ext.length() - 1);\r
-\r
- try {\r
- materialList = (MaterialList) \r
- assetManager.loadAsset(new OgreMaterialKey(sceneName+".material"));\r
- } catch (AssetNotFoundException ex){\r
- logger.log(Level.WARNING, "Cannot locate material file {0}", ex.getMessage());\r
- materialList = null;\r
- }\r
-\r
- reset();\r
- \r
- // Added by larynx 25.06.2011\r
- // Android needs the namespace aware flag set to true \r
- // Kirill 30.06.2011\r
- // Now, hack is applied for both desktop and android to avoid\r
- // checking with JmeSystem.\r
- SAXParserFactory factory = SAXParserFactory.newInstance();\r
- factory.setNamespaceAware(true);\r
- XMLReader xr = factory.newSAXParser().getXMLReader(); \r
- \r
- xr.setContentHandler(this);\r
- xr.setErrorHandler(this);\r
- \r
- InputStreamReader r = null;\r
- \r
- try {\r
- r = new InputStreamReader(info.openStream());\r
- xr.parse(new InputSource(r));\r
- } finally {\r
- if (r != null){\r
- r.close();\r
- }\r
- }\r
- \r
- return root;\r
- }catch (SAXException ex){\r
- IOException ioEx = new IOException("Error while parsing Ogre3D dotScene");\r
- ioEx.initCause(ex);\r
- throw ioEx;\r
- } catch (ParserConfigurationException ex) {\r
- IOException ioEx = new IOException("Error while parsing Ogre3D dotScene");\r
- ioEx.initCause(ex);\r
- throw ioEx;\r
- }\r
- }\r
-\r
-}\r
+/*
+ * Copyright (c) 2009-2012 jMonkeyEngine
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package com.jme3.scene.plugins.ogre;
+
+import com.jme3.asset.*;
+import com.jme3.light.AmbientLight;
+import com.jme3.light.DirectionalLight;
+import com.jme3.light.Light;
+import com.jme3.light.PointLight;
+import com.jme3.light.SpotLight;
+import com.jme3.material.MaterialList;
+import com.jme3.math.ColorRGBA;
+import com.jme3.math.FastMath;
+import com.jme3.math.Quaternion;
+import com.jme3.math.Vector3f;
+import com.jme3.renderer.Camera;
+import com.jme3.scene.CameraNode;
+import com.jme3.scene.LightNode;
+import com.jme3.scene.Spatial;
+import com.jme3.scene.control.CameraControl.ControlDirection;
+import com.jme3.scene.plugins.ogre.matext.OgreMaterialKey;
+import com.jme3.util.PlaceholderAssets;
+import com.jme3.util.xml.SAXUtil;
+import static com.jme3.util.xml.SAXUtil.*;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.util.Stack;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.parsers.SAXParserFactory;
+import org.xml.sax.Attributes;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+import org.xml.sax.XMLReader;
+import org.xml.sax.helpers.DefaultHandler;
+
+public class SceneLoader extends DefaultHandler implements AssetLoader {
+
+ private static final int DEFAULT_CAM_WIDTH = 640;
+ private static final int DEFAULT_CAM_HEIGHT = 480;
+
+ private static final Logger logger = Logger.getLogger(SceneLoader.class.getName());
+ private SceneMaterialLoader materialLoader = new SceneMaterialLoader();
+ private Stack<String> elementStack = new Stack<String>();
+ private AssetKey key;
+ private String sceneName;
+ private String folderName;
+ private AssetManager assetManager;
+ private MaterialList materialList;
+ private com.jme3.scene.Node root;
+ private com.jme3.scene.Node node;
+ private com.jme3.scene.Node entityNode;
+ private Light light;
+ private Camera camera;
+ private CameraNode cameraNode;
+ private int nodeIdx = 0;
+ private static volatile int sceneIdx = 0;
+
+ public SceneLoader() {
+ super();
+ }
+
+ @Override
+ public void startDocument() {
+ }
+
+ @Override
+ public void endDocument() {
+ }
+
+ private void reset() {
+ elementStack.clear();
+ nodeIdx = 0;
+
+ // NOTE: Setting some of those to null is only needed
+ // if the parsed file had an error e.g. startElement was called
+ // but not endElement
+ root = null;
+ node = null;
+ entityNode = null;
+ light = null;
+ camera = null;
+ cameraNode = null;
+ }
+
+ private void checkTopNode(String topNode) throws SAXException {
+ if (!elementStack.peek().equals(topNode)) {
+ throw new SAXException("dotScene parse error: Expected parent node to be " + topNode);
+ }
+ }
+
+ private Quaternion parseQuat(Attributes attribs) throws SAXException {
+ if (attribs.getValue("x") != null) {
+ // defined as quaternion
+ float x = parseFloat(attribs.getValue("x"));
+ float y = parseFloat(attribs.getValue("y"));
+ float z = parseFloat(attribs.getValue("z"));
+ float w = parseFloat(attribs.getValue("w"));
+ return new Quaternion(x, y, z, w);
+ } else if (attribs.getValue("qx") != null) {
+ // defined as quaternion with prefix "q"
+ float x = parseFloat(attribs.getValue("qx"));
+ float y = parseFloat(attribs.getValue("qy"));
+ float z = parseFloat(attribs.getValue("qz"));
+ float w = parseFloat(attribs.getValue("qw"));
+ return new Quaternion(x, y, z, w);
+ } else if (attribs.getValue("angle") != null) {
+ // defined as angle + axis
+ float angle = parseFloat(attribs.getValue("angle"));
+ float axisX = parseFloat(attribs.getValue("axisX"));
+ float axisY = parseFloat(attribs.getValue("axisY"));
+ float axisZ = parseFloat(attribs.getValue("axisZ"));
+ Quaternion q = new Quaternion();
+ q.fromAngleAxis(angle, new Vector3f(axisX, axisY, axisZ));
+ return q;
+ } else {
+ // defines as 3 angles along XYZ axes
+ float angleX = parseFloat(attribs.getValue("angleX"));
+ float angleY = parseFloat(attribs.getValue("angleY"));
+ float angleZ = parseFloat(attribs.getValue("angleZ"));
+ Quaternion q = new Quaternion();
+ q.fromAngles(angleX, angleY, angleZ);
+ return q;
+ }
+ }
+
+ private void parseLightNormal(Attributes attribs) throws SAXException {
+ checkTopNode("light");
+
+ // SpotLight will be supporting a direction-normal, too.
+ if (light instanceof DirectionalLight) {
+ ((DirectionalLight) light).setDirection(parseVector3(attribs));
+ } else if (light instanceof SpotLight) {
+ ((SpotLight) light).setDirection(parseVector3(attribs));
+ }
+ }
+
+ private void parseLightAttenuation(Attributes attribs) throws SAXException {
+ // NOTE: Derives range based on "linear" if it is used solely
+ // for the attenuation. Otherwise derives it from "range"
+ checkTopNode("light");
+
+ if (light instanceof PointLight || light instanceof SpotLight) {
+ float range = parseFloat(attribs.getValue("range"));
+ float constant = parseFloat(attribs.getValue("constant"));
+ float linear = parseFloat(attribs.getValue("linear"));
+
+ String quadraticStr = attribs.getValue("quadratic");
+ if (quadraticStr == null) {
+ quadraticStr = attribs.getValue("quadric");
+ }
+
+ float quadratic = parseFloat(quadraticStr);
+
+ if (constant == 1 && quadratic == 0 && linear > 0) {
+ range = 1f / linear;
+ }
+
+ if (light instanceof PointLight) {
+ ((PointLight) light).setRadius(range);
+ } else {
+ ((SpotLight) light).setSpotRange(range);
+ }
+ }
+ }
+
+ private void parseLightSpotLightRange(Attributes attribs) throws SAXException {
+ checkTopNode("light");
+
+ float outer = SAXUtil.parseFloat(attribs.getValue("outer"));
+ float inner = SAXUtil.parseFloat(attribs.getValue("inner"));
+
+ if (!(light instanceof SpotLight)) {
+ throw new SAXException("dotScene parse error: spotLightRange "
+ + "can only appear under 'spot' light elements");
+ }
+
+ SpotLight sl = (SpotLight) light;
+ sl.setSpotInnerAngle(inner * 0.5f);
+ sl.setSpotOuterAngle(outer * 0.5f);
+ }
+
+ private void parseLight(Attributes attribs) throws SAXException {
+ if (node == null || node.getParent() == null) {
+ throw new SAXException("dotScene parse error: light can only appear under a node");
+ }
+
+ checkTopNode("node");
+
+ String lightType = parseString(attribs.getValue("type"), "point");
+ if (lightType.equals("point")) {
+ light = new PointLight();
+ } else if (lightType.equals("directional") || lightType.equals("sun")) {
+ light = new DirectionalLight();
+ // Assuming "normal" property is not provided
+ ((DirectionalLight) light).setDirection(Vector3f.UNIT_Z);
+ } else if (lightType.equals("spotLight") || lightType.equals("spot")) {
+ light = new SpotLight();
+ } else if (lightType.equals("omni")) {
+ // XXX: It doesn't seem any exporters actually emit this type?
+ light = new AmbientLight();
+ } else {
+ logger.log(Level.WARNING, "No matching jME3 LightType found for OGRE LightType: {0}", lightType);
+ }
+ logger.log(Level.FINEST, "{0} created.", light);
+
+ if (!parseBool(attribs.getValue("visible"), true)) {
+ // set to disabled
+ }
+
+ // "attach" it to the parent of this node
+ if (light != null) {
+ node.getParent().addLight(light);
+ }
+ }
+
+ private void parseCameraClipping(Attributes attribs) throws SAXException {
+ if (attribs.getValue("near") != null) {
+ camera.setFrustumNear(SAXUtil.parseFloat(attribs.getValue("near")));
+ camera.setFrustumFar(SAXUtil.parseFloat(attribs.getValue("far")));
+ } else {
+ camera.setFrustumNear(SAXUtil.parseFloat(attribs.getValue("nearPlaneDist")));
+ camera.setFrustumFar(SAXUtil.parseFloat(attribs.getValue("farPlaneDist")));
+ }
+ }
+
+ private void parseCamera(Attributes attribs) throws SAXException {
+ camera = new Camera(DEFAULT_CAM_WIDTH, DEFAULT_CAM_HEIGHT);
+ if (SAXUtil.parseString(attribs.getValue("projectionType"), "perspective").equals("parallel")){
+ camera.setParallelProjection(true);
+ }
+ float fov = SAXUtil.parseFloat(attribs.getValue("fov"), 45f);
+ if (fov < FastMath.PI) {
+ // XXX: Most likely, it is in radians..
+ fov = fov * FastMath.RAD_TO_DEG;
+ }
+ camera.setFrustumPerspective(fov, (float)DEFAULT_CAM_WIDTH / DEFAULT_CAM_HEIGHT, 1, 1000);
+
+ cameraNode = new CameraNode(attribs.getValue("name"), camera);
+ cameraNode.setControlDir(ControlDirection.SpatialToCamera);
+
+ node.attachChild(cameraNode);
+ node = null;
+ }
+
+ private void parseEntity(Attributes attribs) throws SAXException {
+ String name = attribs.getValue("name");
+ if (name == null) {
+ name = "OgreEntity-" + (++nodeIdx);
+ } else {
+ name += "-entity";
+ }
+
+ String meshFile = attribs.getValue("meshFile");
+ if (meshFile == null) {
+ throw new SAXException("Required attribute 'meshFile' missing for 'entity' node");
+ }
+
+ // TODO: Not currently used
+ String materialName = attribs.getValue("materialName");
+
+ if (folderName != null) {
+ meshFile = folderName + meshFile;
+ }
+
+ // NOTE: append "xml" since its assumed mesh files are binary in dotScene
+ meshFile += ".xml";
+
+ entityNode = new com.jme3.scene.Node(name);
+ OgreMeshKey meshKey = new OgreMeshKey(meshFile, materialList);
+ try {
+ Spatial ogreMesh = assetManager.loadModel(meshKey);
+ entityNode.attachChild(ogreMesh);
+ } catch (AssetNotFoundException ex) {
+ if (ex.getMessage().equals(meshFile)) {
+ logger.log(Level.WARNING, "Cannot locate {0} for scene {1}", new Object[]{meshKey, key});
+ // Attach placeholder asset.
+ Spatial model = PlaceholderAssets.getPlaceholderModel(assetManager);
+ model.setKey(key);
+ entityNode.attachChild(model);
+ } else {
+ throw ex;
+ }
+ }
+
+ node.attachChild(entityNode);
+ node = null;
+ }
+
+ private void parseNode(Attributes attribs) throws SAXException {
+ String name = attribs.getValue("name");
+ if (name == null) {
+ name = "OgreNode-" + (++nodeIdx);
+ }
+
+ com.jme3.scene.Node newNode = new com.jme3.scene.Node(name);
+ if (node != null) {
+ node.attachChild(newNode);
+ }
+ node = newNode;
+ }
+
+ @Override
+ public void startElement(String uri, String localName, String qName, Attributes attribs) throws SAXException {
+ if (qName.equals("scene")) {
+ if (elementStack.size() != 0) {
+ throw new SAXException("dotScene parse error: 'scene' element must be the root XML element");
+ }
+
+ String version = attribs.getValue("formatVersion");
+ if (version == null || (!version.equals("1.0.0") && !version.equals("1.0.1"))) {
+ logger.log(Level.WARNING, "Unrecognized version number"
+ + " in dotScene file: {0}", version);
+ }
+ } else if (qName.equals("nodes")) {
+ if (root != null) {
+ throw new SAXException("dotScene parse error: nodes element was specified twice");
+ }
+ if (sceneName == null) {
+ root = new com.jme3.scene.Node("OgreDotScene" + (++sceneIdx));
+ } else {
+ root = new com.jme3.scene.Node(sceneName + "-scene_node");
+ }
+
+ node = root;
+ } else if (qName.equals("externals")) {
+ checkTopNode("scene");
+ } else if (qName.equals("item")) {
+ checkTopNode("externals");
+ } else if (qName.equals("file")) {
+ checkTopNode("item");
+
+ // NOTE: This part of the file is ignored, it is parsed
+ // by SceneMaterialLoader in the first pass.
+ } else if (qName.equals("node")) {
+ String curElement = elementStack.peek();
+ if (!curElement.equals("node") && !curElement.equals("nodes")) {
+ throw new SAXException("dotScene parse error: "
+ + "node element can only appear under 'node' or 'nodes'");
+ }
+
+ parseNode(attribs);
+ } else if (qName.equals("property")) {
+ if (node != null) {
+ String type = attribs.getValue("type");
+ String name = attribs.getValue("name");
+ String data = attribs.getValue("data");
+ if (type.equals("BOOL")) {
+ node.setUserData(name, Boolean.parseBoolean(data) || data.equals("1"));
+ } else if (type.equals("FLOAT")) {
+ node.setUserData(name, Float.parseFloat(data));
+ } else if (type.equals("STRING")) {
+ node.setUserData(name, data);
+ } else if (type.equals("INT")) {
+ node.setUserData(name, Integer.parseInt(data));
+ }
+ }
+ } else if (qName.equals("entity")) {
+ checkTopNode("node");
+ parseEntity(attribs);
+ } else if (qName.equals("camera")) {
+ checkTopNode("node");
+ parseCamera(attribs);
+ } else if (qName.equals("clipping")) {
+ checkTopNode("camera");
+ parseCameraClipping(attribs);
+ } else if (qName.equals("position")) {
+ if (elementStack.peek().equals("node")) {
+ node.setLocalTranslation(SAXUtil.parseVector3(attribs));
+ } else if (elementStack.peek().equals("camera")) {
+ cameraNode.setLocalTranslation(SAXUtil.parseVector3(attribs));
+ }
+ } else if (qName.equals("quaternion") || qName.equals("rotation")) {
+ node.setLocalRotation(parseQuat(attribs));
+ } else if (qName.equals("scale")) {
+ node.setLocalScale(SAXUtil.parseVector3(attribs));
+ } else if (qName.equals("light")) {
+ parseLight(attribs);
+ } else if (qName.equals("colourDiffuse") || qName.equals("colorDiffuse")) {
+ if (elementStack.peek().equals("light")) {
+ if (light != null) {
+ light.setColor(parseColor(attribs));
+ }
+ } else {
+ checkTopNode("environment");
+ }
+ } else if (qName.equals("colourAmbient") || qName.equals("colorAmbient")) {
+ if (elementStack.peek().equals("environment")) {
+ ColorRGBA color = parseColor(attribs);
+ if (!color.equals(ColorRGBA.Black) && !color.equals(ColorRGBA.BlackNoAlpha)) {
+ // Lets add an ambient light to the scene.
+ AmbientLight al = new AmbientLight();
+ al.setColor(color);
+ root.addLight(al);
+ }
+ }
+ } else if (qName.equals("normal") || qName.equals("direction")) {
+ checkTopNode("light");
+ parseLightNormal(attribs);
+ } else if (qName.equals("lightAttenuation")) {
+ parseLightAttenuation(attribs);
+ } else if (qName.equals("spotLightRange") || qName.equals("lightRange")) {
+ parseLightSpotLightRange(attribs);
+ }
+
+ elementStack.push(qName);
+ }
+
+ @Override
+ public void endElement(String uri, String name, String qName) throws SAXException {
+ if (qName.equals("node")) {
+ node = node.getParent();
+ } else if (qName.equals("nodes")) {
+ node = null;
+ } else if (qName.equals("entity")) {
+ node = entityNode.getParent();
+ entityNode = null;
+ } else if (qName.equals("camera")) {
+ node = cameraNode.getParent();
+ cameraNode = null;
+ } else if (qName.equals("light")) {
+ // apply the node's world transform on the light..
+ root.updateGeometricState();
+ if (light != null) {
+ if (light instanceof DirectionalLight) {
+ DirectionalLight dl = (DirectionalLight) light;
+ Quaternion q = node.getWorldRotation();
+ Vector3f dir = dl.getDirection();
+ q.multLocal(dir);
+ dl.setDirection(dir);
+ } else if (light instanceof PointLight) {
+ PointLight pl = (PointLight) light;
+ Vector3f pos = node.getWorldTranslation();
+ pl.setPosition(pos);
+ } else if (light instanceof SpotLight) {
+ SpotLight sl = (SpotLight) light;
+
+ Vector3f pos = node.getWorldTranslation();
+ sl.setPosition(pos);
+
+ Quaternion q = node.getWorldRotation();
+ Vector3f dir = sl.getDirection();
+ q.multLocal(dir);
+ sl.setDirection(dir);
+ }
+ }
+ light = null;
+ }
+ checkTopNode(qName);
+ elementStack.pop();
+ }
+
+ @Override
+ public void characters(char ch[], int start, int length) {
+ }
+
+ public Object load(AssetInfo info) throws IOException {
+ try {
+ key = info.getKey();
+ assetManager = info.getManager();
+ sceneName = key.getName();
+ String ext = key.getExtension();
+ folderName = key.getFolder();
+ sceneName = sceneName.substring(0, sceneName.length() - ext.length() - 1);
+
+ reset();
+
+ // == Run 1st pass over XML file to determine material list ==
+ materialList = materialLoader.load(assetManager, folderName, info.openStream());
+
+ if (materialList == null || materialList.isEmpty()) {
+ // NOTE: No materials were found by searching the externals section.
+ // Try finding a similarly named material file in the same folder.
+ // (Backward compatibility only!)
+ OgreMaterialKey materialKey = new OgreMaterialKey(sceneName + ".material");
+ try {
+ materialList = (MaterialList) assetManager.loadAsset(materialKey);
+ } catch (AssetNotFoundException ex) {
+ logger.log(Level.WARNING, "Cannot locate {0} for scene {1}", new Object[]{materialKey, key});
+ materialList = null;
+ }
+ }
+
+ // == Run 2nd pass to load entities and other objects ==
+
+ // Added by larynx 25.06.2011
+ // Android needs the namespace aware flag set to true
+ // Kirill 30.06.2011
+ // Now, hack is applied for both desktop and android to avoid
+ // checking with JmeSystem.
+ SAXParserFactory factory = SAXParserFactory.newInstance();
+ factory.setNamespaceAware(true);
+ XMLReader xr = factory.newSAXParser().getXMLReader();
+
+ xr.setContentHandler(this);
+ xr.setErrorHandler(this);
+
+ InputStreamReader r = null;
+
+ try {
+ r = new InputStreamReader(info.openStream());
+ xr.parse(new InputSource(r));
+ } finally {
+ if (r != null) {
+ r.close();
+ }
+ }
+
+ return root;
+ } catch (SAXException ex) {
+ IOException ioEx = new IOException("Error while parsing Ogre3D dotScene");
+ ioEx.initCause(ex);
+ throw ioEx;
+ } catch (ParserConfigurationException ex) {
+ IOException ioEx = new IOException("Error while parsing Ogre3D dotScene");
+ ioEx.initCause(ex);
+ throw ioEx;
+ }
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2009-2012 jMonkeyEngine
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package com.jme3.scene.plugins.ogre;
+
+import com.jme3.asset.AssetManager;
+import com.jme3.asset.AssetNotFoundException;
+import com.jme3.material.MaterialList;
+import com.jme3.scene.plugins.ogre.matext.OgreMaterialKey;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.util.Stack;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.parsers.SAXParserFactory;
+import org.xml.sax.Attributes;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+import org.xml.sax.XMLReader;
+import org.xml.sax.helpers.DefaultHandler;
+
+/**
+ * This is a utility class to load a {@link MaterialList} from a
+ * .scene file. It is only needed because the parsing method
+ * used by the SceneLoader doesn't support reading bottom XML nodes
+ * before reading the top nodes.
+ *
+ * @author Kirill Vainer
+ */
+class SceneMaterialLoader extends DefaultHandler {
+
+ private static final Logger logger = Logger.getLogger(SceneMaterialLoader.class.getName());
+ private Stack<String> elementStack = new Stack<String>();
+ private String folderName;
+ private MaterialList materialList;
+ private AssetManager assetManager;
+ private boolean ignoreItem = false;
+
+ private void reset(){
+ elementStack.clear();
+ materialList = null;
+ ignoreItem = false;
+ }
+
+ private void checkTopNode(String topNode) throws SAXException{
+ if (!elementStack.peek().equals(topNode)){
+ throw new SAXException("dotScene parse error: Expected parent node to be " + topNode);
+ }
+ }
+
+ @Override
+ public void startElement(String uri, String localName, String qName, Attributes attribs) throws SAXException {
+ if (qName.equals("externals")) {
+ checkTopNode("scene");
+
+ // Has an externals block, create material list.
+ materialList = new MaterialList();
+ } else if (qName.equals("item")) {
+ checkTopNode("externals");
+ if (!attribs.getValue("type").equals("material")) {
+ // This is not a material external. Ignore it.
+ ignoreItem = true;
+ }
+ } else if (qName.equals("file")) {
+ checkTopNode("item");
+
+ if (!ignoreItem) {
+ String materialPath = attribs.getValue("name");
+ String materialName = new File(materialPath).getName();
+ String matFile = folderName + materialName;
+ try {
+ MaterialList loadedMaterialList = (MaterialList) assetManager.loadAsset(new OgreMaterialKey(matFile));
+ materialList.putAll(loadedMaterialList);
+ } catch (AssetNotFoundException ex) {
+ logger.log(Level.WARNING, "Cannot locate material file: {0}", matFile);
+ }
+ }
+ }
+ elementStack.push(qName);
+ }
+
+ @Override
+ public void endElement(String uri, String name, String qName) throws SAXException {
+ if (qName.equals("item") && ignoreItem) {
+ ignoreItem = false;
+ }
+ checkTopNode(qName);
+ elementStack.pop();
+ }
+
+ public MaterialList load(AssetManager assetManager, String folderName, InputStream in) throws IOException {
+ try {
+ this.assetManager = assetManager;
+ this.folderName = folderName;
+
+ reset();
+
+ SAXParserFactory factory = SAXParserFactory.newInstance();
+ factory.setNamespaceAware(true);
+ XMLReader xr = factory.newSAXParser().getXMLReader();
+
+ xr.setContentHandler(this);
+ xr.setErrorHandler(this);
+
+ InputStreamReader r = null;
+
+ try {
+ r = new InputStreamReader(in);
+ xr.parse(new InputSource(r));
+ } finally {
+ if (r != null){
+ r.close();
+ }
+ }
+
+ return materialList;
+ } catch (SAXException ex) {
+ IOException ioEx = new IOException("Error while parsing Ogre3D dotScene");
+ ioEx.initCause(ex);
+ throw ioEx;
+ } catch (ParserConfigurationException ex) {
+ IOException ioEx = new IOException("Error while parsing Ogre3D dotScene");
+ ioEx.initCause(ex);
+ throw ioEx;
+ }
+ }
+}
/*
- * Copyright (c) 2009-2010 jMonkeyEngine
+ * Copyright (c) 2009-2012 jMonkeyEngine
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
*/
package com.jme3.scene.plugins.ogre;
+import com.jme3.animation.Animation;
+import com.jme3.animation.Bone;
+import com.jme3.animation.BoneTrack;
+import com.jme3.animation.Skeleton;
+import com.jme3.asset.AssetInfo;
+import com.jme3.asset.AssetLoader;
+import com.jme3.asset.AssetManager;
+import com.jme3.math.Quaternion;
+import com.jme3.math.Vector3f;
+import com.jme3.util.xml.SAXUtil;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.Map;
import java.util.Stack;
import java.util.logging.Logger;
-
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParserFactory;
-
import org.xml.sax.Attributes;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.DefaultHandler;
-import com.jme3.animation.Animation;
-import com.jme3.animation.Bone;
-import com.jme3.animation.BoneTrack;
-import com.jme3.animation.Skeleton;
-import com.jme3.asset.AssetInfo;
-import com.jme3.asset.AssetLoader;
-import com.jme3.asset.AssetManager;
-import com.jme3.math.Quaternion;
-import com.jme3.math.Vector3f;
-import com.jme3.util.xml.SAXUtil;
-
public class SkeletonLoader extends DefaultHandler implements AssetLoader {
private static final Logger logger = Logger.getLogger(SceneLoader.class.getName());
/*
- * Copyright (c) 2009-2010 jMonkeyEngine
+ * Copyright (c) 2009-2012 jMonkeyEngine
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-
package com.jme3.scene.plugins.ogre.matext;
import java.util.HashMap;
/*
- * Copyright (c) 2009-2010 jMonkeyEngine
+ * Copyright (c) 2009-2012 jMonkeyEngine
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-
package com.jme3.scene.plugins.ogre.matext;
+import com.jme3.asset.AssetKey;
import com.jme3.asset.AssetManager;
+import com.jme3.asset.AssetNotFoundException;
import com.jme3.asset.TextureKey;
import com.jme3.material.Material;
import com.jme3.material.MaterialList;
import com.jme3.scene.plugins.ogre.MaterialLoader;
import com.jme3.texture.Texture;
import com.jme3.texture.Texture.WrapMode;
+import com.jme3.texture.Texture2D;
+import com.jme3.util.PlaceholderAssets;
import com.jme3.util.blockparser.Statement;
import java.io.IOException;
import java.util.List;
-import java.util.Scanner;
import java.util.logging.Level;
import java.util.logging.Logger;
private static final Logger logger = Logger.getLogger(MaterialExtensionLoader.class.getName());
+ private AssetKey key;
private AssetManager assetManager;
private MaterialList list;
private MaterialExtensionSet matExts;
private String matName;
private Material material;
+
private void readExtendingMaterialStatement(Statement statement) throws IOException {
if (statement.getLine().startsWith("set_texture_alias")){
String[] split = statement.getLine().split(" ", 3);
String jmeParamName = matExt.getTextureMapping(aliasName);
- TextureKey key = new TextureKey(texturePath, false);
- key.setGenerateMips(true);
- key.setAsCube(false);
- Texture tex = assetManager.loadTexture(key);
- if (tex == null)
- throw new IOException("Cannot load texture: " + texturePath);
- tex.setWrap(WrapMode.Repeat);
-
+ TextureKey texKey = new TextureKey(texturePath, false);
+ texKey.setGenerateMips(true);
+ texKey.setAsCube(false);
+ Texture tex;
+
+ try {
+ tex = assetManager.loadTexture(texKey);
+ tex.setWrap(WrapMode.Repeat);
+ } catch (AssetNotFoundException ex){
+ logger.log(Level.WARNING, "Cannot locate {0} for material {1}", new Object[]{texKey, key});
+ tex = new Texture2D( PlaceholderAssets.getPlaceholderImage() );
+ tex.setWrap(WrapMode.Repeat);
+ tex.setKey(texKey);
+ }
+
material.setTexture(jmeParamName, tex);
}
}
return material;
}
- public MaterialList load(AssetManager assetManager, MaterialExtensionSet matExts,
+ public MaterialList load(AssetManager assetManager, AssetKey key, MaterialExtensionSet matExts,
List<Statement> statements) throws IOException{
this.assetManager = assetManager;
this.matExts = matExts;
+ this.key = key;
list = new MaterialList();
/*
- * Copyright (c) 2009-2010 jMonkeyEngine
+ * Copyright (c) 2009-2012 jMonkeyEngine
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-
package com.jme3.scene.plugins.ogre.matext;
import java.util.ArrayList;
* {@link OgreMaterialKey}s used.
*/
public class MaterialExtensionSet {
- private HashMap<String, MaterialExtension> extensions
- = new HashMap<String, MaterialExtension>();
+
+ private HashMap<String, MaterialExtension> extensions = new HashMap<String, MaterialExtension>();
private HashMap<String, List<String>> nameMappings = new HashMap<String, List<String>>();
/**
* Adds a new material extension to the set of extensions.
+ *
* @param extension The {@link MaterialExtension} to add.
*/
- public void addMaterialExtension(MaterialExtension extension){
+ public void addMaterialExtension(MaterialExtension extension) {
extensions.put(extension.getBaseMaterialName(), extension);
}
/**
- * Returns the {@link MaterialExtension} for a given Ogre3D base
- * material name.
+ * Returns the {@link MaterialExtension} for a given Ogre3D base material
+ * name.
*
* @param baseMatName The ogre3D base material name.
* @return {@link MaterialExtension} that is set, or null if not set.
*/
- public MaterialExtension getMaterialExtension(String baseMatName){
+ public MaterialExtension getMaterialExtension(String baseMatName) {
return extensions.get(baseMatName);
}
-
+
/**
* Adds an alternative name for a material
+ *
* @param name The material name to be found in a .mesh.xml file
* @param alias The material name to be found in a .material file
*/
- public void setNameMapping(String name, String alias){
+ public void setNameMapping(String name, String alias) {
List<String> list = nameMappings.get(name);
- if(list==null){
+ if (list == null) {
list = new ArrayList<String>();
nameMappings.put(name, list);
}
list.add(alias);
}
-
- public List<String> getNameMappings(String name){
+
+ public List<String> getNameMappings(String name) {
return nameMappings.get(name);
}
}
/*
- * Copyright (c) 2009-2010 jMonkeyEngine
+ * Copyright (c) 2009-2012 jMonkeyEngine
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-
package com.jme3.scene.plugins.ogre.matext;
import com.jme3.asset.AssetKey;
import com.jme3.material.MaterialList;
/**
- * <code>OgreMaterialKey</code> allows specifying material extensions,
- * which map from Ogre3D base materials to jME3 materials
+ * <code>OgreMaterialKey</code> allows specifying material extensions, which map
+ * from Ogre3D base materials to jME3 materials
*/
public class OgreMaterialKey extends AssetKey<MaterialList> {
private MaterialExtensionSet matExts;
- public OgreMaterialKey(String name){
+ public OgreMaterialKey(String name) {
super(name);
}
- public OgreMaterialKey(){
+ public OgreMaterialKey() {
super();
}
+ @Override
+ public boolean equals(Object obj) {
+ if (obj == null) {
+ return false;
+ }
+ if (getClass() != obj.getClass()) {
+ return false;
+ }
+ final OgreMaterialKey other = (OgreMaterialKey) obj;
+ if (!super.equals(other)) {
+ return false;
+ }
+ if (this.matExts != other.matExts && (this.matExts == null || !this.matExts.equals(other.matExts))) {
+ return false;
+ }
+ return true;
+ }
+
+ @Override
+ public int hashCode() {
+ int hash = 5;
+ hash = 71 * hash + (super.hashCode());
+ hash = 71 * hash + (this.matExts != null ? this.matExts.hashCode() : 0);
+ return hash;
+ }
+
/**
- * Set the {@link MaterialExtensionSet} to use for mapping
- * base materials to jME3 matdefs when loading.
- * Set to <code>null</code> to disable this functionality.
+ * Set the {@link MaterialExtensionSet} to use for mapping base materials to
+ * jME3 matdefs when loading. Set to
+ * <code>null</code> to disable this functionality.
*
- * @param extension The {@link MaterialExtensionSet} to use
+ * @param matExts The {@link MaterialExtensionSet} to use
*/
- public void setMaterialExtensionSet(MaterialExtensionSet matExts){
+ public void setMaterialExtensionSet(MaterialExtensionSet matExts) {
this.matExts = matExts;
}
/**
* Returns the {@link MaterialExtensionSet} previously set using
- * {@link OgreMaterialKey#setMaterialExtensionSet(com.jme3.scene.plugins.ogre.matext.MaterialExtensionSet) } method.
- * @return
+ * {@link OgreMaterialKey#setMaterialExtensionSet(com.jme3.scene.plugins.ogre.matext.MaterialExtensionSet)
+ * } method.
+ *
+ * @return the {@link MaterialExtensionSet}
*/
public MaterialExtensionSet getMaterialExtensionSet() {
return matExts;