OVR: Show mirror of single eye only
[mercenary-reloaded.git] / src / libovr / ovr.c
index 79fd874..8a9007f 100755 (executable)
@@ -95,17 +95,34 @@ static ovrHmdDesc hmdDesc;
 static ovrSizei TextureSize[2];
 static ovrTextureSwapChain textureSwapChain[2] = { NULL, NULL };
 static GLuint fboId[2] = { 0, 0 };
+static GLuint mirrorFBO = 0;
+static int mirror_width;
+static int mirror_height;
 static ovrEyeRenderDesc eyeRenderDesc[2];
 static ovrPosef hmdToEyeViewPose[2];
+static ovrPosef headPose;
+static ovrPosef handPose;
+static ovrInputState inputState;
 static ovrLayerEyeFov layer;
+static int multisampling;
 static long long frameIndex = 0;
-
-int init_ovr(void)
+static double observer_x = 0.0;
+static double observer_x_reset = 0.0;
+static double hand_x_reset = 0.0;
+static double observer_y = 0.0;
+static double observer_y_reset = 0.0;
+static double hand_y_reset = 0.0;
+static double observer_z = 0.0;
+static double observer_z_reset = 0.0;
+static double hand_z_reset = 0.0;
+
+int init_ovr(int _multisampling)
 {
-       int sample_count = 1; // FIXME: make MSAA
        ovrResult result;
        int eye;
 
+       multisampling = _multisampling;
+
        glewExperimental = GL_TRUE;
        if (glewInit() != GLEW_OK) {
                print_error("Failed to init GLEW\n");
@@ -138,12 +155,13 @@ int init_ovr(void)
        layer.Header.Type      = ovrLayerType_EyeFov;
        layer.Header.Flags     = 0;
 
+       /* do we need this??? seems to work without */
+       if (multisampling > 1)
+               glEnable(GL_MULTISAMPLE);
+
        /* create render buffers */
        for (eye = 0; eye < 2; eye++) {
                TextureSize[eye] = ovr_GetFovTextureSize(session, (eye == 0) ? ovrEye_Left : ovrEye_Right, hmdDesc.DefaultEyeFov[eye], 1.0);
-#warning hacking resolution
-//TextureSize[eye].w *= 2;
-//TextureSize[eye].h *= 2;
                ovrTextureSwapChainDesc desc;
                int length, i;
                GLuint chainTexId;
@@ -155,19 +173,19 @@ int init_ovr(void)
                desc.Width = TextureSize[eye].w;
                desc.Height = TextureSize[eye].h;
                desc.MipLevels = 1;
-               desc.SampleCount = sample_count;
+               desc.SampleCount = (multisampling > 1) ? multisampling : 1;
                desc.StaticImage = ovrFalse;
 
                result = ovr_CreateTextureSwapChainGL(session, &desc, &textureSwapChain[eye]);
                if (OVR_FAILURE(result)) {
-                       print_error("ovr_CreateTextureSwapChainGL() failed!\n");
+                       print_error("ovr_CreateTextureSwapChainGL() failed! (error %d)\n", result);
                        goto error;
                }
 
                ovr_GetTextureSwapChainLength(session, textureSwapChain[eye], &length);
                for (i = 0; i < length; i++) {
                        ovr_GetTextureSwapChainBufferGL(session, textureSwapChain[eye], i, &chainTexId);
-                       glBindTexture(GL_TEXTURE_2D, chainTexId);
+                       glBindTexture((multisampling > 1) ? GL_TEXTURE_2D_MULTISAMPLE : GL_TEXTURE_2D, chainTexId);
                        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
                        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
                        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
@@ -187,6 +205,34 @@ int init_ovr(void)
                layer.Viewport[eye].Size.h = TextureSize[eye].h;
        }
 
+       ovrMirrorTexture mirrorTexture = NULL;
+       ovrMirrorTextureDesc desc;
+       memset(&desc, 0, sizeof(desc));
+       desc.Width = mirror_width = TextureSize[0].w;
+       desc.Height = mirror_height = TextureSize[0].h;
+       desc.Format = OVR_FORMAT_R8G8B8A8_UNORM_SRGB;
+       desc.MirrorOptions =
+//             ovrMirrorOption_PostDistortion |
+               ovrMirrorOption_LeftEyeOnly |
+               ovrMirrorOption_IncludeGuardian |
+               ovrMirrorOption_IncludeNotifications |
+               ovrMirrorOption_IncludeSystemGui;
+
+       /* Create mirror texture and an FBO used to copy mirror texture to back buffer */
+       result = ovr_CreateMirrorTextureWithOptionsGL(session, &desc, &mirrorTexture);
+       if (!OVR_SUCCESS(result)) {
+               print_error("ovr_CreateMirrorTextureWithOptionsGL() failed! (error %d)\n", result);
+               goto error;
+       }
+
+       /* Configure the mirror read buffer */
+       GLuint texId;
+       ovr_GetMirrorTextureBufferGL(session, mirrorTexture, &texId);
+
+       glGenFramebuffers(1, &mirrorFBO);
+       glBindFramebuffer(GL_READ_FRAMEBUFFER, mirrorFBO);
+       glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texId, 0);
+       glFramebufferRenderbuffer(GL_READ_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, 0);
 
        return 0;
 
@@ -195,14 +241,91 @@ error:
        return -EINVAL;
 }
 
-void begin_render_ovr(void)
+void get_poses_ovr(int *button_a, int *button_b, int *button_x, int *button_y, int *button_menu, int *button_left_trigger, int *button_right_trigger, int *button_left_thumb, int *button_right_thumb, double *hand_right_x, double *hand_right_y, double *hand_right_z, double *hand_right_yaw, double *hand_right_pitch, double *hand_right_roll, double *stick_left_x, double *stick_left_y, double *stick_right_x, double *stick_right_y, double *head_yaw, double *head_pitch, double *head_roll)
 {      
        ovrResult result;
+       float yaw, pitch, roll;
+       double x, y, z;
+       unsigned int hand_mask = (ovrStatus_OrientationTracked | ovrStatus_PositionTracked);
+       unsigned int hand_flags = (ovrStatus_OrientationTracked | ovrStatus_PositionTracked);
 
        /* Get both eye poses simultaneously, with IPD offset already included. */
-       double displayMidpointSeconds = ovr_GetPredictedDisplayTime(session, 0);
+       double displayMidpointSeconds = ovr_GetPredictedDisplayTime(session, frameIndex);
        ovrTrackingState hmdState = ovr_GetTrackingState(session, displayMidpointSeconds, ovrTrue);
        ovr_CalcEyePoses(hmdState.HeadPose.ThePose, hmdToEyeViewPose, layer.RenderPose);
+       /* Grab hand poses useful for rendering head/hand or controller representation */
+       headPose = hmdState.HeadPose.ThePose;
+       handPose = headPose;
+//     if ((hmdState.HandStatusFlags[ovrHand_Left] & hand_mask) == hand_flags)
+//             handPose = hmdState.HandPoses[ovrHand_Left].ThePose;
+       if ((hmdState.HandStatusFlags[ovrHand_Right] & hand_mask) == hand_flags)
+               handPose = hmdState.HandPoses[ovrHand_Right].ThePose;
+       x = handPose.Position.x;
+       y = handPose.Position.y;
+       z = handPose.Position.z;
+       x += hand_x_reset;
+       y += hand_y_reset;
+       z += hand_z_reset;
+       *hand_right_x = x / 0.0254;
+       *hand_right_y = y / 0.0254;
+       *hand_right_z = z / 0.0254;
+       ovrOrientation2yawpitchroll(headPose.Orientation, &yaw, &pitch, &roll);
+       *head_yaw = yaw;
+       *head_pitch = pitch;
+       *head_roll = roll;
+       ovrOrientation2yawpitchroll(handPose.Orientation, &yaw, &pitch, &roll);
+       *hand_right_yaw = yaw;
+       *hand_right_pitch = pitch;
+       *hand_right_roll = roll;
+
+       result = ovr_GetInputState(session, ovrControllerType_Active, &inputState);
+       if (OVR_SUCCESS(result)) {
+               if (inputState.Buttons & ovrButton_A)
+                       *button_a = 1;
+               else
+                       *button_a = 0;
+               if (inputState.Buttons & ovrButton_B)
+                       *button_b = 1;
+               else
+                       *button_b = 0;
+               if (inputState.Buttons & ovrButton_X)
+                       *button_x = 1;
+               else
+                       *button_x = 0;
+               if (inputState.Buttons & ovrButton_Y)
+                       *button_y = 1;
+               else
+                       *button_y = 0;
+               if (inputState.Buttons & ovrButton_Enter)
+                       *button_menu = 1;
+               else
+                       *button_menu = 0;
+               if (inputState.Buttons & ovrButton_LThumb)
+                       *button_left_thumb = 1;
+               else
+                       *button_left_thumb = 0;
+               if (inputState.Buttons & ovrButton_RThumb)
+                       *button_right_thumb = 1;
+               else
+                       *button_right_thumb = 0;
+               if (inputState.IndexTrigger[ovrHand_Left] >= 0.8)
+                       *button_left_trigger = 1;
+               else
+                       *button_left_trigger = 0;
+               if (inputState.IndexTrigger[ovrHand_Right] >= 0.8)
+                       *button_right_trigger = 1;
+               else
+                       *button_right_trigger = 0;
+               *stick_left_x = inputState.ThumbstickNoDeadzone[ovrHand_Left].x;
+               *stick_left_y = inputState.ThumbstickNoDeadzone[ovrHand_Left].y;
+               *stick_right_x = inputState.ThumbstickNoDeadzone[ovrHand_Right].x;
+               *stick_right_y = inputState.ThumbstickNoDeadzone[ovrHand_Right].y;
+       }
+}
+
+void begin_render_ovr(void)
+{
+       ovrResult result;
 
        result = ovr_WaitToBeginFrame(session, frameIndex);
        if (!OVR_SUCCESS(result))
@@ -212,7 +335,9 @@ void begin_render_ovr(void)
                print_info("Failed to begin frame (error %d)\n", result);
 }
 
-void begin_render_ovr_eye(int eye)
+static int initial_observer_reset = 1;
+
+void begin_render_ovr_eye(int eye, double *camera_x, double *camera_y, double *camera_z)
 {
        int curIndex;
        GLuint chainTexId;
@@ -223,7 +348,7 @@ void begin_render_ovr_eye(int eye)
        ovr_GetTextureSwapChainCurrentIndex(session, textureSwapChain[eye], &curIndex);
        ovr_GetTextureSwapChainBufferGL(session, textureSwapChain[eye], curIndex, &chainTexId);
        glBindFramebuffer(GL_FRAMEBUFFER, fboId[eye]);
-       glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, chainTexId, 0);
+       glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, (multisampling > 1) ? GL_TEXTURE_2D_MULTISAMPLE : GL_TEXTURE_2D, chainTexId, 0);
 
        glViewport(0, 0, TextureSize[eye].w, TextureSize[eye].h);
        glMatrixMode(GL_PROJECTION);
