Need a new or enhanced Loader

Started by Sebastian, July 11, 2006, 12:47:03 PM

Previous topic - Next topic

Sebastian

Hi,

first I must say "thank you" for this great library. We think about using it in a commercial system. Would it be possible to see the source? I think about writing a additional loader for other formats or for retrieving more information (like texture and animation) from the files.

Best Regards,

Sebastian

EgonOlsen

No, it's free but not open source. But it doesn't have to be for you to write your own loader. You can write your own loader by creating Object3Ds from your files' contents and add the mesh data using Object3D.addTriangle(...); That's what the Loader-class does too. There's no hidden magic in it.

Sebastian

Ok, I believe that would be possible. But if you could show by example the code of the M2 - Loader, it would be much easyer :-)

EgonOlsen

Ok, so here is a basic MD2-Loader. It's not exactly the one that's used in Loader, but behaves bascially the same. The one in Loader isn't helpful because it uses some shortcuts into Object3D that are not public. Anyway, here you go:

package naroth.util.tools;

import java.io.*;
import com.threed.jpct.*;

/**
* An alternative MD2Loader for demonstration purpose only.
*/
public class MD2Loader {

  public static Object3D loadMD2(InputStream is, float newScale) throws Exception {
     int cnt=0;
     byte[] buf=new byte[1000];
     ByteArrayOutputStream bos=new ByteArrayOutputStream();
     do {
        cnt=is.read(buf);
        if (cnt!=-1) {
           bos.write(buf, 0, cnt);
        }
     } while (cnt!=-1);

     buf=bos.toByteArray();

     int magicNum=getInt(buf, 0);
     if (magicNum!=844121161) {
        Logger.log("Not a valid MD2-file!", Logger.ERROR);
     }

     int version=getInt(buf, 4);
     int skinWidth=getInt(buf, 8);
     int skinHeight=getInt(buf, 12);
     int frameSize=getInt(buf, 16);
     int numSkins=getInt(buf, 20);
     int numVertices=getInt(buf, 24);
     int numTexCoords=getInt(buf, 28);
     int numTriangles=getInt(buf, 32);
     int numGlCommands=getInt(buf, 36);
     int numFrames=getInt(buf, 40);
     int offsetTexCoords=getInt(buf, 48);
     int offsetTriangles=getInt(buf, 52);
     int offsetFrames=getInt(buf, 56);

     Logger.log("Magic number: "+magicNum, Logger.MESSAGE);
     Logger.log("Version: "+version, Logger.MESSAGE);
     Logger.log("Skin width: "+skinWidth, Logger.MESSAGE);
     Logger.log("Skin height: "+skinHeight, Logger.MESSAGE);
     Logger.log("Frame size: "+frameSize, Logger.MESSAGE);
     Logger.log("Number of skins: "+numSkins, Logger.MESSAGE);
     Logger.log("Number of Vertices: "+numVertices, Logger.MESSAGE);
     Logger.log("Number of Texture coordinates: "+numTexCoords, Logger.MESSAGE);
     Logger.log("Number of triangles: "+numTriangles, Logger.MESSAGE);
     Logger.log("Number of GL-commands: "+numGlCommands, Logger.MESSAGE);
     Logger.log("Number of Frames: "+numFrames, Logger.MESSAGE);

     int[][] texCoords=new int[numTexCoords][2];
     int[][] triVertex=new int[numTriangles][3];
     int[][] triTexture=new int[numTriangles][3];

     Logger.log("Reading Texture coordinates...", Logger.MESSAGE);
     int oF=offsetTexCoords;
     for (int i=0; i<numTexCoords; i++) {
        int u=getShortInt(buf, oF+(i*4));
        int v=getShortInt(buf, oF+(i*4)+2);
        texCoords[i][0]=u;
        texCoords[i][1]=v;
     }
     Logger.log("Done!", Logger.MESSAGE);

     Logger.log("Reading polygonal data...", Logger.MESSAGE);
     oF=offsetTriangles;
     for (int i=0; i<numTriangles; i++) {
        int iMul=oF+i*12;
        int p1=getShortInt(buf, iMul);
        int p2=getShortInt(buf, iMul+2);
        int p3=getShortInt(buf, iMul+4);
        int t1=getShortInt(buf, iMul+6);
        int t2=getShortInt(buf, iMul+8);
        int t3=getShortInt(buf, iMul+10);
        triVertex[i][0]=p1;
        triVertex[i][1]=p2;
        triVertex[i][2]=p3;
        triTexture[i][0]=t1;
        triTexture[i][1]=t2;
        triTexture[i][2]=t3;
     }
     Logger.log("Done!", Logger.MESSAGE);

     float scales[][]=new float[numFrames][3];
     float trans[][]=new float[numFrames][3];
     String names[]=new String[numFrames];
     int[][][] vertices=new int[numFrames][numVertices][3];

     Logger.log("Reading keyframes...", Logger.MESSAGE);
     for (int i=0; i<numFrames; i++) {
        oF=(i*frameSize)+offsetFrames;
        float scaleX=Float.intBitsToFloat(getInt(buf, oF));
        float scaleY=Float.intBitsToFloat(getInt(buf, oF+4));
        float scaleZ=Float.intBitsToFloat(getInt(buf, oF+8));
        float transX=Float.intBitsToFloat(getInt(buf, oF+12));
        float transY=Float.intBitsToFloat(getInt(buf, oF+16));
        float transZ=Float.intBitsToFloat(getInt(buf, oF+20));

        String name=new String(buf, oF+24, 16);
        scales[i][0]=scaleX;
        scales[i][1]=scaleY;
        scales[i][2]=scaleZ;
        trans[i][0]=transX;
        trans[i][1]=transY;
        trans[i][2]=transZ;
        names[i]=name;

        oF+=40;
        for (int p=0; p<numVertices; p++) {
           int iMul=oF+(p*4);
           int v1=getUnsignedByte(buf, iMul);
           int v2=getUnsignedByte(buf, iMul+1);
           int v3=getUnsignedByte(buf, iMul+2);
           vertices[i][p][0]=v1;
           vertices[i][p][1]=v2;
           vertices[i][p][2]=v3;
        }
     }
     Logger.log("Done!", Logger.MESSAGE);

     Logger.log("Coverting MD2-format into jPCT-format...", Logger.MESSAGE);

     Object3D obj=new Object3D(numTriangles+1);
     Object3D tmp=new Object3D(numTriangles+1);

     // If the triangles in this model are not sharing vertices (i.e. the model isn't closed), this will be needed.
     // This simple loader doesn't detect this rare case.
     //obj.disableVertexSharing();
     //tmp.disableVertexSharing();

     Animation anim=new Animation(numFrames);
     String lastSeq="dummy";

     SimpleVector[] vs=new SimpleVector[3];
     for (int i=0; i<3; i++) {
        vs[i]=new SimpleVector();
     }

     for (int p=0; p<numFrames; p++) {
        tmp.clearObject();

        for (int i=0; i<numTriangles; i++) {
           for (int h=0; h<3; h++) {
              vs[h].x=((float) vertices[p][triVertex[i][h]][0])*scales[p][0]+trans[p][0];
              vs[h].y=((float) vertices[p][triVertex[i][h]][1])*scales[p][1]+trans[p][1];
              vs[h].z=((float) vertices[p][triVertex[i][h]][2])*scales[p][2]+trans[p][2];
              vs[h].scalarMul(newScale);
           }

           int t1p=triTexture[i][0];
           int t2p=triTexture[i][2];
           int t3p=triTexture[i][1];

           float t1u=texCoords[t1p][0]/(float) skinWidth;
           float t1v=texCoords[t1p][1]/(float) skinHeight;

           float t2u=texCoords[t2p][0]/(float) skinWidth;
           float t2v=texCoords[t2p][1]/(float) skinHeight;

           float t3u=texCoords[t3p][0]/(float) skinWidth;
           float t3v=texCoords[t3p][1]/(float) skinHeight;

           if (p==0) {
              obj.addTriangle(vs[0], t1u, t1v, vs[1], t2u, t2v, vs[2], t3u, t3v);
           }
           tmp.addTriangle(vs[0], t1u, t1v, vs[1], t2u, t2v, vs[2], t3u, t3v);

        }
        tmp.calcBoundingBox();
        tmp.calcNormals();

        String tmpS=getSequenceName(names[p]);
        if (!tmpS.equals(lastSeq)) {
           Logger.log("Processing: "+tmpS+"...", Logger.MESSAGE);
           lastSeq=tmpS;
           anim.createSubSequence(tmpS);
        }

        anim.addKeyFrame(tmp.getMesh().cloneMesh(Mesh.COMPRESS));
     }

     obj.calcBoundingBox();
     obj.setAnimationSequence(anim);

     Logger.log("Done!", Logger.MESSAGE);
     return obj;
  }

