summaryrefslogtreecommitdiffstats
path: root/src/demos/util/MD2.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/demos/util/MD2.java')
-rw-r--r--src/demos/util/MD2.java702
1 files changed, 702 insertions, 0 deletions
diff --git a/src/demos/util/MD2.java b/src/demos/util/MD2.java
new file mode 100644
index 0000000..8e43c79
--- /dev/null
+++ b/src/demos/util/MD2.java
@@ -0,0 +1,702 @@
+/*
+ * Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any kind. ALL
+ * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
+ * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
+ * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN
+ * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR
+ * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
+ * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR
+ * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR
+ * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE
+ * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY,
+ * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF
+ * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed or intended for use
+ * in the design, construction, operation or maintenance of any nuclear
+ * facility.
+ *
+ * Sun gratefully acknowledges that this software was originally authored
+ * and developed by Kenneth Bradley Russell and Christopher John Kline.
+ */
+
+package demos.util;
+
+import java.io.*;
+import java.nio.*;
+import java.nio.channels.*;
+import java.util.*;
+
+/** Reader for MD2 models, used by Quake II. */
+
+public class MD2 {
+ public static Model loadMD2(String filename) throws IOException {
+ List/*<IFrame>*/ ifr = new ArrayList/*<IFrame>*/();
+ loadFrames(filename, ifr);
+ return computeModel(ifr);
+ }
+
+ public static Model loadMD2(InputStream in) throws IOException {
+ List/*<IFrame>*/ ifr = new ArrayList/*<IFrame>*/();
+ loadFrames(in, ifr);
+ return computeModel(ifr);
+ }
+
+ public static class FileHeader {
+ public int ident;
+ public int version;
+ public int skinwidth;
+ public int skinheight;
+ public int framesize; // byte size of each frame
+ public int num_skins;
+ public int num_xyz;
+ public int num_st; // greater than num_xyz for seams
+ public int num_tris;
+ public int num_glcmds; // dwords in strip/fan command list
+ public int num_frames;
+ public int ofs_skins; // each skin is a MAX_SKINNAME string
+ public int ofs_st; // byte offset from start for stverts
+ public int ofs_tris; // offset for dtriangles
+ public int ofs_frames; // offset for first frame
+ public int ofs_glcmds;
+ public int ofs_end; // end of file
+ };
+
+ public static class FileCompressedVertex {
+ public byte[] v = new byte[3]; // scaled byte to fit in frame mins/maxs
+ public byte lightnormalindex;
+ }
+
+ public static class FileFrame {
+ public float[] scale = new float[3]; // multiply byte verts by this
+ public float[] translate = new float[3]; // then add this
+ public String name; // frame name from grabbing
+ public FileCompressedVertex[] verts; // variable sized
+ }
+
+ public static class FileModel {
+ public int[] glcmds;
+ public FileFrame[] frames;
+ }
+
+ public static class PositionNormal implements Cloneable {
+ public float x, y, z;
+ public float nx, ny, nz;
+ public Object clone() {
+ try {
+ return super.clone();
+ } catch (CloneNotSupportedException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ }
+
+ public static class TexCoord {
+ public float s,t;
+ }
+
+ public static class Vertex {
+ public int pn_index;
+ public TexCoord tc = new TexCoord();
+ }
+
+ public static class Triangle {
+ public Vertex[] v = new Vertex[3];
+ public boolean kill;
+ }
+
+ public static class WingedEdge {
+ public int[] e = new int[2]; // vertex index
+ public int[] w = new int[2]; // triangle index: for "open" models, w[1] == -1 on open edges
+ }
+
+ public static class Plane implements Cloneable {
+ public float a,b,c,d;
+ public Object clone() {
+ try {
+ return super.clone();
+ } catch (CloneNotSupportedException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ }
+
+ public static class Frame implements Cloneable {
+ public PositionNormal[] pn; // [pn_index]
+ public Plane[] triplane; // [tri_num]
+
+ public Object clone() {
+ Frame res = new Frame();
+ res.pn = new PositionNormal[pn.length];
+ for (int i = 0; i < pn.length; i++) {
+ res.pn[i] = (PositionNormal) pn[i].clone();
+ }
+ res.triplane = new Plane[triplane.length];
+ for (int i = 0; i < triplane.length; i++) {
+ res.triplane[i] = (Plane) triplane[i].clone();
+ }
+ return res;
+ }
+ }
+
+ public static class Model {
+ public Frame[] f;
+ public Triangle[] tri; // [tri_num]
+ public WingedEdge[] edge; // [edge_num]
+ }
+
+ public static void computePlane(PositionNormal a, PositionNormal b, PositionNormal c, Plane p) {
+ float[] v0 = new float[3];
+ v0[0] = b.x - a.x;
+ v0[1] = b.y - a.y;
+ v0[2] = b.z - a.z;
+ float[] v1 = new float[3];
+ v1[0] = c.x - a.x;
+ v1[1] = c.y - a.y;
+ v1[2] = c.z - a.z;
+ float[] cr = new float[3];
+ cr[0] = v0[1] * v1[2] - v0[2] * v1[1];
+ cr[1] = v0[2] * v1[0] - v0[0] * v1[2];
+ cr[2] = v0[0] * v1[1] - v0[1] * v1[0];
+ float l = (float) Math.sqrt(cr[0] * cr[0] + cr[1] * cr[1] + cr[2] * cr[2]);
+ if (l == 0) {
+ // degenerate triangle
+ p.a = p.b = p.c = p.d = 0;
+ return;
+ }
+ p.a = cr[0] / l;
+ p.b = cr[1] / l;
+ p.c = cr[2] / l;
+
+ p.d = -(p.a * a.x + p.b * a.y + p.c * a.z); // signed distance of a point on the plane from the origin
+ }
+
+ //----------------------------------------------------------------------
+ // Internals only below this point
+ //
+
+ private static Model computeModel(List/*<IFrame>*/ ifr) throws IOException {
+ if (!compareFrames(ifr)) {
+ throw new IOException("unsuitable model -- frames aren't same");
+ }
+ Model m = new Model();
+ m.tri = ((IFrame) ifr.get(0)).tri;
+ m.f = new Frame[ifr.size()];
+ for (int i = 0; i < ifr.size(); i++) {
+ Frame f = new Frame();
+ m.f[i] = f;
+ IFrame it = (IFrame) ifr.get(i);
+ f.pn = it.pn;
+ computeFramePlanes(m.tri, f);
+ }
+ computeWingedEdges(m);
+ return m;
+ }
+
+ private static class IFrame {
+ PositionNormal[] pn;
+ Triangle[] tri;
+ }
+
+ // normal table lifted from Mark Kilgard's md2bump demo
+ private static final float[] normalTable = new float[] {
+ -0.525731f, 0.000000f, 0.850651f,
+ -0.442863f, 0.238856f, 0.864188f,
+ -0.295242f, 0.000000f, 0.955423f,
+ -0.309017f, 0.500000f, 0.809017f,
+ -0.162460f, 0.262866f, 0.951056f,
+ 0.000000f, 0.000000f, 1.000000f,
+ 0.000000f, 0.850651f, 0.525731f,
+ -0.147621f, 0.716567f, 0.681718f,
+ 0.147621f, 0.716567f, 0.681718f,
+ 0.000000f, 0.525731f, 0.850651f,
+ 0.309017f, 0.500000f, 0.809017f,
+ 0.525731f, 0.000000f, 0.850651f,
+ 0.295242f, 0.000000f, 0.955423f,
+ 0.442863f, 0.238856f, 0.864188f,
+ 0.162460f, 0.262866f, 0.951056f,
+ -0.681718f, 0.147621f, 0.716567f,
+ -0.809017f, 0.309017f, 0.500000f,
+ -0.587785f, 0.425325f, 0.688191f,
+ -0.850651f, 0.525731f, 0.000000f,
+ -0.864188f, 0.442863f, 0.238856f,
+ -0.716567f, 0.681718f, 0.147621f,
+ -0.688191f, 0.587785f, 0.425325f,
+ -0.500000f, 0.809017f, 0.309017f,
+ -0.238856f, 0.864188f, 0.442863f,
+ -0.425325f, 0.688191f, 0.587785f,
+ -0.716567f, 0.681718f, -0.147621f,
+ -0.500000f, 0.809017f, -0.309017f,
+ -0.525731f, 0.850651f, 0.000000f,
+ 0.000000f, 0.850651f, -0.525731f,
+ -0.238856f, 0.864188f, -0.442863f,
+ 0.000000f, 0.955423f, -0.295242f,
+ -0.262866f, 0.951056f, -0.162460f,
+ 0.000000f, 1.000000f, 0.000000f,
+ 0.000000f, 0.955423f, 0.295242f,
+ -0.262866f, 0.951056f, 0.162460f,
+ 0.238856f, 0.864188f, 0.442863f,
+ 0.262866f, 0.951056f, 0.162460f,
+ 0.500000f, 0.809017f, 0.309017f,
+ 0.238856f, 0.864188f, -0.442863f,
+ 0.262866f, 0.951056f, -0.162460f,
+ 0.500000f, 0.809017f, -0.309017f,
+ 0.850651f, 0.525731f, 0.000000f,
+ 0.716567f, 0.681718f, 0.147621f,
+ 0.716567f, 0.681718f, -0.147621f,
+ 0.525731f, 0.850651f, 0.000000f,
+ 0.425325f, 0.688191f, 0.587785f,
+ 0.864188f, 0.442863f, 0.238856f,
+ 0.688191f, 0.587785f, 0.425325f,
+ 0.809017f, 0.309017f, 0.500000f,
+ 0.681718f, 0.147621f, 0.716567f,
+ 0.587785f, 0.425325f, 0.688191f,
+ 0.955423f, 0.295242f, 0.000000f,
+ 1.000000f, 0.000000f, 0.000000f,
+ 0.951056f, 0.162460f, 0.262866f,
+ 0.850651f, -0.525731f, 0.000000f,
+ 0.955423f, -0.295242f, 0.000000f,
+ 0.864188f, -0.442863f, 0.238856f,
+ 0.951056f, -0.162460f, 0.262866f,
+ 0.809017f, -0.309017f, 0.500000f,
+ 0.681718f, -0.147621f, 0.716567f,
+ 0.850651f, 0.000000f, 0.525731f,
+ 0.864188f, 0.442863f, -0.238856f,
+ 0.809017f, 0.309017f, -0.500000f,
+ 0.951056f, 0.162460f, -0.262866f,
+ 0.525731f, 0.000000f, -0.850651f,
+ 0.681718f, 0.147621f, -0.716567f,
+ 0.681718f, -0.147621f, -0.716567f,
+ 0.850651f, 0.000000f, -0.525731f,
+ 0.809017f, -0.309017f, -0.500000f,
+ 0.864188f, -0.442863f, -0.238856f,
+ 0.951056f, -0.162460f, -0.262866f,
+ 0.147621f, 0.716567f, -0.681718f,
+ 0.309017f, 0.500000f, -0.809017f,
+ 0.425325f, 0.688191f, -0.587785f,
+ 0.442863f, 0.238856f, -0.864188f,
+ 0.587785f, 0.425325f, -0.688191f,
+ 0.688191f, 0.587785f, -0.425325f,
+ -0.147621f, 0.716567f, -0.681718f,
+ -0.309017f, 0.500000f, -0.809017f,
+ 0.000000f, 0.525731f, -0.850651f,
+ -0.525731f, 0.000000f, -0.850651f,
+ -0.442863f, 0.238856f, -0.864188f,
+ -0.295242f, 0.000000f, -0.955423f,
+ -0.162460f, 0.262866f, -0.951056f,
+ 0.000000f, 0.000000f, -1.000000f,
+ 0.295242f, 0.000000f, -0.955423f,
+ 0.162460f, 0.262866f, -0.951056f,
+ -0.442863f, -0.238856f, -0.864188f,
+ -0.309017f, -0.500000f, -0.809017f,
+ -0.162460f, -0.262866f, -0.951056f,
+ 0.000000f, -0.850651f, -0.525731f,
+ -0.147621f, -0.716567f, -0.681718f,
+ 0.147621f, -0.716567f, -0.681718f,
+ 0.000000f, -0.525731f, -0.850651f,
+ 0.309017f, -0.500000f, -0.809017f,
+ 0.442863f, -0.238856f, -0.864188f,
+ 0.162460f, -0.262866f, -0.951056f,
+ 0.238856f, -0.864188f, -0.442863f,
+ 0.500000f, -0.809017f, -0.309017f,
+ 0.425325f, -0.688191f, -0.587785f,
+ 0.716567f, -0.681718f, -0.147621f,
+ 0.688191f, -0.587785f, -0.425325f,
+ 0.587785f, -0.425325f, -0.688191f,
+ 0.000000f, -0.955423f, -0.295242f,
+ 0.000000f, -1.000000f, 0.000000f,
+ 0.262866f, -0.951056f, -0.162460f,
+ 0.000000f, -0.850651f, 0.525731f,
+ 0.000000f, -0.955423f, 0.295242f,
+ 0.238856f, -0.864188f, 0.442863f,
+ 0.262866f, -0.951056f, 0.162460f,
+ 0.500000f, -0.809017f, 0.309017f,
+ 0.716567f, -0.681718f, 0.147621f,
+ 0.525731f, -0.850651f, 0.000000f,
+ -0.238856f, -0.864188f, -0.442863f,
+ -0.500000f, -0.809017f, -0.309017f,
+ -0.262866f, -0.951056f, -0.162460f,
+ -0.850651f, -0.525731f, 0.000000f,
+ -0.716567f, -0.681718f, -0.147621f,
+ -0.716567f, -0.681718f, 0.147621f,
+ -0.525731f, -0.850651f, 0.000000f,
+ -0.500000f, -0.809017f, 0.309017f,
+ -0.238856f, -0.864188f, 0.442863f,
+ -0.262866f, -0.951056f, 0.162460f,
+ -0.864188f, -0.442863f, 0.238856f,
+ -0.809017f, -0.309017f, 0.500000f,
+ -0.688191f, -0.587785f, 0.425325f,
+ -0.681718f, -0.147621f, 0.716567f,
+ -0.442863f, -0.238856f, 0.864188f,
+ -0.587785f, -0.425325f, 0.688191f,
+ -0.309017f, -0.500000f, 0.809017f,
+ -0.147621f, -0.716567f, 0.681718f,
+ -0.425325f, -0.688191f, 0.587785f,
+ -0.162460f, -0.262866f, 0.951056f,
+ 0.442863f, -0.238856f, 0.864188f,
+ 0.162460f, -0.262866f, 0.951056f,
+ 0.309017f, -0.500000f, 0.809017f,
+ 0.147621f, -0.716567f, 0.681718f,
+ 0.000000f, -0.525731f, 0.850651f,
+ 0.425325f, -0.688191f, 0.587785f,
+ 0.587785f, -0.425325f, 0.688191f,
+ 0.688191f, -0.587785f, 0.425325f,
+ -0.955423f, 0.295242f, 0.000000f,
+ -0.951056f, 0.162460f, 0.262866f,
+ -1.000000f, 0.000000f, 0.000000f,
+ -0.850651f, 0.000000f, 0.525731f,
+ -0.955423f, -0.295242f, 0.000000f,
+ -0.951056f, -0.162460f, 0.262866f,
+ -0.864188f, 0.442863f, -0.238856f,
+ -0.951056f, 0.162460f, -0.262866f,
+ -0.809017f, 0.309017f, -0.500000f,
+ -0.864188f, -0.442863f, -0.238856f,
+ -0.951056f, -0.162460f, -0.262866f,
+ -0.809017f, -0.309017f, -0.500000f,
+ -0.681718f, 0.147621f, -0.716567f,
+ -0.681718f, -0.147621f, -0.716567f,
+ -0.850651f, 0.000000f, -0.525731f,
+ -0.688191f, 0.587785f, -0.425325f,
+ -0.587785f, 0.425325f, -0.688191f,
+ -0.425325f, 0.688191f, -0.587785f,
+ -0.425325f, -0.688191f, -0.587785f,
+ -0.587785f, -0.425325f, -0.688191f,
+ -0.688191f, -0.587785f, -0.425325f
+ };
+
+ private static void loadFrames(String filename, List/*<IFrame>*/ md2p) throws IOException {
+ FileModel mf = loadMD2File(filename);
+ computeFrames(mf, md2p);
+ }
+
+ private static void loadFrames(InputStream in, List/*<IFrame>*/ md2p) throws IOException {
+ FileModel mf = loadMD2File(in);
+ computeFrames(mf, md2p);
+ }
+
+ private static void computeFrames(FileModel mf, List/*<IFrame>*/ md2p) throws IOException {
+ for (int i = 0; i < mf.frames.length; i++) {
+ IFrame f = new IFrame();
+ md2p.add(f);
+ FileFrame curframe = mf.frames[i];
+ f.pn = new PositionNormal[curframe.verts.length];
+ for (int j = 0; j < curframe.verts.length; j++) {
+ PositionNormal pn = new PositionNormal();
+ pn.x = (((curframe.verts[j].v[0] & 0xFF) * curframe.scale[0]) + curframe.translate[0]) * .025f;
+ pn.y = (((curframe.verts[j].v[1] & 0xFF) * curframe.scale[1]) + curframe.translate[1]) * .025f;
+ pn.z = (((curframe.verts[j].v[2] & 0xFF) * curframe.scale[2]) + curframe.translate[2]) * .025f;
+ int normal_index = curframe.verts[j].lightnormalindex & 0xFF;
+ pn.nx = normalTable[3 * normal_index + 0];
+ pn.ny = normalTable[3 * normal_index + 1];
+ pn.nz = normalTable[3 * normal_index + 2];
+ f.pn[j] = pn;
+ }
+
+ List/*<Triangle>*/ tris = new ArrayList();
+ int[] idx = new int[1];
+ while (mf.glcmds[idx[0]] != 0) {
+ int vertnum;
+ boolean is_strip;
+ if (mf.glcmds[idx[0]] > 0) {
+ vertnum = mf.glcmds[idx[0]++]; is_strip = true; // triangle strip
+ } else {
+ vertnum = -mf.glcmds[idx[0]++]; is_strip = false; // triangle fan
+ }
+
+ if (is_strip) {
+ Vertex[] prev = new Vertex[2];
+ prev[0] = extractVertex(mf.glcmds, idx);
+ prev[1] = extractVertex(mf.glcmds, idx);
+ for (int j = 2; j < vertnum; j++) {
+ Triangle tri = new Triangle();
+ if ((j % 2) == 0) {
+ tri.v[0] = prev[0];
+ tri.v[1] = prev[1];
+ tri.v[2] = extractVertex(mf.glcmds, idx);
+ prev[0] = tri.v[2];
+ } else {
+ tri.v[0] = prev[1];
+ tri.v[1] = extractVertex(mf.glcmds, idx);
+ tri.v[2] = prev[0];
+ prev[1] = tri.v[1];
+ }
+ // swap v[1] and v[2] to fix triangle winding
+ Vertex hold = tri.v[1];
+ tri.v[1] = tri.v[2];
+ tri.v[2] = hold;
+ tris.add(tri);
+ }
+ } else {
+ // is fan
+ Vertex ctr = extractVertex(mf.glcmds, idx);
+ Vertex prev = extractVertex(mf.glcmds, idx);
+ for (int j = 2; j < vertnum; j++) {
+ Triangle tri = new Triangle();
+ tri.v[0] = ctr;
+ tri.v[1] = prev;
+ tri.v[2] = extractVertex(mf.glcmds, idx);
+ prev = tri.v[2];
+ // swap v[1] and v[2] to fix triangle winding
+ Vertex hold = tri.v[1];
+ tri.v[1] = tri.v[2];
+ tri.v[2] = hold;
+ tris.add(tri);
+ }
+ }
+ }
+ f.tri = (Triangle[]) tris.toArray(new Triangle[0]);
+ }
+ }
+
+ private static FileModel loadMD2File(ByteBuffer buf) throws IOException {
+ buf.order(ByteOrder.LITTLE_ENDIAN);
+ FileModel md2p = new FileModel();
+ FileHeader header = readHeader(buf);
+ buf.position(header.ofs_frames);
+ readFrames(buf, header, md2p);
+ buf.position(header.ofs_glcmds);
+ readGLCommands(buf, header, md2p);
+ return md2p;
+ }
+
+ private static FileModel loadMD2File(InputStream in) throws IOException {
+ in = new BufferedInputStream(in);
+ int avail = in.available();
+ byte[] data = new byte[avail];
+ int numRead = 0;
+ int pos = 0;
+ do {
+ if (pos + avail > data.length) {
+ byte[] newData = new byte[pos + avail];
+ System.arraycopy(data, 0, newData, 0, pos);
+ data = newData;
+ }
+ numRead = in.read(data, pos, avail);
+ if (numRead >= 0) {
+ pos += numRead;
+ }
+ avail = in.available();
+ } while (avail > 0 && numRead >= 0);
+ ByteBuffer buf = ByteBuffer.allocateDirect(pos);
+ buf.put(data, 0, pos);
+ buf.rewind();
+ return loadMD2File(buf);
+ }
+
+ private static FileModel loadMD2File(String filename) throws IOException {
+ FileInputStream fis = new FileInputStream(filename);
+ FileChannel chan = fis.getChannel();
+ ByteBuffer buf = chan.map(FileChannel.MapMode.READ_ONLY, 0, fis.available());
+ FileModel md2p = loadMD2File(buf);
+ chan.close();
+ fis.close();
+ return md2p;
+ }
+
+ private static FileHeader readHeader(ByteBuffer buf) {
+ FileHeader header = new FileHeader();
+ header.ident = buf.getInt();
+ header.version = buf.getInt();
+ header.skinwidth = buf.getInt();
+ header.skinheight = buf.getInt();
+ header.framesize = buf.getInt();
+ header.num_skins = buf.getInt();
+ header.num_xyz = buf.getInt();
+ header.num_st = buf.getInt();
+ header.num_tris = buf.getInt();
+ header.num_glcmds = buf.getInt();
+ header.num_frames = buf.getInt();
+ header.ofs_skins = buf.getInt();
+ header.ofs_st = buf.getInt();
+ header.ofs_tris = buf.getInt();
+ header.ofs_frames = buf.getInt();
+ header.ofs_glcmds = buf.getInt();
+ header.ofs_end = buf.getInt();
+ return header;
+ }
+
+ private static int numVerts(int framesize) {
+ return (framesize >> 2) - 10;
+ }
+
+ private static void readFrames(ByteBuffer buf, FileHeader header, FileModel md2p) throws IOException {
+ int numframes = header.num_frames;
+ int framesize = header.framesize;
+ int numVerts = numVerts(framesize);
+ FileFrame[] frames = new FileFrame[numframes];
+ byte[] name = new byte[16];
+ for (int i = 0; i < numframes; i++) {
+ FileFrame frame = new FileFrame();
+ frame.scale[0] = buf.getFloat();
+ frame.scale[1] = buf.getFloat();
+ frame.scale[2] = buf.getFloat();
+ frame.translate[0] = buf.getFloat();
+ frame.translate[1] = buf.getFloat();
+ frame.translate[2] = buf.getFloat();
+ buf.get(name);
+ try {
+ frame.name = new String(name, "US-ASCII");
+ } catch (UnsupportedEncodingException e) {
+ throw new IOException(e.toString());
+ }
+ frame.verts = new FileCompressedVertex[numVerts];
+ for (int j = 0; j < numVerts; j++) {
+ FileCompressedVertex vert = new FileCompressedVertex();
+ buf.get(vert.v);
+ vert.lightnormalindex = buf.get();
+ frame.verts[j] = vert;
+ }
+ frames[i] = frame;
+ }
+ md2p.frames = frames;
+ }
+
+ private static void readGLCommands(ByteBuffer buf, FileHeader header, FileModel md2p) {
+ int num_glcmds = header.num_glcmds;
+ int[] glcmds = new int[num_glcmds];
+ for (int i = 0; i < num_glcmds; i++) {
+ glcmds[i] = buf.getInt();
+ }
+ md2p.glcmds = glcmds;
+ }
+
+ private static Vertex extractVertex(int[] glcmds, int[] idx) {
+ Vertex v = new Vertex();
+ v.tc.s = Float.intBitsToFloat(glcmds[idx[0]++]);
+ v.tc.t = Float.intBitsToFloat(glcmds[idx[0]++]);
+ v.pn_index = glcmds[idx[0]++];
+ return v;
+ }
+
+ private static boolean compareFrames(List/*<IFrame>*/ m) {
+ IFrame f0 = (IFrame) m.get(0);
+ boolean same_topology = true;
+ boolean same_texcoords = true;
+
+ for (int i = 1; i < m.size(); i++) {
+ IFrame f = (IFrame) m.get(i);
+ if (f.pn.length != f0.pn.length) {
+ System.err.println("pn size different for iframe " + i + " : " + f0.pn.length + " != " + f.pn.length);
+ same_topology = false;
+ }
+ if (f.tri.length != f0.tri.length) {
+ System.err.println("tri size different for iframe " + i + " : " + f0.tri.length + " != " + f.tri.length);
+ same_topology = false;
+ }
+ if (same_topology) {
+ for (int j = 0; j < f.tri.length; j++) {
+ Triangle t0 = f0.tri[j];
+ Triangle t = f.tri[j];
+ for (int k = 0; k < 3; k++) {
+ if (t0.v[k].pn_index != t.v[k].pn_index) {
+ System.err.println("tri " + j + " triangle pn_index " + k + " different!");
+ same_topology = false;
+ }
+ if (t0.v[k].tc.s != t.v[k].tc.s || t0.v[k].tc.t != t.v[k].tc.t) {
+ System.err.println("tri " + j + " triangle tc " + k + " different!");
+ same_texcoords = false;
+ }
+ }
+ }
+ }
+ }
+
+ return same_topology && same_texcoords;
+ }
+
+ /**
+ Computes the plane equations for each polygon of a frame.
+ */
+ private static void computeFramePlanes(Triangle[] tri, Frame f) {
+ f.triplane = new Plane[tri.length];
+ for (int i = 0; i < tri.length; i++) {
+ Triangle t = tri[i];
+ int ia = t.v[0].pn_index;
+ int ib = t.v[1].pn_index;
+ int ic = t.v[2].pn_index;
+ Plane p = new Plane();
+ computePlane(f.pn[ia], f.pn[ib], f.pn[ic], p);
+ f.triplane[i] = p;
+ }
+ }
+
+ private static int computeWingedEdges(Model m) {
+ Triangle[] tri = m.tri;
+ List/*<WingedEdge>*/ edge = new ArrayList/*<WingedEdge>*/();
+
+ // for each triangle, try to add each edge to the winged_edge vector,
+ // but check first to see if it's already there
+ int tsize = tri.length;
+ for (int i = 0; i < tsize; i++) {
+ Triangle t = tri[i];
+ for (int j = 0; j < 3; j++) {
+ WingedEdge we = new WingedEdge();
+ we.e[0] = t.v[ j ].pn_index;
+ we.e[1] = t.v[(j+1)%3].pn_index;
+ we.w[0] = i;
+ we.w[1] = -1; // subsequent attempt to add this edge will replace w[1]
+ addEdge(edge, we);
+ }
+ }
+ int open_edge = 0;
+ for (int i = 0; i < edge.size(); i++) {
+ if (((WingedEdge) edge.get(i)).w[1] == -1)
+ open_edge++;
+ }
+ //fprintf(stderr, "out of % edges, there were %d open edges\n", edge.size(), open_edge);
+ m.edge = (WingedEdge[]) edge.toArray(new WingedEdge[0]);
+ return open_edge;
+ }
+
+ /**
+ add_edge will look to see if the current edge is already in the list.
+ If it is not, it will add it. If it is, it will replace the w[1] in
+ the existing table with w[0] from the edge being added.
+ */
+ private static void addEdge(List/*<WingedEdge>*/ edge, WingedEdge we) {
+ int esize = edge.size();
+ for (int i=0; i < esize; i++) {
+ WingedEdge we0 = (WingedEdge) edge.get(i);
+ if (we0.e[0] == we.e[0] && we0.e[1] == we.e[1]) {
+ System.err.println("facingness different between polys on edge!");
+ }
+ if(we0.e[0] == we.e[1] && we0.e[1] == we.e[0]) {
+ if(we0.w[1] != -1) {
+ System.err.println("triple edge! bad...");
+ }
+ we0.w[1] = we.w[0]; // pair the edge and return
+ return;
+ }
+ }
+ edge.add(we); // otherwise, add the new edge
+ }
+
+ public static void main(String[] args) {
+ for (int i = 0; i < args.length; i++) {
+ try {
+ MD2.Model model = loadMD2(args[i]);
+ System.err.println("Successfully parsed " + args[i]);
+ } catch (IOException e) {
+ System.err.println("Error parsing " + args[i] + ":");
+ e.printStackTrace();
+ }
+ }
+ }
+}