diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 05a195c904..7fad196cd0 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -905,7 +905,9 @@ void Application::keyPressEvent(QKeyEvent* event) { break; case Qt::Key_D: - _myAvatar->setDriveKeys(ROT_RIGHT, 1.f); + if (!isMeta) { + _myAvatar->setDriveKeys(ROT_RIGHT, 1.f); + } break; case Qt::Key_Return: @@ -1073,7 +1075,7 @@ void Application::keyReleaseEvent(QKeyEvent* event) { _keysPressed.remove(event->key()); _controllerScriptingInterface.emitKeyReleaseEvent(event); // send events to any registered scripts - + // if one of our scripts have asked to capture this event, then stop processing it if (_controllerScriptingInterface.isKeyCaptured(event)) { return; @@ -1125,7 +1127,12 @@ void Application::keyReleaseEvent(QKeyEvent* event) { _myAvatar->setDriveKeys(RIGHT, 0.f); _myAvatar->setDriveKeys(ROT_RIGHT, 0.f); break; - + case Qt::Key_Control: + case Qt::Key_Shift: + case Qt::Key_Meta: + case Qt::Key_Alt: + _myAvatar->clearDriveKeys(); + break; default: event->ignore(); break; @@ -2724,6 +2731,9 @@ void Application::displaySide(Camera& whichCamera, bool selfAvatarOnly) { PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), "Application::displaySide()"); // transform by eye offset + // load the view frustum + loadViewFrustum(whichCamera, _displayViewFrustum); + // flip x if in mirror mode (also requires reversing winding order for backface culling) if (whichCamera.getMode() == CAMERA_MODE_MIRROR) { glScalef(-1.0f, 1.0f, 1.0f); @@ -2971,7 +2981,14 @@ void Application::getProjectionMatrix(glm::dmat4* projectionMatrix) { void Application::computeOffAxisFrustum(float& left, float& right, float& bottom, float& top, float& nearVal, float& farVal, glm::vec4& nearClipPlane, glm::vec4& farClipPlane) const { + // allow 3DTV/Oculus to override parameters from camera _viewFrustum.computeOffAxisFrustum(left, right, bottom, top, nearVal, farVal, nearClipPlane, farClipPlane); + if (OculusManager::isConnected()) { + OculusManager::overrideOffAxisFrustum(left, right, bottom, top, nearVal, farVal, nearClipPlane, farClipPlane); + + } else if (TV3DManager::isConnected()) { + TV3DManager::overrideOffAxisFrustum(left, right, bottom, top, nearVal, farVal, nearClipPlane, farClipPlane); + } } glm::vec2 Application::getScaledScreenPoint(glm::vec2 projectedPoint) { diff --git a/interface/src/Application.h b/interface/src/Application.h index f48d88d7a4..fbcc67cf80 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -192,6 +192,7 @@ public: const AudioReflector* getAudioReflector() const { return &_audioReflector; } Camera* getCamera() { return &_myCamera; } ViewFrustum* getViewFrustum() { return &_viewFrustum; } + ViewFrustum* getDisplayViewFrustum() { return &_displayViewFrustum; } ViewFrustum* getShadowViewFrustum() { return &_shadowViewFrustum; } VoxelImporter* getVoxelImporter() { return &_voxelImporter; } VoxelSystem* getVoxels() { return &_voxels; } @@ -486,6 +487,7 @@ private: ViewFrustum _viewFrustum; // current state of view frustum, perspective, orientation, etc. ViewFrustum _lastQueriedViewFrustum; /// last view frustum used to query octree servers (voxels, particles) + ViewFrustum _displayViewFrustum; ViewFrustum _shadowViewFrustum; quint64 _lastQueriedTime; diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index d7679968ae..ff5e50d66c 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -70,6 +70,7 @@ Menu* Menu::getInstance() { const ViewFrustumOffset DEFAULT_FRUSTUM_OFFSET = {-135.0f, 0.0f, 0.0f, 25.0f, 0.0f}; const float DEFAULT_FACESHIFT_EYE_DEFLECTION = 0.25f; +const QString DEFAULT_FACESHIFT_HOSTNAME = "localhost"; const float DEFAULT_AVATAR_LOD_DISTANCE_MULTIPLIER = 1.0f; const int ONE_SECOND_OF_FRAMES = 60; const int FIVE_SECONDS_OF_FRAMES = 5 * ONE_SECOND_OF_FRAMES; @@ -87,6 +88,7 @@ Menu::Menu() : _fieldOfView(DEFAULT_FIELD_OF_VIEW_DEGREES), _realWorldFieldOfView(DEFAULT_REAL_WORLD_FIELD_OF_VIEW_DEGREES), _faceshiftEyeDeflection(DEFAULT_FACESHIFT_EYE_DEFLECTION), + _faceshiftHostname(DEFAULT_FACESHIFT_HOSTNAME), _frustumDrawMode(FRUSTUM_DRAW_MODE_ALL), _viewFrustumOffset(DEFAULT_FRUSTUM_OFFSET), _jsConsole(NULL), @@ -713,6 +715,7 @@ void Menu::loadSettings(QSettings* settings) { _fieldOfView = loadSetting(settings, "fieldOfView", DEFAULT_FIELD_OF_VIEW_DEGREES); _realWorldFieldOfView = loadSetting(settings, "realWorldFieldOfView", DEFAULT_REAL_WORLD_FIELD_OF_VIEW_DEGREES); _faceshiftEyeDeflection = loadSetting(settings, "faceshiftEyeDeflection", DEFAULT_FACESHIFT_EYE_DEFLECTION); + _faceshiftHostname = settings->value("faceshiftHostname", DEFAULT_FACESHIFT_HOSTNAME).toString(); _maxVoxels = loadSetting(settings, "maxVoxels", DEFAULT_MAX_VOXELS_PER_SYSTEM); _maxVoxelPacketsPerSecond = loadSetting(settings, "maxVoxelsPPS", DEFAULT_MAX_VOXEL_PPS); _voxelSizeScale = loadSetting(settings, "voxelSizeScale", DEFAULT_OCTREE_SIZE_SCALE); @@ -777,6 +780,7 @@ void Menu::saveSettings(QSettings* settings) { settings->setValue("fieldOfView", _fieldOfView); settings->setValue("faceshiftEyeDeflection", _faceshiftEyeDeflection); + settings->setValue("faceshiftHostname", _faceshiftHostname); settings->setValue("maxVoxels", _maxVoxels); settings->setValue("maxVoxelsPPS", _maxVoxelPacketsPerSecond); settings->setValue("voxelSizeScale", _voxelSizeScale); diff --git a/interface/src/Menu.h b/interface/src/Menu.h index 3b263add36..7ed963f473 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -104,6 +104,8 @@ public: float getFaceshiftEyeDeflection() const { return _faceshiftEyeDeflection; } void setFaceshiftEyeDeflection(float faceshiftEyeDeflection) { _faceshiftEyeDeflection = faceshiftEyeDeflection; bumpSettings(); } + const QString& getFaceshiftHostname() const { return _faceshiftHostname; } + void setFaceshiftHostname(const QString& hostname) { _faceshiftHostname = hostname; bumpSettings(); } QString getSnapshotsLocation() const; void setSnapshotsLocation(QString snapshotsLocation) { _snapshotsLocation = snapshotsLocation; bumpSettings(); } @@ -271,6 +273,7 @@ private: float _fieldOfView; /// in Degrees, doesn't apply to HMD like Oculus float _realWorldFieldOfView; // The actual FOV set by the user's monitor size and view distance float _faceshiftEyeDeflection; + QString _faceshiftHostname; FrustumDrawMode _frustumDrawMode; ViewFrustumOffset _viewFrustumOffset; QPointer _MetavoxelEditor; diff --git a/interface/src/MetavoxelSystem.cpp b/interface/src/MetavoxelSystem.cpp index 892efe7211..903e443cda 100644 --- a/interface/src/MetavoxelSystem.cpp +++ b/interface/src/MetavoxelSystem.cpp @@ -133,7 +133,7 @@ const GLenum COLOR_NORMAL_DRAW_BUFFERS[] = { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTA void MetavoxelSystem::render() { // update the frustum - ViewFrustum* viewFrustum = Application::getInstance()->getViewFrustum(); + ViewFrustum* viewFrustum = Application::getInstance()->getDisplayViewFrustum(); _frustum.set(viewFrustum->getFarTopLeft(), viewFrustum->getFarTopRight(), viewFrustum->getFarBottomLeft(), viewFrustum->getFarBottomRight(), viewFrustum->getNearTopLeft(), viewFrustum->getNearTopRight(), viewFrustum->getNearBottomLeft(), viewFrustum->getNearBottomRight()); @@ -181,6 +181,14 @@ void MetavoxelSystem::render() { glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_2D, Application::getInstance()->getTextureCache()->getPrimaryNormalTextureID()); + // get the viewport side (left, right, both) + int viewport[4]; + glGetIntegerv(GL_VIEWPORT, viewport); + const int VIEWPORT_X_INDEX = 0; + const int VIEWPORT_WIDTH_INDEX = 2; + float sMin = viewport[VIEWPORT_X_INDEX] / (float)primaryFBO->width(); + float sWidth = viewport[VIEWPORT_WIDTH_INDEX] / (float)primaryFBO->width(); + if (Menu::getInstance()->getShadowsEnabled()) { glActiveTexture(GL_TEXTURE2); glBindTexture(GL_TEXTURE_2D, Application::getInstance()->getTextureCache()->getPrimaryDepthTextureID()); @@ -210,10 +218,13 @@ void MetavoxelSystem::render() { program->setUniformValue(locations->nearLocation, nearVal); program->setUniformValue(locations->depthScale, (farVal - nearVal) / farVal); float nearScale = -1.0f / nearVal; - program->setUniformValue(locations->depthTexCoordOffset, left * nearScale, bottom * nearScale); - program->setUniformValue(locations->depthTexCoordScale, (right - left) * nearScale, (top - bottom) * nearScale); + float sScale = 1.0f / sWidth; + float depthTexCoordScaleS = (right - left) * nearScale * sScale; + program->setUniformValue(locations->depthTexCoordOffset, left * nearScale - sMin * depthTexCoordScaleS, + bottom * nearScale); + program->setUniformValue(locations->depthTexCoordScale, depthTexCoordScaleS, (top - bottom) * nearScale); - renderFullscreenQuad(); + renderFullscreenQuad(sMin, sMin + sWidth); program->release(); @@ -226,7 +237,7 @@ void MetavoxelSystem::render() { } else { _directionalLight.bind(); - renderFullscreenQuad(); + renderFullscreenQuad(sMin, sMin + sWidth); _directionalLight.release(); } @@ -245,7 +256,7 @@ void MetavoxelSystem::render() { glColor4f(1.0f, 1.0f, 1.0f, 1.0f); - renderFullscreenQuad(); + renderFullscreenQuad(sMin, sMin + sWidth); glBindTexture(GL_TEXTURE_2D, 0); glDisable(GL_TEXTURE_2D); @@ -2176,7 +2187,7 @@ private: SpannerRenderVisitor::SpannerRenderVisitor(const MetavoxelLOD& lod) : SpannerVisitor(QVector() << AttributeRegistry::getInstance()->getSpannersAttribute(), QVector(), QVector(), QVector(), - lod, encodeOrder(Application::getInstance()->getViewFrustum()->getDirection())), + lod, encodeOrder(Application::getInstance()->getDisplayViewFrustum()->getDirection())), _containmentDepth(INT_MAX) { } @@ -2212,7 +2223,7 @@ private: BufferRenderVisitor::BufferRenderVisitor(const AttributePointer& attribute) : MetavoxelVisitor(QVector() << attribute), - _order(encodeOrder(Application::getInstance()->getViewFrustum()->getDirection())), + _order(encodeOrder(Application::getInstance()->getDisplayViewFrustum()->getDirection())), _containmentDepth(INT_MAX) { } @@ -2246,12 +2257,12 @@ void DefaultMetavoxelRendererImplementation::render(MetavoxelData& data, Metavox float viewportWidth = viewport[VIEWPORT_WIDTH_INDEX]; float viewportHeight = viewport[VIEWPORT_HEIGHT_INDEX]; float viewportDiagonal = sqrtf(viewportWidth * viewportWidth + viewportHeight * viewportHeight); - float worldDiagonal = glm::distance(Application::getInstance()->getViewFrustum()->getNearBottomLeft(), - Application::getInstance()->getViewFrustum()->getNearTopRight()); + float worldDiagonal = glm::distance(Application::getInstance()->getDisplayViewFrustum()->getNearBottomLeft(), + Application::getInstance()->getDisplayViewFrustum()->getNearTopRight()); _pointProgram.bind(); _pointProgram.setUniformValue(_pointScaleLocation, viewportDiagonal * - Application::getInstance()->getViewFrustum()->getNearClip() / worldDiagonal); + Application::getInstance()->getDisplayViewFrustum()->getNearClip() / worldDiagonal); glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_COLOR_ARRAY); diff --git a/interface/src/Util.cpp b/interface/src/Util.cpp index 4dbb015459..b219509ccd 100644 --- a/interface/src/Util.cpp +++ b/interface/src/Util.cpp @@ -181,9 +181,10 @@ const glm::vec3 randVector() { } static TextRenderer* textRenderer(int mono) { - static TextRenderer* monoRenderer = new TextRenderer(MONO_FONT_FAMILY); - static TextRenderer* proportionalRenderer = new TextRenderer(SANS_FONT_FAMILY, -1, -1, false, TextRenderer::SHADOW_EFFECT); - static TextRenderer* inconsolataRenderer = new TextRenderer(INCONSOLATA_FONT_FAMILY, -1, QFont::Bold, false); + static TextRenderer* monoRenderer = TextRenderer::getInstance(MONO_FONT_FAMILY); + static TextRenderer* proportionalRenderer = TextRenderer::getInstance(SANS_FONT_FAMILY, + -1, -1, false, TextRenderer::SHADOW_EFFECT); + static TextRenderer* inconsolataRenderer = TextRenderer::getInstance(INCONSOLATA_FONT_FAMILY, -1, QFont::Bold, false); switch (mono) { case 1: return monoRenderer; diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index 5c7e89fc37..ba044c9451 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -239,8 +239,9 @@ enum TextRendererType { }; static TextRenderer* textRenderer(TextRendererType type) { - static TextRenderer* chatRenderer = new TextRenderer(SANS_FONT_FAMILY, 24, -1, false, TextRenderer::SHADOW_EFFECT); - static TextRenderer* displayNameRenderer = new TextRenderer(SANS_FONT_FAMILY, 12, -1, false, TextRenderer::NO_EFFECT); + static TextRenderer* chatRenderer = TextRenderer::getInstance(SANS_FONT_FAMILY, 24, -1, + false, TextRenderer::SHADOW_EFFECT); + static TextRenderer* displayNameRenderer = TextRenderer::getInstance(SANS_FONT_FAMILY, 12); switch(type) { case CHAT: diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 6472ba2efa..241b39028f 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -1972,3 +1972,9 @@ glm::vec3 MyAvatar::getLaserPointerTipPosition(const PalmData* palm) { return palm->getPosition(); } + +void MyAvatar::clearDriveKeys() { + for (int i = 0; i < sizeof(_driveKeys); i++) { + _driveKeys[i] = 0.0f; + } +} diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index be828e0c91..35af0faee3 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -98,6 +98,7 @@ public: AttachmentData loadAttachmentData(const QUrl& modelURL, const QString& jointName = QString()) const; // Set what driving keys are being pressed to control thrust levels + void clearDriveKeys(); void setDriveKeys(int key, float val) { _driveKeys[key] = val; }; bool getDriveKeys(int key) { return _driveKeys[key] != 0.f; }; void jump() { _shouldJump = true; }; diff --git a/interface/src/devices/Faceshift.cpp b/interface/src/devices/Faceshift.cpp index 345e635045..74e36a98d1 100644 --- a/interface/src/devices/Faceshift.cpp +++ b/interface/src/devices/Faceshift.cpp @@ -151,7 +151,7 @@ void Faceshift::connectSocket() { qDebug("Faceshift: Connecting..."); } - _tcpSocket.connectToHost("localhost", FACESHIFT_PORT); + _tcpSocket.connectToHost(Menu::getInstance()->getFaceshiftHostname(), FACESHIFT_PORT); _tracking = false; } } diff --git a/interface/src/devices/OculusManager.cpp b/interface/src/devices/OculusManager.cpp index bc6dc842ce..c47ff2c38b 100644 --- a/interface/src/devices/OculusManager.cpp +++ b/interface/src/devices/OculusManager.cpp @@ -53,6 +53,7 @@ unsigned int OculusManager::_frameIndex = 0; bool OculusManager::_frameTimingActive = false; bool OculusManager::_programInitialized = false; Camera* OculusManager::_camera = NULL; +int OculusManager::_activeEyeIndex = -1; #endif @@ -330,6 +331,8 @@ void OculusManager::display(const glm::quat &bodyOrientation, const glm::vec3 &p //Render each eye into an fbo for (int eyeIndex = 0; eyeIndex < ovrEye_Count; eyeIndex++) { + _activeEyeIndex = eyeIndex; + #if defined(__APPLE__) || defined(_WIN32) ovrEyeType eye = _ovrHmd->EyeRenderOrder[eyeIndex]; #else @@ -363,6 +366,7 @@ void OculusManager::display(const glm::quat &bodyOrientation, const glm::vec3 &p Application::getInstance()->displaySide(*_camera); applicationOverlay.displayOverlayTextureOculus(*_camera); + _activeEyeIndex = -1; } //Wait till time-warp to reduce latency @@ -528,3 +532,16 @@ QSize OculusManager::getRenderTargetSize() { return QSize(100, 100); #endif } + +void OculusManager::overrideOffAxisFrustum(float& left, float& right, float& bottom, float& top, float& nearVal, + float& farVal, glm::vec4& nearClipPlane, glm::vec4& farClipPlane) { +#ifdef HAVE_LIBOVR + if (_activeEyeIndex != -1) { + const ovrFovPort& port = _eyeFov[_activeEyeIndex]; + right = nearVal * port.RightTan; + left = -nearVal * port.LeftTan; + top = nearVal * port.UpTan; + bottom = -nearVal * port.DownTan; + } +#endif +} diff --git a/interface/src/devices/OculusManager.h b/interface/src/devices/OculusManager.h index 3959ea1ab7..d8e55647b4 100644 --- a/interface/src/devices/OculusManager.h +++ b/interface/src/devices/OculusManager.h @@ -43,6 +43,9 @@ public: static glm::vec3 getRelativePosition(); static QSize getRenderTargetSize(); + static void overrideOffAxisFrustum(float& left, float& right, float& bottom, float& top, float& nearVal, + float& farVal, glm::vec4& nearClipPlane, glm::vec4& farClipPlane); + private: #ifdef HAVE_LIBOVR static void generateDistortionMesh(); @@ -92,6 +95,7 @@ private: static bool _frameTimingActive; static bool _programInitialized; static Camera* _camera; + static int _activeEyeIndex; #endif }; diff --git a/interface/src/devices/PrioVR.cpp b/interface/src/devices/PrioVR.cpp index d6c74e4a5d..fad80fda6f 100644 --- a/interface/src/devices/PrioVR.cpp +++ b/interface/src/devices/PrioVR.cpp @@ -207,10 +207,11 @@ void PrioVR::renderCalibrationCountdown() { Application::getInstance()->disconnect(this); return; } - static TextRenderer textRenderer(MONO_FONT_FAMILY, 18, QFont::Bold, false, TextRenderer::OUTLINE_EFFECT, 2); + static TextRenderer* textRenderer = TextRenderer::getInstance(MONO_FONT_FAMILY, 18, QFont::Bold, + false, TextRenderer::OUTLINE_EFFECT, 2); QByteArray text = "Assume T-Pose in " + QByteArray::number(secondsRemaining) + "..."; - textRenderer.draw((Application::getInstance()->getGLWidget()->width() - - textRenderer.computeWidth(text.constData())) / 2, Application::getInstance()->getGLWidget()->height() / 2, + textRenderer->draw((Application::getInstance()->getGLWidget()->width() - + textRenderer->computeWidth(text.constData())) / 2, Application::getInstance()->getGLWidget()->height() / 2, text); #endif } diff --git a/interface/src/devices/TV3DManager.cpp b/interface/src/devices/TV3DManager.cpp index 2ce78b7ac1..e8644c00d0 100644 --- a/interface/src/devices/TV3DManager.cpp +++ b/interface/src/devices/TV3DManager.cpp @@ -25,6 +25,7 @@ int TV3DManager::_screenHeight = 1; double TV3DManager::_aspect = 1.0; eyeFrustum TV3DManager::_leftEye; eyeFrustum TV3DManager::_rightEye; +eyeFrustum* TV3DManager::_activeEye = NULL; bool TV3DManager::isConnected() { @@ -93,8 +94,6 @@ void TV3DManager::display(Camera& whichCamera) { int portalW = Application::getInstance()->getGLWidget()->getDeviceWidth() / 2; int portalH = Application::getInstance()->getGLWidget()->getDeviceHeight(); - const bool glowEnabled = Menu::getInstance()->isOptionChecked(MenuOption::EnableGlowEffect); - ApplicationOverlay& applicationOverlay = Application::getInstance()->getApplicationOverlay(); // We only need to render the overlays to a texture once, then we just render the texture as a quad @@ -102,9 +101,7 @@ void TV3DManager::display(Camera& whichCamera) { applicationOverlay.renderOverlay(true); const bool displayOverlays = Menu::getInstance()->isOptionChecked(MenuOption::UserInterface); - if (glowEnabled) { - Application::getInstance()->getGlowEffect()->prepare(); - } + Application::getInstance()->getGlowEffect()->prepare(); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); @@ -115,7 +112,7 @@ void TV3DManager::display(Camera& whichCamera) { glPushMatrix(); { - + _activeEye = &_leftEye; glMatrixMode(GL_PROJECTION); glLoadIdentity(); // reset projection matrix glFrustum(_leftEye.left, _leftEye.right, _leftEye.bottom, _leftEye.top, nearZ, farZ); // set left view frustum @@ -132,6 +129,7 @@ void TV3DManager::display(Camera& whichCamera) { if (displayOverlays) { applicationOverlay.displayOverlayTexture3DTV(whichCamera, _aspect, fov); } + _activeEye = NULL; } glPopMatrix(); glDisable(GL_SCISSOR_TEST); @@ -144,6 +142,7 @@ void TV3DManager::display(Camera& whichCamera) { glScissor(portalX, portalY, portalW, portalH); glPushMatrix(); { + _activeEye = &_rightEye; glMatrixMode(GL_PROJECTION); glLoadIdentity(); // reset projection matrix glFrustum(_rightEye.left, _rightEye.right, _rightEye.bottom, _rightEye.top, nearZ, farZ); // set left view frustum @@ -160,6 +159,7 @@ void TV3DManager::display(Camera& whichCamera) { if (displayOverlays) { applicationOverlay.displayOverlayTexture3DTV(whichCamera, _aspect, fov); } + _activeEye = NULL; } glPopMatrix(); glDisable(GL_SCISSOR_TEST); @@ -168,7 +168,15 @@ void TV3DManager::display(Camera& whichCamera) { glViewport(0, 0, Application::getInstance()->getGLWidget()->getDeviceWidth(), Application::getInstance()->getGLWidget()->getDeviceHeight()); - if (glowEnabled) { - Application::getInstance()->getGlowEffect()->render(); + Application::getInstance()->getGlowEffect()->render(); +} + +void TV3DManager::overrideOffAxisFrustum(float& left, float& right, float& bottom, float& top, float& nearVal, + float& farVal, glm::vec4& nearClipPlane, glm::vec4& farClipPlane) { + if (_activeEye) { + left = _activeEye->left; + right = _activeEye->right; + bottom = _activeEye->bottom; + top = _activeEye->top; } } diff --git a/interface/src/devices/TV3DManager.h b/interface/src/devices/TV3DManager.h index 91a78e9bce..2b2b9e0aa1 100644 --- a/interface/src/devices/TV3DManager.h +++ b/interface/src/devices/TV3DManager.h @@ -14,6 +14,8 @@ #include +#include + class Camera; struct eyeFrustum { @@ -32,6 +34,8 @@ public: static bool isConnected(); static void configureCamera(Camera& camera, int screenWidth, int screenHeight); static void display(Camera& whichCamera); + static void overrideOffAxisFrustum(float& left, float& right, float& bottom, float& top, float& nearVal, + float& farVal, glm::vec4& nearClipPlane, glm::vec4& farClipPlane); private: static void setFrustum(Camera& whichCamera); static int _screenWidth; @@ -39,6 +43,7 @@ private: static double _aspect; static eyeFrustum _leftEye; static eyeFrustum _rightEye; + static eyeFrustum* _activeEye; }; #endif // hifi_TV3DManager_h diff --git a/interface/src/renderer/AmbientOcclusionEffect.cpp b/interface/src/renderer/AmbientOcclusionEffect.cpp index a4977e5e01..f1c1538800 100644 --- a/interface/src/renderer/AmbientOcclusionEffect.cpp +++ b/interface/src/renderer/AmbientOcclusionEffect.cpp @@ -116,9 +116,9 @@ void AmbientOcclusionEffect::render() { glGetIntegerv(GL_VIEWPORT, viewport); const int VIEWPORT_X_INDEX = 0; const int VIEWPORT_WIDTH_INDEX = 2; - QSize widgetSize = Application::getInstance()->getGLWidget()->getDeviceSize(); - float sMin = viewport[VIEWPORT_X_INDEX] / (float)widgetSize.width(); - float sWidth = viewport[VIEWPORT_WIDTH_INDEX] / (float)widgetSize.width(); + QOpenGLFramebufferObject* primaryFBO = Application::getInstance()->getTextureCache()->getPrimaryFramebufferObject(); + float sMin = viewport[VIEWPORT_X_INDEX] / (float)primaryFBO->width(); + float sWidth = viewport[VIEWPORT_WIDTH_INDEX] / (float)primaryFBO->width(); _occlusionProgram->bind(); _occlusionProgram->setUniformValue(_nearLocation, nearVal); @@ -126,7 +126,7 @@ void AmbientOcclusionEffect::render() { _occlusionProgram->setUniformValue(_leftBottomLocation, left, bottom); _occlusionProgram->setUniformValue(_rightTopLocation, right, top); _occlusionProgram->setUniformValue(_noiseScaleLocation, viewport[VIEWPORT_WIDTH_INDEX] / (float)ROTATION_WIDTH, - widgetSize.height() / (float)ROTATION_HEIGHT); + primaryFBO->height() / (float)ROTATION_HEIGHT); _occlusionProgram->setUniformValue(_texCoordOffsetLocation, sMin, 0.0f); _occlusionProgram->setUniformValue(_texCoordScaleLocation, sWidth, 1.0f); @@ -148,7 +148,7 @@ void AmbientOcclusionEffect::render() { glBindTexture(GL_TEXTURE_2D, freeFBO->texture()); _blurProgram->bind(); - _blurProgram->setUniformValue(_blurScaleLocation, 1.0f / widgetSize.width(), 1.0f / widgetSize.height()); + _blurProgram->setUniformValue(_blurScaleLocation, 1.0f / primaryFBO->width(), 1.0f / primaryFBO->height()); renderFullscreenQuad(sMin, sMin + sWidth); diff --git a/interface/src/ui/ApplicationOverlay.cpp b/interface/src/ui/ApplicationOverlay.cpp index 20ed1d9d58..df7c2d2289 100644 --- a/interface/src/ui/ApplicationOverlay.cpp +++ b/interface/src/ui/ApplicationOverlay.cpp @@ -414,7 +414,7 @@ void ApplicationOverlay::displayOverlayTextureOculus(Camera& whichCamera) { renderTexturedHemisphere(); - renderPointersOculus(whichCamera.getPosition()); + renderPointersOculus(myAvatar->getHead()->getEyePosition()); glDepthMask(GL_TRUE); glBindTexture(GL_TEXTURE_2D, 0); diff --git a/interface/src/ui/BandwidthMeter.cpp b/interface/src/ui/BandwidthMeter.cpp index 0f41a1a5cf..327f266106 100644 --- a/interface/src/ui/BandwidthMeter.cpp +++ b/interface/src/ui/BandwidthMeter.cpp @@ -50,7 +50,7 @@ BandwidthMeter::ChannelInfo BandwidthMeter::_CHANNELS[] = { }; BandwidthMeter::BandwidthMeter() : - _textRenderer(INCONSOLATA_FONT_FAMILY, -1, QFont::Bold, false), + _textRenderer(TextRenderer::getInstance(INCONSOLATA_FONT_FAMILY, -1, QFont::Bold, false)), _scaleMaxIndex(INITIAL_SCALE_MAXIMUM_INDEX) { _channels = static_cast( malloc(sizeof(_CHANNELS)) ); @@ -140,7 +140,7 @@ void BandwidthMeter::render(int screenWidth, int screenHeight) { float totalMax = glm::max(totalIn, totalOut); // Get font / caption metrics - QFontMetrics const& fontMetrics = _textRenderer.metrics(); + QFontMetrics const& fontMetrics = _textRenderer->metrics(); int fontDescent = fontMetrics.descent(); int labelWidthIn = fontMetrics.width(CAPTION_IN); int labelWidthOut = fontMetrics.width(CAPTION_OUT); @@ -163,9 +163,9 @@ void BandwidthMeter::render(int screenWidth, int screenHeight) { // Render captions setColorRGBA(COLOR_TEXT); - _textRenderer.draw(barWidth + SPACING_LEFT_CAPTION_UNIT, textYcenteredLine, CAPTION_UNIT); - _textRenderer.draw(-labelWidthIn - SPACING_RIGHT_CAPTION_IN_OUT, textYupperLine, CAPTION_IN); - _textRenderer.draw(-labelWidthOut - SPACING_RIGHT_CAPTION_IN_OUT, textYlowerLine, CAPTION_OUT); + _textRenderer->draw(barWidth + SPACING_LEFT_CAPTION_UNIT, textYcenteredLine, CAPTION_UNIT); + _textRenderer->draw(-labelWidthIn - SPACING_RIGHT_CAPTION_IN_OUT, textYupperLine, CAPTION_IN); + _textRenderer->draw(-labelWidthOut - SPACING_RIGHT_CAPTION_IN_OUT, textYlowerLine, CAPTION_OUT); // Render vertical lines for the frame setColorRGBA(COLOR_FRAME); @@ -229,11 +229,11 @@ void BandwidthMeter::render(int screenWidth, int screenHeight) { char fmtBuf[8]; setColorRGBA(COLOR_TEXT); sprintf(fmtBuf, "%0.1f", totalIn); - _textRenderer.draw(glm::max(xIn - fontMetrics.width(fmtBuf) - PADDING_HORIZ_VALUE, + _textRenderer->draw(glm::max(xIn - fontMetrics.width(fmtBuf) - PADDING_HORIZ_VALUE, PADDING_HORIZ_VALUE), textYupperLine, fmtBuf); sprintf(fmtBuf, "%0.1f", totalOut); - _textRenderer.draw(glm::max(xOut - fontMetrics.width(fmtBuf) - PADDING_HORIZ_VALUE, + _textRenderer->draw(glm::max(xOut - fontMetrics.width(fmtBuf) - PADDING_HORIZ_VALUE, PADDING_HORIZ_VALUE), textYlowerLine, fmtBuf); diff --git a/interface/src/ui/BandwidthMeter.h b/interface/src/ui/BandwidthMeter.h index c6a28a21c3..09353512d1 100644 --- a/interface/src/ui/BandwidthMeter.h +++ b/interface/src/ui/BandwidthMeter.h @@ -78,7 +78,7 @@ private: static ChannelInfo _CHANNELS[]; - TextRenderer _textRenderer; + TextRenderer* _textRenderer; ChannelInfo* _channels; Stream _streams[N_STREAMS]; int _scaleMaxIndex; diff --git a/interface/src/ui/PreferencesDialog.cpp b/interface/src/ui/PreferencesDialog.cpp index 47cb9bad88..61cc9718b3 100644 --- a/interface/src/ui/PreferencesDialog.cpp +++ b/interface/src/ui/PreferencesDialog.cpp @@ -121,6 +121,8 @@ void PreferencesDialog::loadPreferences() { ui.faceshiftEyeDeflectionSider->setValue(menuInstance->getFaceshiftEyeDeflection() * ui.faceshiftEyeDeflectionSider->maximum()); + ui.faceshiftHostnameEdit->setText(menuInstance->getFaceshiftHostname()); + const InboundAudioStream::Settings& streamSettings = menuInstance->getReceivedAudioStreamSettings(); ui.dynamicJitterBuffersCheckBox->setChecked(streamSettings._dynamicJitterBuffers); @@ -165,19 +167,29 @@ void PreferencesDialog::savePreferences() { } QUrl faceModelURL(ui.faceURLEdit->text()); - if (faceModelURL.toString() != _faceURLString) { - // change the faceModelURL in the profile, it will also update this user's BlendFace - myAvatar->setFaceModelURL(faceModelURL); - UserActivityLogger::getInstance().changedModel("head", faceModelURL.toString()); - shouldDispatchIdentityPacket = true; + QString faceModelURLString = faceModelURL.toString(); + if (faceModelURLString != _faceURLString) { + if (faceModelURLString.isEmpty() || faceModelURLString.toLower().endsWith(".fst")) { + // change the faceModelURL in the profile, it will also update this user's BlendFace + myAvatar->setFaceModelURL(faceModelURL); + UserActivityLogger::getInstance().changedModel("head", faceModelURLString); + shouldDispatchIdentityPacket = true; + } else { + qDebug() << "ERROR: Head model not FST or blank - " << faceModelURLString; + } } QUrl skeletonModelURL(ui.skeletonURLEdit->text()); - if (skeletonModelURL.toString() != _skeletonURLString) { - // change the skeletonModelURL in the profile, it will also update this user's Body - myAvatar->setSkeletonModelURL(skeletonModelURL); - UserActivityLogger::getInstance().changedModel("skeleton", skeletonModelURL.toString()); - shouldDispatchIdentityPacket = true; + QString skeletonModelURLString = skeletonModelURL.toString(); + if (skeletonModelURLString != _skeletonURLString) { + if (skeletonModelURLString.isEmpty() || skeletonModelURLString.toLower().endsWith(".fst")) { + // change the skeletonModelURL in the profile, it will also update this user's Body + myAvatar->setSkeletonModelURL(skeletonModelURL); + UserActivityLogger::getInstance().changedModel("skeleton", skeletonModelURLString); + shouldDispatchIdentityPacket = true; + } else { + qDebug() << "ERROR: Skeleton model not FST or blank - " << skeletonModelURLString; + } } if (shouldDispatchIdentityPacket) { @@ -211,6 +223,9 @@ void PreferencesDialog::savePreferences() { Menu::getInstance()->setFaceshiftEyeDeflection(ui.faceshiftEyeDeflectionSider->value() / (float)ui.faceshiftEyeDeflectionSider->maximum()); + + Menu::getInstance()->setFaceshiftHostname(ui.faceshiftHostnameEdit->text()); + Menu::getInstance()->setMaxVoxelPacketsPerSecond(ui.maxVoxelsPPSSpin->value()); Menu::getInstance()->setOculusUIAngularSize(ui.oculusUIAngularSizeSpin->value()); diff --git a/interface/src/ui/TextRenderer.cpp b/interface/src/ui/TextRenderer.cpp index 4ced8c1f2e..c4f6b328ef 100644 --- a/interface/src/ui/TextRenderer.cpp +++ b/interface/src/ui/TextRenderer.cpp @@ -24,22 +24,23 @@ // the width/height of the cached glyph textures const int IMAGE_SIZE = 256; -Glyph::Glyph(int textureID, const QPoint& location, const QRect& bounds, int width) : - _textureID(textureID), _location(location), _bounds(bounds), _width(width) { +static uint qHash(const TextRenderer::Properties& key, uint seed = 0) { + // can be switched to qHash(key.font, seed) when we require Qt 5.3+ + return qHash(key.font.family(), qHash(key.font.pointSize(), seed)); } -TextRenderer::TextRenderer(const char* family, int pointSize, int weight, bool italic, - EffectType effectType, int effectThickness, QColor color) : - _font(family, pointSize, weight, italic), - _metrics(_font), - _effectType(effectType), - _effectThickness(effectThickness), - _x(IMAGE_SIZE), - _y(IMAGE_SIZE), - _rowHeight(0), - _color(color) { - - _font.setKerning(false); +static bool operator==(const TextRenderer::Properties& p1, const TextRenderer::Properties& p2) { + return p1.font == p2.font && p1.effect == p2.effect && p1.effectThickness == p2.effectThickness && p1.color == p2.color; +} + +TextRenderer* TextRenderer::getInstance(const char* family, int pointSize, int weight, bool italic, + EffectType effect, int effectThickness, const QColor& color) { + Properties properties = { QFont(family, pointSize, weight, italic), effect, effectThickness, color }; + TextRenderer*& instance = _instances[properties]; + if (!instance) { + instance = new TextRenderer(properties); + } + return instance; } TextRenderer::~TextRenderer() { @@ -122,6 +123,19 @@ int TextRenderer::computeWidth(const char* str) return width; } +TextRenderer::TextRenderer(const Properties& properties) : + _font(properties.font), + _metrics(_font), + _effectType(properties.effect), + _effectThickness(properties.effectThickness), + _x(IMAGE_SIZE), + _y(IMAGE_SIZE), + _rowHeight(0), + _color(properties.color) { + + _font.setKerning(false); +} + const Glyph& TextRenderer::getGlyph(char c) { Glyph& glyph = _glyphs[c]; if (glyph.isValid()) { @@ -213,3 +227,10 @@ const Glyph& TextRenderer::getGlyph(char c) { glBindTexture(GL_TEXTURE_2D, 0); return glyph; } + +QHash TextRenderer::_instances; + +Glyph::Glyph(int textureID, const QPoint& location, const QRect& bounds, int width) : + _textureID(textureID), _location(location), _bounds(bounds), _width(width) { +} + diff --git a/interface/src/ui/TextRenderer.h b/interface/src/ui/TextRenderer.h index 2daba79c8f..d3340462d5 100644 --- a/interface/src/ui/TextRenderer.h +++ b/interface/src/ui/TextRenderer.h @@ -33,7 +33,6 @@ const char SOLID_BLOCK_CHAR = 127; // the Inconsolata font family #define INCONSOLATA_FONT_FAMILY "Inconsolata" - class Glyph; class TextRenderer { @@ -41,9 +40,17 @@ public: enum EffectType { NO_EFFECT, SHADOW_EFFECT, OUTLINE_EFFECT }; - TextRenderer(const char* family, int pointSize = -1, int weight = -1, bool italic = false, - EffectType effect = NO_EFFECT, int effectThickness = 1, - QColor color = QColor(255, 255, 255)); + class Properties { + public: + QFont font; + EffectType effect; + int effectThickness; + QColor color; + }; + + static TextRenderer* getInstance(const char* family, int pointSize = -1, int weight = -1, bool italic = false, + EffectType effect = NO_EFFECT, int effectThickness = 1, const QColor& color = QColor(255, 255, 255)); + ~TextRenderer(); const QFontMetrics& metrics() const { return _metrics; } @@ -59,7 +66,9 @@ public: private: - const Glyph& getGlyph (char c); + TextRenderer(const Properties& properties); + + const Glyph& getGlyph(char c); // the font to render QFont _font; @@ -90,6 +99,8 @@ private: // text color QColor _color; + + static QHash _instances; }; class Glyph { diff --git a/interface/src/ui/overlays/TextOverlay.cpp b/interface/src/ui/overlays/TextOverlay.cpp index 691179ec54..bc7cbb2cfa 100644 --- a/interface/src/ui/overlays/TextOverlay.cpp +++ b/interface/src/ui/overlays/TextOverlay.cpp @@ -45,22 +45,21 @@ void TextOverlay::render() { //TextRenderer(const char* family, int pointSize = -1, int weight = -1, bool italic = false, // EffectType effect = NO_EFFECT, int effectThickness = 1); - TextRenderer textRenderer(SANS_FONT_FAMILY, _fontSize, 50, false, TextRenderer::NO_EFFECT, 1, - QColor(_color.red, _color.green, _color.blue)); + TextRenderer* textRenderer = TextRenderer::getInstance(SANS_FONT_FAMILY, _fontSize, 50); const int leftAdjust = -1; // required to make text render relative to left edge of bounds const int topAdjust = -2; // required to make text render relative to top edge of bounds int x = _bounds.left() + _leftMargin + leftAdjust; int y = _bounds.top() + _topMargin + topAdjust; - glColor3f(1.0f, 1.0f, 1.0f); + glColor3f(_color.red / MAX_COLOR, _color.green / MAX_COLOR, _color.blue / MAX_COLOR); QStringList lines = _text.split("\n"); int lineOffset = 0; foreach(QString thisLine, lines) { if (lineOffset == 0) { - lineOffset = textRenderer.calculateHeight(qPrintable(thisLine)); + lineOffset = textRenderer->calculateHeight(qPrintable(thisLine)); } - lineOffset += textRenderer.draw(x, y + lineOffset, qPrintable(thisLine)); + lineOffset += textRenderer->draw(x, y + lineOffset, qPrintable(thisLine)); const int lineGap = 2; lineOffset += lineGap; diff --git a/interface/ui/preferencesDialog.ui b/interface/ui/preferencesDialog.ui index 9b6e381602..0108437c1f 100644 --- a/interface/ui/preferencesDialog.ui +++ b/interface/ui/preferencesDialog.ui @@ -1726,6 +1726,70 @@ + + + + 0 + + + 7 + + + 0 + + + 7 + + + + + + Arial + + + + Faceshift hostname + + + 0 + + + faceshiftHostnameEdit + + + + + + + + Arial + + + + Qt::Horizontal + + + + + + + + Arial + + + + Qt::LeftToRight + + + + + + localhost + + + + + diff --git a/libraries/audio/src/AudioBuffer.h b/libraries/audio/src/AudioBuffer.h index 2ef39430c1..863bbdf22a 100644 --- a/libraries/audio/src/AudioBuffer.h +++ b/libraries/audio/src/AudioBuffer.h @@ -110,12 +110,44 @@ public: if ( !_frameBuffer || !frames) { return; } - assert(channelCount <= _channelCountMax); - assert(frameCount <= _frameCountMax); - - _frameCount = frameCount; // we allow copying fewer frames than we've allocated - _channelCount = channelCount; // we allow copying fewer channels that we've allocated - + + if (channelCount <=_channelCountMax && frameCount <=_frameCountMax) { + // We always allow copying fewer frames than we have allocated + _frameCount = frameCount; + _channelCount = channelCount; + } + else { + // + // However we do not attempt to copy more frames than we've allocated ;-) This is a framing error caused by either + // a/ the platform audio driver not correctly queuing and regularly smoothing device IO capture frames -or- + // b/ our IO processing thread (currently running on a Qt GUI thread) has been delayed/scheduled too late. + // + // The fix is not to make the problem worse by allocating additional frames on this thread, rather, it is to handle + // dynamic re-sizing off the IO processing thread. While a/ is not in our control, we will address the off thread + // re-sizing,, as well as b/, in later releases. + // + // For now, we log this condition, and do our best to recover by copying as many frames as we have allocated. + // Unfortunately, this will result (temporarily), in an audible discontinuity. + // + // If you repeatedly receive this error, contact craig@highfidelity.io and send me what audio device you are using, + // what audio-stack you are using (pulse/alsa, core audio, ...), what OS, and what the reported frame/channel + // counts are. In addition, any information about what you were doing at the time of the discontinuity, would be + // useful (e.g., accessing any client features/menus) + // + qDebug() << "Audio framing error: _channelCount=" + << _channelCount + << "channelCountMax=" + << _channelCountMax + << "_frameCount=" + << _frameCount + << "frameCountMax=" + << _frameCountMax; + + + _channelCount = std::min(_channelCount,_channelCountMax); + _frameCount = std::min(_frameCount,_frameCountMax); + } + if (copyOut) { S* dst = frames;