/* * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * - Redistribution of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * - Redistribution in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * Neither the name of Sun Microsystems, Inc. or the names of * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * This software is provided "AS IS," without a warranty of any * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE * POSSIBILITY OF SUCH DAMAGES. * * You acknowledge that this software is not designed, licensed or * intended for use in the design, construction, operation or * maintenance of any nuclear facility. * */ package org.jdesktop.j3d.examples.jcanvas3d; import java.awt.AWTEvent; import java.awt.event.KeyListener; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import java.awt.event.MouseMotionListener; import java.awt.event.MouseWheelListener; import java.util.ArrayList; import java.util.Iterator; import org.jogamp.java3d.Transform3D; import org.jogamp.java3d.WakeupCondition; import org.jogamp.java3d.WakeupCriterion; import org.jogamp.java3d.WakeupOnBehaviorPost; import org.jogamp.java3d.WakeupOnElapsedFrames; import org.jogamp.java3d.exp.swing.JCanvas3D; import org.jogamp.java3d.utils.behaviors.vp.ViewPlatformBehavior; import org.jogamp.java3d.utils.universe.Viewer; import org.jogamp.java3d.utils.universe.ViewingPlatform; /** * Abstract class which implements much of the event tracking and * state updating in a thread safe manner. * * AWT Events are captured and placed in a queue. * * While there are pending events or motion the behavior will wake * up every frame, call processAWTEvents and integrateTransforms. * * @since Java 3D 1.2.1 */ public abstract class ViewPlatformAWTBehaviorJCanvas3D extends ViewPlatformBehavior implements MouseListener, MouseMotionListener, KeyListener, MouseWheelListener { private final static boolean DEBUG = false; /** * Behavior PostId used in this behavior */ protected final static int POST_ID = 9998; /** * The different criterion for the behavior to wakeup */ protected WakeupOnElapsedFrames frameWakeup; /** * The Or of the different criterion for the behavior to wakeup */ protected WakeupOnBehaviorPost postWakeup; /** * The target Transform3D for this behavior */ protected Transform3D targetTransform = new Transform3D(); /** * Boolean for whether the mouse is in motion */ protected boolean motion = false; /** * Flag indicating Behavior should listen for Mouse Events */ public final static int MOUSE_LISTENER = 0x01; /** * Flag indicating Behavior should listen for Mouse Motion Events */ public final static int MOUSE_MOTION_LISTENER = 0x02; /** * Flag indicating Behavior should listen for Key Events */ public final static int KEY_LISTENER = 0x04; /** * Flag indicating Behavior should listen for MouseWheel Events */ public final static int MOUSE_WHEEL_LISTENER = 0x08; /** * The Canvas3Ds from which this Behavior gets AWT events */ protected JCanvas3D canvases[]; private ArrayList eventQueue = new ArrayList(); private int listenerFlags = 0; private boolean firstEvent = false; /** * Parameterless constructor for this behavior, intended for use by * subclasses instantiated through ConfiguredUniverse. Such a constructor * is required for configurable behaviors. * @since Java 3D 1.3 */ protected ViewPlatformAWTBehaviorJCanvas3D() { super(); } /** * Construct a behavior which listens for events specified by the given * flags, intended for use by subclasses instantiated through * ConfiguredUniverse. * * @param listenerFlags Indicates which listener should be registered, * one or more of MOUSE_LISTENER, MOUSE_MOTION_LISTENER, KEY_LISTENER, MOUSE_WHEEL_LISTENER * @since Java 3D 1.3 */ protected ViewPlatformAWTBehaviorJCanvas3D(int listenerFlags) { super(); setListenerFlags(listenerFlags); } /** * Constructs a new ViewPlatformAWTBehavior. * * @param c The Canvas3D on which to listen for events. If this is null a * NullPointerException will be thrown. * @param listenerFlags Indicates which listener should be registered, * one or more of MOUSE_LISTENER, MOUSE_MOTION_LISTENER, KEY_LISTENER, MOUSE_WHEEL_LISTENER */ public ViewPlatformAWTBehaviorJCanvas3D(JCanvas3D c, int listenerFlags ) { super(); if (c == null) throw new NullPointerException(); canvases = new JCanvas3D[] { c }; setListenerFlags(listenerFlags); } /** * Sets listener flags for this behavior. * * @param listenerFlags Indicates which listener should be registered, * one or more of MOUSE_LISTENER, MOUSE_MOTION_LISTENER, KEY_LISTENER, MOUSE_WHEEL_LISTENER * @since Java 3D 1.3 */ protected void setListenerFlags(int listenerFlags) { this.listenerFlags = listenerFlags; } /** * Initializes the behavior. * NOTE: Applications should not call this method. It is called by the * Java 3D behavior scheduler. */ @Override public void initialize() { frameWakeup = new WakeupOnElapsedFrames( 0 ); postWakeup = new WakeupOnBehaviorPost( this, POST_ID ); wakeupOn(postWakeup); } /** * Process a stimulus meant for this behavior. * NOTE: Applications should not call this method. It is called by the * Java 3D behavior scheduler. */ @Override public void processStimulus( Iterator behEnum ) { boolean hadPost = false; while(behEnum.hasNext()) { WakeupCondition wakeup = behEnum.next(); if (wakeup instanceof WakeupOnBehaviorPost) { hadPost = true; } else if (wakeup instanceof WakeupOnElapsedFrames) { AWTEvent[] events = null; // access to event queue must be synchronized synchronized(eventQueue) { events = (AWTEvent[])eventQueue.toArray( new AWTEvent[eventQueue.size()] ); eventQueue.clear(); } processAWTEvents(events); if (motion) integrateTransforms(); } } if (motion || hadPost) { // wake up on behavior posts and elapsed frames if in motion wakeupOn( frameWakeup ); } else { // only wake up on behavior posts if not in motion wakeupOn( postWakeup ); } } /** * Overload setEnable from Behavior. * * Adds/Removes the AWT listeners depending on the requested * state. */ @Override public void setEnable( boolean state ) { if (state==getEnable()) return; super.setEnable(state); if (canvases != null) { enableListeners(state); } } private void enableListeners( boolean enable ) { if (enable) { firstEvent = true ; if ( (listenerFlags & MOUSE_LISTENER)!=0) for(int i=0; inot call this method. */ @Override public void setViewingPlatform(ViewingPlatform vp) { super.setViewingPlatform( vp ); if (vp==null) { enableListeners( false ); } else { if (canvases != null) { // May be switching canvases here. enableListeners(false); } // Use the canvases associated with viewer[0]; if no viewer is // available yet, see if a canvas was provided with a constructor. //Viewer[] viewers = vp.getViewers(); //if (viewers != null && viewers[0] != null) //canvases = viewers[0].getCanvas3Ds(); if (canvases == null || canvases[0] == null) throw new IllegalStateException("No canvases available"); if (getEnable()) { enableListeners(true); } } } /** * This is called once per frame if there are any AWT events to * process. * * The motion variable will be true when the method * is called. If it is true when the method returns integrateTransforms * will be called immediately. * * The AWTEvents are presented in the array in the order in which they * arrived from AWT. */ protected abstract void processAWTEvents( final java.awt.AWTEvent[] events ); /** * Called once per frame (if the view is moving) to calculate the new * view platform transform */ protected abstract void integrateTransforms(); /** * Queue AWTEvents in a thread safe manner. * * If subclasses override this method they must call * super.queueAWTEvent(e) */ protected void queueAWTEvent( AWTEvent e ) { // add new event to the queue // must be MT safe synchronized (eventQueue) { eventQueue.add(e); // Only need to post if this is the only event in the queue. // There have been reports that the first event after // setViewingPlatform() is sometimes missed, so check the // firstEvent flag as well. if (firstEvent || eventQueue.size() == 1) { firstEvent = false; postId( POST_ID ); } } } @Override public void mouseClicked(final MouseEvent e) { queueAWTEvent( e ); } @Override public void mouseEntered(final MouseEvent e) { queueAWTEvent( e ); } @Override public void mouseExited(final MouseEvent e) { queueAWTEvent( e ); } @Override public void mousePressed(final MouseEvent e) { queueAWTEvent( e ); } @Override public void mouseReleased(final MouseEvent e) { queueAWTEvent( e ); } @Override public void mouseDragged(final MouseEvent e) { queueAWTEvent( e ); } @Override public void mouseMoved(final MouseEvent e) { queueAWTEvent( e ); } @Override public void keyReleased(final java.awt.event.KeyEvent e) { queueAWTEvent( e ); } @Override public void keyPressed(final java.awt.event.KeyEvent e) { queueAWTEvent( e ); } @Override public void keyTyped(final java.awt.event.KeyEvent e) { queueAWTEvent( e ); } @Override public void mouseWheelMoved( final java.awt.event.MouseWheelEvent e) { queueAWTEvent( e ); } }