001: /*
002: * $RCSfile: MouseRotate.java,v $
003: *
004: * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * Redistribution and use in source and binary forms, with or without
007: * modification, are permitted provided that the following conditions
008: * are met:
009: *
010: * - Redistribution of source code must retain the above copyright
011: * notice, this list of conditions and the following disclaimer.
012: *
013: * - Redistribution in binary form must reproduce the above copyright
014: * notice, this list of conditions and the following disclaimer in
015: * the documentation and/or other materials provided with the
016: * distribution.
017: *
018: * Neither the name of Sun Microsystems, Inc. or the names of
019: * contributors may be used to endorse or promote products derived
020: * from this software without specific prior written permission.
021: *
022: * This software is provided "AS IS," without a warranty of any
023: * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
024: * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
025: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
026: * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
027: * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
028: * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
029: * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
030: * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
031: * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
032: * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
033: * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
034: * POSSIBILITY OF SUCH DAMAGES.
035: *
036: * You acknowledge that this software is not designed, licensed or
037: * intended for use in the design, construction, operation or
038: * maintenance of any nuclear facility.
039: *
040: * $Revision: 1.4 $
041: * $Date: 2007/02/09 17:20:13 $
042: * $State: Exp $
043: */
044:
045: package com.sun.j3d.utils.behaviors.mouse;
046:
047: import java.awt.*;
048: import java.awt.event.*;
049: import java.util.*;
050: import javax.media.j3d.*;
051: import javax.vecmath.*;
052:
053: /**
054: * MouseRotate is a Java3D behavior object that lets users control the
055: * rotation of an object via a mouse.
056: * <p>
057: * To use this utility, first create a transform group that this
058: * rotate behavior will operate on. Then,
059: *<blockquote><pre>
060: *
061: * MouseRotate behavior = new MouseRotate();
062: * behavior.setTransformGroup(objTrans);
063: * objTrans.addChild(behavior);
064: * behavior.setSchedulingBounds(bounds);
065: *
066: *</pre></blockquote>
067: * The above code will add the rotate behavior to the transform
068: * group. The user can rotate any object attached to the objTrans.
069: */
070:
071: public class MouseRotate extends MouseBehavior {
072: double x_angle, y_angle;
073: double x_factor = .03;
074: double y_factor = .03;
075:
076: private MouseBehaviorCallback callback = null;
077:
078: /**
079: * Creates a rotate behavior given the transform group.
080: * @param transformGroup The transformGroup to operate on.
081: */
082: public MouseRotate(TransformGroup transformGroup) {
083: super (transformGroup);
084: }
085:
086: /**
087: * Creates a default mouse rotate behavior.
088: **/
089: public MouseRotate() {
090: super (0);
091: }
092:
093: /**
094: * Creates a rotate behavior.
095: * Note that this behavior still needs a transform
096: * group to work on (use setTransformGroup(tg)) and
097: * the transform group must add this behavior.
098: * @param flags interesting flags (wakeup conditions).
099: */
100: public MouseRotate(int flags) {
101: super (flags);
102: }
103:
104: /**
105: * Creates a rotate behavior that uses AWT listeners and behavior
106: * posts rather than WakeupOnAWTEvent. The behavior is added to the
107: * specified Component. A null component can be passed to specify
108: * the behavior should use listeners. Components can then be added
109: * to the behavior with the addListener(Component c) method.
110: * @param c The Component to add the MouseListener
111: * and MouseMotionListener to.
112: * @since Java 3D 1.2.1
113: */
114: public MouseRotate(Component c) {
115: super (c, 0);
116: }
117:
118: /**
119: * Creates a rotate behavior that uses AWT listeners and behavior
120: * posts rather than WakeupOnAWTEvent. The behaviors is added to
121: * the specified Component and works on the given TransformGroup.
122: * A null component can be passed to specify the behavior should use
123: * listeners. Components can then be added to the behavior with the
124: * addListener(Component c) method.
125: * @param c The Component to add the MouseListener and
126: * MouseMotionListener to.
127: * @param transformGroup The TransformGroup to operate on.
128: * @since Java 3D 1.2.1
129: */
130: public MouseRotate(Component c, TransformGroup transformGroup) {
131: super (c, transformGroup);
132: }
133:
134: /**
135: * Creates a rotate behavior that uses AWT listeners and behavior
136: * posts rather than WakeupOnAWTEvent. The behavior is added to the
137: * specified Component. A null component can be passed to specify
138: * the behavior should use listeners. Components can then be added to
139: * the behavior with the addListener(Component c) method.
140: * Note that this behavior still needs a transform
141: * group to work on (use setTransformGroup(tg)) and the transform
142: * group must add this behavior.
143: * @param flags interesting flags (wakeup conditions).
144: * @since Java 3D 1.2.1
145: */
146: public MouseRotate(Component c, int flags) {
147: super (c, flags);
148: }
149:
150: public void initialize() {
151: super .initialize();
152: x_angle = 0;
153: y_angle = 0;
154: if ((flags & INVERT_INPUT) == INVERT_INPUT) {
155: invert = true;
156: x_factor *= -1;
157: y_factor *= -1;
158: }
159: }
160:
161: /**
162: * Return the x-axis movement multipler.
163: **/
164: public double getXFactor() {
165: return x_factor;
166: }
167:
168: /**
169: * Return the y-axis movement multipler.
170: **/
171: public double getYFactor() {
172: return y_factor;
173: }
174:
175: /**
176: * Set the x-axis amd y-axis movement multipler with factor.
177: **/
178: public void setFactor(double factor) {
179: x_factor = y_factor = factor;
180: }
181:
182: /**
183: * Set the x-axis amd y-axis movement multipler with xFactor and yFactor
184: * respectively.
185: **/
186: public void setFactor(double xFactor, double yFactor) {
187: x_factor = xFactor;
188: y_factor = yFactor;
189: }
190:
191: public void processStimulus(Enumeration criteria) {
192: WakeupCriterion wakeup;
193: AWTEvent[] events;
194: MouseEvent evt;
195: // int id;
196: // int dx, dy;
197:
198: while (criteria.hasMoreElements()) {
199: wakeup = (WakeupCriterion) criteria.nextElement();
200: if (wakeup instanceof WakeupOnAWTEvent) {
201: events = ((WakeupOnAWTEvent) wakeup).getAWTEvent();
202: if (events.length > 0) {
203: evt = (MouseEvent) events[events.length - 1];
204: doProcess(evt);
205: }
206: }
207:
208: else if (wakeup instanceof WakeupOnBehaviorPost) {
209: while (true) {
210: // access to the queue must be synchronized
211: synchronized (mouseq) {
212: if (mouseq.isEmpty())
213: break;
214: evt = (MouseEvent) mouseq.remove(0);
215: // consolidate MOUSE_DRAG events
216: while ((evt.getID() == MouseEvent.MOUSE_DRAGGED)
217: && !mouseq.isEmpty()
218: && (((MouseEvent) mouseq.get(0))
219: .getID() == MouseEvent.MOUSE_DRAGGED)) {
220: evt = (MouseEvent) mouseq.remove(0);
221: }
222: }
223: doProcess(evt);
224: }
225: }
226:
227: }
228: wakeupOn(mouseCriterion);
229: }
230:
231: void doProcess(MouseEvent evt) {
232: int id;
233: int dx, dy;
234:
235: processMouseEvent(evt);
236: if (((buttonPress) && ((flags & MANUAL_WAKEUP) == 0))
237: || ((wakeUp) && ((flags & MANUAL_WAKEUP) != 0))) {
238: id = evt.getID();
239: if ((id == MouseEvent.MOUSE_DRAGGED) && !evt.isMetaDown()
240: && !evt.isAltDown()) {
241: x = evt.getX();
242: y = evt.getY();
243:
244: dx = x - x_last;
245: dy = y - y_last;
246:
247: if (!reset) {
248: x_angle = dy * y_factor;
249: y_angle = dx * x_factor;
250:
251: transformX.rotX(x_angle);
252: transformY.rotY(y_angle);
253:
254: transformGroup.getTransform(currXform);
255:
256: Matrix4d mat = new Matrix4d();
257: // Remember old matrix
258: currXform.get(mat);
259:
260: // Translate to origin
261: currXform
262: .setTranslation(new Vector3d(0.0, 0.0, 0.0));
263: if (invert) {
264: currXform.mul(currXform, transformX);
265: currXform.mul(currXform, transformY);
266: } else {
267: currXform.mul(transformX, currXform);
268: currXform.mul(transformY, currXform);
269: }
270:
271: // Set old translation back
272: Vector3d translation = new Vector3d(mat.m03,
273: mat.m13, mat.m23);
274: currXform.setTranslation(translation);
275:
276: // Update xform
277: transformGroup.setTransform(currXform);
278:
279: transformChanged(currXform);
280:
281: if (callback != null)
282: callback
283: .transformChanged(
284: MouseBehaviorCallback.ROTATE,
285: currXform);
286: } else {
287: reset = false;
288: }
289:
290: x_last = x;
291: y_last = y;
292: } else if (id == MouseEvent.MOUSE_PRESSED) {
293: x_last = evt.getX();
294: y_last = evt.getY();
295: }
296: }
297: }
298:
299: /**
300: * Users can overload this method which is called every time
301: * the Behavior updates the transform
302: *
303: * Default implementation does nothing
304: */
305: public void transformChanged(Transform3D transform) {
306: }
307:
308: /**
309: * The transformChanged method in the callback class will
310: * be called every time the transform is updated
311: */
312: public void setupCallback(MouseBehaviorCallback callback) {
313: this.callback = callback;
314: }
315: }
|