You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
356 lines
15 KiB
356 lines
15 KiB
/*
|
|
* 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.
|
|
*/
|
|
package com.jme3.input.vr;
|
|
|
|
import java.util.logging.Logger;
|
|
|
|
import com.jme3.app.VREnvironment;
|
|
import com.jme3.math.Quaternion;
|
|
import com.jme3.math.Vector2f;
|
|
import com.jme3.math.Vector3f;
|
|
import com.jme3.renderer.Camera;
|
|
import com.jme3.scene.Spatial;
|
|
import com.jme3.system.osvr.osvrclientkit.OsvrClientKitLibrary;
|
|
import com.jme3.system.osvr.osvrclientkit.OsvrClientKitLibrary.OSVR_ClientInterface;
|
|
import com.jme3.system.osvr.osvrclientreporttypes.OSVR_AnalogReport;
|
|
import com.jme3.system.osvr.osvrclientreporttypes.OSVR_ButtonReport;
|
|
import com.jme3.system.osvr.osvrclientreporttypes.OSVR_Pose3;
|
|
import com.jme3.system.osvr.osvrinterface.OsvrInterfaceLibrary;
|
|
import com.jme3.system.osvr.osvrtimevalue.OSVR_TimeValue;
|
|
import com.jme3.util.VRViewManagerOSVR;
|
|
import com.sun.jna.Callback;
|
|
import com.sun.jna.Pointer;
|
|
import com.sun.jna.ptr.PointerByReference;
|
|
|
|
|
|
/**
|
|
* A class that wraps an <a href="http://www.osvr.org/">OSVR</a> input.
|
|
* @author reden - phr00t - https://github.com/phr00t
|
|
* @author Julien Seinturier - (c) 2016 - JOrigin project - <a href="http://www.jorigin.org">http:/www.jorigin.org</a>
|
|
*/
|
|
public class OSVRInput implements VRInputAPI {
|
|
|
|
private static final Logger logger = Logger.getLogger(OSVRInput.class.getName());
|
|
|
|
// position example: https://github.com/OSVR/OSVR-Core/blob/master/examples/clients/TrackerState.c
|
|
// button example: https://github.com/OSVR/OSVR-Core/blob/master/examples/clients/ButtonCallback.c
|
|
// analog example: https://github.com/OSVR/OSVR-Core/blob/master/examples/clients/AnalogCallback.c
|
|
|
|
private static final int ANALOG_COUNT = 3, BUTTON_COUNT = 7, CHANNEL_COUNT = 3;
|
|
|
|
OSVR_ClientInterface[][] buttons;
|
|
OSVR_ClientInterface[][][] analogs;
|
|
OSVR_ClientInterface[] hands;
|
|
|
|
OSVR_Pose3[] handState;
|
|
Callback buttonHandler, analogHandler;
|
|
OSVR_TimeValue tv = new OSVR_TimeValue();
|
|
boolean[] isHandTracked = new boolean[2];
|
|
|
|
private float[][][] analogState;
|
|
private float[][] buttonState;
|
|
|
|
private final Quaternion tempq = new Quaternion();
|
|
private final Vector3f tempv = new Vector3f();
|
|
private final Vector2f temp2 = new Vector2f();
|
|
private final boolean[][] buttonDown = new boolean[16][16];
|
|
|
|
private static final Vector2f temp2Axis = new Vector2f();
|
|
private static final Vector2f lastCallAxis[] = new Vector2f[16];
|
|
private static float axisMultiplier = 1f;
|
|
|
|
private VREnvironment environment = null;
|
|
|
|
/**
|
|
* Get the system String that identifies a controller.
|
|
* @param left is the controller is the left one (<code>false</code> if the right controller is needed).
|
|
* @param index the index of the controller.
|
|
* @return the system String that identifies the controller.
|
|
*/
|
|
public static byte[] getButtonString(boolean left, byte index) {
|
|
if( left ) {
|
|
return new byte[] { '/', 'c', 'o', 'n', 't', 'r', 'o', 'l', 'l', 'e', 'r', '/', 'l', 'e', 'f', 't', '/', index, (byte)0 };
|
|
}
|
|
return new byte[] { '/', 'c', 'o', 'n', 't', 'r', 'o', 'l', 'l', 'e', 'r', '/', 'r', 'i', 'g', 'h', 't', '/', index, (byte)0 };
|
|
}
|
|
|
|
/**
|
|
* The left hand system String.
|
|
*/
|
|
public static byte[] leftHand = { '/', 'm', 'e', '/', 'h', 'a', 'n', 'd', 's', '/', 'l', 'e', 'f', 't', (byte)0 };
|
|
|
|
/**
|
|
* The right hand system String.
|
|
*/
|
|
public static byte[] rightHand = { '/', 'm', 'e', '/', 'h', 'a', 'n', 'd', 's', '/', 'r', 'i', 'g', 'h', 't', (byte)0 };
|
|
|
|
|
|
/**
|
|
* Create a new <a href="http://www.osvr.org/">OSVR</a> input attached to the given {@link VREnvironment VR environment}.
|
|
* @param environment the {@link VREnvironment VR environment} to which the input is attached.
|
|
*/
|
|
public OSVRInput(VREnvironment environment){
|
|
this.environment = environment;
|
|
}
|
|
|
|
|
|
@Override
|
|
public boolean isButtonDown(int controllerIndex, VRInputType checkButton) {
|
|
return buttonState[controllerIndex][checkButton.getValue()] != 0f;
|
|
}
|
|
|
|
@Override
|
|
public boolean wasButtonPressedSinceLastCall(int controllerIndex, VRInputType checkButton) {
|
|
boolean buttonDownNow = isButtonDown(controllerIndex, checkButton);
|
|
int checkButtonValue = checkButton.getValue();
|
|
boolean retval = buttonDownNow == true && buttonDown[controllerIndex][checkButtonValue] == false;
|
|
buttonDown[controllerIndex][checkButtonValue] = buttonDownNow;
|
|
return retval;
|
|
}
|
|
|
|
@Override
|
|
public void resetInputSinceLastCall() {
|
|
for(int i=0;i<lastCallAxis.length;i++) {
|
|
lastCallAxis[i].x = 0f;
|
|
lastCallAxis[i].y = 0f;
|
|
}
|
|
for(int i=0;i<16;i++) {
|
|
for(int j=0;j<16;j++) {
|
|
buttonDown[i][j] = false;
|
|
}
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public Vector2f getAxisDeltaSinceLastCall(int controllerIndex, VRInputType forAxis) {
|
|
int axisIndex = forAxis.getValue();
|
|
temp2Axis.set(lastCallAxis[axisIndex]);
|
|
lastCallAxis[axisIndex].set(getAxis(controllerIndex, forAxis));
|
|
if( (temp2Axis.x != 0f || temp2Axis.y != 0f) && (lastCallAxis[axisIndex].x != 0f || lastCallAxis[axisIndex].y != 0f) ) {
|
|
temp2Axis.subtractLocal(lastCallAxis[axisIndex]);
|
|
} else {
|
|
// move made from rest, don't count as a delta move
|
|
temp2Axis.x = 0f;
|
|
temp2Axis.y = 0f;
|
|
}
|
|
return temp2Axis;
|
|
}
|
|
|
|
@Override
|
|
public Vector3f getVelocity(int controllerIndex) {
|
|
return Vector3f.ZERO;
|
|
}
|
|
|
|
@Override
|
|
public Vector3f getAngularVelocity(int controllerIndex) {
|
|
return Vector3f.ZERO;
|
|
}
|
|
|
|
@Override
|
|
public Vector2f getAxisRaw(int controllerIndex, VRInputType forAxis) {
|
|
temp2.x = analogState[controllerIndex][forAxis.getValue()][0];
|
|
temp2.y = analogState[controllerIndex][forAxis.getValue()][1];
|
|
return temp2;
|
|
}
|
|
|
|
@Override
|
|
public Vector2f getAxis(int controllerIndex, VRInputType forAxis) {
|
|
temp2.x = analogState[controllerIndex][forAxis.getValue()][0] * axisMultiplier;
|
|
temp2.y = analogState[controllerIndex][forAxis.getValue()][1] * axisMultiplier;
|
|
return temp2;
|
|
}
|
|
|
|
private OSVR_ClientInterface getInterface(byte[] str) {
|
|
PointerByReference pbr = new PointerByReference();
|
|
OsvrClientKitLibrary.osvrClientGetInterface((OsvrClientKitLibrary.OSVR_ClientContext)environment.getVRHardware().getVRSystem(), str, pbr);
|
|
return new OSVR_ClientInterface(pbr.getValue());
|
|
}
|
|
|
|
@Override
|
|
public boolean init() {
|
|
|
|
logger.config("Initialize OSVR input.");
|
|
|
|
buttonHandler = new Callback() {
|
|
@SuppressWarnings("unused")
|
|
public void invoke(Pointer userdata, Pointer timeval, OSVR_ButtonReport report) {
|
|
for(int i=0;i<2;i++) {
|
|
for(int j=0;j<BUTTON_COUNT;j++) {
|
|
if( buttons[i][j] == null ) continue;
|
|
if( userdata.toString().equals(buttons[i][j].getPointer().toString()) ) {
|
|
buttonState[i][j] = report.state;
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
};
|
|
analogHandler = new Callback() {
|
|
@SuppressWarnings("unused")
|
|
public void invoke(Pointer userdata, Pointer timeval, OSVR_AnalogReport report) {
|
|
for(int i=0;i<2;i++) {
|
|
for(int j=0;j<ANALOG_COUNT;j++) {
|
|
for(int k=0;k<CHANNEL_COUNT;k++) {
|
|
if( analogs[i][j][k] == null ) continue;
|
|
if( userdata.toString().equals(analogs[i][j][k].getPointer().toString()) ) {
|
|
analogState[i][j][k] = (float)report.state;
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
buttons = new OSVR_ClientInterface[2][BUTTON_COUNT];
|
|
analogs = new OSVR_ClientInterface[2][ANALOG_COUNT][CHANNEL_COUNT];
|
|
buttonState = new float[2][BUTTON_COUNT];
|
|
analogState = new float[2][ANALOG_COUNT][CHANNEL_COUNT];
|
|
hands = new OSVR_ClientInterface[2];
|
|
hands[0] = getInterface(leftHand);
|
|
hands[1] = getInterface(rightHand);
|
|
handState = new OSVR_Pose3[2];
|
|
handState[0] = new OSVR_Pose3(); handState[1] = new OSVR_Pose3();
|
|
for(int h=0;h<2;h++) {
|
|
for(int i=0;i<BUTTON_COUNT-2;i++) {
|
|
buttons[h][i] = getInterface(getButtonString(h==0, (byte)Integer.toString(i).toCharArray()[0]));
|
|
OsvrClientKitLibrary.osvrRegisterButtonCallback(buttons[h][i], buttonHandler, buttons[h][i].getPointer());
|
|
}
|
|
}
|
|
buttons[0][BUTTON_COUNT-2] = getInterface(new byte[] { '/', 'c', 'o', 'n', 't', 'r', 'o', 'l', 'l', 'e', 'r', '/', 'l', 'e', 'f', 't', '/', 'b', 'u', 'm', 'p', 'e', 'r', (byte)0 } );
|
|
OsvrClientKitLibrary.osvrRegisterButtonCallback(buttons[0][BUTTON_COUNT-2], buttonHandler, buttons[0][BUTTON_COUNT-2].getPointer());
|
|
buttons[1][BUTTON_COUNT-2] = getInterface(new byte[] { '/', 'c', 'o', 'n', 't', 'r', 'o', 'l', 'l', 'e', 'r', '/', 'r', 'i', 'g', 'h', 't', '/', 'b', 'u', 'm', 'p', 'e', 'r', (byte)0 } );
|
|
OsvrClientKitLibrary.osvrRegisterButtonCallback(buttons[1][BUTTON_COUNT-2], buttonHandler, buttons[1][BUTTON_COUNT-2].getPointer());
|
|
buttons[0][BUTTON_COUNT-1] = getInterface(new byte[] { '/', 'c', 'o', 'n', 't', 'r', 'o', 'l', 'l', 'e', 'r', '/', 'l', 'e', 'f', 't', '/', 'j', 'o', 'y', 's', 't', 'i', 'c', 'k', '/', 'b', 'u', 't', 't', 'o', 'n', (byte)0 } );
|
|
OsvrClientKitLibrary.osvrRegisterButtonCallback(buttons[0][BUTTON_COUNT-1], buttonHandler, buttons[0][BUTTON_COUNT-1].getPointer());
|
|
buttons[1][BUTTON_COUNT-1] = getInterface(new byte[] { '/', 'c', 'o', 'n', 't', 'r', 'o', 'l', 'l', 'e', 'r', '/', 'r', 'i', 'g', 'h', 't', '/', 'j', 'o', 'y', 's', 't', 'i', 'c', 'k', '/', 'b', 'u', 't', 't', 'o', 'n', (byte)0 } );
|
|
OsvrClientKitLibrary.osvrRegisterButtonCallback(buttons[1][BUTTON_COUNT-1], buttonHandler, buttons[1][BUTTON_COUNT-1].getPointer());
|
|
|
|
analogs[0][0][0] = getInterface(new byte[] { '/', 'c', 'o', 'n', 't', 'r', 'o', 'l', 'l', 'e', 'r', '/', 'l', 'e', 'f', 't', '/', 't', 'r', 'i', 'g', 'g', 'e', 'r', (byte)0 } );
|
|
analogs[1][0][0] = getInterface(new byte[] { '/', 'c', 'o', 'n', 't', 'r', 'o', 'l', 'l', 'e', 'r', '/', 'r', 'i', 'g', 'h', 't', '/', 't', 'r', 'i', 'g', 'g', 'e', 'r', (byte)0 } );
|
|
OsvrClientKitLibrary.osvrRegisterAnalogCallback(analogs[0][0][0], analogHandler, analogs[0][0][0].getPointer());
|
|
OsvrClientKitLibrary.osvrRegisterAnalogCallback(analogs[1][0][0], analogHandler, analogs[1][0][0].getPointer());
|
|
analogs[0][1][0] = getInterface(new byte[] { '/', 'c', 'o', 'n', 't', 'r', 'o', 'l', 'l', 'e', 'r', '/', 'l', 'e', 'f', 't', '/', 'j', 'o', 'y', 's', 't', 'i', 'c', 'k', '/', 'x', (byte)0 } );
|
|
analogs[0][1][1] = getInterface(new byte[] { '/', 'c', 'o', 'n', 't', 'r', 'o', 'l', 'l', 'e', 'r', '/', 'l', 'e', 'f', 't', '/', 'j', 'o', 'y', 's', 't', 'i', 'c', 'k', '/', 'y', (byte)0 } );
|
|
OsvrClientKitLibrary.osvrRegisterAnalogCallback(analogs[0][1][0], analogHandler, analogs[0][1][0].getPointer());
|
|
OsvrClientKitLibrary.osvrRegisterAnalogCallback(analogs[0][1][1], analogHandler, analogs[0][1][1].getPointer());
|
|
analogs[1][1][0] = getInterface(new byte[] { '/', 'c', 'o', 'n', 't', 'r', 'o', 'l', 'l', 'e', 'r', '/', 'r', 'i', 'g', 'h', 't', '/', 'j', 'o', 'y', 's', 't', 'i', 'c', 'k', '/', 'x', (byte)0 } );
|
|
analogs[1][1][1] = getInterface(new byte[] { '/', 'c', 'o', 'n', 't', 'r', 'o', 'l', 'l', 'e', 'r', '/', 'r', 'i', 'g', 'h', 't', '/', 'j', 'o', 'y', 's', 't', 'i', 'c', 'k', '/', 'y', (byte)0 } );
|
|
OsvrClientKitLibrary.osvrRegisterAnalogCallback(analogs[1][1][0], analogHandler, analogs[1][1][0].getPointer());
|
|
OsvrClientKitLibrary.osvrRegisterAnalogCallback(analogs[1][1][1], analogHandler, analogs[1][1][1].getPointer());
|
|
|
|
return true;
|
|
}
|
|
|
|
@Override
|
|
public int getTrackedControllerCount() {
|
|
return (isHandTracked[0]?1:0) + (isHandTracked[1]?1:0);
|
|
}
|
|
|
|
@Override
|
|
public void updateConnectedControllers() {
|
|
|
|
}
|
|
|
|
@Override
|
|
public void updateControllerStates() {
|
|
for(int i=0;i<hands.length;i++) {
|
|
isHandTracked[i] = OsvrInterfaceLibrary.osvrGetPoseState(hands[i], tv, handState[i]) == 0;
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public Object getRawControllerState(int index) {
|
|
return handState[index];
|
|
}
|
|
|
|
//@Override
|
|
//public Matrix4f getPoseForInputDevice(int index) {
|
|
// return handState[i].
|
|
//}
|
|
|
|
@Override
|
|
public boolean isInputFocused() {
|
|
return true;
|
|
}
|
|
|
|
@Override
|
|
public boolean isInputDeviceTracking(int index) {
|
|
return isHandTracked[index];
|
|
}
|
|
|
|
@Override
|
|
public Quaternion getOrientation(int index) {
|
|
tempq.set((float)-handState[index].rotation.data[1],
|
|
(float)handState[index].rotation.data[2],
|
|
(float)-handState[index].rotation.data[3],
|
|
(float)handState[index].rotation.data[0]);
|
|
return tempq;
|
|
}
|
|
|
|
@Override
|
|
public Vector3f getPosition(int index) {
|
|
tempv.x = (float)-handState[index].translation.data[0];
|
|
tempv.y = (float) handState[index].translation.data[1];
|
|
tempv.z = (float)-handState[index].translation.data[2];
|
|
return tempv;
|
|
}
|
|
|
|
@Override
|
|
public Quaternion getFinalObserverRotation(int index) {
|
|
VRViewManagerOSVR vrvm = (VRViewManagerOSVR)environment.getVRViewManager();
|
|
if( vrvm == null || isInputDeviceTracking(index) == false ) return null;
|
|
Object obs = environment.getObserver();
|
|
if( obs instanceof Camera ) {
|
|
tempq.set(((Camera)obs).getRotation());
|
|
} else {
|
|
tempq.set(((Spatial)obs).getWorldRotation());
|
|
}
|
|
return tempq.multLocal(getOrientation(index));
|
|
}
|
|
|
|
@Override
|
|
public Vector3f getFinalObserverPosition(int index) {
|
|
VRViewManagerOSVR vrvm = (VRViewManagerOSVR) environment.getVRViewManager();
|
|
if( vrvm == null || isInputDeviceTracking(index) == false ) return null;
|
|
Object obs = environment.getObserver();
|
|
Vector3f pos = getPosition(index);
|
|
if( obs instanceof Camera ) {
|
|
((Camera)obs).getRotation().mult(pos, pos);
|
|
return pos.addLocal(((Camera)obs).getLocation());
|
|
} else {
|
|
((Spatial)obs).getWorldRotation().mult(pos, pos);
|
|
return pos.addLocal(((Spatial)obs).getWorldTranslation());
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void triggerHapticPulse(int controllerIndex, float seconds) {
|
|
|
|
}
|
|
|
|
@Override
|
|
public void swapHands() {
|
|
// not supported yet
|
|
}
|
|
|
|
@Override
|
|
public float getAxisMultiplier() {
|
|
return axisMultiplier;
|
|
}
|
|
|
|
@Override
|
|
public void setAxisMultiplier(float set) {
|
|
axisMultiplier = set;
|
|
}
|
|
|
|
@Override
|
|
public VRTrackedController getTrackedController(int index) {
|
|
// TODO Auto-generated method stub
|
|
return null;
|
|
}
|
|
|
|
}
|
|
|