mirror of
https://thingvellir.net/git/overte
synced 2025-03-27 23:52:03 +01:00
Merge branch 'temp' into overlay
This commit is contained in:
commit
5c4fa77acd
25 changed files with 1014 additions and 578 deletions
4
cmake/externals/LibOVR/CMakeLists.txt
vendored
4
cmake/externals/LibOVR/CMakeLists.txt
vendored
|
@ -9,8 +9,8 @@ if (WIN32)
|
|||
|
||||
ExternalProject_Add(
|
||||
${EXTERNAL_NAME}
|
||||
URL http://static.oculus.com/sdk-downloads/ovr_sdk_win_0.5.0.1.zip
|
||||
URL_MD5 d3fc4c02db9be5ff08af4ef4c97b32f9
|
||||
URL http://static.oculus.com/sdk-downloads/0.6.0.0/1431634088/ovr_sdk_win_0.6.0.0.zip
|
||||
URL_MD5 a3dfdab037a854fdcf7e6033fa8d7028
|
||||
CONFIGURE_COMMAND ""
|
||||
BUILD_COMMAND ""
|
||||
INSTALL_COMMAND ""
|
||||
|
|
14
cmake/externals/boostconfig/CMakeLists.txt
vendored
14
cmake/externals/boostconfig/CMakeLists.txt
vendored
|
@ -3,13 +3,13 @@ string(TOUPPER ${EXTERNAL_NAME} EXTERNAL_NAME_UPPER)
|
|||
|
||||
include(ExternalProject)
|
||||
ExternalProject_Add(
|
||||
${EXTERNAL_NAME}
|
||||
URL https://github.com/boostorg/config/archive/boost-1.58.0.zip
|
||||
URL_MD5 42fa673bae2b7645a22736445e80eb8d
|
||||
CONFIGURE_COMMAND ""
|
||||
BUILD_COMMAND ""
|
||||
INSTALL_COMMAND ""
|
||||
LOG_DOWNLOAD 1
|
||||
${EXTERNAL_NAME}
|
||||
URL https://github.com/boostorg/config/archive/boost-1.58.0.zip
|
||||
URL_MD5 42fa673bae2b7645a22736445e80eb8d
|
||||
CONFIGURE_COMMAND ""
|
||||
BUILD_COMMAND ""
|
||||
INSTALL_COMMAND ""
|
||||
LOG_DOWNLOAD 1
|
||||
)
|
||||
|
||||
ExternalProject_Get_Property(${EXTERNAL_NAME} SOURCE_DIR)
|
||||
|
|
14
cmake/externals/oglplus/CMakeLists.txt
vendored
14
cmake/externals/oglplus/CMakeLists.txt
vendored
|
@ -3,13 +3,13 @@ string(TOUPPER ${EXTERNAL_NAME} EXTERNAL_NAME_UPPER)
|
|||
|
||||
include(ExternalProject)
|
||||
ExternalProject_Add(
|
||||
${EXTERNAL_NAME}
|
||||
URL http://softlayer-dal.dl.sourceforge.net/project/oglplus/oglplus-0.61.x/oglplus-0.61.0.zip
|
||||
URL_MD5 bb55038c36c660d2b6c7be380414fa60
|
||||
CONFIGURE_COMMAND ""
|
||||
BUILD_COMMAND ""
|
||||
INSTALL_COMMAND ""
|
||||
LOG_DOWNLOAD 1
|
||||
${EXTERNAL_NAME}
|
||||
GIT_REPOSITORY https://github.com/matus-chochlik/oglplus.git
|
||||
GIT_TAG a2681383928b1166f176512cbe0f95e96fe68d08
|
||||
CONFIGURE_COMMAND ""
|
||||
BUILD_COMMAND ""
|
||||
INSTALL_COMMAND ""
|
||||
LOG_DOWNLOAD 1
|
||||
)
|
||||
|
||||
ExternalProject_Get_Property(${EXTERNAL_NAME} SOURCE_DIR)
|
||||
|
|
43
cmake/macros/SetupHifiOpenGL.cmake
Normal file
43
cmake/macros/SetupHifiOpenGL.cmake
Normal file
|
@ -0,0 +1,43 @@
|
|||
|
||||
|
||||
macro(SETUP_HIFI_OPENGL)
|
||||
|
||||
if (APPLE)
|
||||
|
||||
# link in required OS X frameworks and include the right GL headers
|
||||
find_library(OpenGL OpenGL)
|
||||
target_link_libraries(${TARGET_NAME} ${OpenGL})
|
||||
|
||||
elseif (WIN32)
|
||||
|
||||
add_dependency_external_projects(glew)
|
||||
find_package(GLEW REQUIRED)
|
||||
target_include_directories(${TARGET_NAME} PUBLIC ${GLEW_INCLUDE_DIRS})
|
||||
target_link_libraries(${TARGET_NAME} ${GLEW_LIBRARIES} opengl32.lib)
|
||||
|
||||
if (USE_NSIGHT)
|
||||
# try to find the Nsight package and add it to the build if we find it
|
||||
find_package(NSIGHT)
|
||||
if (NSIGHT_FOUND)
|
||||
include_directories(${NSIGHT_INCLUDE_DIRS})
|
||||
add_definitions(-DNSIGHT_FOUND)
|
||||
target_link_libraries(${TARGET_NAME} "${NSIGHT_LIBRARIES}")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
elseif(ANDROID)
|
||||
|
||||
target_link_libraries(${TARGET_NAME} "-lGLESv3" "-lEGL")
|
||||
|
||||
else()
|
||||
|
||||
find_package(OpenGL REQUIRED)
|
||||
if (${OPENGL_INCLUDE_DIR})
|
||||
include_directories(SYSTEM "${OPENGL_INCLUDE_DIR}")
|
||||
endif()
|
||||
target_link_libraries(${TARGET_NAME} "${OPENGL_LIBRARY}")
|
||||
target_include_directories(${TARGET_NAME} PUBLIC ${OPENGL_INCLUDE_DIR})
|
||||
|
||||
endif()
|
||||
|
||||
endmacro()
|
|
@ -234,7 +234,6 @@ Hifi.Stats {
|
|||
width: perfText.width + 8
|
||||
height: perfText.height + 8
|
||||
color: root.bgColor;
|
||||
anchors.top: row.bottom + 16
|
||||
Text {
|
||||
x: 4; y: 4
|
||||
id: perfText
|
||||
|
|
|
@ -1949,11 +1949,15 @@ void Application::setEnableVRMode(bool enableVRMode) {
|
|||
// attempt to reconnect the Oculus manager - it's possible this was a workaround
|
||||
// for the sixense crash
|
||||
OculusManager::disconnect();
|
||||
OculusManager::connect();
|
||||
OculusManager::connect(_glWidget->context()->contextHandle());
|
||||
_glWidget->setFocus();
|
||||
_glWidget->makeCurrent();
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
}
|
||||
OculusManager::recalibrate();
|
||||
} else {
|
||||
OculusManager::abandonCalibration();
|
||||
OculusManager::disconnect();
|
||||
}
|
||||
|
||||
resizeGL();
|
||||
|
@ -2176,13 +2180,6 @@ void Application::init() {
|
|||
_mirrorCamera.setMode(CAMERA_MODE_MIRROR);
|
||||
#endif
|
||||
|
||||
OculusManager::connect();
|
||||
if (OculusManager::isConnected()) {
|
||||
QMetaObject::invokeMethod(Menu::getInstance()->getActionForOption(MenuOption::Fullscreen),
|
||||
"trigger",
|
||||
Qt::QueuedConnection);
|
||||
}
|
||||
|
||||
TV3DManager::connect();
|
||||
if (TV3DManager::isConnected()) {
|
||||
QMetaObject::invokeMethod(Menu::getInstance()->getActionForOption(MenuOption::Fullscreen),
|
||||
|
@ -4668,11 +4665,9 @@ void Application::postLambdaEvent(std::function<void()> f) {
|
|||
}
|
||||
|
||||
void Application::initPlugins() {
|
||||
OculusManager::init();
|
||||
}
|
||||
|
||||
void Application::shutdownPlugins() {
|
||||
OculusManager::deinit();
|
||||
}
|
||||
|
||||
glm::vec3 Application::getHeadPosition() const {
|
||||
|
|
|
@ -25,6 +25,9 @@
|
|||
#include <avatar/AvatarManager.h>
|
||||
#include <avatar/MyAvatar.h>
|
||||
#include <GlowEffect.h>
|
||||
#include <GlWindow.h>
|
||||
#include <gpu/GLBackend.h>
|
||||
#include <OglplusHelpers.h>
|
||||
#include <PathUtils.h>
|
||||
#include <SharedUtil.h>
|
||||
#include <UserActivityLogger.h>
|
||||
|
@ -34,7 +37,6 @@
|
|||
#include "InterfaceLogging.h"
|
||||
#include "Application.h"
|
||||
|
||||
#include <gpu/GLBackend.h>
|
||||
|
||||
template <typename Function>
|
||||
void for_each_eye(Function function) {
|
||||
|
@ -53,27 +55,133 @@ void for_each_eye(const ovrHmd & hmd, Function function) {
|
|||
}
|
||||
}
|
||||
|
||||
#ifdef OVR_CLIENT_DISTORTION
|
||||
ProgramObject OculusManager::_program;
|
||||
int OculusManager::_textureLocation;
|
||||
int OculusManager::_eyeToSourceUVScaleLocation;
|
||||
int OculusManager::_eyeToSourceUVOffsetLocation;
|
||||
int OculusManager::_eyeRotationStartLocation;
|
||||
int OculusManager::_eyeRotationEndLocation;
|
||||
int OculusManager::_positionAttributeLocation;
|
||||
int OculusManager::_colorAttributeLocation;
|
||||
int OculusManager::_texCoord0AttributeLocation;
|
||||
int OculusManager::_texCoord1AttributeLocation;
|
||||
int OculusManager::_texCoord2AttributeLocation;
|
||||
ovrVector2f OculusManager::_UVScaleOffset[ovrEye_Count][2];
|
||||
GLuint OculusManager::_vertices[ovrEye_Count] = { 0, 0 };
|
||||
GLuint OculusManager::_indices[ovrEye_Count] = { 0, 0 };
|
||||
GLsizei OculusManager::_meshSize[ovrEye_Count] = { 0, 0 };
|
||||
ovrFrameTiming OculusManager::_hmdFrameTiming;
|
||||
bool OculusManager::_programInitialized = false;
|
||||
#endif
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
|
||||
// A base class for FBO wrappers that need to use the Oculus C
|
||||
// API to manage textures via ovrHmd_CreateSwapTextureSetGL,
|
||||
// ovrHmd_CreateMirrorTextureGL, etc
|
||||
template <typename C>
|
||||
struct RiftFramebufferWrapper : public FramebufferWrapper<C, char> {
|
||||
ovrHmd hmd;
|
||||
RiftFramebufferWrapper(const ovrHmd & hmd) : hmd(hmd) {
|
||||
color = 0;
|
||||
depth = 0;
|
||||
};
|
||||
|
||||
void Resize(const uvec2 & size) {
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, oglplus::GetName(fbo));
|
||||
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0);
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
|
||||
this->size = size;
|
||||
initColor();
|
||||
initDone();
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual void initDepth() override final {
|
||||
}
|
||||
};
|
||||
|
||||
// A wrapper for constructing and using a swap texture set,
|
||||
// where each frame you draw to a texture via the FBO,
|
||||
// then submit it and increment to the next texture.
|
||||
// The Oculus SDK manages the creation and destruction of
|
||||
// the textures
|
||||
struct SwapFramebufferWrapper : public RiftFramebufferWrapper<ovrSwapTextureSet*> {
|
||||
SwapFramebufferWrapper(const ovrHmd & hmd)
|
||||
: RiftFramebufferWrapper(hmd) {
|
||||
}
|
||||
|
||||
~SwapFramebufferWrapper() {
|
||||
if (color) {
|
||||
ovrHmd_DestroySwapTextureSet(hmd, color);
|
||||
color = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void Increment() {
|
||||
++color->CurrentIndex;
|
||||
color->CurrentIndex %= color->TextureCount;
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual void initColor() override {
|
||||
if (color) {
|
||||
ovrHmd_DestroySwapTextureSet(hmd, color);
|
||||
color = nullptr;
|
||||
}
|
||||
|
||||
ovrResult result = ovrHmd_CreateSwapTextureSetGL(hmd, GL_RGBA, size.x, size.y, &color);
|
||||
Q_ASSERT(OVR_SUCCESS(result));
|
||||
|
||||
for (int i = 0; i < color->TextureCount; ++i) {
|
||||
ovrGLTexture& ovrTex = (ovrGLTexture&)color->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);
|
||||
}
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
}
|
||||
|
||||
virtual void initDone() override {
|
||||
}
|
||||
|
||||
virtual void onBind(oglplus::Framebuffer::Target target) override {
|
||||
ovrGLTexture& tex = (ovrGLTexture&)(color->Textures[color->CurrentIndex]);
|
||||
glFramebufferTexture2D(toEnum(target), GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tex.OGL.TexId, 0);
|
||||
}
|
||||
|
||||
virtual void onUnbind(oglplus::Framebuffer::Target target) override {
|
||||
glFramebufferTexture2D(toEnum(target), GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// We use a FBO to wrap the mirror texture because it makes it easier to
|
||||
// render to the screen via glBlitFramebuffer
|
||||
struct MirrorFramebufferWrapper : public RiftFramebufferWrapper<ovrGLTexture*> {
|
||||
MirrorFramebufferWrapper(const ovrHmd & hmd)
|
||||
: RiftFramebufferWrapper(hmd) {
|
||||
}
|
||||
|
||||
virtual ~MirrorFramebufferWrapper() {
|
||||
if (color) {
|
||||
ovrHmd_DestroyMirrorTexture(hmd, (ovrTexture*)color);
|
||||
color = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
void initColor() override {
|
||||
if (color) {
|
||||
ovrHmd_DestroyMirrorTexture(hmd, (ovrTexture*)color);
|
||||
color = nullptr;
|
||||
}
|
||||
ovrResult result = ovrHmd_CreateMirrorTextureGL(hmd, GL_RGBA, size.x, size.y, (ovrTexture**)&color);
|
||||
Q_ASSERT(OVR_SUCCESS(result));
|
||||
}
|
||||
|
||||
void initDone() override {
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, oglplus::GetName(fbo));
|
||||
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, color->OGL.TexId, 0);
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
|
||||
}
|
||||
};
|
||||
|
||||
SwapFramebufferWrapper* OculusManager::_swapFbo{ nullptr };
|
||||
MirrorFramebufferWrapper* OculusManager::_mirrorFbo{ nullptr };
|
||||
ovrLayerEyeFov OculusManager::_sceneLayer;
|
||||
|
||||
#else
|
||||
|
||||
ovrTexture OculusManager::_eyeTextures[ovrEye_Count];
|
||||
GlWindow* OculusManager::_outputWindow{ nullptr };
|
||||
|
||||
#endif
|
||||
|
||||
bool OculusManager::_isConnected = false;
|
||||
ovrHmd OculusManager::_ovrHmd;
|
||||
ovrFovPort OculusManager::_eyeFov[ovrEye_Count];
|
||||
|
@ -104,155 +212,175 @@ bool OculusManager::_eyePerFrameMode = false;
|
|||
ovrEyeType OculusManager::_lastEyeRendered = ovrEye_Count;
|
||||
ovrSizei OculusManager::_recommendedTexSize = { 0, 0 };
|
||||
float OculusManager::_offscreenRenderScale = 1.0;
|
||||
|
||||
static glm::mat4 _eyeProjections[ovrEye_Count];
|
||||
static glm::mat4 _combinedProjection;
|
||||
static ovrPosef _eyeRenderPoses[ovrEye_Count];
|
||||
ovrRecti OculusManager::_eyeViewports[ovrEye_Count];
|
||||
|
||||
void OculusManager::initSdk() {
|
||||
ovr_Initialize();
|
||||
_ovrHmd = ovrHmd_Create(0);
|
||||
if (!_ovrHmd) {
|
||||
_ovrHmd = ovrHmd_CreateDebug(ovrHmd_DK2);
|
||||
}
|
||||
}
|
||||
|
||||
void OculusManager::shutdownSdk() {
|
||||
if (_ovrHmd) {
|
||||
ovrHmd_Destroy(_ovrHmd);
|
||||
_ovrHmd = nullptr;
|
||||
ovr_Shutdown();
|
||||
}
|
||||
}
|
||||
|
||||
void OculusManager::init() {
|
||||
#ifdef OVR_DIRECT_MODE
|
||||
initSdk();
|
||||
#endif
|
||||
}
|
||||
|
||||
void OculusManager::deinit() {
|
||||
#ifdef OVR_DIRECT_MODE
|
||||
shutdownSdk();
|
||||
#endif
|
||||
}
|
||||
|
||||
void OculusManager::connect() {
|
||||
#ifndef OVR_DIRECT_MODE
|
||||
initSdk();
|
||||
#endif
|
||||
_calibrationState = UNCALIBRATED;
|
||||
void OculusManager::connect(QOpenGLContext* shareContext) {
|
||||
qCDebug(interfaceapp) << "Oculus SDK" << OVR_VERSION_STRING;
|
||||
if (_ovrHmd) {
|
||||
if (!_isConnected) {
|
||||
UserActivityLogger::getInstance().connectedDevice("hmd", "oculus");
|
||||
}
|
||||
_isConnected = true;
|
||||
|
||||
for_each_eye([&](ovrEyeType eye) {
|
||||
_eyeFov[eye] = _ovrHmd->DefaultEyeFov[eye];
|
||||
});
|
||||
ovrInitParams initParams; memset(&initParams, 0, sizeof(initParams));
|
||||
|
||||
ovrGLConfig cfg;
|
||||
memset(&cfg, 0, sizeof(cfg));
|
||||
cfg.OGL.Header.API = ovrRenderAPI_OpenGL;
|
||||
cfg.OGL.Header.BackBufferSize = _ovrHmd->Resolution;
|
||||
cfg.OGL.Header.Multisample = 1;
|
||||
|
||||
int distortionCaps = 0
|
||||
| ovrDistortionCap_Vignette
|
||||
| ovrDistortionCap_Overdrive
|
||||
| ovrDistortionCap_TimeWarp;
|
||||
|
||||
int configResult = ovrHmd_ConfigureRendering(_ovrHmd, &cfg.Config,
|
||||
distortionCaps, _eyeFov, _eyeRenderDesc);
|
||||
assert(configResult);
|
||||
(void)configResult; // quiet warning
|
||||
|
||||
|
||||
_recommendedTexSize = ovrHmd_GetFovTextureSize(_ovrHmd, ovrEye_Left, _eyeFov[ovrEye_Left], 1.0f);
|
||||
_renderTargetSize = { _recommendedTexSize.w * 2, _recommendedTexSize.h };
|
||||
for_each_eye([&](ovrEyeType eye) {
|
||||
//Get texture size
|
||||
_eyeTextures[eye].Header.API = ovrRenderAPI_OpenGL;
|
||||
_eyeTextures[eye].Header.TextureSize = _renderTargetSize;
|
||||
_eyeTextures[eye].Header.RenderViewport.Pos = { 0, 0 };
|
||||
ovrMatrix4f eyeProjection = ovrMatrix4f_Projection(_ovrHmd->MaxEyeFov[eye], DEFAULT_NEAR_CLIP, DEFAULT_FAR_CLIP, ovrProjection_RightHanded);
|
||||
_eyeProjections[eye] = toGlm(eyeProjection);
|
||||
});
|
||||
_eyeTextures[ovrEye_Right].Header.RenderViewport.Pos.x = _recommendedTexSize.w;
|
||||
|
||||
ovrFovPort combinedFov = _ovrHmd->MaxEyeFov[0];
|
||||
combinedFov.RightTan = _ovrHmd->MaxEyeFov[1].RightTan;
|
||||
_combinedProjection = toGlm(ovrMatrix4f_Projection(combinedFov, DEFAULT_NEAR_CLIP, DEFAULT_FAR_CLIP, ovrProjection_RightHanded));
|
||||
|
||||
ovrHmd_SetEnabledCaps(_ovrHmd, ovrHmdCap_LowPersistence | ovrHmdCap_DynamicPrediction);
|
||||
|
||||
ovrHmd_ConfigureTracking(_ovrHmd, ovrTrackingCap_Orientation | ovrTrackingCap_Position |
|
||||
ovrTrackingCap_MagYawCorrection,
|
||||
ovrTrackingCap_Orientation);
|
||||
|
||||
if (!_camera) {
|
||||
_camera = new Camera;
|
||||
configureCamera(*_camera); // no need to use screen dimensions; they're ignored
|
||||
}
|
||||
#ifdef OVR_CLIENT_DISTORTION
|
||||
if (!_programInitialized) {
|
||||
// Shader program
|
||||
_programInitialized = true;
|
||||
_program.addShaderFromSourceFile(QGLShader::Vertex, PathUtils::resourcesPath() + "shaders/oculus.vert");
|
||||
_program.addShaderFromSourceFile(QGLShader::Fragment, PathUtils::resourcesPath() + "shaders/oculus.frag");
|
||||
_program.link();
|
||||
|
||||
// Uniforms
|
||||
_textureLocation = _program.uniformLocation("texture");
|
||||
_eyeToSourceUVScaleLocation = _program.uniformLocation("EyeToSourceUVScale");
|
||||
_eyeToSourceUVOffsetLocation = _program.uniformLocation("EyeToSourceUVOffset");
|
||||
_eyeRotationStartLocation = _program.uniformLocation("EyeRotationStart");
|
||||
_eyeRotationEndLocation = _program.uniformLocation("EyeRotationEnd");
|
||||
|
||||
// Attributes
|
||||
_positionAttributeLocation = _program.attributeLocation("position");
|
||||
_colorAttributeLocation = _program.attributeLocation("color");
|
||||
_texCoord0AttributeLocation = _program.attributeLocation("texCoord0");
|
||||
_texCoord1AttributeLocation = _program.attributeLocation("texCoord1");
|
||||
_texCoord2AttributeLocation = _program.attributeLocation("texCoord2");
|
||||
}
|
||||
|
||||
//Generate the distortion VBOs
|
||||
generateDistortionMesh();
|
||||
#ifdef DEBUG
|
||||
initParams.Flags |= ovrInit_Debug;
|
||||
#endif
|
||||
} else {
|
||||
|
||||
ovr_Initialize(&initParams);
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
|
||||
ovrResult res = ovrHmd_Create(0, &_ovrHmd);
|
||||
#ifdef DEBUG
|
||||
if (!OVR_SUCCESS(res)) {
|
||||
res = ovrHmd_CreateDebug(ovrHmd_DK2, &_ovrHmd);
|
||||
Q_ASSERT(OVR_SUCCESS(res));
|
||||
}
|
||||
#endif
|
||||
|
||||
#else
|
||||
|
||||
_ovrHmd = ovrHmd_Create(0);
|
||||
#ifdef DEBUG
|
||||
if (!_ovrHmd) {
|
||||
_ovrHmd = ovrHmd_CreateDebug(ovrHmd_DK2);
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
if (!_ovrHmd) {
|
||||
_isConnected = false;
|
||||
|
||||
// we're definitely not in "VR mode" so tell the menu that
|
||||
Menu::getInstance()->getActionForOption(MenuOption::EnableVRMode)->setChecked(false);
|
||||
ovr_Shutdown();
|
||||
return;
|
||||
}
|
||||
|
||||
_calibrationState = UNCALIBRATED;
|
||||
if (!_isConnected) {
|
||||
UserActivityLogger::getInstance().connectedDevice("hmd", "oculus");
|
||||
}
|
||||
_isConnected = true;
|
||||
|
||||
for_each_eye([&](ovrEyeType eye) {
|
||||
_eyeFov[eye] = _ovrHmd->DefaultEyeFov[eye];
|
||||
});
|
||||
|
||||
_recommendedTexSize = ovrHmd_GetFovTextureSize(_ovrHmd, ovrEye_Left, _eyeFov[ovrEye_Left], 1.0f);
|
||||
_renderTargetSize = { _recommendedTexSize.w * 2, _recommendedTexSize.h };
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
|
||||
_mirrorFbo = new MirrorFramebufferWrapper(_ovrHmd);
|
||||
_swapFbo = new SwapFramebufferWrapper(_ovrHmd);
|
||||
_swapFbo->Init(toGlm(_renderTargetSize));
|
||||
_sceneLayer.ColorTexture[0] = _swapFbo->color;
|
||||
_sceneLayer.ColorTexture[1] = nullptr;
|
||||
_sceneLayer.Viewport[0].Pos = { 0, 0 };
|
||||
_sceneLayer.Viewport[0].Size = _recommendedTexSize;
|
||||
_sceneLayer.Viewport[1].Pos = { _recommendedTexSize.w, 0 };
|
||||
_sceneLayer.Viewport[1].Size = _recommendedTexSize;
|
||||
_sceneLayer.Header.Type = ovrLayerType_EyeFov;
|
||||
_sceneLayer.Header.Flags = ovrLayerFlag_TextureOriginAtBottomLeft;
|
||||
for_each_eye([&](ovrEyeType eye) {
|
||||
_eyeViewports[eye] = _sceneLayer.Viewport[eye];
|
||||
_sceneLayer.Fov[eye] = _eyeFov[eye];
|
||||
});
|
||||
|
||||
|
||||
|
||||
#else
|
||||
_outputWindow = new GlWindow(shareContext);
|
||||
_outputWindow->show();
|
||||
// _outputWindow->setFlags(Qt::FramelessWindowHint );
|
||||
// _outputWindow->resize(_ovrHmd->Resolution.w, _ovrHmd->Resolution.h);
|
||||
// _outputWindow->setPosition(_ovrHmd->WindowsPos.x, _ovrHmd->WindowsPos.y);
|
||||
ivec2 desiredPosition = toGlm(_ovrHmd->WindowsPos);
|
||||
foreach(QScreen* screen, qGuiApp->screens()) {
|
||||
ivec2 screenPosition = toGlm(screen->geometry().topLeft());
|
||||
if (screenPosition == desiredPosition) {
|
||||
_outputWindow->setScreen(screen);
|
||||
break;
|
||||
}
|
||||
}
|
||||
_outputWindow->showFullScreen();
|
||||
_outputWindow->makeCurrent();
|
||||
|
||||
ovrGLConfig cfg;
|
||||
memset(&cfg, 0, sizeof(cfg));
|
||||
cfg.OGL.Header.API = ovrRenderAPI_OpenGL;
|
||||
cfg.OGL.Header.BackBufferSize = _ovrHmd->Resolution;
|
||||
cfg.OGL.Header.Multisample = 0;
|
||||
|
||||
int distortionCaps = 0
|
||||
| ovrDistortionCap_Vignette
|
||||
| ovrDistortionCap_Overdrive
|
||||
| ovrDistortionCap_TimeWarp;
|
||||
|
||||
int configResult = ovrHmd_ConfigureRendering(_ovrHmd, &cfg.Config,
|
||||
distortionCaps, _eyeFov, _eyeRenderDesc);
|
||||
assert(configResult);
|
||||
_outputWindow->doneCurrent();
|
||||
|
||||
for_each_eye([&](ovrEyeType eye) {
|
||||
//Get texture size
|
||||
_eyeTextures[eye].Header.API = ovrRenderAPI_OpenGL;
|
||||
_eyeTextures[eye].Header.TextureSize = _renderTargetSize;
|
||||
_eyeTextures[eye].Header.RenderViewport.Pos = { 0, 0 };
|
||||
_eyeTextures[eye].Header.RenderViewport.Size = _renderTargetSize;
|
||||
_eyeTextures[eye].Header.RenderViewport.Size.w /= 2;
|
||||
});
|
||||
_eyeTextures[ovrEye_Right].Header.RenderViewport.Pos.x = _recommendedTexSize.w;
|
||||
for_each_eye([&](ovrEyeType eye) {
|
||||
_eyeViewports[eye] = _eyeTextures[eye].Header.RenderViewport;
|
||||
});
|
||||
#endif
|
||||
|
||||
ovrHmd_SetEnabledCaps(_ovrHmd,
|
||||
ovrHmdCap_LowPersistence | ovrHmdCap_DynamicPrediction);
|
||||
|
||||
ovrHmd_ConfigureTracking(_ovrHmd,
|
||||
ovrTrackingCap_Orientation | ovrTrackingCap_Position | ovrTrackingCap_MagYawCorrection,
|
||||
ovrTrackingCap_Orientation);
|
||||
|
||||
if (!_camera) {
|
||||
_camera = new Camera;
|
||||
configureCamera(*_camera); // no need to use screen dimensions; they're ignored
|
||||
}
|
||||
}
|
||||
|
||||
//Disconnects and deallocates the OR
|
||||
void OculusManager::disconnect() {
|
||||
if (_isConnected) {
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
if (_swapFbo) {
|
||||
delete _swapFbo;
|
||||
_swapFbo = nullptr;
|
||||
}
|
||||
|
||||
if (_mirrorFbo) {
|
||||
delete _mirrorFbo;
|
||||
_mirrorFbo = nullptr;
|
||||
}
|
||||
#else
|
||||
_outputWindow->showNormal();
|
||||
_outputWindow->deleteLater();
|
||||
_outputWindow = nullptr;
|
||||
#endif
|
||||
|
||||
if (_ovrHmd) {
|
||||
ovrHmd_Destroy(_ovrHmd);
|
||||
_ovrHmd = nullptr;
|
||||
}
|
||||
ovr_Shutdown();
|
||||
|
||||
_isConnected = false;
|
||||
// Prepare to potentially have to dismiss the HSW again
|
||||
// if the user re-enables VR
|
||||
_hswDismissed = false;
|
||||
#ifndef OVR_DIRECT_MODE
|
||||
shutdownSdk();
|
||||
#endif
|
||||
|
||||
#ifdef OVR_CLIENT_DISTORTION
|
||||
//Free the distortion mesh data
|
||||
for (int i = 0; i < ovrEye_Count; i++) {
|
||||
if (_vertices[i] != 0) {
|
||||
glDeleteBuffers(1, &(_vertices[i]));
|
||||
_vertices[i] = 0;
|
||||
}
|
||||
if (_indices[i] != 0) {
|
||||
glDeleteBuffers(1, &(_indices[i]));
|
||||
_indices[i] = 0;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -355,7 +483,6 @@ void OculusManager::calibrate(glm::vec3 position, glm::quat orientation) {
|
|||
break;
|
||||
default:
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -372,64 +499,8 @@ void OculusManager::abandonCalibration() {
|
|||
}
|
||||
}
|
||||
|
||||
#ifdef OVR_CLIENT_DISTORTION
|
||||
void OculusManager::generateDistortionMesh() {
|
||||
|
||||
//Check if we already have the distortion mesh
|
||||
if (_vertices[0] != 0) {
|
||||
printf("WARNING: Tried to generate Oculus distortion mesh twice without freeing the VBOs.");
|
||||
return;
|
||||
}
|
||||
|
||||
for (int eyeNum = 0; eyeNum < ovrEye_Count; eyeNum++) {
|
||||
// Allocate and generate distortion mesh vertices
|
||||
ovrDistortionMesh meshData;
|
||||
ovrHmd_CreateDistortionMesh(_ovrHmd, _eyeRenderDesc[eyeNum].Eye, _eyeRenderDesc[eyeNum].Fov, _ovrHmd->DistortionCaps, &meshData);
|
||||
|
||||
// Parse the vertex data and create a render ready vertex buffer
|
||||
DistortionVertex* pVBVerts = new DistortionVertex[meshData.VertexCount];
|
||||
_meshSize[eyeNum] = meshData.IndexCount;
|
||||
|
||||
// Convert the oculus vertex data to the DistortionVertex format.
|
||||
DistortionVertex* v = pVBVerts;
|
||||
ovrDistortionVertex* ov = meshData.pVertexData;
|
||||
for (unsigned int vertNum = 0; vertNum < meshData.VertexCount; vertNum++) {
|
||||
v->pos.x = ov->ScreenPosNDC.x;
|
||||
v->pos.y = ov->ScreenPosNDC.y;
|
||||
v->texR.x = ov->TanEyeAnglesR.x;
|
||||
v->texR.y = ov->TanEyeAnglesR.y;
|
||||
v->texG.x = ov->TanEyeAnglesG.x;
|
||||
v->texG.y = ov->TanEyeAnglesG.y;
|
||||
v->texB.x = ov->TanEyeAnglesB.x;
|
||||
v->texB.y = ov->TanEyeAnglesB.y;
|
||||
v->color.r = v->color.g = v->color.b = (GLubyte)(ov->VignetteFactor * 255.99f);
|
||||
v->color.a = (GLubyte)(ov->TimeWarpFactor * 255.99f);
|
||||
v++;
|
||||
ov++;
|
||||
}
|
||||
|
||||
//vertices
|
||||
glGenBuffers(1, &(_vertices[eyeNum]));
|
||||
glBindBuffer(GL_ARRAY_BUFFER, _vertices[eyeNum]);
|
||||
glBufferData(GL_ARRAY_BUFFER, sizeof(DistortionVertex) * meshData.VertexCount, pVBVerts, GL_STATIC_DRAW);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
|
||||
//indices
|
||||
glGenBuffers(1, &(_indices[eyeNum]));
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _indices[eyeNum]);
|
||||
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(unsigned short) * meshData.IndexCount, meshData.pIndexData, GL_STATIC_DRAW);
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
|
||||
|
||||
//Now that we have the VBOs we can get rid of the mesh data
|
||||
delete [] pVBVerts;
|
||||
ovrHmd_DestroyDistortionMesh(&meshData);
|
||||
}
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
bool OculusManager::isConnected() {
|
||||
return _isConnected && Menu::getInstance()->isOptionChecked(MenuOption::EnableVRMode);
|
||||
return _isConnected;
|
||||
}
|
||||
|
||||
//Begins the frame timing for oculus prediction purposes
|
||||
|
@ -437,10 +508,6 @@ void OculusManager::beginFrameTiming() {
|
|||
if (_frameTimingActive) {
|
||||
printf("WARNING: Called OculusManager::beginFrameTiming() twice in a row, need to call OculusManager::endFrameTiming().");
|
||||
}
|
||||
|
||||
#ifdef OVR_CLIENT_DISTORTION
|
||||
_hmdFrameTiming = ovrHmd_BeginFrameTiming(_ovrHmd, _frameIndex);
|
||||
#endif
|
||||
_frameTimingActive = true;
|
||||
}
|
||||
|
||||
|
@ -450,9 +517,6 @@ bool OculusManager::allowSwap() {
|
|||
|
||||
//Ends frame timing
|
||||
void OculusManager::endFrameTiming() {
|
||||
#ifdef OVR_CLIENT_DISTORTION
|
||||
ovrHmd_EndFrameTiming(_ovrHmd);
|
||||
#endif
|
||||
_frameIndex++;
|
||||
_frameTimingActive = false;
|
||||
}
|
||||
|
@ -482,40 +546,8 @@ void OculusManager::display(QGLWidget * glCanvas, RenderArgs* renderArgs, const
|
|||
assert(oldFrameIndex == -1 || (unsigned int)oldFrameIndex == _frameIndex - 1);
|
||||
oldFrameIndex = _frameIndex;
|
||||
#endif
|
||||
|
||||
// Every so often do some additional timing calculations and debug output
|
||||
bool debugFrame = 0 == _frameIndex % 400;
|
||||
|
||||
#if 0
|
||||
// Try to measure the amount of time taken to do the distortion
|
||||
// (does not seem to work on OSX with SDK based distortion)
|
||||
// FIXME can't use a static object here, because it will cause a crash when the
|
||||
// query attempts deconstruct after the GL context is gone.
|
||||
static bool timerActive = false;
|
||||
static QOpenGLTimerQuery timerQuery;
|
||||
if (!timerQuery.isCreated()) {
|
||||
timerQuery.create();
|
||||
}
|
||||
|
||||
if (timerActive && timerQuery.isResultAvailable()) {
|
||||
auto result = timerQuery.waitForResult();
|
||||
if (result) { qCDebug(interfaceapp) << "Distortion took " << result << "ns"; };
|
||||
timerActive = false;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef OVR_DIRECT_MODE
|
||||
static bool attached = false;
|
||||
if (!attached) {
|
||||
attached = true;
|
||||
void * nativeWindowHandle = (void*)(size_t)glCanvas->effectiveWinId();
|
||||
if (nullptr != nativeWindowHandle) {
|
||||
ovrHmd_AttachToWindow(_ovrHmd, nativeWindowHandle, nullptr, nullptr);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef OVR_CLIENT_DISTORTION
|
||||
#ifndef Q_OS_WIN
|
||||
// FIXME: we need a better way of responding to the HSW. In particular
|
||||
// we need to ensure that it's only displayed once per session, rather than
|
||||
// every time the user toggles VR mode, and we need to hook it up to actual
|
||||
|
@ -531,7 +563,6 @@ void OculusManager::display(QGLWidget * glCanvas, RenderArgs* renderArgs, const
|
|||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
//beginFrameTiming must be called before display
|
||||
if (!_frameTimingActive) {
|
||||
|
@ -574,7 +605,9 @@ void OculusManager::display(QGLWidget * glCanvas, RenderArgs* renderArgs, const
|
|||
static ovrVector3f eyeOffsets[2] = { { 0, 0, 0 }, { 0, 0, 0 } };
|
||||
ovrPosef eyePoses[ovrEye_Count];
|
||||
ovrHmd_GetEyePoses(_ovrHmd, _frameIndex, eyeOffsets, eyePoses, nullptr);
|
||||
#ifndef Q_OS_WIN
|
||||
ovrHmd_BeginFrame(_ovrHmd, _frameIndex);
|
||||
#endif
|
||||
//Render each eye into an fbo
|
||||
for_each_eye(_ovrHmd, [&](ovrEyeType eye){
|
||||
// If we're in eye-per-frame mode, only render one eye
|
||||
|
@ -603,10 +636,9 @@ void OculusManager::display(QGLWidget * glCanvas, RenderArgs* renderArgs, const
|
|||
glMatrixMode(GL_MODELVIEW);
|
||||
glLoadIdentity();
|
||||
|
||||
ovrRecti & vp = _eyeTextures[eye].Header.RenderViewport;
|
||||
ovrRecti & vp = _eyeViewports[eye];
|
||||
vp.Size.h = _recommendedTexSize.h * _offscreenRenderScale;
|
||||
vp.Size.w = _recommendedTexSize.w * _offscreenRenderScale;
|
||||
|
||||
glViewport(vp.Pos.x, vp.Pos.y, vp.Size.w, vp.Size.h);
|
||||
|
||||
renderArgs->_renderSide = RenderArgs::MONO;
|
||||
|
@ -634,142 +666,58 @@ void OculusManager::display(QGLWidget * glCanvas, RenderArgs* renderArgs, const
|
|||
// restore our normal viewport
|
||||
glViewport(0, 0, deviceSize.width(), deviceSize.height());
|
||||
|
||||
#if 0
|
||||
if (debugFrame && !timerActive) {
|
||||
timerQuery.begin();
|
||||
}
|
||||
#endif
|
||||
#ifdef Q_OS_WIN
|
||||
auto srcFboSize = finalFbo->getSize();
|
||||
|
||||
#ifdef OVR_CLIENT_DISTORTION
|
||||
|
||||
//Wait till time-warp to reduce latency
|
||||
ovr_WaitTillTime(_hmdFrameTiming.TimewarpPointSeconds);
|
||||
|
||||
#ifdef DEBUG_RENDER_WITHOUT_DISTORTION
|
||||
auto fboSize = finalFbo->getSize();
|
||||
// Blit to the oculus provided texture
|
||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, gpu::GLBackend::getFramebufferID(finalFbo));
|
||||
_swapFbo->Bound(oglplus::Framebuffer::Target::Draw, [&] {
|
||||
glBlitFramebuffer(
|
||||
0, 0, srcFboSize.x, srcFboSize.y,
|
||||
0, 0, _swapFbo->size.x, _swapFbo->size.y,
|
||||
GL_COLOR_BUFFER_BIT, GL_NEAREST);
|
||||
});
|
||||
|
||||
// Blit to the onscreen window
|
||||
auto destWindowSize = qApp->getDeviceSize();
|
||||
glBlitFramebuffer(
|
||||
0, 0, fboSize.x, fboSize.y,
|
||||
0, 0, deviceSize.width(), deviceSize.height(),
|
||||
0, 0, srcFboSize.x, srcFboSize.y,
|
||||
0, 0, destWindowSize.width(), destWindowSize.height(),
|
||||
GL_COLOR_BUFFER_BIT, GL_NEAREST);
|
||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
|
||||
|
||||
// Submit the frame to the Oculus SDK for timewarp and distortion
|
||||
for_each_eye([&](ovrEyeType eye) {
|
||||
_sceneLayer.RenderPose[eye] = _eyeRenderPoses[eye];
|
||||
});
|
||||
auto header = &_sceneLayer.Header;
|
||||
ovrResult res = ovrHmd_SubmitFrame(_ovrHmd, _frameIndex, nullptr, &header, 1);
|
||||
Q_ASSERT(OVR_SUCCESS(res));
|
||||
_swapFbo->Increment();
|
||||
#else
|
||||
//Clear the color buffer to ensure that there isnt any residual color
|
||||
//Left over from when OR was not connected.
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
glBindTexture(GL_TEXTURE_2D, gpu::GLBackend::getTextureID(finalFbo->getRenderBuffer(0)));
|
||||
//Renders the distorted mesh onto the screen
|
||||
renderDistortionMesh(_eyeRenderPoses);
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
#endif
|
||||
glCanvas->swapBuffers();
|
||||
GLsync syncObject = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
|
||||
glFlush();
|
||||
|
||||
#else
|
||||
_outputWindow->makeCurrent();
|
||||
// force the compositing context to wait for the texture
|
||||
// rendering to complete before it starts the distortion rendering,
|
||||
// but without triggering a CPU/GPU synchronization
|
||||
glWaitSync(syncObject, 0, GL_TIMEOUT_IGNORED);
|
||||
|
||||
GLuint textureId = gpu::GLBackend::getTextureID(finalFbo->getRenderBuffer(0));
|
||||
for_each_eye([&](ovrEyeType eye) {
|
||||
ovrGLTexture & glEyeTexture = reinterpret_cast<ovrGLTexture&>(_eyeTextures[eye]);
|
||||
glEyeTexture.OGL.TexId = finalFbo->texture();
|
||||
|
||||
glEyeTexture.OGL.TexId = textureId;
|
||||
});
|
||||
|
||||
// restore our normal viewport
|
||||
ovrHmd_EndFrame(_ovrHmd, eyeRenderPose, _eyeTextures);
|
||||
|
||||
glCanvas->makeCurrent();
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
if (debugFrame && !timerActive) {
|
||||
timerQuery.end();
|
||||
timerActive = true;
|
||||
}
|
||||
#endif
|
||||
|
||||
// No DK2, no message.
|
||||
{
|
||||
float latencies[5] = {};
|
||||
if (debugFrame && ovrHmd_GetFloatArray(_ovrHmd, "DK2Latency", latencies, 5) == 5)
|
||||
{
|
||||
bool nonZero = false;
|
||||
for (int i = 0; i < 5; ++i)
|
||||
{
|
||||
nonZero |= (latencies[i] != 0.f);
|
||||
}
|
||||
|
||||
if (nonZero)
|
||||
{
|
||||
qCDebug(interfaceapp) << QString().sprintf("M2P Latency: Ren: %4.2fms TWrp: %4.2fms PostPresent: %4.2fms Err: %4.2fms %4.2fms",
|
||||
latencies[0], latencies[1], latencies[2], latencies[3], latencies[4]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
#ifdef OVR_CLIENT_DISTORTION
|
||||
void OculusManager::renderDistortionMesh(ovrPosef eyeRenderPose[ovrEye_Count]) {
|
||||
|
||||
glLoadIdentity();
|
||||
auto deviceSize = qApp->getDeviceSize();
|
||||
glOrtho(0, deviceSize.width(), 0, deviceSize.height(), -1.0, 1.0);
|
||||
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
|
||||
glDisable(GL_BLEND);
|
||||
_program.bind();
|
||||
_program.setUniformValue(_textureLocation, 0);
|
||||
|
||||
_program.enableAttributeArray(_positionAttributeLocation);
|
||||
_program.enableAttributeArray(_colorAttributeLocation);
|
||||
_program.enableAttributeArray(_texCoord0AttributeLocation);
|
||||
_program.enableAttributeArray(_texCoord1AttributeLocation);
|
||||
_program.enableAttributeArray(_texCoord2AttributeLocation);
|
||||
|
||||
//Render the distortion meshes for each eye
|
||||
for (int eyeNum = 0; eyeNum < ovrEye_Count; eyeNum++) {
|
||||
|
||||
ovrHmd_GetRenderScaleAndOffset(_eyeRenderDesc[eyeNum].Fov, _renderTargetSize, _eyeTextures[eyeNum].Header.RenderViewport,
|
||||
_UVScaleOffset[eyeNum]);
|
||||
|
||||
GLfloat uvScale[2] = { _UVScaleOffset[eyeNum][0].x, _UVScaleOffset[eyeNum][0].y };
|
||||
_program.setUniformValueArray(_eyeToSourceUVScaleLocation, uvScale, 1, 2);
|
||||
GLfloat uvOffset[2] = { _UVScaleOffset[eyeNum][1].x, 1.0f - _UVScaleOffset[eyeNum][1].y };
|
||||
_program.setUniformValueArray(_eyeToSourceUVOffsetLocation, uvOffset, 1, 2);
|
||||
|
||||
ovrMatrix4f timeWarpMatrices[2];
|
||||
glm::mat4 transposeMatrices[2];
|
||||
//Grabs the timewarp matrices to be used in the shader
|
||||
ovrHmd_GetEyeTimewarpMatrices(_ovrHmd, (ovrEyeType)eyeNum, eyeRenderPose[eyeNum], timeWarpMatrices);
|
||||
//Have to transpose the matrices before using them
|
||||
transposeMatrices[0] = glm::transpose(toGlm(timeWarpMatrices[0]));
|
||||
transposeMatrices[1] = glm::transpose(toGlm(timeWarpMatrices[1]));
|
||||
|
||||
glUniformMatrix4fv(_eyeRotationStartLocation, 1, GL_FALSE, (GLfloat *)&transposeMatrices[0][0][0]);
|
||||
glUniformMatrix4fv(_eyeRotationEndLocation, 1, GL_FALSE, (GLfloat *)&transposeMatrices[1][0][0]);
|
||||
|
||||
glBindBuffer(GL_ARRAY_BUFFER, _vertices[eyeNum]);
|
||||
|
||||
//Set vertex attribute pointers
|
||||
glVertexAttribPointer(_positionAttributeLocation, 2, GL_FLOAT, GL_FALSE, sizeof(DistortionVertex), (void *)0);
|
||||
glVertexAttribPointer(_texCoord0AttributeLocation, 2, GL_FLOAT, GL_FALSE, sizeof(DistortionVertex), (void *)8);
|
||||
glVertexAttribPointer(_texCoord1AttributeLocation, 2, GL_FLOAT, GL_FALSE, sizeof(DistortionVertex), (void *)16);
|
||||
glVertexAttribPointer(_texCoord2AttributeLocation, 2, GL_FLOAT, GL_FALSE, sizeof(DistortionVertex), (void *)24);
|
||||
glVertexAttribPointer(_colorAttributeLocation, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(DistortionVertex), (void *)32);
|
||||
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _indices[eyeNum]);
|
||||
glDrawElements(GL_TRIANGLES, _meshSize[eyeNum], GL_UNSIGNED_SHORT, 0);
|
||||
}
|
||||
|
||||
_program.disableAttributeArray(_positionAttributeLocation);
|
||||
_program.disableAttributeArray(_colorAttributeLocation);
|
||||
_program.disableAttributeArray(_texCoord0AttributeLocation);
|
||||
_program.disableAttributeArray(_texCoord1AttributeLocation);
|
||||
_program.disableAttributeArray(_texCoord2AttributeLocation);
|
||||
|
||||
glEnable(GL_BLEND);
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
_program.release();
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
//Tries to reconnect to the sensors
|
||||
void OculusManager::reset() {
|
||||
if (_isConnected) {
|
||||
|
@ -777,21 +725,6 @@ void OculusManager::reset() {
|
|||
}
|
||||
}
|
||||
|
||||
//Gets the current predicted angles from the oculus sensors
|
||||
void OculusManager::getEulerAngles(float& yaw, float& pitch, float& roll) {
|
||||
ovrTrackingState ts = ovrHmd_GetTrackingState(_ovrHmd, ovr_GetTimeInSeconds());
|
||||
if (ts.StatusFlags & (ovrStatus_OrientationTracked | ovrStatus_PositionTracked)) {
|
||||
glm::vec3 euler = glm::eulerAngles(toGlm(ts.HeadPose.ThePose.Orientation));
|
||||
yaw = euler.y;
|
||||
pitch = euler.x;
|
||||
roll = euler.z;
|
||||
} else {
|
||||
yaw = 0.0f;
|
||||
pitch = 0.0f;
|
||||
roll = 0.0f;
|
||||
}
|
||||
}
|
||||
|
||||
glm::vec3 OculusManager::getRelativePosition() {
|
||||
ovrTrackingState trackingState = ovrHmd_GetTrackingState(_ovrHmd, ovr_GetTimeInSeconds());
|
||||
return toGlm(trackingState.HeadPose.ThePose.Position);
|
||||
|
@ -822,6 +755,9 @@ void OculusManager::overrideOffAxisFrustum(float& left, float& right, float& bot
|
|||
}
|
||||
|
||||
int OculusManager::getHMDScreen() {
|
||||
#ifdef Q_OS_WIN
|
||||
return -1;
|
||||
#else
|
||||
int hmdScreenIndex = -1; // unknown
|
||||
// TODO: it might be smarter to handle multiple HMDs connected in this case. but for now,
|
||||
// we will simply assume the initialization code that set up _ovrHmd picked the best hmd
|
||||
|
@ -872,6 +808,7 @@ int OculusManager::getHMDScreen() {
|
|||
}
|
||||
}
|
||||
return hmdScreenIndex;
|
||||
#endif
|
||||
}
|
||||
|
||||
mat4 OculusManager::getEyeProjection(int eye) {
|
||||
|
|
|
@ -22,39 +22,23 @@
|
|||
|
||||
#include "RenderArgs.h"
|
||||
|
||||
class QOpenGLContext;
|
||||
|
||||
class Camera;
|
||||
class GlWindow;
|
||||
class PalmData;
|
||||
class Text3DOverlay;
|
||||
|
||||
// Uncomment this to enable client side distortion. NOT recommended since
|
||||
// the Oculus SDK will ideally provide the best practices for distortion in
|
||||
// in terms of performance and quality, and by using it we will get updated
|
||||
// best practices for free with new runtime releases.
|
||||
#define OVR_CLIENT_DISTORTION 1
|
||||
|
||||
|
||||
// Direct HMD mode is currently only supported on windows and some linux systems will
|
||||
// misbehave if we try to enable the Oculus SDK at all, so isolate support for Direct
|
||||
// mode only to windows for now
|
||||
#ifdef Q_OS_WIN
|
||||
// On Win32 platforms, enabling Direct HMD requires that the SDK be
|
||||
// initialized before the GL context is set up, but this breaks v-sync
|
||||
// for any application that has a Direct mode enable Rift connected
|
||||
// but is not rendering to it. For the time being I'm setting this as
|
||||
// a macro enabled mechanism which changes where the SDK is initialized.
|
||||
// To enable Direct HMD mode, you can un-comment this, but with the
|
||||
// caveat that it will break v-sync in NON-VR mode if you have an Oculus
|
||||
// Rift connect and in Direct mode
|
||||
#define OVR_DIRECT_MODE 1
|
||||
struct SwapFramebufferWrapper;
|
||||
struct MirrorFramebufferWrapper;
|
||||
#endif
|
||||
|
||||
|
||||
/// Handles interaction with the Oculus Rift.
|
||||
class OculusManager {
|
||||
public:
|
||||
static void init();
|
||||
static void deinit();
|
||||
static void connect();
|
||||
static void connect(QOpenGLContext* shareContext);
|
||||
static void disconnect();
|
||||
static bool isConnected();
|
||||
static void recalibrate();
|
||||
|
@ -66,10 +50,6 @@ public:
|
|||
static void display(QGLWidget * glCanvas, RenderArgs* renderArgs, const glm::quat &bodyOrientation, const glm::vec3 &position, Camera& whichCamera);
|
||||
static void reset();
|
||||
|
||||
/// param \yaw[out] yaw in radians
|
||||
/// param \pitch[out] pitch in radians
|
||||
/// param \roll[out] roll in radians
|
||||
static void getEulerAngles(float& yaw, float& pitch, float& roll);
|
||||
static glm::vec3 getRelativePosition();
|
||||
static glm::quat getOrientation();
|
||||
static QSize getRenderTargetSize();
|
||||
|
@ -88,44 +68,7 @@ public:
|
|||
private:
|
||||
static void initSdk();
|
||||
static void shutdownSdk();
|
||||
#ifdef OVR_CLIENT_DISTORTION
|
||||
static void generateDistortionMesh();
|
||||
static void renderDistortionMesh(ovrPosef eyeRenderPose[ovrEye_Count]);
|
||||
struct DistortionVertex {
|
||||
glm::vec2 pos;
|
||||
glm::vec2 texR;
|
||||
glm::vec2 texG;
|
||||
glm::vec2 texB;
|
||||
struct {
|
||||
GLubyte r;
|
||||
GLubyte g;
|
||||
GLubyte b;
|
||||
GLubyte a;
|
||||
} color;
|
||||
};
|
||||
|
||||
static ProgramObject _program;
|
||||
//Uniforms
|
||||
static int _textureLocation;
|
||||
static int _eyeToSourceUVScaleLocation;
|
||||
static int _eyeToSourceUVOffsetLocation;
|
||||
static int _eyeRotationStartLocation;
|
||||
static int _eyeRotationEndLocation;
|
||||
//Attributes
|
||||
static int _positionAttributeLocation;
|
||||
static int _colorAttributeLocation;
|
||||
static int _texCoord0AttributeLocation;
|
||||
static int _texCoord1AttributeLocation;
|
||||
static int _texCoord2AttributeLocation;
|
||||
static ovrVector2f _UVScaleOffset[ovrEye_Count][2];
|
||||
static GLuint _vertices[ovrEye_Count];
|
||||
static GLuint _indices[ovrEye_Count];
|
||||
static GLsizei _meshSize[ovrEye_Count];
|
||||
static ovrFrameTiming _hmdFrameTiming;
|
||||
static bool _programInitialized;
|
||||
#endif
|
||||
|
||||
static ovrTexture _eyeTextures[ovrEye_Count];
|
||||
static bool _isConnected;
|
||||
static glm::vec3 _eyePositions[ovrEye_Count];
|
||||
static ovrHmd _ovrHmd;
|
||||
|
@ -133,6 +76,7 @@ private:
|
|||
static ovrVector3f _eyeOffset[ovrEye_Count];
|
||||
static glm::mat4 _eyeProjection[ovrEye_Count];
|
||||
static ovrEyeRenderDesc _eyeRenderDesc[ovrEye_Count];
|
||||
static ovrRecti _eyeViewports[ovrEye_Count];
|
||||
static ovrSizei _renderTargetSize;
|
||||
static unsigned int _frameIndex;
|
||||
static bool _frameTimingActive;
|
||||
|
@ -165,6 +109,14 @@ private:
|
|||
static float _offscreenRenderScale;
|
||||
static bool _eyePerFrameMode;
|
||||
static ovrEyeType _lastEyeRendered;
|
||||
#ifdef Q_OS_WIN
|
||||
static SwapFramebufferWrapper* _swapFbo;
|
||||
static MirrorFramebufferWrapper* _mirrorFbo;
|
||||
static ovrLayerEyeFov _sceneLayer;
|
||||
#else
|
||||
static ovrTexture _eyeTextures[ovrEye_Count];
|
||||
static GlWindow* _outputWindow;
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
|
@ -184,6 +136,10 @@ inline glm::vec2 toGlm(const ovrVector2f & ov) {
|
|||
return glm::make_vec2(&ov.x);
|
||||
}
|
||||
|
||||
inline glm::ivec2 toGlm(const ovrVector2i & ov) {
|
||||
return glm::ivec2(ov.x, ov.y);
|
||||
}
|
||||
|
||||
inline glm::uvec2 toGlm(const ovrSizei & ov) {
|
||||
return glm::uvec2(ov.w, ov.h);
|
||||
}
|
||||
|
|
|
@ -284,6 +284,7 @@ void ApplicationCompositor::displayOverlayTextureHmd(RenderArgs* renderArgs, int
|
|||
mat4 eyePose = qApp->getEyePose(eye);
|
||||
glm::mat4 overlayXfm = glm::inverse(eyePose);
|
||||
|
||||
#define DEBUG_OVERLAY
|
||||
#ifdef DEBUG_OVERLAY
|
||||
{
|
||||
batch.setModelTransform(glm::translate(mat4(), vec3(0, 0, -2)));
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include <DeferredLightingEffect.h>
|
||||
#include <GLMHelpers.h>
|
||||
#include <gpu/GLBackend.h>
|
||||
#include <gpu/GLBackendShared.h>
|
||||
#include <GLMHelpers.h>
|
||||
#include <OffscreenUi.h>
|
||||
#include <CursorManager.h>
|
||||
|
@ -89,8 +90,10 @@ ApplicationOverlay::ApplicationOverlay() :
|
|||
ApplicationOverlay::~ApplicationOverlay() {
|
||||
}
|
||||
|
||||
|
||||
// Renders the overlays either to a texture or to the screen
|
||||
void ApplicationOverlay::renderOverlay(RenderArgs* renderArgs) {
|
||||
CHECK_GL_ERROR();
|
||||
PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), "ApplicationOverlay::displayOverlay()");
|
||||
|
||||
buildFramebufferObject();
|
||||
|
@ -102,18 +105,24 @@ void ApplicationOverlay::renderOverlay(RenderArgs* renderArgs) {
|
|||
_overlayFramebuffer->bind();
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
fboViewport(_overlayFramebuffer);
|
||||
CHECK_GL_ERROR();
|
||||
|
||||
// Now render the overlay components together into a single texture
|
||||
//renderOverlays(renderArgs);
|
||||
//renderAudioMeter(renderArgs);
|
||||
//renderCameraToggle(renderArgs);
|
||||
renderStatsAndLogs(renderArgs);
|
||||
CHECK_GL_ERROR();
|
||||
renderRearView(renderArgs);
|
||||
CHECK_GL_ERROR();
|
||||
|
||||
renderDomainConnectionStatusBorder(renderArgs);
|
||||
CHECK_GL_ERROR();
|
||||
renderQmlUi(renderArgs);
|
||||
CHECK_GL_ERROR();
|
||||
|
||||
_overlayFramebuffer->release();
|
||||
CHECK_GL_ERROR();
|
||||
}
|
||||
|
||||
void ApplicationOverlay::renderQmlUi(RenderArgs* renderArgs) {
|
||||
|
@ -446,7 +455,7 @@ void ApplicationOverlay::renderDomainConnectionStatusBorder(RenderArgs* renderAr
|
|||
gpu::Batch batch;
|
||||
auto geometryCache = DependencyManager::get<GeometryCache>();
|
||||
geometryCache->useSimpleDrawPipeline(batch);
|
||||
batch._glDisable(GL_DEPTH);
|
||||
batch._glDisable(GL_DEPTH_TEST);
|
||||
batch._glDisable(GL_LIGHTING);
|
||||
batch._glEnable(GL_BLEND);
|
||||
batch.setProjectionTransform(mat4());
|
||||
|
|
|
@ -56,8 +56,6 @@ HMDToolsDialog::HMDToolsDialog(QWidget* parent) :
|
|||
|
||||
this->QDialog::setLayout(form);
|
||||
|
||||
_wasMoved = false;
|
||||
_previousRect = Application::getInstance()->getWindow()->rect();
|
||||
Application::getInstance()->getWindow()->activateWindow();
|
||||
|
||||
// watch for our application window moving screens. If it does we want to update our screen details
|
||||
|
@ -136,24 +134,6 @@ void HMDToolsDialog::enterHDMMode() {
|
|||
if (!_inHDMMode) {
|
||||
_switchModeButton->setText("Leave HMD Mode");
|
||||
_debugDetails->setText(getDebugDetails());
|
||||
|
||||
_hmdScreenNumber = OculusManager::getHMDScreen();
|
||||
|
||||
if (_hmdScreenNumber >= 0) {
|
||||
QWindow* mainWindow = Application::getInstance()->getWindow()->windowHandle();
|
||||
_hmdScreen = QGuiApplication::screens()[_hmdScreenNumber];
|
||||
|
||||
_previousRect = Application::getInstance()->getWindow()->rect();
|
||||
_previousRect = QRect(mainWindow->mapToGlobal(_previousRect.topLeft()),
|
||||
mainWindow->mapToGlobal(_previousRect.bottomRight()));
|
||||
_previousScreen = mainWindow->screen();
|
||||
QRect rect = QApplication::desktop()->screenGeometry(_hmdScreenNumber);
|
||||
mainWindow->setScreen(_hmdScreen);
|
||||
mainWindow->setGeometry(rect);
|
||||
|
||||
_wasMoved = true;
|
||||
}
|
||||
|
||||
|
||||
// if we're on a single screen setup, then hide our tools window when entering HMD mode
|
||||
if (QApplication::desktop()->screenCount() == 1) {
|
||||
|
@ -161,58 +141,21 @@ void HMDToolsDialog::enterHDMMode() {
|
|||
}
|
||||
|
||||
Application::getInstance()->setEnableVRMode(true);
|
||||
|
||||
const int SLIGHT_DELAY = 500;
|
||||
// If we go to fullscreen immediately, it ends up on the primary monitor,
|
||||
// even though we've already moved the window. By adding this delay, the
|
||||
// fullscreen target screen ends up correct.
|
||||
QTimer::singleShot(SLIGHT_DELAY, this, [&]{
|
||||
Application::getInstance()->setFullscreen(true);
|
||||
activateWindowAfterEnterMode();
|
||||
});
|
||||
|
||||
|
||||
_inHDMMode = true;
|
||||
}
|
||||
}
|
||||
|
||||
void HMDToolsDialog::activateWindowAfterEnterMode() {
|
||||
Application::getInstance()->getWindow()->activateWindow();
|
||||
|
||||
// center the cursor on the main application window
|
||||
centerCursorOnWidget(Application::getInstance()->getWindow());
|
||||
}
|
||||
|
||||
void HMDToolsDialog::leaveHDMMode() {
|
||||
if (_inHDMMode) {
|
||||
_switchModeButton->setText("Enter HMD Mode");
|
||||
_debugDetails->setText(getDebugDetails());
|
||||
|
||||
Application::getInstance()->setEnableVRMode(false);
|
||||
Application::getInstance()->setFullscreen(false);
|
||||
Application::getInstance()->getWindow()->activateWindow();
|
||||
|
||||
if (_wasMoved) {
|
||||
QWindow* mainWindow = Application::getInstance()->getWindow()->windowHandle();
|
||||
mainWindow->setScreen(_previousScreen);
|
||||
mainWindow->setGeometry(_previousRect);
|
||||
|
||||
const int SLIGHT_DELAY = 1500;
|
||||
QTimer::singleShot(SLIGHT_DELAY, this, SLOT(moveWindowAfterLeaveMode()));
|
||||
}
|
||||
_wasMoved = false;
|
||||
_inHDMMode = false;
|
||||
}
|
||||
}
|
||||
|
||||
void HMDToolsDialog::moveWindowAfterLeaveMode() {
|
||||
QWindow* mainWindow = Application::getInstance()->getWindow()->windowHandle();
|
||||
mainWindow->setScreen(_previousScreen);
|
||||
mainWindow->setGeometry(_previousRect);
|
||||
Application::getInstance()->getWindow()->activateWindow();
|
||||
Application::getInstance()->resetSensors();
|
||||
}
|
||||
|
||||
|
||||
void HMDToolsDialog::reject() {
|
||||
// Just regularly close upon ESC
|
||||
close();
|
||||
|
@ -244,13 +187,15 @@ void HMDToolsDialog::hideEvent(QHideEvent* event) {
|
|||
|
||||
void HMDToolsDialog::aboutToQuit() {
|
||||
if (_inHDMMode) {
|
||||
// FIXME this is ineffective because it doesn't trigger the menu to
|
||||
// save the fact that VR Mode is not checked.
|
||||
leaveHDMMode();
|
||||
}
|
||||
}
|
||||
|
||||
void HMDToolsDialog::screenCountChanged(int newCount) {
|
||||
if (!OculusManager::isConnected()) {
|
||||
OculusManager::connect();
|
||||
//OculusManager::connect();
|
||||
}
|
||||
int hmdScreenNumber = OculusManager::getHMDScreen();
|
||||
|
||||
|
|
|
@ -35,8 +35,6 @@ signals:
|
|||
public slots:
|
||||
void reject();
|
||||
void switchModeClicked(bool checked);
|
||||
void activateWindowAfterEnterMode();
|
||||
void moveWindowAfterLeaveMode();
|
||||
void applicationWindowScreenChanged(QScreen* screen);
|
||||
void aboutToQuit();
|
||||
void screenCountChanged(int newCount);
|
||||
|
@ -51,8 +49,6 @@ private:
|
|||
void enterHDMMode();
|
||||
void leaveHDMMode();
|
||||
|
||||
bool _wasMoved;
|
||||
QRect _previousRect;
|
||||
QScreen* _previousScreen;
|
||||
QScreen* _hmdScreen;
|
||||
int _hmdScreenNumber;
|
||||
|
|
|
@ -12,6 +12,8 @@
|
|||
#include "GLBackendShared.h"
|
||||
#include <glm/gtc/type_ptr.hpp>
|
||||
|
||||
using namespace gpu;
|
||||
|
||||
GLBackend::CommandCall GLBackend::_commandCalls[Batch::NUM_COMMANDS] =
|
||||
{
|
||||
(&::gpu::GLBackend::do_draw),
|
||||
|
@ -141,6 +143,14 @@ bool GLBackend::checkGLError(const char* name) {
|
|||
}
|
||||
}
|
||||
|
||||
bool GLBackend::checkGLErrorDebug(const char* name) {
|
||||
#ifdef DEBUG
|
||||
checkGLError(name);
|
||||
#else
|
||||
Q_UNUSED(name);
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
void GLBackend::syncCache() {
|
||||
syncTransformStateCache();
|
||||
|
|
|
@ -47,6 +47,9 @@ public:
|
|||
|
||||
static bool checkGLError(const char* name = nullptr);
|
||||
|
||||
// Only checks in debug builds
|
||||
static bool checkGLErrorDebug(const char* name = nullptr);
|
||||
|
||||
static bool makeProgram(Shader& shader, const Shader::BindingSet& bindings = Shader::BindingSet());
|
||||
|
||||
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#include "GPULogging.h"
|
||||
#include "GLBackendShared.h"
|
||||
|
||||
using namespace gpu;
|
||||
|
||||
GLBackend::GLFramebuffer::GLFramebuffer() {}
|
||||
|
||||
|
|
|
@ -17,9 +17,7 @@
|
|||
|
||||
#include "Batch.h"
|
||||
|
||||
using namespace gpu;
|
||||
|
||||
static const GLenum _primitiveToGLmode[NUM_PRIMITIVES] = {
|
||||
static const GLenum _primitiveToGLmode[gpu::NUM_PRIMITIVES] = {
|
||||
GL_POINTS,
|
||||
GL_LINES,
|
||||
GL_LINE_STRIP,
|
||||
|
@ -30,7 +28,7 @@ static const GLenum _primitiveToGLmode[NUM_PRIMITIVES] = {
|
|||
GL_QUAD_STRIP,
|
||||
};
|
||||
|
||||
static const GLenum _elementTypeToGLType[NUM_TYPES]= {
|
||||
static const GLenum _elementTypeToGLType[gpu::NUM_TYPES] = {
|
||||
GL_FLOAT,
|
||||
GL_INT,
|
||||
GL_UNSIGNED_INT,
|
||||
|
@ -49,10 +47,8 @@ static const GLenum _elementTypeToGLType[NUM_TYPES]= {
|
|||
GL_UNSIGNED_BYTE
|
||||
};
|
||||
|
||||
#if _DEBUG
|
||||
#define CHECK_GL_ERROR() ::gpu::GLBackend::checkGLError(__FUNCTION__)
|
||||
#else
|
||||
#define CHECK_GL_ERROR() false
|
||||
#endif
|
||||
// Stupid preprocessor trick to turn the line macro into a string
|
||||
#define CHECK_GL_ERROR_HELPER(x) #x
|
||||
#define CHECK_GL_ERROR() gpu::GLBackend::checkGLErrorDebug(__FUNCTION__ ":" CHECK_GL_ERROR_HELPER(__LINE__))
|
||||
|
||||
#endif
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#include "GPULogging.h"
|
||||
#include "GLBackendShared.h"
|
||||
|
||||
using namespace gpu;
|
||||
|
||||
GLBackend::GLTexture::GLTexture() :
|
||||
_storageStamp(0),
|
||||
|
|
|
@ -384,10 +384,12 @@ bool OctreePacketData::appendValue(const glm::vec3& value) {
|
|||
bool OctreePacketData::appendValue(const QVector<glm::vec3>& value) {
|
||||
uint16_t qVecSize = value.size();
|
||||
bool success = appendValue(qVecSize);
|
||||
success = append((const unsigned char*)value.constData(), qVecSize * sizeof(glm::vec3));
|
||||
if (success) {
|
||||
_bytesOfValues += qVecSize * sizeof(glm::vec3);
|
||||
_totalBytesOfValues += qVecSize * sizeof(glm::vec3);
|
||||
success = append((const unsigned char*)value.constData(), qVecSize * sizeof(glm::vec3));
|
||||
if (success) {
|
||||
_bytesOfValues += qVecSize * sizeof(glm::vec3);
|
||||
_totalBytesOfValues += qVecSize * sizeof(glm::vec3);
|
||||
}
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
|
|
@ -270,7 +270,7 @@ void MeshMassProperties::computeMassProperties(const VectorOfPoints& points, con
|
|||
}
|
||||
|
||||
// create some variables to hold temporary results
|
||||
#ifdef DEBUG
|
||||
#ifndef NDEBUG
|
||||
uint32_t numPoints = points.size();
|
||||
#endif
|
||||
const btVector3 p0(0.0f, 0.0f, 0.0f);
|
||||
|
@ -283,9 +283,11 @@ void MeshMassProperties::computeMassProperties(const VectorOfPoints& points, con
|
|||
uint32_t numTriangles = triangleIndices.size() / 3;
|
||||
for (uint32_t i = 0; i < numTriangles; ++i) {
|
||||
uint32_t t = 3 * i;
|
||||
#ifndef NDEBUG
|
||||
assert(triangleIndices[t] < numPoints);
|
||||
assert(triangleIndices[t + 1] < numPoints);
|
||||
assert(triangleIndices[t + 2] < numPoints);
|
||||
#endif
|
||||
|
||||
// extract raw vertices
|
||||
tetraPoints[0] = p0;
|
||||
|
|
|
@ -2,8 +2,20 @@ set(TARGET_NAME shared)
|
|||
|
||||
# use setup_hifi_library macro to setup our project and link appropriate Qt modules
|
||||
# TODO: there isn't really a good reason to have Script linked here - let's get what is requiring it out (RegisteredMetaTypes.cpp)
|
||||
setup_hifi_library(Gui Network Script Widgets)
|
||||
setup_hifi_library(Gui Network OpenGL Script Widgets)
|
||||
|
||||
setup_hifi_opengl()
|
||||
|
||||
add_dependency_external_projects(glm)
|
||||
find_package(GLM REQUIRED)
|
||||
target_include_directories(${TARGET_NAME} PUBLIC ${GLM_INCLUDE_DIRS})
|
||||
target_include_directories(${TARGET_NAME} PUBLIC ${GLM_INCLUDE_DIRS})
|
||||
|
||||
if (WIN32)
|
||||
add_dependency_external_projects(boostconfig)
|
||||
find_package(BoostConfig REQUIRED)
|
||||
target_include_directories(${TARGET_NAME} PUBLIC ${BOOSTCONFIG_INCLUDE_DIRS})
|
||||
|
||||
add_dependency_external_projects(oglplus)
|
||||
find_package(OGLPLUS REQUIRED)
|
||||
target_include_directories(${TARGET_NAME} PUBLIC ${OGLPLUS_INCLUDE_DIRS})
|
||||
endif()
|
|
@ -118,13 +118,15 @@ public:
|
|||
|
||||
template <typename Function>
|
||||
void withPush(Function f) {
|
||||
#ifdef DEBUG
|
||||
#ifndef NDEBUG
|
||||
size_t startingDepth = size();
|
||||
#endif
|
||||
push();
|
||||
f();
|
||||
pop();
|
||||
assert(startingDepth = size());
|
||||
#ifndef NDEBUG
|
||||
assert(startingDepth == size());
|
||||
#endif
|
||||
}
|
||||
|
||||
template <typename Function>
|
||||
|
|
325
libraries/shared/src/OglplusHelpers.cpp
Normal file
325
libraries/shared/src/OglplusHelpers.cpp
Normal file
|
@ -0,0 +1,325 @@
|
|||
#ifdef Q_OS_WIN
|
||||
|
||||
//
|
||||
// Created by Bradley Austin Davis on 2015/05/29
|
||||
// Copyright 2015 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
#include "OglplusHelpers.h"
|
||||
|
||||
using namespace oglplus;
|
||||
using namespace oglplus::shapes;
|
||||
|
||||
static const char * SIMPLE_TEXTURED_VS = R"VS(#version 410 core
|
||||
#pragma line __LINE__
|
||||
|
||||
uniform mat4 Projection = mat4(1);
|
||||
uniform mat4 ModelView = mat4(1);
|
||||
|
||||
layout(location = 0) in vec3 Position;
|
||||
layout(location = 1) in vec2 TexCoord;
|
||||
|
||||
out vec2 vTexCoord;
|
||||
|
||||
void main() {
|
||||
gl_Position = Projection * ModelView * vec4(Position, 1);
|
||||
vTexCoord = TexCoord;
|
||||
}
|
||||
|
||||
)VS";
|
||||
|
||||
static const char * SIMPLE_TEXTURED_FS = R"FS(#version 410 core
|
||||
#pragma line __LINE__
|
||||
|
||||
uniform sampler2D sampler;
|
||||
uniform float Alpha = 1.0;
|
||||
|
||||
in vec2 vTexCoord;
|
||||
out vec4 vFragColor;
|
||||
|
||||
void main() {
|
||||
vec4 c = texture(sampler, vTexCoord);
|
||||
c.a = min(Alpha, c.a);
|
||||
vFragColor = c;
|
||||
}
|
||||
|
||||
)FS";
|
||||
|
||||
|
||||
ProgramPtr loadDefaultShader() {
|
||||
ProgramPtr result;
|
||||
compileProgram(result, SIMPLE_TEXTURED_VS, SIMPLE_TEXTURED_FS);
|
||||
return result;
|
||||
}
|
||||
|
||||
void compileProgram(ProgramPtr & result, const std::string& vs, const std::string& fs) {
|
||||
using namespace oglplus;
|
||||
try {
|
||||
result = ProgramPtr(new Program());
|
||||
// attach the shaders to the program
|
||||
result->AttachShader(
|
||||
VertexShader()
|
||||
.Source(GLSLSource(vs))
|
||||
.Compile()
|
||||
);
|
||||
result->AttachShader(
|
||||
FragmentShader()
|
||||
.Source(GLSLSource(fs))
|
||||
.Compile()
|
||||
);
|
||||
result->Link();
|
||||
} catch (ProgramBuildError & err) {
|
||||
Q_UNUSED(err);
|
||||
Q_ASSERT_X(false, "compileProgram", "Failed to build shader program");
|
||||
qFatal((const char*)err.Message);
|
||||
result.reset();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
ShapeWrapperPtr loadPlane(ProgramPtr program, float aspect) {
|
||||
using namespace oglplus;
|
||||
Vec3f a(1, 0, 0);
|
||||
Vec3f b(0, 1, 0);
|
||||
if (aspect > 1) {
|
||||
b[1] /= aspect;
|
||||
} else {
|
||||
a[0] *= aspect;
|
||||
}
|
||||
return ShapeWrapperPtr(
|
||||
new shapes::ShapeWrapper({ "Position", "TexCoord" }, shapes::Plane(a, b), *program)
|
||||
);
|
||||
}
|
||||
|
||||
// Return a point's cartesian coordinates on a sphere from pitch and yaw
|
||||
static glm::vec3 getPoint(float yaw, float pitch) {
|
||||
return glm::vec3(glm::cos(-pitch) * (-glm::sin(yaw)),
|
||||
glm::sin(-pitch),
|
||||
glm::cos(-pitch) * (-glm::cos(yaw)));
|
||||
}
|
||||
|
||||
|
||||
class SphereSection : public DrawingInstructionWriter, public DrawMode {
|
||||
public:
|
||||
using IndexArray = std::vector<GLuint>;
|
||||
using PosArray = std::vector<float>;
|
||||
using TexArray = std::vector<float>;
|
||||
/// The type of the index container returned by Indices()
|
||||
// vertex positions
|
||||
PosArray _pos_data;
|
||||
// vertex tex coords
|
||||
TexArray _tex_data;
|
||||
IndexArray _idx_data;
|
||||
unsigned int _prim_count{ 0 };
|
||||
|
||||
public:
|
||||
SphereSection(
|
||||
const float fov,
|
||||
const float aspectRatio,
|
||||
const int slices_,
|
||||
const int stacks_) {
|
||||
//UV mapping source: http://www.mvps.org/directx/articles/spheremap.htm
|
||||
if (fov >= PI) {
|
||||
qDebug() << "TexturedHemisphere::buildVBO(): FOV greater or equal than Pi will create issues";
|
||||
}
|
||||
|
||||
int gridSize = std::max(slices_, stacks_);
|
||||
int gridSizeLog2 = 1;
|
||||
while (1 << gridSizeLog2 < gridSize) {
|
||||
++gridSizeLog2;
|
||||
}
|
||||
gridSize = (1 << gridSizeLog2) + 1;
|
||||
// Compute number of vertices needed
|
||||
int vertices = gridSize * gridSize;
|
||||
_pos_data.resize(vertices * 3);
|
||||
_tex_data.resize(vertices * 2);
|
||||
|
||||
// Compute vertices positions and texture UV coordinate
|
||||
for (int y = 0; y <= gridSize; ++y) {
|
||||
for (int x = 0; x <= gridSize; ++x) {
|
||||
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < gridSize; i++) {
|
||||
float stacksRatio = (float)i / (float)(gridSize - 1); // First stack is 0.0f, last stack is 1.0f
|
||||
// abs(theta) <= fov / 2.0f
|
||||
float pitch = -fov * (stacksRatio - 0.5f);
|
||||
for (int j = 0; j < gridSize; j++) {
|
||||
float slicesRatio = (float)j / (float)(gridSize - 1); // First slice is 0.0f, last slice is 1.0f
|
||||
// abs(phi) <= fov * aspectRatio / 2.0f
|
||||
float yaw = -fov * aspectRatio * (slicesRatio - 0.5f);
|
||||
int vertex = i * gridSize + j;
|
||||
int posOffset = vertex * 3;
|
||||
int texOffset = vertex * 2;
|
||||
vec3 pos = getPoint(yaw, pitch);
|
||||
_pos_data[posOffset] = pos.x;
|
||||
_pos_data[posOffset + 1] = pos.y;
|
||||
_pos_data[posOffset + 2] = pos.z;
|
||||
_tex_data[texOffset] = slicesRatio;
|
||||
_tex_data[texOffset + 1] = stacksRatio;
|
||||
}
|
||||
} // done with vertices
|
||||
|
||||
int rowLen = gridSize;
|
||||
|
||||
// gridsize now refers to the triangles, not the vertices, so reduce by one
|
||||
// or die by fencepost error http://en.wikipedia.org/wiki/Off-by-one_error
|
||||
--gridSize;
|
||||
int quads = gridSize * gridSize;
|
||||
for (int t = 0; t < quads; ++t) {
|
||||
int x =
|
||||
((t & 0x0001) >> 0) |
|
||||
((t & 0x0004) >> 1) |
|
||||
((t & 0x0010) >> 2) |
|
||||
((t & 0x0040) >> 3) |
|
||||
((t & 0x0100) >> 4) |
|
||||
((t & 0x0400) >> 5) |
|
||||
((t & 0x1000) >> 6) |
|
||||
((t & 0x4000) >> 7);
|
||||
int y =
|
||||
((t & 0x0002) >> 1) |
|
||||
((t & 0x0008) >> 2) |
|
||||
((t & 0x0020) >> 3) |
|
||||
((t & 0x0080) >> 4) |
|
||||
((t & 0x0200) >> 5) |
|
||||
((t & 0x0800) >> 6) |
|
||||
((t & 0x2000) >> 7) |
|
||||
((t & 0x8000) >> 8);
|
||||
int i = x * (rowLen) + y;
|
||||
|
||||
_idx_data.push_back(i);
|
||||
_idx_data.push_back(i + 1);
|
||||
_idx_data.push_back(i + rowLen + 1);
|
||||
|
||||
_idx_data.push_back(i + rowLen + 1);
|
||||
_idx_data.push_back(i + rowLen);
|
||||
_idx_data.push_back(i);
|
||||
}
|
||||
_prim_count = quads * 2;
|
||||
}
|
||||
|
||||
/// Returns the winding direction of faces
|
||||
FaceOrientation FaceWinding(void) const {
|
||||
return FaceOrientation::CCW;
|
||||
}
|
||||
|
||||
typedef GLuint(SphereSection::*VertexAttribFunc)(std::vector<GLfloat>&) const;
|
||||
|
||||
/// Makes the vertex positions and returns the number of values per vertex
|
||||
template <typename T>
|
||||
GLuint Positions(std::vector<T>& dest) const {
|
||||
dest.clear();
|
||||
dest.insert(dest.begin(), _pos_data.begin(), _pos_data.end());
|
||||
return 3;
|
||||
}
|
||||
|
||||
/// Makes the vertex normals and returns the number of values per vertex
|
||||
template <typename T>
|
||||
GLuint Normals(std::vector<T>& dest) const {
|
||||
dest.clear();
|
||||
return 3;
|
||||
}
|
||||
|
||||
/// Makes the vertex tangents and returns the number of values per vertex
|
||||
template <typename T>
|
||||
GLuint Tangents(std::vector<T>& dest) const {
|
||||
dest.clear();
|
||||
return 3;
|
||||
}
|
||||
|
||||
/// Makes the vertex bi-tangents and returns the number of values per vertex
|
||||
template <typename T>
|
||||
GLuint Bitangents(std::vector<T>& dest) const {
|
||||
dest.clear();
|
||||
return 3;
|
||||
}
|
||||
|
||||
/// Makes the texture coordinates returns the number of values per vertex
|
||||
template <typename T>
|
||||
GLuint TexCoordinates(std::vector<T>& dest) const {
|
||||
dest.clear();
|
||||
dest.insert(dest.begin(), _tex_data.begin(), _tex_data.end());
|
||||
return 2;
|
||||
}
|
||||
|
||||
typedef VertexAttribsInfo<
|
||||
SphereSection,
|
||||
std::tuple<
|
||||
VertexPositionsTag,
|
||||
VertexNormalsTag,
|
||||
VertexTangentsTag,
|
||||
VertexBitangentsTag,
|
||||
VertexTexCoordinatesTag
|
||||
>
|
||||
> VertexAttribs;
|
||||
|
||||
Spheref MakeBoundingSphere(void) const {
|
||||
GLfloat min_x = _pos_data[3], max_x = _pos_data[3];
|
||||
GLfloat min_y = _pos_data[4], max_y = _pos_data[4];
|
||||
GLfloat min_z = _pos_data[5], max_z = _pos_data[5];
|
||||
for (std::size_t v = 0, vn = _pos_data.size() / 3; v != vn; ++v) {
|
||||
GLfloat x = _pos_data[v * 3 + 0];
|
||||
GLfloat y = _pos_data[v * 3 + 1];
|
||||
GLfloat z = _pos_data[v * 3 + 2];
|
||||
|
||||
if (min_x > x) min_x = x;
|
||||
if (min_y > y) min_y = y;
|
||||
if (min_z > z) min_z = z;
|
||||
if (max_x < x) max_x = x;
|
||||
if (max_y < y) max_y = y;
|
||||
if (max_z < z) max_z = z;
|
||||
}
|
||||
|
||||
Vec3f c(
|
||||
(min_x + max_x) * 0.5f,
|
||||
(min_y + max_y) * 0.5f,
|
||||
(min_z + max_z) * 0.5f
|
||||
);
|
||||
|
||||
return Spheref(
|
||||
c.x(), c.y(), c.z(),
|
||||
Distance(c, Vec3f(min_x, min_y, min_z))
|
||||
);
|
||||
}
|
||||
|
||||
/// Queries the bounding sphere coordinates and dimensions
|
||||
template <typename T>
|
||||
void BoundingSphere(oglplus::Sphere<T>& bounding_sphere) const {
|
||||
bounding_sphere = oglplus::Sphere<T>(MakeBoundingSphere());
|
||||
}
|
||||
|
||||
|
||||
/// Returns element indices that are used with the drawing instructions
|
||||
const IndexArray & Indices(Default = Default()) const {
|
||||
return _idx_data;
|
||||
}
|
||||
|
||||
/// Returns the instructions for rendering of faces
|
||||
DrawingInstructions Instructions(PrimitiveType primitive) const {
|
||||
DrawingInstructions instr = this->MakeInstructions();
|
||||
DrawOperation operation;
|
||||
operation.method = DrawOperation::Method::DrawElements;
|
||||
operation.mode = primitive;
|
||||
operation.first = 0;
|
||||
operation.count = _prim_count * 3;
|
||||
operation.restart_index = DrawOperation::NoRestartIndex();
|
||||
operation.phase = 0;
|
||||
this->AddInstruction(instr, operation);
|
||||
return std::move(instr);
|
||||
}
|
||||
|
||||
/// Returns the instructions for rendering of faces
|
||||
DrawingInstructions Instructions(Default = Default()) const {
|
||||
return Instructions(PrimitiveType::Triangles);
|
||||
}
|
||||
};
|
||||
|
||||
ShapeWrapperPtr loadSphereSection(ProgramPtr program, float fov, float aspect, int slices, int stacks) {
|
||||
using namespace oglplus;
|
||||
return ShapeWrapperPtr(
|
||||
new shapes::ShapeWrapper({ "Position", "TexCoord" }, SphereSection(fov, aspect, slices, stacks), *program)
|
||||
);
|
||||
}
|
||||
#endif
|
173
libraries/shared/src/OglplusHelpers.h
Normal file
173
libraries/shared/src/OglplusHelpers.h
Normal file
|
@ -0,0 +1,173 @@
|
|||
//
|
||||
// Created by Bradley Austin Davis on 2015/05/26
|
||||
// Copyright 2015 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
#pragma once
|
||||
|
||||
// FIXME support oglplus on all platforms
|
||||
// For now it's a convenient helper for Windows
|
||||
|
||||
#include <QtGlobal>
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
#include "GLMHelpers.h"
|
||||
|
||||
#define OGLPLUS_USE_GLCOREARB_H 0
|
||||
|
||||
#if defined(__APPLE__)
|
||||
|
||||
#define OGLPLUS_USE_GL3_H 1
|
||||
|
||||
#elif defined(WIN32)
|
||||
|
||||
#define OGLPLUS_USE_GLEW 1
|
||||
#pragma warning(disable : 4068)
|
||||
|
||||
#elif defined(ANDROID)
|
||||
|
||||
#else
|
||||
|
||||
#define OGLPLUS_USE_GLCOREARB_H 1
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#define OGLPLUS_USE_BOOST_CONFIG 1
|
||||
#define OGLPLUS_NO_SITE_CONFIG 1
|
||||
#define OGLPLUS_LOW_PROFILE 1
|
||||
#include <oglplus/gl.hpp>
|
||||
|
||||
#include <oglplus/all.hpp>
|
||||
#include <oglplus/interop/glm.hpp>
|
||||
#include <oglplus/bound/texture.hpp>
|
||||
#include <oglplus/bound/framebuffer.hpp>
|
||||
#include <oglplus/bound/renderbuffer.hpp>
|
||||
#include <oglplus/shapes/wrapper.hpp>
|
||||
#include <oglplus/shapes/plane.hpp>
|
||||
|
||||
#include "NumericalConstants.h"
|
||||
|
||||
using FramebufferPtr = std::shared_ptr<oglplus::Framebuffer>;
|
||||
using ShapeWrapperPtr = std::shared_ptr<oglplus::shapes::ShapeWrapper>;
|
||||
using BufferPtr = std::shared_ptr<oglplus::Buffer>;
|
||||
using VertexArrayPtr = std::shared_ptr<oglplus::VertexArray>;
|
||||
using ProgramPtr = std::shared_ptr<oglplus::Program>;
|
||||
using Mat4Uniform = oglplus::Uniform<mat4>;
|
||||
|
||||
ProgramPtr loadDefaultShader();
|
||||
void compileProgram(ProgramPtr & result, const std::string& vs, const std::string& fs);
|
||||
ShapeWrapperPtr loadPlane(ProgramPtr program, float aspect = 1.0f);
|
||||
ShapeWrapperPtr loadSphereSection(ProgramPtr program, float fov = PI / 3.0f * 2.0f, float aspect = 16.0f / 9.0f, int slices = 32, int stacks = 32);
|
||||
|
||||
|
||||
// A basic wrapper for constructing a framebuffer with a renderbuffer
|
||||
// for the depth attachment and an undefined type for the color attachement
|
||||
// This allows us to reuse the basic framebuffer code for both the Mirror
|
||||
// FBO as well as the Oculus swap textures we will use to render the scene
|
||||
// Though we don't really need depth at all for the mirror FBO, or even an
|
||||
// FBO, but using one means I can just use a glBlitFramebuffer to get it onto
|
||||
// the screen.
|
||||
template <
|
||||
typename C,
|
||||
typename D
|
||||
>
|
||||
struct FramebufferWrapper {
|
||||
uvec2 size;
|
||||
oglplus::Framebuffer fbo;
|
||||
C color;
|
||||
D depth;
|
||||
|
||||
FramebufferWrapper() {}
|
||||
|
||||
virtual ~FramebufferWrapper() {
|
||||
}
|
||||
|
||||
virtual void Init(const uvec2 & size) {
|
||||
this->size = size;
|
||||
initColor();
|
||||
initDepth();
|
||||
initDone();
|
||||
}
|
||||
|
||||
template <typename F>
|
||||
void Bound(F f) {
|
||||
Bound(oglplus::Framebuffer::Target::Draw, f);
|
||||
}
|
||||
|
||||
template <typename F>
|
||||
void Bound(oglplus::Framebuffer::Target target , F f) {
|
||||
fbo.Bind(target);
|
||||
onBind(target);
|
||||
f();
|
||||
onUnbind(target);
|
||||
oglplus::DefaultFramebuffer().Bind(target);
|
||||
}
|
||||
|
||||
void Viewport() {
|
||||
oglplus::Context::Viewport(size.x, size.y);
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual void onBind(oglplus::Framebuffer::Target target) {}
|
||||
virtual void onUnbind(oglplus::Framebuffer::Target target) {}
|
||||
|
||||
static GLenum toEnum(oglplus::Framebuffer::Target target) {
|
||||
switch (target) {
|
||||
case oglplus::Framebuffer::Target::Draw:
|
||||
return GL_DRAW_FRAMEBUFFER;
|
||||
case oglplus::Framebuffer::Target::Read:
|
||||
return GL_READ_FRAMEBUFFER;
|
||||
default:
|
||||
Q_ASSERT(false);
|
||||
return GL_FRAMEBUFFER;
|
||||
}
|
||||
}
|
||||
|
||||
virtual void initDepth() {}
|
||||
|
||||
virtual void initColor() {}
|
||||
|
||||
virtual void initDone() = 0;
|
||||
};
|
||||
|
||||
struct BasicFramebufferWrapper : public FramebufferWrapper <oglplus::Texture, oglplus::Renderbuffer> {
|
||||
protected:
|
||||
virtual void initDepth() override {
|
||||
using namespace oglplus;
|
||||
Context::Bound(Renderbuffer::Target::Renderbuffer, depth)
|
||||
.Storage(
|
||||
PixelDataInternalFormat::DepthComponent,
|
||||
size.x, size.y);
|
||||
}
|
||||
|
||||
virtual void initColor() override {
|
||||
using namespace oglplus;
|
||||
Context::Bound(oglplus::Texture::Target::_2D, color)
|
||||
.MinFilter(TextureMinFilter::Linear)
|
||||
.MagFilter(TextureMagFilter::Linear)
|
||||
.WrapS(TextureWrap::ClampToEdge)
|
||||
.WrapT(TextureWrap::ClampToEdge)
|
||||
.Image2D(
|
||||
0, PixelDataInternalFormat::RGBA8,
|
||||
size.x, size.y,
|
||||
0, PixelDataFormat::RGB, PixelDataType::UnsignedByte, nullptr
|
||||
);
|
||||
}
|
||||
|
||||
virtual void initDone() override {
|
||||
using namespace oglplus;
|
||||
static const Framebuffer::Target target = Framebuffer::Target::Draw;
|
||||
Bound(target, [&] {
|
||||
fbo.AttachTexture(target, FramebufferAttachment::Color, color, 0);
|
||||
fbo.AttachRenderbuffer(target, FramebufferAttachment::Depth, depth);
|
||||
fbo.Complete(target);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
using BasicFramebufferWrapperPtr = std::shared_ptr<BasicFramebufferWrapper>;
|
||||
#endif
|
|
@ -13,35 +13,61 @@
|
|||
#include "SharedLogging.h"
|
||||
#include "VariantMapToScriptValue.h"
|
||||
|
||||
|
||||
QScriptValue variantToScriptValue(QVariant& qValue, QScriptEngine& scriptEngine) {
|
||||
switch(qValue.type()) {
|
||||
case QVariant::Bool:
|
||||
return qValue.toBool();
|
||||
break;
|
||||
case QVariant::Int:
|
||||
return qValue.toInt();
|
||||
break;
|
||||
case QVariant::Double:
|
||||
return qValue.toDouble();
|
||||
break;
|
||||
case QVariant::String: {
|
||||
return scriptEngine.newVariant(qValue);
|
||||
break;
|
||||
}
|
||||
case QVariant::Map: {
|
||||
QVariantMap childMap = qValue.toMap();
|
||||
return variantMapToScriptValue(childMap, scriptEngine);
|
||||
break;
|
||||
}
|
||||
case QVariant::List: {
|
||||
QVariantList childList = qValue.toList();
|
||||
return variantListToScriptValue(childList, scriptEngine);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
qCDebug(shared) << "unhandled QScript type" << qValue.type();
|
||||
break;
|
||||
}
|
||||
|
||||
return QScriptValue();
|
||||
}
|
||||
|
||||
|
||||
QScriptValue variantMapToScriptValue(QVariantMap& variantMap, QScriptEngine& scriptEngine) {
|
||||
QScriptValue scriptValue = scriptEngine.newObject();
|
||||
|
||||
for (QVariantMap::const_iterator iter = variantMap.begin(); iter != variantMap.end(); ++iter) {
|
||||
QString key = iter.key();
|
||||
QVariant qValue = iter.value();
|
||||
|
||||
switch(qValue.type()) {
|
||||
case QVariant::Bool:
|
||||
scriptValue.setProperty(key, qValue.toBool());
|
||||
break;
|
||||
case QVariant::Int:
|
||||
scriptValue.setProperty(key, qValue.toInt());
|
||||
break;
|
||||
case QVariant::Double:
|
||||
scriptValue.setProperty(key, qValue.toDouble());
|
||||
break;
|
||||
case QVariant::String: {
|
||||
scriptValue.setProperty(key, scriptEngine.newVariant(qValue));
|
||||
break;
|
||||
}
|
||||
case QVariant::Map: {
|
||||
QVariantMap childMap = qValue.toMap();
|
||||
scriptValue.setProperty(key, variantMapToScriptValue(childMap, scriptEngine));
|
||||
break;
|
||||
}
|
||||
default:
|
||||
qCDebug(shared) << "unhandled QScript type" << qValue.type();
|
||||
}
|
||||
scriptValue.setProperty(key, variantToScriptValue(qValue, scriptEngine));
|
||||
}
|
||||
|
||||
return scriptValue;
|
||||
}
|
||||
|
||||
|
||||
QScriptValue variantListToScriptValue(QVariantList& variantList, QScriptEngine& scriptEngine) {
|
||||
QScriptValue scriptValue = scriptEngine.newObject();
|
||||
|
||||
scriptValue.setProperty("length", variantList.size());
|
||||
int i = 0;
|
||||
foreach (QVariant v, variantList) {
|
||||
scriptValue.setProperty(i++, variantToScriptValue(v, scriptEngine));
|
||||
}
|
||||
|
||||
return scriptValue;
|
||||
|
|
|
@ -13,4 +13,6 @@
|
|||
#include <QScriptValue>
|
||||
#include <QScriptEngine>
|
||||
|
||||
QScriptValue variantToScriptValue(QVariant& qValue, QScriptEngine& scriptEngine);
|
||||
QScriptValue variantMapToScriptValue(QVariantMap& variantMap, QScriptEngine& scriptEngine);
|
||||
QScriptValue variantListToScriptValue(QVariantList& variantList, QScriptEngine& scriptEngine);
|
||||
|
|
Loading…
Reference in a new issue