// // UserRendererJ3D.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 */ /* PROXY UserRendererJ3D like ClientRendererJ3D, but ? ClientRendererJ3D <--> nodes or UserRendererJ3D <--> RemoteProxyAgentImpl <--> nodes RemoteProxyAgent no Java3D on nodes or proxy RemoteClientDataImpl on Client or Proxy, not on User UserDummyDataImpl extends DataImpl getType() from adaptedRemoteClientData RemoteCellImpl triggered by adaptedRemoteClientData calls notifyReferences() UserDisplayRendererJ3D extends DefaultDisplayRendererJ3D like ClientDisplayRendererJ3D */ 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; /** UserRendererJ3D is the VisAD DataRenderer for remote users connecting to a cluster via a proxy on the client. */ public class UserRendererJ3D extends DefaultRendererJ3D { // no UserDummyDataImpl variable // data access via RemoteProxyAgent private RemoteProxyAgent agent = null; private DisplayImpl display = null; private ConstantMap[] cmaps = null; private DataDisplayLink link = null; private long time_out = 10000; private int[] resolutions = null; public UserRendererJ3D() { this(null, 10000); } public UserRendererJ3D(RemoteProxyAgent a) { this(a, 10000); } public UserRendererJ3D(RemoteProxyAgent a, long to) { agent = a; time_out = to; } public void setResolutions(int[] rs) throws RemoteException { try { agent.setResolutions(rs); } catch (RemoteException re) { if (visad.collab.CollabUtil.isDisconnectException(re)) { getDisplay().connectionFailed(this, link); removeLink(link); return; } throw re; } } public DataShadow prepareAction(boolean go, boolean initialize, DataShadow shadow) throws VisADException, RemoteException { 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); } } } } Vector map_vector = display.getMapVector(); int n = map_vector.size(); ScalarMap[] maps = new ScalarMap[n]; Control[] controls = new Control[n]; for (int i=0; i<n; i++) { maps[i] = (ScalarMap) map_vector.elementAt(i); controls[i] = maps[i].getControl(); } Serializable[] responses = agent.prepareAction(go, initialize, shadow, cmaps, maps, controls, display.getName(), time_out); // 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 { Serializable[] responses = null; try { // responses are VisADGroups responses = agent.doTransform(); } catch (DisplayException e) { addException(e); } // System.out.println("UserRendererJ3D.doTransform messages received"); if (link == null) { addException( new DisplayException("Data is null: UserRendererJ3D.doTransform")); responses = null; } // 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); int n = (responses == null) ? 0 : 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; } public void setSpatialValues(float[][] spatial_values) { 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 { Vector message = new Vector(); message.addElement(type); if (shadow == null) { message.addElement(new Integer(getDisplay().getScalarCount())); } else { message.addElement(shadow); } // PROXY: Vector of ShadowType, (Integer or DataShadow) Serializable[] responses = agent.computeRanges(message); // System.out.println("UserRendererJ3D.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 UserRendererJ3D(agent, 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 UserRendererJ3D"); 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); } }