md3 animation controller

I had to tune the current md3 loader to meet my requirements.

Md2 allready had a way to get the keyController, now md3 has as well.



I just pasted the whole code, but there are only small changes:



One new (public) method: findController, which returns the controller, and I attached to controller to the toReturn Node, so i can actually find the controller.



Usage of this class can be used like this ( the same a an md2 controller ):



converter.convert(md3File.openStream(), BO);
JmeBinaryReader jbr = new JmeBinaryReader();
Node r = jbr.loadBinaryFormat(new ByteArrayInputStream(BO.toByteArray()));               
r.setLocalScale(0.01f);
Md3ToJme.findController((Node)r).setSpeed(100);




Cheers.



package com.jme.scene.model.XMLparser.Converters;

import com.jme.util.BinaryFileReader;
import com.jme.math.Vector3f;
import com.jme.math.Matrix3f;
import com.jme.math.Vector2f;
import com.jme.math.FastMath;
import com.jme.scene.Node;
import com.jme.scene.TriMesh;
import com.jme.scene.model.XMLparser.JmeBinaryWriter;
import com.jme.scene.model.EmptyTriMesh;
import com.jme.animation.KeyframeController;

import java.io.InputStream;
import java.io.OutputStream;
import java.io.IOException;

/**
 * Started Date: Jul 15, 2004<br><br>
 *
 * Converts from MD3 files to jme binary.
 *
 * @author Jack Lindamood
 */
public class Md3ToJme extends FormatConverter{
    private BinaryFileReader file;
    private MD3Header head;
    private MD3Frame[] frames;
    private MD3Tag[][] tags;
    private MD3Surface[] surfaces;
   KeyframeController vkc;
    public void convert(InputStream format, OutputStream jMEFormat) throws IOException {
        file=new BinaryFileReader(format);
        readHeader();
        readFrames();
        readTags();
        readSurfaces();
        JmeBinaryWriter jbw=new JmeBinaryWriter();
        jbw.writeScene(constructMesh(),jMEFormat);
    }

    private Node constructMesh() {
        Node toReturn=new Node("MD3 File");
        for (int i=0;i<head.numSurface;i++){
            vkc =new KeyframeController();
            MD3Surface thisSurface=surfaces[i];
            TriMesh object=new TriMesh(thisSurface.name);
            object.setIndices(thisSurface.triIndexes);
            object.setVertices(thisSurface.verts[0]);
            object.setNormals(thisSurface.norms[0]);
            object.setTextures(thisSurface.texCoords);
            toReturn.attachChild(object);
            vkc.setMorphingMesh(object);
            for (int j=0;j<head.numFrames;j++){
                EmptyTriMesh etm=new EmptyTriMesh();
                etm.setVertices(thisSurface.verts[j]);
                etm.setNormals(thisSurface.norms[j]);
                vkc.setKeyframe(j,etm);
            }
            vkc.setActive(true);
            vkc.setSpeed(5);
            object.addController(vkc);
            toReturn.addController(vkc);
        }
        nullAll();
        return toReturn;
    }

   public KeyframeController getController() {
      return this.vkc;
   }

    private void nullAll() {
        frames=null;
        tags=null;
        surfaces=null;
        head=null;
        file=null;
    }

   public static KeyframeController findController(Node model) {
      if (model.getQuantity()==0 ||
            model.getChild(0).getControllers().size()==0 ||
            !(model.getChild(0).getController(0) instanceof KeyframeController))
         return null;
      return (KeyframeController) model.getChild(0).getController(0);
   }

    private void readSurfaces() throws IOException {
        file.setOffset(head.surfaceOffset);
        surfaces=new MD3Surface[head.numSurface];
        for (int i=0;i<head.numSurface;i++){
            surfaces[i]=new MD3Surface();
            surfaces[i].readMe();
        }
    }

