PageRenderTime 189ms CodeModel.GetById 60ms app.highlight 77ms RepoModel.GetById 24ms app.codeStats 0ms

/extensions/model-loaders/model-loaders/src/com/badlogic/gdx/graphics/g3d/loaders/ogre/OgreXmlLoader.java

https://github.com/Tapay/libgdx
Java | 534 lines | 455 code | 63 blank | 16 comment | 93 complexity | 01e90f8d4d782eaa74191fc6b75febd9 MD5 | raw file
  1/*******************************************************************************
  2 * Copyright 2011 See AUTHORS file.
  3 * 
  4 * Licensed under the Apache License, Version 2.0 (the "License");
  5 * you may not use this file except in compliance with the License.
  6 * You may obtain a copy of the License at
  7 * 
  8 *   http://www.apache.org/licenses/LICENSE-2.0
  9 * 
 10 * Unless required by applicable law or agreed to in writing, software
 11 * distributed under the License is distributed on an "AS IS" BASIS,
 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 13 * See the License for the specific language governing permissions and
 14 * limitations under the License.
 15 ******************************************************************************/
 16
 17package com.badlogic.gdx.graphics.g3d.loaders.ogre;
 18
 19import java.io.InputStream;
 20import java.util.ArrayList;
 21import java.util.HashMap;
 22import java.util.List;
 23import java.util.Map;
 24
 25import javax.xml.bind.JAXBContext;
 26import javax.xml.bind.JAXBException;
 27import javax.xml.bind.Unmarshaller;
 28
 29import com.badlogic.gdx.files.FileHandle;
 30import com.badlogic.gdx.graphics.Color;
 31import com.badlogic.gdx.graphics.GL10;
 32import com.badlogic.gdx.graphics.VertexAttribute;
 33import com.badlogic.gdx.graphics.VertexAttributes;
 34import com.badlogic.gdx.graphics.VertexAttributes.Usage;
 35import com.badlogic.gdx.graphics.g3d.loaders.ogre.mesh.BaseGeometry;
 36import com.badlogic.gdx.graphics.g3d.loaders.ogre.mesh.Boneassignments;
 37import com.badlogic.gdx.graphics.g3d.loaders.ogre.mesh.ColourDiffuse;
 38import com.badlogic.gdx.graphics.g3d.loaders.ogre.mesh.Face;
 39import com.badlogic.gdx.graphics.g3d.loaders.ogre.mesh.Geometry;
 40import com.badlogic.gdx.graphics.g3d.loaders.ogre.mesh.Mesh;
 41import com.badlogic.gdx.graphics.g3d.loaders.ogre.mesh.Submesh;
 42import com.badlogic.gdx.graphics.g3d.loaders.ogre.mesh.Submeshname;
 43import com.badlogic.gdx.graphics.g3d.loaders.ogre.mesh.Texcoord;
 44import com.badlogic.gdx.graphics.g3d.loaders.ogre.mesh.Vertex;
 45import com.badlogic.gdx.graphics.g3d.loaders.ogre.mesh.Vertexboneassignment;
 46import com.badlogic.gdx.graphics.g3d.loaders.ogre.mesh.Vertexbuffer;
 47import com.badlogic.gdx.graphics.g3d.loaders.ogre.skeleton.Animation;
 48import com.badlogic.gdx.graphics.g3d.loaders.ogre.skeleton.Bone;
 49import com.badlogic.gdx.graphics.g3d.loaders.ogre.skeleton.Boneparent;
 50import com.badlogic.gdx.graphics.g3d.loaders.ogre.skeleton.Keyframe;
 51import com.badlogic.gdx.graphics.g3d.loaders.ogre.skeleton.Track;
 52import com.badlogic.gdx.graphics.g3d.model.SubMesh;
 53import com.badlogic.gdx.graphics.g3d.model.skeleton.Skeleton;
 54import com.badlogic.gdx.graphics.g3d.model.skeleton.SkeletonAnimation;
 55import com.badlogic.gdx.graphics.g3d.model.skeleton.SkeletonJoint;
 56import com.badlogic.gdx.graphics.g3d.model.skeleton.SkeletonKeyframe;
 57import com.badlogic.gdx.graphics.g3d.model.skeleton.SkeletonModel;
 58import com.badlogic.gdx.graphics.g3d.model.skeleton.SkeletonSubMesh;
 59import com.badlogic.gdx.graphics.g3d.model.still.StillModel;
 60import com.badlogic.gdx.graphics.g3d.model.still.StillSubMesh;
 61import com.badlogic.gdx.graphics.glutils.ShaderProgram;
 62import com.badlogic.gdx.math.MathUtils;
 63import com.badlogic.gdx.math.Matrix4;
 64import com.badlogic.gdx.utils.Array;
 65import com.badlogic.gdx.utils.FloatArray;
 66import com.badlogic.gdx.utils.GdxRuntimeException;
 67import com.badlogic.gdx.utils.IntArray;
 68
 69public class OgreXmlLoader {
 70	public SubMesh[] loadMeshes (FileHandle file) {
 71		InputStream in = null;
 72		try {
 73			in = file.read();
 74			return loadMesh(in);
 75		} catch (Throwable t) {
 76			throw new GdxRuntimeException("Couldn't load file '" + file.name() + "'", t);
 77		} finally {
 78			if (in != null) try {
 79				in.close();
 80			} catch (Exception e) {
 81			}
 82		}
 83	}
 84
 85	public SubMesh[] loadMesh (InputStream in) {
 86		try {
 87			Mesh ogreMesh = loadOgreMesh(in);
 88			SubMesh[] meshes = generateSubMeshes(ogreMesh);
 89			return meshes;
 90		} catch (Throwable t) {
 91			throw new GdxRuntimeException("Couldn't load meshes", t);
 92		}
 93	}
 94
 95	public SkeletonModel load (FileHandle mesh, FileHandle skeleton) {
 96		SubMesh[] meshes = loadMeshes(mesh);
 97		return new SkeletonModel(loadSkeleton(skeleton), meshes);
 98	}
 99
100	public StillModel load (FileHandle mesh) {
101		SubMesh[] meshes = loadMeshes(mesh);
102		return new StillModel(meshes);
103	}
104	
105	private SubMesh[] generateSubMeshes (Mesh ogreMesh) {
106		List<Submesh> ogreSubmeshes = ogreMesh.getSubmeshes().getSubmesh();
107		SubMesh[] submeshes = new SubMesh[ogreSubmeshes.size()];
108
109		for (int i = 0; i < ogreSubmeshes.size(); i++) {
110			Submesh ogreSubmesh = ogreSubmeshes.get(i);
111			boolean usesTriangleList = false;
112
113			if (ogreSubmesh.use32Bitindexes) throw new GdxRuntimeException("submesh '" + i + "' uses 32-bit indices");
114			if (ogreSubmesh.getOperationtype().equals("triangle_list")) {
115				usesTriangleList = true;
116			}
117
118			short[] indices = new short[ogreSubmesh.getFaces().count * (usesTriangleList ? 3 : 1)];
119			for (int j = 0, idx = 0; j < ogreSubmesh.getFaces().count; j++) {
120				Face face = ogreSubmesh.getFaces().getFace().get(j);
121				indices[idx++] = face.v1;
122				if (usesTriangleList || j == 0) {
123					indices[idx++] = face.v2;
124					indices[idx++] = face.v3;
125				}
126			}
127
128			List<VertexAttribute> attributes = new ArrayList<VertexAttribute>();
129			IntArray offsets = new IntArray();
130			int offset = 0;
131			
132			BaseGeometry geom;
133			
134			if (ogreSubmesh.useSharedVertices) {
135				geom = ogreMesh.getSharedgeometry();
136			} else {
137				geom = ogreSubmesh.getGeometry();
138			}
139			
140			for (int j = 0; j < geom.getVertexbuffer().size(); j++) {
141				Vertexbuffer buffer = geom.getVertexbuffer().get(j);
142				offsets.add(offset);
143				if (buffer.positions) {
144					attributes.add(new VertexAttribute(Usage.Position, 3, ShaderProgram.POSITION_ATTRIBUTE));
145					offset += 3;
146				}
147				if (buffer.normals) {
148					attributes.add(new VertexAttribute(Usage.Normal, 3, ShaderProgram.NORMAL_ATTRIBUTE));
149					offset += 3;
150				}
151				if (buffer.tangents) {
152					attributes.add(new VertexAttribute(Usage.Generic, buffer.tangentDimensions, ShaderProgram.TANGENT_ATTRIBUTE));
153					offset += buffer.tangentDimensions;
154				}
155				if (buffer.binormals) {
156					attributes.add(new VertexAttribute(Usage.Generic, 3, ShaderProgram.BINORMAL_ATTRIBUTE));
157					offset += 3;
158				}
159				if (buffer.coloursDiffuse) {
160					attributes.add(new VertexAttribute(Usage.ColorPacked, 4, ShaderProgram.COLOR_ATTRIBUTE));
161					offset += 4;
162				}
163
164				for (int k = 0; k < buffer.textureCoords; k++) {
165					try {
166						int numTexCoords = 0;
167						switch (k) {
168						case 0:
169							numTexCoords = Integer.valueOf(buffer.getTextureCoordDimensions0());
170							break;
171						case 1:
172							numTexCoords = Integer.valueOf(buffer.getTextureCoordDimensions1());
173							break;
174						case 2:
175							numTexCoords = Integer.valueOf(buffer.getTextureCoordDimensions2());
176							break;
177						case 3:
178							numTexCoords = Integer.valueOf(buffer.getTextureCoordDimensions3());
179							break;
180						case 4:
181							numTexCoords = Integer.valueOf(buffer.getTextureCoordDimensions4());
182							break;
183						case 5:
184							numTexCoords = Integer.valueOf(buffer.getTextureCoordDimensions5());
185							break;
186						case 6:
187							numTexCoords = Integer.valueOf(buffer.getTextureCoordDimensions6());
188							break;
189						case 7:
190							numTexCoords = Integer.valueOf(buffer.getTextureCoordDimensions7());
191							break;
192						}
193						attributes
194							.add(new VertexAttribute(Usage.TextureCoordinates, numTexCoords, ShaderProgram.TEXCOORD_ATTRIBUTE + k));
195						offset += numTexCoords;
196					} catch (NumberFormatException e) {
197						throw new GdxRuntimeException("Can't process texture coords with dimensions != 1, 2, 3, 4 (e.g. float1)");
198					}
199				}
200			}
201			VertexAttributes attribs = new VertexAttributes(attributes.toArray(new VertexAttribute[0]));
202			int vertexSize = offset;
203			float[] vertices = new float[geom.getVertexCount() * offset];
204			for (int j = 0; j < geom.getVertexbuffer().size(); j++) {
205				Vertexbuffer buffer = geom.getVertexbuffer().get(j);
206				offset = offsets.get(j);
207				int idx = offset;
208
209				for (int k = 0; k < buffer.getVertex().size(); k++) {
210					Vertex v = buffer.getVertex().get(k);
211					if (v.getPosition() != null) {
212						vertices[idx++] = v.getPosition().x;
213						vertices[idx++] = v.getPosition().y;
214						vertices[idx++] = v.getPosition().z;
215					}
216
217					if (v.getNormal() != null) {
218						vertices[idx++] = v.getNormal().x;
219						vertices[idx++] = v.getNormal().y;
220						vertices[idx++] = v.getNormal().z;
221					}
222
223					if (v.getTangent() != null) {
224						vertices[idx++] = v.getTangent().x;
225						vertices[idx++] = v.getTangent().y;
226						vertices[idx++] = v.getTangent().z;
227						if (buffer.tangentDimensions == 4) vertices[idx++] = v.getTangent().w;
228					}
229
230					if (v.getBinormal() != null) {
231						vertices[idx++] = v.getBinormal().x;
232						vertices[idx++] = v.getBinormal().y;
233						vertices[idx++] = v.getBinormal().z;
234					}
235
236					if (v.getColourDiffuse() != null) {
237						float color = getColor(v.getColourDiffuse());
238						vertices[idx++] = color;
239					}
240
241					if (v.getTexcoord() != null) {
242						for (int l = 0; l < v.getTexcoord().size(); l++) {
243							Texcoord texCoord = v.getTexcoord().get(l);
244							int numTexCoords = 0;
245							switch (l) {
246							case 0:
247								numTexCoords = Integer.valueOf(buffer.getTextureCoordDimensions0());
248								break;
249							case 1:
250								numTexCoords = Integer.valueOf(buffer.getTextureCoordDimensions1());
251								break;
252							case 2:
253								numTexCoords = Integer.valueOf(buffer.getTextureCoordDimensions2());
254								break;
255							case 3:
256								numTexCoords = Integer.valueOf(buffer.getTextureCoordDimensions3());
257								break;
258							case 4:
259								numTexCoords = Integer.valueOf(buffer.getTextureCoordDimensions4());
260								break;
261							case 5:
262								numTexCoords = Integer.valueOf(buffer.getTextureCoordDimensions5());
263								break;
264							case 6:
265								numTexCoords = Integer.valueOf(buffer.getTextureCoordDimensions6());
266								break;
267							case 7:
268								numTexCoords = Integer.valueOf(buffer.getTextureCoordDimensions7());
269								break;
270							}
271
272							if (numTexCoords == 1) {
273								vertices[idx++] = texCoord.u;
274							}
275
276							if (numTexCoords == 2) {
277								vertices[idx++] = texCoord.u;
278								vertices[idx++] = texCoord.v;
279							}
280
281							if (numTexCoords == 3) {
282								vertices[idx++] = texCoord.u;
283								vertices[idx++] = texCoord.v;
284								vertices[idx++] = texCoord.w;
285							}
286
287							if (numTexCoords == 4) {
288								vertices[idx++] = texCoord.u;
289								vertices[idx++] = texCoord.v;
290								vertices[idx++] = texCoord.w;
291								vertices[idx++] = texCoord.x;
292							}
293						}
294					}
295
296					offset += vertexSize;
297					idx = offset;
298				}
299			}
300
301			com.badlogic.gdx.graphics.Mesh mesh = new com.badlogic.gdx.graphics.Mesh(false, vertices.length / vertexSize,
302				indices.length, attribs);
303			mesh.setIndices(indices);
304			mesh.setVertices(vertices);
305			
306			String meshName = "";
307			if(ogreMesh.getSubmeshnames() != null) {
308				List<Submeshname> names = ogreMesh.getSubmeshnames().getSubmeshname();
309				for(int n = 0; n < names.size(); ++n) {
310					if(Integer.parseInt(names.get(n).getIndex()) == i)
311						meshName = names.get(n).getName();
312				}
313			}
314
315			SubMesh subMesh;
316			Boneassignments boneAssigments = (ogreSubmesh.getBoneassignments() != null)? ogreSubmesh.getBoneassignments() : ogreMesh.getBoneassignments();			
317			
318			if (boneAssigments != null) {
319				subMesh = new SkeletonSubMesh(meshName, mesh, GL10.GL_TRIANGLES);
320			} else {
321				subMesh = new StillSubMesh(meshName, mesh, GL10.GL_TRIANGLES);
322			}
323			
324			// FIXME ? subMesh.materialName = ogreSubmesh.material;
325
326
327			if (boneAssigments != null) {
328				SkeletonSubMesh subSkelMesh = (SkeletonSubMesh) subMesh;
329				subSkelMesh.setVertices(vertices);
330				subSkelMesh.setIndices(indices);
331				subSkelMesh.skinnedVertices = new float[vertices.length];
332				System.arraycopy(subSkelMesh.vertices, 0, subSkelMesh.skinnedVertices, 0, subSkelMesh.vertices.length);
333				loadBones(boneAssigments, subSkelMesh);
334			}
335
336			if (ogreSubmesh.getOperationtype().equals("triangle_list")) subMesh.primitiveType = GL10.GL_TRIANGLES;
337			if (ogreSubmesh.getOperationtype().equals("triangle_fan")) subMesh.primitiveType = GL10.GL_TRIANGLE_FAN;
338			if (ogreSubmesh.getOperationtype().equals("triangle_strip")) subMesh.primitiveType = GL10.GL_TRIANGLE_STRIP;
339
340			submeshes[i] = subMesh;
341		}
342		return submeshes;
343	}
344
345	private void loadBones (Boneassignments boneAssigments, SkeletonSubMesh subMesh) {
346		Array<IntArray> boneAssignments = new Array<IntArray>();
347		Array<FloatArray> boneWeights = new Array<FloatArray>();
348		
349		for (int j = 0; j < subMesh.getMesh().getNumVertices(); j++) {
350			boneAssignments.add(new IntArray(4));
351			boneWeights.add(new FloatArray(4));
352		}
353		
354		List<Vertexboneassignment> vertexboneassignment = boneAssigments.getVertexboneassignment();
355		for (int j = 0; j < vertexboneassignment.size(); j++) {
356			Vertexboneassignment assignment = vertexboneassignment.get(j);
357			int boneIndex = assignment.boneindex;
358			int vertexIndex = assignment.vertexindex;
359			float weight = assignment.weight;
360
361			boneAssignments.get(vertexIndex).add(boneIndex);
362			boneWeights.get(vertexIndex).add(weight);
363		}
364
365		subMesh.boneAssignments = new int[boneAssignments.size][];
366		subMesh.boneWeights = new float[boneWeights.size][];
367		for (int j = 0; j < boneAssignments.size; j++) {
368			subMesh.boneAssignments[j] = new int[boneAssignments.get(j).size];
369			subMesh.boneWeights[j] = new float[boneWeights.get(j).size];
370			for (int k = 0; k < boneAssignments.get(j).size; k++) {
371				subMesh.boneAssignments[j][k] = boneAssignments.get(j).get(k);
372			}
373			for (int k = 0; k < boneWeights.get(j).size; k++) {
374				subMesh.boneWeights[j][k] = boneWeights.get(j).get(k);
375			}
376		}		
377	}
378
379	Color color = new Color();
380
381	private float getColor (ColourDiffuse colourDiffuse) {
382		String[] tokens = colourDiffuse.getValue().split(" ");
383		if (tokens.length == 3)
384			color.set(Float.valueOf(tokens[0]), Float.valueOf(tokens[1]), Float.valueOf(tokens[2]), 1);
385		else
386			color.set(Float.valueOf(tokens[0]), Float.valueOf(tokens[1]), Float.valueOf(tokens[2]), Float.valueOf(tokens[3]));
387		return color.toFloatBits();
388	}
389
390	private Mesh loadOgreMesh (InputStream in) throws JAXBException {
391		JAXBContext context = JAXBContext.newInstance(Mesh.class);
392		Unmarshaller unmarshaller = context.createUnmarshaller();
393		long start = System.nanoTime();
394		Mesh mesh = (Mesh)unmarshaller.unmarshal(in);
395		System.out.println("took: " + (System.nanoTime() - start) / 1000000000.0f);
396		return mesh;
397	}
398
399	public Skeleton loadSkeleton (FileHandle file) {
400		InputStream in = null;
401		try {
402			in = file.read();
403			return loadSkeleton(in);
404		} catch (Throwable t) {
405			throw new GdxRuntimeException("Couldn't load file '" + file.name() + "'", t);
406		} finally {
407			if (in != null) try {
408				in.close();
409			} catch (Exception e) {
410			}
411		}
412	}
413
414	public Skeleton loadSkeleton (InputStream in) {
415		try {
416			com.badlogic.gdx.graphics.g3d.loaders.ogre.skeleton.Skeleton ogreSkel = loadOgreSkeleton(in);
417			return generateSkeleton(ogreSkel);
418		} catch (Throwable t) {
419			throw new GdxRuntimeException("Couldn't load model", t);
420		}
421	}
422
423	private Skeleton generateSkeleton (com.badlogic.gdx.graphics.g3d.loaders.ogre.skeleton.Skeleton ogreSkel) {
424		List<Bone> bones = ogreSkel.getBones().getBone();
425		List<SkeletonJoint> joints = new ArrayList<SkeletonJoint>();
426		Map<String, SkeletonJoint> nameToJoint = new HashMap<String, SkeletonJoint>();
427		for (int i = 0; i < bones.size(); i++) {
428			Bone bone = bones.get(i);
429			SkeletonJoint joint = new SkeletonJoint();
430
431			joint.name = bone.name;
432			joint.position.set(bone.position.x, bone.position.y, bone.position.z);
433			joint.rotation.setFromAxis(bone.rotation.axis.x, bone.rotation.axis.y, bone.rotation.axis.z, MathUtils.radiansToDegrees
434				* bone.rotation.angle);
435			if (bone.scale != null) {
436				if (bone.scale.factor == 0)
437					joint.scale.set(bone.scale.x, bone.scale.y, bone.scale.z);
438				else
439					joint.scale.set(bone.scale.factor, bone.scale.factor, bone.scale.factor);
440			}
441			joints.add(joint);
442			nameToJoint.put(joint.name, joint);
443		}
444
445		List<Boneparent> hierarchy = ogreSkel.getBonehierarchy().getBoneparent();
446		for (int i = 0; i < hierarchy.size(); i++) {
447			Boneparent link = hierarchy.get(i);
448			SkeletonJoint joint = nameToJoint.get(link.getBone());
449			SkeletonJoint parent = nameToJoint.get(link.getParent());
450			parent.children.add(joint);
451			joint.parent = parent;
452		}
453
454		Skeleton skel = new Skeleton();
455		for (int i = 0; i < joints.size(); i++) {
456			SkeletonJoint joint = joints.get(i);
457			if (joint.parent == null) skel.hierarchy.add(joint);
458		}
459
460		skel.buildFromHierarchy();
461
462		List<Animation> animations = ogreSkel.getAnimations().getAnimation();
463		for (int i = 0; i < animations.size(); i++) {
464			Animation animation = animations.get(i);
465			SkeletonKeyframe[][] perJointkeyFrames = new SkeletonKeyframe[skel.bindPoseJoints.size][];
466
467			List<Track> tracks = animation.getTracks().getTrack();
468			if (tracks.size() != perJointkeyFrames.length)
469				throw new IllegalArgumentException("Number of tracks does not equal number of joints");
470
471			Matrix4 rotation = new Matrix4();
472			Matrix4 transform = new Matrix4();
473
474			for (int j = 0; j < tracks.size(); j++) {
475				Track track = tracks.get(j);
476				String jointName = track.getBone();
477				int jointIndex = skel.namesToIndices.get(jointName);
478				if (perJointkeyFrames[jointIndex] != null)
479					throw new IllegalArgumentException("Track for bone " + jointName + " in animation " + animation.name
480						+ " already defined!");
481				SkeletonKeyframe[] jointKeyFrames = new SkeletonKeyframe[track.getKeyframes().getKeyframe().size()];
482				perJointkeyFrames[jointIndex] = jointKeyFrames;
483
484				for (int k = 0; k < track.getKeyframes().getKeyframe().size(); k++) {
485					Keyframe keyFrame = track.getKeyframes().getKeyframe().get(k);
486					SkeletonKeyframe jointKeyframe = new SkeletonKeyframe();
487					jointKeyframe.timeStamp = keyFrame.time;
488					jointKeyframe.position.set(keyFrame.translate.x, keyFrame.translate.y, keyFrame.translate.z);
489					if (keyFrame.scale != null) {
490						if (keyFrame.scale.factor == 0)
491							jointKeyframe.scale.set(keyFrame.scale.x, keyFrame.scale.y, keyFrame.scale.z);
492						else
493							jointKeyframe.scale.set(keyFrame.scale.factor, keyFrame.scale.factor, keyFrame.scale.factor);
494					}
495					jointKeyframe.rotation
496						.setFromAxis(keyFrame.rotate.axis.x, keyFrame.rotate.axis.y, keyFrame.rotate.axis.z,
497							MathUtils.radiansToDegrees * keyFrame.rotate.angle).nor();
498					jointKeyframe.parentIndex = skel.bindPoseJoints.get(jointIndex).parentIndex;
499					jointKeyFrames[k] = jointKeyframe;
500
501					rotation.set(jointKeyframe.rotation);
502					rotation.trn(jointKeyframe.position);
503					transform.set(skel.sceneMatrices.get(jointIndex));
504					transform.mul(rotation);
505					if (jointKeyframe.parentIndex != -1) {
506						rotation.set(skel.offsetMatrices.get(jointKeyframe.parentIndex)).mul(transform);
507						transform.set(rotation);
508					}
509
510					transform.getTranslation(jointKeyframe.position);
511					transform.getRotation(jointKeyframe.rotation);
512				}
513			}
514
515			for (int j = 0; j < perJointkeyFrames.length; j++) {
516				if (perJointkeyFrames[j] == null) throw new IllegalArgumentException("No track for bone " + skel.jointNames.get(j));
517			}
518
519			skel.animations.put(animation.name, new SkeletonAnimation(animation.name, animation.length, perJointkeyFrames));
520		}
521
522		return skel;
523	}
524
525	private com.badlogic.gdx.graphics.g3d.loaders.ogre.skeleton.Skeleton loadOgreSkeleton (InputStream in) throws JAXBException {
526		JAXBContext context = JAXBContext.newInstance(com.badlogic.gdx.graphics.g3d.loaders.ogre.skeleton.Skeleton.class);
527		Unmarshaller unmarshaller = context.createUnmarshaller();
528		long start = System.nanoTime();
529		com.badlogic.gdx.graphics.g3d.loaders.ogre.skeleton.Skeleton skel = (com.badlogic.gdx.graphics.g3d.loaders.ogre.skeleton.Skeleton)unmarshaller
530			.unmarshal(in);
531		System.out.println("took: " + (System.nanoTime() - start) / 1000000000.0f);
532		return skel;
533	}
534}