Merge branch 'temp' into overlay

This commit is contained in:
Brad Davis 2015-06-18 00:59:31 -07:00
commit 5c4fa77acd
25 changed files with 1014 additions and 578 deletions

View file

@ -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 ""

View file

@ -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)

View file

@ -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)

View 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()

View file

@ -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

View file

@ -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 {

View file

@ -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) {

View file

@ -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);
}

View file

@ -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)));

View file

@ -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());

View file

@ -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();

View file

@ -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;

View file

@ -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();

View file

@ -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());

View file

@ -11,6 +11,7 @@
#include "GPULogging.h"
#include "GLBackendShared.h"
using namespace gpu;
GLBackend::GLFramebuffer::GLFramebuffer() {}

View file

@ -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

View file

@ -11,6 +11,7 @@
#include "GPULogging.h"
#include "GLBackendShared.h"
using namespace gpu;
GLBackend::GLTexture::GLTexture() :
_storageStamp(0),

View file

@ -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;
}

View file

@ -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;

View file

@ -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()

View file

@ -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>

View 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

View 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

View file

@ -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;

View file

@ -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);