Merge pull request #756 from neph1/osvr_viewmanager
making VRViewManagerOSVR more similar to VRViewManagerOpenVRempirephoenix-patch-1
commit
e4ce70d0ba
@ -1,461 +1,461 @@ |
||||
/* |
||||
|
||||
https://github.com/sensics/OSVR-RenderManager/blob/master/examples/RenderManagerOpenGLCAPIExample.cpp
|
||||
|
||||
- JVM crashes often.. placing breakpoints during initialization clears it up most of the time (WHY!?) |
||||
- OSVR is just unstable.. any way to improve things? |
||||
- render manager looks good, but left eye seems stretched |
||||
|
||||
*/ |
||||
package com.jme3.input.vr; |
||||
|
||||
import com.jme3.app.VREnvironment; |
||||
import com.jme3.math.Matrix4f; |
||||
import com.jme3.math.Quaternion; |
||||
import com.jme3.math.Vector2f; |
||||
import com.jme3.math.Vector3f; |
||||
import com.jme3.renderer.Camera; |
||||
import com.jme3.system.osvr.osvrclientkit.OsvrClientKitLibrary; |
||||
import com.jme3.system.osvr.osvrdisplay.OsvrDisplayLibrary; |
||||
import com.jme3.system.osvr.osvrdisplay.OsvrDisplayLibrary.OSVR_DisplayConfig; |
||||
import com.jme3.system.osvr.osvrmatrixconventions.OSVR_Pose3; |
||||
import com.jme3.system.osvr.osvrrendermanageropengl.OSVR_OpenResultsOpenGL; |
||||
import com.jme3.system.osvr.osvrrendermanageropengl.OSVR_RenderBufferOpenGL; |
||||
import com.jme3.system.osvr.osvrrendermanageropengl.OSVR_RenderInfoOpenGL; |
||||
import com.jme3.system.osvr.osvrrendermanageropengl.OSVR_RenderParams; |
||||
import com.jme3.system.osvr.osvrrendermanageropengl.OSVR_ViewportDescription; |
||||
import com.jme3.system.osvr.osvrrendermanageropengl.OsvrRenderManagerOpenGLLibrary; |
||||
import com.ochafik.lang.jnaerator.runtime.NativeSize; |
||||
import com.ochafik.lang.jnaerator.runtime.NativeSizeByReference; |
||||
import com.sun.jna.Pointer; |
||||
import com.sun.jna.ptr.PointerByReference; |
||||
import java.nio.FloatBuffer; |
||||
import java.util.logging.Logger; |
||||
|
||||
/** |
||||
* A class that wraps an <a href="http://www.osvr.org/">OSVR</a> system. |
||||
* @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 OSVR implements VRAPI { |
||||
|
||||
private static final Logger logger = Logger.getLogger(OSVR.class.getName()); |
||||
|
||||
/** |
||||
* The first viewer index. |
||||
*/ |
||||
public static final int FIRST_VIEWER = 0; |
||||
|
||||
/** |
||||
* The left eye index. |
||||
*/ |
||||
public static final int EYE_LEFT = 0; |
||||
|
||||
/** |
||||
* The right eye index. |
||||
*/ |
||||
public static final int EYE_RIGHT = 1; |
||||
|
||||
/** |
||||
* The size of the left eye. |
||||
*/ |
||||
public static final NativeSize EYE_LEFT_SIZE = new NativeSize(EYE_LEFT); |
||||
|
||||
/** |
||||
* The size of the right eye. |
||||
*/ |
||||
public static final NativeSize EYE_RIGHT_SIZE = new NativeSize(EYE_RIGHT); |
||||
|
||||
/** |
||||
* The default J String. |
||||
*/ |
||||
public static byte[] defaultJString = { 'j', (byte)0 }; |
||||
|
||||
/** |
||||
* The default OpenGL String. |
||||
*/ |
||||
public static byte[] OpenGLString = { 'O', 'p', 'e', 'n', 'G', 'L', (byte)0 }; |
||||
|
||||
private final Matrix4f[] eyeMatrix = new Matrix4f[2]; |
||||
|
||||
private PointerByReference grabRM; |
||||
private PointerByReference grabRMOGL; |
||||
private PointerByReference grabRIC; |
||||
|
||||
OSVR_RenderParams.ByValue renderParams; |
||||
OsvrClientKitLibrary.OSVR_ClientContext context; |
||||
com.jme3.system.osvr.osvrrendermanageropengl.OSVR_GraphicsLibraryOpenGL.ByValue graphicsLibrary; |
||||
Pointer renderManager, renderManagerOpenGL, renderInfoCollection, registerBufferState; |
||||
OSVRInput VRinput; |
||||
NativeSize numRenderInfo; |
||||
NativeSizeByReference grabNumInfo = new NativeSizeByReference(); |
||||
OSVR_RenderInfoOpenGL.ByValue eyeLeftInfo, eyeRightInfo; |
||||
Matrix4f hmdPoseLeftEye; |
||||
Matrix4f hmdPoseRightEye; |
||||
Vector3f hmdPoseLeftEyeVec, hmdPoseRightEyeVec, hmdSeatToStand; |
||||
OSVR_DisplayConfig displayConfig; |
||||
OSVR_Pose3 hmdPose = new OSVR_Pose3(); |
||||
Vector3f storePos = new Vector3f(); |
||||
Quaternion storeRot = new Quaternion(); |
||||
PointerByReference presentState = new PointerByReference(); |
||||
OSVR_OpenResultsOpenGL openResults = new OSVR_OpenResultsOpenGL(); |
||||
|
||||
long glfwContext; |
||||
long renderManagerContext; |
||||
long wglGLFW; |
||||
long wglRM; |
||||
|
||||
boolean initSuccess = false; |
||||
boolean flipEyes = false; |
||||
|
||||
private VREnvironment environment = null; |
||||
|
||||
/** |
||||
* Create a new <a href="http://www.osvr.org/">OSVR</a> system attached to the given {@link VREnvironment VR environment}. |
||||
* @param environment the {@link VREnvironment VR environment} to which the input is attached. |
||||
*/ |
||||
public OSVR(VREnvironment environment){ |
||||
this.environment = environment; |
||||
} |
||||
|
||||
/** |
||||
* Access to the underlying OSVR structures. |
||||
* @param leftView the left viewport. |
||||
* @param rightView the right viewport. |
||||
* @param leftBuffer the left buffer. |
||||
* @param rightBuffer the right buffer. |
||||
* @return <code>true</code> if the structure are accessible and <code>false</code> otherwise. |
||||
*/ |
||||
public boolean handleRenderBufferPresent(OSVR_ViewportDescription.ByValue leftView, OSVR_ViewportDescription.ByValue rightView, |
||||
OSVR_RenderBufferOpenGL.ByValue leftBuffer, OSVR_RenderBufferOpenGL.ByValue rightBuffer) { |
||||
if( eyeLeftInfo == null || eyeRightInfo == null ) return false; |
||||
byte retval; |
||||
OsvrRenderManagerOpenGLLibrary.osvrRenderManagerStartPresentRenderBuffers(presentState); |
||||
getEyeInfo(); |
||||
OsvrRenderManagerOpenGLLibrary.osvrRenderManagerPresentRenderBufferOpenGL(presentState.getValue(), leftBuffer, eyeLeftInfo, leftView); |
||||
OsvrRenderManagerOpenGLLibrary.osvrRenderManagerPresentRenderBufferOpenGL(presentState.getValue(), rightBuffer, eyeRightInfo, rightView); |
||||
retval = OsvrRenderManagerOpenGLLibrary.osvrRenderManagerFinishPresentRenderBuffers(renderManager, presentState.getValue(), renderParams, (byte)0); |
||||
return retval == 0; // only check the last error, since if something errored above, the last call won't work & all calls will log to syserr
|
||||
} |
||||
|
||||
|
||||
|
||||
@Override |
||||
public boolean initialize() { |
||||
|
||||
logger.config("Initialize OSVR system."); |
||||
|
||||
hmdPose.setAutoSynch(false); |
||||
context = OsvrClientKitLibrary.osvrClientInit(defaultJString, 0); |
||||
VRinput = new OSVRInput(environment); |
||||
initSuccess = context != null && VRinput.init(); |
||||
if( initSuccess ) { |
||||
PointerByReference grabDisplay = new PointerByReference(); |
||||
byte retval = OsvrDisplayLibrary.osvrClientGetDisplay(context, grabDisplay); |
||||
if( retval != 0 ) { |
||||
System.out.println("OSVR Get Display Error: " + retval); |
||||
initSuccess = false; |
||||
return false; |
||||
} |
||||
displayConfig = new OSVR_DisplayConfig(grabDisplay.getValue()); |
||||
System.out.println("Waiting for the display to fully start up, including receiving initial pose update..."); |
||||
int i = 400; |
||||
while (OsvrDisplayLibrary.osvrClientCheckDisplayStartup(displayConfig) != 0) { |
||||
if( i-- < 0 ) { |
||||
System.out.println("Couldn't get display startup update in time, continuing anyway..."); |
||||
break; |
||||
} |
||||
OsvrClientKitLibrary.osvrClientUpdate(context); |
||||
try { |
||||
Thread.sleep(5); |
||||
} catch(Exception e) { } |
||||
} |
||||
System.out.println("OK, display startup status is good!"); |
||||
} |
||||
return initSuccess; |
||||
} |
||||
|
||||
|
||||
/** |
||||
* Grab the current GLFW context. |
||||
*/ |
||||
public void grabGLFWContext() { |
||||
// get current conext
|
||||
wglGLFW = org.lwjgl.opengl.WGL.wglGetCurrentContext(); |
||||
glfwContext = org.lwjgl.glfw.GLFW.glfwGetCurrentContext(); |
||||
} |
||||
|
||||
/** |
||||
* Enable context sharing. |
||||
* @return <code>true</code> if the context is successfully shared and <code>false</code> otherwise. |
||||
*/ |
||||
public boolean shareContext() { |
||||
if( org.lwjgl.opengl.WGL.wglShareLists(wglRM, wglGLFW)) { |
||||
System.out.println("Context sharing success!"); |
||||
return true; |
||||
} else { |
||||
System.out.println("Context sharing problem..."); |
||||
return false; |
||||
} |
||||
} |
||||
|
||||
@Override |
||||
public boolean initVRCompositor(boolean allowed) { |
||||
if( !allowed || renderManager != null ) return false; |
||||
grabGLFWContext(); |
||||
graphicsLibrary = new com.jme3.system.osvr.osvrrendermanageropengl.OSVR_GraphicsLibraryOpenGL.ByValue(); |
||||
graphicsLibrary.toolkit = null; |
||||
graphicsLibrary.setAutoSynch(false); |
||||
grabRM = new PointerByReference(); grabRMOGL = new PointerByReference(); |
||||
byte retval = OsvrRenderManagerOpenGLLibrary.osvrCreateRenderManagerOpenGL(context, OpenGLString, graphicsLibrary, grabRM, grabRMOGL); |
||||
if( retval == 0 ) { |
||||
renderManager = grabRM.getValue(); renderManagerOpenGL = grabRMOGL.getValue(); |
||||
if( renderManager == null || renderManagerOpenGL == null ) { |
||||
System.out.println("Render Manager Created NULL, error!"); |
||||
return false; |
||||
} |
||||
openResults.setAutoSynch(false); |
||||
retval = OsvrRenderManagerOpenGLLibrary.osvrRenderManagerOpenDisplayOpenGL(renderManager, openResults); |
||||
if( retval == 0 ) { |
||||
wglRM = org.lwjgl.opengl.WGL.wglGetCurrentContext(); |
||||
renderManagerContext = org.lwjgl.glfw.GLFW.glfwGetCurrentContext(); |
||||
shareContext(); |
||||
OsvrClientKitLibrary.osvrClientUpdate(context); |
||||
renderParams = new OSVR_RenderParams.ByValue(); |
||||
renderParams.setAutoSynch(false); |
||||
OsvrRenderManagerOpenGLLibrary.osvrRenderManagerGetDefaultRenderParams(renderParams); |
||||
grabRIC = new PointerByReference(); |
||||
retval = OsvrRenderManagerOpenGLLibrary.osvrRenderManagerGetRenderInfoCollection(renderManager, renderParams, grabRIC); |
||||
if( retval == 0 ) { |
||||
renderInfoCollection = grabRIC.getValue(); |
||||
OsvrRenderManagerOpenGLLibrary.osvrRenderManagerGetNumRenderInfoInCollection(renderInfoCollection, grabNumInfo); |
||||
numRenderInfo = grabNumInfo.getValue(); |
||||
eyeLeftInfo = new OSVR_RenderInfoOpenGL.ByValue(); |
||||
eyeRightInfo = new OSVR_RenderInfoOpenGL.ByValue(); |
||||
eyeLeftInfo.setAutoSynch(false); |
||||
eyeRightInfo.setAutoSynch(false); |
||||
return true; |
||||
} |
||||
OsvrRenderManagerOpenGLLibrary.osvrDestroyRenderManager(renderManager); |
||||
System.out.println("OSVR Render Manager Info Collection Error: " + retval); |
||||
return false; |
||||
} |
||||
OsvrRenderManagerOpenGLLibrary.osvrDestroyRenderManager(renderManager); |
||||
System.out.println("OSVR Open Render Manager Display Error: " + retval); |
||||
return false; |
||||
} |
||||
System.out.println("OSVR Create Render Manager Error: " + retval); |
||||
return false; |
||||
} |
||||
|
||||
@Override |
||||
public OsvrClientKitLibrary.OSVR_ClientContext getVRSystem() { |
||||
return context; |
||||
} |
||||
|
||||
@Override |
||||
public Pointer getCompositor() { |
||||
return renderManager; |
||||
} |
||||
|
||||
@Override |
||||
public String getName() { |
||||
return "OSVR"; |
||||
} |
||||
|
||||
@Override |
||||
public VRInputAPI getVRinput() { |
||||
return VRinput; |
||||
} |
||||
|
||||
@Override |
||||
public void setFlipEyes(boolean set) { |
||||
flipEyes = set; |
||||
} |
||||
|
||||
@Override |
||||
public void printLatencyInfoToConsole(boolean set) { |
||||
|
||||
} |
||||
|
||||
@Override |
||||
public int getDisplayFrequency() { |
||||
return 60; //debug display frequency
|
||||
} |
||||
|
||||
@Override |
||||
public void destroy() { |
||||
if( renderManager != null ) OsvrRenderManagerOpenGLLibrary.osvrDestroyRenderManager(renderManager); |
||||
if( displayConfig != null ) OsvrDisplayLibrary.osvrClientFreeDisplay(displayConfig); |
||||
} |
||||
|
||||
@Override |
||||
public boolean isInitialized() { |
||||
return initSuccess; |
||||
} |
||||
|
||||
@Override |
||||
public void reset() { |
||||
// TODO: no native OSVR reset function
|
||||
// may need to take current position and negate it from future values
|
||||
} |
||||
|
||||
@Override |
||||
public void getRenderSize(Vector2f store) { |
||||
if( eyeLeftInfo == null || eyeLeftInfo.viewport.width == 0.0 ) { |
||||
store.x = 1280f; store.y = 720f; |
||||
} else { |
||||
store.x = (float)eyeLeftInfo.viewport.width; |
||||
store.y = (float)eyeLeftInfo.viewport.height; |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Read and update the eye info from the underlying OSVR system. |
||||
*/ |
||||
public void getEyeInfo() { |
||||
OsvrRenderManagerOpenGLLibrary.osvrRenderManagerGetRenderInfoFromCollectionOpenGL(renderInfoCollection, EYE_LEFT_SIZE, eyeLeftInfo); |
||||
OsvrRenderManagerOpenGLLibrary.osvrRenderManagerGetRenderInfoFromCollectionOpenGL(renderInfoCollection, EYE_RIGHT_SIZE, eyeRightInfo); |
||||
eyeLeftInfo.read(); eyeRightInfo.read(); |
||||
} |
||||
/* |
||||
@Override |
||||
public float getFOV(int dir) { |
||||
return 105f; //default FOV
|
||||
} |
||||
*/ |
||||
@Override |
||||
public float getInterpupillaryDistance() { |
||||
return 0.065f; //default IPD
|
||||
} |
||||
|
||||
@Override |
||||
public Quaternion getOrientation() { |
||||
storeRot.set((float)-hmdPose.rotation.data[1], |
||||
(float)hmdPose.rotation.data[2], |
||||
(float)-hmdPose.rotation.data[3], |
||||
(float)hmdPose.rotation.data[0]); |
||||
if( storeRot.equals(Quaternion.ZERO) ) storeRot.set(Quaternion.DIRECTION_Z); |
||||
return storeRot; |
||||
} |
||||
|
||||
@Override |
||||
public Vector3f getPosition() { |
||||
storePos.x = (float)-hmdPose.translation.data[0]; |
||||
storePos.y = (float)hmdPose.translation.data[1]; |
||||
storePos.z = (float)-hmdPose.translation.data[2]; |
||||
return storePos; |
||||
} |
||||
|
||||
@Override |
||||
public void getPositionAndOrientation(Vector3f storePos, Quaternion storeRot) { |
||||
storePos.x = (float)-hmdPose.translation.data[0]; |
||||
storePos.y = (float)hmdPose.translation.data[1]; |
||||
storePos.z = (float)-hmdPose.translation.data[2]; |
||||
storeRot.set((float)-hmdPose.rotation.data[1], |
||||
(float)hmdPose.rotation.data[2], |
||||
(float)-hmdPose.rotation.data[3], |
||||
(float)hmdPose.rotation.data[0]); |
||||
if( storeRot.equals(Quaternion.ZERO) ) storeRot.set(Quaternion.DIRECTION_Z); |
||||
} |
||||
|
||||
@Override |
||||
public void updatePose() { |
||||
if( context == null || displayConfig == null ) return; |
||||
OsvrClientKitLibrary.osvrClientUpdate(context); |
||||
OsvrDisplayLibrary.osvrClientGetViewerPose(displayConfig, FIRST_VIEWER, hmdPose.getPointer()); |
||||
VRinput.updateControllerStates(); |
||||
hmdPose.read(); |
||||
} |
||||
|
||||
@Override |
||||
public Matrix4f getHMDMatrixProjectionLeftEye(Camera cam) { |
||||
if( eyeLeftInfo == null ) return cam.getProjectionMatrix(); |
||||
if( eyeMatrix[EYE_LEFT] == null ) { |
||||
FloatBuffer tfb = FloatBuffer.allocate(16); |
||||
com.jme3.system.osvr.osvrdisplay.OsvrDisplayLibrary.osvrClientGetViewerEyeSurfaceProjectionMatrixf(displayConfig, 0, (byte)EYE_LEFT, 0, cam.getFrustumNear(), cam.getFrustumFar(), (short)0, tfb); |
||||
eyeMatrix[EYE_LEFT] = new Matrix4f(); |
||||
eyeMatrix[EYE_LEFT].set(tfb.get(0), tfb.get(4), tfb.get(8), tfb.get(12), |
||||
tfb.get(1), tfb.get(5), tfb.get(9), tfb.get(13), |
||||
tfb.get(2), tfb.get(6), tfb.get(10), tfb.get(14), |
||||
tfb.get(3), tfb.get(7), tfb.get(11), tfb.get(15)); |
||||
} |
||||
return eyeMatrix[EYE_LEFT]; |
||||
} |
||||
|
||||
@Override |
||||
public Matrix4f getHMDMatrixProjectionRightEye(Camera cam) { |
||||
if( eyeRightInfo == null ) return cam.getProjectionMatrix(); |
||||
if( eyeMatrix[EYE_RIGHT] == null ) { |
||||
FloatBuffer tfb = FloatBuffer.allocate(16); |
||||
com.jme3.system.osvr.osvrdisplay.OsvrDisplayLibrary.osvrClientGetViewerEyeSurfaceProjectionMatrixf(displayConfig, 0, (byte)EYE_RIGHT, 0, cam.getFrustumNear(), cam.getFrustumFar(), (short)0, tfb); |
||||
eyeMatrix[EYE_RIGHT] = new Matrix4f(); |
||||
eyeMatrix[EYE_RIGHT].set(tfb.get(0), tfb.get(4), tfb.get(8), tfb.get(12), |
||||
tfb.get(1), tfb.get(5), tfb.get(9), tfb.get(13), |
||||
tfb.get(2), tfb.get(6), tfb.get(10), tfb.get(14), |
||||
tfb.get(3), tfb.get(7), tfb.get(11), tfb.get(15)); |
||||
} |
||||
return eyeMatrix[EYE_RIGHT]; |
||||
} |
||||
|
||||
@Override |
||||
public Vector3f getHMDVectorPoseLeftEye() { |
||||
if( hmdPoseLeftEyeVec == null ) { |
||||
hmdPoseLeftEyeVec = new Vector3f(); |
||||
hmdPoseLeftEyeVec.x = 0.065f * -0.5f; |
||||
if( flipEyes == false ) hmdPoseLeftEyeVec.x *= -1f; // it seems these need flipping
|
||||
} |
||||
return hmdPoseLeftEyeVec; |
||||
} |
||||
|
||||
@Override |
||||
public Vector3f getHMDVectorPoseRightEye() { |
||||
if( hmdPoseRightEyeVec == null ) { |
||||
hmdPoseRightEyeVec = new Vector3f(); |
||||
hmdPoseRightEyeVec.x = 0.065f * 0.5f; |
||||
if( flipEyes == false ) hmdPoseRightEyeVec.x *= -1f; // it seems these need flipping
|
||||
} |
||||
return hmdPoseRightEyeVec; |
||||
} |
||||
|
||||
@Override |
||||
public Vector3f getSeatedToAbsolutePosition() { |
||||
return Vector3f.ZERO; |
||||
} |
||||
|
||||
@Override |
||||
public Matrix4f getHMDMatrixPoseLeftEye() { |
||||
// not actually used internally...
|
||||
/*if( hmdPoseLeftEye != null ) { |
||||
return hmdPoseLeftEye; |
||||
} else { |
||||
FloatBuffer mat = FloatBuffer.allocate(16); |
||||
OsvrDisplayLibrary.osvrClientGetViewerEyeViewMatrixf(displayConfig, FIRST_VIEWER, (byte)EYE_LEFT, |
||||
(short)(OsvrMatrixConventionsLibrary.OSVR_MatrixVectorFlags.OSVR_MATRIX_COLVECTORS | |
||||
OsvrMatrixConventionsLibrary.OSVR_MatrixOrderingFlags.OSVR_MATRIX_COLMAJOR), tempfb); |
||||
hmdPoseLeftEye = new Matrix4f(tempfb.array()); |
||||
return hmdPoseLeftEye; |
||||
}*/ |
||||
return null; |
||||
} |
||||
|
||||
@Override |
||||
public Matrix4f getHMDMatrixPoseRightEye() { |
||||
// not actually used internally...
|
||||
/*if( hmdPoseRightEye != null ) { |
||||
return hmdPoseRightEye; |
||||
} else { |
||||
OsvrDisplayLibrary.osvrClientGetViewerEyeViewMatrixf(displayConfig, FIRST_VIEWER, (byte)EYE_RIGHT, |
||||
(short)(OsvrMatrixConventionsLibrary.OSVR_MatrixVectorFlags.OSVR_MATRIX_COLVECTORS | |
||||
OsvrMatrixConventionsLibrary.OSVR_MatrixOrderingFlags.OSVR_MATRIX_COLMAJOR), tempfb); |
||||
hmdPoseRightEye = new Matrix4f(tempfb.array()); |
||||
return hmdPoseRightEye; |
||||
}*/ |
||||
return null; |
||||
} |
||||
|
||||
@Override |
||||
public HmdType getType() { |
||||
return HmdType.OSVR; |
||||
} |
||||
} |
||||
/* |
||||
|
||||
https://github.com/sensics/OSVR-RenderManager/blob/master/examples/RenderManagerOpenGLCAPIExample.cpp
|
||||
|
||||
- JVM crashes often.. placing breakpoints during initialization clears it up most of the time (WHY!?) |
||||
- OSVR is just unstable.. any way to improve things? |
||||
- render manager looks good, but left eye seems stretched |
||||
|
||||
*/ |
||||
package com.jme3.input.vr; |
||||
|
||||
import com.jme3.app.VREnvironment; |
||||
import com.jme3.math.Matrix4f; |
||||
import com.jme3.math.Quaternion; |
||||
import com.jme3.math.Vector2f; |
||||
import com.jme3.math.Vector3f; |
||||
import com.jme3.renderer.Camera; |
||||
import com.jme3.system.osvr.osvrclientkit.OsvrClientKitLibrary; |
||||
import com.jme3.system.osvr.osvrdisplay.OsvrDisplayLibrary; |
||||
import com.jme3.system.osvr.osvrdisplay.OsvrDisplayLibrary.OSVR_DisplayConfig; |
||||
import com.jme3.system.osvr.osvrmatrixconventions.OSVR_Pose3; |
||||
import com.jme3.system.osvr.osvrrendermanageropengl.OSVR_OpenResultsOpenGL; |
||||
import com.jme3.system.osvr.osvrrendermanageropengl.OSVR_RenderBufferOpenGL; |
||||
import com.jme3.system.osvr.osvrrendermanageropengl.OSVR_RenderInfoOpenGL; |
||||
import com.jme3.system.osvr.osvrrendermanageropengl.OSVR_RenderParams; |
||||
import com.jme3.system.osvr.osvrrendermanageropengl.OSVR_ViewportDescription; |
||||
import com.jme3.system.osvr.osvrrendermanageropengl.OsvrRenderManagerOpenGLLibrary; |
||||
import com.ochafik.lang.jnaerator.runtime.NativeSize; |
||||
import com.ochafik.lang.jnaerator.runtime.NativeSizeByReference; |
||||
import com.sun.jna.Pointer; |
||||
import com.sun.jna.ptr.PointerByReference; |
||||
import java.nio.FloatBuffer; |
||||
import java.util.logging.Logger; |
||||
|
||||
/** |
||||
* A class that wraps an <a href="http://www.osvr.org/">OSVR</a> system. |
||||
* @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 OSVR implements VRAPI { |
||||
|
||||
private static final Logger logger = Logger.getLogger(OSVR.class.getName()); |
||||
|
||||
/** |
||||
* The first viewer index. |
||||
*/ |
||||
public static final int FIRST_VIEWER = 0; |
||||
|
||||
/** |
||||
* The left eye index. |
||||
*/ |
||||
public static final int EYE_LEFT = 0; |
||||
|
||||
/** |
||||
* The right eye index. |
||||
*/ |
||||
public static final int EYE_RIGHT = 1; |
||||
|
||||
/** |
||||
* The size of the left eye. |
||||
*/ |
||||
public static final NativeSize EYE_LEFT_SIZE = new NativeSize(EYE_LEFT); |
||||
|
||||
/** |
||||
* The size of the right eye. |
||||
*/ |
||||
public static final NativeSize EYE_RIGHT_SIZE = new NativeSize(EYE_RIGHT); |
||||
|
||||
/** |
||||
* The default J String. |
||||
*/ |
||||
public static byte[] defaultJString = { 'j', (byte)0 }; |
||||
|
||||
/** |
||||
* The default OpenGL String. |
||||
*/ |
||||
public static byte[] OpenGLString = { 'O', 'p', 'e', 'n', 'G', 'L', (byte)0 }; |
||||
|
||||
private final Matrix4f[] eyeMatrix = new Matrix4f[2]; |
||||
|
||||
private PointerByReference grabRM; |
||||
private PointerByReference grabRMOGL; |
||||
private PointerByReference grabRIC; |
||||
|
||||
OSVR_RenderParams.ByValue renderParams; |
||||
OsvrClientKitLibrary.OSVR_ClientContext context; |
||||
com.jme3.system.osvr.osvrrendermanageropengl.OSVR_GraphicsLibraryOpenGL.ByValue graphicsLibrary; |
||||
Pointer renderManager, renderManagerOpenGL, renderInfoCollection, registerBufferState; |
||||
OSVRInput VRinput; |
||||
NativeSize numRenderInfo; |
||||
NativeSizeByReference grabNumInfo = new NativeSizeByReference(); |
||||
OSVR_RenderInfoOpenGL.ByValue eyeLeftInfo, eyeRightInfo; |
||||
Matrix4f hmdPoseLeftEye; |
||||
Matrix4f hmdPoseRightEye; |
||||
Vector3f hmdPoseLeftEyeVec, hmdPoseRightEyeVec, hmdSeatToStand; |
||||
OSVR_DisplayConfig displayConfig; |
||||
OSVR_Pose3 hmdPose = new OSVR_Pose3(); |
||||
Vector3f storePos = new Vector3f(); |
||||
Quaternion storeRot = new Quaternion(); |
||||
PointerByReference presentState = new PointerByReference(); |
||||
OSVR_OpenResultsOpenGL openResults = new OSVR_OpenResultsOpenGL(); |
||||
|
||||
long glfwContext; |
||||
long renderManagerContext; |
||||
long wglGLFW; |
||||
long wglRM; |
||||
|
||||
boolean initSuccess = false; |
||||
boolean flipEyes = false; |
||||
|
||||
private VREnvironment environment = null; |
||||
|
||||
/** |
||||
* Create a new <a href="http://www.osvr.org/">OSVR</a> system attached to the given {@link VREnvironment VR environment}. |
||||
* @param environment the {@link VREnvironment VR environment} to which the input is attached. |
||||
*/ |
||||
public OSVR(VREnvironment environment){ |
||||
this.environment = environment; |
||||
} |
||||
|
||||
/** |
||||
* Access to the underlying OSVR structures. |
||||
* @param leftView the left viewport. |
||||
* @param rightView the right viewport. |
||||
* @param leftBuffer the left buffer. |
||||
* @param rightBuffer the right buffer. |
||||
* @return <code>true</code> if the structure are accessible and <code>false</code> otherwise. |
||||
*/ |
||||
public boolean handleRenderBufferPresent(OSVR_ViewportDescription.ByValue leftView, OSVR_ViewportDescription.ByValue rightView, |
||||
OSVR_RenderBufferOpenGL.ByValue leftBuffer, OSVR_RenderBufferOpenGL.ByValue rightBuffer) { |
||||
if( eyeLeftInfo == null || eyeRightInfo == null ) return false; |
||||
byte retval; |
||||
OsvrRenderManagerOpenGLLibrary.osvrRenderManagerStartPresentRenderBuffers(presentState); |
||||
getEyeInfo(); |
||||
OsvrRenderManagerOpenGLLibrary.osvrRenderManagerPresentRenderBufferOpenGL(presentState.getValue(), leftBuffer, eyeLeftInfo, leftView); |
||||
OsvrRenderManagerOpenGLLibrary.osvrRenderManagerPresentRenderBufferOpenGL(presentState.getValue(), rightBuffer, eyeRightInfo, rightView); |
||||
retval = OsvrRenderManagerOpenGLLibrary.osvrRenderManagerFinishPresentRenderBuffers(renderManager, presentState.getValue(), renderParams, (byte)0); |
||||
return retval == 0; // only check the last error, since if something errored above, the last call won't work & all calls will log to syserr
|
||||
} |
||||
|
||||
|
||||
|
||||
@Override |
||||
public boolean initialize() { |
||||
|
||||
logger.config("Initialize OSVR system."); |
||||
|
||||
hmdPose.setAutoSynch(false); |
||||
context = OsvrClientKitLibrary.osvrClientInit(defaultJString, 0); |
||||
VRinput = new OSVRInput(environment); |
||||
initSuccess = context != null && VRinput.init(); |
||||
if( initSuccess ) { |
||||
PointerByReference grabDisplay = new PointerByReference(); |
||||
byte retval = OsvrDisplayLibrary.osvrClientGetDisplay(context, grabDisplay); |
||||
if( retval != 0 ) { |
||||
System.out.println("OSVR Get Display Error: " + retval); |
||||
initSuccess = false; |
||||
return false; |
||||
} |
||||
displayConfig = new OSVR_DisplayConfig(grabDisplay.getValue()); |
||||
System.out.println("Waiting for the display to fully start up, including receiving initial pose update..."); |
||||
int i = 400; |
||||
while (OsvrDisplayLibrary.osvrClientCheckDisplayStartup(displayConfig) != 0) { |
||||
if( i-- < 0 ) { |
||||
System.out.println("Couldn't get display startup update in time, continuing anyway..."); |
||||
break; |
||||
} |
||||
OsvrClientKitLibrary.osvrClientUpdate(context); |
||||
try { |
||||
Thread.sleep(5); |
||||
} catch(Exception e) { } |
||||
} |
||||
System.out.println("OK, display startup status is good!"); |
||||
} |
||||
return initSuccess; |
||||
} |
||||
|
||||
|
||||
/** |
||||
* Grab the current GLFW context. |
||||
*/ |
||||
public void grabGLFWContext() { |
||||
// get current conext
|
||||
wglGLFW = org.lwjgl.opengl.WGL.wglGetCurrentContext(); |
||||
glfwContext = org.lwjgl.glfw.GLFW.glfwGetCurrentContext(); |
||||
} |
||||
|
||||
/** |
||||
* Enable context sharing. |
||||
* @return <code>true</code> if the context is successfully shared and <code>false</code> otherwise. |
||||
*/ |
||||
public boolean shareContext() { |
||||
if( org.lwjgl.opengl.WGL.wglShareLists(wglRM, wglGLFW)) { |
||||
System.out.println("Context sharing success!"); |
||||
return true; |
||||
} else { |
||||
System.out.println("Context sharing problem..."); |
||||
return false; |
||||
} |
||||
} |
||||
|
||||
@Override |
||||
public boolean initVRCompositor(boolean allowed) { |
||||
if( !allowed || renderManager != null ) return false; |
||||
grabGLFWContext(); |
||||
graphicsLibrary = new com.jme3.system.osvr.osvrrendermanageropengl.OSVR_GraphicsLibraryOpenGL.ByValue(); |
||||
graphicsLibrary.toolkit = null; |
||||
graphicsLibrary.setAutoSynch(false); |
||||
grabRM = new PointerByReference(); grabRMOGL = new PointerByReference(); |
||||
byte retval = OsvrRenderManagerOpenGLLibrary.osvrCreateRenderManagerOpenGL(context, OpenGLString, graphicsLibrary, grabRM, grabRMOGL); |
||||
if( retval == 0 ) { |
||||
renderManager = grabRM.getValue(); renderManagerOpenGL = grabRMOGL.getValue(); |
||||
if( renderManager == null || renderManagerOpenGL == null ) { |
||||
System.out.println("Render Manager Created NULL, error!"); |
||||
return false; |
||||
} |
||||
openResults.setAutoSynch(false); |
||||
retval = OsvrRenderManagerOpenGLLibrary.osvrRenderManagerOpenDisplayOpenGL(renderManager, openResults); |
||||
if( retval == 0 ) { |
||||
wglRM = org.lwjgl.opengl.WGL.wglGetCurrentContext(); |
||||
renderManagerContext = org.lwjgl.glfw.GLFW.glfwGetCurrentContext(); |
||||
shareContext(); |
||||
OsvrClientKitLibrary.osvrClientUpdate(context); |
||||
renderParams = new OSVR_RenderParams.ByValue(); |
||||
renderParams.setAutoSynch(false); |
||||
OsvrRenderManagerOpenGLLibrary.osvrRenderManagerGetDefaultRenderParams(renderParams); |
||||
grabRIC = new PointerByReference(); |
||||
retval = OsvrRenderManagerOpenGLLibrary.osvrRenderManagerGetRenderInfoCollection(renderManager, renderParams, grabRIC); |
||||
if( retval == 0 ) { |
||||
renderInfoCollection = grabRIC.getValue(); |
||||
OsvrRenderManagerOpenGLLibrary.osvrRenderManagerGetNumRenderInfoInCollection(renderInfoCollection, grabNumInfo); |
||||
numRenderInfo = grabNumInfo.getValue(); |
||||
eyeLeftInfo = new OSVR_RenderInfoOpenGL.ByValue(); |
||||
eyeRightInfo = new OSVR_RenderInfoOpenGL.ByValue(); |
||||
eyeLeftInfo.setAutoSynch(false); |
||||
eyeRightInfo.setAutoSynch(false); |
||||
return true; |
||||
} |
||||
OsvrRenderManagerOpenGLLibrary.osvrDestroyRenderManager(renderManager); |
||||
System.out.println("OSVR Render Manager Info Collection Error: " + retval); |
||||
return false; |
||||
} |
||||
OsvrRenderManagerOpenGLLibrary.osvrDestroyRenderManager(renderManager); |
||||
System.out.println("OSVR Open Render Manager Display Error: " + retval); |
||||
return false; |
||||
} |
||||
System.out.println("OSVR Create Render Manager Error: " + retval); |
||||
return false; |
||||
} |
||||
|
||||
@Override |
||||
public OsvrClientKitLibrary.OSVR_ClientContext getVRSystem() { |
||||
return context; |
||||
} |
||||
|
||||
@Override |
||||
public Pointer getCompositor() { |
||||
return renderManager; |
||||
} |
||||
|
||||
@Override |
||||
public String getName() { |
||||
return "OSVR"; |
||||
} |
||||
|
||||
@Override |
||||
public VRInputAPI getVRinput() { |
||||
return VRinput; |
||||
} |
||||
|
||||
@Override |
||||
public void setFlipEyes(boolean set) { |
||||
flipEyes = set; |
||||
} |
||||
|
||||
@Override |
||||
public void printLatencyInfoToConsole(boolean set) { |
||||
|
||||
} |
||||
|
||||
@Override |
||||
public int getDisplayFrequency() { |
||||
return 60; //debug display frequency
|
||||
} |
||||
|
||||
@Override |
||||
public void destroy() { |
||||
if( renderManager != null ) OsvrRenderManagerOpenGLLibrary.osvrDestroyRenderManager(renderManager); |
||||
if( displayConfig != null ) OsvrDisplayLibrary.osvrClientFreeDisplay(displayConfig); |
||||
} |
||||
|
||||
@Override |
||||
public boolean isInitialized() { |
||||
return initSuccess; |
||||
} |
||||
|
||||
@Override |
||||
public void reset() { |
||||
// TODO: no native OSVR reset function
|
||||
// may need to take current position and negate it from future values
|
||||
} |
||||
|
||||
@Override |
||||
public void getRenderSize(Vector2f store) { |
||||
if( eyeLeftInfo == null || eyeLeftInfo.viewport.width == 0.0 ) { |
||||
store.x = 1280f; store.y = 720f; |
||||
} else { |
||||
store.x = (float)eyeLeftInfo.viewport.width; |
||||
store.y = (float)eyeLeftInfo.viewport.height; |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Read and update the eye info from the underlying OSVR system. |
||||
*/ |
||||
public void getEyeInfo() { |
||||
OsvrRenderManagerOpenGLLibrary.osvrRenderManagerGetRenderInfoFromCollectionOpenGL(renderInfoCollection, EYE_LEFT_SIZE, eyeLeftInfo); |
||||
OsvrRenderManagerOpenGLLibrary.osvrRenderManagerGetRenderInfoFromCollectionOpenGL(renderInfoCollection, EYE_RIGHT_SIZE, eyeRightInfo); |
||||
eyeLeftInfo.read(); eyeRightInfo.read(); |
||||
} |
||||
/* |
||||
@Override |
||||
public float getFOV(int dir) { |
||||
return 105f; //default FOV
|
||||
} |
||||
*/ |
||||
@Override |
||||
public float getInterpupillaryDistance() { |
||||
return 0.065f; //default IPD
|
||||
} |
||||
|
||||
@Override |
||||
public Quaternion getOrientation() { |
||||
storeRot.set((float)hmdPose.rotation.data[1], |
||||
(float)hmdPose.rotation.data[2], |
||||
(float)hmdPose.rotation.data[3], |
||||
(float)hmdPose.rotation.data[0]); |
||||
if( storeRot.equals(Quaternion.ZERO) ) storeRot.set(Quaternion.DIRECTION_Z); |
||||
return storeRot; |
||||
} |
||||
|
||||
@Override |
||||
public Vector3f getPosition() { |
||||
storePos.x = (float)-hmdPose.translation.data[0]; |
||||
storePos.y = (float)hmdPose.translation.data[1]; |
||||
storePos.z = (float)-hmdPose.translation.data[2]; |
||||
return storePos; |
||||
} |
||||
|
||||
@Override |
||||
public void getPositionAndOrientation(Vector3f storePos, Quaternion storeRot) { |
||||
storePos.x = (float)-hmdPose.translation.data[0]; |
||||
storePos.y = (float)hmdPose.translation.data[1]; |
||||
storePos.z = (float)-hmdPose.translation.data[2]; |
||||
storeRot.set((float)hmdPose.rotation.data[1], |
||||
(float)hmdPose.rotation.data[2], |
||||
(float)hmdPose.rotation.data[3], |
||||
(float)hmdPose.rotation.data[0]); |
||||
if( storeRot.equals(Quaternion.ZERO) ) storeRot.set(Quaternion.DIRECTION_Z); |
||||
} |
||||
|
||||
@Override |
||||
public void updatePose() { |
||||
if( context == null || displayConfig == null ) return; |
||||
OsvrClientKitLibrary.osvrClientUpdate(context); |
||||
OsvrDisplayLibrary.osvrClientGetViewerPose(displayConfig, FIRST_VIEWER, hmdPose.getPointer()); |
||||
VRinput.updateControllerStates(); |
||||
hmdPose.read(); |
||||
} |
||||
|
||||
@Override |
||||
public Matrix4f getHMDMatrixProjectionLeftEye(Camera cam) { |
||||
if( eyeLeftInfo == null ) return cam.getProjectionMatrix(); |
||||
if( eyeMatrix[EYE_LEFT] == null ) { |
||||
FloatBuffer tfb = FloatBuffer.allocate(16); |
||||
com.jme3.system.osvr.osvrdisplay.OsvrDisplayLibrary.osvrClientGetViewerEyeSurfaceProjectionMatrixf(displayConfig, 0, (byte)EYE_LEFT, 0, cam.getFrustumNear(), cam.getFrustumFar(), (short)0, tfb); |
||||
eyeMatrix[EYE_LEFT] = new Matrix4f(); |
||||
eyeMatrix[EYE_LEFT].set(tfb.get(0), tfb.get(4), tfb.get(8), tfb.get(12), |
||||
tfb.get(1), tfb.get(5), tfb.get(9), tfb.get(13), |
||||
tfb.get(2), tfb.get(6), tfb.get(10), tfb.get(14), |
||||
tfb.get(3), tfb.get(7), tfb.get(11), tfb.get(15)); |
||||
} |
||||
return eyeMatrix[EYE_LEFT]; |
||||
} |
||||
|
||||
@Override |
||||
public Matrix4f getHMDMatrixProjectionRightEye(Camera cam) { |
||||
if( eyeRightInfo == null ) return cam.getProjectionMatrix(); |
||||
if( eyeMatrix[EYE_RIGHT] == null ) { |
||||
FloatBuffer tfb = FloatBuffer.allocate(16); |
||||
com.jme3.system.osvr.osvrdisplay.OsvrDisplayLibrary.osvrClientGetViewerEyeSurfaceProjectionMatrixf(displayConfig, 0, (byte)EYE_RIGHT, 0, cam.getFrustumNear(), cam.getFrustumFar(), (short)0, tfb); |
||||
eyeMatrix[EYE_RIGHT] = new Matrix4f(); |
||||
eyeMatrix[EYE_RIGHT].set(tfb.get(0), tfb.get(4), tfb.get(8), tfb.get(12), |
||||
tfb.get(1), tfb.get(5), tfb.get(9), tfb.get(13), |
||||
tfb.get(2), tfb.get(6), tfb.get(10), tfb.get(14), |
||||
tfb.get(3), tfb.get(7), tfb.get(11), tfb.get(15)); |
||||
} |
||||
return eyeMatrix[EYE_RIGHT]; |
||||
} |
||||
|
||||
@Override |
||||
public Vector3f getHMDVectorPoseLeftEye() { |
||||
if( hmdPoseLeftEyeVec == null ) { |
||||
hmdPoseLeftEyeVec = new Vector3f(); |
||||
hmdPoseLeftEyeVec.x = 0.065f * -0.5f; |
||||
if( flipEyes == false ) hmdPoseLeftEyeVec.x *= -1f; // it seems these need flipping
|
||||
} |
||||
return hmdPoseLeftEyeVec; |
||||
} |
||||
|
||||
@Override |
||||
public Vector3f getHMDVectorPoseRightEye() { |
||||
if( hmdPoseRightEyeVec == null ) { |
||||
hmdPoseRightEyeVec = new Vector3f(); |
||||
hmdPoseRightEyeVec.x = 0.065f * 0.5f; |
||||
if( flipEyes == false ) hmdPoseRightEyeVec.x *= -1f; // it seems these need flipping
|
||||
} |
||||
return hmdPoseRightEyeVec; |
||||
} |
||||
|
||||
@Override |
||||
public Vector3f getSeatedToAbsolutePosition() { |
||||
return Vector3f.ZERO; |
||||
} |
||||
|
||||
@Override |
||||
public Matrix4f getHMDMatrixPoseLeftEye() { |
||||
// not actually used internally...
|
||||
/*if( hmdPoseLeftEye != null ) { |
||||
return hmdPoseLeftEye; |
||||
} else { |
||||
FloatBuffer mat = FloatBuffer.allocate(16); |
||||
OsvrDisplayLibrary.osvrClientGetViewerEyeViewMatrixf(displayConfig, FIRST_VIEWER, (byte)EYE_LEFT, |
||||
(short)(OsvrMatrixConventionsLibrary.OSVR_MatrixVectorFlags.OSVR_MATRIX_COLVECTORS | |
||||
OsvrMatrixConventionsLibrary.OSVR_MatrixOrderingFlags.OSVR_MATRIX_COLMAJOR), tempfb); |
||||
hmdPoseLeftEye = new Matrix4f(tempfb.array()); |
||||
return hmdPoseLeftEye; |
||||
}*/ |
||||
return null; |
||||
} |
||||
|
||||
@Override |
||||
public Matrix4f getHMDMatrixPoseRightEye() { |
||||
// not actually used internally...
|
||||
/*if( hmdPoseRightEye != null ) { |
||||
return hmdPoseRightEye; |
||||
} else { |
||||
OsvrDisplayLibrary.osvrClientGetViewerEyeViewMatrixf(displayConfig, FIRST_VIEWER, (byte)EYE_RIGHT, |
||||
(short)(OsvrMatrixConventionsLibrary.OSVR_MatrixVectorFlags.OSVR_MATRIX_COLVECTORS | |
||||
OsvrMatrixConventionsLibrary.OSVR_MatrixOrderingFlags.OSVR_MATRIX_COLMAJOR), tempfb); |
||||
hmdPoseRightEye = new Matrix4f(tempfb.array()); |
||||
return hmdPoseRightEye; |
||||
}*/ |
||||
return null; |
||||
} |
||||
|
||||
@Override |
||||
public HmdType getType() { |
||||
return HmdType.OSVR; |
||||
} |
||||
} |
||||
|
Loading…
Reference in new issue