001    /*
002     * $RCSfile: MouseRotate.java,v $
003     *
004     * Copyright (c) 2004 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.1 $
041     * $Date: 2004/06/09 04:10:24 $
042     * $State: Exp $
043     */
044    
045    package com.appearance3Dchooser;
046    
047    import java.awt.*;
048    import java.awt.event.*;
049    import java.util.*;
050    
051    import com.sun.j3d.utils.behaviors.mouse.*;
052    import javax.media.j3d.*;
053    import javax.vecmath.*;
054    
055    /**
056     * MouseRotate is a Java3D behavior object that lets users control the
057     * rotation of an object via a mouse.
058     * <p>
059     * To use this utility, first create a transform group that this
060     * rotate behavior will operate on. Then,
061     *<blockquote><pre>
062     *
063     *   MouseRotate behavior = new MouseRotate();
064     *   behavior.setTransformGroup(objTrans);
065     *   objTrans.addChild(behavior);
066     *   behavior.setSchedulingBounds(bounds);
067     *
068     *</pre></blockquote>
069     * The above code will add the rotate behavior to the transform
070     * group. The user can rotate any object attached to the objTrans.
071     */
072    
073    public class CustomMouseRotate extends MouseRotate {
074        double x_angle, y_angle;
075        double x_factor = .03;
076        double y_factor = .03;
077    
078        private MouseBehaviorCallback callback = null;
079    
080        private Canvas3D haut, droite, gauche, face, big = null;
081    
082        // Definit une rotation autour de l'axe Z (repere absolu)
083        private Transform3D transformZ = null;
084    
085        /**
086         * Creates a rotate behavior given the transform group.
087         * @param transformGroup The transformGroup to operate on.
088         */
089        public CustomMouseRotate(TransformGroup transformGroup,
090                                 Canvas3D haut, Canvas3D droite,
091                                 Canvas3D gauche, Canvas3D face,
092                                 Canvas3D big
093                                 ) {
094          super(transformGroup);
095          this.haut   = haut;
096          this.droite = droite;
097          this.gauche = gauche;
098          this.face   =  face;
099          this.big   =  big;
100    
101          transformZ = new Transform3D();
102        }
103    
104        /**
105         * Creates a default mouse rotate behavior.
106         **/
107        public CustomMouseRotate() {
108            super(0);
109        }
110    
111        /**
112         * Creates a rotate behavior.
113         * Note that this behavior still needs a transform
114         * group to work on (use setTransformGroup(tg)) and
115         * the transform group must add this behavior.
116         * @param flags interesting flags (wakeup conditions).
117         */
118        public CustomMouseRotate(int flags) {
119            super(flags);
120        }
121    
122        /**
123         * Creates a rotate behavior that uses AWT listeners and behavior
124         * posts rather than WakeupOnAWTEvent.  The behavior is added to the
125         * specified Component. A null component can be passed to specify
126         * the behavior should use listeners.  Components can then be added
127         * to the behavior with the addListener(Component c) method.
128         * @param c The Component to add the MouseListener
129         * and MouseMotionListener to.
130         * @since Java 3D 1.2.1
131         */
132        public CustomMouseRotate(Component c) {
133            super(c, 0);
134        }
135    
136        /**
137         * Creates a rotate behavior that uses AWT listeners and behavior
138         * posts rather than WakeupOnAWTEvent.  The behaviors is added to
139         * the specified Component and works on the given TransformGroup.
140         * A null component can be passed to specify the behavior should use
141         * listeners.  Components can then be added to the behavior with the
142         * addListener(Component c) method.
143         * @param c The Component to add the MouseListener and
144         * MouseMotionListener to.
145         * @param transformGroup The TransformGroup to operate on.
146         * @since Java 3D 1.2.1
147         */
148        public CustomMouseRotate(Component c, TransformGroup transformGroup) {
149            super(c, transformGroup);
150        }
151    
152        /**
153         * Creates a rotate behavior that uses AWT listeners and behavior
154         * posts rather than WakeupOnAWTEvent.  The behavior is added to the
155         * specified Component.  A null component can be passed to specify
156         * the behavior should use listeners.  Components can then be added to
157         * the behavior with the addListener(Component c) method.
158         * Note that this behavior still needs a transform
159         * group to work on (use setTransformGroup(tg)) and the transform
160         * group must add this behavior.
161         * @param flags interesting flags (wakeup conditions).
162         * @since Java 3D 1.2.1
163         */
164        public CustomMouseRotate(Component c, int flags) {
165            super(c, flags);
166        }
167    
168        public void initialize() {
169            super.initialize();
170            x_angle = 0;
171            y_angle = 0;
172            if ((flags & INVERT_INPUT) == INVERT_INPUT) {
173                invert = true;
174                x_factor *= -1;
175                y_factor *= -1;
176            }
177        }
178    
179        /**
180         * Return the x-axis movement multipler.
181         **/
182        public double getXFactor() {
183            return x_factor;
184        }
185    
186        /**
187         * Return the y-axis movement multipler.
188         **/
189        public double getYFactor() {
190            return y_factor;
191        }
192    
193    
194        /**
195         * Set the x-axis amd y-axis movement multipler with factor.
196         **/
197        public void setFactor( double factor) {
198            x_factor = y_factor = factor;
199        }
200    
201        /**
202         * Set the x-axis amd y-axis movement multipler with xFactor and yFactor
203         * respectively.
204         **/
205        public void setFactor( double xFactor, double yFactor) {
206            x_factor = xFactor;
207            y_factor = yFactor;
208        }
209    
210        public void processStimulus (Enumeration criteria) {
211            WakeupCriterion wakeup;
212            AWTEvent[] events;
213            MouseEvent evt;
214    //      int id;
215    //      int dx, dy;
216    
217            while (criteria.hasMoreElements()) {
218                wakeup = (WakeupCriterion) criteria.nextElement();
219                if (wakeup instanceof WakeupOnAWTEvent) {
220                    events = ((WakeupOnAWTEvent)wakeup).getAWTEvent();
221                    if (events.length > 0) {
222                        evt = (MouseEvent) events[events.length-1];
223                        doProcess(evt);
224                    }
225                }
226    
227                else if (wakeup instanceof WakeupOnBehaviorPost) {
228                    while (true) {
229                        // access to the queue must be synchronized
230                        synchronized (mouseq) {
231                            if (mouseq.isEmpty()) break;
232                            evt = (MouseEvent)mouseq.remove(0);
233                            // consolidate MOUSE_DRAG events
234                            while ((evt.getID() == MouseEvent.MOUSE_DRAGGED) &&
235                                   !mouseq.isEmpty() &&
236                                   (((MouseEvent)mouseq.get(0)).getID() ==
237                                    MouseEvent.MOUSE_DRAGGED)) {
238                                evt = (MouseEvent)mouseq.remove(0);
239                            }
240                        }
241                        doProcess(evt);
242                    }
243                }
244    
245            }
246            wakeupOn (mouseCriterion);
247        }
248    
249        void doProcess(MouseEvent evt) {
250            int id;
251            int dx, dy;
252    
253            processMouseEvent(evt);
254            if (((buttonPress)&&((flags & MANUAL_WAKEUP) == 0)) ||
255                ((wakeUp)&&((flags & MANUAL_WAKEUP) != 0))) {
256                id = evt.getID();
257                if ((id == MouseEvent.MOUSE_DRAGGED) &&
258                    !evt.isMetaDown() && ! evt.isAltDown()){
259                    x = evt.getX();
260                    y = evt.getY();
261    
262                    dx = x - x_last;
263                    dy = y - y_last;
264    
265                    if (!reset){
266                        x_angle = dy * y_factor;
267                        y_angle = dx * x_factor;
268    
269                    // Transformations specifiques a chaque canvas 3D
270                    if (evt.getSource().equals(haut)) {
271                      transformX.rotX(x_angle);
272                      transformY.setIdentity();
273                      transformZ.rotZ(-y_angle);
274                    }
275                    else if (evt.getSource().equals(droite)) {
276                      transformX.setIdentity();
277                      transformY.rotY(y_angle);
278                      transformZ.rotZ(-x_angle);
279                    }
280                    else if (evt.getSource().equals(gauche)) {
281                      transformX.setIdentity();
282                      transformY.rotY(y_angle);
283                      transformZ.rotZ(x_angle);
284                    }
285                    else if (evt.getSource().equals(face)) {
286                      transformX.rotX(x_angle);
287                      transformY.rotY(y_angle);
288                      transformZ.setIdentity();
289                    }
290                    else if (evt.getSource().equals(big)) {
291                        transformX.rotX(x_angle);
292                        transformY.rotY(y_angle);
293                        transformZ.setIdentity();
294                    }
295    
296                    transformGroup.getTransform(currXform);
297    
298                    Matrix4d mat = new Matrix4d();
299                    // Remember old matrix
300                    currXform.get(mat);
301    
302                    // Translate to origin
303                    currXform.setTranslation(new Vector3d(0.0,0.0,0.0));
304                    if (invert) {
305                      currXform.mul(currXform, transformX);
306                      currXform.mul(currXform, transformY);
307                      currXform.mul(currXform, transformZ);
308                    } else {
309                      currXform.mul(transformX, currXform);
310                      currXform.mul(transformY, currXform);
311                      currXform.mul(transformZ, currXform);
312                    }
313    
314                        // Set old translation back
315                        Vector3d translation = new
316                            Vector3d(mat.m03, mat.m13, mat.m23);
317                        currXform.setTranslation(translation);
318    
319                        // Update xform
320                        transformGroup.setTransform(currXform);
321    
322                        transformChanged( currXform );
323    
324                        if (callback!=null)
325                            callback.transformChanged( MouseBehaviorCallback.ROTATE,
326                                                       currXform );
327                    }
328                    else {
329                        reset = false;
330                    }
331    
332                    x_last = x;
333                    y_last = y;
334                }
335                else if (id == MouseEvent.MOUSE_PRESSED) {
336                    x_last = evt.getX();
337                    y_last = evt.getY();
338                }
339            }
340        }
341    
342        /**
343         * Users can overload this method  which is called every time
344         * the Behavior updates the transform
345         *
346         * Default implementation does nothing
347         */
348        public void transformChanged( Transform3D transform ) {
349        }
350    
351    
352        /**
353         * The transformChanged method in the callback class will
354         * be called every time the transform is updated
355         */
356        public void setupCallback( MouseBehaviorCallback callback ) {
357            this.callback = callback;
358        }
359    }