package rajawali.parser.md5; import java.io.BufferedReader; import java.io.FileNotFoundException; import java.io.FileReader; import java.io.InputStream; import java.io.InputStreamReader; import java.util.StringTokenizer; import rajawali.animation.mesh.BoneAnimationFrame; import rajawali.animation.mesh.BoneAnimationSequence; import rajawali.animation.mesh.IAnimationSequence; import rajawali.animation.mesh.Skeleton; import rajawali.animation.mesh.SkeletonJoint; import rajawali.math.Number3D; import rajawali.parser.AParser; import rajawali.parser.IAnimationSequenceParser; import rajawali.renderer.RajawaliRenderer; import rajawali.util.RajLog; public class MD5AnimParser extends AParser implements IAnimationSequenceParser { private static final String MD5_VERSION = "MD5Version"; private static final String COMMAND_LINE = "commandline"; private static final String NUM_JOINTS = "numJoints"; private static final String NUM_FRAMES = "numFrames"; private static final String FRAME_RATE = "frameRate"; private static final String NUM_ANIMATED_COMPONENTS = "numAnimatedComponents"; private static final String HIERARCHY = "hierarchy"; private static final String BOUNDS = "bounds"; private static final String BASEFRAME = "baseframe"; private static final String FRAME = "frame"; private BoneAnimationSequence mSequence; private String mAnimationName; private SkeletonJoint[] mBaseFrame; private SkeletonJoint[] mJoints; private int mNumJoints; private int mNumAnimatedComponents; public MD5AnimParser(String animationName, RajawaliRenderer renderer, String fileOnSDCard) { super(renderer, fileOnSDCard); mAnimationName = animationName; } public MD5AnimParser(String animationName, RajawaliRenderer renderer, int resourceId) { super(renderer, resourceId); mAnimationName = animationName; } public MD5AnimParser parse() throws ParsingException { super.parse(); BufferedReader buffer = null; if(mFile == null) { InputStream fileIn = mResources.openRawResource(mResourceId); buffer = new BufferedReader(new InputStreamReader(fileIn)); } else { try { buffer = new BufferedReader(new FileReader(mFile)); } catch (FileNotFoundException e) { RajLog.e("["+getClass().getCanonicalName()+"] Could not find file."); e.printStackTrace(); } } mSequence = new BoneAnimationSequence(mAnimationName); BoneAnimationFrame[] frames = null; String line; try { while((line = buffer.readLine()) != null) { line = line.replace("\t", " "); StringTokenizer parts = new StringTokenizer(line, " "); int numTokens = parts.countTokens(); if(numTokens == 0) continue; String type = parts.nextToken(); if(type.equalsIgnoreCase(MD5_VERSION)) { } else if(type.equalsIgnoreCase(COMMAND_LINE)) { } else if(type.equalsIgnoreCase(NUM_JOINTS)) { mNumJoints = Integer.parseInt(parts.nextToken()); mJoints = new SkeletonJoint[mNumJoints]; } else if(type.equalsIgnoreCase(NUM_FRAMES)) { mSequence.setNumFrames(Integer.parseInt(parts.nextToken())); frames = new BoneAnimationFrame[mSequence.getNumFrames()]; } else if(type.equalsIgnoreCase(FRAME_RATE)) { mSequence.setFrameRate(Integer.parseInt(parts.nextToken())); } else if(type.equalsIgnoreCase(NUM_ANIMATED_COMPONENTS)) { mNumAnimatedComponents = Integer.parseInt(parts.nextToken()); } else if(type.equalsIgnoreCase(HIERARCHY)) { parseHierarchy(buffer); } else if(type.equalsIgnoreCase(BOUNDS)) { parseBounds(frames, buffer); } else if(type.equalsIgnoreCase(FRAME)) { parseFrame(frames, Integer.parseInt(parts.nextToken()), buffer); } else if(type.equalsIgnoreCase(BASEFRAME)) { mBaseFrame = new SkeletonJoint[mNumJoints]; parseBaseFrame(buffer); } } buffer.close(); } catch(Exception e) { e.printStackTrace(); } mSequence.setFrames(frames); return this; } public IAnimationSequence getParsedAnimationSequence() { return mSequence; } private void parseHierarchy(BufferedReader buffer) { try { String line; int index = 0; while((line = buffer.readLine()) != null) { line = line.replace("\t", " "); StringTokenizer parts = new StringTokenizer(line, " "); int numTokens = parts.countTokens(); if(line.indexOf('}') > -1) return; if(numTokens == 0) continue; SkeletonJoint joint = new SkeletonJoint(); joint.setIndex(index); joint.setName(parts.nextToken()); joint.setParentIndex(Integer.parseInt(parts.nextToken())); joint.setFlags(Integer.parseInt(parts.nextToken())); joint.setStartIndex(Integer.parseInt(parts.nextToken())); mJoints[index++] = joint; } } catch(Exception e) { e.printStackTrace(); } } private void parseBounds(BoneAnimationFrame[] frames, BufferedReader buffer) { try { String line; int index = 0; while((line = buffer.readLine()) != null) { StringTokenizer parts = new StringTokenizer(line, " "); int numTokens = parts.countTokens(); if(line.indexOf('}') > -1) return; if(numTokens == 0) continue; BoneAnimationFrame frame = new BoneAnimationFrame(); frames[index++] = frame; // discard ( parts.nextToken(); Number3D min = new Number3D(Float.parseFloat(parts.nextToken()), Float.parseFloat(parts.nextToken()), Float.parseFloat(parts.nextToken())); // discard ) parts.nextToken(); // discard ( parts.nextToken(); Number3D max = new Number3D(Float.parseFloat(parts.nextToken()), Float.parseFloat(parts.nextToken()), Float.parseFloat(parts.nextToken())); frame.setBounds(min, max); } } catch(Exception e) { e.printStackTrace(); } } private void parseFrame(BoneAnimationFrame[] frames, int frameIndex, BufferedReader buffer) { try { String line; BoneAnimationFrame frame = frames[frameIndex]; frame.setFrameIndex(frameIndex); Skeleton skeleton = frame.getSkeleton(); SkeletonJoint[] joints = new SkeletonJoint[mNumJoints]; float[] frameData = new float[mNumAnimatedComponents]; int index = 0; while((line = buffer.readLine()) != null) { line = line.replace("\t", " "); StringTokenizer parts = new StringTokenizer(line, " "); if(line.indexOf('}') > -1) { skeleton.setJoints(joints); buildFrameSkeleton(frameData, skeleton); return; } while(parts.hasMoreTokens()) { frameData[index++] = Float.parseFloat(parts.nextToken()); } } } catch(Exception e) { e.printStackTrace(); } } private void buildFrameSkeleton(float[] frameData, Skeleton skeleton) { for(int i=0; i<mNumJoints; ++i) { SkeletonJoint joint = new SkeletonJoint(mBaseFrame[i]); SkeletonJoint jointInfo = mJoints[i]; joint.setParentIndex(jointInfo.getParentIndex()); int j = 0; int startIndex = jointInfo.getStartIndex(); if((jointInfo.getFlags() & 1) == 1) joint.getPosition().x = frameData[startIndex + j++]; if((jointInfo.getFlags() & 2) == 2) joint.getPosition().z = frameData[startIndex + j++]; if((jointInfo.getFlags() & 4) == 4) joint.getPosition().y = frameData[startIndex + j++]; if((jointInfo.getFlags() & 8) == 8) joint.getOrientation().x = frameData[startIndex + j++]; if((jointInfo.getFlags() & 16) == 16) joint.getOrientation().z = frameData[startIndex + j++]; if((jointInfo.getFlags() & 32) == 32) joint.getOrientation().y = frameData[startIndex + j++]; joint.getOrientation().computeW(); if (joint.getParentIndex() >= 0 ) // Has a parent joint { SkeletonJoint parentJoint = skeleton.getJoint(joint.getParentIndex()); Number3D rotPos = parentJoint.getOrientation().multiply(joint.getPosition()).clone(); joint.getPosition().setAllFrom(Number3D.add(parentJoint.getPosition(), rotPos)); joint.getOrientation().multiply(parentJoint.getOrientation()); joint.getOrientation().normalize(); } skeleton.setJoint(i, joint); } } private void parseBaseFrame(BufferedReader buffer) { try { String line; int index = 0; while((line = buffer.readLine()) != null) { line = line.replace("\t", " "); StringTokenizer parts = new StringTokenizer(line, " "); int numTokens = parts.countTokens(); if(line.indexOf('}') > -1) return; if(numTokens == 0) continue; SkeletonJoint joint = new SkeletonJoint(); mBaseFrame[index++] = joint; // ignore "(" parts.nextToken(); float x = Float.parseFloat(parts.nextToken()); float y = Float.parseFloat(parts.nextToken()); float z = Float.parseFloat(parts.nextToken()); joint.setPosition(x, z, y); // ignore ")" parts.nextToken(); // ignore "(" parts.nextToken(); x = Float.parseFloat(parts.nextToken()); y = Float.parseFloat(parts.nextToken()); z = Float.parseFloat(parts.nextToken()); joint.setOrientation(x, z, y); joint.getOrientation().computeW(); } } catch(Exception e) { e.printStackTrace(); } } }