//
// ClientRendererJ3D.java
//
/*
VisAD system for interactive analysis and visualization of numerical
data. Copyright (C) 1996 - 2017 Bill Hibbard, Curtis Rueden, Tom
Rink, Dave Glowacki, Steve Emmerson, Tom Whittaker, Don Murray, and
Tommy Jasmin.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free
Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
MA 02111-1307, USA
*/
package visad.cluster;
import visad.*;
import visad.java3d.*;
import javax.media.j3d.*;
import java.awt.event.*;
import java.awt.image.BufferedImage;
import javax.swing.*;
import java.util.Vector;
import java.util.Enumeration;
import java.rmi.*;
import java.io.Serializable;
/**
ClientRendererJ3D is the VisAD DataRenderer for cluster clients
*/
public class ClientRendererJ3D extends DefaultRendererJ3D {
private DisplayImpl display = null;
private ConstantMap[] cmaps = null;
private DataDisplayLink link = null;
private Data data = null;
private boolean cluster = true;
private RemoteClientAgentImpl[] agents = null;
private RemoteClientAgentImpl focus_agent = null;
private RemoteAgentContact[] contacts = null;
private long time_out = 10000;
private int[] resolutions = null;
public ClientRendererJ3D () {
this(10000);
}
public ClientRendererJ3D (long to) {
time_out = to;
}
public void setResolutions(int[] rs) {
if (rs == null) return;
int n = rs.length;
resolutions = new int[n];
for (int i=0; i<n; i++) resolutions[i] = rs[i];
}
public DataShadow prepareAction(boolean go, boolean initialize,
DataShadow shadow)
throws VisADException, RemoteException {
Data old_data = data;
DataDisplayLink[] Links = getLinks();
if (Links != null && Links.length > 0) {
link = Links[0];
// initialize cmaps if not already
if (cmaps == null) {
display = getDisplay();
Vector cvector = link.getConstantMaps();
if (cvector != null && cvector.size() > 0) {
int clength = cvector.size();
cmaps = new ConstantMap[clength];
for (int i=0; i<clength; i++) {
cmaps[i] = (ConstantMap) cvector.elementAt(i);
}
}
}
// get the data
try {
data = link.getData(); // PROXY
} catch (RemoteException re) {
if (visad.collab.CollabUtil.isDisconnectException(re)) {
getDisplay().connectionFailed(this, link);
removeLink(link);
return null;
}
throw re;
}
if (data == null) {
addException(
new DisplayException("Data is null: ClientRendererJ3D.doTransform"));
}
// is this cluster data?
cluster = (data instanceof RemoteClientDataImpl);
/*
if (cluster) {
Set partitionSet = ((RemoteClientDataImpl) data).getPartitionSet();
}
*/
if (cluster && data != old_data) { // PROXY
// send agents to nodes if data changed
RemoteClientDataImpl rcdi = (RemoteClientDataImpl) data;
focus_agent = new RemoteClientAgentImpl(null, -1, time_out);
RemoteClusterData[] jvmTable = rcdi.getTable();
int nagents = jvmTable.length - 1;
agents = new RemoteClientAgentImpl[nagents];
contacts = new RemoteAgentContact[nagents];
for (int i=0; i<nagents; i++) {
agents[i] = new RemoteClientAgentImpl(focus_agent, i);
DefaultNodeRendererAgent node_agent =
new DefaultNodeRendererAgent(agents[i], display.getName(), cmaps);
contacts[i] = ((RemoteNodeData) jvmTable[i]).sendAgent(node_agent);
}
}
}
// WLH new 16 April 2001
Vector message = new Vector();
Vector map_vector = display.getMapVector();
Enumeration maps = map_vector.elements();
while (maps.hasMoreElements()) {
ScalarMap map = (ScalarMap) maps.nextElement();
message.addElement(map);
message.addElement(map.getControl());
}
Serializable[] responses =
focus_agent.broadcastWithResponses(message, contacts); // PROXY
// System.out.println("ClientRendererJ3D.prepareAction messages received");
// now do usual prepareAction()
return super.prepareAction(go, initialize, shadow);
}
/** create a scene graph for Data in links[0] */
public BranchGroup doTransform() throws VisADException, RemoteException {
if (link == null || data == null) {
addException(
new DisplayException("Data is null: ClientRendererJ3D.doTransform"));
}
if (!cluster) {
// not cluster data, so just do the usual
return super.doTransform(); // PROXY (do this on user but not on client)
}
int n = contacts.length;
Vector[] messages = new Vector[n];
if (resolutions == null || resolutions.length != n) {
resolutions = new int[n];
for (int i=0; i<n; i++) resolutions[i] = 1;
}
for (int i=0; i<n; i++) {
// String message = "transform";
messages[i] = new Vector();
messages[i].addElement("transform");
messages[i].addElement(new Integer(resolutions[i]));
Vector map_vector = display.getMapVector();
Enumeration maps = map_vector.elements();
while (maps.hasMoreElements()) {
ScalarMap map = (ScalarMap) maps.nextElement();
messages[i].addElement(map);
}
}
// responses are VisADGroups
Serializable[] responses =
focus_agent.broadcastWithResponses(messages, contacts);
// System.out.println("ClientRendererJ3D.doTransform messages received");
// responses are VisADGroups
// need to:
// 1. rebuild images and volumes
// 2. convert from VisADGroups to BranchGroups
// GeometryArray = display.makeGeometry(VisADGeometryArray)
// 3. add them as children of branch
// link.clearData(); ????
BranchGroup branch = new BranchGroup();
branch.setCapability(BranchGroup.ALLOW_DETACH);
branch.setCapability(Group.ALLOW_CHILDREN_READ);
branch.setCapability(Group.ALLOW_CHILDREN_WRITE);
branch.setCapability(Group.ALLOW_CHILDREN_EXTEND);
n = responses.length;
for (int i=0; i<n; i++) {
if (responses[i] != null) {
VisADSceneGraphObject vsgo = (VisADSceneGraphObject) responses[i];
branch.addChild(convertSceneGraph(vsgo));
}
}
if (n == 0) ShadowTypeJ3D.ensureNotEmpty(branch, display);
return branch;
}
private boolean enable_spatial = true;
public synchronized void setSpatialValues(float[][] spatial_values) {
if (enable_spatial) super.setSpatialValues(spatial_values);
}
/* convert from VisAD scene graph to Java3D scene graph
and rebuild images and volumes */
public Node convertSceneGraph(VisADSceneGraphObject scene)
throws VisADException {
if (scene instanceof VisADSwitch) {
VisADSwitch Vswit = (VisADSwitch) scene;
BranchGroup branch = new BranchGroup();
branch.setCapability(BranchGroup.ALLOW_DETACH);
branch.setCapability(Group.ALLOW_CHILDREN_READ);
branch.setCapability(Group.ALLOW_CHILDREN_WRITE);
branch.setCapability(Group.ALLOW_CHILDREN_EXTEND);
Switch swit = new Switch();
swit.setCapability(Switch.ALLOW_SWITCH_READ);
swit.setCapability(Switch.ALLOW_SWITCH_WRITE);
swit.setCapability(BranchGroup.ALLOW_DETACH);
swit.setCapability(Group.ALLOW_CHILDREN_READ);
swit.setCapability(Group.ALLOW_CHILDREN_WRITE);
int n = Vswit.numChildren();
Set set = Vswit.getSet();
// set != null for Animation
// set == null for volume rendering
if (set != null) {
// Switch for Animation or SelectValue
for (int i=0; i<n; i++) {
VisADSceneGraphObject vsgo = Vswit.getChild(i);
swit.addChild((Node) convertSceneGraph(vsgo));
}
RealType real = (RealType)
((SetType) set.getType()).getDomain().getComponent(0);
AVControl control = null;
Vector mapVector = display.getMapVector();
Enumeration maps = mapVector.elements();
while (maps.hasMoreElements()) {
ScalarMap map = (ScalarMap )maps.nextElement();
if (real.equals(map.getScalar())) {
DisplayRealType dreal = map.getDisplayScalar();
if (dreal.equals(Display.Animation) ||
dreal.equals(Display.SelectValue)) {
control = (AVControl) map.getControl();
break;
}
} // end if (values != null && && real.equals(map.getScalar()))
}
if (control == null) {
throw new ClusterException("AVControl is null");
}
// from ShadowFunctionOrSetTypeJ3D.addSwitch()
((AVControlJ3D) control).addPair(swit, set, this);
((AVControlJ3D) control).init();
}
else { // if (set == null)
// Switch for volume rendering
// see visad.java3d.ShadowFunctionOrSetTypeJ3D.textureStackToGroup()
// and visad.cluster.ShadowNodeFunctionTypeJ3D.textureStackToGroup()
if (Vswit.numChildren() != 3) {
throw new ClusterException("VisADSwitch for volume render " +
"must have 3 children");
}
VisADGroup VbranchX =
(VisADGroup) ((VisADSwitch) scene).getChild(0);
VisADGroup VbranchY =
(VisADGroup) ((VisADSwitch) scene).getChild(1);
VisADGroup VbranchZ =
(VisADGroup) ((VisADSwitch) scene).getChild(2);
int nX = VbranchX.numChildren();
OrderedGroup branchX = new OrderedGroup();
branchX.setCapability(Group.ALLOW_CHILDREN_READ);
VisADAppearance[] appearanceX = new VisADAppearance[nX];
for (int i=0; i<nX; i++) {
VisADAppearance appearance = (VisADAppearance) VbranchX.getChild(i);
branchX.addChild((Shape3D) convertSceneGraph(appearance));
}
OrderedGroup branchXrev = new OrderedGroup();
branchXrev.setCapability(Group.ALLOW_CHILDREN_READ);
for (int i=nX-1; i>=0; i--) {
VisADAppearance appearance = (VisADAppearance) VbranchX.getChild(i);
branchXrev.addChild((Shape3D) convertSceneGraph(appearance));
}
int nY = VbranchY.numChildren();
OrderedGroup branchY = new OrderedGroup();
branchY.setCapability(Group.ALLOW_CHILDREN_READ);
VisADAppearance[] appearanceY = new VisADAppearance[nY];
for (int i=0; i<nY; i++) {
VisADAppearance appearance = (VisADAppearance) VbranchY.getChild(i);
branchY.addChild((Shape3D) convertSceneGraph(appearance));
}
OrderedGroup branchYrev = new OrderedGroup();
branchYrev.setCapability(Group.ALLOW_CHILDREN_READ);
for (int i=nY-1; i>=0; i--) {
VisADAppearance appearance = (VisADAppearance) VbranchY.getChild(i);
branchYrev.addChild((Shape3D) convertSceneGraph(appearance));
}
int nZ = VbranchZ.numChildren();
OrderedGroup branchZ = new OrderedGroup();
branchZ.setCapability(Group.ALLOW_CHILDREN_READ);
VisADAppearance[] appearanceZ = new VisADAppearance[nZ];
for (int i=0; i<nZ; i++) {
VisADAppearance appearance = (VisADAppearance) VbranchZ.getChild(i);
branchZ.addChild((Shape3D) convertSceneGraph(appearance));
}
OrderedGroup branchZrev = new OrderedGroup();
branchZrev.setCapability(Group.ALLOW_CHILDREN_READ);
for (int i=nZ-1; i>=0; i--) {
VisADAppearance appearance = (VisADAppearance) VbranchZ.getChild(i);
branchZrev.addChild((Shape3D) convertSceneGraph(appearance));
}
swit.addChild(branchX);
swit.addChild(branchY);
swit.addChild(branchZ);
swit.addChild(branchXrev);
swit.addChild(branchYrev);
swit.addChild(branchZrev);
ProjectionControlJ3D control =
(ProjectionControlJ3D) display.getProjectionControl();
control.addPair(swit, this);
}
branch.addChild(swit);
return branch;
}
else if (scene instanceof VisADGroup) {
VisADGroup group = (VisADGroup) scene;
BranchGroup branch = new BranchGroup();
branch.setCapability(BranchGroup.ALLOW_DETACH);
branch.setCapability(Group.ALLOW_CHILDREN_READ);
branch.setCapability(Group.ALLOW_CHILDREN_WRITE);
branch.setCapability(Group.ALLOW_CHILDREN_EXTEND);
int n = group.numChildren();
for (int i=0; i<n; i++) {
VisADSceneGraphObject vsgo = group.getChild(i);
branch.addChild((Node) convertSceneGraph(vsgo));
}
ShadowTypeJ3D.ensureNotEmpty(branch, display);
return branch;
}
else if (scene instanceof VisADAppearance) {
VisADAppearance appearance = (VisADAppearance) scene;
GraphicsModeControl mode = display.getGraphicsModeControl();
VisADGeometryArray vga = appearance.array;
GeometryArray array = ((DisplayImplJ3D) display).makeGeometry(vga);
if (array == null) return null;
BufferedImage image = null;
if (appearance.image_pixels != null) {
image = new BufferedImage(appearance.image_width, appearance.image_height,
appearance.image_type);
image.setRGB(0, 0, appearance.image_width, appearance.image_height,
appearance.image_pixels, 0, appearance.image_width);
/* OR:
ColorModel colorModel = ColorModel.getRGBdefault();
WritableRaster raster =
colorModel.createCompatibleWritableRaster(appearance.image_width,
appearance.image_height);
DataBuffer db = raster.getDataBuffer();
if (!(db instanceof DataBufferInt)) {
throw new UnimplementedException("getRGBdefault isn't DataBufferInt");
}
image = new BufferedImage(colorModel, raster, false, null);
int[] intData = ((DataBufferInt)db).getData();
System.arraycopy(appearance.image_pixels, 0, intData, 0, intData.length);
*/
}
if (image != null) {
// need to do Texture stuff
Appearance appearance_j3d =
makeTextureAppearance(appearance, mode, array);
// create TextureAttributes
TextureAttributes texture_attributes = new TextureAttributes();
texture_attributes.setTextureMode(TextureAttributes.MODULATE);
texture_attributes.setPerspectiveCorrectionMode(
TextureAttributes.NICEST);
appearance_j3d.setTextureAttributes(texture_attributes);
int transparencyMode = mode.getTransparencyMode();
Texture2D texture = new Texture2D(Texture.BASE_LEVEL, Texture.RGBA,
appearance.texture_width,
appearance.texture_height);
texture.setCapability(Texture.ALLOW_IMAGE_READ);
ImageComponent2D image2d =
new ImageComponent2D(ImageComponent.FORMAT_RGBA, image);
image2d.setCapability(ImageComponent.ALLOW_IMAGE_READ);
texture.setImage(0, image2d);
// this from textureStackToGroup,
// but not in textureToGroup
if (transparencyMode == TransparencyAttributes.FASTEST) {
texture.setMinFilter(Texture.BASE_LEVEL_POINT);
texture.setMagFilter(Texture.BASE_LEVEL_POINT);
}
else {
texture.setBoundaryModeS(Texture.CLAMP);
texture.setBoundaryModeT(Texture.CLAMP);
texture.setMinFilter(Texture.BASE_LEVEL_LINEAR);
texture.setMagFilter(Texture.BASE_LEVEL_LINEAR);
}
texture.setEnable(true);
appearance_j3d.setTexture(texture);
appearance_j3d.setCapability(Appearance.ALLOW_TEXTURE_READ);
Shape3D shape = new Shape3D(array, appearance_j3d);
shape.setCapability(Shape3D.ALLOW_APPEARANCE_READ);
return shape;
}
else {
Appearance appearance_j3d =
makeAppearance(appearance, mode, array);
Shape3D shape = new Shape3D(array, appearance_j3d);
return shape;
}
}
else {
throw new VisADException("unknown scene " + scene);
}
}
private Appearance makeTextureAppearance(VisADAppearance appearance,
GraphicsModeControl mode, GeometryArray array) {
TransparencyAttributes c_alpha = null;
if (appearance.alpha == 1.0f) {
// constant opaque alpha = NONE
c_alpha = null;
}
else if (appearance.alpha == appearance.alpha) {
c_alpha = new TransparencyAttributes(TransparencyAttributes.BLENDED,
appearance.alpha);
}
else {
c_alpha = new TransparencyAttributes();
c_alpha.setTransparencyMode(TransparencyAttributes.BLENDED);
}
ColoringAttributes c_color = null;
if (appearance.red == appearance.red &&
appearance.green == appearance.green &&
appearance.blue == appearance.blue) {
c_color = new ColoringAttributes();
c_color.setColor(appearance.red, appearance.green, appearance.blue);
}
return ShadowTypeJ3D.staticMakeAppearance(mode, c_alpha, null,
array, false);
}
private Appearance makeAppearance(VisADAppearance appearance,
GraphicsModeControl mode, GeometryArray array) {
TransparencyAttributes c_alpha = null;
if (appearance.alpha == 1.0f) {
// constant opaque alpha = NONE
c_alpha = new TransparencyAttributes(TransparencyAttributes.NONE, 0.0f);
}
else if (appearance.alpha == appearance.alpha) {
c_alpha = new TransparencyAttributes(mode.getTransparencyMode(),
appearance.alpha);
}
else {
c_alpha = new TransparencyAttributes(mode.getTransparencyMode(), 0.0f);
}
ColoringAttributes c_color = null;
if (appearance.red == appearance.red &&
appearance.green == appearance.green &&
appearance.blue == appearance.blue) {
c_color = new ColoringAttributes();
c_color.setColor(appearance.red, appearance.green, appearance.blue);
}
return ShadowTypeJ3D.staticMakeAppearance(mode, c_alpha, c_color,
array, false);
}
public DataShadow computeRanges(Data data, ShadowType type, DataShadow shadow)
throws VisADException, RemoteException {
if (!cluster) {
return super.computeRanges(data, type, shadow);
}
DataShadow[] shadows = null;
Vector message = new Vector();
message.addElement(type);
if (shadow == null) {
message.addElement(new Integer(getDisplay().getScalarCount()));
// shadow =
// data.computeRanges(type, getDisplay().getScalarCount());
}
else {
message.addElement(shadow);
// shadow = data.computeRanges(type, shadow);
}
Serializable[] responses =
focus_agent.broadcastWithResponses(message, contacts);
// System.out.println("ClientRendererJ3D.computeRanges messages received");
DataShadow new_shadow = null;
int n = responses.length;
for (int i=0; i<n; i++) {
if (responses[i] != null) {
if (new_shadow == null) {
new_shadow = (DataShadow) responses[i];
}
else {
new_shadow.merge((DataShadow) responses[i]);
}
}
}
return new_shadow;
}
public Object clone() {
return new ClientRendererJ3D(time_out);
}
public static void main(String args[])
throws VisADException, RemoteException {
DisplayImpl display =
new DisplayImplJ3D("display", new ClientDisplayRendererJ3D());
// create JFrame (i.e., a window) for display and slider
JFrame frame = new JFrame("test ClientRendererJ3D");
frame.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {System.exit(0);}
});
// create JPanel in JFrame
JPanel panel = new JPanel();
panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
panel.setAlignmentY(JPanel.TOP_ALIGNMENT);
panel.setAlignmentX(JPanel.LEFT_ALIGNMENT);
frame.getContentPane().add(panel);
// add display to JPanel
panel.add(display.getComponent());
// set size of JFrame and make it visible
frame.setSize(500, 500);
frame.setVisible(true);
}
}