diff options
Diffstat (limited to 'engine/src/ogre/com/jme3/scene/plugins/ogre/MeshLoader.java')
-rw-r--r-- | engine/src/ogre/com/jme3/scene/plugins/ogre/MeshLoader.java | 892 |
1 files changed, 892 insertions, 0 deletions
diff --git a/engine/src/ogre/com/jme3/scene/plugins/ogre/MeshLoader.java b/engine/src/ogre/com/jme3/scene/plugins/ogre/MeshLoader.java new file mode 100644 index 0000000..e7f4b10 --- /dev/null +++ b/engine/src/ogre/com/jme3/scene/plugins/ogre/MeshLoader.java @@ -0,0 +1,892 @@ +/* + * 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 + IntMap<VertexBuffer> bufs = mesh.getBuffers(); + for (Entry<VertexBuffer> entry : bufs) { + Buffer data = entry.getValue().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; + } + + } +} |