diff options
Diffstat (limited to 'src/demos/util/MD2.java')
-rw-r--r-- | src/demos/util/MD2.java | 702 |
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(); + } + } + } +} |