Java tutorial
/* * @(#)TextureByReference.java 1.14 02/10/21 14:36:22 * * Copyright (c) 1996-2002 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: - * Redistributions 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 AND ITS LICENSORS SHALL NOT BE * LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING * OR DISTRIBUTING THE 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 SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY * OF SUCH DAMAGES. * * You acknowledge that Software is not designed,licensed or intended for use in * the design, construction, operation or maintenance of any nuclear facility. */ import java.applet.Applet; import java.awt.BorderLayout; import java.awt.Component; import java.awt.Dimension; import java.awt.GraphicsConfiguration; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.Transparency; import java.awt.color.ColorSpace; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.ItemEvent; import java.awt.event.ItemListener; import java.awt.image.BufferedImage; import java.awt.image.ColorModel; import java.awt.image.ComponentColorModel; import java.awt.image.DataBuffer; import java.awt.image.DataBufferByte; import java.awt.image.Raster; import java.awt.image.WritableRaster; import java.util.Enumeration; import javax.media.j3d.Alpha; import javax.media.j3d.AmbientLight; import javax.media.j3d.Appearance; import javax.media.j3d.Behavior; import javax.media.j3d.BoundingSphere; import javax.media.j3d.BranchGroup; import javax.media.j3d.Canvas3D; import javax.media.j3d.DirectionalLight; import javax.media.j3d.ImageComponent; import javax.media.j3d.ImageComponent2D; import javax.media.j3d.Material; import javax.media.j3d.RotationInterpolator; import javax.media.j3d.Shape3D; import javax.media.j3d.Texture; import javax.media.j3d.Texture2D; import javax.media.j3d.TextureAttributes; import javax.media.j3d.Transform3D; import javax.media.j3d.TransformGroup; import javax.media.j3d.TriangleArray; import javax.media.j3d.WakeupCriterion; import javax.media.j3d.WakeupOnElapsedFrames; import javax.swing.BoxLayout; import javax.swing.ButtonGroup; import javax.swing.JButton; import javax.swing.JCheckBox; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JRadioButton; import javax.swing.JSlider; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; import javax.vecmath.Color3f; import javax.vecmath.Point2f; import javax.vecmath.Point3d; import javax.vecmath.Point3f; import javax.vecmath.TexCoord2f; import javax.vecmath.Vector3f; import com.sun.j3d.utils.applet.MainFrame; import com.sun.j3d.utils.image.TextureLoader; import com.sun.j3d.utils.universe.SimpleUniverse; public class TextureByReference extends Applet implements ItemListener, ActionListener, ChangeListener { // need reference to animation behavior private AnimateTexturesBehavior animate; // need reference to tetrahedron private Tetrahedron tetra; // the gui buttons private JCheckBox flipB; private JRadioButton texByRef; private JRadioButton texByCopy; private JRadioButton geomByRef; private JRadioButton geomByCopy; private JRadioButton img4ByteABGR; private JRadioButton img3ByteBGR; private JRadioButton imgIntARGB; private JRadioButton imgCustomRGBA; private JRadioButton imgCustomRGB; private JRadioButton yUp; private JRadioButton yDown; private JButton animationB; private JSlider frameDelay; private SimpleUniverse universe = null; // image files used for the Texture animation for the applet, // or if no parameters are passed in for the application public static final String[] defaultFiles = { "animation1.gif", "animation2.gif", "animation3.gif", "animation4.gif", "animation5.gif", "animation6.gif", "animation7.gif", "animation8.gif", "animation9.gif", "animation10.gif" }; private java.net.URL[] urls = null; public TextureByReference() { } public TextureByReference(java.net.URL[] fnamesP) { urls = fnamesP; } public void init() { if (urls == null) { urls = new java.net.URL[defaultFiles.length]; for (int i = 0; i < defaultFiles.length; i++) { try { urls[i] = new java.net.URL(getCodeBase().toString() + defaultFiles[i]); } catch (java.net.MalformedURLException ex) { System.out.println(ex.getMessage()); System.exit(1); } } } setLayout(new BorderLayout()); GraphicsConfiguration config = SimpleUniverse.getPreferredConfiguration(); Canvas3D canvas = new Canvas3D(config); add("Center", canvas); // create a simple scene graph and attach it to a simple universe BranchGroup scene = createSceneGraph(); universe = new SimpleUniverse(canvas); universe.getViewingPlatform().setNominalViewingTransform(); universe.addBranchGraph(scene); // create the gui JPanel gui = buildGui(); this.add("South", gui); } public void destroy() { universe.cleanup(); } public JPanel buildGui() { flipB = new JCheckBox("flip image", true); flipB.addItemListener(this); javax.swing.Box flipBox = new javax.swing.Box(BoxLayout.Y_AXIS); flipBox.add(flipB); Component strut1 = flipBox.createVerticalStrut(flipB.getPreferredSize().height); Component strut2 = flipBox.createVerticalStrut(flipB.getPreferredSize().height); Component strut3 = flipBox.createVerticalStrut(flipB.getPreferredSize().height); Component strut4 = flipBox.createVerticalStrut(flipB.getPreferredSize().height); Component strut5 = flipBox.createVerticalStrut(flipB.getPreferredSize().height); flipBox.add(strut1); flipBox.add(strut2); flipBox.add(strut3); flipBox.add(strut4); flipBox.add(strut5); yUp = new JRadioButton("y up"); yUp.addActionListener(this); yUp.setSelected(true); yDown = new JRadioButton("y down"); yDown.addActionListener(this); ButtonGroup yGroup = new ButtonGroup(); yGroup.add(yUp); yGroup.add(yDown); JLabel yLabel = new JLabel("Image Orientation:"); javax.swing.Box yBox = new javax.swing.Box(BoxLayout.Y_AXIS); yBox.add(yLabel); yBox.add(yUp); yBox.add(yDown); strut1 = yBox.createVerticalStrut(yUp.getPreferredSize().height); strut2 = yBox.createVerticalStrut(yUp.getPreferredSize().height); strut3 = yBox.createVerticalStrut(yUp.getPreferredSize().height); yBox.add(strut1); yBox.add(strut2); yBox.add(strut3); texByRef = new JRadioButton("by reference"); texByRef.addActionListener(this); texByRef.setSelected(true); texByCopy = new JRadioButton("by copy"); texByCopy.addActionListener(this); ButtonGroup texGroup = new ButtonGroup(); texGroup.add(texByRef); texGroup.add(texByCopy); JLabel texLabel = new JLabel("Texture:*"); javax.swing.Box texBox = new javax.swing.Box(BoxLayout.Y_AXIS); texBox.add(texLabel); texBox.add(texByRef); texBox.add(texByCopy); strut1 = texBox.createVerticalStrut(texByRef.getPreferredSize().height); strut2 = texBox.createVerticalStrut(texByRef.getPreferredSize().height); strut3 = texBox.createVerticalStrut(texByRef.getPreferredSize().height); texBox.add(strut1); texBox.add(strut2); texBox.add(strut3); geomByRef = new JRadioButton("by reference"); geomByRef.addActionListener(this); geomByRef.setSelected(true); geomByCopy = new JRadioButton("by copy"); geomByCopy.addActionListener(this); ButtonGroup geomGroup = new ButtonGroup(); geomGroup.add(geomByRef); geomGroup.add(geomByCopy); JLabel geomLabel = new JLabel("Geometry:"); javax.swing.Box geomBox = new javax.swing.Box(BoxLayout.Y_AXIS); geomBox.add(geomLabel); geomBox.add(geomByRef); geomBox.add(geomByCopy); strut1 = geomBox.createVerticalStrut(geomByRef.getPreferredSize().height); strut2 = geomBox.createVerticalStrut(geomByRef.getPreferredSize().height); strut3 = geomBox.createVerticalStrut(geomByRef.getPreferredSize().height); geomBox.add(strut1); geomBox.add(strut2); geomBox.add(strut3); img4ByteABGR = new JRadioButton("TYPE_4BYTE_ABGR"); img4ByteABGR.addActionListener(this); img4ByteABGR.setSelected(true); img3ByteBGR = new JRadioButton("TYPE_3BYTE_BGR"); img3ByteBGR.addActionListener(this); imgIntARGB = new JRadioButton("TYPE_INT_ARGB"); imgIntARGB.addActionListener(this); imgCustomRGBA = new JRadioButton("TYPE_CUSTOM RGBA"); imgCustomRGBA.addActionListener(this); imgCustomRGB = new JRadioButton("TYPE_CUSTOM RGB"); imgCustomRGB.addActionListener(this); ButtonGroup imgGroup = new ButtonGroup(); imgGroup.add(img4ByteABGR); imgGroup.add(img3ByteBGR); imgGroup.add(imgIntARGB); imgGroup.add(imgCustomRGBA); imgGroup.add(imgCustomRGB); JLabel imgLabel = new JLabel("Image Type:*"); javax.swing.Box imgBox = new javax.swing.Box(BoxLayout.Y_AXIS); imgBox.add(imgLabel); imgBox.add(img4ByteABGR); imgBox.add(img3ByteBGR); imgBox.add(imgIntARGB); imgBox.add(imgCustomRGBA); imgBox.add(imgCustomRGB); javax.swing.Box topBox = new javax.swing.Box(BoxLayout.X_AXIS); topBox.add(flipBox); topBox.add(texBox); topBox.add(geomBox); topBox.add(yBox); Component strut = topBox.createRigidArea(new Dimension(10, 10)); topBox.add(strut); topBox.add(imgBox); frameDelay = new JSlider(0, 50, 0); frameDelay.addChangeListener(this); frameDelay.setSnapToTicks(true); frameDelay.setPaintTicks(true); frameDelay.setPaintLabels(true); frameDelay.setMajorTickSpacing(10); frameDelay.setMinorTickSpacing(1); frameDelay.setValue(20); JLabel delayL = new JLabel("frame delay"); javax.swing.Box delayBox = new javax.swing.Box(BoxLayout.X_AXIS); delayBox.add(delayL); delayBox.add(frameDelay); animationB = new JButton(" stop animation "); animationB.addActionListener(this); JLabel texInfo1 = new JLabel("*To use ImageComponent by reference feature, use TYPE_4BYTE_ABGR on Solaris"); JLabel texInfo2 = new JLabel("and TYPE_3BYTE_BGR on Windows"); JPanel buttonP = new JPanel(); GridBagLayout gridbag = new GridBagLayout(); GridBagConstraints c = new GridBagConstraints(); buttonP.setLayout(gridbag); c.anchor = GridBagConstraints.CENTER; c.gridwidth = GridBagConstraints.REMAINDER; gridbag.setConstraints(topBox, c); buttonP.add(topBox); gridbag.setConstraints(delayBox, c); buttonP.add(delayBox); gridbag.setConstraints(animationB, c); buttonP.add(animationB); gridbag.setConstraints(texInfo1, c); buttonP.add(texInfo1); gridbag.setConstraints(texInfo2, c); buttonP.add(texInfo2); return buttonP; } public BranchGroup createSceneGraph() { // create the root of the branch group BranchGroup objRoot = new BranchGroup(); // create the transform group node and initialize it // enable the TRANSFORM_WRITE capability so that it can be modified // at runtime. Add it to the root of the subgraph Transform3D rotate = new Transform3D(); TransformGroup objTrans = new TransformGroup(rotate); objTrans.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE); objRoot.addChild(objTrans); // bounds BoundingSphere bounds = new BoundingSphere(new Point3d(0.0, 0.0, 0.0), 100.0); // set up some light Color3f lColor1 = new Color3f(0.7f, 0.7f, 0.7f); Vector3f lDir1 = new Vector3f(-1.0f, -0.5f, -1.0f); Color3f alColor = new Color3f(0.2f, 0.2f, 0.2f); AmbientLight aLgt = new AmbientLight(alColor); aLgt.setInfluencingBounds(bounds); DirectionalLight lgt1 = new DirectionalLight(lColor1, lDir1); lgt1.setInfluencingBounds(bounds); objRoot.addChild(aLgt); objRoot.addChild(lgt1); Appearance appearance = new Appearance(); // enable the TEXTURE_WRITE so we can modify it at runtime appearance.setCapability(Appearance.ALLOW_TEXTURE_WRITE); // load the first texture TextureLoader loader = new TextureLoader(urls[0], TextureLoader.BY_REFERENCE | TextureLoader.Y_UP, this); // get the texture from the loader Texture2D tex = (Texture2D) loader.getTexture(); // get the BufferedImage to convert to TYPE_4BYTE_ABGR and flip // get the ImageComponent because we need it anyway ImageComponent2D imageComp = (ImageComponent2D) tex.getImage(0); BufferedImage bImage = imageComp.getImage(); // convert the image bImage = ImageOps.convertImage(bImage, BufferedImage.TYPE_4BYTE_ABGR); // flip the image ImageOps.flipImage(bImage); imageComp.set(bImage); tex.setCapability(Texture.ALLOW_IMAGE_WRITE); tex.setBoundaryModeS(Texture.CLAMP); tex.setBoundaryModeT(Texture.CLAMP); tex.setBoundaryColor(1.0f, 1.0f, 1.0f, 1.0f); // set the image of the texture tex.setImage(0, imageComp); // set the texture on the appearance appearance.setTexture(tex); // set texture attributes TextureAttributes texAttr = new TextureAttributes(); texAttr.setTextureMode(TextureAttributes.MODULATE); appearance.setTextureAttributes(texAttr); // set material properties Color3f black = new Color3f(0.0f, 0.0f, 0.0f); Color3f white = new Color3f(1.0f, 1.0f, 1.0f); appearance.setMaterial(new Material(white, black, white, black, 1.0f)); // create a scale transform Transform3D scale = new Transform3D(); scale.set(.6); TransformGroup objScale = new TransformGroup(scale); objTrans.addChild(objScale); tetra = new Tetrahedron(true); tetra.setAppearance(appearance); objScale.addChild(tetra); // create the behavior animate = new AnimateTexturesBehavior(tex, urls, appearance, this); animate.setSchedulingBounds(bounds); objTrans.addChild(animate); // add a rotation behavior so we can see all sides of the tetrahedron Transform3D yAxis = new Transform3D(); Alpha rotorAlpha = new Alpha(-1, Alpha.INCREASING_ENABLE, 0, 0, 4000, 0, 0, 0, 0, 0); RotationInterpolator rotator = new RotationInterpolator(rotorAlpha, objTrans, yAxis, 0.0f, (float) Math.PI * 2.0f); rotator.setSchedulingBounds(bounds); objTrans.addChild(rotator); // have java3d perform optimizations on this scene graph objRoot.compile(); return objRoot; } // callback for the animation button and delay text field public void actionPerformed(ActionEvent e) { Object o = e.getSource(); // for the animation button if (o == animationB) { if (animate.getEnable()) { animate.setEnable(false); animationB.setText("start animation"); } else { animate.setEnable(true); animationB.setText(" stop animation "); } } // for the texByRef button else if (o == texByRef && texByRef.isSelected()) { animate.setByReference(true); } // texByCopy button else if (o == texByCopy && texByCopy.isSelected()) { animate.setByReference(false); } // yUp button else if (o == yUp && yUp.isSelected()) { animate.setYUp(true); } // ydown button else if (o == yDown && yDown.isSelected()) { animate.setYUp(false); } //geomByRef button else if (o == geomByRef) { tetra.setByReference(true); } // geomByCopy button else if (o == geomByCopy) { tetra.setByReference(false); } // TYPE_INT_ARGB else if (o == imgIntARGB) { animate.setImageType(BufferedImage.TYPE_INT_ARGB); } // TYPE_4BYTE_ABGR else if (o == img4ByteABGR) { animate.setImageType(BufferedImage.TYPE_4BYTE_ABGR); } // TYPE_3BYTE_BGR else if (o == img3ByteBGR) { animate.setImageType(BufferedImage.TYPE_3BYTE_BGR); } // TYPE_CUSTOM RGBA else if (o == imgCustomRGBA) { animate.setImageTypeCustomRGBA(); } // TYPE_CUSTOM RGB else if (o == imgCustomRGB) { animate.setImageTypeCustomRGB(); } } // callback for the checkboxes public void itemStateChanged(ItemEvent e) { Object o = e.getSource(); // for the flip checkbox if (o == flipB) { if (e.getStateChange() == ItemEvent.DESELECTED) { animate.setFlipImages(false); } else animate.setFlipImages(true); } } // callback for the slider public void stateChanged(ChangeEvent e) { Object o = e.getSource(); // for the frame delay if (o == frameDelay) { animate.setFrameDelay(frameDelay.getValue()); } } // allows TextureByReference to be run as an application as well as an // applet public static void main(String[] args) { java.net.URL fnames[] = null; if (args.length > 1) { fnames = new java.net.URL[args.length]; for (int i = 0; i < args.length; i++) { try { fnames[i] = new java.net.URL("file:" + args[i]); } catch (java.net.MalformedURLException ex) { System.out.println(ex.getMessage()); } } } else { fnames = new java.net.URL[TextureByReference.defaultFiles.length]; for (int i = 0; i < TextureByReference.defaultFiles.length; i++) { try { fnames[i] = new java.net.URL("file:" + TextureByReference.defaultFiles[i]); } catch (java.net.MalformedURLException ex) { System.out.println(ex.getMessage()); System.exit(1); } } } new MainFrame((new TextureByReference(fnames)), 650, 750); } } class AnimateTexturesBehavior extends Behavior { // what image are we on private int current; private int max; // the images private ImageComponent2D[] images; // the target private Texture2D texture; private Appearance appearance; // the wakeup criterion private WakeupCriterion wakeupC; // are the images flipped? private boolean flip; // need the current type because by copy changes all images // to TYPE_INT_ARGB private int currentType; // for custom types public static final int TYPE_CUSTOM_RGBA = 0x01; public static final int TYPE_CUSTOM_RGB = 0x02; private int customType; // create a new AnimateTextureBehavior // initialize the images public AnimateTexturesBehavior(Texture2D texP, java.net.URL[] fnames, Appearance appP, TextureByReference applet) { int size = fnames.length; images = new ImageComponent2D[size]; BufferedImage bImage; TextureLoader loader; for (int i = 0; i < size; i++) { loader = new TextureLoader(fnames[i], TextureLoader.BY_REFERENCE | TextureLoader.Y_UP, applet); images[i] = loader.getImage(); bImage = images[i].getImage(); // convert the image to TYPE_4BYTE_ABGR currentType = BufferedImage.TYPE_4BYTE_ABGR; bImage = ImageOps.convertImage(bImage, currentType); // flip the image flip = true; ImageOps.flipImage(bImage); // set the image on the ImageComponent to the new one images[i].set(bImage); images[i].setCapability(ImageComponent.ALLOW_IMAGE_READ); images[i].setCapability(ImageComponent.ALLOW_FORMAT_READ); } texture = texP; current = 0; max = size; wakeupC = new WakeupOnElapsedFrames(20); appearance = appP; } // initialize to the first image public void initialize() { texture.setImage(0, images[current]); if (current < max - 1) current++; else current = 0; wakeupOn(wakeupC); } // procesStimulus changes the ImageComponent of the texture public void processStimulus(Enumeration criteria) { // ImageOps.printType(images[current].getImage()); texture.setImage(0, images[current]); appearance.setTexture(texture); if (current < max - 1) current++; else current = 0; wakeupOn(wakeupC); } // flip the image -- useful depending on yUp public void setFlipImages(boolean b) { // double check that flipping is necessary if (b != flip) { BufferedImage bImage; // these are the same for all images so get info once int format = images[0].getFormat(); boolean byRef = images[0].isByReference(); boolean yUp = images[0].isYUp(); // flip all the images // have to new ImageComponents because can't set the image at // runtime for (int i = 0; i < images.length; i++) { bImage = images[i].getImage(); ImageOps.flipImage(bImage); // if we are byRef and the bImage type does not match // currentType // we need to convert it. If we are not byRef we will // save converting until it is changed to byRef if (byRef && bImage.getType() != currentType) { if (currentType != BufferedImage.TYPE_CUSTOM) { bImage = ImageOps.convertImage(bImage, currentType); } else if (customType == this.TYPE_CUSTOM_RGBA) { bImage = ImageOps.convertToCustomRGBA(bImage); } else { bImage = ImageOps.convertToCustomRGB(bImage); } } images[i] = new ImageComponent2D(format, bImage, byRef, yUp); images[i].setCapability(ImageComponent.ALLOW_IMAGE_READ); images[i].setCapability(ImageComponent.ALLOW_FORMAT_READ); } // set flip to new value flip = b; } } // create new ImageComponents with yUp set to the parameter. yUp on // an ImageComponent cannot be changed at runtim public void setYUp(boolean b) { // double check that changing yUp is necessary if (b != images[0].isYUp()) { // these are the same for all images so get info once int format = images[0].getFormat(); boolean byRef = images[0].isByReference(); // reset yUp on all the images -- have to new ImageComponents // because // cannot change the value at runtime for (int i = 0; i < images.length; i++) { // if we are byRef and the bImage type does not match // currentType // we need to convert it. If we are not byRef we will // save converting until it is changed to byRef BufferedImage bImage = images[i].getImage(); if (byRef && bImage.getType() != currentType) { // bImage = ImageOps.convertImage(bImage, currentType); if (currentType != BufferedImage.TYPE_CUSTOM) { bImage = ImageOps.convertImage(bImage, currentType); } else if (customType == this.TYPE_CUSTOM_RGBA) { bImage = ImageOps.convertToCustomRGBA(bImage); } else { bImage = ImageOps.convertToCustomRGB(bImage); } } images[i] = new ImageComponent2D(format, bImage, byRef, b); images[i].setCapability(ImageComponent.ALLOW_IMAGE_READ); images[i].setCapability(ImageComponent.ALLOW_FORMAT_READ); } } } // create new ImageComponents with ByReference set by parameter. // by reference cannot be changed on an image component at runtime public void setByReference(boolean b) { // double check that changing is necessary if (b != images[0].isByReference()) { // these are the same for all images so get info once int format = images[0].getFormat(); boolean yUp = images[0].isYUp(); // reset yUp on all the images // have to new ImageComponents because cannot set value for (int i = 0; i < images.length; i++) { // if the bImage type does not match currentType and we are // setting // to byRef we need to convert it BufferedImage bImage = images[i].getImage(); if (bImage.getType() != currentType && b) { // bImage = ImageOps.convertImage(bImage, currentType); if (currentType != BufferedImage.TYPE_CUSTOM) { bImage = ImageOps.convertImage(bImage, currentType); } else if (customType == this.TYPE_CUSTOM_RGBA) { bImage = ImageOps.convertToCustomRGBA(bImage); } else { bImage = ImageOps.convertToCustomRGB(bImage); } } images[i] = new ImageComponent2D(format, bImage, b, yUp); images[i].setCapability(ImageComponent.ALLOW_IMAGE_READ); images[i].setCapability(ImageComponent.ALLOW_FORMAT_READ); } } } // make a new wakeup criterion object based on the new delay time public void setFrameDelay(int delay) { wakeupC = new WakeupOnElapsedFrames(delay); } //change the type of image public void setImageType(int newType) { currentType = newType; // only need to change the images if we are byRef otherwise will change // them when we chnage to byRef if (images[0].isByReference() == true) { // this information is the same for all int format = images[0].getFormat(); boolean yUp = images[0].isYUp(); boolean byRef = true; for (int i = 0; i < images.length; i++) { BufferedImage bImage = images[i].getImage(); bImage = ImageOps.convertImage(bImage, currentType); images[i] = new ImageComponent2D(format, bImage, byRef, yUp); images[i].setCapability(ImageComponent.ALLOW_IMAGE_READ); images[i].setCapability(ImageComponent.ALLOW_FORMAT_READ); } } } public void setImageTypeCustomRGBA() { currentType = BufferedImage.TYPE_CUSTOM; customType = this.TYPE_CUSTOM_RGBA; // only need to change images if we are byRef otherwise will change // them when we change to byRef if (images[0].isByReference()) { // this information is the same for all int format = images[0].getFormat(); boolean yUp = images[0].isYUp(); boolean byRef = true; for (int i = 0; i < images.length; i++) { BufferedImage bImage = images[i].getImage(); bImage = ImageOps.convertToCustomRGBA(bImage); images[i] = new ImageComponent2D(format, bImage, byRef, yUp); images[i].setCapability(ImageComponent.ALLOW_IMAGE_READ); images[i].setCapability(ImageComponent.ALLOW_FORMAT_READ); } } } public void setImageTypeCustomRGB() { currentType = BufferedImage.TYPE_CUSTOM; customType = this.TYPE_CUSTOM_RGB; // only need to change images if we are byRef otherwise will change // them when we change to byRef if (images[0].isByReference()) { // this information is the same for all int format = images[0].getFormat(); boolean yUp = images[0].isYUp(); boolean byRef = true; for (int i = 0; i < images.length; i++) { BufferedImage bImage = images[i].getImage(); bImage = ImageOps.convertToCustomRGB(bImage); images[i] = new ImageComponent2D(format, bImage, byRef, yUp); images[i].setCapability(ImageComponent.ALLOW_IMAGE_READ); images[i].setCapability(ImageComponent.ALLOW_FORMAT_READ); } } } } class Tetrahedron extends Shape3D { private static final float sqrt3 = (float) Math.sqrt(3.0); private static final float sqrt3_3 = sqrt3 / 3.0f; private static final float sqrt24_3 = (float) Math.sqrt(24.0) / 3.0f; private static final float ycenter = 0.5f * sqrt24_3; private static final float zcenter = -sqrt3_3; private static final Point3f p1 = new Point3f(-1.0f, -ycenter, -zcenter); private static final Point3f p2 = new Point3f(1.0f, -ycenter, -zcenter); private static final Point3f p3 = new Point3f(0.0f, -ycenter, -sqrt3 - zcenter); private static final Point3f p4 = new Point3f(0.0f, sqrt24_3 - ycenter, 0.0f); private static final Point3f[] verts = { p1, p2, p4, // front face p1, p4, p3, // left, back face p2, p3, p4, // right, back face p1, p3, p2, // bottom face }; private Point2f texCoord[] = { new Point2f(-0.25f, 0.0f), new Point2f(1.25f, 0.0f), new Point2f(0.5f, 2.0f), }; private TriangleArray geometryByRef; private TriangleArray geometryByCopy; // for geometry by reference private Point3f[] verticesArray = new Point3f[12]; private TexCoord2f[] textureCoordsArray = new TexCoord2f[12]; private Vector3f[] normalsArray = new Vector3f[12]; // default to geometry by copy public Tetrahedron() { this(false); } // creates a tetrahedron with geometry by reference or by copy depending on // the byRef parameter public Tetrahedron(boolean byRef) { if (byRef) { createGeometryByRef(); this.setGeometry(geometryByRef); } else { createGeometryByCopy(); this.setGeometry(geometryByCopy); } this.setCapability(Shape3D.ALLOW_GEOMETRY_READ); this.setCapability(Shape3D.ALLOW_GEOMETRY_WRITE); setAppearance(new Appearance()); } // create the geometry by reference and // store it in the geometryByRef variable public void createGeometryByRef() { // System.out.println("createGeometryByRef"); geometryByRef = new TriangleArray(12, TriangleArray.COORDINATES | TriangleArray.NORMALS | TriangleArray.TEXTURE_COORDINATE_2 | TriangleArray.BY_REFERENCE); int i; // the coordinates for (i = 0; i < 12; i++) { verticesArray[i] = new Point3f(verts[i]); } geometryByRef.setCoordRef3f(verticesArray); // System.out.println("coordinates set"); // Point3f[] temp1 = geometryByRef.getCoordRef3f(); // for (i = 0; i < 12; i++) { // System.out.println(temp1[i]); // } // the texture coordinates for (i = 0; i < 12; i++) { textureCoordsArray[i] = new TexCoord2f(texCoord[i % 3]); } geometryByRef.setTexCoordRef2f(0, textureCoordsArray); // System.out.println("texture coords set"); // TexCoord2f[] temp2 = geometryByRef.getTexCoordRef2f(0); // for (i = 0; i < 12; i++) { // System.out.println(temp2[i]); // } // the normals Vector3f normal = new Vector3f(); Vector3f v1 = new Vector3f(); Vector3f v2 = new Vector3f(); Point3f[] pts = new Point3f[3]; for (int face = 0; face < 4; face++) { pts[0] = new Point3f(verts[face * 3]); pts[1] = new Point3f(verts[face * 3 + 1]); pts[2] = new Point3f(verts[face * 3 + 2]); v1.sub(pts[1], pts[0]); v2.sub(pts[2], pts[0]); normal.cross(v1, v2); normal.normalize(); for (i = 0; i < 3; i++) { normalsArray[face * 3 + i] = new Vector3f(normal); } } geometryByRef.setNormalRef3f(normalsArray); // System.out.println("normals set"); // Vector3f[] temp3 = geometryByRef.getNormalRef3f(); // for (i = 0; i < 12; i++) { // System.out.println(temp3[i]); // } } // create the geometry by copy and store it in the geometryByCopy variable public void createGeometryByCopy() { int i; geometryByCopy = new TriangleArray(12, TriangleArray.COORDINATES | TriangleArray.NORMALS | TriangleArray.TEXTURE_COORDINATE_2); geometryByCopy.setCoordinates(0, verts); for (i = 0; i < 12; i++) { geometryByCopy.setTextureCoordinate(0, i, new TexCoord2f(texCoord[i % 3])); } int face; Vector3f normal = new Vector3f(); Vector3f v1 = new Vector3f(); Vector3f v2 = new Vector3f(); Point3f[] pts = new Point3f[3]; for (i = 0; i < 3; i++) pts[i] = new Point3f(); for (face = 0; face < 4; face++) { geometryByCopy.getCoordinates(face * 3, pts); v1.sub(pts[1], pts[0]); v2.sub(pts[2], pts[0]); normal.cross(v1, v2); normal.normalize(); for (i = 0; i < 3; i++) { geometryByCopy.setNormal((face * 3 + i), normal); } } } // set the geometry to geometryByRef or geometryByCopy depending on the // parameter. Create geometryByRef or geometryByCopy if necessary public void setByReference(boolean b) { // System.out.println("Tetrahedron.setByReference " + b); // by reference is true if (b) { // if there is no geometryByRef, create it if (geometryByRef == null) { createGeometryByRef(); } // set the geometry this.setGeometry(geometryByRef); } // by reference is false else { // if there is no geometryByCopy, create it if (geometryByCopy == null) { createGeometryByCopy(); } // set the geometry this.setGeometry(geometryByCopy); } } } //some useful, static image operations class ImageOps { // flip the image public static void flipImage(BufferedImage bImage) { int width = bImage.getWidth(); int height = bImage.getHeight(); int[] rgbArray = new int[width * height]; bImage.getRGB(0, 0, width, height, rgbArray, 0, width); int[] tempArray = new int[width * height]; int y2 = 0; for (int y = height - 1; y >= 0; y--) { for (int x = 0; x < width; x++) { tempArray[y2 * width + x] = rgbArray[y * width + x]; } y2++; } bImage.setRGB(0, 0, width, height, tempArray, 0, width); } // convert the image to a specified BufferedImage type and return it public static BufferedImage convertImage(BufferedImage bImage, int type) { int width = bImage.getWidth(); int height = bImage.getHeight(); BufferedImage newImage = new BufferedImage(width, height, type); int[] rgbArray = new int[width * height]; bImage.getRGB(0, 0, width, height, rgbArray, 0, width); newImage.setRGB(0, 0, width, height, rgbArray, 0, width); return newImage; } // print out some of the types of BufferedImages static void printType(BufferedImage bImage) { int type = bImage.getType(); if (type == BufferedImage.TYPE_4BYTE_ABGR) { System.out.println("TYPE_4BYTE_ABGR"); } else if (type == BufferedImage.TYPE_INT_ARGB) { System.out.println("TYPE_INT_ARGB"); } else if (type == BufferedImage.TYPE_3BYTE_BGR) { System.out.println("TYPE_3BYTE_BGR"); } else if (type == BufferedImage.TYPE_CUSTOM) { System.out.println("TYPE_CUSTOM"); } else System.out.println(type); } public static BufferedImage convertToCustomRGBA(BufferedImage bImage) { if (bImage.getType() != BufferedImage.TYPE_INT_ARGB) { ImageOps.convertImage(bImage, BufferedImage.TYPE_INT_ARGB); } int width = bImage.getWidth(); int height = bImage.getHeight(); ColorSpace cs = ColorSpace.getInstance(ColorSpace.CS_sRGB); int[] nBits = { 8, 8, 8, 8 }; ColorModel cm = new ComponentColorModel(cs, nBits, true, false, Transparency.OPAQUE, 0); int[] bandOffset = { 0, 1, 2, 3 }; WritableRaster newRaster = Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE, width, height, width * 4, 4, bandOffset, null); byte[] byteData = ((DataBufferByte) newRaster.getDataBuffer()).getData(); Raster origRaster = bImage.getData(); int[] pixel = new int[4]; int k = 0; for (int j = 0; j < height; j++) { for (int i = 0; i < width; i++) { pixel = origRaster.getPixel(i, j, pixel); byteData[k++] = (byte) (pixel[0]); byteData[k++] = (byte) (pixel[1]); byteData[k++] = (byte) (pixel[2]); byteData[k++] = (byte) (pixel[3]); } } BufferedImage newImage = new BufferedImage(cm, newRaster, false, null); // if (newImage.getType() == BufferedImage.TYPE_CUSTOM) { // System.out.println("Type is custom"); // } return newImage; } public static BufferedImage convertToCustomRGB(BufferedImage bImage) { if (bImage.getType() != BufferedImage.TYPE_INT_ARGB) { ImageOps.convertImage(bImage, BufferedImage.TYPE_INT_ARGB); } int width = bImage.getWidth(); int height = bImage.getHeight(); ColorSpace cs = ColorSpace.getInstance(ColorSpace.CS_sRGB); int[] nBits = { 8, 8, 8 }; ColorModel cm = new ComponentColorModel(cs, nBits, false, false, Transparency.OPAQUE, 0); int[] bandOffset = { 0, 1, 2 }; WritableRaster newRaster = Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE, width, height, width * 3, 3, bandOffset, null); byte[] byteData = ((DataBufferByte) newRaster.getDataBuffer()).getData(); Raster origRaster = bImage.getData(); int[] pixel = new int[4]; int k = 0; for (int j = 0; j < height; j++) { for (int i = 0; i < width; i++) { pixel = origRaster.getPixel(i, j, pixel); byteData[k++] = (byte) (pixel[0]); byteData[k++] = (byte) (pixel[1]); byteData[k++] = (byte) (pixel[2]); } } BufferedImage newImage = new BufferedImage(cm, newRaster, false, null); // if (newImage.getType() == BufferedImage.TYPE_CUSTOM) { // System.out.println("Type is custom"); // } return newImage; } }