/******************************************************************************* * Copyright 2011 See AUTHORS file. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the * specific language governing permissions and limitations under the License. ******************************************************************************/ package com.badlogic.gdx.graphics.g3d.loaders.g3d.chunks; import java.io.IOException; import java.io.OutputStream; import com.badlogic.gdx.files.FileHandle; import com.badlogic.gdx.graphics.VertexAttribute; import com.badlogic.gdx.graphics.g3d.loaders.g3d.G3dConstants; import com.badlogic.gdx.graphics.g3d.model.keyframe.Keyframe; import com.badlogic.gdx.graphics.g3d.model.keyframe.KeyframedAnimation; import com.badlogic.gdx.graphics.g3d.model.keyframe.KeyframedModel; import com.badlogic.gdx.graphics.g3d.model.keyframe.KeyframedSubMesh; import com.badlogic.gdx.graphics.g3d.model.skeleton.SkeletonAnimation; import com.badlogic.gdx.graphics.g3d.model.skeleton.SkeletonJoint; import com.badlogic.gdx.graphics.g3d.model.skeleton.SkeletonKeyframe; import com.badlogic.gdx.graphics.g3d.model.skeleton.SkeletonModel; import com.badlogic.gdx.graphics.g3d.model.skeleton.SkeletonSubMesh; import com.badlogic.gdx.graphics.g3d.model.still.StillModel; import com.badlogic.gdx.graphics.g3d.model.still.StillSubMesh; import com.badlogic.gdx.utils.GdxRuntimeException; public class G3dExporter { public static void export(StillModel model, FileHandle file) { ChunkWriter writer = new ChunkWriter(); // write version info writer.newChunk(G3dConstants.VERSION_INFO); writer.writeByte(G3dConstants.MAJOR_VERSION); writer.writeByte(G3dConstants.MINOR_VERSION); writer.endChunk(); // write still model writer.newChunk(G3dConstants.STILL_MODEL); writer.writeInt(model.subMeshes.length); // write sub mesh for (StillSubMesh mesh : model.subMeshes) { // start sub mesh writer.newChunk(G3dConstants.STILL_SUBMESH); writer.writeString(mesh.name == null ? "" : mesh.name); writer.writeInt(mesh.primitiveType); // write vertex attributes writer.newChunk(G3dConstants.VERTEX_ATTRIBUTES); writer.writeInt(mesh.mesh.getVertexAttributes().size()); for (int i = 0; i < mesh.mesh.getVertexAttributes().size(); i++) { VertexAttribute attribute = mesh.mesh.getVertexAttributes().get(i); writer.newChunk(G3dConstants.VERTEX_ATTRIBUTE); writer.writeInt(attribute.usage); writer.writeInt(attribute.numComponents); writer.writeString(attribute.alias); writer.endChunk(); } writer.endChunk(); // write vertices writer.newChunk(G3dConstants.VERTEX_LIST); int numFloats = mesh.mesh.getNumVertices() * mesh.mesh.getVertexSize() / 4; float[] vertices = new float[numFloats]; mesh.mesh.getVertices(vertices); writer.writeInt(mesh.mesh.getNumVertices()); writer.writeFloats(vertices); writer.endChunk(); // write indices writer.newChunk(G3dConstants.INDEX_LIST); int numShorts = mesh.mesh.getNumIndices(); short[] indices = new short[numShorts]; mesh.mesh.getIndices(indices); writer.writeInt(numShorts); writer.writeShorts(indices); writer.endChunk(); // end sub mesh writer.endChunk(); } // end still model writer.endChunk(); // write to file OutputStream out = null; try { out = file.write(false); writer.writeToStream(out); } catch (IOException e) { throw new GdxRuntimeException("An error occured while exporting the still model, " + e.getMessage(), e); } finally { if (out != null) try { out.close(); } catch (IOException e) { } } } public static void export(KeyframedModel model, FileHandle file) { ChunkWriter writer = new ChunkWriter(); // write version info writer.newChunk(G3dConstants.VERSION_INFO); writer.writeByte(G3dConstants.MAJOR_VERSION); writer.writeByte(G3dConstants.MINOR_VERSION); writer.endChunk(); // write keyframed model writer.newChunk(G3dConstants.KEYFRAMED_MODEL); writer.writeInt(model.subMeshes.length); for (KeyframedSubMesh mesh : model.subMeshes) { // writes keyframed submesh writer.newChunk(G3dConstants.KEYFRAMED_SUBMESH); writer.writeString(mesh.name == null ? "" : mesh.name); writer.writeInt(mesh.primitiveType); writer.writeInt(mesh.animatedComponents); writer.writeInt(mesh.animations.size); // write vertex attributes writer.newChunk(G3dConstants.VERTEX_ATTRIBUTES); writer.writeInt(mesh.mesh.getVertexAttributes().size()); for (int i = 0; i < mesh.mesh.getVertexAttributes().size(); i++) { VertexAttribute attribute = mesh.mesh.getVertexAttributes().get(i); writer.newChunk(G3dConstants.VERTEX_ATTRIBUTE); writer.writeInt(attribute.usage); writer.writeInt(attribute.numComponents); writer.writeString(attribute.alias); writer.endChunk(); } writer.endChunk(); // write static components, sort of like a bind pose mesh writer.newChunk(G3dConstants.VERTEX_LIST); int numFloats = mesh.mesh.getNumVertices() * mesh.mesh.getVertexSize() / 4; float[] vertices = new float[numFloats]; mesh.mesh.getVertices(vertices); writer.writeInt(mesh.mesh.getNumVertices()); writer.writeFloats(vertices); writer.endChunk(); // write indices writer.newChunk(G3dConstants.INDEX_LIST); int numShorts = mesh.mesh.getNumIndices(); short[] indices = new short[numShorts]; mesh.mesh.getIndices(indices); writer.writeInt(mesh.mesh.getNumIndices()); writer.writeShorts(indices); writer.endChunk(); // write animations for (String animationName : mesh.animations.keys()) { KeyframedAnimation animation = mesh.animations.get(animationName); // write keyframed animation writer.newChunk(G3dConstants.KEYFRAMED_ANIMATION); writer.writeString(animation.name); writer.writeFloat(animation.frameDuration); // write key frames writer.writeInt(animation.keyframes.length); for (Keyframe keyframe : animation.keyframes) { // write keyframed writer.newChunk(G3dConstants.KEYFRAMED_FRAME); writer.writeFloat(keyframe.timeStamp); writer.writeFloats(keyframe.vertices); writer.endChunk(); } // end keyframed animation writer.endChunk(); } // end keyframed submesh writer.endChunk(); } // end keyframed model writer.endChunk(); // write to file OutputStream out = null; try { out = file.write(false); writer.writeToStream(out); } catch (IOException e) { throw new GdxRuntimeException("An error occured while exporting the still model, " + e.getMessage(), e); } finally { if (out != null) try { out.close(); } catch (IOException e) { } } } public static void export(SkeletonModel model, FileHandle file) { ChunkWriter writer = new ChunkWriter(); // write version info writer.newChunk(G3dConstants.VERSION_INFO); writer.writeByte(G3dConstants.MAJOR_VERSION); writer.writeByte(G3dConstants.MINOR_VERSION); writer.endChunk(); // write skeleton model writer.newChunk(G3dConstants.SKELETON_MODEL); writer.writeInt(model.subMeshes.length); for (SkeletonSubMesh mesh : model.subMeshes) { // writes skeleton submesh writer.newChunk(G3dConstants.SKELETON_SUBMESH); writer.writeString(mesh.name == null ? "" : mesh.name); writer.writeInt(mesh.primitiveType); // write vertex attributes writer.newChunk(G3dConstants.VERTEX_ATTRIBUTES); writer.writeInt(mesh.mesh.getVertexAttributes().size()); for (int i = 0; i < mesh.mesh.getVertexAttributes().size(); i++) { VertexAttribute attribute = mesh.mesh.getVertexAttributes().get(i); writer.newChunk(G3dConstants.VERTEX_ATTRIBUTE); writer.writeInt(attribute.usage); writer.writeInt(attribute.numComponents); writer.writeString(attribute.alias); writer.endChunk(); } writer.endChunk(); // write static components, sort of like a bind pose mesh writer.newChunk(G3dConstants.VERTEX_LIST); int numFloats = mesh.mesh.getNumVertices() * mesh.mesh.getVertexSize() / 4; writer.writeInt(mesh.mesh.getNumVertices()); writer.writeFloats(mesh.vertices); writer.endChunk(); // write indices writer.newChunk(G3dConstants.INDEX_LIST); int numShorts = mesh.mesh.getNumIndices(); writer.writeInt(numShorts); writer.writeShorts(mesh.indices); writer.endChunk(); // write bone weight writer.newChunk(G3dConstants.BONE_WEIGHTS); writer.writeInt(mesh.boneWeights.length); for (float array[] : mesh.boneWeights) { writer.newChunk(G3dConstants.BONE_WEIGHT); writer.writeInt(array.length); writer.writeFloats(array); writer.endChunk(); } writer.endChunk(); // write bone assignment writer.newChunk(G3dConstants.BONE_ASSIGNMENTS); writer.writeInt(mesh.boneAssignments.length); for (int array[] : mesh.boneAssignments) { writer.newChunk(G3dConstants.BONE_ASSIGNMENT); writer.writeInt(array.length); writer.writeInts(array); writer.endChunk(); } writer.endChunk(); // end skeleton submesh writer.endChunk(); } //Write Skeleton writer.newChunk(G3dConstants.SKELETON); //Write Skeleton hierarchy writer.newChunk(G3dConstants.SKELETON_HIERARCHY); writer.writeInt(model.skeleton.hierarchy.size); for (SkeletonJoint joint : model.skeleton.hierarchy) { writeSkeletonJoint(writer, joint); } // end Skeleton hierarchy writer.endChunk(); //Write Skeleton animations writer.newChunk(G3dConstants.SKELETON_ANIMATIONS); writer.writeInt(model.skeleton.animations.size); for (String animationName : model.skeleton.animations.keys()) { writer.newChunk(G3dConstants.SKELETON_ANIMATION); writer.writeString(animationName); SkeletonAnimation animation = model.skeleton.animations.get(animationName); writer.writeFloat(animation.totalDuration); writer.writeInt(animation.perJointkeyFrames.length); for (SkeletonKeyframe array[] : animation.perJointkeyFrames) { writer.writeInt(array.length); for (SkeletonKeyframe frame : array) { writer.writeFloat(frame.timeStamp); writer.writeInt(frame.parentIndex); writer.writeFloat(frame.position.x); writer.writeFloat(frame.position.y); writer.writeFloat(frame.position.z); writer.writeFloat(frame.rotation.w); writer.writeFloat(frame.rotation.x); writer.writeFloat(frame.rotation.y); writer.writeFloat(frame.rotation.z); writer.writeFloat(frame.scale.x); writer.writeFloat(frame.scale.y); writer.writeFloat(frame.scale.z); } } writer.endChunk(); } // end Skeleton animations writer.endChunk(); // end Skeleton writer.endChunk(); // end skeleton model writer.endChunk(); // write to file OutputStream out = null; try { out = file.write(false); writer.writeToStream(out); } catch (IOException e) { throw new GdxRuntimeException("An error occured while exporting the still model, " + e.getMessage(), e); } finally { if (out != null) try { out.close(); } catch (IOException e) { } } } private static void writeSkeletonJoint(ChunkWriter writer, SkeletonJoint joint) { writer.writeString(joint.name); writer.writeFloat(joint.position.x); writer.writeFloat(joint.position.y); writer.writeFloat(joint.position.z); writer.writeFloat(joint.rotation.w); writer.writeFloat(joint.rotation.x); writer.writeFloat(joint.rotation.y); writer.writeFloat(joint.rotation.z); writer.writeFloat(joint.scale.x); writer.writeFloat(joint.scale.y); writer.writeFloat(joint.scale.z); writer.writeInt(joint.children.size); for (SkeletonJoint child : joint.children) { writeSkeletonJoint(writer, child); } } }