summaryrefslogtreecommitdiffstats
path: root/src/demos/util
diff options
context:
space:
mode:
authorKenneth Russel <[email protected]>2003-06-25 09:05:29 +0000
committerKenneth Russel <[email protected]>2003-06-25 09:05:29 +0000
commit2179980ed660ef66a9c064d153c5de7994d431ab (patch)
tree926fa0ccc31737ad9753a64bf0451dd818652d1b /src/demos/util
parent1a1ad3a33b2932187410bc8bb4bf44362a26c8b0 (diff)
Split up net.java.games.util; moved GLUT and BufferUtils into
net.java.games.jogl.util, and moved demo-specific utility classes into jogl-demos project under demos.util. Added nearly all JavaOne demos into jogl-demos project; rewrote where necessary to use ClassLoader.getResourceAsStream() instead of flat files, put into packages and added to Makefile. Added gleem to jogl-demos project. Added jogl.jar build rule. git-svn-id: file:///usr/local/projects/SUN/JOGL/git-svn/../svn-server-sync/jogl-demos/trunk@3 3298f667-5e0e-4b4a-8ed4-a3559d26a5f4
Diffstat (limited to 'src/demos/util')
-rw-r--r--src/demos/util/Bunny.java141
-rw-r--r--src/demos/util/DDSReader.java413
-rw-r--r--src/demos/util/DurationTimer.java68
-rw-r--r--src/demos/util/DxTex.java375
-rw-r--r--src/demos/util/FloatList.java100
-rw-r--r--src/demos/util/IntList.java100
-rw-r--r--src/demos/util/LEDataInputStream.java223
-rw-r--r--src/demos/util/MD2.java702
-rw-r--r--src/demos/util/ObjReader.java347
-rw-r--r--src/demos/util/SystemTime.java110
-rw-r--r--src/demos/util/TGAImage.java319
-rw-r--r--src/demos/util/Time.java52
-rw-r--r--src/demos/util/Triceratops.java137
13 files changed, 3087 insertions, 0 deletions
diff --git a/src/demos/util/Bunny.java b/src/demos/util/Bunny.java
new file mode 100644
index 0000000..578dff0
--- /dev/null
+++ b/src/demos/util/Bunny.java
@@ -0,0 +1,141 @@
+/*
+ * 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
+ * MIDROSYSTEMS, 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 net.java.games.jogl.*;
+
+/** Renders a bunny.
+
+ <P> This file was produced by 3D Exploration Plugin: CPP Export filter.
+
+ <P> 3D Exploration
+
+ <P> Copyright (c) 1999-2000 X Dimension Software
+
+ <P>WWW http://www.xdsoft.com/explorer/ <BR>
+*/
+public class Bunny {
+
+ /** Generates and returns a display list for the bunny model. */
+ public static int gen3DObjectList(GL gl) throws IOException {
+ StreamTokenizer tok = new StreamTokenizer(new BufferedReader(new InputStreamReader(
+ Bunny.class.getClassLoader().getResourceAsStream("demos/data/models/bunny.txt"))));
+ // Reset tokenizer's syntax so numbers are not parsed
+ tok.resetSyntax();
+ tok.wordChars('a', 'z');
+ tok.wordChars('A', 'Z');
+ tok.wordChars('0', '9');
+ tok.wordChars('-', '-');
+ tok.wordChars('.', '.');
+ tok.wordChars(128 + 32, 255);
+ tok.whitespaceChars(0, ' ');
+ tok.whitespaceChars(',', ',');
+ tok.whitespaceChars('{', '{');
+ tok.whitespaceChars('}', '}');
+ tok.commentChar('/');
+ tok.quoteChar('"');
+ tok.quoteChar('\'');
+ tok.slashSlashComments(true);
+ tok.slashStarComments(true);
+
+ // Read in file
+ int numFaceIndices = nextInt(tok, "number of face indices");
+ short[] faceIndices = new short[numFaceIndices * 6];
+ for (int i = 0; i < numFaceIndices * 6; i++) {
+ faceIndices[i] = (short) nextInt(tok, "face index");
+ }
+ int numVertices = nextInt(tok, "number of vertices");
+ float[] vertices = new float[numVertices * 3];
+ for (int i = 0; i < numVertices * 3; i++) {
+ vertices[i] = nextFloat(tok, "vertex");
+ }
+ int numNormals = nextInt(tok, "number of normals");
+ float[] normals = new float[numNormals * 3];
+ for (int i = 0; i < numNormals * 3; i++) {
+ normals[i] = nextFloat(tok, "normal");
+ }
+
+ int lid = gl.glGenLists(1);
+ gl.glNewList(lid, GL.GL_COMPILE);
+
+ gl.glBegin(GL.GL_TRIANGLES);
+ for (int i = 0; i < faceIndices.length; i += 6) {
+ for (int j = 0; j < 3; j++) {
+ int vi = faceIndices[i + j];
+ int ni = faceIndices[i + j + 3];
+ gl.glNormal3f(normals[3 * ni],
+ normals[3 * ni + 1],
+ normals[3 * ni + 2]);
+ gl.glVertex3f(vertices[3 * vi],
+ vertices[3 * vi + 1],
+ vertices[3 * vi + 2]);
+ }
+ }
+ gl.glEnd();
+
+ gl.glEndList();
+ return lid;
+ }
+
+ private static int nextInt(StreamTokenizer tok, String error) throws IOException {
+ if (tok.nextToken() != StreamTokenizer.TT_WORD) {
+ throw new IOException("Parse error reading " + error + " at line " + tok.lineno());
+ }
+ try {
+ return Integer.parseInt(tok.sval);
+ } catch (NumberFormatException e) {
+ throw new IOException("Parse error reading " + error + " at line " + tok.lineno());
+ }
+ }
+
+ private static float nextFloat(StreamTokenizer tok, String error) throws IOException {
+ if (tok.nextToken() != StreamTokenizer.TT_WORD) {
+ throw new IOException("Parse error reading " + error + " at line " + tok.lineno());
+ }
+ try {
+ return Float.parseFloat(tok.sval);
+ } catch (NumberFormatException e) {
+ throw new IOException("Parse error reading " + error + " at line " + tok.lineno());
+ }
+ }
+}
diff --git a/src/demos/util/DDSReader.java b/src/demos/util/DDSReader.java
new file mode 100644
index 0000000..6355a65
--- /dev/null
+++ b/src/demos/util/DDSReader.java
@@ -0,0 +1,413 @@
+/*
+ * 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
+ * MIDROSYSTEMS, 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.*;
+
+/** A reader for DirectDraw Surface (.dds) files, which are used to
+ describe textures. These files can contain multiple mipmap levels
+ in one file. This reader is currently minimal and does not support
+ all of the possible file formats. */
+
+public class DDSReader {
+
+ /** Simple class describing images and data; does not encapsulate
+ image format information. User is responsible for transmitting
+ that information in another way. */
+
+ public static class ImageInfo {
+ private ByteBuffer data;
+ private int width;
+ private int height;
+
+ public ImageInfo(ByteBuffer data, int width, int height) {
+ this.data = data; this.width = width; this.height = height;
+ }
+ public int getWidth() { return width; }
+ public int getHeight() { return height; }
+ public ByteBuffer getData() { return data; }
+ }
+
+ private FileInputStream fis;
+ private FileChannel chan;
+ private ByteBuffer buf;
+ private Header header;
+
+ // FourCC codes (compression formats)
+ public static final int DXT1 = 0x31545844;
+ public static final int DXT2 = 0x32545844;
+ public static final int DXT3 = 0x33545844;
+ public static final int DXT4 = 0x34545844;
+ public static final int DXT5 = 0x35545844;
+
+ //
+ // Selected bits in header flags
+ //
+
+ public static final int DDSD_CAPS = 0x00000001; // Capacities are valid
+ public static final int DDSD_HEIGHT = 0x00000002; // Height is valid
+ public static final int DDSD_WIDTH = 0x00000004; // Width is valid
+ public static final int DDSD_PITCH = 0x00000008; // Pitch is valid
+ public static final int DDSD_BACKBUFFERCOUNT = 0x00000020; // Back buffer count is valid
+ public static final int DDSD_ZBUFFERBITDEPTH = 0x00000040; // Z-buffer bit depth is valid (shouldn't be used in DDSURFACEDESC2)
+ public static final int DDSD_ALPHABITDEPTH = 0x00000080; // Alpha bit depth is valid
+ public static final int DDSD_LPSURFACE = 0x00000800; // lpSurface is valid
+ public static final int DDSD_PIXELFORMAT = 0x00001000; // ddpfPixelFormat is valid
+ public static final int DDSD_MIPMAPCOUNT = 0x00020000; // Mip map count is valid
+ public static final int DDSD_LINEARSIZE = 0x00080000; // dwLinearSize is valid
+ public static final int DDSD_DEPTH = 0x00800000; // dwDepth is valid
+
+ public static final int DDPF_ALPHAPIXELS = 0x00000001; // Alpha channel is present
+ public static final int DDPF_ALPHA = 0x00000002; // Only contains alpha information
+ public static final int DDPF_RGB = 0x00000040; // RGB data is present
+
+ // Selected bits in DDS capabilities flags
+ public static final int DDSCAPS_TEXTURE = 0x00001000; // Can be used as a texture
+ public static final int DDSCAPS_MIPMAP = 0x00400000; // Is one level of a mip-map
+
+ // Known pixel formats
+ public static final int D3DFMT_UNKNOWN = 0;
+ public static final int D3DFMT_R8G8B8 = 20;
+ public static final int D3DFMT_A8R8G8B8 = 21;
+ public static final int D3DFMT_X8R8G8B8 = 22;
+
+ public void loadFile(String filename) throws IOException {
+ File file = new File(filename);
+ fis = new FileInputStream(filename);
+ chan = fis.getChannel();
+ buf = chan.map(FileChannel.MapMode.READ_ONLY,
+ 0, (int) file.length());
+ buf.order(ByteOrder.LITTLE_ENDIAN);
+ header = new Header();
+ header.read(buf);
+ }
+
+ public void close() {
+ try {
+ chan.close();
+ fis.close();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+
+ /** Test for presence/absence of surface description flags (DDSD_*) */
+ public boolean isSurfaceDescFlagSet(int flag) {
+ return ((header.flags & flag) != 0);
+ }
+
+ /** Test for presence/absence of pixel format flags (DDPF_*) */
+ public boolean isPixelFormatFlagSet(int flag) {
+ return ((header.pfFlags & flag) != 0);
+ }
+
+ /** Gets the pixel format of this texture (D3DFMT_*) based on some
+ heuristics. Returns D3DFMT_UNKNOWN if could not recognize the
+ pixel format. */
+ public int getPixelFormat() {
+ if (isPixelFormatFlagSet(DDPF_RGB)) {
+ if (isPixelFormatFlagSet(DDPF_ALPHAPIXELS)) {
+ if (getDepth() == 32 &&
+ header.pfRBitMask == 0x00FF0000 &&
+ header.pfGBitMask == 0x0000FF00 &&
+ header.pfBBitMask == 0x000000FF &&
+ header.pfABitMask == 0xFF000000) {
+ return D3DFMT_A8R8G8B8;
+ }
+ } else {
+ if (getDepth() == 24 &&
+ header.pfRBitMask == 0x00FF0000 &&
+ header.pfGBitMask == 0x0000FF00 &&
+ header.pfBBitMask == 0x000000FF) {
+ return D3DFMT_R8G8B8;
+ } else if (getDepth() == 32 &&
+ header.pfRBitMask == 0x00FF0000 &&
+ header.pfGBitMask == 0x0000FF00 &&
+ header.pfBBitMask == 0x000000FF) {
+ return D3DFMT_X8R8G8B8;
+ }
+ }
+ }
+
+ return D3DFMT_UNKNOWN;
+ }
+
+ /** Indicates whether this texture is compressed. */
+ public boolean isCompressed() {
+ return (getCompressionFormat() != 0);
+ }
+
+ /** If this surface is compressed, returns the kind of compression
+ used (DXT1..DXT5). */
+ public int getCompressionFormat() {
+ return header.pfFourCC;
+ }
+
+ /** Width of the texture (or the top-most mipmap if mipmaps are
+ present) */
+ public int getWidth() {
+ return header.width;
+ }
+
+ /** Height of the texture (or the top-most mipmap if mipmaps are
+ present) */
+ public int getHeight() {
+ return header.height;
+ }
+
+ /** Total number of bits per pixel. Only valid if DDPF_RGB is
+ present. For A8R8G8B8, would be 32. */
+ public int getDepth() {
+ return header.pfRGBBitCount;
+ }
+
+ /** Number of mip maps in the texture */
+ public int getNumMipMaps() {
+ if (!isSurfaceDescFlagSet(DDSD_MIPMAPCOUNT)) {
+ return 0;
+ }
+ return header.mipMapCountOrAux;
+ }
+
+ /** Gets the <i>i</i>th mipmap data (0..getNumMipMaps() - 1) */
+ public ImageInfo getMipMap(int map) {
+ if (isCompressed()) {
+ throw new RuntimeException("Sorry, compressed textures not supported yet");
+ }
+ // Figure out how far to seek
+ int seek = 4 + header.size;
+ for (int i = 0; i < map; i++) {
+ seek += mipMapSizeInBytes(i);
+ }
+ buf.limit(seek + mipMapSizeInBytes(map));
+ buf.position(seek);
+ ByteBuffer next = buf.slice();
+ buf.position(0);
+ buf.limit(buf.capacity());
+ return new ImageInfo(next, mipMapWidth(map), mipMapHeight(map));
+ }
+
+ /** Returns an array of ImageInfos corresponding to all mipmap
+ levels of this DDS file. */
+ public ImageInfo[] getAllMipMaps() {
+ int numLevels = getNumMipMaps();
+ if (numLevels == 0) {
+ numLevels = 1;
+ }
+ ImageInfo[] result = new ImageInfo[numLevels];
+ for (int i = 0; i < numLevels; i++) {
+ result[i] = getMipMap(i);
+ }
+ return result;
+ }
+
+ public void debugPrint() {
+ PrintStream tty = System.err;
+ tty.println("Compressed texture: " + isCompressed());
+ if (isCompressed()) {
+ int fmt = getCompressionFormat();
+ StringBuffer buf = new StringBuffer();
+ for (int i = 0; i < 4; i++) {
+ char c = (char) (fmt & 0xFF);
+ buf.append(c);
+ fmt = fmt >> 8;
+ }
+ tty.println("Compression format: 0x" + Integer.toHexString(getCompressionFormat()) + " (" + buf + ")");
+ }
+ tty.println("SurfaceDesc flags:");
+ boolean recognizedAny = false;
+ recognizedAny |= printIfRecognized(tty, header.flags, DDSD_CAPS, "DDSD_CAPS");
+ recognizedAny |= printIfRecognized(tty, header.flags, DDSD_HEIGHT, "DDSD_HEIGHT");
+ recognizedAny |= printIfRecognized(tty, header.flags, DDSD_WIDTH, "DDSD_WIDTH");
+ recognizedAny |= printIfRecognized(tty, header.flags, DDSD_PITCH, "DDSD_PITCH");
+ recognizedAny |= printIfRecognized(tty, header.flags, DDSD_BACKBUFFERCOUNT, "DDSD_BACKBUFFERCOUNT");
+ recognizedAny |= printIfRecognized(tty, header.flags, DDSD_ZBUFFERBITDEPTH, "DDSD_ZBUFFERBITDEPTH");
+ recognizedAny |= printIfRecognized(tty, header.flags, DDSD_ALPHABITDEPTH, "DDSD_ALPHABITDEPTH");
+ recognizedAny |= printIfRecognized(tty, header.flags, DDSD_LPSURFACE, "DDSD_LPSURFACE");
+ recognizedAny |= printIfRecognized(tty, header.flags, DDSD_PIXELFORMAT, "DDSD_PIXELFORMAT");
+ recognizedAny |= printIfRecognized(tty, header.flags, DDSD_MIPMAPCOUNT, "DDSD_MIPMAPCOUNT");
+ recognizedAny |= printIfRecognized(tty, header.flags, DDSD_LINEARSIZE, "DDSD_LINEARSIZE");
+ recognizedAny |= printIfRecognized(tty, header.flags, DDSD_DEPTH, "DDSD_DEPTH");
+ if (!recognizedAny) {
+ tty.println("(none)");
+ }
+ tty.println("Raw SurfaceDesc flags: 0x" + Integer.toHexString(header.flags));
+ tty.println("Pixel format flags:");
+ recognizedAny = false;
+ recognizedAny |= printIfRecognized(tty, header.pfFlags, DDPF_RGB, "DDPF_RGB");
+ recognizedAny |= printIfRecognized(tty, header.pfFlags, DDPF_ALPHA, "DDPF_ALPHA");
+ recognizedAny |= printIfRecognized(tty, header.pfFlags, DDPF_ALPHAPIXELS, "DDPF_ALPHAPIXELS");
+ if (!recognizedAny) {
+ tty.println("(none)");
+ }
+ tty.println("Raw pixel format flags: 0x" + Integer.toHexString(header.pfFlags));
+ tty.println("Depth: " + getDepth());
+ tty.println("Number of mip maps: " + getNumMipMaps());
+ int fmt = getPixelFormat();
+ tty.print("Pixel format: ");
+ switch (fmt) {
+ case D3DFMT_R8G8B8: tty.println("D3DFMT_R8G8B8"); break;
+ case D3DFMT_A8R8G8B8: tty.println("D3DFMT_A8R8G8B8"); break;
+ case D3DFMT_X8R8G8B8: tty.println("D3DFMT_X8R8G8B8"); break;
+ case D3DFMT_UNKNOWN: tty.println("D3DFMT_UNKNOWN"); break;
+ default: tty.println("(unknown pixel format " + fmt + ")"); break;
+ }
+ }
+
+ //----------------------------------------------------------------------
+ // Internals only below this point
+ //
+
+ private static final int MAGIC = 0x20534444;
+
+ static class Header {
+ int size; // size of the DDSURFACEDESC structure
+ int flags; // determines what fields are valid
+ int height; // height of surface to be created
+ int width; // width of input surface
+ int pitchOrLinearSize;
+ int backBufferCountOrDepth;
+ int mipMapCountOrAux; // number of mip-map levels requested (in this context)
+ int alphaBitDepth; // depth of alpha buffer requested
+ int reserved1; // reserved
+ int surface; // pointer to the associated surface memory
+ // NOTE: following two entries are from DDCOLORKEY data structure
+ // Are overlaid with color for empty cubemap faces (unused in this reader)
+ int colorSpaceLowValue;
+ int colorSpaceHighValue;
+ int destBltColorSpaceLowValue;
+ int destBltColorSpaceHighValue;
+ int srcOverlayColorSpaceLowValue;
+ int srcOverlayColorSpaceHighValue;
+ int srcBltColorSpaceLowValue;
+ int srcBltColorSpaceHighValue;
+ // NOTE: following entries are from DDPIXELFORMAT data structure
+ // Are overlaid with flexible vertex format description of vertex
+ // buffers (unused in this reader)
+ int pfSize; // size of DDPIXELFORMAT structure
+ int pfFlags; // pixel format flags
+ int pfFourCC; // (FOURCC code)
+ // Following five entries have multiple interpretations, not just
+ // RGBA (but that's all we support right now)
+ int pfRGBBitCount; // how many bits per pixel
+ int pfRBitMask; // mask for red bits
+ int pfGBitMask; // mask for green bits
+ int pfBBitMask; // mask for blue bits
+ int pfABitMask; // mask for alpha channel
+ int ddsCaps1; // Texture and mip-map flags
+ int ddsCaps2; // Advanced capabilities, not yet used
+ int ddsCapsReserved1;
+ int ddsCapsReserved2;
+ int textureStage; // stage in multitexture cascade
+
+ void read(ByteBuffer buf) throws IOException {
+ int magic = buf.getInt();
+ if (magic != MAGIC) {
+ throw new IOException("Incorrect magic number 0x" +
+ Integer.toHexString(magic) +
+ " (expected " + MAGIC + ")");
+ }
+
+ size = buf.getInt();
+ flags = buf.getInt();
+ height = buf.getInt();
+ width = buf.getInt();
+ pitchOrLinearSize = buf.getInt();
+ backBufferCountOrDepth = buf.getInt();
+ mipMapCountOrAux = buf.getInt();
+ alphaBitDepth = buf.getInt();
+ reserved1 = buf.getInt();
+ surface = buf.getInt();
+ colorSpaceLowValue = buf.getInt();
+ colorSpaceHighValue = buf.getInt();
+ destBltColorSpaceLowValue = buf.getInt();
+ destBltColorSpaceHighValue = buf.getInt();
+ srcOverlayColorSpaceLowValue = buf.getInt();
+ srcOverlayColorSpaceHighValue = buf.getInt();
+ srcBltColorSpaceLowValue = buf.getInt();
+ srcBltColorSpaceHighValue = buf.getInt();
+ pfSize = buf.getInt();
+ pfFlags = buf.getInt();
+ pfFourCC = buf.getInt();
+ pfRGBBitCount = buf.getInt();
+ pfRBitMask = buf.getInt();
+ pfGBitMask = buf.getInt();
+ pfBBitMask = buf.getInt();
+ pfABitMask = buf.getInt();
+ ddsCaps1 = buf.getInt();
+ ddsCaps2 = buf.getInt();
+ ddsCapsReserved1 = buf.getInt();
+ ddsCapsReserved2 = buf.getInt();
+ textureStage = buf.getInt();
+ }
+ }
+
+ private int mipMapWidth(int map) {
+ int width = getWidth();
+ for (int i = 0; i < map; i++) {
+ width >>= 1;
+ }
+ return width;
+ }
+
+ private int mipMapHeight(int map) {
+ int height = getHeight();
+ for (int i = 0; i < map; i++) {
+ height >>= 1;
+ }
+ return height;
+ }
+
+ private int mipMapSizeInBytes(int map) {
+ int width = mipMapWidth(map);
+ int height = mipMapHeight(map);
+ return width * height * (getDepth() / 8);
+ }
+
+ private boolean printIfRecognized(PrintStream tty, int flags, int flag, String what) {
+ if ((flags & flag) != 0) {
+ tty.println(what);
+ return true;
+ }
+ return false;
+ }
+}
diff --git a/src/demos/util/DurationTimer.java b/src/demos/util/DurationTimer.java
new file mode 100644
index 0000000..cd53fe1
--- /dev/null
+++ b/src/demos/util/DurationTimer.java
@@ -0,0 +1,68 @@
+/*
+ * 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
+ * MIDROSYSTEMS, 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;
+
+/** Simple class for helping measure frames-per-second. */
+
+public class DurationTimer {
+ private long startTime;
+ private long accumulatedTime;
+
+ public void reset() {
+ accumulatedTime = 0;
+ }
+
+ public void start() {
+ startTime = System.currentTimeMillis();
+ }
+
+ public void stop() {
+ long curTime = System.currentTimeMillis();
+ accumulatedTime += (curTime - startTime);
+ }
+
+ public long getDuration() {
+ return accumulatedTime;
+ }
+
+ public float getDurationAsSeconds() {
+ return (float) accumulatedTime / 1000.0f;
+ }
+}
diff --git a/src/demos/util/DxTex.java b/src/demos/util/DxTex.java
new file mode 100644
index 0000000..8e066f8
--- /dev/null
+++ b/src/demos/util/DxTex.java
@@ -0,0 +1,375 @@
+/*
+ * 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
+ * MIDROSYSTEMS, 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.awt.image.*;
+import java.awt.event.*;
+import javax.swing.*;
+import javax.swing.event.*;
+import javax.swing.filechooser.*;
+
+/** Simplified clone of DxTex tool from the DirectX SDK, written in
+ Java using the DDSReader; tests fetching of texture data */
+
+public class DxTex {
+ private InternalFrameListener frameListener;
+ private File defaultDirectory;
+ private JDesktopPane desktop;
+ private static String endl = System.getProperty("line.separator");
+ private JMenu mipMapMenu;
+
+ public static void main(String[] args) {
+ new DxTex().run(args);
+ }
+
+ private void run(String[] args) {
+ defaultDirectory = new File(System.getProperty("user.dir"));
+ JFrame frame = new JFrame("DirectX Texture Tool");
+ frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
+ JMenuBar menuBar = new JMenuBar();
+ JMenu menu = createMenu("File", 'F', 0);
+ JMenuItem item =
+ createMenuItem("Open...",
+ new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ openFile();
+ }
+ },
+ KeyEvent.VK_O, InputEvent.CTRL_MASK,
+ 'O', 0);
+ menu.add(item);
+ item =
+ createMenuItem("Exit",
+ new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ System.exit(0);
+ }
+ },
+ KeyEvent.VK_Q, InputEvent.CTRL_MASK,
+ 'x', 1);
+ menu.add(item);
+ menuBar.add(menu);
+
+ menu = createMenu("MipMap", 'M', 0);
+ menu.setEnabled(false);
+ mipMapMenu = menu;
+ menuBar.add(menu);
+
+ frame.setJMenuBar(menuBar);
+
+ desktop = new JDesktopPane();
+ frame.getContentPane().add(desktop);
+ frame.setSize(640, 480);
+ frame.show();
+
+ frameListener = new InternalFrameAdapter() {
+ public void internalFrameActivated(InternalFrameEvent e) {
+ JInternalFrame ifr = e.getInternalFrame();
+ if (ifr instanceof ImageFrame) {
+ // Recompute entries in mip map menu
+ final ImageFrame frame = (ImageFrame) ifr;
+ if (frame.getNumMipMaps() > 0) {
+ mipMapMenu.removeAll();
+ // Add entries
+ for (int i = 0; i < frame.getNumMipMaps(); i++) {
+ final int map = i;
+ JMenuItem item;
+ String title = "Level " + (i + 1);
+ ActionListener listener = new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ SwingUtilities.invokeLater(new Runnable() {
+ public void run() {
+ frame.setMipMapLevel(map);
+ }
+ });
+ }
+ };
+ if (i < 9) {
+ char c = (char) ('0' + i + 1);
+ item = createMenuItem(title, listener, c, 6);
+ } else {
+ item = createMenuItem(title, listener);
+ }
+ mipMapMenu.add(item);
+ }
+ mipMapMenu.setEnabled(true);
+ } else {
+ mipMapMenu.setEnabled(false);
+ }
+ } else {
+ mipMapMenu.setEnabled(false);
+ }
+ }
+
+ public void internalFrameClosing(InternalFrameEvent e) {
+ desktop.remove(e.getInternalFrame());
+ desktop.invalidate();
+ desktop.validate();
+ desktop.repaint();
+ // THIS SHOULD NOT BE NECESSARY
+ desktop.requestFocus();
+ }
+
+ public void internalFrameClosed(InternalFrameEvent e) {
+ JInternalFrame ifr = e.getInternalFrame();
+ if (ifr instanceof ImageFrame) {
+ ((ImageFrame) ifr).close();
+ }
+ }
+ };
+
+ for (int i = 0; i < args.length; i++) {
+ final File file = new File(args[i]);
+ SwingUtilities.invokeLater(new Runnable() {
+ public void run() {
+ openFile(file);
+ }
+ });
+ }
+ }
+
+ //----------------------------------------------------------------------
+ // Actions
+ //
+
+ private void openFile() {
+ JFileChooser chooser = new JFileChooser(defaultDirectory);
+ chooser.setMultiSelectionEnabled(false);
+ chooser.addChoosableFileFilter(new javax.swing.filechooser.FileFilter() {
+ public boolean accept(File f) {
+ return (f.isDirectory() ||
+ f.getName().endsWith(".dds"));
+ }
+
+ public String getDescription() {
+ return "Texture files (*.dds)";
+ }
+ });
+
+ int res = chooser.showOpenDialog(null);
+ if (res == JFileChooser.APPROVE_OPTION) {
+ final File file = chooser.getSelectedFile();
+ defaultDirectory = file.getParentFile();
+ SwingUtilities.invokeLater(new Runnable() {
+ public void run() {
+ openFile(file);
+ }
+ });
+ }
+ }
+
+ private void openFile(File file) {
+ try {
+ DDSReader reader = new DDSReader();
+ reader.loadFile(file.getAbsolutePath());
+ showImage(file.getName(), reader, 0);
+ } catch (IOException e) {
+ showMessageDialog("Error while opening file:" + endl +
+ exceptionToString(e),
+ "Error opening file",
+ JOptionPane.WARNING_MESSAGE);
+ }
+ }
+
+ //----------------------------------------------------------------------
+ // Image display
+ //
+
+ private void showImage(String filename, DDSReader reader, int mipMapLevel) {
+ try {
+ ImageFrame fr = new ImageFrame(filename, reader, mipMapLevel);
+ desktop.add(fr);
+ fr.show();
+ } catch (Exception e) {
+ showMessageDialog("Error while loading file:" + endl +
+ exceptionToString(e),
+ "Error loading file",
+ JOptionPane.WARNING_MESSAGE);
+ }
+ }
+
+ class ImageFrame extends JInternalFrame {
+ private String filename;
+ private DDSReader reader;
+ private int mipMapLevel;
+ private int curWidth;
+ private int curHeight;
+ private JLabel label;
+
+ ImageFrame(String filename, DDSReader reader, int mipMapLevel) {
+ super();
+ this.filename = filename;
+ this.reader = reader;
+
+ addInternalFrameListener(frameListener);
+ label = new JLabel();
+ JScrollPane scroller = new JScrollPane(label);
+ getContentPane().add(scroller);
+ setSize(400, 400);
+ setResizable(true);
+ setIconifiable(true);
+ setClosable(true);
+ setMipMapLevel(mipMapLevel);
+ }
+
+ int getNumMipMaps() {
+ return reader.getNumMipMaps();
+ }
+
+ void setMipMapLevel(int level) {
+ mipMapLevel = level;
+ computeImage();
+ resetTitle();
+ }
+
+ void close() {
+ System.err.println("Closing files");
+ reader.close();
+ }
+
+ private void computeImage() {
+ // Get image data
+ reader.getNumMipMaps();
+ DDSReader.ImageInfo info = reader.getMipMap(mipMapLevel);
+ int width = info.getWidth();
+ int height = info.getHeight();
+ curWidth = width;
+ curHeight = height;
+ ByteBuffer data = info.getData();
+
+ // Build ImageIcon out of image data
+ BufferedImage img = new BufferedImage(width, height,
+ BufferedImage.TYPE_3BYTE_BGR);
+ WritableRaster dst = img.getRaster();
+
+ int skipSize;
+ if (reader.getPixelFormat() == DDSReader.D3DFMT_A8R8G8B8) {
+ skipSize = 4;
+ } else if (reader.getPixelFormat() == DDSReader.D3DFMT_R8G8B8) {
+ skipSize = 3;
+ } else {
+ reader.close();
+ throw new RuntimeException("Unsupported pixel format " + reader.getPixelFormat());
+ }
+
+ for (int y = 0; y < height; y++) {
+ for (int x = 0; x < width; x++) {
+ // NOTE: highly suspicious that A comes fourth in
+ // A8R8G8B8...not really ARGB, but RGBA (like OpenGL)
+ dst.setSample(x, y, 0, data.get(skipSize * (width * y + x) + 2) & 0xFF);
+ dst.setSample(x, y, 1, data.get(skipSize * (width * y + x) + 1) & 0xFF);
+ dst.setSample(x, y, 2, data.get(skipSize * (width * y + x) + 0) & 0xFF);
+ }
+ }
+
+ label.setIcon(new ImageIcon(img));
+ }
+
+ private void resetTitle() {
+ setTitle(filename + " (" + curWidth + "x" + curHeight +
+ ", mipmap " + (1 + mipMapLevel) + " of " +
+ reader.getNumMipMaps() + ")");
+ }
+ }
+
+
+ //----------------------------------------------------------------------
+ // Menu and menu item creation
+ //
+
+ private static JMenu createMenu(String name, char mnemonic, int mnemonicPos) {
+ JMenu menu = new JMenu(name);
+ menu.setMnemonic(mnemonic);
+ menu.setDisplayedMnemonicIndex(mnemonicPos);
+ return menu;
+ }
+
+ private static JMenuItem createMenuItem(String name, ActionListener l) {
+ JMenuItem item = new JMenuItem(name);
+ item.addActionListener(l);
+ return item;
+ }
+
+ private static JMenuItem createMenuItemInternal(String name, ActionListener l, int accelerator, int modifiers) {
+ JMenuItem item = createMenuItem(name, l);
+ item.setAccelerator(KeyStroke.getKeyStroke(accelerator, modifiers));
+ return item;
+ }
+
+ private static JMenuItem createMenuItem(String name, ActionListener l, int accelerator) {
+ return createMenuItemInternal(name, l, accelerator, 0);
+ }
+
+ private static JMenuItem createMenuItem(String name, ActionListener l, char mnemonic, int mnemonicPos) {
+ JMenuItem item = createMenuItem(name, l);
+ item.setMnemonic(mnemonic);
+ item.setDisplayedMnemonicIndex(mnemonicPos);
+ return item;
+ }
+
+ private static JMenuItem createMenuItem(String name,
+ ActionListener l,
+ int accelerator,
+ int acceleratorMods,
+ char mnemonic,
+ int mnemonicPos) {
+ JMenuItem item = createMenuItemInternal(name, l, accelerator, acceleratorMods);
+ item.setMnemonic(mnemonic);
+ item.setDisplayedMnemonicIndex(mnemonicPos);
+ return item;
+ }
+
+ private void showMessageDialog(final String message, final String title, final int jOptionPaneKind) {
+ SwingUtilities.invokeLater(new Runnable() {
+ public void run() {
+ JOptionPane.showInternalMessageDialog(desktop, message, title, jOptionPaneKind);
+ }
+ });
+ }
+
+ private static String exceptionToString(Exception e) {
+ ByteArrayOutputStream bos = new ByteArrayOutputStream();
+ PrintStream s = new PrintStream(bos);
+ e.printStackTrace(s);
+ return bos.toString();
+ }
+}
diff --git a/src/demos/util/FloatList.java b/src/demos/util/FloatList.java
new file mode 100644
index 0000000..6a7f117
--- /dev/null
+++ b/src/demos/util/FloatList.java
@@ -0,0 +1,100 @@
+/*
+ * 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
+ * MIDROSYSTEMS, 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;
+
+/** Growable array of floats. */
+
+public class FloatList {
+ private static final int DEFAULT_SIZE = 10;
+
+ private float[] data = new float[DEFAULT_SIZE];
+ private int numElements;
+
+ public void add(float f) {
+ if (numElements == data.length) {
+ resize(1 + numElements);
+ }
+ data[numElements++] = f;
+ assert numElements <= data.length;
+ }
+
+ public int size() {
+ return numElements;
+ }
+
+ public float get(int index) {
+ if (index >= numElements) {
+ throw new ArrayIndexOutOfBoundsException(index);
+ }
+ return data[index];
+ }
+
+ public void put(int index, float val) {
+ if (index >= numElements) {
+ throw new ArrayIndexOutOfBoundsException(index);
+ }
+ data[index] = val;
+ }
+
+ public void trim() {
+ if (data.length > numElements) {
+ float[] newData = new float[numElements];
+ System.arraycopy(data, 0, newData, 0, numElements);
+ data = newData;
+ }
+ }
+
+ public float[] getData() {
+ return data;
+ }
+
+ private void resize(int minCapacity) {
+ int newCapacity = 2 * data.length;
+ if (newCapacity == 0) {
+ newCapacity = DEFAULT_SIZE;
+ }
+ if (newCapacity < minCapacity) {
+ newCapacity = minCapacity;
+ }
+ float[] newData = new float[newCapacity];
+ System.arraycopy(data, 0, newData, 0, data.length);
+ data = newData;
+ }
+}
diff --git a/src/demos/util/IntList.java b/src/demos/util/IntList.java
new file mode 100644
index 0000000..9e48033
--- /dev/null
+++ b/src/demos/util/IntList.java
@@ -0,0 +1,100 @@
+/*
+ * 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
+ * MIDROSYSTEMS, 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;
+
+/** Growable array of ints. */
+
+public class IntList {
+ private static final int DEFAULT_SIZE = 10;
+
+ private int[] data = new int[DEFAULT_SIZE];
+ private int numElements;
+
+ public void add(int f) {
+ if (numElements == data.length) {
+ resize(1 + numElements);
+ }
+ data[numElements++] = f;
+ assert numElements <= data.length;
+ }
+
+ public int size() {
+ return numElements;
+ }
+
+ public int get(int index) {
+ if (index >= numElements) {
+ throw new ArrayIndexOutOfBoundsException(index);
+ }
+ return data[index];
+ }
+
+ public void put(int index, int val) {
+ if (index >= numElements) {
+ throw new ArrayIndexOutOfBoundsException(index);
+ }
+ data[index] = val;
+ }
+
+ public void trim() {
+ if (data.length > numElements) {
+ int[] newData = new int[numElements];
+ System.arraycopy(data, 0, newData, 0, numElements);
+ data = newData;
+ }
+ }
+
+ public int[] getData() {
+ return data;
+ }
+
+ private void resize(int minCapacity) {
+ int newCapacity = 2 * data.length;
+ if (newCapacity == 0) {
+ newCapacity = DEFAULT_SIZE;
+ }
+ if (newCapacity < minCapacity) {
+ newCapacity = minCapacity;
+ }
+ int[] newData = new int[newCapacity];
+ System.arraycopy(data, 0, newData, 0, data.length);
+ data = newData;
+ }
+}
diff --git a/src/demos/util/LEDataInputStream.java b/src/demos/util/LEDataInputStream.java
new file mode 100644
index 0000000..b391885
--- /dev/null
+++ b/src/demos/util/LEDataInputStream.java
@@ -0,0 +1,223 @@
+/*
+ * 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
+ * MIDROSYSTEMS, 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.DataInput;
+import java.io.DataInputStream;
+import java.io.FilterInputStream;
+import java.io.InputStream;
+import java.io.FileInputStream;
+import java.io.EOFException;
+import java.io.IOException;
+
+/**
+ * Little Endian Data Input Stream.
+ *
+ * This class implements an input stream filter to allow reading
+ * of java native datatypes from an input stream which has those
+ * native datatypes stored in a little endian byte order.<p>
+ *
+ * This is the sister class of the DataInputStream which allows
+ * for reading of java native datatypes from an input stream with
+ * the datatypes stored in big endian byte order.<p>
+ *
+ * This class implements the minimum required and calls DataInputStream
+ * for some of the required methods for DataInput.<p>
+ *
+ * Not all methods are implemented due to lack of immediatte requirement
+ * for that functionality. It is not clear if it is ever going to be
+ * functionally required to be able to read UTF data in a LittleEndianManner<p>
+ *
+ * @author Robin Luiten
+ * @version 1.1 15/Dec/1997
+ */
+public class LEDataInputStream extends FilterInputStream implements DataInput
+{
+ /**
+ * To reuse some of the non endian dependent methods from
+ * DataInputStreams methods.
+ */
+ DataInputStream dataIn;
+
+ public LEDataInputStream(InputStream in)
+ {
+ super(in);
+ dataIn = new DataInputStream(in);
+ }
+
+ public void close() throws IOException
+ {
+ dataIn.close(); // better close as we create it.
+ // this will close underlying as well.
+ }
+
+ public synchronized final int read(byte b[]) throws IOException
+ {
+ return dataIn.read(b, 0, b.length);
+ }
+
+ public synchronized final int read(byte b[], int off, int len) throws IOException
+ {
+ int rl = dataIn.read(b, off, len);
+ return rl;
+ }
+
+ public final void readFully(byte b[]) throws IOException
+ {
+ dataIn.readFully(b, 0, b.length);
+ }
+
+ public final void readFully(byte b[], int off, int len) throws IOException
+ {
+ dataIn.readFully(b, off, len);
+ }
+
+ public final int skipBytes(int n) throws IOException
+ {
+ return dataIn.skipBytes(n);
+ }
+
+ public final boolean readBoolean() throws IOException
+ {
+ int ch = dataIn.read();
+ if (ch < 0)
+ throw new EOFException();
+ return (ch != 0);
+ }
+
+ public final byte readByte() throws IOException
+ {
+ int ch = dataIn.read();
+ if (ch < 0)
+ throw new EOFException();
+ return (byte)(ch);
+ }
+
+ public final int readUnsignedByte() throws IOException
+ {
+ int ch = dataIn.read();
+ if (ch < 0)
+ throw new EOFException();
+ return ch;
+ }
+
+ public final short readShort() throws IOException
+ {
+ int ch1 = dataIn.read();
+ int ch2 = dataIn.read();
+ if ((ch1 | ch2) < 0)
+ throw new EOFException();
+ return (short)((ch1 << 0) + (ch2 << 8));
+ }
+
+ public final int readUnsignedShort() throws IOException
+ {
+ int ch1 = dataIn.read();
+ int ch2 = dataIn.read();
+ if ((ch1 | ch2) < 0)
+ throw new EOFException();
+ return (ch1 << 0) + (ch2 << 8);
+ }
+
+ public final char readChar() throws IOException
+ {
+ int ch1 = dataIn.read();
+ int ch2 = dataIn.read();
+ if ((ch1 | ch2) < 0)
+ throw new EOFException();
+ return (char)((ch1 << 0) + (ch2 << 8));
+ }
+
+ public final int readInt() throws IOException
+ {
+ int ch1 = dataIn.read();
+ int ch2 = dataIn.read();
+ int ch3 = dataIn.read();
+ int ch4 = dataIn.read();
+ if ((ch1 | ch2 | ch3 | ch4) < 0)
+ throw new EOFException();
+ return ((ch1 << 0) + (ch2 << 8) + (ch3 << 16) + (ch4 << 24));
+ }
+
+ public final long readLong() throws IOException
+ {
+ int i1 = readInt();
+ int i2 = readInt();
+ return ((long)(i1) & 0xFFFFFFFFL) + (i2 << 32);
+ }
+
+ public final float readFloat() throws IOException
+ {
+ return Float.intBitsToFloat(readInt());
+ }
+
+ public final double readDouble() throws IOException
+ {
+ return Double.longBitsToDouble(readLong());
+ }
+
+ /**
+ * dont call this it is not implemented.
+ * @return empty new string
+ **/
+ public final String readLine() throws IOException
+ {
+ return new String();
+ }
+
+ /**
+ * dont call this it is not implemented
+ * @return empty new string
+ **/
+ public final String readUTF() throws IOException
+ {
+ return new String();
+ }
+
+ /**
+ * dont call this it is not implemented
+ * @return empty new string
+ **/
+ public final static String readUTF(DataInput in) throws IOException
+ {
+ return new String();
+ }
+}
+
diff --git a/src/demos/util/MD2.java b/src/demos/util/MD2.java
new file mode 100644
index 0000000..25ba88f
--- /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
+ * MIDROSYSTEMS, 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 (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();
+ }
+ }
+ }
+}
diff --git a/src/demos/util/ObjReader.java b/src/demos/util/ObjReader.java
new file mode 100644
index 0000000..382a658
--- /dev/null
+++ b/src/demos/util/ObjReader.java
@@ -0,0 +1,347 @@
+/*
+ * 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
+ * MIDROSYSTEMS, 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.util.*;
+
+import net.java.games.jogl.util.*;
+
+/** Simple parser for Wavefront .OBJ files. Does not support all file
+ options -- currently requires vertices and normals (only) to be
+ present. */
+
+public class ObjReader {
+ private int verticesPerFace = -1;
+ private FloatBuffer vertices;
+ private FloatBuffer normals;
+ private float[] aabbMin = new float[3];
+ private float[] aabbMax = new float[3];
+ private float[] center = new float[3];
+ private float radius;
+ // If we wanted this to be really general we'd have an array of
+ // FloatLists for the various kinds of vertices as well
+ private FloatList tmpVertices;
+ private FloatList tmpVertexNormals;
+ private IntList faceIndices;
+ private IntList[] tmpFaceIndices;
+
+ public ObjReader(String filename) throws IOException {
+ this(new File(filename));
+ }
+
+ public ObjReader(File file) throws IOException {
+ BufferedReader reader = new BufferedReader(new FileReader(file));
+ String line = null;
+ int lineNo = 0;
+ float[] floatTmp = new float[3];
+
+ while ((line = reader.readLine()) != null) {
+ ++lineNo;
+ if (line.length() > 0) {
+ char c = line.charAt(0);
+ // FIXME: support continuation of lines with trailing '\'
+ switch (c) {
+ case '#':
+ break;
+
+ case 'v':
+ if (Character.isWhitespace(line.charAt(1))) {
+ addVertex(parseFloats(line, 3, floatTmp, lineNo));
+ } else if (line.startsWith("vn")) {
+ addVertexNormal(parseFloats(line, 3, floatTmp, lineNo));
+ } else {
+ throw new IOException("Unsupported vertex command on line " + lineNo);
+ }
+ break;
+
+ case 'f':
+ parseIndices(line, lineNo);
+
+ default:
+ // For now we ignore all other lines
+ }
+ }
+ }
+
+ // Now have all vertex information.
+ // Make it possible to use same indices for both vertices and normals
+ condenseIndices();
+
+ // Compute axis-aligned bounding box and radius
+ computeBoundingBox();
+ }
+
+ public void rescale(float amount) {
+ for (int i = 0; i < vertices.capacity(); i++) {
+ vertices.put(i, vertices.get(i) * amount);
+ }
+ }
+
+ public FloatBuffer getVertices() {
+ return vertices;
+ }
+
+ public FloatBuffer getVertexNormals() {
+ return normals;
+ }
+
+ public int[] getFaceIndices() {
+ return faceIndices.getData();
+ }
+
+ public int getVerticesPerFace() {
+ return verticesPerFace;
+ }
+
+ public float[] getAABBMin() {
+ return aabbMin;
+ }
+
+ public float[] getAABBMax() {
+ return aabbMax;
+ }
+
+ public float[] getCenter() {
+ return center;
+ }
+
+ public float getRadius() {
+ return radius;
+ }
+
+ //----------------------------------------------------------------------
+ // Internals only below this point
+ //
+
+ private void addVertex(float[] tmp) {
+ if (tmpVertices == null) {
+ tmpVertices = new FloatList();
+ }
+ for (int i = 0; i < 3; i++) {
+ tmpVertices.add(tmp[i]);
+ }
+ }
+
+ private void addVertexNormal(float[] tmp) {
+ if (tmpVertexNormals == null) {
+ tmpVertexNormals = new FloatList();
+ }
+ for (int i = 0; i < 3; i++) {
+ tmpVertexNormals.add(tmp[i]);
+ }
+ }
+
+ private float[] parseFloats(String line, int num, float[] tmp, int lineNo) throws IOException {
+ StringTokenizer tok = new StringTokenizer(line);
+ tok.nextToken(); // skip command
+ int idx = 0;
+ while (tok.hasMoreTokens()) {
+ if (idx >= tmp.length) {
+ throw new IOException("Too many floating-point values on line " + lineNo);
+ }
+ tmp[idx++] = Float.parseFloat(tok.nextToken());
+ }
+ return tmp;
+ }
+
+ private void parseIndices(String line, int lineNo) throws IOException {
+ StringTokenizer tok = new StringTokenizer(line);
+ tok.nextToken(); // skip command
+ List tokens = new ArrayList();
+ while (tok.hasMoreTokens()) {
+ tokens.add(tok.nextToken());
+ }
+ // This is the number of vertices in this face.
+ // If we seem to have already found this, it had better match the
+ // previously read value (for now - don't want to add the
+ // complexity of supporting some faces with a certain number of
+ // vertices and some with a different number)
+ if (verticesPerFace < 0) {
+ verticesPerFace = tokens.size();
+ } else {
+ if (verticesPerFace != tokens.size()) {
+ throw new IOException("Face on line " + lineNo + " had " + tokens.size() +
+ " vertices, but had already previously set the number of vertices per face to " +
+ verticesPerFace);
+ }
+ }
+ // Now read the individual indices out of each token
+ for (Iterator iter = tokens.iterator(); iter.hasNext(); ) {
+ String indices = (String) iter.next();
+ if (tmpFaceIndices == null) {
+ StringTokenizer tmpTok = new StringTokenizer(indices, "/");
+ int numIndicesPerVertex = 0;
+ while (tmpTok.hasMoreTokens()) {
+ tmpTok.nextToken();
+ ++numIndicesPerVertex;
+ }
+ tmpFaceIndices = new IntList[numIndicesPerVertex];
+ for (int i = 0; i < numIndicesPerVertex; i++) {
+ tmpFaceIndices[i] = new IntList();
+ }
+ }
+
+ StringTokenizer tok2 = new StringTokenizer(indices, "/");
+ int which = 0;
+ while (tok2.hasMoreTokens()) {
+ if (which >= tmpFaceIndices.length) {
+ throw new IOException("Expected all vertices to have " + tmpFaceIndices.length +
+ " indices based on earlier input, but saw vertex with more on line " + lineNo);
+ }
+ String token = tok2.nextToken();
+ int index = Integer.parseInt(token);
+ tmpFaceIndices[which].add(index);
+ ++which;
+ }
+ }
+ }
+
+ // Don't know the hashing rules for arrays off the top of my head
+ static class Indices {
+ int[] data;
+ Indices(int[] data) {
+ this.data = data;
+ }
+
+ public boolean equals(Object obj) {
+ if ((obj == null) || (!(obj instanceof Indices))) {
+ return false;
+ }
+
+ Indices other = (Indices) obj;
+
+ if (data.length != other.data.length) {
+ return false;
+ }
+
+ for (int i = 0; i < data.length; i++) {
+ if (data[i] != other.data[i]) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ public int hashCode() {
+ int hash = 0;
+ for (int i = 0; i < data.length; i++) {
+ hash ^= data[i];
+ }
+ return hash;
+ }
+ }
+
+ private void condenseIndices() {
+ FloatList newVertices = new FloatList();
+ FloatList newVertexNormals = new FloatList();
+ IntList newIndices = new IntList();
+ int nextIndex = 0;
+ HashMap condensingMap = new HashMap();
+ for (int i = 0; i < tmpFaceIndices[0].size(); i++) {
+ Indices indices = getIndices(i);
+ Integer newIndex = (Integer) condensingMap.get(indices);
+ if (newIndex == null) {
+ // Fabricate new vertex and normal index for this one
+ // FIXME: generalize this by putting vertices and vertex
+ // normals in FloatList[] as well
+ condensingMap.put(indices, new Integer(nextIndex));
+ int vtxIdx = 3 * (indices.data[0] - 1);
+ int vtxNrmIdx = 3 * (indices.data[1] - 1);
+ newVertices.add(tmpVertices.get(vtxIdx + 0));
+ newVertices.add(tmpVertices.get(vtxIdx + 1));
+ newVertices.add(tmpVertices.get(vtxIdx + 2));
+ newVertexNormals.add(tmpVertexNormals.get(vtxNrmIdx + 0));
+ newVertexNormals.add(tmpVertexNormals.get(vtxNrmIdx + 1));
+ newVertexNormals.add(tmpVertexNormals.get(vtxNrmIdx + 2));
+ newIndices.add(nextIndex);
+ ++nextIndex;
+ } else {
+ newIndices.add(newIndex.intValue());
+ }
+ }
+ newVertices.trim();
+ newVertexNormals.trim();
+ newIndices.trim();
+ vertices = BufferUtils.newFloatBuffer(newVertices.size());
+ vertices.put(newVertices.getData());
+ normals = BufferUtils.newFloatBuffer(newVertexNormals.size());
+ normals.put(newVertexNormals.getData());
+ faceIndices = newIndices;
+ tmpVertices = null;
+ tmpVertexNormals = null;
+ }
+
+ private void computeBoundingBox() {
+ for (int i = 0; i < vertices.capacity(); i += 3) {
+ if (i == 0) {
+ aabbMin[0] = vertices.get(i + 0);
+ aabbMin[1] = vertices.get(i + 1);
+ aabbMin[2] = vertices.get(i + 2);
+ aabbMax[0] = vertices.get(i + 0);
+ aabbMax[1] = vertices.get(i + 1);
+ aabbMax[2] = vertices.get(i + 2);
+ } else {
+ aabbMin[0] = Math.min(aabbMin[0], vertices.get(i + 0));
+ aabbMin[1] = Math.min(aabbMin[1], vertices.get(i + 1));
+ aabbMin[2] = Math.min(aabbMin[2], vertices.get(i + 2));
+ aabbMax[0] = Math.max(aabbMax[0], vertices.get(i + 0));
+ aabbMax[1] = Math.max(aabbMax[1], vertices.get(i + 1));
+ aabbMax[2] = Math.max(aabbMax[2], vertices.get(i + 2));
+ }
+ }
+ center[0] = 0.5f * (aabbMin[0] + aabbMax[0]);
+ center[1] = 0.5f * (aabbMin[1] + aabbMax[1]);
+ center[2] = 0.5f * (aabbMin[2] + aabbMax[2]);
+ radius = (float) Math.sqrt((aabbMax[0] - center[0]) * (aabbMax[0] - center[0]) +
+ (aabbMax[1] - center[1]) * (aabbMax[1] - center[1]) +
+ (aabbMax[2] - center[2]) * (aabbMax[2] - center[2]));
+ }
+
+ private Indices getIndices(int index) {
+ int[] indices = new int[tmpFaceIndices.length];
+ for (int i = 0; i < tmpFaceIndices.length; i++) {
+ indices[i] = tmpFaceIndices[i].get(index);
+ }
+ return new Indices(indices);
+ }
+}
diff --git a/src/demos/util/SystemTime.java b/src/demos/util/SystemTime.java
new file mode 100644
index 0000000..1812f2a
--- /dev/null
+++ b/src/demos/util/SystemTime.java
@@ -0,0 +1,110 @@
+/*
+ * 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
+ * MIDROSYSTEMS, 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;
+
+/** Implementation of {@link demos.util.Time} interface based
+ on {@link java.lang.System.currentTimeMillis}. Performs smoothing
+ internally to avoid effects of poor granularity of
+ currentTimeMillis on Windows platform in particular. */
+
+public class SystemTime implements Time {
+ private static final int DEFAULT_NUM_SMOOTHING_SAMPLES = 10;
+ private long[] samples = new long[DEFAULT_NUM_SMOOTHING_SAMPLES];
+ private int numSmoothingSamples;
+ private int curSmoothingSample; // Index of current sample to be replaced
+ private long baseTime = System.currentTimeMillis();
+ private boolean hasCurTime;
+ private double curTime;
+ private double deltaT;
+
+ /** Sets number of smoothing samples. Defaults to 10. Note that
+ there may be a discontinuity in the reported time after a call
+ to this method. */
+ public void setNumSmoothingSamples(int num) {
+ samples = new long[num];
+ numSmoothingSamples = 0;
+ curSmoothingSample = 0;
+ hasCurTime = false;
+ }
+
+ /** Returns number of smoothing samples; default is 10. */
+ public int getNumSmoothingSamples() {
+ return samples.length;
+ }
+
+ /** Rebases this timer. After very long periods of time the
+ resolution of this timer may decrease; the application can call
+ this to restore higher resolution. Note that there may be a
+ discontinuity in the reported time after a call to this
+ method. */
+ public void rebase() {
+ baseTime = System.currentTimeMillis();
+ setNumSmoothingSamples(samples.length);
+ }
+
+ public void update() {
+ long tmpTime = System.currentTimeMillis();
+ long diffSinceBase = tmpTime - baseTime;
+ samples[curSmoothingSample] = diffSinceBase;
+ curSmoothingSample = (curSmoothingSample + 1) % samples.length;
+ numSmoothingSamples = Math.min(1 + numSmoothingSamples, samples.length);
+ // Average of samples is current time
+ double newCurTime = 0.0;
+ for (int i = 0; i < numSmoothingSamples; i++) {
+ newCurTime += samples[i];
+ }
+ newCurTime /= (1000.0f * numSmoothingSamples);
+ double lastTime = curTime;
+ if (!hasCurTime) {
+ lastTime = newCurTime;
+ hasCurTime = true;
+ }
+ deltaT = newCurTime - lastTime;
+ curTime = newCurTime;
+ }
+
+ public double time() {
+ return curTime;
+ }
+
+ public double deltaT() {
+ return deltaT;
+ }
+}
diff --git a/src/demos/util/TGAImage.java b/src/demos/util/TGAImage.java
new file mode 100644
index 0000000..187fb7a
--- /dev/null
+++ b/src/demos/util/TGAImage.java
@@ -0,0 +1,319 @@
+/*
+ * 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
+ * MIDROSYSTEMS, 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 net.java.games.jogl.*;
+
+/**
+ * Targa image reader adapted from sources of the <a href =
+ * "http://java.sun.com/products/jimi/">Jimi</a> image I/O class library.
+ *
+ * <P>
+ *
+ * Image decoder for image data stored in TGA file format.
+ * Currently only the original TGA file format is supported. This is
+ * because the new TGA format has data at the end of the file, getting
+ * to the end of a file in an InputStream orient environment presents
+ * several difficulties which are avoided at the moment.
+ *
+ * <P>
+ *
+ * This is a simple decoder and is only setup to load a single image
+ * from the input stream
+ *
+ * <P>
+ *
+ * @author Robin Luiten
+ * @author Kenneth Russell
+ * @version $Revision: 1.3 $
+ */
+
+public class TGAImage {
+ private Header header;
+ private int format;
+ private byte[] data;
+
+ private TGAImage(Header header) {
+ this.header = header;
+ }
+
+ /**
+ * This class reads in all of the TGA image header in addition it also
+ * reads in the imageID field as it is convenient to handle that here.
+ *
+ * @author Robin Luiten
+ * @version 1.1
+ */
+ public static class Header {
+ /** Set of possible file format TGA types */
+ public final static int TYPE_NEW = 0;
+ public final static int TYPE_OLD = 1;
+ public final static int TYPE_UNK = 2; // cant rewind stream so unknown for now.
+
+ /** Set of possible image types in TGA file */
+ public final static int NO_IMAGE = 0; // no image data
+ public final static int UCOLORMAPPED = 1; // uncompressed color mapped image
+ public final static int UTRUECOLOR = 2; // uncompressed true color image
+ public final static int UBLACKWHITE = 3; // uncompressed black and white image
+ public final static int COLORMAPPED = 9; // compressed color mapped image
+ public final static int TRUECOLOR = 10; // compressed true color image
+ public final static int BLACKWHITE = 11; // compressed black and white image
+
+ /** Field image descriptor bitfield values definitions */
+ public final static int ID_ATTRIBPERPIXEL = 0xF;
+ public final static int ID_LEFTTORIGHT = 0x10;
+ public final static int ID_TOPTOBOTTOM = 0x20;
+ public final static int ID_INTERLEAVE = 0xC0;
+
+ /** Field image descriptor / interleave values */
+ public final static int I_NOTINTERLEAVED = 0;
+ public final static int I_TWOWAY = 1;
+ public final static int I_FOURWAY = 2;
+
+ /** Type of this TGA file format */
+ private int tgaType;
+
+ /** initial TGA image data fields */
+ private int idLength; // byte value
+ private int colorMapType; // byte value
+ private int imageType; // byte value
+
+ /** TGA image colour map fields */
+ private int firstEntryIndex;
+ private int colorMapLength;
+ private byte colorMapEntrySize;
+
+ /** TGA image specification fields */
+ private int xOrigin;
+ private int yOrigin;
+ private int width;
+ private int height;
+ private byte pixelDepth;
+ private byte imageDescriptor;
+
+ /** bitfields in imageDescriptor */
+ private byte attribPerPixel; // how many attribute bits per pixel
+ private boolean leftToRight; // order of data on scan line
+ private boolean topToBottom; // order scan lines stored
+ private byte interleave; // how rows are stored in image data
+
+ private byte[] imageIDbuf;
+ private String imageID;
+
+ public Header(LEDataInputStream in) throws IOException {
+ int ret;
+
+ tgaType = TYPE_OLD; // dont try and get footer.
+
+ // initial header fields
+ idLength = in.readUnsignedByte();
+ colorMapType = in.readUnsignedByte();
+ imageType = in.readUnsignedByte();
+
+ // color map header fields
+ firstEntryIndex = in.readUnsignedShort();
+ colorMapLength = in.readUnsignedShort();
+ colorMapEntrySize = in.readByte();
+
+ // TGA image specification fields
+ xOrigin = in.readUnsignedShort();
+ yOrigin = in.readUnsignedShort();
+ width = in.readUnsignedShort();
+ height = in.readUnsignedShort();
+ pixelDepth = in.readByte();
+ imageDescriptor = in.readByte();
+
+ attribPerPixel = (byte)(imageDescriptor & ID_ATTRIBPERPIXEL);
+ leftToRight = (imageDescriptor & ID_LEFTTORIGHT) != 0; // not used ?
+ topToBottom = (imageDescriptor & ID_TOPTOBOTTOM) != 0;
+ interleave = (byte)((imageDescriptor & ID_INTERLEAVE) >> 6);
+
+ if (idLength > 0) {
+ imageIDbuf = new byte[idLength];
+ in.read(imageIDbuf, 0, idLength);
+ imageID = new String(imageIDbuf, "US-ASCII");
+ }
+ }
+
+ public int tgaType() { return tgaType; }
+
+ /** initial TGA image data fields */
+ public int idLength() { return idLength; }
+ public int colorMapType() { return colorMapType; }
+ public int imageType() { return imageType; }
+
+ /** TGA image colour map fields */
+ public int firstEntryIndex() { return firstEntryIndex; }
+ public int colorMapLength() { return colorMapLength; }
+ public byte colorMapEntrySize() { return colorMapEntrySize; }
+
+ /** TGA image specification fields */
+ public int xOrigin() { return xOrigin; }
+ public int yOrigin() { return yOrigin; }
+ public int width() { return width; }
+ public int height() { return height; }
+ public byte pixelDepth() { return pixelDepth; }
+ public byte imageDescriptor() { return imageDescriptor; }
+
+ /** bitfields in imageDescriptor */
+ public byte attribPerPixel() { return attribPerPixel; }
+ public boolean leftToRight() { return leftToRight; }
+ public boolean topToBottom() { return topToBottom; }
+ public byte interleave() { return interleave; }
+
+ public byte[] imageIDbuf() { return imageIDbuf; }
+ public String imageID() { return imageID; }
+
+ public String toString() {
+ return "TGA Header " +
+ " id length: " + idLength +
+ " color map type: "+ colorMapType +
+ " image type: "+ imageType +
+ " first entry index: " + firstEntryIndex +
+ " color map length: " + colorMapLength +
+ " color map entry size: " + colorMapEntrySize +
+ " x Origin: " + xOrigin +
+ " y Origin: " + yOrigin +
+ " width: "+ width +
+ " height: "+ height +
+ " pixel depth: "+ pixelDepth +
+ " image descriptor: "+ imageDescriptor +
+ (imageIDbuf == null ? "" : (" ID String: " + imageID));
+ }
+ }
+
+
+ /**
+ * Identifies the image type of the tga image data and loads
+ * it into the JimiImage structure. This was taken from the
+ * prototype and modified for the new Jimi structure
+ */
+ private void decodeImage(LEDataInputStream dIn) throws IOException {
+ switch (header.imageType()) {
+ case Header.UCOLORMAPPED:
+ throw new IOException("TGADecoder Uncompressed Colormapped images not supported");
+
+ case Header.UTRUECOLOR: // pixelDepth 15, 16, 24 and 32
+ switch (header.pixelDepth) {
+ case 16:
+ throw new IOException("TGADecoder Compressed 16-bit True Color images not supported");
+
+ case 24:
+ case 32:
+ decodeRGBImageU24_32(dIn);
+ break;
+ }
+ break;
+
+ case Header.UBLACKWHITE:
+ throw new IOException("TGADecoder Uncompressed Grayscale images not supported");
+
+ case Header.COLORMAPPED:
+ throw new IOException("TGADecoder Compressed Colormapped images not supported");
+
+ case Header.TRUECOLOR:
+ throw new IOException("TGADecoder Compressed True Color images not supported");
+
+ case Header.BLACKWHITE:
+ throw new IOException("TGADecoder Compressed Grayscale images not supported");
+ }
+ }
+
+ /**
+ * This assumes that the body is for a 24 bit or 32 bit for a
+ * RGB or ARGB image respectively.
+ */
+ private void decodeRGBImageU24_32(LEDataInputStream dIn) throws IOException {
+ int i; // row index
+ int j; // column index
+ int y; // output row index
+ int raw; // index through the raw input buffer
+ int rawWidth = header.width() * (header.pixelDepth() / 8);
+ byte[] rawBuf = new byte[rawWidth];
+ data = new byte[rawWidth * header.height()];
+
+ if (header.pixelDepth() == 24) {
+ format = GL.GL_BGR_EXT;
+ } else {
+ assert header.pixelDepth() == 32;
+ format = GL.GL_BGRA_EXT;
+ }
+
+ for (i = 0; i < header.height(); ++i) {
+ dIn.readFully(rawBuf, 0, rawWidth);
+
+ if (header.topToBottom)
+ y = header.height - i - 1; // range 0 to (header.height - 1)
+ else
+ y = i;
+
+ System.arraycopy(rawBuf, 0, data, y * rawWidth, rawBuf.length);
+ }
+ }
+
+ /** Returns the width of the image. */
+ public int getWidth() { return header.width(); }
+
+ /** Returns the height of the image. */
+ public int getHeight() { return header.height(); }
+
+ /** Returns the OpenGL format for this texture; e.g. GL.GL_BGR_EXT or GL.GL_BGRA_EXT. */
+ public int getGLFormat() { return format; }
+
+ /** Returns the raw data for this texture in the correct
+ (bottom-to-top) order for calls to glTexImage2D. */
+ public byte[] getData() { return data; }
+
+ /** Reads a Targa image from the specified file. */
+ public static TGAImage read(String filename) throws IOException {
+ return read(new FileInputStream(filename));
+ }
+
+ /** Reads a Targa image from the specified InputStream. */
+ public static TGAImage read(InputStream in) throws IOException {
+ LEDataInputStream dIn = new LEDataInputStream(new BufferedInputStream(in));
+
+ Header header = new Header(dIn);
+ TGAImage res = new TGAImage(header);
+ res.decodeImage(dIn);
+ return res;
+ }
+}
diff --git a/src/demos/util/Time.java b/src/demos/util/Time.java
new file mode 100644
index 0000000..ade74c4
--- /dev/null
+++ b/src/demos/util/Time.java
@@ -0,0 +1,52 @@
+/*
+ * 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
+ * MIDROSYSTEMS, 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;
+
+/** Interface abstracting concept of time from applications. */
+
+public interface Time {
+ /** Updates this Time object. Call update() each frame before
+ calling the accessor routines. */
+ public void update();
+ /** Time in seconds since beginning of application. */
+ public double time();
+ /** Time in seconds since last update. */
+ public double deltaT();
+}
diff --git a/src/demos/util/Triceratops.java b/src/demos/util/Triceratops.java
new file mode 100644
index 0000000..dde452b
--- /dev/null
+++ b/src/demos/util/Triceratops.java
@@ -0,0 +1,137 @@
+/*
+ * 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
+ * MIDROSYSTEMS, 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 net.java.games.jogl.*;
+
+/** Renders a triceratops. <P>
+
+ Copyright by Thomas Baier ([email protected])<br>
+ Created by OpenGL Export Plugin 1.0 at Fri Oct 27 22:04:55 2000<br>
+ OpenGL-Structure <br><p>
+
+ Ported to Java by Kenneth Russell
+*/
+public class Triceratops {
+
+ /** Draws the triceratops object. Callers should capture the result
+ in a display list. */
+ public static void drawObject(GL gl) throws IOException {
+ Reader reader = new BufferedReader(new InputStreamReader(
+ Triceratops.class.getClassLoader().getResourceAsStream("demos/data/models/triceratops.txt")));
+ StreamTokenizer tok = new StreamTokenizer(reader);
+ // Reset tokenizer's syntax so numbers are not parsed
+ tok.resetSyntax();
+ tok.wordChars('a', 'z');
+ tok.wordChars('A', 'Z');
+ tok.wordChars('0', '9');
+ tok.wordChars('-', '-');
+ tok.wordChars('.', '.');
+ tok.wordChars(128 + 32, 255);
+ tok.whitespaceChars(0, ' ');
+ tok.whitespaceChars(',', ',');
+ tok.whitespaceChars('{', '{');
+ tok.whitespaceChars('}', '}');
+ tok.commentChar('/');
+ tok.quoteChar('"');
+ tok.quoteChar('\'');
+ tok.slashSlashComments(true);
+ tok.slashStarComments(true);
+
+ // Read in file
+ int numVertices = nextInt(tok, "number of vertices");
+ float[] vertices = new float[numVertices * 3];
+ for (int i = 0; i < numVertices * 3; i++) {
+ vertices[i] = nextFloat(tok, "vertex");
+ }
+ int numNormals = nextInt(tok, "number of normals");
+ float[] normals = new float[numNormals * 3];
+ for (int i = 0; i < numNormals * 3; i++) {
+ normals[i] = nextFloat(tok, "normal");
+ }
+ int numFaceIndices = nextInt(tok, "number of face indices");
+ short[] faceIndices = new short[numFaceIndices * 9];
+ for (int i = 0; i < numFaceIndices * 9; i++) {
+ faceIndices[i] = (short) nextInt(tok, "face index");
+ }
+
+ reader.close();
+
+ float sf = 0.1f;
+ gl.glBegin(GL.GL_TRIANGLES);
+ for (int i = 0; i < faceIndices.length; i += 9) {
+ for (int j = 0; j < 3; j++) {
+ int vi = faceIndices[i + j ] & 0xFFFF;
+ int ni = faceIndices[i + j + 3] & 0xFFFF;
+ gl.glNormal3f(normals[3 * ni],
+ normals[3 * ni + 1],
+ normals[3 * ni + 2]);
+ gl.glVertex3f(sf * vertices[3 * vi],
+ sf * vertices[3 * vi + 1],
+ sf * vertices[3 * vi + 2]);
+ }
+ }
+ gl.glEnd();
+ }
+
+ private static int nextInt(StreamTokenizer tok, String error) throws IOException {
+ if (tok.nextToken() != StreamTokenizer.TT_WORD) {
+ throw new IOException("Parse error reading " + error + " at line " + tok.lineno());
+ }
+ try {
+ return Integer.parseInt(tok.sval);
+ } catch (NumberFormatException e) {
+ throw new IOException("Parse error reading " + error + " at line " + tok.lineno());
+ }
+ }
+
+ private static float nextFloat(StreamTokenizer tok, String error) throws IOException {
+ if (tok.nextToken() != StreamTokenizer.TT_WORD) {
+ throw new IOException("Parse error reading " + error + " at line " + tok.lineno());
+ }
+ try {
+ return Float.parseFloat(tok.sval);
+ } catch (NumberFormatException e) {
+ throw new IOException("Parse error reading " + error + " at line " + tok.lineno());
+ }
+ }
+}