diff options
Diffstat (limited to 'src/demos/util')
-rw-r--r-- | src/demos/util/Bunny.java | 141 | ||||
-rw-r--r-- | src/demos/util/DDSReader.java | 413 | ||||
-rw-r--r-- | src/demos/util/DurationTimer.java | 68 | ||||
-rw-r--r-- | src/demos/util/DxTex.java | 375 | ||||
-rw-r--r-- | src/demos/util/FloatList.java | 100 | ||||
-rw-r--r-- | src/demos/util/IntList.java | 100 | ||||
-rw-r--r-- | src/demos/util/LEDataInputStream.java | 223 | ||||
-rw-r--r-- | src/demos/util/MD2.java | 702 | ||||
-rw-r--r-- | src/demos/util/ObjReader.java | 347 | ||||
-rw-r--r-- | src/demos/util/SystemTime.java | 110 | ||||
-rw-r--r-- | src/demos/util/TGAImage.java | 319 | ||||
-rw-r--r-- | src/demos/util/Time.java | 52 | ||||
-rw-r--r-- | src/demos/util/Triceratops.java | 137 |
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> + eMail [email protected] +*/ +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()); + } + } +} |