    private void readTags() {
        file.setOffset(head.tagOffset);
        tags=new MD3Tag[head.numFrames][];
        for (int i=0;i<head.numFrames;i++){
            tags[i]=new MD3Tag[head.numTags];
            for (int j=0;j<head.numTags;j++){
                tags[i][j]=new MD3Tag();
                tags[i][j].readMe();
            }
        }

    }

    private void readFrames() {
        file.setOffset(head.frameOffset);
        frames=new MD3Frame[head.numFrames];
        for (int i=0;i<head.numFrames;i++){
            frames[i]=new MD3Frame();
            frames[i].readMe();
        }
    }

    private void readHeader() throws IOException {
        head=new MD3Header();
        head.readMe();
    }

    private class MD3Header{
        int version;
        String name;
        int flags;
        int numFrames;
        int numTags;
        int numSurface;
        int numSkins;
        int frameOffset;
        int tagOffset;
        int surfaceOffset;
        int fileOffset;
        void readMe() throws IOException {
            int ident=file.readInt();
            if (ident!=0x33504449)
                throw new IOException("Unknown file format:"+ident);
            version=file.readInt();
            if (version!=15)
                throw new IOException("Unsupported version " + version + ", only know ver 15");
            name=file.readString(64);
            flags=file.readInt();
            numFrames=file.readInt();
            numTags=file.readInt();
            numSurface=file.readInt();
            numSkins=file.readInt();
            frameOffset=file.readInt();
            tagOffset=file.readInt();
            surfaceOffset=file.readInt();
            fileOffset=file.readInt();
        }
    }
    private class MD3Frame{
        Vector3f minBounds=new Vector3f();
        Vector3f maxBounds=new Vector3f();
        Vector3f localOrigin=new Vector3f();
        float scale;
        String name;
        void readMe(){
            readVecFloat(minBounds);
            readVecFloat(maxBounds);
            readVecFloat(localOrigin);
            scale=file.readFloat();
            name=file.readString(16);
        }
    }

    private class MD3Tag{
        String path;
        Vector3f origin=new Vector3f();
        Matrix3f axis;
        void readMe(){
            path=file.readString(64);
            readVecFloat(origin);
            float[] axisFs=new float[9];
            for (int i=0;i<9;i++)
                axisFs[i]=file.readFloat();
            axis=new Matrix3f();
            axis.set(axisFs);
        }
    }

    private class MD3Surface{
        String name;
        int flags;
        int numFrames;
        int numShaders;
        int numVerts;
        int numTriangles;
        int offTriangles;
        int offShaders;
        int offTexCoord;
        int offXyzNor;
        int offEnd;
        int[] triIndexes;
        Vector2f[] texCoords;
        Vector3f[][] verts;
        Vector3f[][] norms;
        private final static float XYZ_SCALE=1.0f/64;
        private static final boolean DEBUG = false;

        public void readMe() throws IOException {
            file.markPos();
            int ident=file.readInt();
            if (ident!=0x33504449)
                throw new IOException("Unknown file format:"+ident);
            name=file.readString(64);
            flags=file.readInt();
            numFrames=file.readInt();
            numShaders=file.readInt();
            numVerts=file.readInt();
            numTriangles=file.readInt();
            offTriangles=file.readInt();
            offShaders=file.readInt();
            offTexCoord=file.readInt();
            offXyzNor=file.readInt();
            offEnd=file.readInt();
//            readShader();            // Skip shader info
            readTriangles();
            readTexCoord();
            readVerts();
        }

        private void readVerts() {
            file.seekMarkOffset(offXyzNor);
            verts=new Vector3f[head.numFrames][];
            norms=new Vector3f[head.numFrames][];
            for (int i=0;i<head.numFrames;i++){
                verts[i]=new Vector3f[numVerts];
                norms[i]=new Vector3f[numVerts];
                for (int j=0;j<numVerts;j++){
                    verts[i][j]=new Vector3f();
                    norms[i][j]=new Vector3f();
                    readVecShort(verts[i][j]);
                    readNormal(norms[i][j]);
                }
            }
        }

