/** * Copyright (c) 2003-2009, Xith3D Project Group all rights reserved. * * Portions based on the Java3D interface, Copyright by Sun Microsystems. * Many thanks to the developers of Java3D and Sun Microsystems for their * innovation and design. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * Redistributions 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 the 'Xith3D Project Group' nor the names of its * contributors may be used to endorse or promote products derived from this * software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) A * RISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE */ package org.xith3d.io; import org.jagatoo.image.DirectBufferedImage; import org.openmali.vecmath2.*; import org.xith3d.utility.logging.X3DLog; import org.xith3d.utility.memory.NioMemoryBuffer; import javax.imageio.ImageIO; import java.awt.image.BufferedImage; import java.io.ByteArrayInputStream; import java.io.DataInputStream; import java.io.IOException; import java.io.InputStream; import java.nio.ByteBuffer; import java.nio.FloatBuffer; import java.nio.IntBuffer; import java.nio.ShortBuffer; import java.util.ArrayList; /** * Stream for reading cosm objects. * * :Id: ScribeInputStream.java,v 1.10 2003/02/24 00:13:44 wurp Exp $ * * :Log: ScribeInputStream.java,v $ Revision 1.10 2003/02/24 00:13:44 wurp * Formatted all java code for cvs (strictSunConvention.xml) * * Revision 1.9 2002/09/11 00:53:53 dilvish Big commit of new changes * * Revision 1.8 2002/01/23 04:38:33 wurp Integrating i18n code * * Revision 1.7 2002/01/20 05:26:02 dilvish JDK 1.4 port * * Revision 1.6 2002/01/15 03:36:55 dilvish Improvements to the animation system * * Revision 1.5 2002/01/12 03:16:27 dilvish Added read/write of buffered images * * Revision 1.4 2001/11/17 03:13:02 dilvish Added the ability to read/write * arrays of vectors * * Revision 1.3 2001/07/14 14:48:10 wurp New animation, sky and avatar movement * * Revision 1.2 2001/06/20 04:05:41 wurp added log4j. * * Revision 1.1 2001/06/06 22:42:37 wizofid Massive commit / reintegration * * @author David Yazel */ public class ScribeInputStream extends DataInputStream { private static final boolean USE_NEW = false; private ArrayList< String > map = new ArrayList< String >(); // used for super fast reads of float arrays private byte[] byteBuffer = null; private FloatBuffer floatBuffer = null; private ByteBuffer bBuffer = null; private IntBuffer intBuffer = null; private ShortBuffer shortBuffer = null; private boolean readHeaderOnly = false; public ScribeInputStream( InputStream in ) { super( in ); } /** * Setting this to true will allow objects being loaded to only load their * header information. * * @param header */ public void setReadHeaderOnly( boolean header ) { this.readHeaderOnly = header; } public boolean shouldReadHeaderOnly() { return ( this.readHeaderOnly ); } private boolean clutchByteBuffer( int size ) { if ( size < 1000 ) { size = 1000; } if ( bBuffer != null ) { if ( bBuffer.capacity() >= size ) { bBuffer.rewind(); return false; } } byteBuffer = new byte[ size ]; bBuffer = ByteBuffer.wrap( byteBuffer ); floatBuffer = bBuffer.asFloatBuffer(); intBuffer = bBuffer.asIntBuffer(); return ( true ); } /** * Internal routine that creates a float buffer big enough to hold the * number of floats specified. If the buffer is already big enough then it * rewinds the buffer and returns * * @param size Number of floats to make room for */ private void clutchFloatBuffer( int size ) { // Log.print( "Clutching " + size + " floats" ); clutchByteBuffer( size * 4 ); } /** * Internal routine that creates an int buffer big enough to hold the number * of ints specified. If the buffer is already big enough then it rewinds * the buffer and returns * * @param size Number of floats to make room for */ private void clutchIntBuffer( int size ) { clutchByteBuffer( size * 4 ); } private void clutchShortBuffer( int size ) { clutchByteBuffer( size * 2 ); shortBuffer = bBuffer.asShortBuffer(); } /** * reads in a scribable node by getting the class name from the stream, * building the object and calling its scribable method to load it. */ public Scribable readScribable() throws java.io.IOException, InvalidFormat { int c = readInt(); String className = null; if ( c == ScribeOutputStream.CLASS_DEF ) { className = readUTF(); map.add( className ); X3DLog.debug( "Reading class ", className ); } else { int ref = readInt(); X3DLog.debug( "Reading class ref ", ref ); className = map.get( ref ); X3DLog.debug( " Class is ", className ); } // now instantiate the object using its default constructor Scribable s = null; try { s = (Scribable)Class.forName( className ).newInstance(); s.load( this ); } catch ( java.lang.ClassNotFoundException e1 ) { X3DLog.print( e1 ); throw new InvalidFormat( e1.getMessage() ); } catch ( java.lang.IllegalAccessException e2 ) { X3DLog.print( e2 ); throw new InvalidFormat( e2.getMessage() ); } catch ( java.lang.InstantiationException e3 ) { X3DLog.print( e3 ); throw new InvalidFormat( e3.getMessage() ); } return ( s ); } /** * Reads in the data into the array. An exception is raised if The data * array is not big enough. */ private void readFloatArray( float[] data, int size ) throws java.io.IOException { if ( data.length < size ) { IOException e = new IOException( "Array not big enough to read " + size + " data elements" ); X3DLog.print( e ); throw e; } // attempt to do this with NIO for speed if ( Scribe.useNIO ) { if ( !USE_NEW ) { clutchFloatBuffer( size ); readFully( byteBuffer, 0, size * 4 ); floatBuffer.rewind(); floatBuffer.get( data, 0, size ); } else { NioMemoryBuffer< ? > m = NioMemoryBuffer.getInstance( size * 4 ); readFully( m.getByteArray(), 0, size * 4 ); m.getFloatBuffer().rewind(); m.getFloatBuffer().get( data, 0, size ); m.returnInstance(); } } else { for ( int i = 0; i < size; i++ ) data[ i ] = readFloat(); } } /** * Reads in an array of float and return the number of floats read. The data * array must be big enough to read in all the floats in the array */ public int readFloatArray( float[] data ) throws java.io.IOException { int size = readInt(); readFloatArray( data, size ); return ( size ); } /** * Allocates a float array and loads it from the stream */ public float[] readFloatArray() throws java.io.IOException { int size = readInt(); float[] data = new float[ size ]; readFloatArray( data, size ); return ( data ); } /** * Reads in the data into the array. An exception is raised if The data * array is not big enough. */ private void readByteArray( byte[] data, int size ) throws java.io.IOException { if ( data.length < size ) { throw new java.io.IOException( "Array not big enough to read " + size + " data elements" ); } // attempt to do this with NIO for speed if ( Scribe.useNIO ) { readFully( data, 0, size ); } else { for ( int i = 0; i < size; i++ ) data[ i ] = readByte(); } } /** * Reads in an array of byte and return the number of bytes read. The data * array must be big enough to read in all the bytes in the array */ public int readByteArray( byte[] data ) throws java.io.IOException { int size = readInt(); readByteArray( data, size ); return ( size ); } /** * Allocates a byte array and loads it from the stream */ public byte[] readByteArray() throws java.io.IOException { int size = readInt(); byte[] data = new byte[ size ]; readByteArray( data, size ); return ( data ); } private void readVectorArray( Vector3f[] data, int size ) throws java.io.IOException { if ( data.length < size ) { throw new java.io.IOException( "Array not big enough to read " + size + " data elements" ); } for ( int i = 0; i < size; i++ ) data[ i ] = readVector(); } /** * Reads in an array of vectors and return the number of vectors read. The * data array must be big enough to read in all the vectors in the array */ public int readVectorArray( Vector3f[] data ) throws java.io.IOException { int size = readInt(); readVectorArray( data, size ); return ( size ); } /** * Allocates a float array and loads it from the stream */ public Vector3f[] readVectorArray() throws java.io.IOException { int size = readInt(); Vector3f[] data = new Vector3f[ size ]; readVectorArray( data, size ); return ( data ); } /** * Reads in the data into the array. An exception is raised if The data * array is not big enough. */ private void readIntArray( int[] data, int size ) throws java.io.IOException { if ( data.length < size ) { throw new java.io.IOException( "Array not big enough to read " + size + " data elements" ); } if ( Scribe.useNIO ) { if ( !USE_NEW ) { clutchIntBuffer( size ); readFully( byteBuffer, 0, size * 4 ); intBuffer.rewind(); intBuffer.get( data, 0, size ); } else { NioMemoryBuffer< ? > m = NioMemoryBuffer.getInstance( size * 4 ); byte[] a = m.getByteArray(); for ( int i = 0; i < a.length; i++ ) a[ i ] = 0; readFully( m.getByteArray(), 0, size * 4 ); m.getIntBuffer().rewind(); m.getIntBuffer().get( data, 0, size ); m.returnInstance(); } } else { for ( int i = 0; i < size; i++ ) data[ i ] = readInt(); } } private void readShortArray( short[] data, int size ) throws java.io.IOException { if ( data.length < size ) { throw new java.io.IOException( "Array not big enough to read " + size + " data elements" ); } if ( Scribe.useNIO ) { clutchShortBuffer( size ); readFully( byteBuffer, 0, size * 2 ); shortBuffer.get( data, 0, size ); } else { for ( int i = 0; i < size; i++ ) data[ i ] = readShort(); } } /** * Reads in an array of float and return the number of floats read. The data * array must be big enough to read in all the floats in the array */ public int readIntArray( int[] data ) throws java.io.IOException { int size = readInt(); // Log.print("Reading and int array of size "+size); readIntArray( data, size ); return ( size ); } /** * Reads in an array of float and return the number of floats read. The data * array must be big enough to read in all the floats in the array */ public int readShortArray( short[] data ) throws java.io.IOException { int size = readInt(); // Log.print( "Reading and int array of size " + size ); readShortArray( data, size ); return ( size ); } /** * Allocates a float array and loads it from the stream */ public int[] readIntArray() throws java.io.IOException { int size = readInt(); int[] data = new int[ size ]; readIntArray( data, size ); return ( data ); } public short[] readShortArray() throws java.io.IOException { int size = readInt(); short[] data = new short[ size ]; readShortArray( data, size ); return ( data ); } public void readPoint( Point3f p ) throws java.io.IOException { p.setX( readFloat() ); p.setY( readFloat() ); p.setZ( readFloat() ); } public void readVector( Vector3f v ) throws java.io.IOException { v.setX( readFloat() ); v.setY( readFloat() ); v.setZ( readFloat() ); } public Vector3f readVector() throws java.io.IOException { Vector3f v = new Vector3f(); readVector( v ); return ( v ); } public void readColor3f( Colorf v ) throws java.io.IOException { v.setRed( readFloat() ); v.setGreen( readFloat() ); v.setBlue( readFloat() ); } public Colorf readColor3f() throws java.io.IOException { Colorf v = new Colorf(); readColor3f( v ); return ( v ); } public void readQuat( Quaternion4f v ) throws java.io.IOException { v.setA( readFloat() ); v.setB( readFloat() ); v.setC( readFloat() ); v.setD( readFloat() ); } public Quaternion4f readQuat4f() throws java.io.IOException { Quaternion4f v = new Quaternion4f(); readQuat( v ); return ( v ); } public void readMatrix( Matrix3f v ) throws java.io.IOException { v.m00( readFloat() ); v.m01( readFloat() ); v.m02( readFloat() ); v.m10( readFloat() ); v.m11( readFloat() ); v.m12( readFloat() ); v.m20( readFloat() ); v.m21( readFloat() ); v.m22( readFloat() ); } public void readMatrix( Matrix4f v ) throws java.io.IOException { v.m00( readFloat() ); v.m01( readFloat() ); v.m02( readFloat() ); v.m03( readFloat() ); v.m10( readFloat() ); v.m11( readFloat() ); v.m12( readFloat() ); v.m13( readFloat() ); v.m20( readFloat() ); v.m21( readFloat() ); v.m22( readFloat() ); v.m23( readFloat() ); v.m30( readFloat() ); v.m31( readFloat() ); v.m32( readFloat() ); v.m33( readFloat() ); } public Matrix3f readMatrix3f() throws java.io.IOException { Matrix3f m = new Matrix3f(); readMatrix( m ); return ( m ); } public Matrix4f readMatrix4f() throws java.io.IOException { Matrix4f m = new Matrix4f(); readMatrix( m ); return ( m ); } public void readTexCoord( TexCoord2f v ) throws java.io.IOException { v.setS( readFloat() ); v.setT( readFloat() ); } public TexCoord2f readTexCoord() throws java.io.IOException { TexCoord2f c = new TexCoord2f(); readTexCoord( c ); return ( c ); } public BufferedImage readImage() throws java.io.IOException { BufferedImage b = null; int w = readInt(); if ( w != 0 ) { int h = readInt(); int ttype = readInt(); int[] pixels = readIntArray(); b = new BufferedImage( w, h, ttype ); b.setRGB( 0, 0, w, h, pixels, 0, w ); } return ( b ); } public DirectBufferedImage readDirectImage() throws java.io.IOException { DirectBufferedImage dbi = null; int w = readInt(); if ( w != 0 ) { int h = readInt(); int ttype = readInt(); switch ( ttype ) { case 0: //DirectBufferedImage.Type.DIRECT_RGB dbi = DirectBufferedImage.makeDirectImageRGB( w, h ); break; case 1: //DirectBufferedImage.Type.DIRECT_RGBA dbi = DirectBufferedImage.makeDirectImageRGBA( w, h ); break; case 2: //DirectBufferedImage.Type.DIRECT_GRAY dbi = DirectBufferedImage.makeDirectImageOneByte( w, h ); break; } //readFully( b.getBackingStore(), 0, b.getBackingStore().length ); final int numBytes = dbi.getNumBytes(); final ByteBuffer bb = dbi.getByteBuffer(); for ( int i = 0; i < numBytes; i++ ) { byte b = readByte(); bb.put( i, b ); } } return ( dbi ); } /** * Reads in the image which has been stored in a lossy compression format * * @return BufferedImage * @throws IOException */ public BufferedImage readLossyImage() throws java.io.IOException { BufferedImage b = null; int w = readInt(); if ( w != 0 ) { int size = readInt(); byte[] buf = new byte[ size ]; readFully( buf ); ByteArrayInputStream in = new ByteArrayInputStream( buf, 0, size ); b = ImageIO.read(in); // JPEGImageDecoder decoder = JPEGCodec.createJPEGDecoder( in ); // b = decoder.decodeAsBufferedImage(); } return ( b ); } }