Hi,
I was looking for virtual trackball or arcball like this: http://viewport3d.com/trackball.htm or this: http://www.cs.sunysb.edu/~mueller/teaching/cse564/trackball.ppt. So, I modified JMESwingTest from the tutorial. With the mouse and the left mouse button pressed, you can move around the box and with the key "+" and "-", you can zoom. The graphics are in the MyImplementor class.
import java.awt.AWTEvent;
import java.awt.BorderLayout;
import java.awt.Canvas;
import java.awt.EventQueue;
import java.awt.GraphicsDevice;
import java.awt.GraphicsEnvironment;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.util.concurrent.Callable;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JColorChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTree;
import javax.swing.UIManager;
import org.lwjgl.opengl.DisplayMode;
import com.jme.bounding.BoundingBox;
import com.jme.image.Texture;
import com.jme.input.AbsoluteMouse;
import com.jme.input.InputHandler;
import com.jme.input.KeyBindingManager;
import com.jme.input.KeyInput;
import com.jme.input.MouseInput;
import com.jme.input.action.InputAction;
import com.jme.input.action.InputActionEvent;
import com.jme.math.FastMath;
import com.jme.math.Matrix3f;
import com.jme.math.Quaternion;
import com.jme.math.Vector2f;
import com.jme.math.Vector3f;
import com.jme.renderer.Renderer;
import com.jme.scene.CameraNode;
import com.jme.scene.Node;
import com.jme.scene.shape.Box;
import com.jme.scene.state.TextureState;
import com.jme.system.DisplaySystem;
import com.jme.util.GameTaskQueueManager;
import com.jme.util.TextureManager;
import com.jmex.awt.JMECanvas;
import com.jmex.awt.JMECanvasImplementor;
import com.jmex.awt.SimpleCanvasImpl;
import com.jmex.awt.input.AWTMouseInput;
public class JMESwingTest {
private static final Logger logger = Logger.getLogger(JMESwingTest.class
.getName());
int width = 640, height = 480;
// Swing frame
private SwingFrame frame;
public JMESwingTest() {
frame = new SwingFrame();
// center the frame
frame.setLocationRelativeTo(null);
// show frame
frame.setVisible(true);
}
/**
* Main Entry point...
*
* @param args
* String[]
*/
public static void main(String[] args) {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (Exception e) {
logger.logp(Level.SEVERE, JMESwingTest.class.toString(),
"main(args)", "Exception", e);
}
new JMESwingTest();
}
// **************** SWING FRAME ****************
// Our custom Swing frame... Nothing really special here.
class SwingFrame extends JFrame {
private static final long serialVersionUID = 1L;
JPanel contentPane;
JPanel mainPanel = new JPanel();
Canvas comp = null;
JButton coolButton = new JButton();
JButton uncoolButton = new JButton();
JPanel spPanel = new JPanel();
JScrollPane scrollPane = new JScrollPane();
JTree jTree1 = new JTree();
JCheckBox scaleBox = new JCheckBox("Scale GL Image");
JPanel colorPanel = new JPanel();
JLabel colorLabel = new JLabel("BG Color:");
MyImplementor impl;
// Construct the frame
public SwingFrame() {
addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
dispose();
}
});
init();
pack();
// MAKE SURE YOU REPAINT SOMEHOW OR YOU WON'T SEE THE UPDATES...
new Thread() {
{
setDaemon(true);
}
public void run() {
while (true) {
comp.repaint();
try {
Thread.sleep(1);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}// yield();
}
}
}.start();
}
// Component initialization
private void init() {
contentPane = (JPanel) this.getContentPane();
contentPane.setLayout(new BorderLayout());
mainPanel.setLayout(new GridBagLayout());
setTitle("JME - SWING INTEGRATION TEST");
coolButton.setText("Cool Button");
uncoolButton.setText("Uncool Button");
colorPanel.setBackground(java.awt.Color.black);
colorPanel.setToolTipText("Click here to change Panel BG color.");
colorPanel.setBorder(BorderFactory.createRaisedBevelBorder());
colorPanel.addMouseListener(new java.awt.event.MouseAdapter() {
public void mouseClicked(MouseEvent e) {
final java.awt.Color color = JColorChooser.showDialog(
SwingFrame.this, "Choose new background color:",
colorPanel.getBackground());
if (color == null)
return;
colorPanel.setBackground(color);
Callable<?> call = new Callable<Object>() {
public Object call() throws Exception {
comp.setBackground(color);
return null;
}
};
GameTaskQueueManager.getManager().render(call);
}
});
scaleBox.setOpaque(false);
scaleBox.setSelected(true);
scaleBox.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
if (comp != null)
doResize();
}
});
spPanel.setLayout(new BorderLayout());
contentPane.add(mainPanel, BorderLayout.WEST);
mainPanel.add(scaleBox,
new GridBagConstraints(0, 0, 1, 1, 0.0, 0.0,
GridBagConstraints.CENTER,
GridBagConstraints.HORIZONTAL, new Insets(5, 5, 0,
5), 0, 0));
mainPanel.add(colorLabel,
new GridBagConstraints(0, 1, 1, 1, 0.0, 0.0,
GridBagConstraints.CENTER,
GridBagConstraints.HORIZONTAL, new Insets(5, 5, 0,
5), 0, 0));
mainPanel.add(colorPanel, new GridBagConstraints(0, 2, 1, 1, 0.0,
0.0, GridBagConstraints.CENTER, GridBagConstraints.NONE,
new Insets(5, 5, 0, 5), 25, 25));
mainPanel.add(coolButton,
new GridBagConstraints(0, 3, 1, 1, 0.0, 0.0,
GridBagConstraints.CENTER,
GridBagConstraints.HORIZONTAL, new Insets(5, 5, 0,
5), 0, 0));
mainPanel.add(uncoolButton,
new GridBagConstraints(0, 4, 1, 1, 0.0, 0.0,
GridBagConstraints.CENTER,
GridBagConstraints.HORIZONTAL, new Insets(5, 5, 0,
5), 0, 0));
mainPanel.add(spPanel, new GridBagConstraints(0, 5, 1, 1, 1.0, 1.0,
GridBagConstraints.CENTER, GridBagConstraints.BOTH,
new Insets(5, 5, 0, 5), 0, 0));
spPanel.add(scrollPane, BorderLayout.CENTER);
scrollPane.setViewportView(jTree1);
//
GL STUFF
// make the canvas:
comp = DisplaySystem.getDisplaySystem("lwjgl").createCanvas(width,
height);
// add a listener... if window is resized, we can do something about
// it.
comp.addComponentListener(new ComponentAdapter() {
public void componentResized(ComponentEvent ce) {
doResize();
}
});
KeyInput.setProvider(KeyInput.INPUT_AWT);
AWTMouseInput.setup(comp, false);
GraphicsEnvironment env = GraphicsEnvironment
.getLocalGraphicsEnvironment();
GraphicsDevice gd = env.getDefaultScreenDevice();
java.awt.DisplayMode dm = gd.getDisplayMode();
// Important! Here is where we add the guts to the panel:
impl = new MyImplementor(width, height);
JMECanvas jmeCanvas = ((JMECanvas) comp);
jmeCanvas.setImplementor(impl);
jmeCanvas.setUpdateInput(true);
//
END OF GL STUFF
comp.setBounds(0, 0, width, height);
contentPane.add(comp, BorderLayout.CENTER);
Toolkit.getDefaultToolkit().getSystemEventQueue().push(
new EventQueue(){
protected void dispatchEvent(AWTEvent event) {
if (event instanceof KeyEvent) {
KeyEvent keyEvent = (KeyEvent) event;
if (keyEvent.getID() == KeyEvent.KEY_TYPED){
if(keyEvent.getKeyChar()=='+'){
impl.scalePlus();
}else if(keyEvent.getKeyChar()=='-'){
impl.scaleMinus();
}
}
}
super.dispatchEvent(event);
}
});
}
protected void doResize() {
if (scaleBox != null && scaleBox.isSelected()) {
impl.resizeCanvas(comp.getWidth(), comp.getHeight());
} else {
impl.resizeCanvas(width, height);
}
}
// Overridden so we can exit when window is closed
protected void processWindowEvent(WindowEvent e) {
super.processWindowEvent(e);
if (e.getID() == WindowEvent.WINDOW_CLOSING) {
System.exit(0);
}
}
}
// IMPLEMENTING THE SCENE:
public class MyImplementor extends SimpleCanvasImpl {
private Quaternion rotQuat, rotQuat2;
private Vector3f oCamTranslation;
private CameraNode oCamNode;
private Box box;
private boolean pressed = false;
AbsoluteMouse am;
private float scale=0;
private int oldX, oldY, newX, newY;
public MyImplementor(int width, int height) {
super(width, height);
}
public void scalePlus(){
scale-=0.05f;
if(scale<-0.25f)scale=-0.25f;
}
public void scaleMinus(){
scale+=0.05f;
if(scale>3)scale=3;
}
public void simpleSetup() {
am = new AbsoluteMouse("The Mouse", width, height);
// Normal Scene setup stuff...
rotQuat = new Quaternion();
rotQuat2 = new Quaternion();
oCamNode = new CameraNode( "Camera Node", this.getCamera());
Vector3f max = new Vector3f(5, 5, 5);
Vector3f min = new Vector3f(-5, -5, -5);
box = new Box("Box", min, max);
rootNode.attachChild(box);
rootNode.attachChild(oCamNode);
box.setRandomColors();
oCamTranslation=new Vector3f(0,0,-20);
oCamNode.setLocalTranslation(oCamTranslation);
oCamNode.lookAt(box.getLocalTranslation(), new Vector3f(0,1,0));
box.setModelBound(new BoundingBox());
box.updateModelBound();
rotQuat2=oCamNode.getLocalRotation();
}
private Vector3f trackBallMapping(int px, int py) {
float x = (2 * (float) px) / width - 1;
float y = (2 * (float) py) / height -1;
float z2 = 1 - x * x - y * y;
float z = z2 > 0 ? FastMath.sqrt(z2) : 0;
return new Vector3f(x, y, z);
}
public void simpleUpdate() {
if (MouseInput.get().isButtonDown(0)) {
if (!pressed) {
pressed = true;
oldX = MouseInput.get().getXAbsolute();
oldY = MouseInput.get().getYAbsolute();
}
newX=MouseInput.get().getXAbsolute();
newY=MouseInput.get().getYAbsolute();
Vector3f oLastVector3f = this.trackBallMapping(oldX, oldY);
Vector3f oNewVector3f = this.trackBallMapping(newX, newY);
Vector3f oAxisVector = oLastVector3f.cross(oNewVector3f);
Vector2f oVector2f=new Vector2f(newX-oldX,newY-oldY);
float tAngle = oVector2f.length();
rotQuat.fromAngleAxis(-tAngle*FastMath.DEG_TO_RAD,oAxisVector);
rotQuat2.multLocal(rotQuat);
oCamNode.setLocalTranslation(rotQuat2.mult(oCamTranslation).mult(FastMath.exp(scale)));
oCamNode.setLocalRotation(rotQuat2);
oldX=newX;
oldY=newY;
} else {
if (pressed) {
pressed = false;
}
oCamNode.setLocalTranslation(rotQuat2.mult(oCamTranslation).mult(FastMath.exp(scale)));
}
}
}
Best,
Andreas