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;
static double observer_x = 0.0;
-static double observer_x_normalize = 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_normalize = 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_normalize = 0.0;
+static double observer_z_reset = 0.0;
+static double hand_z_reset = 0.0;
-int init_ovr(void)
+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");
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;
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);
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;
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))
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;
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);
y = layer.RenderPose[eye].Position.y;
z = layer.RenderPose[eye].Position.z;
- /* normalize height to game's observer, if requrested by user */
+ /* reset to game's observer, if requrested by user */
observer_x = x;
- x += observer_x_normalize;
observer_y = y;
- y += observer_y_normalize;
observer_z = z;
- z += observer_z_normalize;
+ 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);
{
// 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
void render_mirror_ovr(int view_width, int view_height)
{
int view_x = 0, view_y = 0;
- int new_width, new_height;
- int eye = 0; /* left eye */
- int curIndex;
- GLuint chainTexId;
+ 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 * TextureSize[eye].w > view_width * TextureSize[eye].h) {
- new_height = view_width * TextureSize[eye].h / TextureSize[eye].w;
+// 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 * TextureSize[eye].w < view_width * TextureSize[eye].h) {
- new_width = view_height * TextureSize[eye].w / TextureSize[eye].h;
- view_x = view_x + view_width / 2 - new_width / 2;
- view_width = new_width;
- }
+// } 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 */
+ glBindFramebuffer(GL_FRAMEBUFFER, 0);
+
glClearColor(0.0, 0.0, 0.0, 1.0);
glClear(GL_COLOR_BUFFER_BIT);
- /* orthogonal viewport */
- glViewport((GLsizei)view_x, (GLsizei)view_y, (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);
-
- /* get texture from OVR */
- ovr_GetTextureSwapChainCurrentIndex(session, textureSwapChain[eye], &curIndex);
- ovr_GetTextureSwapChainBufferGL(session, textureSwapChain[eye], curIndex, &chainTexId);
+ /* 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);
+}
- /* 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);
+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;
}
-void normalize_observer_ovr(void)
+int should_quit_ovr(void)
{
- observer_x_normalize = -observer_x;
- observer_y_normalize = -observer_y;
- observer_z_normalize = -observer_z;
+ ovrSessionStatus sessionStatus;
+ ovrResult result;
+
+ result = ovr_GetSessionStatus(session, &sessionStatus);
+
+ if (OVR_SUCCESS(result))
+ return sessionStatus.ShouldQuit;
+ return 0;
}
void exit_ovr(void)
fboId[eye] = 0;
}
}
+ if (mirrorFBO) {
+ glDeleteFramebuffers(1, &mirrorFBO);
+ mirrorFBO = 0;
+ }
if (session) {
ovr_Destroy(session);