blob: fc8cc6b837d733130dac9207a05ee747b519b82a [file] [log] [blame]
/*
* Copyright (c) 2009-2010 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.animation.AnimControl;
import com.jme3.animation.Animation;
import com.jme3.animation.SkeletonControl;
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.*;
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.*;
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;
/**
* Loads Ogre3D mesh.xml files.
*/
public class MeshLoader extends DefaultHandler implements AssetLoader {
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.TexCoord2,
Type.TexCoord3,
Type.TexCoord4,
Type.TexCoord5,
Type.TexCoord6,
Type.TexCoord7,
Type.TexCoord8,};
private AssetKey key;
private String meshName;
private String folderName;
private AssetManager assetManager;
private MaterialList materialList;
// Data per submesh/sharedgeom
private ShortBuffer sb;
private IntBuffer ib;
private FloatBuffer fb;
private VertexBuffer vb;
private Mesh mesh;
private Geometry geom;
private ByteBuffer indicesData;
private FloatBuffer weightsFloatData;
private boolean actuallyHasWeights = false;
private int vertCount;
private boolean usesSharedVerts;
private boolean usesBigIndices;
// 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;
public MeshLoader() {
super();
}
@Override
public void startDocument() {
geoms.clear();
lodLevels.clear();
sb = null;
ib = null;
fb = null;
vb = null;
mesh = null;
geom = null;
sharedMesh = null;
usesSharedMesh.clear();
usesSharedVerts = false;
vertCount = 0;
meshIndex = 0;
texCoordIndex = 0;
ignoreUntilEnd = null;
animData = null;
actuallyHasWeights = false;
indicesData = null;
weightsFloatData = null;
}
@Override
public void endDocument() {
}
private void pushIndex(int index){
if (ib != null){
ib.put(index);
}else{
sb.put((short)index);
}
}
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 indicesPerFace = 0;
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, indicesPerFace, Format.UnsignedShort, sb);
} else {
ib = BufferUtils.createIntBuffer(numIndices);
sb = null;
vb.setupData(Usage.Static, indicesPerFace, Format.UnsignedInt, ib);
}
mesh.setBuffer(vb);
}
private void applyMaterial(Geometry geom, String matName) {
Material mat = null;
if (matName.endsWith(".j3m")) {
// load as native jme3 material instance
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, "Cannot locate {0} for model {1}", new Object[]{matName, key});
mat = PlaceholderAssets.getPlaceholderMaterial(assetManager);
}
if (mat.isTransparent()) {
geom.setQueueBucket(Bucket.Transparent);
}
geom.setMaterial(mat);
}
private void startSubMesh(String matName, String usesharedvertices, String use32bitIndices, String opType) throws SAXException {
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("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());
// }
}else{
usesSharedMesh.add(false);
}
if (meshName == null) {
geom = new Geometry("OgreSubmesh-" + (++meshIndex), mesh);
} else {
geom = new Geometry(meshName + "-geom-" + (++meshIndex), mesh);
}
if (usesSharedVerts) {
// Old code for buffer sharer
// this mesh is shared!
//geom.setUserData(UserData.JME_SHAREDMESH, sharedMesh);
}
applyMaterial(geom, matName);
geoms.add(geom);
}
private void startSharedGeom(String vertexcount) throws SAXException {
sharedMesh = new Mesh();
vertCount = parseInt(vertexcount);
usesSharedVerts = false;
geom = null;
mesh = sharedMesh;
}
private void startGeometry(String vertexcount) throws SAXException {
vertCount = parseInt(vertexcount);
}
/**
* 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)) {
// 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;
}
//int vertCount = mesh.getVertexCount();
int maxWeightsPerVert = 0;
weightsFloatData.rewind();
for (int v = 0; v < vertCount; v++) {
float w0 = weightsFloatData.get(),
w1 = weightsFloatData.get(),
w2 = weightsFloatData.get(),
w3 = weightsFloatData.get();
if (w3 != 0) {
maxWeightsPerVert = Math.max(maxWeightsPerVert, 4);
} else if (w2 != 0) {
maxWeightsPerVert = Math.max(maxWeightsPerVert, 3);
} else if (w1 != 0) {
maxWeightsPerVert = Math.max(maxWeightsPerVert, 2);
} else if (w0 != 0) {
maxWeightsPerVert = Math.max(maxWeightsPerVert, 1);
}
float sum = w0 + w1 + w2 + w3;
if (sum != 1f) {
weightsFloatData.position(weightsFloatData.position() - 4);
// compute new vals based on sum
float sumToB = 1f / sum;
weightsFloatData.put(w0 * sumToB);
weightsFloatData.put(w1 * sumToB);
weightsFloatData.put(w2 * sumToB);
weightsFloatData.put(w3 * sumToB);
}
}
weightsFloatData.rewind();
actuallyHasWeights = false;
weightsFloatData = null;
indicesData = null;
mesh.setMaxNumWeights(maxWeightsPerVert);
}
private void startBoneAssigns() {
if (mesh != sharedMesh && usesSharedVerts) {
// will use bone assignments from shared mesh (?)
return;
}
// current mesh will have bone assigns
//int vertCount = mesh.getVertexCount();
// 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);
}
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);
mesh.setBuffer(weights);
mesh.setBuffer(indices);
}
private void startVertexBuffer(Attributes attribs) throws SAXException {
if (parseBool(attribs.getValue("positions"), false)) {
vb = new VertexBuffer(Type.Position);
fb = BufferUtils.createFloatBuffer(vertCount * 3);
vb.setupData(Usage.Static, 3, Format.Float, fb);
mesh.setBuffer(vb);
}
if (parseBool(attribs.getValue("normals"), false)) {
vb = new VertexBuffer(Type.Normal);
fb = BufferUtils.createFloatBuffer(vertCount * 3);
vb.setupData(Usage.Static, 3, Format.Float, fb);
mesh.setBuffer(vb);
}
if (parseBool(attribs.getValue("colours_diffuse"), false)) {
vb = new VertexBuffer(Type.Color);
fb = BufferUtils.createFloatBuffer(vertCount * 4);
vb.setupData(Usage.Static, 4, Format.Float, fb);
mesh.setBuffer(vb);
}
if (parseBool(attribs.getValue("tangents"), false)) {
int dimensions = parseInt(attribs.getValue("tangent_dimensions"), 3);
vb = new VertexBuffer(Type.Tangent);
fb = BufferUtils.createFloatBuffer(vertCount * dimensions);
vb.setupData(Usage.Static, dimensions, Format.Float, fb);
mesh.setBuffer(vb);
}
if (parseBool(attribs.getValue("binormals"), false)) {
vb = new VertexBuffer(Type.Binormal);
fb = BufferUtils.createFloatBuffer(vertCount * 3);
vb.setupData(Usage.Static, 3, Format.Float, fb);
mesh.setBuffer(vb);
}
int texCoords = parseInt(attribs.getValue("texture_coords"), 0);
for (int i = 0; i < texCoords; i++) {
int dims = parseInt(attribs.getValue("texture_coord_dimensions_" + i), 2);
if (dims < 1 || dims > 4) {
throw new SAXException("Texture coord dimensions must be 1 <= dims <= 4");
}
if (i <= 7) {
vb = new VertexBuffer(TEXCOORD_TYPES[i]);
} else {
// more than 8 texture coordinates are not supported by ogre.
throw new SAXException("More than 8 texture coordinates not supported");
}
fb = BufferUtils.createFloatBuffer(vertCount * dims);
vb.setupData(Usage.Static, dims, Format.Float, fb);
mesh.setBuffer(vb);
}
}
private void startVertex() {
texCoordIndex = 0;
}
private void pushAttrib(Type type, Attributes attribs) throws SAXException {
try {
FloatBuffer buf = (FloatBuffer) mesh.getBuffer(type).getData();
buf.put(parseFloat(attribs.getValue("x"))).put(parseFloat(attribs.getValue("y"))).put(parseFloat(attribs.getValue("z")));
} catch (Exception ex) {
throw new SAXException("Failed to push attrib", ex);
}
}
private void pushTangent(Attributes attribs) throws SAXException {
try {
VertexBuffer tangentBuf = mesh.getBuffer(Type.Tangent);
FloatBuffer buf = (FloatBuffer) tangentBuf.getData();
buf.put(parseFloat(attribs.getValue("x"))).put(parseFloat(attribs.getValue("y"))).put(parseFloat(attribs.getValue("z")));
if (tangentBuf.getNumComponents() == 4) {
buf.put(parseFloat(attribs.getValue("w")));
}
} catch (Exception ex) {
throw new SAXException("Failed to push attrib", ex);
}
}
private void pushTexCoord(Attributes attribs) throws SAXException {
if (texCoordIndex >= 8) {
return; // More than 8 not supported by ogre.
}
Type type = TEXCOORD_TYPES[texCoordIndex];
VertexBuffer tcvb = mesh.getBuffer(type);
FloatBuffer buf = (FloatBuffer) tcvb.getData();
buf.put(parseFloat(attribs.getValue("u")));
if (tcvb.getNumComponents() >= 2) {
buf.put(parseFloat(attribs.getValue("v")));
if (tcvb.getNumComponents() >= 3) {
buf.put(parseFloat(attribs.getValue("w")));
if (tcvb.getNumComponents() == 4) {
buf.put(parseFloat(attribs.getValue("x")));
}
}
}
texCoordIndex++;
}
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("\\s");
if (vals.length != 3 && vals.length != 4) {
throw new SAXException("Color value must contain 3 or 4 components");
}
ColorRGBA color = new ColorRGBA();
color.r = parseFloat(vals[0]);
color.g = parseFloat(vals[1]);
color.b = parseFloat(vals[2]);
if (vals.length == 3) {
color.a = 1f;
} else {
color.a = parseFloat(vals[3]);
}
buf.put(color.r).put(color.g).put(color.b).put(color.a);
}
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);
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>();
// Add the first LOD level (always the original index buffer)
levels.add(originalIndexBuffer);
lodLevels.put(index, levels);
}
levels.add(vb);
}
private void startLevelOfDetail(String numlevels) {
// numLevels = Integer.parseInt(numlevels);
}
private void endLevelOfDetail() {
// set the lod data for each mesh
for (Entry<List<VertexBuffer>> entry : lodLevels) {
Mesh m = geoms.get(entry.getKey()).getMesh();
List<VertexBuffer> levels = entry.getValue();
VertexBuffer[] levelArray = new VertexBuffer[levels.size()];
levels.toArray(levelArray);
m.setLodLevels(levelArray);
}
}
private void startLodGenerated(String depthsqr) {
}
private void pushBoneAssign(String vertIndex, String boneIndex, String weight) throws SAXException {
int vert = parseInt(vertIndex);
float w = parseFloat(weight);
byte bone = (byte) parseInt(boneIndex);
assert bone >= 0;
assert vert >= 0 && vert < mesh.getVertexCount();
int i;
float v = 0;
// see which weights are unused for a given bone
for (i = vert * 4; i < vert * 4 + 4; i++) {
v = weightsFloatData.get(i);
if (v == 0) {
break;
}
}
if (v != 0) {
logger.log(Level.WARNING, "Vertex {0} has more than 4 weights per vertex! Ignoring..", vert);
return;
}
weightsFloatData.put(i, w);
indicesData.put(i, bone);
actuallyHasWeights = true;
}
private void startSkeleton(String name) {
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);
}
@Override
public void startElement(String uri, String localName, String qName, Attributes attribs) throws SAXException {
if (ignoreUntilEnd != null) {
return;
}
if (qName.equals("texcoord")) {
pushTexCoord(attribs);
} else if (qName.equals("vertexboneassignment")) {
pushBoneAssign(attribs.getValue("vertexindex"),
attribs.getValue("boneindex"),
attribs.getValue("weight"));
} else if (qName.equals("face")) {
pushFace(attribs.getValue("v1"),
attribs.getValue("v2"),
attribs.getValue("v3"));
} else if (qName.equals("position")) {
pushAttrib(Type.Position, attribs);
} else if (qName.equals("normal")) {
pushAttrib(Type.Normal, attribs);
} else if (qName.equals("tangent")) {
pushTangent(attribs);
} else if (qName.equals("binormal")) {
pushAttrib(Type.Binormal, attribs);
} else if (qName.equals("colour_diffuse")) {
pushColor(attribs);
} else if (qName.equals("vertex")) {
startVertex();
} else if (qName.equals("faces")) {
startFaces(attribs.getValue("count"));
} else if (qName.equals("geometry")) {
String count = attribs.getValue("vertexcount");
if (count == null) {
count = attribs.getValue("count");
}
startGeometry(count);
} else if (qName.equals("vertexbuffer")) {
startVertexBuffer(attribs);
} else if (qName.equals("lodfacelist")) {
startLodFaceList(attribs.getValue("submeshindex"),
attribs.getValue("numfaces"));
} else if (qName.equals("lodgenerated")) {
startLodGenerated(attribs.getValue("fromdepthsquared"));
} else if (qName.equals("levelofdetail")) {
startLevelOfDetail(attribs.getValue("numlevels"));
} else if (qName.equals("boneassignments")) {
startBoneAssigns();
} else if (qName.equals("submesh")) {
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) {
count = attribs.getValue("count");
}
if (count != null && !count.equals("0")) {
startSharedGeom(count);
}
} else if (qName.equals("submeshes")) {
// ok
} else if (qName.equals("skeletonlink")) {
startSkeleton(attribs.getValue("name"));
} else if (qName.equals("submeshnames")) {
// ok
} else if (qName.equals("submeshname")) {
startSubmeshName(attribs.getValue("index"), attribs.getValue("name"));
} else if (qName.equals("mesh")) {
// ok
} else {
logger.log(Level.WARNING, "Unknown tag: {0}. Ignoring.", qName);
ignoreUntilEnd = qName;
}
}
@Override
public void endElement(String uri, String name, String qName) {
if (ignoreUntilEnd != null) {
if (ignoreUntilEnd.equals(qName)) {
ignoreUntilEnd = null;
}
return;
}
if (qName.equals("submesh")) {
usesBigIndices = false;
geom = null;
mesh = null;
} else if (qName.equals("submeshes")) {
// IMPORTANT: restore sharedmesh, for use with shared boneweights
geom = null;
mesh = sharedMesh;
usesSharedVerts = false;
} else if (qName.equals("faces")) {
if (ib != null) {
ib.flip();
} else {
sb.flip();
}
vb = null;
ib = null;
sb = null;
} else if (qName.equals("vertexbuffer")) {
fb = null;
vb = null;
} else if (qName.equals("geometry")
|| qName.equals("sharedgeometry")) {
// finish writing to buffers
for (VertexBuffer buf : mesh.getBufferList().getArray()) {
Buffer data = buf.getData();
if (data.position() != 0) {
data.flip();
}
}
mesh.updateBound();
mesh.setStatic();
if (qName.equals("sharedgeometry")) {
geom = null;
mesh = null;
}
} else if (qName.equals("lodfacelist")) {
sb.flip();
vb = null;
sb = null;
} else if (qName.equals("levelofdetail")) {
endLevelOfDetail();
} else if (qName.equals("boneassignments")) {
endBoneAssigns();
}
}
@Override
public void characters(char ch[], int start, int length) {
}
private Node compileModel() {
Node model = new Node(meshName + "-ogremesh");
for (int i = 0; i < geoms.size(); i++) {
Geometry g = geoms.get(i);
Mesh m = g.getMesh();
// New code for buffer extract
if (sharedMesh != null && usesSharedMesh.get(i)) {
m.extractVertexData(sharedMesh);
}
// Old code for buffer sharer
//if (sharedMesh != null && isUsingSharedVerts(g)) {
// m.setBound(sharedMesh.getBound().clone());
//}
model.attachChild(geoms.get(i));
}
// Do not attach shared geometry to the node!
if (animData != null) {
// This model uses animation
// Old code for buffer sharer
// 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();
m.generateBindPose(!HARDWARE_SKINNING);
// Old code for buffer sharer
//boolean useShared = isUsingSharedVerts(g);
//if (!useShared) {
// create bind pose
//m.generateBindPose(!HARDWARE_SKINNING);
//}
}
// Put the animations in the AnimControl
HashMap<String, Animation> anims = new HashMap<String, Animation>();
ArrayList<Animation> animList = animData.anims;
for (int i = 0; i < animList.size(); i++) {
Animation anim = animList.get(i);
anims.put(anim.getName(), anim);
}
AnimControl ctrl = new AnimControl(animData.skeleton);
ctrl.setAnimations(anims);
model.addControl(ctrl);
// Put the skeleton in the skeleton control
SkeletonControl skeletonControl = new SkeletonControl(animData.skeleton);
// This will acquire the targets from the node
model.addControl(skeletonControl);
}
return model;
}
public Object load(AssetInfo info) throws IOException {
try {
key = info.getKey();
meshName = key.getName();
folderName = key.getFolder();
String ext = key.getExtension();
meshName = meshName.substring(0, meshName.length() - ext.length() - 1);
if (folderName != null && folderName.length() > 0) {
meshName = meshName.substring(folderName.length());
}
assetManager = info.getManager();
if (key instanceof OgreMeshKey) {
// OgreMeshKey is being used, try getting the material list
// from it
OgreMeshKey meshKey = (OgreMeshKey) key;
materialList = meshKey.getMaterialList();
String materialName = meshKey.getMaterialName();
// 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(materialKey);
} catch (AssetNotFoundException e) {
logger.log(Level.WARNING, "Cannot locate {0} for model {1}", new Object[]{ materialKey, key });
}
}
// 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 compileModel();
} catch (SAXException ex) {
IOException ioEx = new IOException("Error while parsing Ogre3D mesh.xml");
ioEx.initCause(ex);
throw ioEx;
} catch (ParserConfigurationException ex) {
IOException ioEx = new IOException("Error while parsing Ogre3D mesh.xml");
ioEx.initCause(ex);
throw ioEx;
}
}
}