/*
* Copyright (C) 2011 United States Government as represented by the Administrator of the
* National Aeronautics and Space Administration.
* All Rights Reserved.
*/
package au.gov.ga.earthsci.newt.awt;
import gov.nasa.worldwind.Model;
import gov.nasa.worldwind.SceneController;
import gov.nasa.worldwind.View;
import gov.nasa.worldwind.WorldWind;
import gov.nasa.worldwind.WorldWindow;
import gov.nasa.worldwind.WorldWindowImpl;
import gov.nasa.worldwind.avlist.AVKey;
import gov.nasa.worldwind.avlist.AVList;
import gov.nasa.worldwind.cache.GpuResourceCache;
import gov.nasa.worldwind.event.InputHandler;
import gov.nasa.worldwind.event.NoOpInputHandler;
import gov.nasa.worldwind.event.PositionListener;
import gov.nasa.worldwind.event.RenderingExceptionListener;
import gov.nasa.worldwind.event.RenderingListener;
import gov.nasa.worldwind.event.SelectListener;
import gov.nasa.worldwind.exception.WWRuntimeException;
import gov.nasa.worldwind.geom.Position;
import gov.nasa.worldwind.pick.PickedObjectList;
import gov.nasa.worldwind.util.Logging;
import gov.nasa.worldwind.util.PerformanceStatistic;
import java.awt.GraphicsDevice;
import java.awt.event.KeyListener;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.event.MouseWheelListener;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.Collection;
import java.util.Map;
import java.util.Set;
import javax.media.opengl.GLCapabilities;
import javax.media.opengl.GLCapabilitiesChooser;
import javax.media.opengl.GLContext;
import javax.media.opengl.GLProfile;
import javax.media.opengl.awt.GLCanvas;
import com.jogamp.newt.awt.NewtCanvasAWT;
import com.jogamp.newt.event.awt.AWTAdapter;
import com.jogamp.newt.opengl.GLWindow;
/**
* {@link WorldWindow} implementation that uses a {@link NewtCanvasAWT} for
* rendering. To use this class, the {@link AVKey#WORLD_WINDOW_CLASS_NAME}
* configuration property must be the name of a class that implements the
* {@link WorldWindowNewtDrawableAWT} interface.
* <p/>
* Most of this implementation is copied from the WorldWindowGLCanvas source.
*
* @author Michael de Hoog (michael.dehoog@ga.gov.au)
*/
public class WorldWindowNewtCanvasAWT extends NewtCanvasAWT implements WorldWindow, PropertyChangeListener
{
/**
* Returns a {@link GLCapabilities} identifying default graphics features to
* request. The capabilities instance returned requests a frame buffer with
* 8 bits each of red, green, blue and alpha, a 24-bit depth buffer, double
* buffering, and if the Java property "gov.nasa.worldwind.stereo.mode" is
* set to "device", device-supported stereo.
*
* @return a new capabilities instance identifying desired graphics
* features.
*/
protected static GLCapabilities getCaps()
{
GLCapabilities caps = new GLCapabilities(GLProfile.get(GLProfile.GL2));
caps.setAlphaBits(8);
caps.setRedBits(8);
caps.setGreenBits(8);
caps.setBlueBits(8);
caps.setDepthBits(24);
caps.setDoubleBuffered(true);
// Determine whether we should request a stereo canvas
String stereo = System.getProperty(AVKey.STEREO_MODE);
if ("device".equals(stereo)) //$NON-NLS-1$
{
caps.setStereo(true);
}
return caps;
}
/** The drawable to which {@link WorldWindow} methods are delegated. */
protected final WorldWindowNewtDrawableAWT wwd; // WorldWindow interface delegates to wwd
protected final GLWindow window;
public WorldWindowNewtCanvasAWT()
{
this(GLWindow.create(getCaps()));
}
/**
* Constructs a new <code>WorldWindowGLCanvas</code> on the default graphics
* device.
*/
public WorldWindowNewtCanvasAWT(GLWindow window)
{
super(window);
this.window = window;
try
{
this.wwd =
((WorldWindowNewtDrawableAWT) WorldWind.createConfigurationComponent(AVKey.WORLD_WINDOW_CLASS_NAME));
this.wwd.initDrawable(window, this);
this.wwd.initGpuResourceCache(WorldWindowImpl.createGpuResourceCache());
this.createView();
this.createDefaultInputHandler();
WorldWind.addPropertyChangeListener(WorldWind.SHUTDOWN_EVENT, this);
this.wwd.endInitialization();
}
catch (Exception e)
{
String message = Logging.getMessage("Awt.WorldWindowGLSurface.UnabletoCreateWindow"); //$NON-NLS-1$
Logging.logger().severe(message);
throw new WWRuntimeException(message, e);
}
}
/**
* Constructs a new <code>WorldWindowGLCanvas</code> on the default graphics
* device and shares graphics resources with another
* <code>WorldWindow</code>.
*
* @param shareWith
* a <code>WorldWindow</code> with which to share graphics
* resources. May be null, in which case resources are not
* shared.
*
* @see GLCanvas#GLCanvas(GLCapabilities, GLCapabilitiesChooser, GLContext,
* GraphicsDevice)
*/
public WorldWindowNewtCanvasAWT(WorldWindow shareWith)
{
this(shareWith, GLWindow.create(getCaps()));
}
/**
* Constructs a new <code>WorldWindowGLCanvas</code> on the default graphics
* device and shares graphics resources with another
* <code>WorldWindow</code>.
*
* @param shareWith
* a <code>WorldWindow</code> with which to share graphics
* resources. May be null, in which case resources are not
* shared.
*
* @see GLCanvas#GLCanvas(GLCapabilities, GLCapabilitiesChooser, GLContext,
* GraphicsDevice)
*/
public WorldWindowNewtCanvasAWT(WorldWindow shareWith, GLWindow window)
{
super(window);
this.window = window;
if (shareWith != null)
{
this.window.setSharedContext(shareWith.getContext());
}
try
{
this.wwd =
((WorldWindowNewtDrawableAWT) WorldWind.createConfigurationComponent(AVKey.WORLD_WINDOW_CLASS_NAME));
this.wwd.initDrawable(window, this);
if (shareWith != null)
{
this.wwd.initGpuResourceCache(shareWith.getGpuResourceCache());
}
else
{
this.wwd.initGpuResourceCache(WorldWindowImpl.createGpuResourceCache());
}
this.createView();
this.createDefaultInputHandler();
WorldWind.addPropertyChangeListener(WorldWind.SHUTDOWN_EVENT, this);
this.wwd.endInitialization();
}
catch (Exception e)
{
String message = Logging.getMessage("Awt.WorldWindowGLSurface.UnabletoCreateWindow"); //$NON-NLS-1$
Logging.logger().severe(message);
throw new WWRuntimeException(message, e);
}
}
@Override
public void propertyChange(PropertyChangeEvent evt)
{
//noinspection StringEquality
if (evt.getPropertyName() == WorldWind.SHUTDOWN_EVENT)
{
this.shutdown();
}
}
@Override
public void shutdown()
{
WorldWind.removePropertyChangeListener(WorldWind.SHUTDOWN_EVENT, this);
this.wwd.shutdown();
}
/**
* Constructs and attaches the {@link View} for this
* <code>WorldWindow</code>.
*/
protected void createView()
{
this.setView((View) WorldWind.createConfigurationComponent(AVKey.VIEW_CLASS_NAME));
}
/**
* Constructs and attaches the {@link InputHandler} for this
* <code>WorldWindow</code>.
*/
protected void createDefaultInputHandler()
{
this.setInputHandler((InputHandler) WorldWind.createConfigurationComponent(AVKey.INPUT_HANDLER_CLASS_NAME));
}
@Override
public InputHandler getInputHandler()
{
return this.wwd.getInputHandler();
}
@Override
public void setInputHandler(InputHandler inputHandler)
{
if (this.wwd.getInputHandler() != null)
{
this.wwd.getInputHandler().setEventSource(null); // remove this window as a source of events
}
this.wwd.setInputHandler(inputHandler != null ? inputHandler : new NoOpInputHandler());
if (inputHandler != null)
{
inputHandler.setEventSource(this);
}
}
@Override
public SceneController getSceneController()
{
return this.wwd.getSceneController();
}
@Override
public void setSceneController(SceneController sceneController)
{
this.wwd.setSceneController(sceneController);
}
@Override
public GpuResourceCache getGpuResourceCache()
{
return this.wwd.getGpuResourceCache();
}
@Override
public void redraw()
{
this.repaint();
}
@Override
public void redrawNow()
{
this.wwd.redrawNow();
}
@Override
public void setModel(Model model)
{
// null models are permissible
this.wwd.setModel(model);
}
@Override
public Model getModel()
{
return this.wwd.getModel();
}
@Override
public void setView(View view)
{
// null views are permissible
if (view != null)
{
this.wwd.setView(view);
}
}
@Override
public View getView()
{
return this.wwd.getView();
}
@Override
public void setModelAndView(Model model, View view)
{ // null models/views are permissible
this.setModel(model);
this.setView(view);
}
@Override
public void addRenderingListener(RenderingListener listener)
{
this.wwd.addRenderingListener(listener);
}
@Override
public void removeRenderingListener(RenderingListener listener)
{
this.wwd.removeRenderingListener(listener);
}
@Override
public void addSelectListener(SelectListener listener)
{
this.wwd.getInputHandler().addSelectListener(listener);
this.wwd.addSelectListener(listener);
}
@Override
public void removeSelectListener(SelectListener listener)
{
this.wwd.getInputHandler().removeSelectListener(listener);
this.wwd.removeSelectListener(listener);
}
@Override
public void addPositionListener(PositionListener listener)
{
this.wwd.addPositionListener(listener);
}
@Override
public void removePositionListener(PositionListener listener)
{
this.wwd.removePositionListener(listener);
}
@Override
public void addRenderingExceptionListener(RenderingExceptionListener listener)
{
this.wwd.addRenderingExceptionListener(listener);
}
@Override
public void removeRenderingExceptionListener(RenderingExceptionListener listener)
{
this.wwd.removeRenderingExceptionListener(listener);
}
@Override
public Position getCurrentPosition()
{
return this.wwd.getCurrentPosition();
}
@Override
public PickedObjectList getObjectsAtCurrentPosition()
{
return this.wwd.getSceneController() != null ? this.wwd.getSceneController().getPickedObjectList() : null;
}
@Override
public PickedObjectList getObjectsInSelectionBox()
{
return this.wwd.getSceneController() != null ? this.wwd.getSceneController().getObjectsInPickRectangle() : null;
}
@Override
public Object setValue(String key, Object value)
{
return this.wwd.setValue(key, value);
}
@Override
public AVList setValues(AVList avList)
{
return this.wwd.setValues(avList);
}
@Override
public Object getValue(String key)
{
return this.wwd.getValue(key);
}
@Override
public Collection<Object> getValues()
{
return this.wwd.getValues();
}
@Override
public Set<Map.Entry<String, Object>> getEntries()
{
return this.wwd.getEntries();
}
@Override
public String getStringValue(String key)
{
return this.wwd.getStringValue(key);
}
@Override
public boolean hasKey(String key)
{
return this.wwd.hasKey(key);
}
@Override
public Object removeKey(String key)
{
return this.wwd.removeKey(key);
}
@Override
public synchronized void addPropertyChangeListener(PropertyChangeListener listener)
{
super.addPropertyChangeListener(listener);
this.wwd.addPropertyChangeListener(listener);
}
@Override
public synchronized void addPropertyChangeListener(String propertyName, PropertyChangeListener listener)
{
super.addPropertyChangeListener(propertyName, listener);
this.wwd.addPropertyChangeListener(propertyName, listener);
}
@Override
public synchronized void removePropertyChangeListener(PropertyChangeListener listener)
{
super.removePropertyChangeListener(listener);
this.wwd.removePropertyChangeListener(listener);
}
@Override
public synchronized void removePropertyChangeListener(String propertyName, PropertyChangeListener listener)
{
super.removePropertyChangeListener(listener);
this.wwd.removePropertyChangeListener(listener);
}
@Override
public void firePropertyChange(String propertyName, Object oldValue, Object newValue)
{
super.firePropertyChange(propertyName, oldValue, newValue);
}
@Override
public void firePropertyChange(PropertyChangeEvent propertyChangeEvent)
{
this.wwd.firePropertyChange(propertyChangeEvent);
}
@Override
public AVList copy()
{
return this.wwd.copy();
}
@Override
public AVList clearList()
{
return this.wwd.clearList();
}
@Override
public void setPerFrameStatisticsKeys(Set<String> keys)
{
this.wwd.setPerFrameStatisticsKeys(keys);
}
@Override
public Collection<PerformanceStatistic> getPerFrameStatistics()
{
return this.wwd.getPerFrameStatistics();
}
@Override
public GLContext getContext()
{
return window.getContext();
}
public GLWindow getWindow()
{
return window;
}
/* -------------------------------------------------------------------------------
* The below methods are overridden to prevent the superclass adding the AWT->NEWT
* event adapter implementation, as this causes an endless loop of events being
* generated in combination with our NEWT->AWT event adapter.
* ------------------------------------------------------------------------------- */
@Override
public synchronized void addMouseListener(MouseListener l)
{
if (l instanceof AWTAdapter)
{
return;
}
super.addMouseListener(l);
}
@Override
public synchronized void addMouseMotionListener(MouseMotionListener l)
{
if (l instanceof AWTAdapter)
{
return;
}
super.addMouseMotionListener(l);
}
@Override
public synchronized void addMouseWheelListener(MouseWheelListener l)
{
if (l instanceof AWTAdapter)
{
return;
}
super.addMouseWheelListener(l);
}
@Override
public synchronized void addKeyListener(KeyListener l)
{
if (l instanceof AWTAdapter)
{
return;
}
super.addKeyListener(l);
}
}