// // VisADCanvasJ3D.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.java3d; import visad.*; import javax.media.j3d.*; import java.awt.*; import java.awt.image.BufferedImage; import java.rmi.RemoteException; import javax.swing.BoxLayout; import javax.swing.JFrame; import javax.swing.JPanel; import java.awt.Graphics; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import com.sun.j3d.utils.universe.SimpleUniverse; /** VisADCanvasJ3D is the VisAD extension of Canvas3D */ public class VisADCanvasJ3D extends Canvas3D { /** */ private DisplayRendererJ3D displayRenderer; /** */ private DisplayImplJ3D display; /** */ private Component component; /** */ Dimension prefSize = new Dimension(0, 0); /** */ boolean captureFlag = false; /** */ BufferedImage captureImage = null; // size of image for off screen rendering /** */ private int width; /** */ private int height; /** */ private static int textureWidthMax = 0; /** */ private static int textureHeightMax = 0; /** */ private final static int textureWidthMaxDefault = 1024; /** */ private final static int textureHeightMaxDefault = 1024; /** */ private boolean offscreen = false; /** */ private static GraphicsConfiguration defaultConfig = null; /** */ private GraphicsConfiguration myConfig = null; /** tracks whether stop has been called */ private boolean stopCalled = false; /** * Make the graphics configuration * @param offscreen true if this is offscreen rendering (sets double * buffering to UNNECESSARY) * @return the graphics configuration */ private static GraphicsConfiguration makeConfig(boolean offscreen) { GraphicsEnvironment e = GraphicsEnvironment.getLocalGraphicsEnvironment(); GraphicsDevice d = e.getDefaultScreenDevice(); // GraphicsConfiguration c = d.getDefaultConfiguration(); /* fix suggested by John Brecht from http://www.j3d.org/faq/running.html#flicker GraphicsConfigTemplate3D gct3d = new GraphicsConfigTemplate3D(); GraphicsConfiguration c = gct3d.getBestConfiguration(d.getConfigurations()); */ GraphicsConfigTemplate3D template = new GraphicsConfigTemplate3D(); if (offscreen) { template.setDoubleBuffer(GraphicsConfigTemplate3D.UNNECESSARY); } GraphicsConfiguration c = d.getBestConfiguration(template); return c; } /** * Set up the texture properties from the GraphicsConfiguration * @param c GraphicsConfiguration */ private void setTextureProperties() { //- see if we've already set this if (!((textureHeightMax == 0) && (textureWidthMax == 0))) return; //- determine textureWidthMax --------------------------------------- //- first check user-defined cmd-line specs: String prop = null; try { prop = System.getProperty("textureWidthMax"); } catch (Exception exp) { prop = null; } textureWidthMax = (prop == null) ? textureWidthMax : Integer.parseInt(prop); // no user defined values, so query Java3D, or set to defaults if ((textureHeightMax == 0) && (textureWidthMax == 0)) { Integer wProp = null; Integer hProp = null; Canvas3D cnvs = new Canvas3D(myConfig); try { java.lang.reflect.Method method = cnvs.getClass().getMethod("queryProperties", (Class[])null); java.util.Map propertiesMap = (java.util.Map)method.invoke(cnvs, (Object[])null); wProp = (Integer)propertiesMap.get("textureWidthMax"); hProp = (Integer)propertiesMap.get("textureHeightMax"); } catch (Exception exc) { } if ((wProp == null) || (hProp == null)) { textureWidthMax = textureWidthMaxDefault; textureHeightMax = textureHeightMaxDefault; System.out.println( "This version of Java3D can't query \"textureWidthMax/textureHeightMax\"\n" + "so they are being assigned the default values: \n" + "textureWidthMax: " + textureWidthMaxDefault + "\n" + "textureHeightMax: " + textureHeightMaxDefault); System.out.println( "If images render as a 'grey-box', try setting these parameters\n" + "to a lower value, eg. 512, with '-DtextureWidthMax=512'\n" + "Otherwise check your graphics environment specifications"); } else { textureWidthMax = wProp.intValue(); textureHeightMax = hProp.intValue(); } } } /** * Get the default configuration. * @return the default configuration */ public static GraphicsConfiguration getDefaultConfig() { return defaultConfig; } /** * Create the canvase for the renderer. * @param renderer the renderer for this canvas */ public VisADCanvasJ3D(DisplayRendererJ3D renderer) { this(renderer, null); } /** * Create the canvase for the renderer with the specified configuration. * @param renderer the renderer for this canvas * @param config GraphicsConfiguration (may be null - in which case * a default configuration is used) */ public VisADCanvasJ3D(DisplayRendererJ3D renderer, GraphicsConfiguration config) { super(config == null ? defaultConfig = (defaultConfig == null ? makeConfig(false) : defaultConfig) : config); myConfig = (config == null) ? defaultConfig : config; setTextureProperties(); displayRenderer = renderer; display = (DisplayImplJ3D)renderer.getDisplay(); component = null; } /** * Set the component for this canvas. * @param c Component to use */ void setComponent(Component c) { component = c; } /** */ private static final double METER_RATIO = (0.0254 / 90.0); // from Java3D docs /** * Constructor for offscreen rendering. * @param renderer renderer to use * @param w width of canvas * @param h height of canvas * * @throws VisADException */ public VisADCanvasJ3D(DisplayRendererJ3D renderer, int w, int h) throws VisADException { // to disable off screen rendering (if you have lower than Java3D // version 1.2.1 installed), uncomment out the following six lines (the // super and throw statements) /** * super(defaultConfig); * throw new VisADException("\n\nFor off screen rendering in Java3D\n" + * "please edit visad/java3d/VisADCanvasJ3D.java as follows:\n" + * "remove or comment-out \"super(defaultConfig);\" and the\n" + * " throw statement for this Exception,\n" + * "and un-comment the body of this constructor\n"); */ // AND comment out the rest of this constructor, super(defaultConfig = (defaultConfig == null ? makeConfig(true) : defaultConfig), true); myConfig = defaultConfig; setTextureProperties(); displayRenderer = renderer; display = (DisplayImplJ3D)renderer.getDisplay(); component = null; offscreen = true; width = w; height = h; BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); ImageComponent2D image2d = new ImageComponent2D(ImageComponent2D.FORMAT_RGB, image); setOffScreenBuffer(image2d); Screen3D screen = getScreen3D(); int screen_width = 1280; int screen_height = 1024; screen.setSize(screen_width, screen_height); double width_in_meters = screen_width * METER_RATIO; double height_in_meters = screen_height * METER_RATIO; screen.setPhysicalScreenWidth(width_in_meters); screen.setPhysicalScreenHeight(height_in_meters); } /** * Set the display associated with this canvas (from renderer) */ void setDisplay() { if (display == null) { display = (DisplayImplJ3D)displayRenderer.getDisplay(); } } /** * See if this is an offscreen rendering. * @return true if offscreen. */ public boolean getOffscreen() { return offscreen; } /** * Render the readout for the field at index. * @param i index. */ public void renderField(int i) { displayRenderer.drawCursorStringVector(this); } /** * Override base class method for grabbing image. */ public void postSwap() { // make sure stop() wasn't called before callback completed if (display == null) return; if (captureFlag || display.hasSlaves()) { // WLH 18 March 99 - SRP suggests that in some implementations // this may need to be in postRender (invoked before buffer swap) captureFlag = false; int width = getSize().width; int height = getSize().height; GraphicsContext3D ctx = getGraphicsContext3D(); Raster ras = new Raster(); ras.setType(Raster.RASTER_COLOR); ras.setSize(width, height); ras.setOffset(0, 0); BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); ImageComponent2D image2d = new ImageComponent2D(ImageComponent2D.FORMAT_RGB, image); ras.setImage(image2d); ctx.readRaster(ras); // Now strip out the image info ImageComponent2D img_src = ras.getImage(); if (captureImage != null) captureImage.flush(); captureImage = img_src.getImage(); displayRenderer.notifyCapture(); // CTR 21 Sep 99 - send BufferedImage to any attached slaved displays if (display.hasSlaves()) display.updateSlaves(captureImage); } // WLH 15 March 99 if (offscreen) { Runnable notify = new Runnable() { public void run() { try { //Check if the display is null. We get this when doing off screen //image capture from the IDV DisplayImplJ3D tmpDisplay = display; if (tmpDisplay != null) { tmpDisplay.notifyListeners(DisplayEvent.FRAME_DONE, 0, 0); } } catch (VisADException e) { } catch (RemoteException e) { } } }; Thread t = new Thread(notify); t.start(); } else { try { display.notifyListeners(DisplayEvent.FRAME_DONE, 0, 0); } catch (VisADException e) { } catch (RemoteException e) { } } } /** * Get the preferred size of this canvas * @return the preferred size */ public Dimension getPreferredSize() { return prefSize; } /** * Set the preferred size of this canvas * @param size the preferred size */ public void setPreferredSize(Dimension size) { prefSize = size; } /** * Get the maximum texture width supported by this display * @return the maximum texture width */ public static int getTextureWidthMax() { return textureWidthMax; } /** * Get the maximum texture height supported by this display * @return the maximum texture height */ public static int getTextureHeightMax() { return textureHeightMax; } /** * Method to test this class * * @param args * * @throws RemoteException * @throws VisADException */ public static void main(String[] args) throws RemoteException, VisADException { DisplayImplJ3D display = new DisplayImplJ3D("offscreen", 300, 300); RealType[] types = {RealType.Latitude, RealType.Longitude}; RealTupleType earth_location = new RealTupleType(types); RealType vis_radiance = RealType.getRealType("vis_radiance"); RealType ir_radiance = RealType.getRealType("ir_radiance"); RealType[] types2 = {vis_radiance, ir_radiance}; RealTupleType radiance = new RealTupleType(types2); FunctionType image_tuple = new FunctionType(earth_location, radiance); int size = 32; FlatField imaget1 = FlatField.makeField(image_tuple, size, false); display.addMap(new ScalarMap(RealType.Latitude, Display.YAxis)); display.addMap(new ScalarMap(RealType.Longitude, Display.XAxis)); display.addMap(new ScalarMap(vis_radiance, Display.RGB)); display.addMap(new ScalarMap(vis_radiance, Display.IsoContour)); DataReferenceImpl ref_imaget1 = new DataReferenceImpl("ref_imaget1"); ref_imaget1.setData(imaget1); display.addReference(ref_imaget1, null); JFrame jframe1 = new JFrame("test off screen"); jframe1.addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { System.exit(0); } }); JPanel panel1 = new JPanel(); panel1.setLayout(new BoxLayout(panel1, BoxLayout.X_AXIS)); panel1.setAlignmentY(JPanel.TOP_ALIGNMENT); panel1.setAlignmentX(JPanel.LEFT_ALIGNMENT); jframe1.setContentPane(panel1); jframe1.pack(); jframe1.setSize(300, 300); jframe1.setVisible(true); while(true) { Graphics gp = panel1.getGraphics(); BufferedImage image = display.getImage(); gp.drawImage(image, 0, 0, panel1); System.out.println("drawImage"); gp.dispose(); try { Thread.sleep(1000); } catch (InterruptedException e) { } } } /** * Stop the applet */ public void stop() { //If we have already been called then return if (stopCalled) { return; } stopCalled = true; if (!offscreen) { stopRenderer(); } display = null; displayRenderer = null; if (component != null) { try { if (component instanceof DisplayPanelJ3D) { ((DisplayPanelJ3D)component).destroy(); } else if (component instanceof DisplayAppletJ3D) { ((DisplayAppletJ3D)component).destroy(); } } catch (Exception exc) { //jeffmc: we kept getting these exceptions so for now //just print out the error cond continue on System.err.println("Error destroying java3d component"); exc.printStackTrace(); } component = null; // WLH 17 Dec 2001 } captureImage = null; myConfig = null; } }