//
// 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;
}
}