I have managed to make an extremely simple example that replicates our issue. I am posting code that simply outputs the cursor position as it is moved through the 3D context. When using JME 3.1 or greater, cursor position falls to 0 before reaching the bottom of the viewport. When using JME 3.0 cursor position is shown as expected through the full range of the viewport. The effect on user input is when there is no change in the y position (mouse is below the 0 point) no rotation or dragging occurs until the mouse moves back above 0.
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
import com.jme3.system.AppSettings;
import com.jme3.system.JmeCanvasContext;
import com.jme3.util.JmeFormatter;
import java.awt.Canvas;
import java.awt.Dimension;
import java.awt.Toolkit;
import java.util.logging.ConsoleHandler;
import java.util.logging.Handler;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JFrame;
import javax.swing.JPopupMenu;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
/**
*
* @author dmorgan
*/
public class JMEMouseTest extends JFrame
{
private static JmeCanvasContext context;
// private static JmeCanvasContext context2;
private static Canvas canvas;
// private static Canvas canvas2;
private static MouseTest_SimpleApp mouseTestApp;
public JMEMouseTest()
{
this.add(canvas);
setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
}
/**
* @param args the command line arguments
*/
public static void main(String args[])
{
String arg = "true";
if (args.length > 0)
{
arg = args[0];
}
final String flag = arg;
JmeFormatter formatter = new JmeFormatter();
Handler consoleHandler = new ConsoleHandler();
consoleHandler.setFormatter(formatter);
Logger.getLogger("").removeHandler(Logger.getLogger("").getHandlers()[0]);
Logger.getLogger("").addHandler(consoleHandler);
SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
// switch to system l&f for native font rendering etc.
try
{
UIManager.setLookAndFeel("com.sun.java.swing.plaf.nimbus.NimbusLookAndFeel");
} catch (Exception ex)
{
Logger.getLogger(getClass().getName()).log(Level.INFO, "can not enable system look and feel", ex);
}
JPopupMenu.setDefaultLightWeightPopupEnabled(false);
JMEMouseTest frame = new JMEMouseTest();
frame.initFrameSize();
frame.setVisible(true);
}
});
createCanvas();
}
public static void createCanvas()
{
AppSettings settings = new AppSettings(true);
settings.setWidth(1300);
settings.setHeight(860);
mouseTestApp = new MouseTest_SimpleApp();
mouseTestApp.setPauseOnLostFocus(false);
mouseTestApp.setSettings(settings);
mouseTestApp.createCanvas();
context = (JmeCanvasContext) mouseTestApp.getContext();
canvas = context.getCanvas();
}
public void initFrameSize()
{
Toolkit tk = Toolkit.getDefaultToolkit();
Dimension d1 = tk.getScreenSize();
int height = d1.height;
int width = d1.width;
final Dimension d = new Dimension(width, height);
final int numerator = 9;
final int denominator = 10;
setSize(d.width * numerator / denominator, d.height * (numerator) / denominator);
setLocationRelativeTo(null);
}
}
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
import com.jme3.app.SimpleApplication;
import com.jme3.app.state.AppStateManager;
import com.jme3.font.BitmapFont;
import com.jme3.font.BitmapText;
import com.jme3.input.MouseInput;
import com.jme3.input.controls.ActionListener;
import com.jme3.input.controls.AnalogListener;
import com.jme3.input.controls.MouseAxisTrigger;
import com.jme3.input.controls.MouseButtonTrigger;
import com.jme3.math.ColorRGBA;
import com.jme3.math.Quaternion;
import com.jme3.math.Vector2f;
import com.jme3.math.Vector3f;
import com.jme3.renderer.RenderManager;
import com.jme3.scene.Node;
import com.jme3.scene.Spatial;
import com.petrabytes.volume.ui.viewstates.AxisPointer_ViewState;
/**
*
* @author dmorgan
*/
public class MouseTest_SimpleApp extends SimpleApplication
{
protected float zoom = 1f;
protected float zoomFactor = 1.2f;
protected boolean mouseRButtonDown = false;
protected boolean mouseLButtonDown = false;
protected boolean mouseMoving = false;
protected boolean z_rotate = false;
protected boolean y_rotate = false;
protected boolean x_rotate = false;
private final static float TRANS_SPEED = 5f;
private final static float ROTATE_SPEED = 10f;
private Node main = new Node("Main");
private Node axis = new Node("Axis");
// private Node gridAxis = new Node("GridAxis");
// private AxisPointer_ViewState axisPointer;
private AppStateManager appStateManager;
public MouseTest_SimpleApp()
{
main.setCullHint(Spatial.CullHint.Never);
// gridAxis.setCullHint(Spatial.CullHint.Never);
rootNode.attachChild(main);
rootNode.attachChild(axis);
}
@Override
public void simpleInitApp()
{
appStateManager = new AppStateManager(this);
// axisPointer = new AxisPointer_ViewState(this);
//
// appStateManager.attach(axisPointer);
appStateManager.update(speed);
flyCam.setEnabled(false);
inputManager.clearMappings();
_setupInputs();
this.viewPort.setBackgroundColor(ColorRGBA.White);
System.out.println("Completed initializing 3D graphics engine.");
}
private void _setupInputs()
{
if (inputManager.hasMapping("Right Mouse Button"))
{
inputManager.clearMappings();
}
inputManager.addMapping("Right Mouse Button",
new MouseButtonTrigger(MouseInput.BUTTON_RIGHT));
inputManager.addMapping("Left Mouse Button",
new MouseButtonTrigger(MouseInput.BUTTON_LEFT));
inputManager.addMapping("Zoom In",
new MouseAxisTrigger(MouseInput.AXIS_WHEEL, false));
inputManager.addMapping("Zoom Out",
new MouseAxisTrigger(MouseInput.AXIS_WHEEL, true));
inputManager.addMapping("Move Right",
new MouseAxisTrigger(MouseInput.AXIS_X, true));
inputManager.addMapping("Move Left",
new MouseAxisTrigger(MouseInput.AXIS_X, false));
inputManager.addMapping("Move Up",
new MouseAxisTrigger(MouseInput.AXIS_Y, false));
inputManager.addMapping("Move Down",
new MouseAxisTrigger(MouseInput.AXIS_Y, true));
inputManager.addMapping("RotateRight",
new MouseAxisTrigger(MouseInput.AXIS_X, true));
inputManager.addMapping("RotateLeft",
new MouseAxisTrigger(MouseInput.AXIS_X, false));
inputManager.addMapping("RotateUp",
new MouseAxisTrigger(MouseInput.AXIS_Y, false));
inputManager.addMapping("RotateDown",
new MouseAxisTrigger(MouseInput.AXIS_Y, true));
inputManager.addListener(analogListener, "RotateUp", "RotateDown", "RotateRight", "RotateLeft", "Zoom In", "Zoom Out",
"Move Right", "Move Left", "Move Up", "Move Down");
inputManager.addListener(actionListener, "Right Mouse Button", "Left Mouse Button");
}
private ActionListener actionListener = new ActionListener()
{
public void onAction(String name, boolean keyPressed, float tpf)
{
if (name.equals("Right Mouse Button"))
{
mouseRButtonDown = keyPressed;
}
if (name.equals("Left Mouse Button"))
{
mouseLButtonDown = keyPressed;
if (!keyPressed)
{
_leftMouseClick();
}
}
}
};
private void _leftMouseClick()
{
}
private AnalogListener analogListener = new AnalogListener()
{
public void onAnalog(String name, float value, float tpf)
{
if (mouseLButtonDown)
{
mouseMoving = true;
if (name.equals("RotateUp"))
{
mouseRotateUD(value);
} else if (name.equals("RotateDown"))
{
mouseRotateUD(-value);
}
if (name.equals("RotateRight"))
{
mouseRotateRL(-value);
} else if (name.equals("RotateLeft"))
{
mouseRotateRL(value);
}
}
if (mouseRButtonDown)
{
if (name.equals("Move Right"))
{
mouseDragRL(-value);
}
if (name.equals("Move Left"))
{
mouseDragRL(value);
}
if (name.equals("Move Up"))
{
mouseDragUD(-value);
}
if (name.equals("Move Down"))
{
mouseDragUD(value);
}
}
if (name.equals("Zoom In"))
{
mouseZoomIn();
}
if (name.equals("Zoom Out"))
{
mouseZoomOut();
}
if (name.equals("Move Right") || name.equals("Move Left") || name.equals("Move Up") || name.equals("Move Down"))
{
_updateMousePositionText();
}
}
};
private void _updateMousePositionText()
{
Vector2f pos = inputManager.getCursorPosition();
Node curseNode = (Node) guiNode.getChild("Cursor Node");
if (curseNode == null)
{
curseNode = new Node("Cursor Node");
BitmapFont myFont = assetManager.loadFont("Interface/Fonts/Console.fnt");
BitmapText hudText = new BitmapText(myFont, false);
hudText.setSize(myFont.getCharSet().getRenderedSize()); // font size
hudText.setColor(ColorRGBA.Blue);
hudText.setText("Cursor position: " + pos.toString());
hudText.setName("Cursor Label");
hudText.setLocalTranslation(20, hudText.getLineHeight() - 22, 0);
curseNode.move(800, 25, 0);
curseNode.attachChild(hudText);
guiNode.attachChild(curseNode);
} else
{
BitmapText hudText = (BitmapText) curseNode.getChild("Cursor Label");
String text = "Cursor position: " + pos.toString();
hudText.setText(text);
}
}
private void mouseDragRL(float val)
{
Vector3f v = new Vector3f(cam.getLocation().x + -val * TRANS_SPEED, cam.getLocation().y, cam.getLocation().z);
Vector3f v2 = new Vector3f(val * TRANS_SPEED, 0f, 0f);
cam.setLocation(v);
// this.axisPointer.drag(v2.negate());
}
private void mouseDragUD(float val)
{
Vector3f v = new Vector3f(cam.getLocation().x, cam.getLocation().y + val * TRANS_SPEED, cam.getLocation().z);
Vector3f v2 = new Vector3f(0f, -val * TRANS_SPEED, 0f);
cam.setLocation(v);
// this.axisPointer.drag(v2.negate());
}
private void mouseZoomIn()
{
}
private void mouseZoomOut()
{
}
public float getZoom()
{
return zoom;
}
private void mouseRotateUD(float val)
{
Vector3f localVector = new Vector3f();
Quaternion mouse_quat = new Quaternion();
Node n = (Node) this.viewPort.getScenes().get(0);
if (n.getChild("Main") == null)
{
return;
}
n.getChild("Main").worldToLocal(Vector3f.UNIT_X, localVector);
Quaternion rotation = mouse_quat.fromAngleAxis(-val * this.ROTATE_SPEED, localVector);
n.getChild("Main").rotate(rotation);
if (n.getName().equals("Root Node"))
{
// this.axisPointer.rotatePointerUD(-val * this.ROTATE_SPEED);
}
n.updateGeometricState();
}
private void mouseRotateRL(float val)
{
Vector3f localVector = new Vector3f();
Quaternion mouse_quat = new Quaternion();
Node n = (Node) this.viewPort.getScenes().get(0);
if (n.getChild("Main") == null)
{
return;
}
n.getChild("Main").worldToLocal(Vector3f.UNIT_Y, localVector);
Quaternion rotation = mouse_quat.fromAngleAxis(val * this.ROTATE_SPEED, localVector);
n.getChild("Main").rotate(rotation);
if (n.getName().equals("Root Node"))
{
// this.axisPointer.rotatePointerLR(-val * this.ROTATE_SPEED);
}
n.updateGeometricState();
}
private void setRotation(Quaternion q)
{
main.setLocalRotation(q);
// axisPointer.setRotation(q);
}
public void rotateRight()
{
float deg90 = (float) Math.toRadians(-90);
Quaternion rotate = new Quaternion();
rotate.fromAngleAxis(deg90, new Vector3f(0f, 1f, 0f));
setRotation(rotate);
}
public void rotateLeft()
{
float deg90 = (float) Math.toRadians(90);
Quaternion rotate = new Quaternion();
rotate.fromAngleAxis(deg90, new Vector3f(0f, 1f, 0f));
setRotation(rotate);
}
public void rotateUp()
{
setRotation(Quaternion.IDENTITY.inverse());
}
public void rotateDown()
{
float deg90 = (float) Math.toRadians(180);
Quaternion rotate = new Quaternion();
rotate.fromAngleAxis(deg90, new Vector3f(1f, 0f, 0f));
setRotation(rotate);
}
public void rotateFront()
{
float deg90 = (float) Math.toRadians(-90);
Quaternion rotate = new Quaternion();
rotate.fromAngleAxis(deg90, new Vector3f(1f, 0f, 0f));
setRotation(rotate);
}
public void rotateBack()
{
float deg90 = (float) Math.toRadians(180);
Quaternion rotate = new Quaternion();
rotate.fromAngleAxis(deg90, new Vector3f(0f, 1f, 1f));
setRotation(rotate);
}
public void rotateNiceView()
{
rotateFront();
Vector3f localVector = new Vector3f();
float deg45 = (float) Math.toRadians(-45);
Quaternion mouse_quat = new Quaternion();
Node n = (Node) this.viewPort.getScenes().get(0);
n.getChild("Main").worldToLocal(Vector3f.UNIT_Y, localVector);
Quaternion rotation = mouse_quat.fromAngleAxis(deg45, localVector);
n.getChild("Main").rotate(rotation);
if (n.getName().equals("Root Node"))
{
// this.axisPointer.rotatePointerLR(-deg45);
}
n.updateGeometricState();
}
@Override
public void simpleRender(RenderManager rm)
{
}
public boolean isMouseRButtonDown()
{
return mouseRButtonDown;
}
public boolean isMouseLButtonDown()
{
return mouseLButtonDown;
}
public boolean isZrotate()
{
return z_rotate;
}
public void setZrotate(boolean z_rotate)
{
this.z_rotate = z_rotate;
}
public boolean isYrotate()
{
return y_rotate;
}
public void setYrotate(boolean y_rotate)
{
this.y_rotate = y_rotate;
}
public boolean isXrotate()
{
return x_rotate;
}
public void setXrotate(boolean x_rotate)
{
this.x_rotate = x_rotate;
}
public AxisPointer_ViewState getAxisPointer()
{
return null;
// return axisPointer;
}
@Override
public void simpleUpdate(float tpf)
{
if (cam.isViewportChanged())
{
// this.axisPointer.setResetPos(true);
// axisPointer.update(30);
}
}
}