/*
* @(#)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;
}
}