Finally, here’s the source for the nonfunctional 3D version. Note the correct usage (If I understand correctly) of the ImageComponent3D.Updater interface to update the data.
/**
*
*/
package help;
import java.awt.Color;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.URL;
import java.util.Enumeration;
import javax.imageio.ImageIO;
import javax.media.j3d.*;
import javax.vecmath.*;
import com.sun.j3d.utils.behaviors.mouse.MouseRotate;
/**
* @author Mark Bastian
*
*/
public class ByRef3D extends TransformGroup implements ImageComponent3D.Updater
{
public ByRef3D()
{
Appearance appearance = createAppearance();
//Experimental behavior that modifies the image data
addBehavior(appearance);
GeometryArray[] geometry = createGeometry();
for(int i = 0; i < geometry.length; i++)
{
//Create and add the shape
Shape3D shape = new Shape3D(geometry[i], appearance);
addChild(shape);
}
//All of this is unimportant. It is just here to allow some mousing.
Transform3D transform = new Transform3D();
transform.setScale(0.5);
setTransform(transform);
setCapability(TransformGroup.ALLOW_TRANSFORM_READ);
setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
MouseRotate mb = new MouseRotate();
mb.setSchedulingBounds(TextureByrefTester.getBoundingSphere());
mb.setTransformGroup(this);
this.addChild(mb);
}
/**
* Create the 3D texture
* @return created 3D texture
*/
private Texture createTexture()
{
BufferedImage[] images = new BufferedImage[4];
URL url0 = ByRef2D.class.getResource("/help/red.png");
URL url1 = ByRef2D.class.getResource("/help/red.png");
URL url2 = ByRef2D.class.getResource("/help/red.png");
URL url3 = ByRef2D.class.getResource("/help/red.png");
try
{
images[0] = ImageIO.read(url0);
images[1] = ImageIO.read(url1);
images[2] = ImageIO.read(url2);
images[3] = ImageIO.read(url3);
} catch(IOException e)
{
e.printStackTrace();
}
//Create the image data
ImageComponent3D component = new ImageComponent3D(ImageComponent.FORMAT_RGBA, images, true, false);
component.setCapability(ImageComponent.ALLOW_IMAGE_READ);
component.setCapability(ImageComponent.ALLOW_IMAGE_WRITE);
//Create the texture itself from the image component
Texture3D texture = new Texture3D(Texture.BASE_LEVEL, Texture.RGBA,
images[0].getWidth(), images[0].getHeight(), images.length);
texture.setImage(0, component);
return texture;
}
private Appearance createAppearance()
{
//This is an essential ingredient to make sure the texture gets blended correctly
TransparencyAttributes transAttrib = new TransparencyAttributes();
transAttrib.setTransparencyMode(TransparencyAttributes.BLENDED);
//Texture attributes
TextureAttributes textureAttrib = new TextureAttributes();
textureAttrib.setCapability(TextureAttributes.ALLOW_TRANSFORM_READ);
textureAttrib.setCapability(TextureAttributes.ALLOW_TRANSFORM_WRITE);
Transform3D textureTransform = new Transform3D();
textureAttrib.setTextureTransform(textureTransform);
//We want to show the back side of the polygon
PolygonAttributes polygonAttrib = new PolygonAttributes();
polygonAttrib.setCullFace(PolygonAttributes.CULL_NONE);
Appearance appearance = new Appearance();
appearance.setTransparencyAttributes(transAttrib);
appearance.setPolygonAttributes(polygonAttrib);
appearance.setTextureAttributes(textureAttrib);
appearance.setTexture(createTexture());
return appearance;
}
private GeometryArray[] createGeometry()
{
int dim = 128;
GeometryArray[] geometry = new GeometryArray[dim];
float w = 1.0f;
float start = -w;
float delta = 2.0f * w / (dim - 1);
for(int i = 0; i < dim; i++)
{
float value = start + i * delta;
geometry[i] = createQuad(value);
}
return geometry;
}
private GeometryArray createQuad(float z)
{
Point3f[] points = new Point3f[4];
float dim = 1.0f;
points[0] = new Point3f(-dim, -dim, z);
points[1] = new Point3f( dim, -dim, z);
points[2] = new Point3f( dim, dim, z);
points[3] = new Point3f(-dim, dim, z);
z = (z + 1.0f) * 0.5f;
TexCoord3f[] texCoords = new TexCoord3f[4];
texCoords[0] = new TexCoord3f(0.0f, 0.0f, z);
texCoords[1] = new TexCoord3f(1.0f, 0.0f, z);
texCoords[2] = new TexCoord3f(1.0f, 1.0f, z);
texCoords[3] = new TexCoord3f(0.0f, 1.0f, z);
QuadArray array = new QuadArray(4, GeometryArray.COORDINATES | GeometryArray.TEXTURE_COORDINATE_3);
array.setCoordinates(0, points);
array.setTextureCoordinates(0, 0, texCoords);
return array;
}
private void addBehavior(final Appearance appearance)
{
final WakeupCondition condition = new WakeupOnElapsedTime(100);
Behavior behavior = new Behavior()
{
@Override
public void initialize()
{
wakeupOn(condition);
}
@Override
public void processStimulus(Enumeration enumeration)
{
ImageComponent3D component = (ImageComponent3D)appearance.getTexture().getImage(0);
for(int i = 0; i < 4; i++)
{
component.updateData(ByRef3D.this, i, 0, 0, component.getWidth(), component.getHeight());
}
}
};
behavior.setSchedulingBounds(TextureByrefTester.getBoundingSphere());
addChild(behavior);
}
public void updateData(ImageComponent3D component, int index, int x, int y, int width, int height)
{
BufferedImage image = component.getImage(index);
for(int i = 0; i < width; i++)
{
for(int j = 0; j < height; j++)
{
Color c = new Color((int)(Math.random() * 256), (int)(Math.random() * 256), (int)(Math.random() * 256));
image.setRGB(i, j, c.getRGB());
}
}
}
}