OSDN Git Service

db5eba18062bf66ab895b9b745d71162f38bd7c3
[mikumikustudio/MikuMikuStudio.git] / engine / src / ogre / com / jme3 / scene / plugins / ogre / MeshLoader.java
1 /*
2  * Copyright (c) 2009-2010 jMonkeyEngine
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are
7  * met:
8  *
9  * * Redistributions of source code must retain the above copyright
10  *   notice, this list of conditions and the following disclaimer.
11  *
12  * * Redistributions in binary form must reproduce the above copyright
13  *   notice, this list of conditions and the following disclaimer in the
14  *   documentation and/or other materials provided with the distribution.
15  *
16  * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
17  *   may be used to endorse or promote products derived from this software
18  *   without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
24  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
25  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
26  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
27  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
28  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
29  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
30  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  */
32 package com.jme3.scene.plugins.ogre;
33
34 import com.jme3.animation.Animation;
35 import com.jme3.scene.plugins.ogre.matext.OgreMaterialKey;
36 import com.jme3.animation.AnimControl;
37 import com.jme3.animation.SkeletonControl;
38 import com.jme3.asset.AssetInfo;
39 import com.jme3.asset.AssetKey;
40 import com.jme3.asset.AssetLoader;
41 import com.jme3.asset.AssetManager;
42 import com.jme3.asset.AssetNotFoundException;
43 import com.jme3.material.Material;
44 import com.jme3.material.MaterialList;
45 import com.jme3.math.ColorRGBA;
46 import com.jme3.renderer.queue.RenderQueue.Bucket;
47 import com.jme3.scene.Geometry;
48 import com.jme3.scene.Mesh;
49 import com.jme3.scene.Node;
50 import com.jme3.scene.UserData;
51 import com.jme3.scene.VertexBuffer;
52 import com.jme3.scene.VertexBuffer.Format;
53 import com.jme3.scene.VertexBuffer.Type;
54 import com.jme3.scene.VertexBuffer.Usage;
55 import com.jme3.util.BufferUtils;
56 import com.jme3.util.IntMap;
57 import com.jme3.util.IntMap.Entry;
58 import java.io.IOException;
59 import java.io.InputStreamReader;
60 import java.nio.Buffer;
61 import java.nio.ByteBuffer;
62 import java.nio.FloatBuffer;
63 import java.nio.IntBuffer;
64 import java.nio.ShortBuffer;
65 import java.util.ArrayList;
66 import java.util.HashMap;
67 import java.util.List;
68 import java.util.logging.Level;
69 import java.util.logging.Logger;
70
71 import javax.xml.parsers.ParserConfigurationException;
72 import javax.xml.parsers.SAXParserFactory;
73
74 import org.xml.sax.Attributes;
75 import org.xml.sax.InputSource;
76 import org.xml.sax.SAXException;
77 import org.xml.sax.XMLReader;
78 import org.xml.sax.helpers.DefaultHandler;
79
80 import static com.jme3.util.xml.SAXUtil.*;
81
82 /**
83  * Loads Ogre3D mesh.xml files.
84  */
85 public class MeshLoader extends DefaultHandler implements AssetLoader {
86
87     private static final Logger logger = Logger.getLogger(MeshLoader.class.getName());
88     public static boolean AUTO_INTERLEAVE = true;
89     public static boolean HARDWARE_SKINNING = false;
90     private static final Type[] TEXCOORD_TYPES =
91             new Type[]{
92         Type.TexCoord,
93         Type.TexCoord2,
94         Type.TexCoord3,
95         Type.TexCoord4,
96         Type.TexCoord5,
97         Type.TexCoord6,
98         Type.TexCoord7,
99         Type.TexCoord8,};
100     private String meshName;
101     private String folderName;
102     private AssetManager assetManager;
103     private MaterialList materialList;
104     // Data per submesh/sharedgeom
105     private ShortBuffer sb;
106     private IntBuffer ib;
107     private FloatBuffer fb;
108     private VertexBuffer vb;
109     private Mesh mesh;
110     private Geometry geom;
111     private ByteBuffer indicesData;
112     private FloatBuffer weightsFloatData;
113     private int vertCount;
114     private boolean usesSharedVerts;
115     private boolean usesBigIndices;
116     // Global data
117     private Mesh sharedMesh;
118     private int meshIndex = 0;
119     private int texCoordIndex = 0;
120     private String ignoreUntilEnd = null;
121     private List<Geometry> geoms = new ArrayList<Geometry>();
122     private IntMap<List<VertexBuffer>> lodLevels = new IntMap<List<VertexBuffer>>();
123     private AnimData animData;
124
125     public MeshLoader() {
126         super();
127     }
128
129     @Override
130     public void startDocument() {
131         geoms.clear();
132         lodLevels.clear();
133
134         sb = null;
135         ib = null;
136         fb = null;
137         vb = null;
138         mesh = null;
139         geom = null;
140         sharedMesh = null;
141
142         usesSharedVerts = false;
143         vertCount = 0;
144         meshIndex = 0;
145         texCoordIndex = 0;
146         ignoreUntilEnd = null;
147
148         animData = null;
149
150         indicesData = null;
151         weightsFloatData = null;
152     }
153
154     @Override
155     public void endDocument() {
156     }
157
158     private void pushFace(String v1, String v2, String v3) throws SAXException {
159         int i1 = parseInt(v1);
160
161         // TODO: fan/strip support
162         int i2 = parseInt(v2);
163         int i3 = parseInt(v3);
164         if (ib != null) {
165             ib.put(i1).put(i2).put(i3);
166         } else {
167             sb.put((short) i1).put((short) i2).put((short) i3);
168         }
169     }
170
171     private boolean isUsingSharedVerts(Geometry geom) {
172         return geom.getUserData(UserData.JME_SHAREDMESH) != null;
173     }
174
175     private void startFaces(String count) throws SAXException {
176         int numFaces = parseInt(count);
177         int numIndices;
178
179         if (mesh.getMode() == Mesh.Mode.Triangles) {
180             numIndices = numFaces * 3;
181         } else {
182             throw new SAXException("Triangle strip or fan not supported!");
183         }
184
185         vb = new VertexBuffer(VertexBuffer.Type.Index);
186         if (!usesBigIndices) {
187             sb = BufferUtils.createShortBuffer(numIndices);
188             ib = null;
189             vb.setupData(Usage.Static, 3, Format.UnsignedShort, sb);
190         } else {
191             ib = BufferUtils.createIntBuffer(numIndices);
192             sb = null;
193             vb.setupData(Usage.Static, 3, Format.UnsignedInt, ib);
194         }
195         mesh.setBuffer(vb);
196     }
197
198     private void applyMaterial(Geometry geom, String matName) {
199         Material mat = null;
200         if (matName.endsWith(".j3m")) {
201             // load as native jme3 material instance
202             mat = assetManager.loadMaterial(matName);
203         } else {
204             if (materialList != null) {
205                 mat = materialList.get(matName);
206             }
207             if (mat == null) {
208                 logger.log(Level.WARNING, "Material {0} not found. Applying default material", matName);
209                 mat = (Material) assetManager.loadMaterial("Common/Materials/RedColor.j3m");
210             }
211         }
212
213         if (mat == null) {
214             throw new RuntimeException("Cannot locate material named " + matName);
215         }
216
217         if (mat.isTransparent()) {
218             geom.setQueueBucket(Bucket.Transparent);
219         }
220
221         geom.setMaterial(mat);
222     }
223
224     private void startSubMesh(String matName, String usesharedvertices, String use32bitIndices, String opType) throws SAXException {
225         mesh = new Mesh();
226         if (opType == null || opType.equals("triangle_list")) {
227             mesh.setMode(Mesh.Mode.Triangles);
228         } else if (opType.equals("triangle_strip")) {
229             mesh.setMode(Mesh.Mode.TriangleStrip);
230         } else if (opType.equals("triangle_fan")) {
231             mesh.setMode(Mesh.Mode.TriangleFan);
232         }
233
234         usesBigIndices = parseBool(use32bitIndices, false);
235         usesSharedVerts = parseBool(usesharedvertices, false);
236         if (usesSharedVerts) {
237             // import vertexbuffers from shared geom
238             IntMap<VertexBuffer> sharedBufs = sharedMesh.getBuffers();
239             for (Entry<VertexBuffer> entry : sharedBufs) {
240                 mesh.setBuffer(entry.getValue());
241             }
242         }
243
244         if (meshName == null) {
245             geom = new Geometry("OgreSubmesh-" + (++meshIndex), mesh);
246         } else {
247             geom = new Geometry(meshName + "-geom-" + (++meshIndex), mesh);
248         }
249
250         if (usesSharedVerts) {
251             // this mesh is shared!
252             geom.setUserData(UserData.JME_SHAREDMESH, sharedMesh);
253         }
254
255         applyMaterial(geom, matName);
256         geoms.add(geom);
257     }
258
259     private void startSharedGeom(String vertexcount) throws SAXException {
260         sharedMesh = new Mesh();
261         vertCount = parseInt(vertexcount);
262         usesSharedVerts = false;
263
264         geom = null;
265         mesh = sharedMesh;
266     }
267
268     private void startGeometry(String vertexcount) throws SAXException {
269         vertCount = parseInt(vertexcount);
270     }
271
272     /**
273      * Normalizes weights if needed and finds largest amount of weights used
274      * for all vertices in the buffer.
275      */
276     private void endBoneAssigns() {
277         if (mesh != sharedMesh && isUsingSharedVerts(geom)) {
278             return;
279         }
280
281         //int vertCount = mesh.getVertexCount();
282         int maxWeightsPerVert = 0;
283         weightsFloatData.rewind();
284         for (int v = 0; v < vertCount; v++) {
285             float w0 = weightsFloatData.get(),
286                     w1 = weightsFloatData.get(),
287                     w2 = weightsFloatData.get(),
288                     w3 = weightsFloatData.get();
289
290             if (w3 != 0) {
291                 maxWeightsPerVert = Math.max(maxWeightsPerVert, 4);
292             } else if (w2 != 0) {
293                 maxWeightsPerVert = Math.max(maxWeightsPerVert, 3);
294             } else if (w1 != 0) {
295                 maxWeightsPerVert = Math.max(maxWeightsPerVert, 2);
296             } else if (w0 != 0) {
297                 maxWeightsPerVert = Math.max(maxWeightsPerVert, 1);
298             }
299
300             float sum = w0 + w1 + w2 + w3;
301             if (sum != 1f) {
302                 weightsFloatData.position(weightsFloatData.position() - 4);
303                 // compute new vals based on sum
304                 float sumToB = 1f / sum;
305                 weightsFloatData.put(w0 * sumToB);
306                 weightsFloatData.put(w1 * sumToB);
307                 weightsFloatData.put(w2 * sumToB);
308                 weightsFloatData.put(w3 * sumToB);
309             }
310         }
311         weightsFloatData.rewind();
312
313         weightsFloatData = null;
314         indicesData = null;
315
316         mesh.setMaxNumWeights(maxWeightsPerVert);
317     }
318
319     private void startBoneAssigns() {
320         if (mesh != sharedMesh && usesSharedVerts) {
321             // will use bone assignments from shared mesh (?)
322             return;
323         }
324
325         // current mesh will have bone assigns
326         //int vertCount = mesh.getVertexCount();
327         // each vertex has
328         // - 4 bone weights
329         // - 4 bone indices
330         if (HARDWARE_SKINNING) {
331             weightsFloatData = BufferUtils.createFloatBuffer(vertCount * 4);
332             indicesData = BufferUtils.createByteBuffer(vertCount * 4);
333         } else {
334             // create array-backed buffers if software skinning for access speed
335             weightsFloatData = FloatBuffer.allocate(vertCount * 4);
336             indicesData = ByteBuffer.allocate(vertCount * 4);
337         }
338
339         VertexBuffer weights = new VertexBuffer(Type.BoneWeight);
340         VertexBuffer indices = new VertexBuffer(Type.BoneIndex);
341
342         Usage usage = HARDWARE_SKINNING ? Usage.Static : Usage.CpuOnly;
343         weights.setupData(usage, 4, Format.Float, weightsFloatData);
344         indices.setupData(usage, 4, Format.UnsignedByte, indicesData);
345
346         mesh.setBuffer(weights);
347         mesh.setBuffer(indices);
348     }
349
350     private void startVertexBuffer(Attributes attribs) throws SAXException {
351         if (parseBool(attribs.getValue("positions"), false)) {
352             vb = new VertexBuffer(Type.Position);
353             fb = BufferUtils.createFloatBuffer(vertCount * 3);
354             vb.setupData(Usage.Static, 3, Format.Float, fb);
355             mesh.setBuffer(vb);
356         }
357         if (parseBool(attribs.getValue("normals"), false)) {
358             vb = new VertexBuffer(Type.Normal);
359             fb = BufferUtils.createFloatBuffer(vertCount * 3);
360             vb.setupData(Usage.Static, 3, Format.Float, fb);
361             mesh.setBuffer(vb);
362         }
363         if (parseBool(attribs.getValue("colours_diffuse"), false)) {
364             vb = new VertexBuffer(Type.Color);
365             fb = BufferUtils.createFloatBuffer(vertCount * 4);
366             vb.setupData(Usage.Static, 4, Format.Float, fb);
367             mesh.setBuffer(vb);
368         }
369         if (parseBool(attribs.getValue("tangents"), false)) {
370             int dimensions = parseInt(attribs.getValue("tangent_dimensions"), 3);
371             vb = new VertexBuffer(Type.Tangent);
372             fb = BufferUtils.createFloatBuffer(vertCount * dimensions);
373             vb.setupData(Usage.Static, dimensions, Format.Float, fb);
374             mesh.setBuffer(vb);
375         }
376         if (parseBool(attribs.getValue("binormals"), false)) {
377             vb = new VertexBuffer(Type.Binormal);
378             fb = BufferUtils.createFloatBuffer(vertCount * 3);
379             vb.setupData(Usage.Static, 3, Format.Float, fb);
380             mesh.setBuffer(vb);
381         }
382
383         int texCoords = parseInt(attribs.getValue("texture_coords"), 0);
384         for (int i = 0; i < texCoords; i++) {
385             int dims = parseInt(attribs.getValue("texture_coord_dimensions_" + i), 2);
386             if (dims < 1 || dims > 4) {
387                 throw new SAXException("Texture coord dimensions must be 1 <= dims <= 4");
388             }
389
390             if (i <= 7) {
391                 vb = new VertexBuffer(TEXCOORD_TYPES[i]);
392             } else {
393                 // more than 8 texture coordinates are not supported by ogre.
394                 throw new SAXException("More than 8 texture coordinates not supported");
395             }
396             fb = BufferUtils.createFloatBuffer(vertCount * dims);
397             vb.setupData(Usage.Static, dims, Format.Float, fb);
398             mesh.setBuffer(vb);
399         }
400     }
401
402     private void startVertex() {
403         texCoordIndex = 0;
404     }
405
406     private void pushAttrib(Type type, Attributes attribs) throws SAXException {
407         try {
408             FloatBuffer buf = (FloatBuffer) mesh.getBuffer(type).getData();
409             buf.put(parseFloat(attribs.getValue("x"))).put(parseFloat(attribs.getValue("y"))).put(parseFloat(attribs.getValue("z")));
410         } catch (Exception ex) {
411             throw new SAXException("Failed to push attrib", ex);
412         }
413     }
414
415     private void pushTangent(Attributes attribs) throws SAXException {
416         try {
417             VertexBuffer tangentBuf = mesh.getBuffer(Type.Tangent);
418             FloatBuffer buf = (FloatBuffer) tangentBuf.getData();
419             buf.put(parseFloat(attribs.getValue("x"))).put(parseFloat(attribs.getValue("y"))).put(parseFloat(attribs.getValue("z")));
420             if (tangentBuf.getNumComponents() == 4) {
421                 buf.put(parseFloat(attribs.getValue("w")));
422             }
423         } catch (Exception ex) {
424             throw new SAXException("Failed to push attrib", ex);
425         }
426     }
427
428     private void pushTexCoord(Attributes attribs) throws SAXException {
429         if (texCoordIndex >= 8) {
430             return; // More than 8 not supported by ogre.
431         }
432         Type type = TEXCOORD_TYPES[texCoordIndex];
433
434         VertexBuffer tcvb = mesh.getBuffer(type);
435         FloatBuffer buf = (FloatBuffer) tcvb.getData();
436
437         buf.put(parseFloat(attribs.getValue("u")));
438         if (tcvb.getNumComponents() >= 2) {
439             buf.put(parseFloat(attribs.getValue("v")));
440             if (tcvb.getNumComponents() >= 3) {
441                 buf.put(parseFloat(attribs.getValue("w")));
442                 if (tcvb.getNumComponents() == 4) {
443                     buf.put(parseFloat(attribs.getValue("x")));
444                 }
445             }
446         }
447
448         texCoordIndex++;
449     }
450
451     private void pushColor(Attributes attribs) throws SAXException {
452         FloatBuffer buf = (FloatBuffer) mesh.getBuffer(Type.Color).getData();
453         String value = parseString(attribs.getValue("value"));
454         String[] vals = value.split(" ");
455         if (vals.length != 3 && vals.length != 4) {
456             throw new SAXException("Color value must contain 3 or 4 components");
457         }
458
459         ColorRGBA color = new ColorRGBA();
460         color.r = parseFloat(vals[0]);
461         color.g = parseFloat(vals[1]);
462         color.b = parseFloat(vals[2]);
463         if (vals.length == 3) {
464             color.a = 1f;
465         } else {
466             color.a = parseFloat(vals[3]);
467         }
468
469         buf.put(color.r).put(color.g).put(color.b).put(color.a);
470     }
471
472     private void startLodFaceList(String submeshindex, String numfaces) {
473         int index = Integer.parseInt(submeshindex);
474         int faceCount = Integer.parseInt(numfaces);
475
476         vb = new VertexBuffer(VertexBuffer.Type.Index);
477         sb = BufferUtils.createShortBuffer(faceCount * 3);
478         ib = null;
479         vb.setupData(Usage.Static, 3, Format.UnsignedShort, sb);
480
481         List<VertexBuffer> levels = lodLevels.get(index);
482         if (levels == null) {
483             levels = new ArrayList<VertexBuffer>();
484             Mesh submesh = geoms.get(index).getMesh();
485             levels.add(submesh.getBuffer(Type.Index));
486             lodLevels.put(index, levels);
487         }
488
489         levels.add(vb);
490     }
491
492     private void startLevelOfDetail(String numlevels) {
493 //        numLevels = Integer.parseInt(numlevels);
494     }
495
496     private void endLevelOfDetail() {
497         // set the lod data for each mesh
498         for (Entry<List<VertexBuffer>> entry : lodLevels) {
499             Mesh m = geoms.get(entry.getKey()).getMesh();
500             List<VertexBuffer> levels = entry.getValue();
501             VertexBuffer[] levelArray = new VertexBuffer[levels.size()];
502             levels.toArray(levelArray);
503             m.setLodLevels(levelArray);
504         }
505     }
506
507     private void startLodGenerated(String depthsqr) {
508     }
509
510     private void pushBoneAssign(String vertIndex, String boneIndex, String weight) throws SAXException {
511         int vert = parseInt(vertIndex);
512         float w = parseFloat(weight);
513         byte bone = (byte) parseInt(boneIndex);
514
515         assert bone >= 0;
516         assert vert >= 0 && vert < mesh.getVertexCount();
517
518         int i;
519         float v = 0;
520         // see which weights are unused for a given bone
521         for (i = vert * 4; i < vert * 4 + 4; i++) {
522             v = weightsFloatData.get(i);
523             if (v == 0) {
524                 break;
525             }
526         }
527         if (v != 0) {
528             logger.log(Level.WARNING, "Vertex {0} has more than 4 weights per vertex! Ignoring..", vert);
529             return;
530         }
531
532         weightsFloatData.put(i, w);
533         indicesData.put(i, bone);
534     }
535
536     private void startSkeleton(String name) {
537         animData = (AnimData) assetManager.loadAsset(folderName + name + ".xml");
538     }
539
540     private void startSubmeshName(String indexStr, String nameStr) {
541         int index = Integer.parseInt(indexStr);
542         geoms.get(index).setName(nameStr);
543     }
544
545     @Override
546     public void startElement(String uri, String localName, String qName, Attributes attribs) throws SAXException {
547         if (ignoreUntilEnd != null) {
548             return;
549         }
550
551         if (qName.equals("texcoord")) {
552             pushTexCoord(attribs);
553         } else if (qName.equals("vertexboneassignment")) {
554             pushBoneAssign(attribs.getValue("vertexindex"),
555                     attribs.getValue("boneindex"),
556                     attribs.getValue("weight"));
557         } else if (qName.equals("face")) {
558             pushFace(attribs.getValue("v1"),
559                     attribs.getValue("v2"),
560                     attribs.getValue("v3"));
561         } else if (qName.equals("position")) {
562             pushAttrib(Type.Position, attribs);
563         } else if (qName.equals("normal")) {
564             pushAttrib(Type.Normal, attribs);
565         } else if (qName.equals("tangent")) {
566             pushTangent(attribs);
567         } else if (qName.equals("binormal")) {
568             pushAttrib(Type.Binormal, attribs);
569         } else if (qName.equals("colour_diffuse")) {
570             pushColor(attribs);
571         } else if (qName.equals("vertex")) {
572             startVertex();
573         } else if (qName.equals("faces")) {
574             startFaces(attribs.getValue("count"));
575         } else if (qName.equals("geometry")) {
576             String count = attribs.getValue("vertexcount");
577             if (count == null) {
578                 count = attribs.getValue("count");
579             }
580             startGeometry(count);
581         } else if (qName.equals("vertexbuffer")) {
582             startVertexBuffer(attribs);
583         } else if (qName.equals("lodfacelist")) {
584             startLodFaceList(attribs.getValue("submeshindex"),
585                     attribs.getValue("numfaces"));
586         } else if (qName.equals("lodgenerated")) {
587             startLodGenerated(attribs.getValue("fromdepthsquared"));
588         } else if (qName.equals("levelofdetail")) {
589             startLevelOfDetail(attribs.getValue("numlevels"));
590         } else if (qName.equals("boneassignments")) {
591             startBoneAssigns();
592         } else if (qName.equals("submesh")) {
593             startSubMesh(attribs.getValue("material"),
594                     attribs.getValue("usesharedvertices"),
595                     attribs.getValue("use32bitindexes"),
596                     attribs.getValue("operationtype"));
597         } else if (qName.equals("sharedgeometry")) {
598             String count = attribs.getValue("vertexcount");
599             if (count == null) {
600                 count = attribs.getValue("count");
601             }
602
603             if (count != null && !count.equals("0")) {
604                 startSharedGeom(count);
605             }
606         } else if (qName.equals("submeshes")) {
607             // ok
608         } else if (qName.equals("skeletonlink")) {
609             startSkeleton(attribs.getValue("name"));
610         } else if (qName.equals("submeshnames")) {
611             // ok
612         } else if (qName.equals("submeshname")) {
613             startSubmeshName(attribs.getValue("index"), attribs.getValue("name"));
614         } else if (qName.equals("mesh")) {
615             // ok
616         } else {
617             logger.log(Level.WARNING, "Unknown tag: {0}. Ignoring.", qName);
618             ignoreUntilEnd = qName;
619         }
620     }
621
622     @Override
623     public void endElement(String uri, String name, String qName) {
624         if (ignoreUntilEnd != null) {
625             if (ignoreUntilEnd.equals(qName)) {
626                 ignoreUntilEnd = null;
627             }
628             return;
629         }
630
631         if (qName.equals("submesh")) {
632             usesBigIndices = false;
633             geom = null;
634             mesh = null;
635         } else if (qName.equals("submeshes")) {
636             // IMPORTANT: restore sharedmesh, for use with shared boneweights
637             geom = null;
638             mesh = sharedMesh;
639             usesSharedVerts = false;
640         } else if (qName.equals("faces")) {
641             if (ib != null) {
642                 ib.flip();
643             } else {
644                 sb.flip();
645             }
646
647             vb = null;
648             ib = null;
649             sb = null;
650         } else if (qName.equals("vertexbuffer")) {
651             fb = null;
652             vb = null;
653         } else if (qName.equals("geometry")
654                 || qName.equals("sharedgeometry")) {
655             // finish writing to buffers
656             IntMap<VertexBuffer> bufs = mesh.getBuffers();
657             for (Entry<VertexBuffer> entry : bufs) {
658                 Buffer data = entry.getValue().getData();
659                 if (data.position() != 0) {
660                     data.flip();
661                 }
662             }
663             mesh.updateBound();
664             mesh.setStatic();
665
666             if (qName.equals("sharedgeometry")) {
667                 geom = null;
668                 mesh = null;
669             }
670         } else if (qName.equals("lodfacelist")) {
671             sb.flip();
672             vb = null;
673             sb = null;
674         } else if (qName.equals("levelofdetail")) {
675             endLevelOfDetail();
676         } else if (qName.equals("boneassignments")) {
677             endBoneAssigns();
678         }
679     }
680
681     @Override
682     public void characters(char ch[], int start, int length) {
683     }
684
685     private Node compileModel() {
686         Node model = new Node(meshName + "-ogremesh");
687
688         for (int i = 0; i < geoms.size(); i++) {
689             Geometry g = geoms.get(i);
690             Mesh m = g.getMesh();
691             if (sharedMesh != null && isUsingSharedVerts(g)) {
692                 m.setBound(sharedMesh.getBound().clone());
693             }
694             model.attachChild(geoms.get(i));
695         }
696
697         // Do not attach shared geometry to the node!
698
699         if (animData != null) {
700             // This model uses animation
701
702             // generate bind pose for mesh
703             // ONLY if not using shared geometry
704             // This includes the shared geoemtry itself actually
705             if (sharedMesh != null) {
706                 sharedMesh.generateBindPose(!HARDWARE_SKINNING);
707             }
708
709             for (int i = 0; i < geoms.size(); i++) {
710                 Geometry g = geoms.get(i);
711                 Mesh m = geoms.get(i).getMesh();
712                 boolean useShared = isUsingSharedVerts(g);
713
714
715                 if (!useShared) {
716                     // create bind pose
717                     m.generateBindPose(!HARDWARE_SKINNING);
718 //                } else {
719                     // Inherit animation data from shared mesh
720 //                    VertexBuffer bindPos = sharedMesh.getBuffer(Type.BindPosePosition);
721 //                    VertexBuffer bindNorm = sharedMesh.getBuffer(Type.BindPoseNormal);
722 //                    VertexBuffer boneIndex = sharedMesh.getBuffer(Type.BoneIndex);
723 //                    VertexBuffer boneWeight = sharedMesh.getBuffer(Type.BoneWeight);
724 //
725 //                    if (bindPos != null) {
726 //                        m.setBuffer(bindPos);
727 //                    }
728 //
729 //                    if (bindNorm != null) {
730 //                        m.setBuffer(bindNorm);
731 //                    }
732 //
733 //                    if (boneIndex != null) {
734 //                        m.setBuffer(boneIndex);
735 //                    }
736 //
737 //                    if (boneWeight != null) {
738 //                        m.setBuffer(boneWeight);
739 //                    }
740                 }
741             }
742
743             // Put the animations in the AnimControl
744             HashMap<String, Animation> anims = new HashMap<String, Animation>();
745             ArrayList<Animation> animList = animData.anims;
746             for (int i = 0; i < animList.size(); i++) {
747                 Animation anim = animList.get(i);
748                 anims.put(anim.getName(), anim);
749             }
750
751             AnimControl ctrl = new AnimControl(animData.skeleton);
752             ctrl.setAnimations(anims);
753             model.addControl(ctrl);
754
755             // Put the skeleton in the skeleton control
756             SkeletonControl skeletonControl = new SkeletonControl(animData.skeleton);
757
758             // This will acquire the targets from the node
759             model.addControl(skeletonControl);
760         }
761
762         return model;
763     }
764
765     public Object load(AssetInfo info) throws IOException {
766         try {
767             AssetKey key = info.getKey();
768             meshName = key.getName();
769             folderName = key.getFolder();
770             String ext = key.getExtension();
771             meshName = meshName.substring(0, meshName.length() - ext.length() - 1);
772             if (folderName != null && folderName.length() > 0) {
773                 meshName = meshName.substring(folderName.length());
774             }
775             assetManager = info.getManager();
776
777             OgreMeshKey meshKey = null;
778             if (key instanceof OgreMeshKey) {
779                 meshKey = (OgreMeshKey) key;
780                 materialList = meshKey.getMaterialList();
781                 String materialName = meshKey.getMaterialName();
782                 if (materialList == null) {
783                     if (materialName != null) {
784                         try {
785                             materialList = (MaterialList) assetManager.loadAsset(new OgreMaterialKey(folderName + materialName + ".material"));
786                         } catch (AssetNotFoundException e) {
787                             logger.log(Level.WARNING, "Cannot locate {0}{1}.material for model {2}{3}.{4}", new Object[]{folderName, materialName, folderName, meshName, ext});
788                             logger.log(Level.WARNING, "", e);
789                         }
790                     } else {
791                         try {
792                             materialList = (MaterialList) assetManager.loadAsset(new OgreMaterialKey(folderName + meshName + ".material"));
793                         } catch (AssetNotFoundException e) {
794                             logger.log(Level.WARNING, "Cannot locate {0}{1}.material for model {2}{3}.{4}", new Object[]{folderName, meshName, folderName, meshName, ext});
795                             logger.log(Level.WARNING, "", e);
796                         }
797                     }
798                 }
799             } else {
800                 try {
801                     materialList = (MaterialList) assetManager.loadAsset(new OgreMaterialKey(folderName + meshName + ".material"));
802                 } catch (AssetNotFoundException e) {
803                     logger.log(Level.WARNING, "Cannot locate {0}{1}.material for model {2}{3}.{4}", new Object[]{folderName, meshName, folderName, meshName, ext});
804                                         logger.log(Level.WARNING, "", e);
805                                 }
806
807             }
808
809             // Added by larynx 25.06.2011
810             // Android needs the namespace aware flag set to true                 
811             // Kirill 30.06.2011
812             // Now, hack is applied for both desktop and android to avoid
813             // checking with JmeSystem.
814             SAXParserFactory factory = SAXParserFactory.newInstance();
815             factory.setNamespaceAware(true);
816             
817             XMLReader xr = factory.newSAXParser().getXMLReader();
818             xr.setContentHandler(this);
819             xr.setErrorHandler(this);
820             
821             InputStreamReader r = null;
822             try {
823                 r = new InputStreamReader(info.openStream());
824                 xr.parse(new InputSource(r));
825             } finally {
826                 if (r != null){
827                     r.close();
828                 }
829             }
830             
831             return compileModel();
832         } catch (SAXException ex) {
833             IOException ioEx = new IOException("Error while parsing Ogre3D mesh.xml");
834             ioEx.initCause(ex);
835             throw ioEx;
836         } catch (ParserConfigurationException ex) {
837             IOException ioEx = new IOException("Error while parsing Ogre3D mesh.xml");
838             ioEx.initCause(ex);
839             throw ioEx;
840         }
841
842     }
843 }