@@ -240,11 +365,26 @@ void begin_render_ovr_eye(int eye)
        y = layer.RenderPose[eye].Position.y;
        z = layer.RenderPose[eye].Position.z;
 
+       /* reset to game's observer, if requrested by user */
+       observer_x = x;
+       observer_y = y;
+       observer_z = z;
+       if (initial_observer_reset) {
+               initial_observer_reset = 0;
+               reset_observer_ovr();
+       }
+       x += observer_x_reset;
+       y += observer_y_reset;
+       z += observer_z_reset;
+
        glRotatef(-roll / M_PI * 180.0,0,0,1);
        glRotatef(-pitch / M_PI * 180.0,1,0,0);
        glRotatef(-yaw / M_PI * 180.0,0,1,0);
 
-       glTranslated(-x / 0.0254, -y / 0.0254, -z / 0.0254); /* convert to inch */
+       *camera_x = x / 0.0254;
+       *camera_y = y / 0.0254;
+       *camera_z = z / 0.0254;
+       glTranslated(-(*camera_x), -(*camera_y), -(*camera_z)); /* convert to inch */
 
        glMatrixMode(GL_MODELVIEW);
 
@@ -257,8 +397,8 @@ void end_render_ovr_eye(int eye)
 {
        // unset render surface
        glBindFramebuffer(GL_FRAMEBUFFER, fboId[eye]);
-       glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0);
-       glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, 0, 0);
+       glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, (multisampling > 1) ? GL_TEXTURE_2D_MULTISAMPLE : GL_TEXTURE_2D, 0, 0);
+       glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, (multisampling > 1) ? GL_TEXTURE_2D_MULTISAMPLE : GL_TEXTURE_2D, 0, 0);
        glBindFramebuffer(GL_FRAMEBUFFER, 0);
 
        // Commit the changes to the texture swap chain