        private void readVecShort(Vector3f vector3f) {
            vector3f.z = file.readSignedShort()*XYZ_SCALE;
            vector3f.x = file.readSignedShort()*XYZ_SCALE;
            vector3f.y = file.readSignedShort()*XYZ_SCALE;
        }

        private void readNormal(Vector3f norm) {
            int lng=file.readByte();
            int lat=file.readByte();
            float newlat=(lat*2*FastMath.PI)/255;
            float newlng=(lng*2*FastMath.PI)/255;
            norm.x = FastMath.cos(newlat)*FastMath.sin(newlng);
            norm.y = FastMath.sin(newlat)*FastMath.sin(newlng);
            norm.z = FastMath.cos(newlng);
        }

        private void readTexCoord() {
            file.seekMarkOffset(offTexCoord);
            texCoords=new Vector2f[numVerts];
            for (int i=0;i<texCoords.length;i++){
                texCoords[i]=new Vector2f();
                texCoords[i].x=file.readFloat();
                texCoords[i].y=1-file.readFloat();
            }

        }

        private void readTriangles() {
            file.seekMarkOffset(offTriangles);
            triIndexes=new int[numTriangles*3];
            for (int i=0;i<triIndexes.length;i++)
                triIndexes[i]=file.readInt();
        }

        private void readShader() {
            file.seekMarkOffset(offShaders);
            for (int i=0;i<numShaders;i++){
                String pathName=file.readString(64);
                int shaderIndex=file.readInt();
                if (DEBUG) System.out.println("path:"+pathName+" Index:"+shaderIndex);
            }
        }

    }

    void readVecFloat(Vector3f in){
        in.z=file.readFloat();
        in.x=file.readFloat();
        in.y=file.readFloat();

    }
}

[/code]

Looks fine to me. Just add some javadoc to the public function and should be good to go.

Looks like the javadoc hasn’t happened, I’ll try to take care of it and get this in.

Well, the last post was approximately 1.5 years ago. Is there any special reason why the current version of Md3ToJme() does not have the findController() method?

"Never send a Monkey to do a Man's work."  XD

It's going in now locally, sans javadoc.

Looks like the javadoc hasn't happened, I'll try to take care of it and get this in.


emphasis on *try*. ;)

Neat!

Make sure not to overwrite the other changes that where made during the last 1.5 years, though.



Which reminds me…

The typical "jME Javadoc header comment" only states the initial author of a Java file. There is no change history inside.

Well, I know you can get change information from CVS, but in my opinion a change history inside a source file itself is way more convenient and almost alway more detailed.

Therefore I think you should consider to start change histories inside the source code. But well, it's up to you, really.

Good luck enforcing that, plus where we've tried it gets ugly.  (Look at Spatial which has 109 changes in cvs at the moment and imagine a long section up front with changes listed for each checkin.)

in my opinion, using a good IDE with good cvs support, it's alot better to check change history from that…markup a few lines of code in a file, press show history, and i get full browsing of differences between my current code and whatever version i want…

@renanse

You're right, but when you are using an IDE that is capable of collapsing comments those 109 entries inside the spatial source won't bother you. The filesize may, though.



@MrCoder

The problem with CVS comments is, that they get incomplete quite easily and tend to be less detailed than comments. And checking the diff between two files definitely takes more time then just reading a "few" lines of comments.



But well, renanse is right. It would definitely be hard to enforce that kind of change history. Especially for a project with as much fluctuation as jME.

Nevermind, it was just a thought to consider.

and every thought is worth posting!

I strongly support the idea that ALL models should be able to be loaded and used in a game by the same code. Once a model is converted the converter should not be used for anything. I think a better solution would be to make a utill that works with all the converters.

Did someone say "every thought is worth posting"?  I guess I do have a purpose after all. :wink:



darkfrog

Yes, but that defines "thought" rather loosly… oh, did I say that out loud?  :wink:

Now THAT was funny. :slight_smile:



darkfrog

Don't worry, we all love ya, darkfrog.  8)