// Copyright (c) 2012-2017 VideoStitch SAS // Copyright (c) 2018 stitchEm #pragma once #include "renderer.hpp" #include "common-config.hpp" #include #include #include #include "OVR_CAPI_GL.h" struct DepthBuffer : public QOpenGLFunctions { GLuint texId; explicit DepthBuffer(ovrSizei size) { initializeOpenGLFunctions(); glGenTextures(1, &texId); glBindTexture(GL_TEXTURE_2D, 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); glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT24, size.w, size.h, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, NULL); } ~DepthBuffer() { if (texId) { glDeleteTextures(1, &texId); texId = 0; } } }; struct TextureBuffer : public QOpenGLFunctions { ovrSession session; ovrTextureSwapChain textureSwapChain; GLuint fboId; ovrSizei texSize; TextureBuffer(ovrSession session, ovrSizei size) : session(session), texSize(size) { initializeOpenGLFunctions(); ovrTextureSwapChainDesc desc = {}; desc.Type = ovrTexture_2D; desc.Format = OVR_FORMAT_R8G8B8A8_UNORM_SRGB; desc.ArraySize = 1; desc.Width = size.w; desc.Height = size.h; desc.MipLevels = 1; desc.SampleCount = 1; desc.StaticImage = ovrFalse; ovr_CreateTextureSwapChainGL(session, &desc, &textureSwapChain); int length = 0; ovr_GetTextureSwapChainLength(session, textureSwapChain, &length); for (int i = 0; i < length; ++i) { GLuint texId = 0; ovr_GetTextureSwapChainBufferGL(session, textureSwapChain, i, &texId); glBindTexture(GL_TEXTURE_2D, 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); } glGenFramebuffers(1, &fboId); } ~TextureBuffer() { if (textureSwapChain) { ovr_DestroyTextureSwapChain(session, textureSwapChain); textureSwapChain = nullptr; } if (fboId) { glDeleteFramebuffers(1, &fboId); fboId = 0; } } ovrSizei GetSize(void) const { return texSize; } void SetAndClearRenderSurface(DepthBuffer* dbuffer) { GLuint texId = 0; ovr_GetTextureSwapChainBufferGL(session, textureSwapChain, -1, &texId); glBindFramebuffer(GL_FRAMEBUFFER, fboId); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texId, 0); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, dbuffer->texId, 0); glViewport(0, 0, texSize.w, texSize.h); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); } void UnsetRenderSurface() { glBindFramebuffer(GL_FRAMEBUFFER, fboId); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, 0, 0); } void commitTexture() { ovr_CommitTextureSwapChain(session, textureSwapChain); } }; class VS_COMMON_EXPORT OculusRenderer : public Renderer { Q_OBJECT public: OculusRenderer(); ~OculusRenderer(); bool initializeOculus(); void configureRendering(int w, int h, bool mirror); virtual void render(); void startTimer() { renderTimer.start(); } GLuint getMirrorTextureId() const; signals: void fpsChanged(const QString); void orientationChanged(double yaw, double pitch, double roll); void renderingConfigured(); private: void notifyOrientation(ovrQuatf newOrientation); private: std::array eyeRenderTexture; std::array eyeDepthBuffer; ovrMirrorTexture mirrorTexture; ovrSession session; ovrGraphicsLuid luid; ovrHmdDesc hmdDesc; // eye pose and fov ovrVector3f viewOffset[2]; ovrEyeRenderDesc eyeRenderDesc[2]; int nbRenderedFrames; QElapsedTimer renderTimer; bool openglInitialized; };