|
@@ -8,11 +8,17 @@ package com.jme3.input.vr;
|
|
|
import com.jme3.app.VREnvironment;
|
|
|
import com.jme3.math.*;
|
|
|
import com.jme3.renderer.Camera;
|
|
|
+import com.jme3.texture.FrameBuffer;
|
|
|
+import com.jme3.texture.Image;
|
|
|
+import com.jme3.texture.Texture2D;
|
|
|
+import org.lwjgl.BufferUtils;
|
|
|
import org.lwjgl.PointerBuffer;
|
|
|
import org.lwjgl.ovr.*;
|
|
|
|
|
|
+import java.nio.IntBuffer;
|
|
|
import java.util.logging.Logger;
|
|
|
|
|
|
+import static org.lwjgl.BufferUtils.createPointerBuffer;
|
|
|
import static org.lwjgl.ovr.OVR.*;
|
|
|
import static org.lwjgl.ovr.OVRErrorCode.ovrSuccess;
|
|
|
import static org.lwjgl.ovr.OVRUtil.ovr_Detect;
|
|
@@ -81,6 +87,24 @@ public class OculusVR implements VRAPI {
|
|
|
*/
|
|
|
private final Matrix4f[] eyePoses = new Matrix4f[2];
|
|
|
|
|
|
+ // The size of the texture drawn onto the HMD
|
|
|
+ private int textureW;
|
|
|
+ private int textureH;
|
|
|
+
|
|
|
+ // Layers to render into
|
|
|
+ private PointerBuffer layers;
|
|
|
+ private OVRLayerEyeFov layer0;
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Chain texture set thing.
|
|
|
+ */
|
|
|
+ private long chain;
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Frame buffers we can draw into.
|
|
|
+ */
|
|
|
+ private FrameBuffer framebuffers[];
|
|
|
+
|
|
|
public OculusVR(VREnvironment environment) {
|
|
|
this.environment = environment;
|
|
|
}
|
|
@@ -226,7 +250,32 @@ public class OculusVR implements VRAPI {
|
|
|
|
|
|
@Override
|
|
|
public void destroy() {
|
|
|
- throw new UnsupportedOperationException();
|
|
|
+ // fovPorts: contents are managed by LibOVR, no need to do anything.
|
|
|
+
|
|
|
+ // Check if we've set up rendering - if so, clean that up.
|
|
|
+ if (chain != 0) {
|
|
|
+ // Destroy our set of huge buffer images.
|
|
|
+ ovr_DestroyTextureSwapChain(session, chain);
|
|
|
+
|
|
|
+ // Free up the layer
|
|
|
+ layer0.free();
|
|
|
+
|
|
|
+ // The layers array apparently takes care of itself (and crashes if we try to free it)
|
|
|
+ }
|
|
|
+
|
|
|
+ for (OVREyeRenderDesc eye : eyeRenderDesc) {
|
|
|
+ eye.free();
|
|
|
+ }
|
|
|
+ for (OVRMatrix4f projection : projections) {
|
|
|
+ projection.free();
|
|
|
+ }
|
|
|
+
|
|
|
+ hmdDesc.free();
|
|
|
+ sessionStatus.free();
|
|
|
+
|
|
|
+ // Wrap everything up
|
|
|
+ ovr_Destroy(session);
|
|
|
+ ovr_Shutdown();
|
|
|
}
|
|
|
|
|
|
@Override
|
|
@@ -305,6 +354,10 @@ public class OculusVR implements VRAPI {
|
|
|
throw new UnsupportedOperationException("Cannot use LibOVR without compositor!");
|
|
|
}
|
|
|
|
|
|
+ findHMDTextureSize();
|
|
|
+ setupLayers();
|
|
|
+ setupFramebuffers();
|
|
|
+
|
|
|
// TODO move initialization code here from VRViewManagerOculus
|
|
|
return true;
|
|
|
}
|
|
@@ -325,6 +378,114 @@ public class OculusVR implements VRAPI {
|
|
|
throw new UnsupportedOperationException("Not yet implemented!");
|
|
|
}
|
|
|
|
|
|
+ // Rendering-type stuff
|
|
|
+
|
|
|
+ public void findHMDTextureSize() {
|
|
|
+ // Texture sizes
|
|
|
+ float pixelScaling = 1.0f; // pixelsPerDisplayPixel
|
|
|
+
|
|
|
+ OVRSizei leftTextureSize = OVRSizei.malloc();
|
|
|
+ ovr_GetFovTextureSize(session, ovrEye_Left, fovPorts[ovrEye_Left], pixelScaling, leftTextureSize);
|
|
|
+ System.out.println("leftTextureSize W=" + leftTextureSize.w() + ", H=" + leftTextureSize.h());
|
|
|
+
|
|
|
+ OVRSizei rightTextureSize = OVRSizei.malloc();
|
|
|
+ ovr_GetFovTextureSize(session, ovrEye_Right, fovPorts[ovrEye_Right], pixelScaling, rightTextureSize);
|
|
|
+ System.out.println("rightTextureSize W=" + rightTextureSize.w() + ", H=" + rightTextureSize.h());
|
|
|
+
|
|
|
+ textureW = leftTextureSize.w() + rightTextureSize.w();
|
|
|
+ textureH = Math.max(leftTextureSize.h(), rightTextureSize.h());
|
|
|
+
|
|
|
+ leftTextureSize.free();
|
|
|
+ rightTextureSize.free();
|
|
|
+ }
|
|
|
+
|
|
|
+ private PointerBuffer setupTextureChain() {
|
|
|
+ // Set up the information for the texture buffer chain thing
|
|
|
+ OVRTextureSwapChainDesc swapChainDesc = OVRTextureSwapChainDesc.calloc()
|
|
|
+ .Type(ovrTexture_2D)
|
|
|
+ .ArraySize(1)
|
|
|
+ .Format(OVR_FORMAT_R8G8B8A8_UNORM_SRGB)
|
|
|
+ .Width(textureW)
|
|
|
+ .Height(textureH)
|
|
|
+ .MipLevels(1)
|
|
|
+ .SampleCount(1)
|
|
|
+ .StaticImage(false); // ovrFalse
|
|
|
+
|
|
|
+ // Create the chain
|
|
|
+ PointerBuffer textureSetPB = createPointerBuffer(1);
|
|
|
+ if (OVRGL.ovr_CreateTextureSwapChainGL(session, swapChainDesc, textureSetPB) != ovrSuccess) {
|
|
|
+ throw new RuntimeException("Failed to create Swap Texture Set");
|
|
|
+ }
|
|
|
+ chain = textureSetPB.get(0);
|
|
|
+ swapChainDesc.free();
|
|
|
+ System.out.println("done chain creation");
|
|
|
+
|
|
|
+ return textureSetPB;
|
|
|
+ }
|
|
|
+
|
|
|
+ public void setupLayers() {
|
|
|
+ PointerBuffer chainPtr = setupTextureChain();
|
|
|
+
|
|
|
+ //Layers
|
|
|
+ layer0 = OVRLayerEyeFov.calloc();
|
|
|
+ layer0.Header().Type(ovrLayerType_EyeFov);
|
|
|
+ layer0.Header().Flags(ovrLayerFlag_TextureOriginAtBottomLeft);
|
|
|
+
|
|
|
+ for (int eye = 0; eye < 2; eye++) {
|
|
|
+ OVRRecti viewport = OVRRecti.calloc();
|
|
|
+ viewport.Pos().x(0);
|
|
|
+ viewport.Pos().y(0);
|
|
|
+ viewport.Size().w(textureW);
|
|
|
+ viewport.Size().h(textureH);
|
|
|
+
|
|
|
+ layer0.ColorTexture(chainPtr);
|
|
|
+ layer0.Viewport(eye, viewport);
|
|
|
+ layer0.Fov(eye, fovPorts[eye]);
|
|
|
+
|
|
|
+ viewport.free();
|
|
|
+ // we update pose only when we have it in the render loop
|
|
|
+ }
|
|
|
+
|
|
|
+ layers = createPointerBuffer(1);
|
|
|
+ layers.put(0, layer0);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Create framebuffers bound to each of the eye textures
|
|
|
+ */
|
|
|
+ public void setupFramebuffers() {
|
|
|
+ // Find the chain length
|
|
|
+ IntBuffer length = BufferUtils.createIntBuffer(1);
|
|
|
+ ovr_GetTextureSwapChainLength(session, chain, length);
|
|
|
+ int chainLength = length.get();
|
|
|
+
|
|
|
+ System.out.println("chain length=" + chainLength);
|
|
|
+
|
|
|
+ // Create the frame buffers
|
|
|
+ framebuffers = new FrameBuffer[chainLength];
|
|
|
+ for (int i = 0; i < chainLength; i++) {
|
|
|
+ // find the GL texture ID for this texture
|
|
|
+ IntBuffer textureIdB = BufferUtils.createIntBuffer(1);
|
|
|
+ OVRGL.ovr_GetTextureSwapChainBufferGL(session, chain, i, textureIdB);
|
|
|
+ int textureId = textureIdB.get();
|
|
|
+
|
|
|
+ // TODO less hacky way of getting our texture into JMonkeyEngine
|
|
|
+ Image img = new Image();
|
|
|
+ img.setId(textureId);
|
|
|
+ img.setFormat(Image.Format.RGBA8);
|
|
|
+ img.setWidth(textureW);
|
|
|
+ img.setHeight(textureH);
|
|
|
+
|
|
|
+ Texture2D tex = new Texture2D(img);
|
|
|
+
|
|
|
+ FrameBuffer buffer = new FrameBuffer(textureW, textureH, 1);
|
|
|
+ buffer.setDepthBuffer(Image.Format.Depth);
|
|
|
+ buffer.setColorTexture(tex);
|
|
|
+
|
|
|
+ framebuffers[i] = buffer;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
// UTILITIES
|
|
|
// TODO move to helper class
|
|
|
|
|
@@ -382,16 +543,21 @@ public class OculusVR implements VRAPI {
|
|
|
}
|
|
|
|
|
|
// Getters, intended for VRViewManager.
|
|
|
- public OVRHmdDesc getHmdDesc() {
|
|
|
- return hmdDesc;
|
|
|
+
|
|
|
+ public long getSessionPointer() {
|
|
|
+ return session;
|
|
|
}
|
|
|
|
|
|
- public OVRFovPort[] getFovPorts() {
|
|
|
- return fovPorts;
|
|
|
+ public long getChain() {
|
|
|
+ return chain;
|
|
|
}
|
|
|
|
|
|
- public long getSessionPointer() {
|
|
|
- return session;
|
|
|
+ public FrameBuffer[] getFramebuffers() {
|
|
|
+ return framebuffers;
|
|
|
+ }
|
|
|
+
|
|
|
+ public PointerBuffer getLayers() {
|
|
|
+ return layers;
|
|
|
}
|
|
|
}
|
|
|
|