fbo_t CreateFBO(int width, int height) { int i; fbo_t fbo; fbo.size.width = width; fbo.size.height = height; glGenFramebuffersEXT(1, &fbo.framebuffer); glGenTextures(1, &fbo.depth_texture); glBindTexture(GL_TEXTURE_2D, fbo.depth_texture); 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); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT24, width, height, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, NULL); ovrHmd_CreateSwapTextureSetGL(hmd, GL_RGBA, width, height, &fbo.color_textures); for( i = 0; i < fbo.color_textures->TextureCount; ++i ) { ovrGLTexture* tex = (ovrGLTexture*)&fbo.color_textures->Textures[i]; glBindTexture(GL_TEXTURE_2D, tex->OGL.TexId); 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); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); } return fbo; }
///@brief Called once a GL context has been set up. void OVRSDK06AppSkeleton::initVR(bool swapBackBufferDims) { if (m_Hmd == NULL) return; for (int i = 0; i < 2; ++i) { if (m_pTexSet[i]) { ovrHmd_DestroySwapTextureSet(m_Hmd, m_pTexSet[i]); m_pTexSet[i] = nullptr; } } // Set up eye fields of view ovrLayerEyeFov& layer = m_layerEyeFov; layer.Header.Type = ovrLayerType_EyeFov; layer.Header.Flags = ovrLayerFlag_TextureOriginAtBottomLeft; // Create eye render target textures and FBOs for (ovrEyeType eye = ovrEyeType::ovrEye_Left; eye < ovrEyeType::ovrEye_Count; eye = static_cast<ovrEyeType>(eye + 1)) { const ovrFovPort& fov = layer.Fov[eye] = m_Hmd->MaxEyeFov[eye]; const ovrSizei& size = layer.Viewport[eye].Size = ovrHmd_GetFovTextureSize(m_Hmd, eye, fov, 1.f); layer.Viewport[eye].Pos = { 0, 0 }; LOG_INFO("Eye %d tex : %dx%d @ (%d,%d)", eye, size.w, size.h, layer.Viewport[eye].Pos.x, layer.Viewport[eye].Pos.y); ovrEyeRenderDesc & erd = m_eyeRenderDescs[eye]; erd = ovrHmd_GetRenderDesc(m_Hmd, eye, m_Hmd->MaxEyeFov[eye]); ovrMatrix4f ovrPerspectiveProjection = ovrMatrix4f_Projection(erd.Fov, .1f, 10000.f, ovrProjection_RightHanded); m_eyeProjections[eye] = glm::transpose(glm::make_mat4(&ovrPerspectiveProjection.M[0][0])); m_eyeOffsets[eye] = erd.HmdToEyeViewOffset; // Allocate the frameBuffer that will hold the scene, and then be // re-rendered to the screen with distortion if (!OVR_SUCCESS(ovrHmd_CreateSwapTextureSetGL(m_Hmd, GL_RGBA, size.w, size.h, &m_pTexSet[eye]))) { LOG_ERROR("Unable to create swap textures"); return; } ovrSwapTextureSet& swapSet = *m_pTexSet[eye]; for (int i = 0; i < swapSet.TextureCount; ++i) { const ovrGLTexture& ovrTex = (ovrGLTexture&)swapSet.Textures[i]; glBindTexture(GL_TEXTURE_2D, ovrTex.OGL.TexId); 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); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); } // Manually assemble swap FBO m_swapFBO.w = size.w; m_swapFBO.h = size.h; glGenFramebuffers(1, &m_swapFBO.id); glBindFramebuffer(GL_FRAMEBUFFER, m_swapFBO.id); const int idx = 0; const ovrGLTextureData* pGLData = reinterpret_cast<ovrGLTextureData*>(&swapSet.Textures[idx]); m_swapFBO.tex = pGLData->TexId; glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_swapFBO.tex, 0); m_swapFBO.depth = 0; glGenRenderbuffers(1, &m_swapFBO.depth); glBindRenderbuffer(GL_RENDERBUFFER, m_swapFBO.depth); glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, size.w, size.h); glBindRenderbuffer(GL_RENDERBUFFER, 0); glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, m_swapFBO.depth); // Check status { const GLenum status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT); if (status != GL_FRAMEBUFFER_COMPLETE_EXT) { LOG_ERROR("Framebuffer status incomplete: %d %x", status, status); } } glBindFramebuffer(GL_FRAMEBUFFER, 0); layer.ColorTexture[eye] = m_pTexSet[eye]; } // Mirror texture for displaying to desktop window if (m_pMirrorTex) { ovrHmd_DestroyMirrorTexture(m_Hmd, m_pMirrorTex); } const ovrEyeType eye = ovrEyeType::ovrEye_Left; const ovrFovPort& fov = layer.Fov[eye] = m_Hmd->MaxEyeFov[eye]; const ovrSizei& size = layer.Viewport[eye].Size = ovrHmd_GetFovTextureSize(m_Hmd, eye, fov, 1.f); ovrResult result = ovrHmd_CreateMirrorTextureGL(m_Hmd, GL_RGBA, size.w, size.h, &m_pMirrorTex); if (!OVR_SUCCESS(result)) { LOG_ERROR("Unable to create mirror texture"); return; } // Manually assemble mirror FBO m_mirrorFBO.w = size.w; m_mirrorFBO.h = size.h; glGenFramebuffers(1, &m_mirrorFBO.id); glBindFramebuffer(GL_FRAMEBUFFER, m_mirrorFBO.id); const ovrGLTextureData* pMirrorGLData = reinterpret_cast<ovrGLTextureData*>(m_pMirrorTex); m_mirrorFBO.tex = pMirrorGLData->TexId; glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_mirrorFBO.tex, 0); // Check status { const GLenum status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT); if (status != GL_FRAMEBUFFER_COMPLETE_EXT) { LOG_ERROR("Framebuffer status incomplete: %d %x", status, status); } } glBindFramebuffer(GL_FRAMEBUFFER, 0); glBindTexture(GL_TEXTURE_2D, 0); glEnable(GL_DEPTH_TEST); }