@@ -278,40 +418,62 @@ void end_render_ovr(void)
 
 void render_mirror_ovr(int view_width, int view_height)
 {
-       int eye = 0; /* left eye */
-       int curIndex;
-       GLuint chainTexId;
+       int view_x = 0, view_y = 0;
+       int new_height; //, new_width;
+
+       /* avoid division by zero, if one dimension is too small */
+       if (view_width < 1 || view_height < 1)
+               return;
+
+       /* calculate a viewport that has apect of TextureSize */
+//     if (view_height * mirror_width > view_width * mirror_height) {
+               new_height = view_width * mirror_height / mirror_width;
+               view_y = view_y + view_height / 2 - new_height / 2;
+               view_height = new_height;
+//     } else if (view_height * mirror_width < view_width * mirror_height) {
+//             new_width = view_height * mirror_width / mirror_height;
+//             view_x = view_x + view_width / 2 - new_width / 2;
+//             view_width = new_width;
+//     }
+
+       /* avoid views that are too small */
+       if (view_width < 1 || view_height < 1)
+               return;
 
-       /* clear screen */
-       glClearColor(1.0, 0.0, 0.0, 1.0);
+       glBindFramebuffer(GL_FRAMEBUFFER, 0);
+
+       glClearColor(0.0, 0.0, 0.0, 1.0);
        glClear(GL_COLOR_BUFFER_BIT);
 
-       /* orthogonal viewport */
-       glViewport((GLsizei)0, (GLsizei)0, (GLsizei)view_width, (GLsizei)view_height);
-       glMatrixMode(GL_PROJECTION);
-       glLoadIdentity();
-       glOrtho(-1.0, 1.0, -1.0, 1.0, -1.0, 1.0);
-       glMatrixMode(GL_MODELVIEW);
+       /* Blit mirror texture to back buffer */
+       glBindFramebuffer(GL_READ_FRAMEBUFFER, mirrorFBO);
+       glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
+       glBlitFramebuffer(0, mirror_height, mirror_width, 0,
+               view_x, view_y, view_x + view_width, view_y + view_height,
+               GL_COLOR_BUFFER_BIT, GL_LINEAR);
+       glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
+}
 