  private static int getInt(byte[] b, int offset) {
     if (offset+3<b.length) {
        int a=unsignedByteToInt(b[offset]);
        int d=unsignedByteToInt(b[offset+1]);
        int e=unsignedByteToInt(b[offset+2]);
        int f=unsignedByteToInt(b[offset+3]);
        return (int) (a+(d<<8)+(e<<16)+(f<<24));
     }
     return-1;
  }

  private static int getShortInt(byte[] b, int offset) {
     if (offset+1<b.length) {
        int a=unsignedByteToInt(b[offset]);
        int d=unsignedByteToInt(b[offset+1]);
        return (int) (a+(d<<8));
     }
     return-1;
  }

  private static int getUnsignedByte(byte[] b, int offset) {
     if (offset<b.length) {
        return unsignedByteToInt(b[offset]);
     }
     return-1;
  }

  private static int unsignedByteToInt(byte b) {
     return (int) b&0xFF;
  }

  private static String getSequenceName(String a) {
     char c=' ';
     StringBuffer res=new StringBuffer(16);
     a=a.toLowerCase();
     for (int i=0; i<a.length(); i++) {
        c=a.charAt(i);
        if (c>='a'&&c<='z') {
           res.append(c);
        }
     }
     return res.toString();
  }
}

Mizuki Takase

Hee hee... Admittingly, I wanted to make a new Loader but was too afraid to ask~