/* -*- tab-width: 4 -*-
*
* Electric(tm) VLSI Design System
*
* File: J3DKeyBehavior.java
* Written by Gilda Garreton, Sun Microsystems.
*
* Copyright (c) 2005 Sun Microsystems and Static Free Software
*
* Electric(tm) is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* Electric(tm) 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Electric(tm); see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
* Boston, Mass 02111-1307, USA.
*/
package com.sun.electric.plugins.j3d;
import java.awt.AWTEvent;
import java.awt.event.*;
import java.util.Enumeration;
import java.util.Arrays;
import javax.media.j3d.*;
import javax.vecmath.*;
/** Inspired in example found in Daniel Selman's book "Java 3D Programming"
* For more information about the original example, contact Daniel Selman: daniel@selman.org
* Free Software Foundation, Inc.,
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
* @author Gilda Garreton
* @version 0.1
*/
public class J3DKeyBehavior extends Behavior
{
protected static final double FAST_SPEED = 10.0;
protected static final double NORMAL_SPEED = 1.0;
protected TransformGroup tGroup; /* Contains main scene*/
protected Transform3D transform;
protected WakeupCondition keyCriterion;
private double delta = 5;
private double rotateAmount = Math.PI / 10.0;
private double speed = NORMAL_SPEED;
private int forwardKey = KeyEvent.VK_UP;
private int backKey = KeyEvent.VK_DOWN;
private int leftKey = KeyEvent.VK_LEFT;
private int rightKey = KeyEvent.VK_RIGHT;
public J3DKeyBehavior(TransformGroup tg)
{
super();
tGroup = tg;
transform = new Transform3D();
}
public void initialize()
{
WakeupCriterion[] keyEvents = new WakeupCriterion[2];
keyEvents[0] = new WakeupOnAWTEvent(KeyEvent.KEY_PRESSED);
keyEvents[1] = new WakeupOnAWTEvent(KeyEvent.KEY_RELEASED);
keyCriterion = new WakeupOr(keyEvents);
wakeupOn(keyCriterion);
}
public void processStimulus(Enumeration criteria)
{
WakeupCriterion wakeup;
AWTEvent[] event;
while(criteria.hasMoreElements( ))
{
wakeup = (WakeupCriterion) criteria.nextElement( );
if( !(wakeup instanceof WakeupOnAWTEvent) )
continue;
event = ((WakeupOnAWTEvent)wakeup).getAWTEvent( );
for( int i = 0; i < event.length; i++ )
{
if( event[i].getID( ) == KeyEvent.KEY_PRESSED )
processKeyEvent((KeyEvent)event[i]);
}
}
wakeupOn( keyCriterion );
}
protected void processKeyEvent(KeyEvent event)
{
int keycode = event.getKeyCode();
if(event.isShiftDown())
speed = FAST_SPEED;
else
speed = NORMAL_SPEED;
if( event.isAltDown())
altMove(keycode);
else if(event.isControlDown())
controlMove(keycode );
else
standardMove(keycode);
}
//moves forward backward or rotates left right
private void standardMove(int keycode)
{
if(keycode == forwardKey)
moveAlongAxis(Z, 1);
else if(keycode == backKey)
moveAlongAxis(Z, -1);
else if(keycode == leftKey)
rotateAlongAxis(Y, 1);
else if(keycode == rightKey)
rotateAlongAxis(Y, -1);
}
//moves left right, rotate up down
protected void altMove(int keycode)
{
if(keycode == forwardKey)
rotateAlongAxis(X, 1);
else if(keycode == backKey)
rotateAlongAxis(X, -1);
else if(keycode == leftKey)
moveAlongAxis(X, -1);
else if(keycode == rightKey)
moveAlongAxis(X, 1);
}
//move up down, rot left right
protected void controlMove(int keycode)
{
if(keycode == forwardKey)
moveAlongAxis(Y, 1);
else if(keycode == backKey)
moveAlongAxis(Y, -1);
else if(keycode == leftKey)
rotateAlongAxis(Z, 1);
else if(keycode == rightKey)
rotateAlongAxis(Z, -1);
}
private static double[] values = new double[3];
private static Vector3d move = new Vector3d();
/**
* Method to shift along axis in direction provided
* @param axis
* @param dir
*/
public void moveAlongAxis(int axis, int dir)
{
Arrays.fill(values, 0);
values[axis] = dir * getMovementRate();
move.set(values);
// If move gets a collision, then move back
if (!doMove(move, false))
{
values[axis] = -dir * getMovementRate();
move.set(values);
doMove(move, true);
}
}
/**
* Method to rotate along given axis and direction provided
* @param axis
* @param dir
*/
protected void rotateAlongAxis(int axis, int dir)
{
double radian = rotateAmount * speed;
// in case of collision, move the opposite direction
if (!rotate(axis, dir * radian, false))
rotate(axis, -dir * radian, true);
}
protected boolean updateTransform(boolean force)
{
tGroup.setTransform(transform);
return true;
}
private static final int X = 0;
private static final int Y = 1;
private static final int Z = 2;
/**
* Method to set the original rotation
* @param rotVals
*/
public void setHomeRotation(double[] rotVals)
{
for (int i = 0; i < rotVals.length; i++)
rotate(i, rotVals[i], true);
}
/**
* Method that rotates along given axis
* @param axis
* @param radians
* @return True if there was no collision
*/
protected boolean rotate(int axis, double radians, boolean force)
{
tGroup.getTransform(transform);
Transform3D toMove = new Transform3D();
switch(axis)
{
case X:
toMove.rotX(radians);
break;
case Y:
toMove.rotY(radians);
break;
case Z:
toMove.rotZ(radians);
break;
}
transform.mul(toMove);
// Need to move in opposite direction to avoid collision
boolean noCollision = updateTransform(force);
return (noCollision);
}
void zoomInOut(boolean out)
{
double z_factor = 0.7;//Math.abs(0.7);
//double factor = (out) ? (0.5/z_factor) : (2*z_factor);
double factor = (out) ? (1/z_factor) : (z_factor);
// Remember old matrix
tGroup.getTransform(transform);
Matrix4d mat = new Matrix4d();
transform.get(mat);
double dy = transform.getScale() * factor;
transform.setScale(dy);
tGroup.setTransform(transform);
}
private static Transform3D toMove = new Transform3D();
private boolean doMove(Vector3d theMove, boolean force)
{
tGroup.getTransform(transform);
toMove.setIdentity();
toMove.setTranslation(theMove);
transform.mul(toMove);
return updateTransform(force);
}
protected double getMovementRate()
{
return delta * speed;
}
}