-       /* get texture from OVR */
-       ovr_GetTextureSwapChainCurrentIndex(session, textureSwapChain[eye], &curIndex);
-       ovr_GetTextureSwapChainBufferGL(session, textureSwapChain[eye], curIndex, &chainTexId);
+void reset_observer_ovr(void)
+{
+       observer_x_reset = -observer_x;
+       observer_y_reset = -observer_y;
+       observer_z_reset = -observer_z;
+       hand_x_reset = -observer_x;
+       hand_y_reset = -observer_y;
+       hand_z_reset = -observer_z;
+}
 
-       /* render mirror from texture */
-       glEnable(GL_TEXTURE_2D);
-       glBindTexture(GL_TEXTURE_2D, chainTexId);
-       glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);  /* no modulation with color */
-       glBegin(GL_QUADS);
-       glTexCoord2f(0, 1);
-       glVertex3f(-1.0, -1.0, 0.0);
-       glTexCoord2f(1, 1);
-       glVertex3f(1.0, -1.0, 0.0);
-       glTexCoord2f(1, 0);
-       glVertex3f(1.0, 1.0, 0.0);
-       glTexCoord2f(0, 0);
-       glVertex3f(-1.0, 1.0, 0.0);
-       glEnd();
-       glDisable(GL_TEXTURE_2D);
+int should_quit_ovr(void)
+{
+       ovrSessionStatus sessionStatus;
+       ovrResult result;
+
+       result = ovr_GetSessionStatus(session, &sessionStatus);
+
+       if (OVR_SUCCESS(result))
+               return sessionStatus.ShouldQuit;
+       return 0;
 }
 
 void exit_ovr(void)
@@ -329,6 +491,10 @@ void exit_ovr(void)
                        fboId[eye] = 0;
                }
        }
+       if (mirrorFBO) {
+               glDeleteFramebuffers(1, &mirrorFBO);
+               mirrorFBO = 0;
+       }
 
        if (session) {
                ovr_Destroy(session);