Showing the changes to interface/src (61 of 214 files). Show all
Unified · Split
| @@ -66,6 +66,9 @@ · 65 unmodified lines | ||
| 66 | 66 | #include <EntityScriptingInterface.h> |
| 67 | 67 | #include <ErrorDialog.h> |
| 68 | 68 | #include <GlowEffect.h> |
| 69 | +#include <gpu/Batch.h> | |
| 70 | +#include <gpu/Context.h> | |
| 71 | +#include <gpu/GLBackend.h> | |
| 69 | 72 | #include <HFActionEvent.h> |
| 70 | 73 | #include <HFBackEvent.h> |
| 71 | 74 | #include <InfoView.h> |
| @@ -83,12 +86,14 @@ · 11 unmodified lines | ||
| 83 | 86 | #include <PerfStat.h> |
| 84 | 87 | #include <PhysicsEngine.h> |
| 85 | 88 | #include <ProgramObject.h> |
| 89 | +#include <RenderDeferredTask.h> | |
| 86 | 90 | #include <ResourceCache.h> |
| 87 | 91 | #include <SceneScriptingInterface.h> |
| 88 | 92 | #include <ScriptCache.h> |
| 89 | 93 | #include <SettingHandle.h> |
| 90 | 94 | #include <SoundCache.h> |
| 91 | 95 | #include <TextRenderer.h> |
| 96 | +#include <Tooltip.h> | |
| 92 | 97 | #include <UserActivityLogger.h> |
| 93 | 98 | #include <UUID.h> |
| 94 | 99 | #include <VrMenu.h> |
| @@ -106,11 +111,9 @@ · 11 unmodified lines | ||
| 106 | 111 | |
| 107 | 112 | #include "avatar/AvatarManager.h" |
| 108 | 113 | |
| 109 | −#include "audio/AudioToolBox.h" | |
| 110 | 114 | #include "audio/AudioIOStatsRenderer.h" |
| 111 | 115 | #include "audio/AudioScope.h" |
| 112 | 116 | |
| 113 | −#include "devices/CameraToolBox.h" | |
| 114 | 117 | #include "devices/DdeFaceTracker.h" |
| 115 | 118 | #include "devices/Faceshift.h" |
| 116 | 119 | #include "devices/Leapmotion.h" |
| @@ -120,12 +123,6 @@ · 3 unmodified lines | ||
| 120 | 123 | #include "devices/OculusManager.h" |
| 121 | 124 | #include "devices/TV3DManager.h" |
| 122 | 125 | |
| 123 | −#include "gpu/Batch.h" | |
| 124 | −#include "gpu/Context.h" | |
| 125 | −#include "gpu/GLBackend.h" | |
| 126 | − | |
| 127 | −#include "RenderDeferredTask.h" | |
| 128 | − | |
| 129 | 126 | #include "scripting/AccountScriptingInterface.h" |
| 130 | 127 | #include "scripting/AudioDeviceScriptingInterface.h" |
| 131 | 128 | #include "scripting/ClipboardScriptingInterface.h" |
| @@ -141,6 +138,7 @@ · 9 unmodified lines | ||
| 141 | 138 | #include "SpeechRecognizer.h" |
| 142 | 139 | #endif |
| 143 | 140 | |
| 141 | +#include "ui/AvatarInputs.h" | |
| 144 | 142 | #include "ui/DataWebDialog.h" |
| 145 | 143 | #include "ui/DialogsManager.h" |
| 146 | 144 | #include "ui/LoginDialog.h" |
| @@ -281,8 +279,6 @@ bool setupEssentials(int& argc, char** argv) { · 134 unmodified lines | ||
| 281 | 279 | auto animationCache = DependencyManager::set<AnimationCache>(); |
| 282 | 280 | auto ddeFaceTracker = DependencyManager::set<DdeFaceTracker>(); |
| 283 | 281 | auto modelBlender = DependencyManager::set<ModelBlender>(); |
| 284 | − auto audioToolBox = DependencyManager::set<AudioToolBox>(); | |
| 285 | − auto cameraToolBox = DependencyManager::set<CameraToolBox>(); | |
| 286 | 282 | auto avatarManager = DependencyManager::set<AvatarManager>(); |
| 287 | 283 | auto lodManager = DependencyManager::set<LODManager>(); |
| 288 | 284 | auto jsConsole = DependencyManager::set<StandAloneJSConsole>(); |
| @@ -335,8 +331,6 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) : · 46 unmodified lines | ||
| 335 | 331 | _cursorVisible(true), |
| 336 | 332 | _lastMouseMove(usecTimestampNow()), |
| 337 | 333 | _lastMouseMoveWasSimulated(false), |
| 338 | − _touchAvgX(0.0f), | |
| 339 | − _touchAvgY(0.0f), | |
| 340 | 334 | _isTouchPressed(false), |
| 341 | 335 | _mousePressed(false), |
| 342 | 336 | _enableProcessOctreeThread(true), |
| @@ -814,9 +808,9 @@ void Application::initializeGL() { · 471 unmodified lines | ||
| 814 | 808 | _idleLoopStdev.reset(); |
| 815 | 809 | |
| 816 | 810 | if (_justStarted) { |
| 817 | − float startupTime = (float)_applicationStartupTime.elapsed() / 1000.0; | |
| 811 | + float startupTime = (float)_applicationStartupTime.elapsed() / 1000.0f; | |
| 818 | 812 | _justStarted = false; |
| 819 | − qCDebug(interfaceapp, "Startup time: %4.2f seconds.", startupTime); | |
| 813 | + qCDebug(interfaceapp, "Startup time: %4.2f seconds.", (double)startupTime); | |
| 820 | 814 | } |
| 821 | 815 | |
| 822 | 816 | // update before the first render |
| @@ -831,6 +825,7 @@ void Application::initializeUi() { · 8 unmodified lines | ||
| 831 | 825 | LoginDialog::registerType(); |
| 832 | 826 | MessageDialog::registerType(); |
| 833 | 827 | VrMenu::registerType(); |
| 828 | + Tooltip::registerType(); | |
| 834 | 829 | UpdateDialog::registerType(); |
| 835 | 830 | |
| 836 | 831 | auto offscreenUi = DependencyManager::get<OffscreenUi>(); |
| @@ -844,7 +839,7 @@ void Application::initializeUi() { · 7 unmodified lines | ||
| 844 | 839 | VrMenu::executeQueuedLambdas(); |
| 845 | 840 | offscreenUi->setMouseTranslator([this](const QPointF& p){ |
| 846 | 841 | if (OculusManager::isConnected()) { |
| 847 | − glm::vec2 pos = _applicationOverlay.screenToOverlay(toGlm(p)); | |
| 842 | + glm::vec2 pos = _compositor.screenToOverlay(toGlm(p)); | |
| 848 | 843 | return QPointF(pos.x, pos.y); |
| 849 | 844 | } |
| 850 | 845 | return QPointF(p); |
| @@ -877,6 +872,7 @@ void Application::paintGL() { · 26 unmodified lines | ||
| 877 | 872 | OculusManager::beginFrameTiming(); |
| 878 | 873 | } |
| 879 | 874 | |
| 875 | + | |
| 880 | 876 | PerformanceWarning::setSuppressShortTimings(Menu::getInstance()->isOptionChecked(MenuOption::SuppressShortTimings)); |
| 881 | 877 | bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings); |
| 882 | 878 | PerformanceWarning warn(showWarnings, "Application::paintGL()"); |
| @@ -884,6 +880,12 @@ void Application::paintGL() { · 1 unmodified line | ||
| 884 | 880 | |
| 885 | 881 | { |
| 886 | 882 | PerformanceTimer perfTimer("renderOverlay"); |
| 883 | + /* | |
| 884 | + gpu::Context context(new gpu::GLBackend()); | |
| 885 | + RenderArgs renderArgs(&context, nullptr, getViewFrustum(), lodManager->getOctreeSizeScale(), | |
| 886 | + lodManager->getBoundaryLevelAdjust(), RenderArgs::DEFAULT_RENDER_MODE, | |
| 887 | + RenderArgs::MONO, RenderArgs::RENDER_DEBUG_NONE); | |
| 888 | + */ | |
| 887 | 889 | _applicationOverlay.renderOverlay(&renderArgs); |
| 888 | 890 | } |
| 889 | 891 | |
| @@ -912,13 +914,18 @@ void Application::paintGL() { · 22 unmodified lines | ||
| 912 | 914 | } |
| 913 | 915 | |
| 914 | 916 | } else if (_myCamera.getMode() == CAMERA_MODE_THIRD_PERSON) { |
| 915 | − _myCamera.setPosition(_myAvatar->getDefaultEyePosition() + | |
| 916 | − _myAvatar->getOrientation() * glm::vec3(0.0f, 0.0f, 1.0f) * _myAvatar->getBoomLength() * _myAvatar->getScale()); | |
| 917 | 917 | if (OculusManager::isConnected()) { |
| 918 | 918 | _myCamera.setRotation(_myAvatar->getWorldAlignedOrientation()); |
| 919 | 919 | } else { |
| 920 | 920 | _myCamera.setRotation(_myAvatar->getHead()->getOrientation()); |
| 921 | 921 | } |
| 922 | + if (Menu::getInstance()->isOptionChecked(MenuOption::CenterPlayerInView)) { | |
| 923 | + _myCamera.setPosition(_myAvatar->getDefaultEyePosition() + | |
| 924 | + _myCamera.getRotation() * glm::vec3(0.0f, 0.0f, 1.0f) * _myAvatar->getBoomLength() * _myAvatar->getScale()); | |
| 925 | + } else { | |
| 926 | + _myCamera.setPosition(_myAvatar->getDefaultEyePosition() + | |
| 927 | + _myAvatar->getOrientation() * glm::vec3(0.0f, 0.0f, 1.0f) * _myAvatar->getBoomLength() * _myAvatar->getScale()); | |
| 928 | + } | |
| 922 | 929 | |
| 923 | 930 | } else if (_myCamera.getMode() == CAMERA_MODE_MIRROR) { |
| 924 | 931 | _myCamera.setRotation(_myAvatar->getWorldAlignedOrientation() * glm::quat(glm::vec3(0.0f, PI + _rotateMirror, 0.0f))); |
| @@ -967,9 +974,7 @@ void Application::paintGL() { · 42 unmodified lines | ||
| 967 | 974 | glPopMatrix(); |
| 968 | 975 | |
| 969 | 976 | renderArgs._renderMode = RenderArgs::MIRROR_RENDER_MODE; |
| 970 | − if (Menu::getInstance()->isOptionChecked(MenuOption::FullscreenMirror)) { | |
| 971 | − _rearMirrorTools->render(&renderArgs, true, _glWidget->mapFromGlobal(QCursor::pos())); | |
| 972 | − } else if (Menu::getInstance()->isOptionChecked(MenuOption::Mirror)) { | |
| 977 | + if (Menu::getInstance()->isOptionChecked(MenuOption::Mirror)) { | |
| 973 | 978 | renderRearViewMirror(&renderArgs, _mirrorViewRect); |
| 974 | 979 | } |
| 975 | 980 | |
| @@ -977,6 +982,7 @@ void Application::paintGL() { · 1 unmodified line | ||
| 977 | 982 | |
| 978 | 983 | auto finalFbo = DependencyManager::get<GlowEffect>()->render(&renderArgs); |
| 979 | 984 | |
| 985 | + | |
| 980 | 986 | glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); |
| 981 | 987 | glBindFramebuffer(GL_READ_FRAMEBUFFER, gpu::GLBackend::getFramebufferID(finalFbo)); |
| 982 | 988 | glBlitFramebuffer(0, 0, _renderResolution.x, _renderResolution.y, |
| @@ -984,9 +990,10 @@ void Application::paintGL() { · 1 unmodified line | ||
| 984 | 990 | GL_COLOR_BUFFER_BIT, GL_NEAREST); |
| 985 | 991 | glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); |
| 986 | 992 | |
| 987 | − _applicationOverlay.displayOverlayTexture(); | |
| 993 | + _compositor.displayOverlayTexture(&renderArgs); | |
| 988 | 994 | } |
| 989 | 995 | |
| 996 | + | |
| 990 | 997 | if (!OculusManager::isConnected() || OculusManager::allowSwap()) { |
| 991 | 998 | _glWidget->swapBuffers(); |
| 992 | 999 | } |
| @@ -1044,27 +1051,24 @@ void Application::resizeGL() { · 51 unmodified lines | ||
| 1044 | 1051 | } else { |
| 1045 | 1052 | renderSize = _glWidget->getDeviceSize() * getRenderResolutionScale(); |
| 1046 | 1053 | } |
| 1047 | − if (_renderResolution == toGlm(renderSize)) { | |
| 1048 | − return; | |
| 1049 | − } | |
| 1050 | 1054 | |
| 1051 | − _renderResolution = toGlm(renderSize); | |
| 1052 | − DependencyManager::get<TextureCache>()->setFrameBufferSize(renderSize); | |
| 1053 | − resetCamerasOnResizeGL(_myCamera, _renderResolution); | |
| 1055 | + if (_renderResolution != toGlm(renderSize)) { | |
| 1056 | + _renderResolution = toGlm(renderSize); | |
| 1057 | + DependencyManager::get<TextureCache>()->setFrameBufferSize(renderSize); | |
| 1058 | + resetCamerasOnResizeGL(_myCamera, _renderResolution); | |
| 1054 | 1059 | |
| 1055 | − glViewport(0, 0, _renderResolution.x, _renderResolution.y); // shouldn't this account for the menu??? | |
| 1060 | + glViewport(0, 0, _renderResolution.x, _renderResolution.y); // shouldn't this account for the menu??? | |
| 1056 | 1061 | |
| 1057 | − updateProjectionMatrix(); | |
| 1058 | − glLoadIdentity(); | |
| 1062 | + updateProjectionMatrix(); | |
| 1063 | + glLoadIdentity(); | |
| 1064 | + } | |
| 1059 | 1065 | |
| 1060 | 1066 | auto offscreenUi = DependencyManager::get<OffscreenUi>(); |
| 1061 | − offscreenUi->resize(_glWidget->size()); | |
| 1067 | + | |
| 1068 | + auto canvasSize = _glWidget->size(); | |
| 1069 | + offscreenUi->resize(canvasSize); | |
| 1062 | 1070 | _glWidget->makeCurrent(); |
| 1063 | 1071 | |
| 1064 | − // update Stats width | |
| 1065 | − // let's set horizontal offset to give stats some margin to mirror | |
| 1066 | − int horizontalOffset = MIRROR_VIEW_WIDTH + MIRROR_VIEW_LEFT_PADDING * 2; | |
| 1067 | − Stats::getInstance()->resetWidth(_renderResolution.x, horizontalOffset); | |
| 1068 | 1072 | } |
| 1069 | 1073 | |
| 1070 | 1074 | void Application::updateProjectionMatrix() { |
| @@ -1568,27 +1572,9 @@ void Application::mousePressEvent(QMouseEvent* event, unsigned int deviceID) { · 497 unmodified lines | ||
| 1568 | 1572 | _keyboardMouseDevice.mousePressEvent(event); |
| 1569 | 1573 | |
| 1570 | 1574 | if (event->button() == Qt::LeftButton) { |
| 1571 | − _mouseDragStartedX = getTrueMouseX(); | |
| 1572 | − _mouseDragStartedY = getTrueMouseY(); | |
| 1575 | + _mouseDragStarted = getTrueMouse(); | |
| 1573 | 1576 | _mousePressed = true; |
| 1574 | 1577 | |
| 1575 | − if (mouseOnScreen()) { | |
| 1576 | − if (DependencyManager::get<AudioToolBox>()->mousePressEvent(getMouseX(), getMouseY())) { | |
| 1577 | − // stop propagation | |
| 1578 | − return; | |
| 1579 | − } | |
| 1580 | − | |
| 1581 | − if (DependencyManager::get<CameraToolBox>()->mousePressEvent(getMouseX(), getMouseY())) { | |
| 1582 | − // stop propagation | |
| 1583 | − return; | |
| 1584 | − } | |
| 1585 | − | |
| 1586 | − if (_rearMirrorTools->mousePressEvent(getMouseX(), getMouseY())) { | |
| 1587 | − // stop propagation | |
| 1588 | − return; | |
| 1589 | − } | |
| 1590 | − } | |
| 1591 | − | |
| 1592 | 1578 | // nobody handled this - make it an action event on the _window object |
| 1593 | 1579 | HFActionEvent actionEvent(HFActionEvent::startType(), |
| 1594 | 1580 | computePickRay(event->x(), event->y())); |
| @@ -1606,16 +1592,7 @@ void Application::mouseDoublePressEvent(QMouseEvent* event, unsigned int deviceI · 11 unmodified lines | ||
| 1606 | 1592 | return; |
| 1607 | 1593 | } |
| 1608 | 1594 | |
| 1609 | − if (activeWindow() == _window) { | |
| 1610 | − if (event->button() == Qt::LeftButton) { | |
| 1611 | − if (mouseOnScreen()) { | |
| 1612 | − if (DependencyManager::get<CameraToolBox>()->mouseDoublePressEvent(getMouseX(), getMouseY())) { | |
| 1613 | − // stop propagation | |
| 1614 | − return; | |
| 1615 | − } | |
| 1616 | − } | |
| 1617 | − } | |
| 1618 | − } | |
| 1595 | + _controllerScriptingInterface.emitMouseDoublePressEvent(event); | |
| 1619 | 1596 | } |
| 1620 | 1597 | |
| 1621 | 1598 | void Application::mouseReleaseEvent(QMouseEvent* event, unsigned int deviceID) { |
| @@ -1637,13 +1614,6 @@ void Application::mouseReleaseEvent(QMouseEvent* event, unsigned int deviceID) { · 15 unmodified lines | ||
| 1637 | 1614 | if (event->button() == Qt::LeftButton) { |
| 1638 | 1615 | _mousePressed = false; |
| 1639 | 1616 | |
| 1640 | − if (Menu::getInstance()->isOptionChecked(MenuOption::Stats) && mouseOnScreen()) { | |
| 1641 | − // let's set horizontal offset to give stats some margin to mirror | |
| 1642 | − int horizontalOffset = MIRROR_VIEW_WIDTH; | |
| 1643 | − Stats::getInstance()->checkClick(getMouseX(), getMouseY(), | |
| 1644 | − getMouseDragStartedX(), getMouseDragStartedY(), horizontalOffset); | |
| 1645 | − } | |
| 1646 | − | |
| 1647 | 1617 | // fire an action end event |
| 1648 | 1618 | HFActionEvent actionEvent(HFActionEvent::endType(), |
| 1649 | 1619 | computePickRay(event->x(), event->y())); |
| @@ -1671,22 +1641,18 @@ void Application::touchUpdateEvent(QTouchEvent* event) { · 21 unmodified lines | ||
| 1671 | 1641 | bool validTouch = false; |
| 1672 | 1642 | if (activeWindow() == _window) { |
| 1673 | 1643 | const QList<QTouchEvent::TouchPoint>& tPoints = event->touchPoints(); |
| 1674 | − _touchAvgX = 0.0f; | |
| 1675 | − _touchAvgY = 0.0f; | |
| 1644 | + _touchAvg = vec2(); | |
| 1676 | 1645 | int numTouches = tPoints.count(); |
| 1677 | 1646 | if (numTouches > 1) { |
| 1678 | 1647 | for (int i = 0; i < numTouches; ++i) { |
| 1679 | − _touchAvgX += tPoints[i].pos().x(); | |
| 1680 | − _touchAvgY += tPoints[i].pos().y(); | |
| 1648 | + _touchAvg += toGlm(tPoints[i].pos()); | |
| 1681 | 1649 | } |
| 1682 | − _touchAvgX /= (float)(numTouches); | |
| 1683 | − _touchAvgY /= (float)(numTouches); | |
| 1650 | + _touchAvg /= (float)(numTouches); | |
| 1684 | 1651 | validTouch = true; |
| 1685 | 1652 | } |
| 1686 | 1653 | } |
| 1687 | 1654 | if (!_isTouchPressed) { |
| 1688 | − _touchDragStartedAvgX = _touchAvgX; | |
| 1689 | − _touchDragStartedAvgY = _touchAvgY; | |
| 1655 | + _touchDragStartedAvg = _touchAvg; | |
| 1690 | 1656 | } |
| 1691 | 1657 | _isTouchPressed = validTouch; |
| 1692 | 1658 | } |
| @@ -1722,8 +1688,7 @@ void Application::touchEndEvent(QTouchEvent* event) { · 29 unmodified lines | ||
| 1722 | 1688 | _keyboardMouseDevice.touchEndEvent(event); |
| 1723 | 1689 | |
| 1724 | 1690 | // put any application specific touch behavior below here.. |
| 1725 | − _touchDragStartedAvgX = _touchAvgX; | |
| 1726 | − _touchDragStartedAvgY = _touchAvgY; | |
| 1691 | + _touchDragStartedAvg = _touchAvg; | |
| 1727 | 1692 | _isTouchPressed = false; |
| 1728 | 1693 | |
| 1729 | 1694 | } |
| @@ -1872,9 +1837,9 @@ void Application::setFullscreen(bool fullscreen) { · 142 unmodified lines | ||
| 1872 | 1837 | Menu::getInstance()->getActionForOption(MenuOption::Fullscreen)->setChecked(fullscreen); |
| 1873 | 1838 | } |
| 1874 | 1839 | |
| 1875 | −// The following code block is useful on platforms that can have a visible | |
| 1876 | −// app menu in a fullscreen window. However the OSX mechanism hides the | |
| 1877 | −// application menu for fullscreen apps, so the check is not required. | |
| 1840 | + // The following code block is useful on platforms that can have a visible | |
| 1841 | + // app menu in a fullscreen window. However the OSX mechanism hides the | |
| 1842 | + // application menu for fullscreen apps, so the check is not required. | |
| 1878 | 1843 | #ifndef Q_OS_MAC |
| 1879 | 1844 | if (Menu::getInstance()->isOptionChecked(MenuOption::EnableVRMode)) { |
| 1880 | 1845 | if (fullscreen) { |
| @@ -1939,16 +1904,15 @@ void Application::setEnableVRMode(bool enableVRMode) { · 58 unmodified lines | ||
| 1939 | 1904 | // attempt to reconnect the Oculus manager - it's possible this was a workaround |
| 1940 | 1905 | // for the sixense crash |
| 1941 | 1906 | OculusManager::disconnect(); |
| 1942 | − OculusManager::connect(); | |
| 1907 | + OculusManager::connect(_glWidget->context()->contextHandle()); | |
| 1908 | + _glWidget->setFocus(); | |
| 1909 | + _glWidget->makeCurrent(); | |
| 1910 | + glClear(GL_COLOR_BUFFER_BIT); | |
| 1943 | 1911 | } |
| 1944 | 1912 | OculusManager::recalibrate(); |
| 1945 | 1913 | } else { |
| 1946 | 1914 | OculusManager::abandonCalibration(); |
| 1947 | − | |
| 1948 | − _mirrorCamera.setHmdPosition(glm::vec3()); | |
| 1949 | − _mirrorCamera.setHmdRotation(glm::quat()); | |
| 1950 | − _myCamera.setHmdPosition(glm::vec3()); | |
| 1951 | − _myCamera.setHmdRotation(glm::quat()); | |
| 1915 | + OculusManager::disconnect(); | |
| 1952 | 1916 | } |
| 1953 | 1917 | |
| 1954 | 1918 | resizeGL(); |
| @@ -1960,44 +1924,34 @@ void Application::setLowVelocityFilter(bool lowVelocityFilter) { · 5 unmodified lines | ||
| 1960 | 1924 | |
| 1961 | 1925 | bool Application::mouseOnScreen() const { |
| 1962 | 1926 | if (OculusManager::isConnected()) { |
| 1963 | − return getMouseX() >= 0 && getMouseX() <= _glWidget->getDeviceWidth() && | |
| 1964 | − getMouseY() >= 0 && getMouseY() <= _glWidget->getDeviceHeight(); | |
| 1927 | + ivec2 mouse = getMouse(); | |
| 1928 | + if (!glm::all(glm::greaterThanEqual(mouse, ivec2()))) { | |
| 1929 | + return false; | |
| 1930 | + } | |
| 1931 | + ivec2 size = toGlm(_glWidget->getDeviceSize()); | |
| 1932 | + if (!glm::all(glm::lessThanEqual(mouse, size))) { | |
| 1933 | + return false; | |
| 1934 | + } | |
| 1965 | 1935 | } |
| 1966 | 1936 | return true; |
| 1967 | 1937 | } |
| 1968 | 1938 | |
| 1969 | −int Application::getMouseX() const { | |
| 1970 | − if (OculusManager::isConnected()) { | |
| 1971 | − glm::vec2 pos = _applicationOverlay.screenToOverlay(glm::vec2(getTrueMouseX(), getTrueMouseY())); | |
| 1972 | − return pos.x; | |
| 1973 | − } | |
| 1974 | − return getTrueMouseX(); | |
| 1975 | −} | |
| 1976 | − | |
| 1977 | −int Application::getMouseY() const { | |
| 1939 | +ivec2 Application::getMouse() const { | |
| 1978 | 1940 | if (OculusManager::isConnected()) { |
| 1979 | − glm::vec2 pos = _applicationOverlay.screenToOverlay(glm::vec2(getTrueMouseX(), getTrueMouseY())); | |
| 1980 | − return pos.y; | |
| 1941 | + return _compositor.screenToOverlay(getTrueMouse()); | |
| 1981 | 1942 | } |
| 1982 | − return getTrueMouseY(); | |
| 1943 | + return getTrueMouse(); | |
| 1983 | 1944 | } |
| 1984 | 1945 | |
| 1985 | −int Application::getMouseDragStartedX() const { | |
| 1946 | +ivec2 Application::getMouseDragStarted() const { | |
| 1986 | 1947 | if (OculusManager::isConnected()) { |
| 1987 | − glm::vec2 pos = _applicationOverlay.screenToOverlay(glm::vec2(getTrueMouseDragStartedX(), | |
| 1988 | − getTrueMouseDragStartedY())); | |
| 1989 | − return pos.x; | |
| 1948 | + return _compositor.screenToOverlay(getTrueMouseDragStarted()); | |
| 1990 | 1949 | } |
| 1991 | − return getTrueMouseDragStartedX(); | |
| 1950 | + return getTrueMouseDragStarted(); | |
| 1992 | 1951 | } |
| 1993 | 1952 | |
| 1994 | −int Application::getMouseDragStartedY() const { | |
| 1995 | − if (OculusManager::isConnected()) { | |
| 1996 | − glm::vec2 pos = _applicationOverlay.screenToOverlay(glm::vec2(getTrueMouseDragStartedX(), | |
| 1997 | − getTrueMouseDragStartedY())); | |
| 1998 | − return pos.y; | |
| 1999 | − } | |
| 2000 | − return getTrueMouseDragStartedY(); | |
| 1953 | +ivec2 Application::getTrueMouseDragStarted() const { | |
| 1954 | + return _mouseDragStarted; | |
| 2001 | 1955 | } |
| 2002 | 1956 | |
| 2003 | 1957 | FaceTracker* Application::getActiveFaceTracker() { |
| @@ -2179,13 +2133,6 @@ void Application::init() { · 175 unmodified lines | ||
| 2179 | 2133 | |
| 2180 | 2134 | _mirrorCamera.setMode(CAMERA_MODE_MIRROR); |
| 2181 | 2135 | |
| 2182 | − OculusManager::connect(); | |
| 2183 | − if (OculusManager::isConnected()) { | |
| 2184 | − QMetaObject::invokeMethod(Menu::getInstance()->getActionForOption(MenuOption::Fullscreen), | |
| 2185 | − "trigger", | |
| 2186 | − Qt::QueuedConnection); | |
| 2187 | − } | |
| 2188 | − | |
| 2189 | 2136 | TV3DManager::connect(); |
| 2190 | 2137 | if (TV3DManager::isConnected()) { |
| 2191 | 2138 | QMetaObject::invokeMethod(Menu::getInstance()->getActionForOption(MenuOption::Fullscreen), |
| @@ -2249,13 +2196,6 @@ void Application::init() { · 57 unmodified lines | ||
| 2249 | 2196 | _entityClipboardRenderer.setViewFrustum(getViewFrustum()); |
| 2250 | 2197 | _entityClipboardRenderer.setTree(&_entityClipboard); |
| 2251 | 2198 | |
| 2252 | − _rearMirrorTools = new RearMirrorTools(_mirrorViewRect); | |
| 2253 | − | |
| 2254 | − connect(_rearMirrorTools, SIGNAL(closeView()), SLOT(closeMirrorView())); | |
| 2255 | − connect(_rearMirrorTools, SIGNAL(restoreView()), SLOT(restoreMirrorView())); | |
| 2256 | − connect(_rearMirrorTools, SIGNAL(shrinkView()), SLOT(shrinkMirrorView())); | |
| 2257 | − connect(_rearMirrorTools, SIGNAL(resetView()), SLOT(resetSensors())); | |
| 2258 | − | |
| 2259 | 2199 | // initialize the GlowEffect with our widget |
| 2260 | 2200 | bool glow = Menu::getInstance()->isOptionChecked(MenuOption::EnableGlowEffect); |
| 2261 | 2201 | DependencyManager::get<GlowEffect>()->init(glow); |
| @@ -2434,6 +2374,12 @@ void Application::cameraMenuChanged() { · 172 unmodified lines | ||
| 2434 | 2374 | } |
| 2435 | 2375 | } |
| 2436 | 2376 | |
| 2377 | +void Application::rotationModeChanged() { | |
| 2378 | + if (!Menu::getInstance()->isOptionChecked(MenuOption::CenterPlayerInView)) { | |
| 2379 | + _myAvatar->setHeadPitch(0); | |
| 2380 | + } | |
| 2381 | +} | |
| 2382 | + | |
| 2437 | 2383 | void Application::updateCamera(float deltaTime) { |
| 2438 | 2384 | PerformanceTimer perfTimer("updateCamera"); |
| 2439 | 2385 | bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings); |
| @@ -3155,7 +3101,7 @@ PickRay Application::computePickRay(float x, float y) const { · 715 unmodified lines | ||
| 3155 | 3101 | y /= size.y; |
| 3156 | 3102 | PickRay result; |
| 3157 | 3103 | if (isHMDMode()) { |
| 3158 | − getApplicationOverlay().computeHmdPickRay(glm::vec2(x, y), result.origin, result.direction); | |
| 3104 | + getApplicationCompositor().computeHmdPickRay(glm::vec2(x, y), result.origin, result.direction); | |
| 3159 | 3105 | } else { |
| 3160 | 3106 | if (QThread::currentThread() == activeRenderingThread) { |
| 3161 | 3107 | getDisplayViewFrustum()->computePickRay(x, y, result.origin, result.direction); |
| @@ -3184,13 +3130,11 @@ QImage Application::renderAvatarBillboard(RenderArgs* renderArgs) { · 22 unmodified lines | ||
| 3184 | 3130 | renderRearViewMirror(renderArgs, QRect(0, _glWidget->getDeviceHeight() - BILLBOARD_SIZE, |
| 3185 | 3131 | BILLBOARD_SIZE, BILLBOARD_SIZE), |
| 3186 | 3132 | true); |
| 3187 | − | |
| 3188 | 3133 | QImage image(BILLBOARD_SIZE, BILLBOARD_SIZE, QImage::Format_ARGB32); |
| 3189 | 3134 | glReadPixels(0, 0, BILLBOARD_SIZE, BILLBOARD_SIZE, GL_BGRA, GL_UNSIGNED_BYTE, image.bits()); |
| 3190 | 3135 | glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); |
| 3191 | 3136 | |
| 3192 | 3137 | glBindFramebuffer(GL_FRAMEBUFFER, 0); |
| 3193 | − | |
| 3194 | 3138 | return image; |
| 3195 | 3139 | } |
| 3196 | 3140 | |
| @@ -3386,9 +3330,8 @@ void Application::displaySide(RenderArgs* renderArgs, Camera& theCamera, bool se · 189 unmodified lines | ||
| 3386 | 3330 | |
| 3387 | 3331 | // flip x if in mirror mode (also requires reversing winding order for backface culling) |
| 3388 | 3332 | if (theCamera.getMode() == CAMERA_MODE_MIRROR) { |
| 3389 | − glScalef(-1.0f, 1.0f, 1.0f); | |
| 3390 | − glFrontFace(GL_CW); | |
| 3391 | − | |
| 3333 | + //glScalef(-1.0f, 1.0f, 1.0f); | |
| 3334 | + //glFrontFace(GL_CW); | |
| 3392 | 3335 | } else { |
| 3393 | 3336 | glFrontFace(GL_CCW); |
| 3394 | 3337 | } |
| @@ -3411,7 +3354,7 @@ void Application::displaySide(RenderArgs* renderArgs, Camera& theCamera, bool se · 16 unmodified lines | ||
| 3411 | 3354 | viewTransform.setTranslation(theCamera.getPosition()); |
| 3412 | 3355 | viewTransform.setRotation(rotation); |
| 3413 | 3356 | if (theCamera.getMode() == CAMERA_MODE_MIRROR) { |
| 3414 | − viewTransform.setScale(Transform::Vec3(-1.0f, 1.0f, 1.0f)); | |
| 3357 | +// viewTransform.setScale(Transform::Vec3(-1.0f, 1.0f, 1.0f)); | |
| 3415 | 3358 | } |
| 3416 | 3359 | if (renderArgs->_renderSide != RenderArgs::MONO) { |
| 3417 | 3360 | glm::mat4 invView = glm::inverse(_untranslatedViewMatrix); |
| @@ -3548,6 +3491,7 @@ void Application::displaySide(RenderArgs* renderArgs, Camera& theCamera, bool se · 130 unmodified lines | ||
| 3548 | 3491 | |
| 3549 | 3492 | renderContext._maxDrawnOpaqueItems = sceneInterface->getEngineMaxDrawnOpaqueItems(); |
| 3550 | 3493 | renderContext._maxDrawnTransparentItems = sceneInterface->getEngineMaxDrawnTransparentItems(); |
| 3494 | + renderContext._maxDrawnOverlay3DItems = sceneInterface->getEngineMaxDrawnOverlay3DItems(); | |
| 3551 | 3495 | |
| 3552 | 3496 | renderArgs->_shouldRender = LODManager::shouldRender; |
| 3553 | 3497 | |
| @@ -3564,7 +3508,9 @@ void Application::displaySide(RenderArgs* renderArgs, Camera& theCamera, bool se · 10 unmodified lines | ||
| 3564 | 3508 | |
| 3565 | 3509 | sceneInterface->setEngineFeedTransparentItems(engineRC->_numFeedTransparentItems); |
| 3566 | 3510 | sceneInterface->setEngineDrawnTransparentItems(engineRC->_numDrawnTransparentItems); |
| 3567 | − | |
| 3511 | + | |
| 3512 | + sceneInterface->setEngineFeedOverlay3DItems(engineRC->_numFeedOverlay3DItems); | |
| 3513 | + sceneInterface->setEngineDrawnOverlay3DItems(engineRC->_numDrawnOverlay3DItems); | |
| 3568 | 3514 | } |
| 3569 | 3515 | //Render the sixense lasers |
| 3570 | 3516 | if (Menu::getInstance()->isOptionChecked(MenuOption::SixenseLasers)) { |
| @@ -3672,8 +3618,8 @@ glm::vec2 Application::getScaledScreenPoint(glm::vec2 projectedPoint) { · 101 unmodified lines | ||
| 3672 | 3618 | // +-----------------------+ |
| 3673 | 3619 | // -1,-1 1,-1 |
| 3674 | 3620 | |
| 3675 | − glm::vec2 screenPoint((projectedPoint.x + 1.0) * horizontalScale, | |
| 3676 | − ((projectedPoint.y + 1.0) * -verticalScale) + _glWidget->getDeviceHeight()); | |
| 3621 | + glm::vec2 screenPoint((projectedPoint.x + 1.0f) * horizontalScale, | |
| 3622 | + ((projectedPoint.y + 1.0f) * -verticalScale) + _glWidget->getDeviceHeight()); | |
| 3677 | 3623 | |
| 3678 | 3624 | return screenPoint; |
| 3679 | 3625 | } |
| @@ -3691,7 +3637,7 @@ void Application::renderRearViewMirror(RenderArgs* renderArgs, const QRect& regi · 11 unmodified lines | ||
| 3691 | 3637 | _mirrorCamera.setPosition(_myAvatar->getPosition() + |
| 3692 | 3638 | _myAvatar->getOrientation() * glm::vec3(0.0f, 0.0f, -1.0f) * BILLBOARD_DISTANCE * _myAvatar->getScale()); |
| 3693 | 3639 | |
| 3694 | − } else if (RearMirrorTools::rearViewZoomLevel.get() == BODY) { | |
| 3640 | + } else if (!AvatarInputs::getInstance()->mirrorZoomed()) { | |
| 3695 | 3641 | _mirrorCamera.setPosition(_myAvatar->getChestPosition() + |
| 3696 | 3642 | _myAvatar->getOrientation() * glm::vec3(0.0f, 0.0f, -1.0f) * MIRROR_REARVIEW_BODY_DISTANCE * _myAvatar->getScale()); |
| 3697 | 3643 | |
| @@ -3726,7 +3672,7 @@ void Application::renderRearViewMirror(RenderArgs* renderArgs, const QRect& regi · 28 unmodified lines | ||
| 3726 | 3672 | } else { |
| 3727 | 3673 | // if not rendering the billboard, the region is in device independent coordinates; must convert to device |
| 3728 | 3674 | QSize size = DependencyManager::get<TextureCache>()->getFrameBufferSize(); |
| 3729 | − float ratio = QApplication::desktop()->windowHandle()->devicePixelRatio() * getRenderResolutionScale(); | |
| 3675 | + float ratio = (float)QApplication::desktop()->windowHandle()->devicePixelRatio() * getRenderResolutionScale(); | |
| 3730 | 3676 | int x = region.x() * ratio, y = region.y() * ratio, width = region.width() * ratio, height = region.height() * ratio; |
| 3731 | 3677 | glViewport(x, size.height() - y - height, width, height); |
| 3732 | 3678 | glScissor(x, size.height() - y - height, width, height); |
| @@ -3741,10 +3687,6 @@ void Application::renderRearViewMirror(RenderArgs* renderArgs, const QRect& regi · 8 unmodified lines | ||
| 3741 | 3687 | displaySide(renderArgs, _mirrorCamera, true, billboard); |
| 3742 | 3688 | glPopMatrix(); |
| 3743 | 3689 | |
| 3744 | − if (!billboard) { | |
| 3745 | − _rearMirrorTools->render(renderArgs, false, _glWidget->mapFromGlobal(QCursor::pos())); | |
| 3746 | − } | |
| 3747 | − | |
| 3748 | 3690 | // reset Viewport and projection matrix |
| 3749 | 3691 | glViewport(viewport[0], viewport[1], viewport[2], viewport[3]); |
| 3750 | 3692 | glDisable(GL_SCISSOR_TEST); |
| @@ -3884,7 +3826,7 @@ void Application::nodeKilled(SharedNodePointer node) { · 133 unmodified lines | ||
| 3884 | 3826 | _entityServerJurisdictions.unlock(); |
| 3885 | 3827 | |
| 3886 | 3828 | qCDebug(interfaceapp, "model server going away...... v[%f, %f, %f, %f]", |
| 3887 | − rootDetails.x, rootDetails.y, rootDetails.z, rootDetails.s); | |
| 3829 | + (double)rootDetails.x, (double)rootDetails.y, (double)rootDetails.z, (double)rootDetails.s); | |
| 3888 | 3830 | |
| 3889 | 3831 | // Add the jurisditionDetails object to the list of "fade outs" |
| 3890 | 3832 | if (!Menu::getInstance()->isOptionChecked(MenuOption::DontFadeOnOctreeServerChanges)) { |
| @@ -3970,7 +3912,8 @@ int Application::parseOctreeStats(const QByteArray& packet, const SharedNodePoin · 79 unmodified lines | ||
| 3970 | 3912 | jurisdiction->unlock(); |
| 3971 | 3913 | |
| 3972 | 3914 | qCDebug(interfaceapp, "stats from new %s server... [%f, %f, %f, %f]", |
| 3973 | − qPrintable(serverType), rootDetails.x, rootDetails.y, rootDetails.z, rootDetails.s); | |
| 3915 | + qPrintable(serverType), | |
| 3916 | + (double)rootDetails.x, (double)rootDetails.y, (double)rootDetails.z, (double)rootDetails.s); | |
| 3974 | 3917 | |
| 3975 | 3918 | // Add the jurisditionDetails object to the list of "fade outs" |
| 3976 | 3919 | if (!Menu::getInstance()->isOptionChecked(MenuOption::DontFadeOnOctreeServerChanges)) { |
| @@ -4750,11 +4693,9 @@ void Application::postLambdaEvent(std::function<void()> f) { · 773 unmodified lines | ||
| 4750 | 4693 | } |
| 4751 | 4694 | |
| 4752 | 4695 | void Application::initPlugins() { |
| 4753 | − OculusManager::init(); | |
| 4754 | 4696 | } |
| 4755 | 4697 | |
| 4756 | 4698 | void Application::shutdownPlugins() { |
| 4757 | − OculusManager::deinit(); | |
| 4758 | 4699 | } |
| 4759 | 4700 | |
| 4760 | 4701 | glm::vec3 Application::getHeadPosition() const { |
| @@ -4774,12 +4715,8 @@ QSize Application::getDeviceSize() const { · 13 unmodified lines | ||
| 4774 | 4715 | return _glWidget->getDeviceSize(); |
| 4775 | 4716 | } |
| 4776 | 4717 | |
| 4777 | −int Application::getTrueMouseX() const { | |
| 4778 | − return _glWidget->mapFromGlobal(QCursor::pos()).x(); | |
| 4779 | −} | |
| 4780 | − | |
| 4781 | −int Application::getTrueMouseY() const { | |
| 4782 | − return _glWidget->mapFromGlobal(QCursor::pos()).y(); | |
| 4718 | +ivec2 Application::getTrueMouse() const { | |
| 4719 | + return toGlm(_glWidget->mapFromGlobal(QCursor::pos())); | |
| 4783 | 4720 | } |
| 4784 | 4721 | |
| 4785 | 4722 | bool Application::isThrottleRendering() const { |
| @@ -4809,3 +4746,25 @@ qreal Application::getDevicePixelRatio() { · 23 unmodified lines | ||
| 4809 | 4746 | return _window ? _window->windowHandle()->devicePixelRatio() : 1.0; |
| 4810 | 4747 | } |
| 4811 | 4748 | |
| 4749 | +mat4 Application::getEyeProjection(int eye) const { | |
| 4750 | + if (isHMDMode()) { | |
| 4751 | + return OculusManager::getEyeProjection(eye); | |
| 4752 | + } | |
| 4753 | + | |
| 4754 | + return _viewFrustum.getProjection(); | |
| 4755 | +} | |
| 4756 | + | |
| 4757 | +mat4 Application::getEyePose(int eye) const { | |
| 4758 | + if (isHMDMode()) { | |
| 4759 | + return OculusManager::getEyePose(eye); | |
| 4760 | + } | |
| 4761 | + | |
| 4762 | + return mat4(); | |
| 4763 | +} | |
| 4764 | + | |
| 4765 | +mat4 Application::getHeadPose() const { | |
| 4766 | + if (isHMDMode()) { | |
| 4767 | + return OculusManager::getHeadPose(); | |
| 4768 | + } | |
| 4769 | + return mat4(); | |
| 4770 | +} | |
| @@ -62,12 +62,12 @@ · 61 unmodified lines | ||
| 62 | 62 | #include "ui/ModelsBrowser.h" |
| 63 | 63 | #include "ui/NodeBounds.h" |
| 64 | 64 | #include "ui/OctreeStatsDialog.h" |
| 65 | −#include "ui/RearMirrorTools.h" | |
| 66 | 65 | #include "ui/SnapshotShareDialog.h" |
| 67 | 66 | #include "ui/LodToolsDialog.h" |
| 68 | 67 | #include "ui/LogDialog.h" |
| 69 | 68 | #include "ui/overlays/Overlays.h" |
| 70 | 69 | #include "ui/ApplicationOverlay.h" |
| 70 | +#include "ui/ApplicationCompositor.h" | |
| 71 | 71 | #include "ui/RunningScriptsWidget.h" |
| 72 | 72 | #include "ui/ToolWindow.h" |
| 73 | 73 | #include "ui/UserInputMapper.h" |
| @@ -221,15 +221,21 @@ public: · 147 unmodified lines | ||
| 221 | 221 | const glm::vec3& getMouseRayOrigin() const { return _mouseRayOrigin; } |
| 222 | 222 | const glm::vec3& getMouseRayDirection() const { return _mouseRayDirection; } |
| 223 | 223 | bool mouseOnScreen() const; |
| 224 | − int getMouseX() const; | |
| 225 | − int getMouseY() const; | |
| 226 | − glm::ivec2 getTrueMousePosition() const; | |
| 227 | − int getTrueMouseX() const; | |
| 228 | − int getTrueMouseY() const; | |
| 229 | − int getMouseDragStartedX() const; | |
| 230 | − int getMouseDragStartedY() const; | |
| 231 | − int getTrueMouseDragStartedX() const { return _mouseDragStartedX; } | |
| 232 | − int getTrueMouseDragStartedY() const { return _mouseDragStartedY; } | |
| 224 | + | |
| 225 | + ivec2 getMouse() const; | |
| 226 | + ivec2 getTrueMouse() const; | |
| 227 | + ivec2 getMouseDragStarted() const; | |
| 228 | + ivec2 getTrueMouseDragStarted() const; | |
| 229 | + | |
| 230 | + // TODO get rid of these and use glm types directly | |
| 231 | + int getMouseX() const { return getMouse().x; } | |
| 232 | + int getMouseY() const { return getMouse().y; } | |
| 233 | + int getTrueMouseX() const { return getTrueMouse().x; } | |
| 234 | + int getTrueMouseY() const { return getTrueMouse().y; } | |
| 235 | + int getMouseDragStartedX() const { return getMouseDragStarted().x; } | |
| 236 | + int getMouseDragStartedY() const { return getMouseDragStarted().y; } | |
| 237 | + int getTrueMouseDragStartedX() const { return getTrueMouseDragStarted().x; } | |
| 238 | + int getTrueMouseDragStartedY() const { return getTrueMouseDragStarted().y; } | |
| 233 | 239 | bool getLastMouseMoveWasSimulated() const { return _lastMouseMoveWasSimulated; } |
| 234 | 240 | |
| 235 | 241 | FaceTracker* getActiveFaceTracker(); |
| @@ -238,6 +244,8 @@ public: · 2 unmodified lines | ||
| 238 | 244 | QSystemTrayIcon* getTrayIcon() { return _trayIcon; } |
| 239 | 245 | ApplicationOverlay& getApplicationOverlay() { return _applicationOverlay; } |
| 240 | 246 | const ApplicationOverlay& getApplicationOverlay() const { return _applicationOverlay; } |
| 247 | + ApplicationCompositor& getApplicationCompositor() { return _compositor; } | |
| 248 | + const ApplicationCompositor& getApplicationCompositor() const { return _compositor; } | |
| 241 | 249 | Overlays& getOverlays() { return _overlays; } |
| 242 | 250 | |
| 243 | 251 | float getFps() const { return _fps; } |
| @@ -330,6 +338,9 @@ public: · 86 unmodified lines | ||
| 330 | 338 | bool isHMDMode() const; |
| 331 | 339 | glm::quat getHeadOrientation() const; |
| 332 | 340 | glm::vec3 getHeadPosition() const; |
| 341 | + glm::mat4 getHeadPose() const; | |
| 342 | + glm::mat4 getEyePose(int eye) const; | |
| 343 | + glm::mat4 getEyeProjection(int eye) const; | |
| 333 | 344 | |
| 334 | 345 | QRect getDesirableApplicationGeometry(); |
| 335 | 346 | RunningScriptsWidget* getRunningScriptsWidget() { return _runningScriptsWidget; } |
| @@ -451,6 +462,8 @@ private slots: · 115 unmodified lines | ||
| 451 | 462 | void setFullscreen(bool fullscreen); |
| 452 | 463 | void setEnable3DTVMode(bool enable3DTVMode); |
| 453 | 464 | void setEnableVRMode(bool enableVRMode); |
| 465 | + | |
| 466 | + void rotationModeChanged(); | |
| 454 | 467 | |
| 455 | 468 | glm::vec2 getScaledScreenPoint(glm::vec2 projectedPoint); |
| 456 | 469 | |
| @@ -548,21 +561,17 @@ private: · 91 unmodified lines | ||
| 548 | 561 | |
| 549 | 562 | OctreeQuery _octreeQuery; // NodeData derived class for querying octee cells from octree servers |
| 550 | 563 | |
| 551 | − KeyboardMouseDevice _keyboardMouseDevice; // Default input device, the good old keyboard mouse and maybe touchpad | |
| 552 | − | |
| 553 | − UserInputMapper _userInputMapper; // User input mapper allowing to mapp different real devices to the action channels that the application has to offer | |
| 554 | − | |
| 555 | − MyAvatar* _myAvatar; // TODO: move this and relevant code to AvatarManager (or MyAvatar as the case may be) | |
| 556 | − | |
| 557 | − Camera _myCamera; // My view onto the world | |
| 564 | + KeyboardMouseDevice _keyboardMouseDevice; // Default input device, the good old keyboard mouse and maybe touchpad | |
| 565 | + UserInputMapper _userInputMapper; // User input mapper allowing to mapp different real devices to the action channels that the application has to offer | |
| 566 | + MyAvatar* _myAvatar; // TODO: move this and relevant code to AvatarManager (or MyAvatar as the case may be) | |
| 567 | + Camera _myCamera; // My view onto the world | |
| 558 | 568 | Camera _mirrorCamera; // Cammera for mirror view |
| 559 | 569 | QRect _mirrorViewRect; |
| 560 | − RearMirrorTools* _rearMirrorTools; | |
| 561 | 570 | |
| 562 | − Setting::Handle<bool> _firstRun; | |
| 563 | − Setting::Handle<QString> _previousScriptLocation; | |
| 564 | − Setting::Handle<QString> _scriptsLocationHandle; | |
| 565 | − Setting::Handle<float> _fieldOfView; | |
| 571 | + Setting::Handle<bool> _firstRun; | |
| 572 | + Setting::Handle<QString> _previousScriptLocation; | |
| 573 | + Setting::Handle<QString> _scriptsLocationHandle; | |
| 574 | + Setting::Handle<float> _fieldOfView; | |
| 566 | 575 | |
| 567 | 576 | Transform _viewTransform; |
| 568 | 577 | glm::mat4 _untranslatedViewMatrix; |
| @@ -580,18 +589,17 @@ private: · 11 unmodified lines | ||
| 580 | 589 | Environment _environment; |
| 581 | 590 | |
| 582 | 591 | bool _cursorVisible; |
| 583 | − int _mouseDragStartedX; | |
| 584 | − int _mouseDragStartedY; | |
| 592 | + ivec2 _mouseDragStarted; | |
| 593 | + | |
| 585 | 594 | quint64 _lastMouseMove; |
| 586 | 595 | bool _lastMouseMoveWasSimulated; |
| 587 | 596 | |
| 588 | 597 | glm::vec3 _mouseRayOrigin; |
| 589 | 598 | glm::vec3 _mouseRayDirection; |
| 590 | 599 | |
| 591 | − float _touchAvgX; | |
| 592 | − float _touchAvgY; | |
| 593 | − float _touchDragStartedAvgX; | |
| 594 | − float _touchDragStartedAvgY; | |
| 600 | + vec2 _touchAvg; | |
| 601 | + vec2 _touchDragStartedAvg; | |
| 602 | + | |
| 595 | 603 | bool _isTouchPressed; // true if multitouch has been pressed (clear when finished) |
| 596 | 604 | |
| 597 | 605 | bool _mousePressed; // true if mouse has been pressed (clear when finished) |
| @@ -669,6 +677,7 @@ private: · 71 unmodified lines | ||
| 669 | 677 | |
| 670 | 678 | Overlays _overlays; |
| 671 | 679 | ApplicationOverlay _applicationOverlay; |
| 680 | + ApplicationCompositor _compositor; | |
| 672 | 681 | }; |
| 673 | 682 | |
| 674 | 683 | #endif // hifi_Application_h |
| @@ -49,8 +49,6 @@ Camera::Camera() : · 48 unmodified lines | ||
| 49 | 49 | _mode(CAMERA_MODE_THIRD_PERSON), |
| 50 | 50 | _position(0.0f, 0.0f, 0.0f), |
| 51 | 51 | _projection(glm::perspective(glm::radians(DEFAULT_FIELD_OF_VIEW_DEGREES), 16.0f/9.0f, DEFAULT_NEAR_CLIP, DEFAULT_FAR_CLIP)), |
| 52 | − _hmdPosition(), | |
| 53 | − _hmdRotation(), | |
| 54 | 52 | _isKeepLookingAt(false), |
| 55 | 53 | _lookingAt(0.0f, 0.0f, 0.0f) |
| 56 | 54 | { |
| @@ -74,20 +72,6 @@ void Camera::setRotation(const glm::quat& rotation) { · 17 unmodified lines | ||
| 74 | 72 | } |
| 75 | 73 | } |
| 76 | 74 | |
| 77 | −void Camera::setHmdPosition(const glm::vec3& hmdPosition) { | |
| 78 | − _hmdPosition = hmdPosition; | |
| 79 | − if (_isKeepLookingAt) { | |
| 80 | − lookAt(_lookingAt); | |
| 81 | − } | |
| 82 | −} | |
| 83 | − | |
| 84 | −void Camera::setHmdRotation(const glm::quat& hmdRotation) { | |
| 85 | − _hmdRotation = hmdRotation; | |
| 86 | − if (_isKeepLookingAt) { | |
| 87 | − lookAt(_lookingAt); | |
| 88 | − } | |
| 89 | −} | |
| 90 | − | |
| 91 | 75 | void Camera::setMode(CameraMode mode) { |
| 92 | 76 | _mode = mode; |
| 93 | 77 | emit modeUpdated(modeToString(mode)); |
| @@ -45,26 +45,22 @@ public: · 44 unmodified lines | ||
| 45 | 45 | |
| 46 | 46 | void setRotation(const glm::quat& rotation); |
| 47 | 47 | void setProjection(const glm::mat4 & projection); |
| 48 | − void setHmdPosition(const glm::vec3& hmdPosition); | |
| 49 | − void setHmdRotation(const glm::quat& hmdRotation); | |
| 50 | 48 | void setMode(CameraMode m); |
| 51 | 49 | |
| 52 | − glm::quat getRotation() const { return _rotation * _hmdRotation; } | |
| 50 | + glm::quat getRotation() const { return _rotation; } | |
| 53 | 51 | const glm::mat4& getProjection() const { return _projection; } |
| 54 | − const glm::vec3& getHmdPosition() const { return _hmdPosition; } | |
| 55 | − const glm::quat& getHmdRotation() const { return _hmdRotation; } | |
| 56 | 52 | CameraMode getMode() const { return _mode; } |
| 57 | 53 | |
| 58 | 54 | public slots: |
| 59 | 55 | QString getModeString() const; |
| 60 | 56 | void setModeString(const QString& mode); |
| 61 | 57 | |
| 62 | − glm::vec3 getPosition() const { return _position + _hmdPosition; } | |
| 58 | + glm::vec3 getPosition() const { return _position; } | |
| 63 | 59 | void setPosition(const glm::vec3& position); |
| 64 | 60 | |
| 65 | − void setOrientation(const glm::quat& orientation) { setRotation(orientation); } | |
| 66 | 61 | glm::quat getOrientation() const { return getRotation(); } |
| 67 | − | |
| 62 | + void setOrientation(const glm::quat& orientation) { setRotation(orientation); } | |
| 63 | + | |
| 68 | 64 | PickRay computePickRay(float x, float y); |
| 69 | 65 | |
| 70 | 66 | // These only work on independent cameras |
| @@ -86,8 +82,6 @@ private: · 15 unmodified lines | ||
| 86 | 82 | glm::vec3 _position; |
| 87 | 83 | glm::quat _rotation; |
| 88 | 84 | glm::mat4 _projection; |
| 89 | − glm::vec3 _hmdPosition; | |
| 90 | − glm::quat _hmdRotation; | |
| 91 | 85 | bool _isKeepLookingAt; |
| 92 | 86 | glm::vec3 _lookingAt; |
| 93 | 87 | }; |
| @@ -39,11 +39,11 @@ bool GLCanvas::isThrottleRendering() const { · 38 unmodified lines | ||
| 39 | 39 | } |
| 40 | 40 | |
| 41 | 41 | int GLCanvas::getDeviceWidth() const { |
| 42 | − return width() * (windowHandle() ? windowHandle()->devicePixelRatio() : 1.0f); | |
| 42 | + return width() * (windowHandle() ? (float)windowHandle()->devicePixelRatio() : 1.0f); | |
| 43 | 43 | } |
| 44 | 44 | |
| 45 | 45 | int GLCanvas::getDeviceHeight() const { |
| 46 | − return height() * (windowHandle() ? windowHandle()->devicePixelRatio() : 1.0f); | |
| 46 | + return height() * (windowHandle() ? (float)windowHandle()->devicePixelRatio() : 1.0f); | |
| 47 | 47 | } |
| 48 | 48 | |
| 49 | 49 | void GLCanvas::initializeGL() { |
| @@ -12,7 +12,7 @@ · 11 unmodified lines | ||
| 12 | 12 | |
| 13 | 13 | |
| 14 | 14 | #include <avatar/AvatarActionHold.h> |
| 15 | −#include <ObjectActionPullToPoint.h> | |
| 15 | +#include <ObjectActionOffset.h> | |
| 16 | 16 | #include <ObjectActionSpring.h> |
| 17 | 17 | |
| 18 | 18 | #include "InterfaceActionFactory.h" |
| @@ -27,8 +27,8 @@ EntityActionPointer InterfaceActionFactory::factory(EntitySimulation* simulation · 8 unmodified lines | ||
| 27 | 27 | switch (type) { |
| 28 | 28 | case ACTION_TYPE_NONE: |
| 29 | 29 | return nullptr; |
| 30 | − case ACTION_TYPE_PULL_TO_POINT: | |
| 31 | − action = (EntityActionPointer) new ObjectActionPullToPoint(id, ownerEntity); | |
| 30 | + case ACTION_TYPE_OFFSET: | |
| 31 | + action = (EntityActionPointer) new ObjectActionOffset(id, ownerEntity); | |
| 32 | 32 | break; |
| 33 | 33 | case ACTION_TYPE_SPRING: |
| 34 | 34 | action = (EntityActionPointer) new ObjectActionSpring(id, ownerEntity); |
| @@ -205,11 +205,11 @@ QString LODManager::getLODFeedbackText() { · 204 unmodified lines | ||
| 205 | 205 | int relativeToTwentyTwenty = 20 / relativeToDefault; |
| 206 | 206 | |
| 207 | 207 | QString result; |
| 208 | − if (relativeToDefault > 1.01) { | |
| 208 | + if (relativeToDefault > 1.01f) { | |
| 209 | 209 | result = QString("20:%1 or %2 times further than average vision%3").arg(relativeToTwentyTwenty).arg(relativeToDefault,0,'f',2).arg(granularityFeedback); |
| 210 | − } else if (relativeToDefault > 0.99) { | |
| 210 | + } else if (relativeToDefault > 0.99f) { | |
| 211 | 211 | result = QString("20:20 or the default distance for average vision%1").arg(granularityFeedback); |
| 212 | − } else if (relativeToDefault > 0.01) { | |
| 212 | + } else if (relativeToDefault > 0.01f) { | |
| 213 | 213 | result = QString("20:%1 or %2 of default distance for average vision%3").arg(relativeToTwentyTwenty).arg(relativeToDefault,0,'f',3).arg(granularityFeedback); |
| 214 | 214 | } else { |
| 215 | 215 | result = QString("%2 of default distance for average vision%3").arg(relativeToDefault,0,'f',3).arg(granularityFeedback); |
| @@ -287,6 +287,12 @@ Menu::Menu() { · 286 unmodified lines | ||
| 287 | 287 | addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::Mirror, |
| 288 | 288 | 0, //QML Qt::SHIFT | Qt::Key_H, |
| 289 | 289 | true); |
| 290 | + addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::FullscreenMirror, | |
| 291 | + 0, // QML Qt::Key_H, | |
| 292 | + false, qApp, SLOT(cameraMenuChanged())); | |
| 293 | + | |
| 294 | + addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::CenterPlayerInView, | |
| 295 | + 0, false, qApp, SLOT(rotationModeChanged())); | |
| 290 | 296 | |
| 291 | 297 | addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::HMDTools, |
| 292 | 298 | #ifdef Q_OS_MAC |
| @@ -201,6 +201,7 @@ namespace MenuOption { · 200 unmodified lines | ||
| 201 | 201 | const QString FrameTimer = "Show Timer"; |
| 202 | 202 | const QString Fullscreen = "Fullscreen"; |
| 203 | 203 | const QString FullscreenMirror = "Fullscreen Mirror"; |
| 204 | + const QString CenterPlayerInView = "Center Player In View"; | |
| 204 | 205 | const QString GlowWhenSpeaking = "Glow When Speaking"; |
| 205 | 206 | const QString NamesAboveHeads = "Names Above Heads"; |
| 206 | 207 | const QString HMDTools = "HMD Tools"; |
| @@ -33,19 +33,19 @@ _basePath(basePath), · 32 unmodified lines | ||
| 33 | 33 | _geometry(geometry) |
| 34 | 34 | { |
| 35 | 35 | setWindowTitle("Set Model Properties"); |
| 36 | − | |
| 36 | + | |
| 37 | 37 | QFormLayout* form = new QFormLayout(); |
| 38 | 38 | setLayout(form); |
| 39 | − | |
| 39 | + | |
| 40 | 40 | form->addRow("Name:", _name = new QLineEdit()); |
| 41 | − | |
| 41 | + | |
| 42 | 42 | form->addRow("Texture Directory:", _textureDirectory = new QPushButton()); |
| 43 | 43 | connect(_textureDirectory, SIGNAL(clicked(bool)), SLOT(chooseTextureDirectory())); |
| 44 | − | |
| 44 | + | |
| 45 | 45 | form->addRow("Scale:", _scale = new QDoubleSpinBox()); |
| 46 | 46 | _scale->setMaximum(FLT_MAX); |
| 47 | 47 | _scale->setSingleStep(0.01); |
| 48 | − | |
| 48 | + | |
| 49 | 49 | if (_modelType != FSTReader::ENTITY_MODEL) { |
| 50 | 50 | if (_modelType == FSTReader::ATTACHMENT_MODEL) { |
| 51 | 51 | QHBoxLayout* translation = new QHBoxLayout(); |
| @@ -57,7 +57,7 @@ _geometry(geometry) · 5 unmodified lines | ||
| 57 | 57 | form->addRow("Pivot Joint:", _pivotJoint = createJointBox()); |
| 58 | 58 | connect(_pivotAboutCenter, SIGNAL(toggled(bool)), SLOT(updatePivotJoint())); |
| 59 | 59 | _pivotAboutCenter->setChecked(true); |
| 60 | − | |
| 60 | + | |
| 61 | 61 | } else { |
| 62 | 62 | form->addRow("Left Eye Joint:", _leftEyeJoint = createJointBox()); |
| 63 | 63 | form->addRow("Right Eye Joint:", _rightEyeJoint = createJointBox()); |
| @@ -69,22 +69,22 @@ _geometry(geometry) · 5 unmodified lines | ||
| 69 | 69 | form->addRow("Head Joint:", _headJoint = createJointBox()); |
| 70 | 70 | form->addRow("Left Hand Joint:", _leftHandJoint = createJointBox()); |
| 71 | 71 | form->addRow("Right Hand Joint:", _rightHandJoint = createJointBox()); |
| 72 | − | |
| 72 | + | |
| 73 | 73 | form->addRow("Free Joints:", _freeJoints = new QVBoxLayout()); |
| 74 | 74 | QPushButton* newFreeJoint = new QPushButton("New Free Joint"); |
| 75 | 75 | _freeJoints->addWidget(newFreeJoint); |
| 76 | 76 | connect(newFreeJoint, SIGNAL(clicked(bool)), SLOT(createNewFreeJoint())); |
| 77 | 77 | } |
| 78 | 78 | } |
| 79 | − | |
| 79 | + | |
| 80 | 80 | QDialogButtonBox* buttons = new QDialogButtonBox(QDialogButtonBox::Ok | |
| 81 | 81 | QDialogButtonBox::Cancel | QDialogButtonBox::Reset); |
| 82 | 82 | connect(buttons, SIGNAL(accepted()), SLOT(accept())); |
| 83 | 83 | connect(buttons, SIGNAL(rejected()), SLOT(reject())); |
| 84 | 84 | connect(buttons->button(QDialogButtonBox::Reset), SIGNAL(clicked(bool)), SLOT(reset())); |
| 85 | − | |
| 85 | + | |
| 86 | 86 | form->addRow(buttons); |
| 87 | − | |
| 87 | + | |
| 88 | 88 | // reset to initialize the fields |
| 89 | 89 | reset(); |
| 90 | 90 | } |
| @@ -100,42 +100,42 @@ QVariantHash ModelPropertiesDialog::getMapping() const { · 9 unmodified lines | ||
| 100 | 100 | mapping.insert(NAME_FIELD, _name->text()); |
| 101 | 101 | mapping.insert(TEXDIR_FIELD, _textureDirectory->text()); |
| 102 | 102 | mapping.insert(SCALE_FIELD, QString::number(_scale->value())); |
| 103 | − | |
| 103 | + | |
| 104 | 104 | // update the joint indices |
| 105 | 105 | QVariantHash jointIndices; |
| 106 | 106 | for (int i = 0; i < _geometry.joints.size(); i++) { |
| 107 | 107 | jointIndices.insert(_geometry.joints.at(i).name, QString::number(i)); |
| 108 | 108 | } |
| 109 | 109 | mapping.insert(JOINT_INDEX_FIELD, jointIndices); |
| 110 | − | |
| 110 | + | |
| 111 | 111 | if (_modelType != FSTReader::ENTITY_MODEL) { |
| 112 | 112 | QVariantHash joints = mapping.value(JOINT_FIELD).toHash(); |
| 113 | 113 | if (_modelType == FSTReader::ATTACHMENT_MODEL) { |
| 114 | 114 | glm::vec3 pivot; |
| 115 | 115 | if (_pivotAboutCenter->isChecked()) { |
| 116 | 116 | pivot = (_geometry.meshExtents.minimum + _geometry.meshExtents.maximum) * 0.5f; |
| 117 | − | |
| 117 | + | |
| 118 | 118 | } else if (_pivotJoint->currentIndex() != 0) { |
| 119 | 119 | pivot = extractTranslation(_geometry.joints.at(_pivotJoint->currentIndex() - 1).transform); |
| 120 | 120 | } |
| 121 | − mapping.insert(TRANSLATION_X_FIELD, -pivot.x * _scale->value() + _translationX->value()); | |
| 122 | − mapping.insert(TRANSLATION_Y_FIELD, -pivot.y * _scale->value() + _translationY->value()); | |
| 123 | − mapping.insert(TRANSLATION_Z_FIELD, -pivot.z * _scale->value() + _translationZ->value()); | |
| 124 | − | |
| 121 | + mapping.insert(TRANSLATION_X_FIELD, -pivot.x * (float)_scale->value() + (float)_translationX->value()); | |
| 122 | + mapping.insert(TRANSLATION_Y_FIELD, -pivot.y * (float)_scale->value() + (float)_translationY->value()); | |
| 123 | + mapping.insert(TRANSLATION_Z_FIELD, -pivot.z * (float)_scale->value() + (float)_translationZ->value()); | |
| 124 | + | |
| 125 | 125 | } else { |
| 126 | 126 | insertJointMapping(joints, "jointEyeLeft", _leftEyeJoint->currentText()); |
| 127 | 127 | insertJointMapping(joints, "jointEyeRight", _rightEyeJoint->currentText()); |
| 128 | 128 | insertJointMapping(joints, "jointNeck", _neckJoint->currentText()); |
| 129 | 129 | } |
| 130 | − | |
| 131 | − | |
| 130 | + | |
| 131 | + | |
| 132 | 132 | if (_modelType == FSTReader::BODY_ONLY_MODEL || _modelType == FSTReader::HEAD_AND_BODY_MODEL) { |
| 133 | 133 | insertJointMapping(joints, "jointRoot", _rootJoint->currentText()); |
| 134 | 134 | insertJointMapping(joints, "jointLean", _leanJoint->currentText()); |
| 135 | 135 | insertJointMapping(joints, "jointHead", _headJoint->currentText()); |
| 136 | 136 | insertJointMapping(joints, "jointLeftHand", _leftHandJoint->currentText()); |
| 137 | 137 | insertJointMapping(joints, "jointRightHand", _rightHandJoint->currentText()); |
| 138 | − | |
| 138 | + | |
| 139 | 139 | mapping.remove(FREE_JOINT_FIELD); |
| 140 | 140 | for (int i = 0; i < _freeJoints->count() - 1; i++) { |
| 141 | 141 | QComboBox* box = static_cast<QComboBox*>(_freeJoints->itemAt(i)->widget()->layout()->itemAt(0)->widget()); |
| @@ -144,7 +144,7 @@ QVariantHash ModelPropertiesDialog::getMapping() const { · 2 unmodified lines | ||
| 144 | 144 | } |
| 145 | 145 | mapping.insert(JOINT_FIELD, joints); |
| 146 | 146 | } |
| 147 | − | |
| 147 | + | |
| 148 | 148 | return mapping; |
| 149 | 149 | } |
| 150 | 150 | |
| @@ -156,9 +156,9 @@ void ModelPropertiesDialog::reset() { · 5 unmodified lines | ||
| 156 | 156 | _name->setText(_originalMapping.value(NAME_FIELD).toString()); |
| 157 | 157 | _textureDirectory->setText(_originalMapping.value(TEXDIR_FIELD).toString()); |
| 158 | 158 | _scale->setValue(_originalMapping.value(SCALE_FIELD).toDouble()); |
| 159 | − | |
| 159 | + | |
| 160 | 160 | QVariantHash jointHash = _originalMapping.value(JOINT_FIELD).toHash(); |
| 161 | − | |
| 161 | + | |
| 162 | 162 | if (_modelType != FSTReader::ENTITY_MODEL) { |
| 163 | 163 | if (_modelType == FSTReader::ATTACHMENT_MODEL) { |
| 164 | 164 | _translationX->setValue(_originalMapping.value(TRANSLATION_X_FIELD).toDouble()); |
| @@ -166,20 +166,20 @@ void ModelPropertiesDialog::reset() { · 1 unmodified line | ||
| 166 | 166 | _translationZ->setValue(_originalMapping.value(TRANSLATION_Z_FIELD).toDouble()); |
| 167 | 167 | _pivotAboutCenter->setChecked(true); |
| 168 | 168 | _pivotJoint->setCurrentIndex(0); |
| 169 | − | |
| 169 | + | |
| 170 | 170 | } else { |
| 171 | 171 | setJointText(_leftEyeJoint, jointHash.value("jointEyeLeft").toString()); |
| 172 | 172 | setJointText(_rightEyeJoint, jointHash.value("jointEyeRight").toString()); |
| 173 | 173 | setJointText(_neckJoint, jointHash.value("jointNeck").toString()); |
| 174 | 174 | } |
| 175 | − | |
| 175 | + | |
| 176 | 176 | if (_modelType == FSTReader::BODY_ONLY_MODEL || _modelType == FSTReader::HEAD_AND_BODY_MODEL) { |
| 177 | 177 | setJointText(_rootJoint, jointHash.value("jointRoot").toString()); |
| 178 | 178 | setJointText(_leanJoint, jointHash.value("jointLean").toString()); |
| 179 | 179 | setJointText(_headJoint, jointHash.value("jointHead").toString()); |
| 180 | 180 | setJointText(_leftHandJoint, jointHash.value("jointLeftHand").toString()); |
| 181 | 181 | setJointText(_rightHandJoint, jointHash.value("jointRightHand").toString()); |
| 182 | − | |
| 182 | + | |
| 183 | 183 | while (_freeJoints->count() > 1) { |
| 184 | 184 | delete _freeJoints->itemAt(0)->widget(); |
| 185 | 185 | } |
| @@ -16,13 +16,13 @@ · 15 unmodified lines | ||
| 16 | 16 | #include "InterfaceConfig.h" |
| 17 | 17 | #include "starfield/Controller.h" |
| 18 | 18 | |
| 19 | −Stars::Stars() : | |
| 19 | +Stars::Stars() : | |
| 20 | 20 | _controller(0l), _starsLoaded(false) { |
| 21 | 21 | _controller = new starfield::Controller; |
| 22 | 22 | } |
| 23 | 23 | |
| 24 | −Stars::~Stars() { | |
| 25 | − delete _controller; | |
| 24 | +Stars::~Stars() { | |
| 25 | + delete _controller; | |
| 26 | 26 | } |
| 27 | 27 | |
| 28 | 28 | bool Stars::generate(unsigned numStars, unsigned seed) { |
| @@ -30,22 +30,20 @@ bool Stars::generate(unsigned numStars, unsigned seed) { · 1 unmodified line | ||
| 30 | 30 | return _starsLoaded; |
| 31 | 31 | } |
| 32 | 32 | |
| 33 | −bool Stars::setResolution(unsigned k) { | |
| 34 | − return _controller->setResolution(k); | |
| 33 | +bool Stars::setResolution(unsigned k) { | |
| 34 | + return _controller->setResolution(k); | |
| 35 | 35 | } |
| 36 | 36 | |
| 37 | 37 | void Stars::render(float fovY, float aspect, float nearZ, float alpha) { |
| 38 | 38 | // determine length of screen diagonal from quadrant height and aspect ratio |
| 39 | − float quadrantHeight = nearZ * tan(RADIANS_PER_DEGREE * fovY * 0.5f); | |
| 39 | + float quadrantHeight = nearZ * tanf(RADIANS_PER_DEGREE * fovY * 0.5f); | |
| 40 | 40 | float halfDiagonal = sqrt(quadrantHeight * quadrantHeight * (1.0f + aspect * aspect)); |
| 41 | 41 | |
| 42 | 42 | // determine fov angle in respect to the diagonal |
| 43 | − float fovDiagonal = atan(halfDiagonal / nearZ) * 2.0f; | |
| 43 | + float fovDiagonal = atanf(halfDiagonal / nearZ) * 2.0f; | |
| 44 | 44 | |
| 45 | 45 | // pull the modelview matrix off the GL stack |
| 46 | − glm::mat4 view; glGetFloatv(GL_MODELVIEW_MATRIX, glm::value_ptr(view)); | |
| 46 | + glm::mat4 view; glGetFloatv(GL_MODELVIEW_MATRIX, glm::value_ptr(view)); | |
| 47 | 47 | |
| 48 | 48 | _controller->render(fovDiagonal, aspect, glm::affineInverse(view), alpha); |
| 49 | 49 | } |
| 50 | − | |
| 51 | − | |
| @@ -70,6 +70,6 @@ void UIUtil::internalScaleWidgetFontSizes(QWidget* widget, float scale) { · 69 unmodified lines | ||
| 70 | 70 | } |
| 71 | 71 | |
| 72 | 72 | QFont font = widget->font(); |
| 73 | − font.setPointSizeF(font.pointSizeF() * scale); | |
| 73 | + font.setPointSizeF(font.pointSizeF() * (double)scale); | |
| 74 | 74 | widget->setFont(font); |
| 75 | 75 | } |
| @@ -41,7 +41,7 @@ void renderWorldBox(gpu::Batch& batch) { · 40 unmodified lines | ||
| 41 | 41 | static const glm::vec3 green(0.0f, 1.0f, 0.0f); |
| 42 | 42 | static const glm::vec3 blue(0.0f, 0.0f, 1.0f); |
| 43 | 43 | static const glm::vec3 grey(0.5f, 0.5f, 0.5f); |
| 44 | − | |
| 44 | + | |
| 45 | 45 | auto transform = Transform{}; |
| 46 | 46 | batch.setModelTransform(transform); |
| 47 | 47 | geometryCache->renderLine(batch, glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(TREE_SCALE, 0.0f, 0.0f), red); |
| @@ -49,13 +49,13 @@ void renderWorldBox(gpu::Batch& batch) { · 1 unmodified line | ||
| 49 | 49 | geometryCache->renderLine(batch, glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(0.0f, 0.0f, TREE_SCALE), blue); |
| 50 | 50 | geometryCache->renderLine(batch, glm::vec3(0.0f, 0.0f, TREE_SCALE), glm::vec3(TREE_SCALE, 0.0f, TREE_SCALE), grey); |
| 51 | 51 | geometryCache->renderLine(batch, glm::vec3(TREE_SCALE, 0.0f, TREE_SCALE), glm::vec3(TREE_SCALE, 0.0f, 0.0f), grey); |
| 52 | − | |
| 52 | + | |
| 53 | 53 | // Draw meter markers along the 3 axis to help with measuring things |
| 54 | 54 | const float MARKER_DISTANCE = 1.0f; |
| 55 | 55 | const float MARKER_RADIUS = 0.05f; |
| 56 | − | |
| 56 | + | |
| 57 | 57 | geometryCache->renderSphere(batch, MARKER_RADIUS, 10, 10, red); |
| 58 | − | |
| 58 | + | |
| 59 | 59 | transform.setTranslation(glm::vec3(MARKER_DISTANCE, 0.0f, 0.0f)); |
| 60 | 60 | batch.setModelTransform(transform); |
| 61 | 61 | geometryCache->renderSphere(batch, MARKER_RADIUS, 10, 10, red); |
| @@ -79,10 +79,10 @@ const glm::vec3 randVector() { · 17 unmodified lines | ||
| 79 | 79 | } |
| 80 | 80 | |
| 81 | 81 | static TextRenderer* textRenderer(int mono) { |
| 82 | − static TextRenderer* monoRenderer = TextRenderer::getInstance(MONO_FONT_FAMILY); | |
| 82 | + static TextRenderer* monoRenderer = TextRenderer::getInstance(MONO_FONT_FAMILY); | |
| 83 | 83 | static TextRenderer* proportionalRenderer = TextRenderer::getInstance(SANS_FONT_FAMILY, |
| 84 | 84 | -1, -1, false, TextRenderer::SHADOW_EFFECT); |
| 85 | − static TextRenderer* inconsolataRenderer = TextRenderer::getInstance(INCONSOLATA_FONT_FAMILY, -1, INCONSOLATA_FONT_WEIGHT, | |
| 85 | + static TextRenderer* inconsolataRenderer = TextRenderer::getInstance(INCONSOLATA_FONT_FAMILY, -1, INCONSOLATA_FONT_WEIGHT, | |
| 86 | 86 | false); |
| 87 | 87 | switch (mono) { |
| 88 | 88 | case 1: |
| @@ -133,46 +133,46 @@ void runTimingTests() { · 44 unmodified lines | ||
| 133 | 133 | QElapsedTimer startTime; |
| 134 | 134 | startTime.start(); |
| 135 | 135 | float elapsedUsecs; |
| 136 | − | |
| 136 | + | |
| 137 | 137 | float NSEC_TO_USEC = 1.0f / 1000.0f; |
| 138 | 138 | elapsedUsecs = (float)startTime.nsecsElapsed() * NSEC_TO_USEC; |
| 139 | − qCDebug(interfaceapp, "QElapsedTimer::nsecElapsed() usecs: %f", elapsedUsecs); | |
| 140 | − | |
| 139 | + qCDebug(interfaceapp, "QElapsedTimer::nsecElapsed() usecs: %f", (double)elapsedUsecs); | |
| 140 | + | |
| 141 | 141 | // Test sleep functions for accuracy |
| 142 | 142 | startTime.start(); |
| 143 | 143 | QThread::msleep(1); |
| 144 | 144 | elapsedUsecs = (float)startTime.nsecsElapsed() * NSEC_TO_USEC; |
| 145 | − qCDebug(interfaceapp, "QThread::msleep(1) ms: %f", elapsedUsecs / 1000.0f); | |
| 145 | + qCDebug(interfaceapp, "QThread::msleep(1) ms: %f", (double)(elapsedUsecs / 1000.0f)); | |
| 146 | 146 | |
| 147 | 147 | startTime.start(); |
| 148 | 148 | QThread::sleep(1); |
| 149 | 149 | elapsedUsecs = (float)startTime.nsecsElapsed() * NSEC_TO_USEC; |
| 150 | − qCDebug(interfaceapp, "QThread::sleep(1) ms: %f", elapsedUsecs / 1000.0f); | |
| 150 | + qCDebug(interfaceapp, "QThread::sleep(1) ms: %f", (double)(elapsedUsecs / 1000.0f)); | |
| 151 | 151 | |
| 152 | 152 | startTime.start(); |
| 153 | 153 | usleep(1); |
| 154 | 154 | elapsedUsecs = (float)startTime.nsecsElapsed() * NSEC_TO_USEC; |
| 155 | − qCDebug(interfaceapp, "usleep(1) ms: %f", elapsedUsecs / 1000.0f); | |
| 155 | + qCDebug(interfaceapp, "usleep(1) ms: %f", (double)(elapsedUsecs / 1000.0f)); | |
| 156 | 156 | |
| 157 | 157 | startTime.start(); |
| 158 | 158 | usleep(10); |
| 159 | 159 | elapsedUsecs = (float)startTime.nsecsElapsed() * NSEC_TO_USEC; |
| 160 | − qCDebug(interfaceapp, "usleep(10) ms: %f", elapsedUsecs / 1000.0f); | |
| 160 | + qCDebug(interfaceapp, "usleep(10) ms: %f", (double)(elapsedUsecs / 1000.0f)); | |
| 161 | 161 | |
| 162 | 162 | startTime.start(); |
| 163 | 163 | usleep(100); |
| 164 | 164 | elapsedUsecs = (float)startTime.nsecsElapsed() * NSEC_TO_USEC; |
| 165 | − qCDebug(interfaceapp, "usleep(100) ms: %f", elapsedUsecs / 1000.0f); | |
| 165 | + qCDebug(interfaceapp, "usleep(100) ms: %f", (double)(elapsedUsecs / 1000.0f)); | |
| 166 | 166 | |
| 167 | 167 | startTime.start(); |
| 168 | 168 | usleep(1000); |
| 169 | 169 | elapsedUsecs = (float)startTime.nsecsElapsed() * NSEC_TO_USEC; |
| 170 | − qCDebug(interfaceapp, "usleep(1000) ms: %f", elapsedUsecs / 1000.0f); | |
| 170 | + qCDebug(interfaceapp, "usleep(1000) ms: %f", (double)(elapsedUsecs / 1000.0f)); | |
| 171 | 171 | |
| 172 | 172 | startTime.start(); |
| 173 | 173 | usleep(15000); |
| 174 | 174 | elapsedUsecs = (float)startTime.nsecsElapsed() * NSEC_TO_USEC; |
| 175 | − qCDebug(interfaceapp, "usleep(15000) ms: %f", elapsedUsecs / 1000.0f); | |
| 175 | + qCDebug(interfaceapp, "usleep(15000) ms: %f", (double)(elapsedUsecs / 1000.0f)); | |
| 176 | 176 | |
| 177 | 177 | // Random number generation |
| 178 | 178 | startTime.start(); |
| @@ -180,7 +180,8 @@ void runTimingTests() { · 1 unmodified line | ||
| 180 | 180 | iResults[i] = rand(); |
| 181 | 181 | } |
| 182 | 182 | elapsedUsecs = (float)startTime.nsecsElapsed() * NSEC_TO_USEC; |
| 183 | − qCDebug(interfaceapp, "rand() stored in array usecs: %f, first result:%d", elapsedUsecs / (float) numTests, iResults[0]); | |
| 183 | + qCDebug(interfaceapp, "rand() stored in array usecs: %f, first result:%d", | |
| 184 | + (double)(elapsedUsecs / numTests), iResults[0]); | |
| 184 | 185 | |
| 185 | 186 | // Random number generation using randFloat() |
| 186 | 187 | startTime.start(); |
| @@ -188,7 +189,8 @@ void runTimingTests() { · 1 unmodified line | ||
| 188 | 189 | fResults[i] = randFloat(); |
| 189 | 190 | } |
| 190 | 191 | elapsedUsecs = (float)startTime.nsecsElapsed() * NSEC_TO_USEC; |
| 191 | − qCDebug(interfaceapp, "randFloat() stored in array usecs: %f, first result: %f", elapsedUsecs / (float) numTests, fResults[0]); | |
| 192 | + qCDebug(interfaceapp, "randFloat() stored in array usecs: %f, first result: %f", | |
| 193 | + (double)(elapsedUsecs / numTests), (double)(fResults[0])); | |
| 192 | 194 | |
| 193 | 195 | free(iResults); |
| 194 | 196 | free(fResults); |
| @@ -200,7 +202,7 @@ void runTimingTests() { · 5 unmodified lines | ||
| 200 | 202 | fTest = powf(fTest, 0.5f); |
| 201 | 203 | } |
| 202 | 204 | elapsedUsecs = (float)startTime.nsecsElapsed() * NSEC_TO_USEC; |
| 203 | − qCDebug(interfaceapp, "powf(f, 0.5) usecs: %f", elapsedUsecs / (float) numTests); | |
| 205 | + qCDebug(interfaceapp, "powf(f, 0.5) usecs: %f", (double)(elapsedUsecs / (float) numTests)); | |
| 204 | 206 | |
| 205 | 207 | // Vector Math |
| 206 | 208 | float distance; |
| @@ -213,19 +215,20 @@ void runTimingTests() { · 6 unmodified lines | ||
| 213 | 215 | } |
| 214 | 216 | elapsedUsecs = (float)startTime.nsecsElapsed() * NSEC_TO_USEC; |
| 215 | 217 | qCDebug(interfaceapp, "vector math usecs: %f [%f usecs total for %d tests], last result:%f", |
| 216 | − elapsedUsecs / (float) numTests, elapsedUsecs, numTests, distance); | |
| 218 | + (double)(elapsedUsecs / (float) numTests), (double)elapsedUsecs, numTests, (double)distance); | |
| 217 | 219 | |
| 218 | 220 | // Vec3 test |
| 219 | 221 | glm::vec3 vecA(randVector()), vecB(randVector()); |
| 220 | 222 | float result; |
| 221 | − | |
| 223 | + | |
| 222 | 224 | startTime.start(); |
| 223 | 225 | for (int i = 0; i < numTests; i++) { |
| 224 | 226 | glm::vec3 temp = vecA-vecB; |
| 225 | 227 | result = glm::dot(temp,temp); |
| 226 | 228 | } |
| 227 | 229 | elapsedUsecs = (float)startTime.nsecsElapsed() * NSEC_TO_USEC; |
| 228 | − qCDebug(interfaceapp, "vec3 assign and dot() usecs: %f, last result:%f", elapsedUsecs / (float) numTests, result); | |
| 230 | + qCDebug(interfaceapp, "vec3 assign and dot() usecs: %f, last result:%f", | |
| 231 | + (double)(elapsedUsecs / numTests), (double)result); | |
| 229 | 232 | } |
| 230 | 233 | |
| 231 | 234 | bool rayIntersectsSphere(const glm::vec3& rayStarting, const glm::vec3& rayNormalizedDirection, |
| @@ -41,32 +41,32 @@ void AudioIOStatsRenderer::render(const float* color, int width, int height) { · 40 unmodified lines | ||
| 41 | 41 | if (!_isEnabled) { |
| 42 | 42 | return; |
| 43 | 43 | } |
| 44 | − | |
| 44 | + | |
| 45 | 45 | const int linesWhenCentered = _shouldShowInjectedStreams ? 34 : 27; |
| 46 | 46 | const int CENTERED_BACKGROUND_HEIGHT = STATS_HEIGHT_PER_LINE * linesWhenCentered; |
| 47 | − | |
| 47 | + | |
| 48 | 48 | int lines = _shouldShowInjectedStreams ? _stats->getMixerInjectedStreamStatsMap().size() * 7 + 27 : 27; |
| 49 | 49 | int statsHeight = STATS_HEIGHT_PER_LINE * lines; |
| 50 | − | |
| 51 | − | |
| 50 | + | |
| 51 | + | |
| 52 | 52 | static const glm::vec4 backgroundColor = { 0.2f, 0.2f, 0.2f, 0.6f }; |
| 53 | 53 | int x = std::max((width - (int)STATS_WIDTH) / 2, 0); |
| 54 | 54 | int y = std::max((height - CENTERED_BACKGROUND_HEIGHT) / 2, 0); |
| 55 | 55 | int w = STATS_WIDTH; |
| 56 | 56 | int h = statsHeight; |
| 57 | 57 | DependencyManager::get<GeometryCache>()->renderQuad(x, y, w, h, backgroundColor); |
| 58 | − | |
| 58 | + | |
| 59 | 59 | int horizontalOffset = x + 5; |
| 60 | 60 | int verticalOffset = y; |
| 61 | − | |
| 61 | + | |
| 62 | 62 | float scale = 0.10f; |
| 63 | 63 | float rotation = 0.0f; |
| 64 | 64 | int font = 2; |
| 65 | − | |
| 65 | + | |
| 66 | 66 | char latencyStatString[512]; |
| 67 | − | |
| 67 | + | |
| 68 | 68 | float audioInputBufferLatency = 0.0f, inputRingBufferLatency = 0.0f, networkRoundtripLatency = 0.0f, mixerRingBufferLatency = 0.0f, outputRingBufferLatency = 0.0f, audioOutputBufferLatency = 0.0f; |
| 69 | − | |
| 69 | + | |
| 70 | 70 | AudioStreamStats downstreamAudioStreamStats = _stats->getMixerDownstreamStats(); |
| 71 | 71 | SharedNodePointer audioMixerNodePointer = DependencyManager::get<NodeList>()->soloNodeOfType(NodeType::AudioMixer); |
| 72 | 72 | if (!audioMixerNodePointer.isNull()) { |
| @@ -78,48 +78,62 @@ void AudioIOStatsRenderer::render(const float* color, int width, int height) { · 5 unmodified lines | ||
| 78 | 78 | audioOutputBufferLatency = _stats->getAudioOutputMsecsUnplayedStats().getWindowAverage(); |
| 79 | 79 | } |
| 80 | 80 | float totalLatency = audioInputBufferLatency + inputRingBufferLatency + networkRoundtripLatency + mixerRingBufferLatency + outputRingBufferLatency + audioOutputBufferLatency; |
| 81 | − | |
| 82 | − sprintf(latencyStatString, " Audio input buffer: %7.2fms - avg msecs of samples read to the input ring buffer in last 10s", audioInputBufferLatency); | |
| 81 | + | |
| 82 | + sprintf(latencyStatString, | |
| 83 | + " Audio input buffer: %7.2fms - avg msecs of samples read to the input ring buffer in last 10s", | |
| 84 | + (double)audioInputBufferLatency); | |
| 83 | 85 | verticalOffset += STATS_HEIGHT_PER_LINE; |
| 84 | 86 | drawText(horizontalOffset, verticalOffset, scale, rotation, font, latencyStatString, color); |
| 85 | − | |
| 86 | − sprintf(latencyStatString, " Input ring buffer: %7.2fms - avg msecs of samples in input ring buffer in last 10s", inputRingBufferLatency); | |
| 87 | + | |
| 88 | + sprintf(latencyStatString, | |
| 89 | + " Input ring buffer: %7.2fms - avg msecs of samples in input ring buffer in last 10s", | |
| 90 | + (double)inputRingBufferLatency); | |
| 87 | 91 | verticalOffset += STATS_HEIGHT_PER_LINE; |
| 88 | 92 | drawText(horizontalOffset, verticalOffset, scale, rotation, font, latencyStatString, color); |
| 89 | − | |
| 90 | − sprintf(latencyStatString, " Network to mixer: %7.2fms - half of last ping value calculated by the node list", networkRoundtripLatency / 2.0f); | |
| 93 | + | |
| 94 | + sprintf(latencyStatString, | |
| 95 | + " Network to mixer: %7.2fms - half of last ping value calculated by the node list", | |
| 96 | + (double)(networkRoundtripLatency / 2.0f)); | |
| 91 | 97 | verticalOffset += STATS_HEIGHT_PER_LINE; |
| 92 | 98 | drawText(horizontalOffset, verticalOffset, scale, rotation, font, latencyStatString, color); |
| 93 | − | |
| 94 | − sprintf(latencyStatString, " AudioMixer ring buffer: %7.2fms - avg msecs of samples in audio mixer's ring buffer in last 10s", mixerRingBufferLatency); | |
| 99 | + | |
| 100 | + sprintf(latencyStatString, | |
| 101 | + " AudioMixer ring buffer: %7.2fms - avg msecs of samples in audio mixer's ring buffer in last 10s", | |
| 102 | + (double)mixerRingBufferLatency); | |
| 95 | 103 | verticalOffset += STATS_HEIGHT_PER_LINE; |
| 96 | 104 | drawText(horizontalOffset, verticalOffset, scale, rotation, font, latencyStatString, color); |
| 97 | − | |
| 98 | − sprintf(latencyStatString, " Network to client: %7.2fms - half of last ping value calculated by the node list", networkRoundtripLatency / 2.0f); | |
| 105 | + | |
| 106 | + sprintf(latencyStatString, | |
| 107 | + " Network to client: %7.2fms - half of last ping value calculated by the node list", | |
| 108 | + (double)(networkRoundtripLatency / 2.0f)); | |
| 99 | 109 | verticalOffset += STATS_HEIGHT_PER_LINE; |
| 100 | 110 | drawText(horizontalOffset, verticalOffset, scale, rotation, font, latencyStatString, color); |
| 101 | − | |
| 102 | − sprintf(latencyStatString, " Output ring buffer: %7.2fms - avg msecs of samples in output ring buffer in last 10s", outputRingBufferLatency); | |
| 111 | + | |
| 112 | + sprintf(latencyStatString, | |
| 113 | + " Output ring buffer: %7.2fms - avg msecs of samples in output ring buffer in last 10s", | |
| 114 | + (double)outputRingBufferLatency); | |
| 103 | 115 | verticalOffset += STATS_HEIGHT_PER_LINE; |
| 104 | 116 | drawText(horizontalOffset, verticalOffset, scale, rotation, font, latencyStatString, color); |
| 105 | − | |
| 106 | − sprintf(latencyStatString, " Audio output buffer: %7.2fms - avg msecs of samples in audio output buffer in last 10s", audioOutputBufferLatency); | |
| 117 | + | |
| 118 | + sprintf(latencyStatString, | |
| 119 | + " Audio output buffer: %7.2fms - avg msecs of samples in audio output buffer in last 10s", | |
| 120 | + (double)audioOutputBufferLatency); | |
| 107 | 121 | verticalOffset += STATS_HEIGHT_PER_LINE; |
| 108 | 122 | drawText(horizontalOffset, verticalOffset, scale, rotation, font, latencyStatString, color); |
| 109 | − | |
| 110 | − sprintf(latencyStatString, " TOTAL: %7.2fms\n", totalLatency); | |
| 123 | + | |
| 124 | + sprintf(latencyStatString, " TOTAL: %7.2fms\n", (double)totalLatency); | |
| 111 | 125 | verticalOffset += STATS_HEIGHT_PER_LINE; |
| 112 | 126 | drawText(horizontalOffset, verticalOffset, scale, rotation, font, latencyStatString, color); |
| 113 | − | |
| 114 | − | |
| 127 | + | |
| 128 | + | |
| 115 | 129 | verticalOffset += STATS_HEIGHT_PER_LINE; // blank line |
| 116 | − | |
| 130 | + | |
| 117 | 131 | char clientUpstreamMicLabelString[] = "Upstream Mic Audio Packets Sent Gaps (by client):"; |
| 118 | 132 | verticalOffset += STATS_HEIGHT_PER_LINE; |
| 119 | 133 | drawText(horizontalOffset, verticalOffset, scale, rotation, font, clientUpstreamMicLabelString, color); |
| 120 | − | |
| 134 | + | |
| 121 | 135 | const MovingMinMaxAvg<quint64>& packetSentTimeGaps = _stats->getPacketSentTimeGaps(); |
| 122 | − | |
| 136 | + | |
| 123 | 137 | char stringBuffer[512]; |
| 124 | 138 | sprintf(stringBuffer, " Inter-packet timegaps (overall) | min: %9s, max: %9s, avg: %9s", |
| 125 | 139 | formatUsecTime(packetSentTimeGaps.getMin()).toLatin1().data(), |
| @@ -127,47 +141,47 @@ void AudioIOStatsRenderer::render(const float* color, int width, int height) { · 1 unmodified line | ||
| 127 | 141 | formatUsecTime(packetSentTimeGaps.getAverage()).toLatin1().data()); |
| 128 | 142 | verticalOffset += STATS_HEIGHT_PER_LINE; |
| 129 | 143 | drawText(horizontalOffset, verticalOffset, scale, rotation, font, stringBuffer, color); |
| 130 | − | |
| 144 | + | |
| 131 | 145 | sprintf(stringBuffer, " Inter-packet timegaps (last 30s) | min: %9s, max: %9s, avg: %9s", |
| 132 | 146 | formatUsecTime(packetSentTimeGaps.getWindowMin()).toLatin1().data(), |
| 133 | 147 | formatUsecTime(packetSentTimeGaps.getWindowMax()).toLatin1().data(), |
| 134 | 148 | formatUsecTime(packetSentTimeGaps.getWindowAverage()).toLatin1().data()); |
| 135 | 149 | verticalOffset += STATS_HEIGHT_PER_LINE; |
| 136 | 150 | drawText(horizontalOffset, verticalOffset, scale, rotation, font, stringBuffer, color); |
| 137 | − | |
| 151 | + | |
| 138 | 152 | verticalOffset += STATS_HEIGHT_PER_LINE; // blank line |
| 139 | − | |
| 153 | + | |
| 140 | 154 | char upstreamMicLabelString[] = "Upstream mic audio stats (received and reported by audio-mixer):"; |
| 141 | 155 | verticalOffset += STATS_HEIGHT_PER_LINE; |
| 142 | 156 | drawText(horizontalOffset, verticalOffset, scale, rotation, font, upstreamMicLabelString, color); |
| 143 | − | |
| 157 | + | |
| 144 | 158 | renderAudioStreamStats(&_stats->getMixerAvatarStreamStats(), horizontalOffset, verticalOffset, |
| 145 | 159 | scale, rotation, font, color); |
| 146 | − | |
| 147 | − | |
| 160 | + | |
| 161 | + | |
| 148 | 162 | verticalOffset += STATS_HEIGHT_PER_LINE; // blank line |
| 149 | − | |
| 163 | + | |
| 150 | 164 | char downstreamLabelString[] = "Downstream mixed audio stats:"; |
| 151 | 165 | verticalOffset += STATS_HEIGHT_PER_LINE; |
| 152 | 166 | drawText(horizontalOffset, verticalOffset, scale, rotation, font, downstreamLabelString, color); |
| 153 | − | |
| 167 | + | |
| 154 | 168 | AudioStreamStats downstreamStats = _stats->getMixerDownstreamStats(); |
| 155 | 169 | renderAudioStreamStats(&downstreamStats, horizontalOffset, verticalOffset, |
| 156 | 170 | scale, rotation, font, color, true); |
| 157 | − | |
| 158 | − | |
| 171 | + | |
| 172 | + | |
| 159 | 173 | if (_shouldShowInjectedStreams) { |
| 160 | − | |
| 174 | + | |
| 161 | 175 | foreach(const AudioStreamStats& injectedStreamAudioStats, _stats->getMixerInjectedStreamStatsMap()) { |
| 162 | − | |
| 176 | + | |
| 163 | 177 | verticalOffset += STATS_HEIGHT_PER_LINE; // blank line |
| 164 | − | |
| 178 | + | |
| 165 | 179 | char upstreamInjectedLabelString[512]; |
| 166 | 180 | sprintf(upstreamInjectedLabelString, "Upstream injected audio stats: stream ID: %s", |
| 167 | 181 | injectedStreamAudioStats._streamIdentifier.toString().toLatin1().data()); |
| 168 | 182 | verticalOffset += STATS_HEIGHT_PER_LINE; |
| 169 | 183 | drawText(horizontalOffset, verticalOffset, scale, rotation, font, upstreamInjectedLabelString, color); |
| 170 | − | |
| 184 | + | |
| 171 | 185 | renderAudioStreamStats(&injectedStreamAudioStats, horizontalOffset, verticalOffset, scale, rotation, font, color); |
| 172 | 186 | } |
| 173 | 187 | } |
| @@ -175,22 +189,22 @@ void AudioIOStatsRenderer::render(const float* color, int width, int height) { · 1 unmodified line | ||
| 175 | 189 | |
| 176 | 190 | void AudioIOStatsRenderer::renderAudioStreamStats(const AudioStreamStats* streamStats, int horizontalOffset, int& verticalOffset, |
| 177 | 191 | float scale, float rotation, int font, const float* color, bool isDownstreamStats) { |
| 178 | − | |
| 192 | + | |
| 179 | 193 | char stringBuffer[512]; |
| 180 | − | |
| 194 | + | |
| 181 | 195 | sprintf(stringBuffer, " Packet loss | overall: %5.2f%% (%d lost), last_30s: %5.2f%% (%d lost)", |
| 182 | − streamStats->_packetStreamStats.getLostRate() * 100.0f, | |
| 196 | + (double)(streamStats->_packetStreamStats.getLostRate() * 100.0f), | |
| 183 | 197 | streamStats->_packetStreamStats._lost, |
| 184 | − streamStats->_packetStreamWindowStats.getLostRate() * 100.0f, | |
| 198 | + (double)(streamStats->_packetStreamWindowStats.getLostRate() * 100.0f), | |
| 185 | 199 | streamStats->_packetStreamWindowStats._lost); |
| 186 | 200 | verticalOffset += STATS_HEIGHT_PER_LINE; |
| 187 | 201 | drawText(horizontalOffset, verticalOffset, scale, rotation, font, stringBuffer, color); |
| 188 | − | |
| 202 | + | |
| 189 | 203 | if (isDownstreamStats) { |
| 190 | 204 | sprintf(stringBuffer, " Ringbuffer frames | desired: %u, avg_available(10s): %u+%d, available: %u+%d", |
| 191 | 205 | streamStats->_desiredJitterBufferFrames, |
| 192 | 206 | streamStats->_framesAvailableAverage, |
| 193 | − (int)(_stats->getAudioInputMsecsReadStats().getWindowAverage() / AudioConstants::NETWORK_FRAME_MSECS), | |
| 207 | + (int)((float)_stats->getAudioInputMsecsReadStats().getWindowAverage() / AudioConstants::NETWORK_FRAME_MSECS), | |
| 194 | 208 | streamStats->_framesAvailable, |
| 195 | 209 | (int)(_stats->getAudioOutputMsecsUnplayedStats().getCurrentIntervalLastSample() |
| 196 | 210 | / AudioConstants::NETWORK_FRAME_MSECS)); |
| @@ -200,10 +214,10 @@ void AudioIOStatsRenderer::renderAudioStreamStats(const AudioStreamStats* stream · 3 unmodified lines | ||
| 200 | 214 | streamStats->_framesAvailableAverage, |
| 201 | 215 | streamStats->_framesAvailable); |
| 202 | 216 | } |
| 203 | − | |
| 217 | + | |
| 204 | 218 | verticalOffset += STATS_HEIGHT_PER_LINE; |
| 205 | 219 | drawText(horizontalOffset, verticalOffset, scale, rotation, font, stringBuffer, color); |
| 206 | − | |
| 220 | + | |
| 207 | 221 | sprintf(stringBuffer, " Ringbuffer stats | starves: %u, prev_starve_lasted: %u, frames_dropped: %u, overflows: %u", |
| 208 | 222 | streamStats->_starveCount, |
| 209 | 223 | streamStats->_consecutiveNotMixedCount, |
| @@ -211,18 +225,18 @@ void AudioIOStatsRenderer::renderAudioStreamStats(const AudioStreamStats* stream · 1 unmodified line | ||
| 211 | 225 | streamStats->_overflowCount); |
| 212 | 226 | verticalOffset += STATS_HEIGHT_PER_LINE; |
| 213 | 227 | drawText(horizontalOffset, verticalOffset, scale, rotation, font, stringBuffer, color); |
| 214 | − | |
| 228 | + | |
| 215 | 229 | sprintf(stringBuffer, " Inter-packet timegaps (overall) | min: %9s, max: %9s, avg: %9s", |
| 216 | 230 | formatUsecTime(streamStats->_timeGapMin).toLatin1().data(), |
| 217 | 231 | formatUsecTime(streamStats->_timeGapMax).toLatin1().data(), |
| 218 | 232 | formatUsecTime(streamStats->_timeGapAverage).toLatin1().data()); |
| 219 | 233 | verticalOffset += STATS_HEIGHT_PER_LINE; |
| 220 | 234 | drawText(horizontalOffset, verticalOffset, scale, rotation, font, stringBuffer, color); |
| 221 | − | |
| 235 | + | |
| 222 | 236 | sprintf(stringBuffer, " Inter-packet timegaps (last 30s) | min: %9s, max: %9s, avg: %9s", |
| 223 | 237 | formatUsecTime(streamStats->_timeGapWindowMin).toLatin1().data(), |
| 224 | 238 | formatUsecTime(streamStats->_timeGapWindowMax).toLatin1().data(), |
| 225 | 239 | formatUsecTime(streamStats->_timeGapWindowAverage).toLatin1().data()); |
| 226 | 240 | verticalOffset += STATS_HEIGHT_PER_LINE; |
| 227 | 241 | drawText(horizontalOffset, verticalOffset, scale, rotation, font, stringBuffer, color); |
| 228 | −} | |
| 242 | +} | |
| @@ -1,114 +0,0 @@ | ||
| 1 | −// | |
| 2 | −// AudioToolBox.cpp | |
| 3 | −// interface/src/audio | |
| 4 | −// | |
| 5 | −// Created by Stephen Birarda on 2014-12-16. | |
| 6 | −// Copyright 2014 High Fidelity, Inc. | |
| 7 | −// | |
| 8 | −// Distributed under the Apache License, Version 2.0. | |
| 9 | −// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html | |
| 10 | −// | |
| 11 | − | |
| 12 | −#include "InterfaceConfig.h" | |
| 13 | − | |
| 14 | −#include <AudioClient.h> | |
| 15 | −#include <GLCanvas.h> | |
| 16 | −#include <PathUtils.h> | |
| 17 | −#include <GeometryCache.h> | |
| 18 | −#include <gpu/GLBackend.h> | |
| 19 | − | |
| 20 | −#include "Application.h" | |
| 21 | −#include "AudioToolBox.h" | |
| 22 | − | |
| 23 | −// Mute icon configration | |
| 24 | −const int MUTE_ICON_SIZE = 24; | |
| 25 | − | |
| 26 | −AudioToolBox::AudioToolBox() : | |
| 27 | − _iconPulseTimeReference(usecTimestampNow()) | |
| 28 | −{ | |
| 29 | −} | |
| 30 | − | |
| 31 | −bool AudioToolBox::mousePressEvent(int x, int y) { | |
| 32 | − if (_iconBounds.contains(x, y)) { | |
| 33 | − DependencyManager::get<AudioClient>()->toggleMute(); | |
| 34 | − return true; | |
| 35 | − } | |
| 36 | − return false; | |
| 37 | −} | |
| 38 | − | |
| 39 | −void AudioToolBox::render(int x, int y, int padding, bool boxed) { | |
| 40 | − glEnable(GL_TEXTURE_2D); | |
| 41 | − | |
| 42 | − if (!_micTexture) { | |
| 43 | − _micTexture = TextureCache::getImageTexture(PathUtils::resourcesPath() + "images/mic.svg"); | |
| 44 | − } | |
| 45 | − if (!_muteTexture) { | |
| 46 | − _muteTexture = TextureCache::getImageTexture(PathUtils::resourcesPath() + "images/mic-mute.svg"); | |
| 47 | − } | |
| 48 | − if (_boxTexture) { | |
| 49 | − _boxTexture = TextureCache::getImageTexture(PathUtils::resourcesPath() + "images/audio-box.svg"); | |
| 50 | − } | |
| 51 | − | |
| 52 | − auto audioIO = DependencyManager::get<AudioClient>(); | |
| 53 | − | |
| 54 | − if (boxed) { | |
| 55 | − bool isClipping = ((audioIO->getTimeSinceLastClip() > 0.0f) && (audioIO->getTimeSinceLastClip() < 1.0f)); | |
| 56 | − const int BOX_LEFT_PADDING = 5; | |
| 57 | − const int BOX_TOP_PADDING = 10; | |
| 58 | − const int BOX_WIDTH = 266; | |
| 59 | − const int BOX_HEIGHT = 44; | |
| 60 | − | |
| 61 | − QRect boxBounds = QRect(x - BOX_LEFT_PADDING, y - BOX_TOP_PADDING, BOX_WIDTH, BOX_HEIGHT); | |
| 62 | − glm::vec4 quadColor; | |
| 63 | − | |
| 64 | − if (isClipping) { | |
| 65 | − quadColor = glm::vec4(1.0f, 0.0f, 0.0f, 1.0f); | |
| 66 | − } else { | |
| 67 | − quadColor = glm::vec4(0.41f, 0.41f, 0.41f, 1.0f); | |
| 68 | − } | |
| 69 | − glm::vec2 topLeft(boxBounds.left(), boxBounds.top()); | |
| 70 | − glm::vec2 bottomRight(boxBounds.right(), boxBounds.bottom()); | |
| 71 | − static const glm::vec2 texCoordTopLeft(1,1); | |
| 72 | − static const glm::vec2 texCoordBottomRight(0, 0); | |
| 73 | − glBindTexture(GL_TEXTURE_2D, gpu::GLBackend::getTextureID(_boxTexture)); | |
| 74 | − DependencyManager::get<GeometryCache>()->renderQuad(topLeft, bottomRight, texCoordTopLeft, texCoordBottomRight, quadColor); | |
| 75 | − } | |
| 76 | − | |
| 77 | − float iconColor = 1.0f; | |
| 78 | − | |
| 79 | − _iconBounds = QRect(x + padding, y, MUTE_ICON_SIZE, MUTE_ICON_SIZE); | |
| 80 | − if (!audioIO->isMuted()) { | |
| 81 | − glBindTexture(GL_TEXTURE_2D, gpu::GLBackend::getTextureID(_micTexture)); | |
| 82 | − iconColor = 1.0f; | |
| 83 | − } else { | |
| 84 | − glBindTexture(GL_TEXTURE_2D, gpu::GLBackend::getTextureID(_muteTexture)); | |
| 85 | − | |
| 86 | − // Make muted icon pulsate | |
| 87 | − static const float PULSE_MIN = 0.4f; | |
| 88 | − static const float PULSE_MAX = 1.0f; | |
| 89 | − static const float PULSE_FREQUENCY = 1.0f; // in Hz | |
| 90 | − qint64 now = usecTimestampNow(); | |
| 91 | − if (now - _iconPulseTimeReference > (qint64)USECS_PER_SECOND) { | |
| 92 | − // Prevents t from getting too big, which would diminish glm::cos precision | |
| 93 | − _iconPulseTimeReference = now - ((now - _iconPulseTimeReference) % USECS_PER_SECOND); | |
| 94 | − } | |
| 95 | − float t = (float)(now - _iconPulseTimeReference) / (float)USECS_PER_SECOND; | |
| 96 | − float pulseFactor = (glm::cos(t * PULSE_FREQUENCY * 2.0f * PI) + 1.0f) / 2.0f; | |
| 97 | − iconColor = PULSE_MIN + (PULSE_MAX - PULSE_MIN) * pulseFactor; | |
| 98 | − } | |
| 99 | − | |
| 100 | − glm::vec4 quadColor(iconColor, iconColor, iconColor, 1.0f); | |
| 101 | − | |
| 102 | − glm::vec2 topLeft(_iconBounds.left(), _iconBounds.top()); | |
| 103 | − glm::vec2 bottomRight(_iconBounds.right(), _iconBounds.bottom()); | |
| 104 | − glm::vec2 texCoordTopLeft(1,1); | |
| 105 | − glm::vec2 texCoordBottomRight(0,0); | |
| 106 | − | |
| 107 | − if (_boxQuadID == GeometryCache::UNKNOWN_ID) { | |
| 108 | − _boxQuadID = DependencyManager::get<GeometryCache>()->allocateID(); | |
| 109 | − } | |
| 110 | − | |
| 111 | − DependencyManager::get<GeometryCache>()->renderQuad(topLeft, bottomRight, texCoordTopLeft, texCoordBottomRight, quadColor, _boxQuadID); | |
| 112 | − glBindTexture(GL_TEXTURE_2D, 0); | |
| 113 | − glDisable(GL_TEXTURE_2D); | |
| 114 | −} | |
| @@ -1,36 +0,0 @@ | ||
| 1 | −// | |
| 2 | −// AudioToolBox.h | |
| 3 | −// interface/src/audio | |
| 4 | −// | |
| 5 | −// Created by Stephen Birarda on 2014-12-16. | |
| 6 | −// Copyright 2014 High Fidelity, Inc. | |
| 7 | −// | |
| 8 | −// Distributed under the Apache License, Version 2.0. | |
| 9 | −// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html | |
| 10 | −// | |
| 11 | − | |
| 12 | −#ifndef hifi_AudioToolBox_h | |
| 13 | −#define hifi_AudioToolBox_h | |
| 14 | − | |
| 15 | −#include <DependencyManager.h> | |
| 16 | −#include <GeometryCache.h> | |
| 17 | −#include <QOpenGLTexture> | |
| 18 | − | |
| 19 | −class AudioToolBox : public Dependency { | |
| 20 | − SINGLETON_DEPENDENCY | |
| 21 | −public: | |
| 22 | − void render(int x, int y, int padding, bool boxed); | |
| 23 | − | |
| 24 | − bool mousePressEvent(int x, int y); | |
| 25 | −protected: | |
| 26 | − AudioToolBox(); | |
| 27 | −private: | |
| 28 | − gpu::TexturePointer _micTexture; | |
| 29 | − gpu::TexturePointer _muteTexture; | |
| 30 | − gpu::TexturePointer _boxTexture; | |
| 31 | − int _boxQuadID = GeometryCache::UNKNOWN_ID; | |
| 32 | − QRect _iconBounds; | |
| 33 | − qint64 _iconPulseTimeReference = 0; | |
| 34 | −}; | |
| 35 | − | |
| 36 | −#endif // hifi_AudioToolBox_h | |
| @@ -57,7 +57,7 @@ const float CHAT_MESSAGE_SCALE = 0.0015f; · 56 unmodified lines | ||
| 57 | 57 | const float CHAT_MESSAGE_HEIGHT = 0.1f; |
| 58 | 58 | const float DISPLAYNAME_FADE_TIME = 0.5f; |
| 59 | 59 | const float DISPLAYNAME_FADE_FACTOR = pow(0.01f, 1.0f / DISPLAYNAME_FADE_TIME); |
| 60 | −const float DISPLAYNAME_ALPHA = 0.95f; | |
| 60 | +const float DISPLAYNAME_ALPHA = 1.0f; | |
| 61 | 61 | const float DISPLAYNAME_BACKGROUND_ALPHA = 0.4f; |
| 62 | 62 | |
| 63 | 63 | namespace render { |
| @@ -107,6 +107,7 @@ Avatar::Avatar() : · 43 unmodified lines | ||
| 107 | 107 | } |
| 108 | 108 | |
| 109 | 109 | Avatar::~Avatar() { |
| 110 | + assert(_motionState == nullptr); | |
| 110 | 111 | for(auto attachment : _unusedAttachments) { |
| 111 | 112 | delete attachment; |
| 112 | 113 | } |
| @@ -280,9 +281,9 @@ enum TextRendererType { · 167 unmodified lines | ||
| 280 | 281 | }; |
| 281 | 282 | |
| 282 | 283 | static TextRenderer3D* textRenderer(TextRendererType type) { |
| 283 | − static TextRenderer3D* chatRenderer = TextRenderer3D::getInstance(SANS_FONT_FAMILY, 24, -1, | |
| 284 | + static TextRenderer3D* chatRenderer = TextRenderer3D::getInstance(SANS_FONT_FAMILY, -1, | |
| 284 | 285 | false, TextRenderer3D::SHADOW_EFFECT); |
| 285 | − static TextRenderer3D* displayNameRenderer = TextRenderer3D::getInstance(SANS_FONT_FAMILY, 12); | |
| 286 | + static TextRenderer3D* displayNameRenderer = TextRenderer3D::getInstance(SANS_FONT_FAMILY); | |
| 286 | 287 | |
| 287 | 288 | switch(type) { |
| 288 | 289 | case CHAT: |
| @@ -323,7 +324,7 @@ void Avatar::render(RenderArgs* renderArgs, const glm::vec3& cameraPosition, boo · 34 unmodified lines | ||
| 323 | 324 | _referential->update(); |
| 324 | 325 | } |
| 325 | 326 | |
| 326 | − auto batch = renderArgs->_batch; | |
| 327 | + auto& batch = *renderArgs->_batch; | |
| 327 | 328 | |
| 328 | 329 | if (postLighting && |
| 329 | 330 | glm::distance(DependencyManager::get<AvatarManager>()->getMyAvatar()->getPosition(), _position) < 10.0f) { |
| @@ -354,9 +355,9 @@ void Avatar::render(RenderArgs* renderArgs, const glm::vec3& cameraPosition, boo · 24 unmodified lines | ||
| 354 | 355 | Transform pointerTransform; |
| 355 | 356 | pointerTransform.setTranslation(position); |
| 356 | 357 | pointerTransform.setRotation(rotation); |
| 357 | − batch->setModelTransform(pointerTransform); | |
| 358 | − deferredLighting->bindSimpleProgram(*batch); | |
| 359 | − geometryCache->renderLine(*batch, glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(0.0f, laserLength, 0.0f), laserColor); | |
| 358 | + batch.setModelTransform(pointerTransform); | |
| 359 | + deferredLighting->bindSimpleProgram(batch); | |
| 360 | + geometryCache->renderLine(batch, glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(0.0f, laserLength, 0.0f), laserColor); | |
| 360 | 361 | } |
| 361 | 362 | } |
| 362 | 363 | |
| @@ -377,9 +378,9 @@ void Avatar::render(RenderArgs* renderArgs, const glm::vec3& cameraPosition, boo · 14 unmodified lines | ||
| 377 | 378 | Transform pointerTransform; |
| 378 | 379 | pointerTransform.setTranslation(position); |
| 379 | 380 | pointerTransform.setRotation(rotation); |
| 380 | − batch->setModelTransform(pointerTransform); | |
| 381 | − deferredLighting->bindSimpleProgram(*batch); | |
| 382 | − geometryCache->renderLine(*batch, glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(0.0f, laserLength, 0.0f), laserColor); | |
| 381 | + batch.setModelTransform(pointerTransform); | |
| 382 | + deferredLighting->bindSimpleProgram(batch); | |
| 383 | + geometryCache->renderLine(batch, glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(0.0f, laserLength, 0.0f), laserColor); | |
| 383 | 384 | } |
| 384 | 385 | } |
| 385 | 386 | } |
| @@ -464,8 +465,8 @@ void Avatar::render(RenderArgs* renderArgs, const glm::vec3& cameraPosition, boo · 78 unmodified lines | ||
| 464 | 465 | } |
| 465 | 466 | Transform transform; |
| 466 | 467 | transform.setTranslation(position); |
| 467 | − batch->setModelTransform(transform); | |
| 468 | − DependencyManager::get<DeferredLightingEffect>()->renderSolidSphere(*batch, LOOK_AT_INDICATOR_RADIUS | |
| 468 | + batch.setModelTransform(transform); | |
| 469 | + DependencyManager::get<DeferredLightingEffect>()->renderSolidSphere(batch, LOOK_AT_INDICATOR_RADIUS | |
| 469 | 470 | , 15, 15, LOOK_AT_INDICATOR_COLOR); |
| 470 | 471 | } |
| 471 | 472 | } |
| @@ -492,14 +493,14 @@ void Avatar::render(RenderArgs* renderArgs, const glm::vec3& cameraPosition, boo · 20 unmodified lines | ||
| 492 | 493 | Transform transform; |
| 493 | 494 | transform.setTranslation(_position); |
| 494 | 495 | transform.setScale(height); |
| 495 | − batch->setModelTransform(transform); | |
| 496 | + batch.setModelTransform(transform); | |
| 496 | 497 | |
| 497 | 498 | if (_voiceSphereID == GeometryCache::UNKNOWN_ID) { |
| 498 | 499 | _voiceSphereID = DependencyManager::get<GeometryCache>()->allocateID(); |
| 499 | 500 | } |
| 500 | 501 | |
| 501 | − DependencyManager::get<DeferredLightingEffect>()->bindSimpleProgram(*batch); | |
| 502 | − DependencyManager::get<GeometryCache>()->renderSphere(*batch, sphereRadius, 15, 15, | |
| 502 | + DependencyManager::get<DeferredLightingEffect>()->bindSimpleProgram(batch); | |
| 503 | + DependencyManager::get<GeometryCache>()->renderSphere(batch, sphereRadius, 15, 15, | |
| 503 | 504 | glm::vec4(SPHERE_COLOR[0], SPHERE_COLOR[1], SPHERE_COLOR[2], 1.0f - angle / MAX_SPHERE_ANGLE), true, |
| 504 | 505 | _voiceSphereID); |
| 505 | 506 | } |
| @@ -507,14 +508,12 @@ void Avatar::render(RenderArgs* renderArgs, const glm::vec3& cameraPosition, boo · 1 unmodified line | ||
| 507 | 508 | } |
| 508 | 509 | |
| 509 | 510 | const float DISPLAYNAME_DISTANCE = 20.0f; |
| 510 | − setShowDisplayName(renderArgs->_renderMode == RenderArgs::NORMAL_RENDER_MODE && distanceToTarget < DISPLAYNAME_DISTANCE); | |
| 511 | + setShowDisplayName(distanceToTarget < DISPLAYNAME_DISTANCE); | |
| 511 | 512 | |
| 512 | − if (renderArgs->_renderMode != RenderArgs::NORMAL_RENDER_MODE || (isMyAvatar() && | |
| 513 | − Application::getInstance()->getCamera()->getMode() == CAMERA_MODE_FIRST_PERSON)) { | |
| 514 | − return; | |
| 513 | + auto cameraMode = Application::getInstance()->getCamera()->getMode(); | |
| 514 | + if (!isMyAvatar() || cameraMode != CAMERA_MODE_FIRST_PERSON) { | |
| 515 | + renderDisplayName(batch, *renderArgs->_viewFrustum); | |
| 515 | 516 | } |
| 516 | − | |
| 517 | − renderDisplayName(renderArgs); | |
| 518 | 517 | } |
| 519 | 518 | |
| 520 | 519 | glm::quat Avatar::computeRotationFromBodyToWorldUp(float proportion) const { |
| @@ -654,8 +653,8 @@ float Avatar::getBillboardSize() const { · 133 unmodified lines | ||
| 654 | 653 | return _scale * BILLBOARD_DISTANCE * tanf(glm::radians(BILLBOARD_FIELD_OF_VIEW / 2.0f)); |
| 655 | 654 | } |
| 656 | 655 | |
| 657 | −glm::vec3 Avatar::getDisplayNamePosition() { | |
| 658 | − glm::vec3 namePosition; | |
| 656 | +glm::vec3 Avatar::getDisplayNamePosition() const { | |
| 657 | + glm::vec3 namePosition(0.0f); | |
| 659 | 658 | if (getSkeletonModel().getNeckPosition(namePosition)) { |
| 660 | 659 | namePosition += getBodyUpDirection() * getHeadHeight() * 1.1f; |
| 661 | 660 | } else { |
| @@ -665,81 +664,73 @@ glm::vec3 Avatar::getDisplayNamePosition() { · 3 unmodified lines | ||
| 665 | 664 | return namePosition; |
| 666 | 665 | } |
| 667 | 666 | |
| 668 | −float Avatar::calculateDisplayNameScaleFactor(const glm::vec3& textPosition, bool inHMD) { | |
| 669 | − | |
| 670 | − // We need to compute the scale factor such as the text remains with fixed size respect to window coordinates | |
| 671 | − // We project a unit vector and check the difference in screen coordinates, to check which is the | |
| 672 | − // correction scale needed | |
| 673 | − // save the matrices for later scale correction factor | |
| 674 | − // The up vector must be relative to the rotation current rotation matrix: | |
| 675 | − // we set the identity | |
| 667 | +Transform Avatar::calculateDisplayNameTransform(const ViewFrustum& frustum, float fontSize) const { | |
| 668 | + Transform result; | |
| 669 | + // We assume textPosition is whithin the frustum | |
| 670 | + glm::vec3 textPosition = getDisplayNamePosition(); | |
| 671 | + | |
| 672 | + // Compute viewProjection matrix | |
| 673 | + glm::mat4 projMat, viewMat; | |
| 674 | + Transform view; | |
| 675 | + frustum.evalProjectionMatrix(projMat); | |
| 676 | + frustum.evalViewTransform(view); | |
| 677 | + glm::mat4 viewProj = projMat * view.getInverseMatrix(viewMat); | |
| 678 | + | |
| 679 | + // Used to determine correct scale | |
| 676 | 680 | glm::vec3 testPoint0 = textPosition; |
| 677 | − glm::vec3 testPoint1 = textPosition + (Application::getInstance()->getCamera()->getRotation() * IDENTITY_UP); | |
| 678 | − | |
| 679 | − double textWindowHeight; | |
| 680 | − | |
| 681 | + glm::vec3 testPoint1 = testPoint0 + glm::normalize(frustum.getUp()); | |
| 682 | + // testPoints projections | |
| 683 | + glm::vec4 p0 = viewProj * glm::vec4(testPoint0, 1.0); | |
| 684 | + glm::vec4 p1 = viewProj * glm::vec4(testPoint1, 1.0); | |
| 685 | + | |
| 686 | + // TODO REMOVE vvv | |
| 681 | 687 | GLint viewportMatrix[4]; |
| 682 | 688 | glGetIntegerv(GL_VIEWPORT, viewportMatrix); |
| 683 | 689 | glm::dmat4 modelViewMatrix; |
| 684 | − float windowSizeX = viewportMatrix[2] - viewportMatrix[0]; | |
| 685 | 690 | float windowSizeY = viewportMatrix[3] - viewportMatrix[1]; |
| 691 | + // TODO REMOVE ^^^ | |
| 692 | + | |
| 693 | + const float DESIRED_HIGHT_ON_SCREEN = 20; // In pixels (this is double on retinas) | |
| 694 | + | |
| 695 | + // Projected point are between -1.0f and 1.0f, hence 0.5f * windowSizeY | |
| 696 | + double pixelHeight = 0.5f * windowSizeY * glm::abs((p1.y / p1.w) - (p0.y / p0.w)); // | |
| 697 | + // Handles pixel density (especially for macs retina displays) | |
| 698 | + double devicePixelRatio = qApp->getDevicePixelRatio() * qApp->getRenderResolutionScale(); // pixels / unit | |
| 699 | + | |
| 700 | + // Compute correct scale to apply | |
| 701 | + float scale = DESIRED_HIGHT_ON_SCREEN / (fontSize * pixelHeight) * devicePixelRatio; | |
| 702 | + | |
| 703 | + // Compute pixel alignment offset | |
| 704 | + float clipToPix = 0.5f * windowSizeY / p1.w; // Got from clip to pixel coordinates | |
| 705 | + glm::vec4 screenPos = clipToPix * p1; // in pixels coords | |
| 706 | + glm::vec4 screenOffset = (glm::round(screenPos) - screenPos) / clipToPix; // in clip coords | |
| 707 | + glm::vec3 worldOffset = glm::vec3(screenOffset.x, screenOffset.y, 0.0f) / (float)pixelHeight; | |
| 708 | + | |
| 709 | + // Compute orientation | |
| 710 | + glm::vec3 eulerAngles = ::safeEulerAngles(frustum.getOrientation()); | |
| 711 | + eulerAngles.z = 0.0f; // Cancel roll | |
| 712 | + glm::quat orientation(eulerAngles); // back to quaternions | |
| 713 | + | |
| 714 | + // Set transform (The order IS important) | |
| 715 | + result.setTranslation(textPosition); | |
| 716 | + result.setRotation(orientation); // Always face the screen | |
| 717 | + result.postTranslate(worldOffset); // Pixel alignment | |
| 718 | + result.setScale(scale); | |
| 719 | + return result; | |
| 686 | 720 | |
| 687 | − glm::dmat4 projectionMatrix; | |
| 688 | − Application::getInstance()->getModelViewMatrix(&modelViewMatrix); | |
| 689 | − Application::getInstance()->getProjectionMatrix(&projectionMatrix); | |
| 690 | − | |
| 691 | − | |
| 692 | − glm::dvec4 p0 = modelViewMatrix * glm::dvec4(testPoint0, 1.0); | |
| 693 | − p0 = projectionMatrix * p0; | |
| 694 | − glm::dvec2 result0 = glm::vec2(windowSizeX * (p0.x / p0.w + 1.0f) * 0.5f, windowSizeY * (p0.y / p0.w + 1.0f) * 0.5f); | |
| 695 | − | |
| 696 | − glm::dvec4 p1 = modelViewMatrix * glm::dvec4(testPoint1, 1.0); | |
| 697 | − p1 = projectionMatrix * p1; | |
| 698 | − glm::vec2 result1 = glm::vec2(windowSizeX * (p1.x / p1.w + 1.0f) * 0.5f, windowSizeY * (p1.y / p1.w + 1.0f) * 0.5f); | |
| 699 | − textWindowHeight = abs(result1.y - result0.y); | |
| 700 | − | |
| 701 | − // need to scale to compensate for the font resolution due to the device | |
| 702 | − float scaleFactor = QApplication::desktop()->windowHandle()->devicePixelRatio() * | |
| 703 | − ((textWindowHeight > EPSILON) ? 1.0f / textWindowHeight : 1.0f); | |
| 704 | − if (inHMD) { | |
| 705 | − const float HMDMODE_NAME_SCALE = 0.65f; | |
| 706 | − scaleFactor *= HMDMODE_NAME_SCALE; | |
| 707 | − } else { | |
| 708 | − scaleFactor *= Application::getInstance()->getRenderResolutionScale(); | |
| 709 | − } | |
| 710 | − return scaleFactor; | |
| 711 | 721 | } |
| 712 | 722 | |
| 713 | −void Avatar::renderDisplayName(RenderArgs* renderArgs) { | |
| 714 | − auto batch = renderArgs->_batch; | |
| 715 | − | |
| 723 | +void Avatar::renderDisplayName(gpu::Batch& batch, const ViewFrustum& frustum) const { | |
| 716 | 724 | bool shouldShowReceiveStats = DependencyManager::get<AvatarManager>()->shouldShowReceiveStats() && !isMyAvatar(); |
| 717 | 725 | |
| 726 | + // If we have nothing to draw, or it's tottaly transparent, return | |
| 718 | 727 | if ((_displayName.isEmpty() && !shouldShowReceiveStats) || _displayNameAlpha == 0.0f) { |
| 719 | 728 | return; |
| 720 | 729 | } |
| 721 | − | |
| 722 | − // which viewing mode? | |
| 723 | − bool inHMD = Application::getInstance()->isHMDMode(); | |
| 724 | − | |
| 725 | − glm::vec3 textPosition = getDisplayNamePosition(); | |
| 726 | − | |
| 727 | − // we need "always facing camera": we must remove the camera rotation from the stac | |
| 728 | − glm::quat rotation = Application::getInstance()->getCamera()->getRotation(); | |
| 729 | − | |
| 730 | − // TODO: Fix scaling - at some point this or the text rendering changed in scale. | |
| 731 | − float scaleFactor = calculateDisplayNameScaleFactor(textPosition, inHMD); | |
| 732 | − scaleFactor /= 3.5f; | |
| 733 | − | |
| 734 | − Transform textTransform; | |
| 735 | − textTransform.setTranslation(textPosition); | |
| 736 | − textTransform.setRotation(rotation); | |
| 737 | − textTransform.setScale(scaleFactor); | |
| 730 | + auto renderer = textRenderer(DISPLAYNAME); | |
| 738 | 731 | |
| 739 | 732 | // optionally render timing stats for this avatar with the display name |
| 740 | 733 | QString renderedDisplayName = _displayName; |
| 741 | − QRect nameDynamicRect = _displayNameBoundingRect; | |
| 742 | − | |
| 743 | 734 | if (shouldShowReceiveStats) { |
| 744 | 735 | float kilobitsPerSecond = getAverageBytesReceivedPerSecond() / (float) BYTES_PER_KILOBIT; |
| 745 | 736 | |
| @@ -747,42 +738,43 @@ void Avatar::renderDisplayName(RenderArgs* renderArgs) { · 1 unmodified line | ||
| 747 | 738 | if (!renderedDisplayName.isEmpty()) { |
| 748 | 739 | statsFormat.prepend(" - "); |
| 749 | 740 | } |
| 750 | − | |
| 751 | − QString statsText = statsFormat.arg(QString::number(kilobitsPerSecond, 'f', 2)).arg(getReceiveRate()); | |
| 752 | − renderedDisplayName += statsText; | |
| 753 | − | |
| 754 | − glm::vec2 extent = textRenderer(DISPLAYNAME)->computeExtent(renderedDisplayName); | |
| 755 | − nameDynamicRect = QRect(0, 0, (int)extent.x, (int)extent.y); | |
| 741 | + renderedDisplayName += statsFormat.arg(QString::number(kilobitsPerSecond, 'f', 2)).arg(getReceiveRate()); | |
| 756 | 742 | } |
| 757 | − | |
| 758 | − int text_x = -nameDynamicRect.width() / 2; | |
| 759 | − int text_y = -nameDynamicRect.height() / 2; | |
| 760 | − | |
| 761 | − // draw a gray background | |
| 762 | − int left = text_x; | |
| 763 | − int right = left + nameDynamicRect.width(); | |
| 764 | − int bottom = text_y; | |
| 765 | − int top = bottom + nameDynamicRect.height(); | |
| 766 | − const int border = 8; | |
| 767 | − bottom -= border; | |
| 768 | − left -= border; | |
| 769 | − top += border; | |
| 770 | − right += border; | |
| 771 | 743 | |
| 744 | + // Compute display name extent/position offset | |
| 745 | + glm::vec2 extent = renderer->computeExtent(renderedDisplayName); | |
| 746 | + QRect nameDynamicRect = QRect(0, 0, (int)extent.x, (int)extent.y); | |
| 747 | + const int text_x = -nameDynamicRect.width() / 2; | |
| 748 | + const int text_y = -nameDynamicRect.height() / 2; | |
| 749 | + | |
| 750 | + // Compute background position/size | |
| 751 | + static const float SLIGHTLY_BEHIND = -0.05f; | |
| 752 | + const int border = 0.1f * nameDynamicRect.height(); | |
| 753 | + const int left = text_x - border; | |
| 754 | + const int bottom = text_y - border; | |
| 755 | + const int width = nameDynamicRect.width() + 2.0f * border; | |
| 756 | + const int height = nameDynamicRect.height() + 2.0f * border; | |
| 757 | + const int bevelDistance = 0.1f * height; | |
| 758 | + | |
| 759 | + // Display name and background colors | |
| 772 | 760 | glm::vec4 textColor(0.93f, 0.93f, 0.93f, _displayNameAlpha); |
| 773 | 761 | glm::vec4 backgroundColor(0.2f, 0.2f, 0.2f, |
| 774 | − _displayNameAlpha * DISPLAYNAME_BACKGROUND_ALPHA / DISPLAYNAME_ALPHA); | |
| 762 | + (_displayNameAlpha / DISPLAYNAME_ALPHA) * DISPLAYNAME_BACKGROUND_ALPHA); | |
| 763 | + | |
| 764 | + // Compute display name transform | |
| 765 | + auto textTransform = calculateDisplayNameTransform(frustum, renderer->getFontSize()); | |
| 775 | 766 | |
| 767 | + // Render background slightly behind to avoid z-fighting | |
| 776 | 768 | auto backgroundTransform = textTransform; |
| 777 | − backgroundTransform.postTranslate(glm::vec3(0.0f, 0.0f, -0.001f)); | |
| 778 | − batch->setModelTransform(backgroundTransform); | |
| 779 | − DependencyManager::get<DeferredLightingEffect>()->bindSimpleProgram(*batch); | |
| 780 | − DependencyManager::get<GeometryCache>()->renderBevelCornersRect(*batch, left, bottom, right - left, top - bottom, 3, | |
| 781 | − backgroundColor); | |
| 769 | + backgroundTransform.postTranslate(glm::vec3(0.0f, 0.0f, SLIGHTLY_BEHIND)); | |
| 770 | + batch.setModelTransform(backgroundTransform); | |
| 771 | + DependencyManager::get<DeferredLightingEffect>()->bindSimpleProgram(batch); | |
| 772 | + DependencyManager::get<GeometryCache>()->renderBevelCornersRect(batch, left, bottom, width, height, | |
| 773 | + bevelDistance, backgroundColor); | |
| 774 | + // Render actual name | |
| 782 | 775 | QByteArray nameUTF8 = renderedDisplayName.toLocal8Bit(); |
| 783 | − | |
| 784 | − batch->setModelTransform(textTransform); | |
| 785 | − textRenderer(DISPLAYNAME)->draw(*batch, text_x, -text_y, nameUTF8.data(), textColor); | |
| 776 | + batch.setModelTransform(textTransform); | |
| 777 | + renderer->draw(batch, text_x, -text_y, nameUTF8.data(), textColor); | |
| 786 | 778 | } |
| 787 | 779 | |
| 788 | 780 | bool Avatar::findRayIntersection(RayIntersectionInfo& intersection) const { |
| @@ -987,13 +979,6 @@ void Avatar::setAttachmentData(const QVector<AttachmentData>& attachmentData) { · 198 unmodified lines | ||
| 987 | 979 | } |
| 988 | 980 | } |
| 989 | 981 | |
| 990 | −void Avatar::setDisplayName(const QString& displayName) { | |
| 991 | − AvatarData::setDisplayName(displayName); | |
| 992 | − // FIXME is this a sufficient replacement for tightBoundingRect? | |
| 993 | − glm::vec2 extent = textRenderer(DISPLAYNAME)->computeExtent(displayName); | |
| 994 | − _displayNameBoundingRect = QRect(0, 0, (int)extent.x, (int)extent.y); | |
| 995 | −} | |
| 996 | − | |
| 997 | 982 | void Avatar::setBillboard(const QByteArray& billboard) { |
| 998 | 983 | AvatarData::setBillboard(billboard); |
| 999 | 984 | |
| @@ -1092,7 +1077,12 @@ float Avatar::getSkeletonHeight() const { · 92 unmodified lines | ||
| 1092 | 1077 | float Avatar::getHeadHeight() const { |
| 1093 | 1078 | Extents extents = getHead()->getFaceModel().getMeshExtents(); |
| 1094 | 1079 | if (!extents.isEmpty() && extents.isValid()) { |
| 1095 | − return extents.maximum.y - extents.minimum.y; | |
| 1080 | + | |
| 1081 | + // HACK: We have a really odd case when fading out for some models where this value explodes | |
| 1082 | + float result = extents.maximum.y - extents.minimum.y; | |
| 1083 | + if (result >= 0.0f && result < 100.0f * _scale ) { | |
| 1084 | + return result; | |
| 1085 | + } | |
| 1096 | 1086 | } |
| 1097 | 1087 | |
| 1098 | 1088 | extents = _skeletonModel.getMeshExtents(); |
| @@ -1116,7 +1106,7 @@ void Avatar::setShowDisplayName(bool showDisplayName) { · 17 unmodified lines | ||
| 1116 | 1106 | } |
| 1117 | 1107 | |
| 1118 | 1108 | // For myAvatar, the alpha update is not done (called in simulate for other avatars) |
| 1119 | − if (DependencyManager::get<AvatarManager>()->getMyAvatar() == this) { | |
| 1109 | + if (isMyAvatar()) { | |
| 1120 | 1110 | if (showDisplayName) { |
| 1121 | 1111 | _displayNameAlpha = DISPLAYNAME_ALPHA; |
| 1122 | 1112 | } else { |
| @@ -1129,7 +1119,6 @@ void Avatar::setShowDisplayName(bool showDisplayName) { · 6 unmodified lines | ||
| 1129 | 1119 | } else { |
| 1130 | 1120 | _displayNameTargetAlpha = 0.0f; |
| 1131 | 1121 | } |
| 1132 | − | |
| 1133 | 1122 | } |
| 1134 | 1123 | |
| 1135 | 1124 | // virtual |
| @@ -98,6 +98,7 @@ public: · 97 unmodified lines | ||
| 98 | 98 | //getters |
| 99 | 99 | bool isInitialized() const { return _initialized; } |
| 100 | 100 | SkeletonModel& getSkeletonModel() { return _skeletonModel; } |
| 101 | + const SkeletonModel& getSkeletonModel() const { return _skeletonModel; } | |
| 101 | 102 | const QVector<Model*>& getAttachmentModels() const { return _attachmentModels; } |
| 102 | 103 | glm::vec3 getChestPosition() const; |
| 103 | 104 | float getScale() const { return _scale; } |
| @@ -131,7 +132,7 @@ public: · 27 unmodified lines | ||
| 131 | 132 | /// \return whether or not the plane penetrated |
| 132 | 133 | bool findPlaneCollisions(const glm::vec4& plane, CollisionList& collisions); |
| 133 | 134 | |
| 134 | − virtual bool isMyAvatar() { return false; } | |
| 135 | + virtual bool isMyAvatar() const { return false; } | |
| 135 | 136 | |
| 136 | 137 | virtual QVector<glm::quat> getJointRotations() const; |
| 137 | 138 | virtual glm::quat getJointRotation(int index) const; |
| @@ -141,7 +142,6 @@ public: · 3 unmodified lines | ||
| 141 | 142 | virtual void setFaceModelURL(const QUrl& faceModelURL); |
| 142 | 143 | virtual void setSkeletonModelURL(const QUrl& skeletonModelURL); |
| 143 | 144 | virtual void setAttachmentData(const QVector<AttachmentData>& attachmentData); |
| 144 | − virtual void setDisplayName(const QString& displayName); | |
| 145 | 145 | virtual void setBillboard(const QByteArray& billboard); |
| 146 | 146 | |
| 147 | 147 | void setShowDisplayName(bool showDisplayName); |
| @@ -232,10 +232,10 @@ protected: · 84 unmodified lines | ||
| 232 | 232 | float getSkeletonHeight() const; |
| 233 | 233 | float getHeadHeight() const; |
| 234 | 234 | float getPelvisFloatingHeight() const; |
| 235 | − glm::vec3 getDisplayNamePosition(); | |
| 235 | + glm::vec3 getDisplayNamePosition() const; | |
| 236 | 236 | |
| 237 | − float calculateDisplayNameScaleFactor(const glm::vec3& textPosition, bool inHMD); | |
| 238 | − void renderDisplayName(RenderArgs* renderArgs); | |
| 237 | + Transform calculateDisplayNameTransform(const ViewFrustum& frustum, float fontSize) const; | |
| 238 | + void renderDisplayName(gpu::Batch& batch, const ViewFrustum& frustum) const; | |
| 239 | 239 | virtual void renderBody(RenderArgs* renderArgs, ViewFrustum* renderFrustum, bool postLighting, float glowLevel = 0.0f); |
| 240 | 240 | virtual bool shouldRenderHead(const RenderArgs* renderArgs, const glm::vec3& cameraPosition) const; |
| 241 | 241 | virtual void fixupModelsInScene(); |
| @@ -29,6 +29,12 @@ AvatarActionHold::~AvatarActionHold() { · 28 unmodified lines | ||
| 29 | 29 | |
| 30 | 30 | void AvatarActionHold::updateActionWorker(float deltaTimeStep) { |
| 31 | 31 | auto myAvatar = DependencyManager::get<AvatarManager>()->getMyAvatar(); |
| 32 | + | |
| 33 | + if (!tryLockForRead()) { | |
| 34 | + // don't risk hanging the thread running the physics simulation | |
| 35 | + return; | |
| 36 | + } | |
| 37 | + | |
| 32 | 38 | glm::vec3 palmPosition; |
| 33 | 39 | if (_hand == "right") { |
| 34 | 40 | palmPosition = myAvatar->getRightPalmPosition(); |
| @@ -40,8 +46,11 @@ void AvatarActionHold::updateActionWorker(float deltaTimeStep) { · 5 unmodified lines | ||
| 40 | 46 | auto offset = rotation * _relativePosition; |
| 41 | 47 | auto position = palmPosition + offset; |
| 42 | 48 | rotation *= _relativeRotation; |
| 49 | + unlock(); | |
| 43 | 50 | |
| 44 | − lockForWrite(); | |
| 51 | + if (!tryLockForWrite()) { | |
| 52 | + return; | |
| 53 | + } | |
| 45 | 54 | _positionalTarget = position; |
| 46 | 55 | _rotationalTarget = rotation; |
| 47 | 56 | unlock(); |
| @@ -13,8 +13,18 @@ · 12 unmodified lines | ||
| 13 | 13 | |
| 14 | 14 | #include <QScriptEngine> |
| 15 | 15 | |
| 16 | +#ifdef __GNUC__ | |
| 17 | +#pragma GCC diagnostic push | |
| 18 | +#pragma GCC diagnostic ignored "-Wdouble-promotion" | |
| 19 | +#endif | |
| 20 | + | |
| 16 | 21 | #include <glm/gtx/string_cast.hpp> |
| 17 | 22 | |
| 23 | +#ifdef __GNUC__ | |
| 24 | +#pragma GCC diagnostic pop | |
| 25 | +#endif | |
| 26 | + | |
| 27 | + | |
| 18 | 28 | #include <GlowEffect.h> |
| 19 | 29 | #include <PerfStat.h> |
| 20 | 30 | #include <RegisteredMetaTypes.h> |
| @@ -104,6 +114,7 @@ void AvatarManager::updateOtherAvatars(float deltaTime) { · 83 unmodified lines | ||
| 104 | 114 | // DO NOT update or fade out uninitialized Avatars |
| 105 | 115 | ++avatarIterator; |
| 106 | 116 | } else if (avatar->shouldDie()) { |
| 117 | + removeAvatarMotionState(avatar); | |
| 107 | 118 | _avatarFades.push_back(avatarIterator.value()); |
| 108 | 119 | avatarIterator = _avatarHash.erase(avatarIterator); |
| 109 | 120 | } else { |
| @@ -153,12 +164,13 @@ AvatarSharedPointer AvatarManager::addAvatar(const QUuid& sessionUUID, const QWe · 43 unmodified lines | ||
| 153 | 164 | } |
| 154 | 165 | |
| 155 | 166 | // protected |
| 156 | −void AvatarManager::removeAvatarMotionState(Avatar* avatar) { | |
| 157 | − AvatarMotionState* motionState= avatar->_motionState; | |
| 167 | +void AvatarManager::removeAvatarMotionState(AvatarSharedPointer avatar) { | |
| 168 | + auto rawPointer = std::static_pointer_cast<Avatar>(avatar); | |
| 169 | + AvatarMotionState* motionState= rawPointer->_motionState; | |
| 158 | 170 | if (motionState) { |
| 159 | 171 | // clean up physics stuff |
| 160 | 172 | motionState->clearObjectBackPointer(); |
| 161 | − avatar->_motionState = nullptr; | |
| 173 | + rawPointer->_motionState = nullptr; | |
| 162 | 174 | _avatarMotionStates.remove(motionState); |
| 163 | 175 | _motionStatesToAdd.remove(motionState); |
| 164 | 176 | _motionStatesToDelete.push_back(motionState); |
| @@ -171,7 +183,7 @@ void AvatarManager::removeAvatar(const QUuid& sessionUUID) { · 6 unmodified lines | ||
| 171 | 183 | if (avatarIterator != _avatarHash.end()) { |
| 172 | 184 | std::shared_ptr<Avatar> avatar = std::dynamic_pointer_cast<Avatar>(avatarIterator.value()); |
| 173 | 185 | if (avatar != _myAvatar && avatar->isInitialized()) { |
| 174 | − removeAvatarMotionState(avatar.get()); | |
| 186 | + removeAvatarMotionState(avatar); | |
| 175 | 187 | _avatarFades.push_back(avatarIterator.value()); |
| 176 | 188 | _avatarHash.erase(avatarIterator); |
| 177 | 189 | } |
| @@ -187,7 +199,7 @@ void AvatarManager::clearOtherAvatars() { · 9 unmodified lines | ||
| 187 | 199 | // don't remove myAvatar or uninitialized avatars from the list |
| 188 | 200 | ++avatarIterator; |
| 189 | 201 | } else { |
| 190 | − removeAvatarMotionState(avatar.get()); | |
| 202 | + removeAvatarMotionState(avatar); | |
| 191 | 203 | _avatarFades.push_back(avatarIterator.value()); |
| 192 | 204 | avatarIterator = _avatarHash.erase(avatarIterator); |
| 193 | 205 | } |
| @@ -73,7 +73,7 @@ private: · 72 unmodified lines | ||
| 73 | 73 | // virtual overrides |
| 74 | 74 | virtual AvatarSharedPointer newSharedAvatar(); |
| 75 | 75 | virtual AvatarSharedPointer addAvatar(const QUuid& sessionUUID, const QWeakPointer<Node>& mixerWeakPointer); |
| 76 | − void removeAvatarMotionState(Avatar* avatar); | |
| 76 | + void removeAvatarMotionState(AvatarSharedPointer avatar); | |
| 77 | 77 | virtual void removeAvatar(const QUuid& sessionUUID); |
| 78 | 78 | |
| 79 | 79 | QVector<AvatarSharedPointer> _avatarFades; |
| @@ -77,7 +77,7 @@ void Head::simulate(float deltaTime, bool isMine, bool billboard) { · 76 unmodified lines | ||
| 77 | 77 | const float AUDIO_LONG_TERM_AVERAGING_SECS = 30.0f; |
| 78 | 78 | _averageLoudness = glm::mix(_averageLoudness, _audioLoudness, glm::min(deltaTime / AUDIO_AVERAGING_SECS, 1.0f)); |
| 79 | 79 | |
| 80 | − if (_longTermAverageLoudness == -1.0) { | |
| 80 | + if (_longTermAverageLoudness == -1.0f) { | |
| 81 | 81 | _longTermAverageLoudness = _averageLoudness; |
| 82 | 82 | } else { |
| 83 | 83 | _longTermAverageLoudness = glm::mix(_longTermAverageLoudness, _averageLoudness, glm::min(deltaTime / AUDIO_LONG_TERM_AVERAGING_SECS, 1.0f)); |
| @@ -124,18 +124,25 @@ void Head::simulate(float deltaTime, bool isMine, bool billboard) { · 40 unmodified lines | ||
| 124 | 124 | |
| 125 | 125 | if (!(_isFaceTrackerConnected || billboard)) { |
| 126 | 126 | // Update eye saccades |
| 127 | − const float AVERAGE_MICROSACCADE_INTERVAL = 0.50f; | |
| 128 | − const float AVERAGE_SACCADE_INTERVAL = 4.0f; | |
| 127 | + const float AVERAGE_MICROSACCADE_INTERVAL = 1.0f; | |
| 128 | + const float AVERAGE_SACCADE_INTERVAL = 6.0f; | |
| 129 | 129 | const float MICROSACCADE_MAGNITUDE = 0.002f; |
| 130 | 130 | const float SACCADE_MAGNITUDE = 0.04f; |
| 131 | − | |
| 131 | + const float MAXIMUM_SACCADE_SPEED = 0.8f; | |
| 132 | + | |
| 132 | 133 | if (randFloat() < deltaTime / AVERAGE_MICROSACCADE_INTERVAL) { |
| 133 | 134 | _saccadeTarget = MICROSACCADE_MAGNITUDE * randVector(); |
| 134 | 135 | } else if (randFloat() < deltaTime / AVERAGE_SACCADE_INTERVAL) { |
| 135 | 136 | _saccadeTarget = SACCADE_MAGNITUDE * randVector(); |
| 136 | 137 | } |
| 137 | − _saccade += (_saccadeTarget - _saccade) * 0.50f; | |
| 138 | − | |
| 138 | + | |
| 139 | + glm::vec3 saccadeDelta = (_saccadeTarget - _saccade) * 0.5f; | |
| 140 | + float speed = glm::length(saccadeDelta) / deltaTime; | |
| 141 | + if (speed > MAXIMUM_SACCADE_SPEED) { | |
| 142 | + saccadeDelta = saccadeDelta * MAXIMUM_SACCADE_SPEED / speed; | |
| 143 | + } | |
| 144 | + _saccade += saccadeDelta; | |
| 145 | + | |
| 139 | 146 | // Detect transition from talking to not; force blink after that and a delay |
| 140 | 147 | bool forceBlink = false; |
| 141 | 148 | const float TALKING_LOUDNESS = 100.0f; |
| @@ -59,10 +59,10 @@ const float MAX_WALKING_SPEED = 2.5f; // human walking speed · 58 unmodified lines | ||
| 59 | 59 | const float MAX_BOOST_SPEED = 0.5f * MAX_WALKING_SPEED; // keyboard motor gets additive boost below this speed |
| 60 | 60 | const float MIN_AVATAR_SPEED = 0.05f; // speed is set to zero below this |
| 61 | 61 | |
| 62 | −// TODO: normalize avatar speed for standard avatar size, then scale all motion logic | |
| 62 | +// TODO: normalize avatar speed for standard avatar size, then scale all motion logic | |
| 63 | 63 | // to properly follow avatar size. |
| 64 | 64 | float MAX_AVATAR_SPEED = 300.0f; |
| 65 | −float MAX_KEYBOARD_MOTOR_SPEED = MAX_AVATAR_SPEED; | |
| 65 | +float MAX_KEYBOARD_MOTOR_SPEED = MAX_AVATAR_SPEED; | |
| 66 | 66 | float DEFAULT_KEYBOARD_MOTOR_TIMESCALE = 0.25f; |
| 67 | 67 | float MIN_SCRIPTED_MOTOR_TIMESCALE = 0.005f; |
| 68 | 68 | float DEFAULT_SCRIPTED_MOTOR_TIMESCALE = 1.0e6f; |
| @@ -146,7 +146,7 @@ void MyAvatar::update(float deltaTime) { · 77 unmodified lines | ||
| 146 | 146 | if (_referential) { |
| 147 | 147 | _referential->update(); |
| 148 | 148 | } |
| 149 | − | |
| 149 | + | |
| 150 | 150 | Head* head = getHead(); |
| 151 | 151 | head->relaxLean(deltaTime); |
| 152 | 152 | updateFromTrackers(deltaTime); |
| @@ -163,12 +163,12 @@ void MyAvatar::update(float deltaTime) { · 10 unmodified lines | ||
| 163 | 163 | |
| 164 | 164 | void MyAvatar::simulate(float deltaTime) { |
| 165 | 165 | PerformanceTimer perfTimer("simulate"); |
| 166 | − | |
| 166 | + | |
| 167 | 167 | // Play back recording |
| 168 | 168 | if (_player && _player->isPlaying()) { |
| 169 | 169 | _player->play(); |
| 170 | 170 | } |
| 171 | − | |
| 171 | + | |
| 172 | 172 | if (_scale != _targetScale) { |
| 173 | 173 | float scale = (1.0f - SMOOTHING_RATIO) * _scale + SMOOTHING_RATIO * _targetScale; |
| 174 | 174 | setScale(scale); |
| @@ -179,7 +179,7 @@ void MyAvatar::simulate(float deltaTime) { · 4 unmodified lines | ||
| 179 | 179 | updateOrientation(deltaTime); |
| 180 | 180 | updatePosition(deltaTime); |
| 181 | 181 | } |
| 182 | − | |
| 182 | + | |
| 183 | 183 | { |
| 184 | 184 | PerformanceTimer perfTimer("hand"); |
| 185 | 185 | // update avatar skeleton and simulate hand and head |
| @@ -222,12 +222,12 @@ void MyAvatar::simulate(float deltaTime) { · 36 unmodified lines | ||
| 222 | 222 | head->setScale(_scale); |
| 223 | 223 | head->simulate(deltaTime, true); |
| 224 | 224 | } |
| 225 | − | |
| 225 | + | |
| 226 | 226 | // Record avatars movements. |
| 227 | 227 | if (_recorder && _recorder->isRecording()) { |
| 228 | 228 | _recorder->record(); |
| 229 | 229 | } |
| 230 | − | |
| 230 | + | |
| 231 | 231 | // consider updating our billboard |
| 232 | 232 | maybeUpdateBillboard(); |
| 233 | 233 | } |
| @@ -235,18 +235,18 @@ void MyAvatar::simulate(float deltaTime) { · 1 unmodified line | ||
| 235 | 235 | // Update avatar head rotation with sensor data |
| 236 | 236 | void MyAvatar::updateFromTrackers(float deltaTime) { |
| 237 | 237 | glm::vec3 estimatedPosition, estimatedRotation; |
| 238 | − | |
| 238 | + | |
| 239 | 239 | bool inHmd = qApp->isHMDMode(); |
| 240 | − | |
| 240 | + | |
| 241 | 241 | if (isPlaying() && inHmd) { |
| 242 | 242 | return; |
| 243 | 243 | } |
| 244 | 244 | |
| 245 | 245 | if (inHmd) { |
| 246 | − estimatedPosition = qApp->getHeadPosition(); | |
| 246 | + estimatedPosition = qApp->getHeadPosition(); | |
| 247 | 247 | estimatedPosition.x *= -1.0f; |
| 248 | 248 | _trackedHeadPosition = estimatedPosition; |
| 249 | − | |
| 249 | + | |
| 250 | 250 | const float OCULUS_LEAN_SCALE = 0.05f; |
| 251 | 251 | estimatedPosition /= OCULUS_LEAN_SCALE; |
| 252 | 252 | } else { |
| @@ -257,7 +257,7 @@ void MyAvatar::updateFromTrackers(float deltaTime) { · 4 unmodified lines | ||
| 257 | 257 | estimatedRotation = glm::degrees(safeEulerAngles(tracker->getHeadRotation())); |
| 258 | 258 | } |
| 259 | 259 | } |
| 260 | − | |
| 260 | + | |
| 261 | 261 | // Rotate the body if the head is turned beyond the screen |
| 262 | 262 | if (Menu::getInstance()->isOptionChecked(MenuOption::TurnWithHead)) { |
| 263 | 263 | const float TRACKER_YAW_TURN_SENSITIVITY = 0.5f; |
| @@ -317,7 +317,7 @@ void MyAvatar::renderDebugBodyPoints() { · 53 unmodified lines | ||
| 317 | 317 | glm::vec3 headPosition(getHead()->getEyePosition()); |
| 318 | 318 | float torsoToHead = glm::length(headPosition - torsoPosition); |
| 319 | 319 | glm::vec3 position; |
| 320 | − qCDebug(interfaceapp, "head-above-torso %.2f, scale = %0.2f", torsoToHead, getScale()); | |
| 320 | + qCDebug(interfaceapp, "head-above-torso %.2f, scale = %0.2f", (double)torsoToHead, (double)getScale()); | |
| 321 | 321 | |
| 322 | 322 | // Torso Sphere |
| 323 | 323 | position = torsoPosition; |
| @@ -433,7 +433,7 @@ void MyAvatar::startRecording() { · 109 unmodified lines | ||
| 433 | 433 | auto audioClient = DependencyManager::get<AudioClient>(); |
| 434 | 434 | connect(audioClient.data(), &AudioClient::inputReceived, _recorder.data(), |
| 435 | 435 | &Recorder::recordAudio, Qt::BlockingQueuedConnection); |
| 436 | − | |
| 436 | + | |
| 437 | 437 | _recorder->startRecording(); |
| 438 | 438 | } |
| 439 | 439 | |
| @@ -449,7 +449,7 @@ void MyAvatar::stopRecording() { · 9 unmodified lines | ||
| 449 | 449 | // stop grabbing audio from the AudioClient |
| 450 | 450 | auto audioClient = DependencyManager::get<AudioClient>(); |
| 451 | 451 | disconnect(audioClient.data(), 0, _recorder.data(), 0); |
| 452 | − | |
| 452 | + | |
| 453 | 453 | _recorder->stopRecording(); |
| 454 | 454 | } |
| 455 | 455 | } |
| @@ -481,7 +481,7 @@ void MyAvatar::loadLastRecording() { · 25 unmodified lines | ||
| 481 | 481 | if (!_player) { |
| 482 | 482 | _player = PlayerPointer(new Player(this)); |
| 483 | 483 | } |
| 484 | − | |
| 484 | + | |
| 485 | 485 | _player->loadRecording(_recorder->getRecording()); |
| 486 | 486 | } |
| 487 | 487 | |
| @@ -573,7 +573,7 @@ AnimationDetails MyAvatar::getAnimationDetailsByRole(const QString& role) { · 85 unmodified lines | ||
| 573 | 573 | AnimationDetails result; |
| 574 | 574 | if (QThread::currentThread() != thread()) { |
| 575 | 575 | QMetaObject::invokeMethod(this, "getAnimationDetailsByRole", Qt::BlockingQueuedConnection, |
| 576 | − Q_RETURN_ARG(AnimationDetails, result), | |
| 576 | + Q_RETURN_ARG(AnimationDetails, result), | |
| 577 | 577 | Q_ARG(const QString&, role)); |
| 578 | 578 | return result; |
| 579 | 579 | } |
| @@ -590,7 +590,7 @@ AnimationDetails MyAvatar::getAnimationDetails(const QString& url) { · 10 unmodified lines | ||
| 590 | 590 | AnimationDetails result; |
| 591 | 591 | if (QThread::currentThread() != thread()) { |
| 592 | 592 | QMetaObject::invokeMethod(this, "getAnimationDetails", Qt::BlockingQueuedConnection, |
| 593 | − Q_RETURN_ARG(AnimationDetails, result), | |
| 593 | + Q_RETURN_ARG(AnimationDetails, result), | |
| 594 | 594 | Q_ARG(const QString&, url)); |
| 595 | 595 | return result; |
| 596 | 596 | } |
| @@ -638,7 +638,7 @@ void MyAvatar::saveData() { · 41 unmodified lines | ||
| 638 | 638 | settings.setValue("scale", attachment.scale); |
| 639 | 639 | } |
| 640 | 640 | settings.endArray(); |
| 641 | − | |
| 641 | + | |
| 642 | 642 | settings.beginWriteArray("animationHandles"); |
| 643 | 643 | for (int i = 0; i < _animationHandles.size(); i++) { |
| 644 | 644 | settings.setArrayIndex(i); |
| @@ -655,7 +655,7 @@ void MyAvatar::saveData() { · 10 unmodified lines | ||
| 655 | 655 | settings.setValue("maskedJoints", pointer->getMaskedJoints()); |
| 656 | 656 | } |
| 657 | 657 | settings.endArray(); |
| 658 | − | |
| 658 | + | |
| 659 | 659 | settings.setValue("displayName", _displayName); |
| 660 | 660 | |
| 661 | 661 | settings.endGroup(); |
| @@ -681,7 +681,7 @@ void MyAvatar::loadData() { · 19 unmodified lines | ||
| 681 | 681 | _targetScale = loadSetting(settings, "scale", 1.0f); |
| 682 | 682 | setScale(_scale); |
| 683 | 683 | |
| 684 | − // The old preferences only stored the face and skeleton URLs, we didn't track if the user wanted to use 1 or 2 urls | |
| 684 | + // The old preferences only stored the face and skeleton URLs, we didn't track if the user wanted to use 1 or 2 urls | |
| 685 | 685 | // for their avatar, So we need to attempt to detect this old case and set our new preferences accordingly. If |
| 686 | 686 | // the head URL is empty, then we will assume they are using a full url... |
| 687 | 687 | bool isOldSettings = !(settings.contains("useFullAvatar") || settings.contains("fullAvatarURL")); |
| @@ -693,7 +693,7 @@ void MyAvatar::loadData() { · 5 unmodified lines | ||
| 693 | 693 | _headModelName = settings.value("headModelName", DEFAULT_HEAD_MODEL_NAME).toString(); |
| 694 | 694 | _bodyModelName = settings.value("bodyModelName", DEFAULT_BODY_MODEL_NAME).toString(); |
| 695 | 695 | _fullAvatarModelName = settings.value("fullAvatarModelName", DEFAULT_FULL_AVATAR_MODEL_NAME).toString(); |
| 696 | − | |
| 696 | + | |
| 697 | 697 | if (isOldSettings) { |
| 698 | 698 | bool assumeFullAvatar = _headURLFromPreferences.isEmpty(); |
| 699 | 699 | _useFullAvatar = assumeFullAvatar; |
| @@ -719,14 +719,14 @@ void MyAvatar::loadData() { · 19 unmodified lines | ||
| 719 | 719 | QVariantHash bodyFST = FSTReader::downloadMapping(_skeletonURLFromPreferences.toString()); |
| 720 | 720 | _bodyModelName = bodyFST["name"].toString(); |
| 721 | 721 | } |
| 722 | − | |
| 722 | + | |
| 723 | 723 | if (_headURLFromPreferences == DEFAULT_HEAD_MODEL_URL) { |
| 724 | 724 | _headModelName = DEFAULT_HEAD_MODEL_NAME; |
| 725 | 725 | } else { |
| 726 | 726 | QVariantHash headFST = FSTReader::downloadMapping(_headURLFromPreferences.toString()); |
| 727 | 727 | _headModelName = headFST["name"].toString(); |
| 728 | 728 | } |
| 729 | − | |
| 729 | + | |
| 730 | 730 | _fullAvatarModelName = "Default"; |
| 731 | 731 | } |
| 732 | 732 | } |
| @@ -736,7 +736,7 @@ void MyAvatar::loadData() { · 3 unmodified lines | ||
| 736 | 736 | } else { |
| 737 | 737 | useHeadAndBodyURLs(_headURLFromPreferences, _skeletonURLFromPreferences, _headModelName, _bodyModelName); |
| 738 | 738 | } |
| 739 | − | |
| 739 | + | |
| 740 | 740 | QVector<AttachmentData> attachmentData; |
| 741 | 741 | int attachmentCount = settings.beginReadArray("attachmentData"); |
| 742 | 742 | for (int i = 0; i < attachmentCount; i++) { |
| @@ -757,7 +757,7 @@ void MyAvatar::loadData() { · 14 unmodified lines | ||
| 757 | 757 | } |
| 758 | 758 | settings.endArray(); |
| 759 | 759 | setAttachmentData(attachmentData); |
| 760 | − | |
| 760 | + | |
| 761 | 761 | int animationCount = settings.beginReadArray("animationHandles"); |
| 762 | 762 | while (_animationHandles.size() > animationCount) { |
| 763 | 763 | _animationHandles.takeLast()->stop(); |
| @@ -780,7 +780,7 @@ void MyAvatar::loadData() { · 16 unmodified lines | ||
| 780 | 780 | handle->setStartAutomatically(settings.value("startAutomatically", true).toBool()); |
| 781 | 781 | } |
| 782 | 782 | settings.endArray(); |
| 783 | − | |
| 783 | + | |
| 784 | 784 | setDisplayName(settings.value("displayName").toString()); |
| 785 | 785 | |
| 786 | 786 | settings.endGroup(); |
| @@ -792,7 +792,7 @@ void MyAvatar::saveAttachmentData(const AttachmentData& attachment) const { · 5 unmodified lines | ||
| 792 | 792 | settings.beginGroup(_skeletonModel.getURL().toString()); |
| 793 | 793 | settings.beginGroup(attachment.modelURL.toString()); |
| 794 | 794 | settings.setValue("jointName", attachment.jointName); |
| 795 | − | |
| 795 | + | |
| 796 | 796 | settings.beginGroup(attachment.jointName); |
| 797 | 797 | settings.setValue("translation_x", attachment.translation.x); |
| 798 | 798 | settings.setValue("translation_y", attachment.translation.y); |
| @@ -802,7 +802,7 @@ void MyAvatar::saveAttachmentData(const AttachmentData& attachment) const { · 3 unmodified lines | ||
| 802 | 802 | settings.setValue("rotation_y", eulers.y); |
| 803 | 803 | settings.setValue("rotation_z", eulers.z); |
| 804 | 804 | settings.setValue("scale", attachment.scale); |
| 805 | − | |
| 805 | + | |
| 806 | 806 | settings.endGroup(); |
| 807 | 807 | settings.endGroup(); |
| 808 | 808 | settings.endGroup(); |
| @@ -814,7 +814,7 @@ AttachmentData MyAvatar::loadAttachmentData(const QUrl& modelURL, const QString& · 5 unmodified lines | ||
| 814 | 814 | settings.beginGroup("savedAttachmentData"); |
| 815 | 815 | settings.beginGroup(_skeletonModel.getURL().toString()); |
| 816 | 816 | settings.beginGroup(modelURL.toString()); |
| 817 | − | |
| 817 | + | |
| 818 | 818 | AttachmentData attachment; |
| 819 | 819 | attachment.modelURL = modelURL; |
| 820 | 820 | if (jointName.isEmpty()) { |
| @@ -836,18 +836,18 @@ AttachmentData MyAvatar::loadAttachmentData(const QUrl& modelURL, const QString& · 15 unmodified lines | ||
| 836 | 836 | } else { |
| 837 | 837 | attachment = AttachmentData(); |
| 838 | 838 | } |
| 839 | − | |
| 839 | + | |
| 840 | 840 | settings.endGroup(); |
| 841 | 841 | settings.endGroup(); |
| 842 | 842 | settings.endGroup(); |
| 843 | 843 | settings.endGroup(); |
| 844 | − | |
| 844 | + | |
| 845 | 845 | return attachment; |
| 846 | 846 | } |
| 847 | 847 | |
| 848 | 848 | int MyAvatar::parseDataAtOffset(const QByteArray& packet, int offset) { |
| 849 | 849 | qCDebug(interfaceapp) << "Error: ignoring update packet for MyAvatar" |
| 850 | − << " packetLength = " << packet.size() | |
| 850 | + << " packetLength = " << packet.size() | |
| 851 | 851 | << " offset = " << offset; |
| 852 | 852 | // this packet is just bad, so we pretend that we unpacked it ALL |
| 853 | 853 | return packet.size() - offset; |
| @@ -865,14 +865,14 @@ void MyAvatar::updateLookAtTargetAvatar() { · 11 unmodified lines | ||
| 865 | 865 | // |
| 866 | 866 | _lookAtTargetAvatar.reset(); |
| 867 | 867 | _targetAvatarPosition = glm::vec3(0.0f); |
| 868 | − | |
| 868 | + | |
| 869 | 869 | glm::vec3 lookForward = getHead()->getFinalOrientationInWorldFrame() * IDENTITY_FRONT; |
| 870 | 870 | glm::vec3 cameraPosition = Application::getInstance()->getCamera()->getPosition(); |
| 871 | − | |
| 871 | + | |
| 872 | 872 | float smallestAngleTo = glm::radians(DEFAULT_FIELD_OF_VIEW_DEGREES) / 2.0f; |
| 873 | 873 | const float KEEP_LOOKING_AT_CURRENT_ANGLE_FACTOR = 1.3f; |
| 874 | 874 | const float GREATEST_LOOKING_AT_DISTANCE = 10.0f; |
| 875 | − | |
| 875 | + | |
| 876 | 876 | int howManyLookingAtMe = 0; |
| 877 | 877 | foreach (const AvatarSharedPointer& avatarPointer, DependencyManager::get<AvatarManager>()->getAvatarHash()) { |
| 878 | 878 | Avatar* avatar = static_cast<Avatar*>(avatarPointer.get()); |
| @@ -1004,13 +1004,13 @@ void MyAvatar::useFullAvatarURL(const QUrl& fullAvatarURL, const QString& modelN · 125 unmodified lines | ||
| 1004 | 1004 | } |
| 1005 | 1005 | |
| 1006 | 1006 | _useFullAvatar = true; |
| 1007 | − | |
| 1007 | + | |
| 1008 | 1008 | if (_fullAvatarURLFromPreferences != fullAvatarURL) { |
| 1009 | 1009 | _fullAvatarURLFromPreferences = fullAvatarURL; |
| 1010 | 1010 | if (modelName.isEmpty()) { |
| 1011 | 1011 | QVariantHash fullAvatarFST = FSTReader::downloadMapping(_fullAvatarURLFromPreferences.toString()); |
| 1012 | 1012 | _fullAvatarModelName = fullAvatarFST["name"].toString(); |
| 1013 | − } else { | |
| 1013 | + } else { | |
| 1014 | 1014 | _fullAvatarModelName = modelName; |
| 1015 | 1015 | } |
| 1016 | 1016 | } |
| @@ -1051,7 +1051,7 @@ void MyAvatar::useHeadAndBodyURLs(const QUrl& headURL, const QUrl& bodyURL, cons · 34 unmodified lines | ||
| 1051 | 1051 | if (headName.isEmpty()) { |
| 1052 | 1052 | QVariantHash headFST = FSTReader::downloadMapping(_headURLFromPreferences.toString()); |
| 1053 | 1053 | _headModelName = headFST["name"].toString(); |
| 1054 | − } else { | |
| 1054 | + } else { | |
| 1055 | 1055 | _headModelName = headName; |
| 1056 | 1056 | } |
| 1057 | 1057 | } |
| @@ -1061,7 +1061,7 @@ void MyAvatar::useHeadAndBodyURLs(const QUrl& headURL, const QUrl& bodyURL, cons · 3 unmodified lines | ||
| 1061 | 1061 | if (bodyName.isEmpty()) { |
| 1062 | 1062 | QVariantHash bodyFST = FSTReader::downloadMapping(_skeletonURLFromPreferences.toString()); |
| 1063 | 1063 | _bodyModelName = bodyFST["name"].toString(); |
| 1064 | − } else { | |
| 1064 | + } else { | |
| 1065 | 1065 | _bodyModelName = bodyName; |
| 1066 | 1066 | } |
| 1067 | 1067 | } |
| @@ -1092,7 +1092,7 @@ void MyAvatar::setAttachmentData(const QVector<AttachmentData>& attachmentData) · 24 unmodified lines | ||
| 1092 | 1092 | glm::vec3 MyAvatar::getSkeletonPosition() const { |
| 1093 | 1093 | CameraMode mode = Application::getInstance()->getCamera()->getMode(); |
| 1094 | 1094 | if (mode == CAMERA_MODE_THIRD_PERSON || mode == CAMERA_MODE_INDEPENDENT) { |
| 1095 | − // The avatar is rotated PI about the yAxis, so we have to correct for it | |
| 1095 | + // The avatar is rotated PI about the yAxis, so we have to correct for it | |
| 1096 | 1096 | // to get the skeleton offset contribution in the world-frame. |
| 1097 | 1097 | const glm::quat FLIP = glm::angleAxis(PI, glm::vec3(0.0f, 1.0f, 0.0f)); |
| 1098 | 1098 | glm::vec3 skeletonOffset = _skeletonOffset; |
| @@ -1135,9 +1135,9 @@ void MyAvatar::setScriptedMotorVelocity(const glm::vec3& velocity) { · 36 unmodified lines | ||
| 1135 | 1135 | } |
| 1136 | 1136 | |
| 1137 | 1137 | void MyAvatar::setScriptedMotorTimescale(float timescale) { |
| 1138 | − // we clamp the timescale on the large side (instead of just the low side) to prevent | |
| 1138 | + // we clamp the timescale on the large side (instead of just the low side) to prevent | |
| 1139 | 1139 | // obnoxiously large values from introducing NaN into avatar's velocity |
| 1140 | − _scriptedMotorTimescale = glm::clamp(timescale, MIN_SCRIPTED_MOTOR_TIMESCALE, | |
| 1140 | + _scriptedMotorTimescale = glm::clamp(timescale, MIN_SCRIPTED_MOTOR_TIMESCALE, | |
| 1141 | 1141 | DEFAULT_SCRIPTED_MOTOR_TIMESCALE); |
| 1142 | 1142 | } |
| 1143 | 1143 | |
| @@ -1155,14 +1155,14 @@ void MyAvatar::clearScriptableSettings() { · 11 unmodified lines | ||
| 1155 | 1155 | clearJointAnimationPriorities(); |
| 1156 | 1156 | _scriptedMotorVelocity = glm::vec3(0.0f); |
| 1157 | 1157 | _scriptedMotorTimescale = DEFAULT_SCRIPTED_MOTOR_TIMESCALE; |
| 1158 | −} | |
| 1158 | +} | |
| 1159 | 1159 | |
| 1160 | 1160 | void MyAvatar::attach(const QString& modelURL, const QString& jointName, const glm::vec3& translation, |
| 1161 | 1161 | const glm::quat& rotation, float scale, bool allowDuplicates, bool useSaved) { |
| 1162 | − if (QThread::currentThread() != thread()) { | |
| 1162 | + if (QThread::currentThread() != thread()) { | |
| 1163 | 1163 | Avatar::attach(modelURL, jointName, translation, rotation, scale, allowDuplicates, useSaved); |
| 1164 | 1164 | return; |
| 1165 | − } | |
| 1165 | + } | |
| 1166 | 1166 | if (useSaved) { |
| 1167 | 1167 | AttachmentData attachment = loadAttachmentData(modelURL, jointName); |
| 1168 | 1168 | if (attachment.isValid()) { |
| @@ -1199,7 +1199,7 @@ const float RENDER_HEAD_CUTOFF_DISTANCE = 0.50f; · 30 unmodified lines | ||
| 1199 | 1199 | |
| 1200 | 1200 | bool MyAvatar::shouldRenderHead(const RenderArgs* renderArgs, const glm::vec3& cameraPosition) const { |
| 1201 | 1201 | const Head* head = getHead(); |
| 1202 | − return (renderArgs->_renderMode != RenderArgs::NORMAL_RENDER_MODE) || (Application::getInstance()->getCamera()->getMode() != CAMERA_MODE_FIRST_PERSON) || | |
| 1202 | + return (renderArgs->_renderMode != RenderArgs::NORMAL_RENDER_MODE) || (Application::getInstance()->getCamera()->getMode() != CAMERA_MODE_FIRST_PERSON) || | |
| 1203 | 1203 | (glm::length(cameraPosition - head->getEyePosition()) > RENDER_HEAD_CUTOFF_DISTANCE * _scale); |
| 1204 | 1204 | } |
| 1205 | 1205 | |
| @@ -1230,10 +1230,10 @@ void MyAvatar::updateOrientation(float deltaTime) { · 24 unmodified lines | ||
| 1230 | 1230 | |
| 1231 | 1231 | //Invert yaw and roll when in mirror mode |
| 1232 | 1232 | if (Application::getInstance()->getCamera()->getMode() == CAMERA_MODE_MIRROR) { |
| 1233 | − YAW(euler) *= -1.0; | |
| 1234 | − ROLL(euler) *= -1.0; | |
| 1233 | + YAW(euler) *= -1.0f; | |
| 1234 | + ROLL(euler) *= -1.0f; | |
| 1235 | 1235 | } |
| 1236 | − | |
| 1236 | + | |
| 1237 | 1237 | Head* head = getHead(); |
| 1238 | 1238 | head->setBaseYaw(YAW(euler)); |
| 1239 | 1239 | head->setBasePitch(PITCH(euler)); |
| @@ -1246,9 +1246,9 @@ glm::vec3 MyAvatar::applyKeyboardMotor(float deltaTime, const glm::vec3& localVe · 6 unmodified lines | ||
| 1246 | 1246 | return localVelocity; |
| 1247 | 1247 | } |
| 1248 | 1248 | // compute motor efficiency |
| 1249 | − // The timescale of the motor is the approximate time it takes for the motor to | |
| 1250 | − // accomplish its intended localVelocity. A short timescale makes the motor strong, | |
| 1251 | − // and a long timescale makes it weak. The value of timescale to use depends | |
| 1249 | + // The timescale of the motor is the approximate time it takes for the motor to | |
| 1250 | + // accomplish its intended localVelocity. A short timescale makes the motor strong, | |
| 1251 | + // and a long timescale makes it weak. The value of timescale to use depends | |
| 1252 | 1252 | // on what the motor is doing: |
| 1253 | 1253 | // |
| 1254 | 1254 | // (1) braking --> short timescale (aggressive motor assertion) |
| @@ -1259,8 +1259,8 @@ glm::vec3 MyAvatar::applyKeyboardMotor(float deltaTime, const glm::vec3& localVe · 4 unmodified lines | ||
| 1259 | 1259 | float MIN_KEYBOARD_BRAKE_SPEED = 0.3f; |
| 1260 | 1260 | float timescale = MAX_KEYBOARD_MOTOR_TIMESCALE; |
| 1261 | 1261 | bool isThrust = (glm::length2(_thrust) > EPSILON); |
| 1262 | − if (_isPushing || isThrust || | |
| 1263 | − (_scriptedMotorTimescale < MAX_KEYBOARD_MOTOR_TIMESCALE && | |
| 1262 | + if (_isPushing || isThrust || | |
| 1263 | + (_scriptedMotorTimescale < MAX_KEYBOARD_MOTOR_TIMESCALE && | |
| 1264 | 1264 | _motionBehaviors | AVATAR_MOTION_SCRIPTED_MOTOR_ENABLED)) { |
| 1265 | 1265 | // we don't want to brake if something is pushing the avatar around |
| 1266 | 1266 | timescale = _keyboardMotorTimescale; |
| @@ -1277,18 +1277,18 @@ glm::vec3 MyAvatar::applyKeyboardMotor(float deltaTime, const glm::vec3& localVe · 10 unmodified lines | ||
| 1277 | 1277 | float motorEfficiency = glm::clamp(deltaTime / timescale, 0.0f, 1.0f); |
| 1278 | 1278 | |
| 1279 | 1279 | glm::vec3 newLocalVelocity = localVelocity; |
| 1280 | − float keyboardInput = fabsf(_driveKeys[FWD] - _driveKeys[BACK]) + | |
| 1281 | − (fabsf(_driveKeys[RIGHT] - _driveKeys[LEFT])) + | |
| 1280 | + float keyboardInput = fabsf(_driveKeys[FWD] - _driveKeys[BACK]) + | |
| 1281 | + (fabsf(_driveKeys[RIGHT] - _driveKeys[LEFT])) + | |
| 1282 | 1282 | fabsf(_driveKeys[UP] - _driveKeys[DOWN]); |
| 1283 | 1283 | if (keyboardInput) { |
| 1284 | 1284 | // Compute keyboard input |
| 1285 | 1285 | glm::vec3 front = (_driveKeys[FWD] - _driveKeys[BACK]) * IDENTITY_FRONT; |
| 1286 | 1286 | glm::vec3 right = (_driveKeys[RIGHT] - _driveKeys[LEFT]) * IDENTITY_RIGHT; |
| 1287 | 1287 | glm::vec3 up = (_driveKeys[UP] - _driveKeys[DOWN]) * IDENTITY_UP; |
| 1288 | − | |
| 1288 | + | |
| 1289 | 1289 | glm::vec3 direction = front + right + up; |
| 1290 | 1290 | float directionLength = glm::length(direction); |
| 1291 | − | |
| 1291 | + | |
| 1292 | 1292 | // Compute motor magnitude |
| 1293 | 1293 | if (directionLength > EPSILON) { |
| 1294 | 1294 | direction /= directionLength; |
| @@ -1318,7 +1318,7 @@ glm::vec3 MyAvatar::applyKeyboardMotor(float deltaTime, const glm::vec3& localVe · 23 unmodified lines | ||
| 1318 | 1318 | motorEfficiency = glm::clamp(deltaTime / WALK_ACCELERATION_TIMESCALE, 0.0f, 1.0f); |
| 1319 | 1319 | } |
| 1320 | 1320 | _isPushing = true; |
| 1321 | − } | |
| 1321 | + } | |
| 1322 | 1322 | newLocalVelocity = localVelocity + motorEfficiency * (_keyboardMotorVelocity - localVelocity); |
| 1323 | 1323 | } else { |
| 1324 | 1324 | _keyboardMotorVelocity = glm::vec3(0.0f); |
| @@ -1382,13 +1382,13 @@ void MyAvatar::updatePosition(float deltaTime) { · 57 unmodified lines | ||
| 1382 | 1382 | _targetVelocity *= MAX_AVATAR_SPEED / speed; |
| 1383 | 1383 | speed = MAX_AVATAR_SPEED; |
| 1384 | 1384 | } |
| 1385 | − | |
| 1385 | + | |
| 1386 | 1386 | if (speed > MIN_AVATAR_SPEED && !_characterController.isEnabled()) { |
| 1387 | 1387 | // update position ourselves |
| 1388 | 1388 | applyPositionDelta(deltaTime * _targetVelocity); |
| 1389 | 1389 | measureMotionDerivatives(deltaTime); |
| 1390 | 1390 | } // else physics will move avatar later |
| 1391 | − | |
| 1391 | + | |
| 1392 | 1392 | // update _moving flag based on speed |
| 1393 | 1393 | const float MOVING_SPEED_THRESHOLD = 0.01f; |
| 1394 | 1394 | _moving = speed > MOVING_SPEED_THRESHOLD; |
| @@ -1405,7 +1405,7 @@ bool findAvatarAvatarPenetration(const glm::vec3 positionA, float radiusA, float · 10 unmodified lines | ||
| 1405 | 1405 | float xzDistance = sqrt(positionBA.x * positionBA.x + positionBA.z * positionBA.z); |
| 1406 | 1406 | if (xzDistance < (radiusA + radiusB)) { |
| 1407 | 1407 | float yDistance = fabs(positionBA.y); |
| 1408 | − float halfHeights = 0.5 * (heightA + heightB); | |
| 1408 | + float halfHeights = 0.5f * (heightA + heightB); | |
| 1409 | 1409 | if (yDistance < halfHeights) { |
| 1410 | 1410 | // cylinders collide |
| 1411 | 1411 | if (xzDistance > 0.0f) { |
| @@ -1448,60 +1448,60 @@ void MyAvatar::maybeUpdateBillboard() { · 36 unmodified lines | ||
| 1448 | 1448 | } |
| 1449 | 1449 | gpu::Context context(new gpu::GLBackend()); |
| 1450 | 1450 | RenderArgs renderArgs(&context); |
| 1451 | − QImage image = Application::getInstance()->renderAvatarBillboard(&renderArgs); | |
| 1451 | + QImage image = qApp->renderAvatarBillboard(&renderArgs); | |
| 1452 | 1452 | _billboard.clear(); |
| 1453 | 1453 | QBuffer buffer(&_billboard); |
| 1454 | 1454 | buffer.open(QIODevice::WriteOnly); |
| 1455 | 1455 | image.save(&buffer, "PNG"); |
| 1456 | 1456 | _billboardValid = true; |
| 1457 | − | |
| 1457 | + | |
| 1458 | 1458 | sendBillboardPacket(); |
| 1459 | 1459 | } |
| 1460 | 1460 | |
| 1461 | 1461 | void MyAvatar::increaseSize() { |
| 1462 | 1462 | if ((1.0f + SCALING_RATIO) * _targetScale < MAX_AVATAR_SCALE) { |
| 1463 | 1463 | _targetScale *= (1.0f + SCALING_RATIO); |
| 1464 | − qCDebug(interfaceapp, "Changed scale to %f", _targetScale); | |
| 1464 | + qCDebug(interfaceapp, "Changed scale to %f", (double)_targetScale); | |
| 1465 | 1465 | } |
| 1466 | 1466 | } |
| 1467 | 1467 | |
| 1468 | 1468 | void MyAvatar::decreaseSize() { |
| 1469 | 1469 | if (MIN_AVATAR_SCALE < (1.0f - SCALING_RATIO) * _targetScale) { |
| 1470 | 1470 | _targetScale *= (1.0f - SCALING_RATIO); |
| 1471 | − qCDebug(interfaceapp, "Changed scale to %f", _targetScale); | |
| 1471 | + qCDebug(interfaceapp, "Changed scale to %f", (double)_targetScale); | |
| 1472 | 1472 | } |
| 1473 | 1473 | } |
| 1474 | 1474 | |
| 1475 | 1475 | void MyAvatar::resetSize() { |
| 1476 | 1476 | _targetScale = 1.0f; |
| 1477 | − qCDebug(interfaceapp, "Reseted scale to %f", _targetScale); | |
| 1477 | + qCDebug(interfaceapp, "Reseted scale to %f", (double)_targetScale); | |
| 1478 | 1478 | } |
| 1479 | 1479 | |
| 1480 | 1480 | void MyAvatar::goToLocation(const glm::vec3& newPosition, |
| 1481 | 1481 | bool hasOrientation, const glm::quat& newOrientation, |
| 1482 | 1482 | bool shouldFaceLocation) { |
| 1483 | − | |
| 1483 | + | |
| 1484 | 1484 | qCDebug(interfaceapp).nospace() << "MyAvatar goToLocation - moving to " << newPosition.x << ", " |
| 1485 | 1485 | << newPosition.y << ", " << newPosition.z; |
| 1486 | − | |
| 1486 | + | |
| 1487 | 1487 | glm::vec3 shiftedPosition = newPosition; |
| 1488 | − | |
| 1488 | + | |
| 1489 | 1489 | if (hasOrientation) { |
| 1490 | 1490 | qCDebug(interfaceapp).nospace() << "MyAvatar goToLocation - new orientation is " |
| 1491 | 1491 | << newOrientation.x << ", " << newOrientation.y << ", " << newOrientation.z << ", " << newOrientation.w; |
| 1492 | − | |
| 1492 | + | |
| 1493 | 1493 | // orient the user to face the target |
| 1494 | 1494 | glm::quat quatOrientation = newOrientation; |
| 1495 | − | |
| 1495 | + | |
| 1496 | 1496 | if (shouldFaceLocation) { |
| 1497 | − | |
| 1497 | + | |
| 1498 | 1498 | quatOrientation = newOrientation * glm::angleAxis(PI, glm::vec3(0.0f, 1.0f, 0.0f)); |
| 1499 | − | |
| 1499 | + | |
| 1500 | 1500 | // move the user a couple units away |
| 1501 | 1501 | const float DISTANCE_TO_USER = 2.0f; |
| 1502 | 1502 | shiftedPosition = newPosition - quatOrientation * IDENTITY_FRONT * DISTANCE_TO_USER; |
| 1503 | 1503 | } |
| 1504 | − | |
| 1504 | + | |
| 1505 | 1505 | setOrientation(quatOrientation); |
| 1506 | 1506 | } |
| 1507 | 1507 | |
| @@ -1547,7 +1547,6 @@ void MyAvatar::renderLaserPointers() { · 39 unmodified lines | ||
| 1547 | 1547 | |
| 1548 | 1548 | //Gets the tip position for the laser pointer |
| 1549 | 1549 | glm::vec3 MyAvatar::getLaserPointerTipPosition(const PalmData* palm) { |
| 1550 | − const ApplicationOverlay& applicationOverlay = Application::getInstance()->getApplicationOverlay(); | |
| 1551 | 1550 | glm::vec3 direction = glm::normalize(palm->getTipPosition() - palm->getPosition()); |
| 1552 | 1551 | |
| 1553 | 1552 | glm::vec3 position = palm->getPosition(); |
| @@ -1556,7 +1555,8 @@ glm::vec3 MyAvatar::getLaserPointerTipPosition(const PalmData* palm) { · 2 unmodified lines | ||
| 1556 | 1555 | |
| 1557 | 1556 | |
| 1558 | 1557 | glm::vec3 result; |
| 1559 | − if (applicationOverlay.calculateRayUICollisionPoint(position, direction, result)) { | |
| 1558 | + const auto& compositor = qApp->getApplicationCompositor(); | |
| 1559 | + if (compositor.calculateRayUICollisionPoint(position, direction, result)) { | |
| 1560 | 1560 | return result; |
| 1561 | 1561 | } |
| 1562 | 1562 | |
| @@ -1569,8 +1569,8 @@ void MyAvatar::clearDriveKeys() { · 6 unmodified lines | ||
| 1569 | 1569 | } |
| 1570 | 1570 | } |
| 1571 | 1571 | |
| 1572 | −void MyAvatar::relayDriveKeysToCharacterController() { | |
| 1572 | +void MyAvatar::relayDriveKeysToCharacterController() { | |
| 1573 | 1573 | if (_driveKeys[UP] > 0.0f) { |
| 1574 | − _characterController.jump(); | |
| 1574 | + _characterController.jump(); | |
| 1575 | 1575 | } |
| 1576 | 1576 | } |
| @@ -90,7 +90,7 @@ public: · 89 unmodified lines | ||
| 90 | 90 | |
| 91 | 91 | void relayDriveKeysToCharacterController(); |
| 92 | 92 | |
| 93 | − bool isMyAvatar() { return true; } | |
| 93 | + bool isMyAvatar() const { return true; } | |
| 94 | 94 | |
| 95 | 95 | bool isLookingAtLeftEye(); |
| 96 | 96 | |
| @@ -1,121 +0,0 @@ | ||
| 1 | −// | |
| 2 | −// CameraToolBox.cpp | |
| 3 | −// interface/src/devices | |
| 4 | −// | |
| 5 | −// Created by David Rowe on 30 Apr 2015. | |
| 6 | −// Copyright 2015 High Fidelity, Inc. | |
| 7 | −// | |
| 8 | −// Distributed under the Apache License, Version 2.0. | |
| 9 | −// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html | |
| 10 | −// | |
| 11 | − | |
| 12 | −#include "InterfaceConfig.h" | |
| 13 | − | |
| 14 | −#include <GLCanvas.h> | |
| 15 | −#include <PathUtils.h> | |
| 16 | − | |
| 17 | −#include "gpu/GLBackend.h" | |
| 18 | −#include "Application.h" | |
| 19 | −#include "CameraToolBox.h" | |
| 20 | −#include "FaceTracker.h" | |
| 21 | − | |
| 22 | − | |
| 23 | −CameraToolBox::CameraToolBox() : | |
| 24 | − _iconPulseTimeReference(usecTimestampNow()), | |
| 25 | − _doubleClickTimer(NULL) | |
| 26 | −{ | |
| 27 | −} | |
| 28 | − | |
| 29 | −CameraToolBox::~CameraToolBox() { | |
| 30 | − if (_doubleClickTimer) { | |
| 31 | − _doubleClickTimer->stop(); | |
| 32 | − delete _doubleClickTimer; | |
| 33 | − } | |
| 34 | −} | |
| 35 | − | |
| 36 | −bool CameraToolBox::mousePressEvent(int x, int y) { | |
| 37 | − if (_iconBounds.contains(x, y)) { | |
| 38 | − if (!_doubleClickTimer) { | |
| 39 | − // Toggle mute after waiting to check that it's not a double-click. | |
| 40 | − const int DOUBLE_CLICK_WAIT = 200; // ms | |
| 41 | − _doubleClickTimer = new QTimer(this); | |
| 42 | − connect(_doubleClickTimer, SIGNAL(timeout()), this, SLOT(toggleMute())); | |
| 43 | − _doubleClickTimer->setSingleShot(true); | |
| 44 | − _doubleClickTimer->setInterval(DOUBLE_CLICK_WAIT); | |
| 45 | − _doubleClickTimer->start(); | |
| 46 | − } | |
| 47 | − return true; | |
| 48 | − } | |
| 49 | − return false; | |
| 50 | −} | |
| 51 | − | |
| 52 | −bool CameraToolBox::mouseDoublePressEvent(int x, int y) { | |
| 53 | − if (_iconBounds.contains(x, y)) { | |
| 54 | − if (_doubleClickTimer) { | |
| 55 | − _doubleClickTimer->stop(); | |
| 56 | − delete _doubleClickTimer; | |
| 57 | − _doubleClickTimer = NULL; | |
| 58 | − } | |
| 59 | − Application::getInstance()->resetSensors(); | |
| 60 | − return true; | |
| 61 | − } | |
| 62 | − return false; | |
| 63 | −} | |
| 64 | − | |
| 65 | −void CameraToolBox::toggleMute() { | |
| 66 | − delete _doubleClickTimer; | |
| 67 | − _doubleClickTimer = NULL; | |
| 68 | − | |
| 69 | − FaceTracker* faceTracker = Application::getInstance()->getSelectedFaceTracker(); | |
| 70 | − if (faceTracker) { | |
| 71 | − faceTracker->toggleMute(); | |
| 72 | − } | |
| 73 | −} | |
| 74 | − | |
| 75 | −void CameraToolBox::render(int x, int y, bool boxed) { | |
| 76 | − glEnable(GL_TEXTURE_2D); | |
| 77 | − | |
| 78 | − if (!_enabledTexture) { | |
| 79 | − _enabledTexture = TextureCache::getImageTexture(PathUtils::resourcesPath() + "images/face.svg"); | |
| 80 | − } | |
| 81 | − if (!_mutedTexture) { | |
| 82 | − _mutedTexture = TextureCache::getImageTexture(PathUtils::resourcesPath() + "images/face-mute.svg"); | |
| 83 | − } | |
| 84 | − | |
| 85 | − const int MUTE_ICON_SIZE = 24; | |
| 86 | − _iconBounds = QRect(x, y, MUTE_ICON_SIZE, MUTE_ICON_SIZE); | |
| 87 | − float iconColor = 1.0f; | |
| 88 | − if (!Menu::getInstance()->isOptionChecked(MenuOption::MuteFaceTracking)) { | |
| 89 | − glBindTexture(GL_TEXTURE_2D, gpu::GLBackend::getTextureID(_enabledTexture)); | |
| 90 | − } else { | |
| 91 | − glBindTexture(GL_TEXTURE_2D, gpu::GLBackend::getTextureID(_mutedTexture)); | |
| 92 | − | |
| 93 | − // Make muted icon pulsate | |
| 94 | − static const float PULSE_MIN = 0.4f; | |
| 95 | − static const float PULSE_MAX = 1.0f; | |
| 96 | − static const float PULSE_FREQUENCY = 1.0f; // in Hz | |
| 97 | − qint64 now = usecTimestampNow(); | |
| 98 | − if (now - _iconPulseTimeReference > (qint64)USECS_PER_SECOND) { | |
| 99 | − // Prevents t from getting too big, which would diminish glm::cos precision | |
| 100 | − _iconPulseTimeReference = now - ((now - _iconPulseTimeReference) % USECS_PER_SECOND); | |
| 101 | − } | |
| 102 | − float t = (float)(now - _iconPulseTimeReference) / (float)USECS_PER_SECOND; | |
| 103 | − float pulseFactor = (glm::cos(t * PULSE_FREQUENCY * 2.0f * PI) + 1.0f) / 2.0f; | |
| 104 | − iconColor = PULSE_MIN + (PULSE_MAX - PULSE_MIN) * pulseFactor; | |
| 105 | − } | |
| 106 | − | |
| 107 | − glm::vec4 quadColor(iconColor, iconColor, iconColor, 1.0f); | |
| 108 | − | |
| 109 | − glm::vec2 topLeft(_iconBounds.left(), _iconBounds.top()); | |
| 110 | − glm::vec2 bottomRight(_iconBounds.right(), _iconBounds.bottom()); | |
| 111 | − glm::vec2 texCoordTopLeft(1,1); | |
| 112 | − glm::vec2 texCoordBottomRight(0,0); | |
| 113 | − | |
| 114 | − if (_boxQuadID == GeometryCache::UNKNOWN_ID) { | |
| 115 | − _boxQuadID = DependencyManager::get<GeometryCache>()->allocateID(); | |
| 116 | − } | |
| 117 | − | |
| 118 | − DependencyManager::get<GeometryCache>()->renderQuad(topLeft, bottomRight, texCoordTopLeft, texCoordBottomRight, quadColor, _boxQuadID); | |
| 119 | − | |
| 120 | − glDisable(GL_TEXTURE_2D); | |
| 121 | −} | |
| @@ -1,45 +0,0 @@ | ||
| 1 | −// | |
| 2 | −// CameraToolBox.h | |
| 3 | −// interface/src/devices | |
| 4 | −// | |
| 5 | −// Created by David Rowe on 30 Apr 2015. | |
| 6 | −// Copyright 2015 High Fidelity, Inc. | |
| 7 | −// | |
| 8 | −// Distributed under the Apache License, Version 2.0. | |
| 9 | −// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html | |
| 10 | −// | |
| 11 | − | |
| 12 | −#ifndef hifi_CameraToolBox_h | |
| 13 | −#define hifi_CameraToolBox_h | |
| 14 | − | |
| 15 | −#include <QObject> | |
| 16 | − | |
| 17 | −#include <DependencyManager.h> | |
| 18 | −#include <GeometryCache.h> | |
| 19 | − | |
| 20 | −class CameraToolBox : public QObject, public Dependency { | |
| 21 | − Q_OBJECT | |
| 22 | − SINGLETON_DEPENDENCY | |
| 23 | − | |
| 24 | −public: | |
| 25 | − void render(int x, int y, bool boxed); | |
| 26 | − bool mousePressEvent(int x, int y); | |
| 27 | − bool mouseDoublePressEvent(int x, int y); | |
| 28 | − | |
| 29 | −protected: | |
| 30 | − CameraToolBox(); | |
| 31 | − ~CameraToolBox(); | |
| 32 | − | |
| 33 | −private slots: | |
| 34 | − void toggleMute(); | |
| 35 | − | |
| 36 | −private: | |
| 37 | − gpu::TexturePointer _enabledTexture; | |
| 38 | − gpu::TexturePointer _mutedTexture; | |
| 39 | − int _boxQuadID = GeometryCache::UNKNOWN_ID; | |
| 40 | − QRect _iconBounds; | |
| 41 | − qint64 _iconPulseTimeReference = 0; | |
| 42 | − QTimer* _doubleClickTimer; | |
| 43 | −}; | |
| 44 | − | |
| 45 | −#endif // hifi_CameraToolBox_h | |
| @@ -415,7 +415,7 @@ void DdeFaceTracker::decodePacket(const QByteArray& buffer) { · 414 unmodified lines | ||
| 415 | 415 | float browUp = _coefficients[_browUpCenterIndex]; |
| 416 | 416 | if (isFiltering) { |
| 417 | 417 | const float BROW_VELOCITY_FILTER_STRENGTH = 0.5f; |
| 418 | − float velocity = fabs(browUp - _lastBrowUp) / _averageMessageTime; | |
| 418 | + float velocity = fabsf(browUp - _lastBrowUp) / _averageMessageTime; | |
| 419 | 419 | float velocityFilter = glm::clamp(velocity * BROW_VELOCITY_FILTER_STRENGTH, 0.0f, 1.0f); |
| 420 | 420 | _filteredBrowUp = velocityFilter * browUp + (1.0f - velocityFilter) * _filteredBrowUp; |
| 421 | 421 | _lastBrowUp = browUp; |
| @@ -438,11 +438,12 @@ void DdeFaceTracker::decodePacket(const QByteArray& buffer) { · 16 unmodified lines | ||
| 438 | 438 | |
| 439 | 439 | // Velocity filter EyeBlink values |
| 440 | 440 | const float DDE_EYEBLINK_SCALE = 3.0f; |
| 441 | − float eyeBlinks[] = { DDE_EYEBLINK_SCALE * _coefficients[_leftBlinkIndex], DDE_EYEBLINK_SCALE * _coefficients[_rightBlinkIndex] }; | |
| 441 | + float eyeBlinks[] = { DDE_EYEBLINK_SCALE * _coefficients[_leftBlinkIndex], | |
| 442 | + DDE_EYEBLINK_SCALE * _coefficients[_rightBlinkIndex] }; | |
| 442 | 443 | if (isFiltering) { |
| 443 | 444 | const float BLINK_VELOCITY_FILTER_STRENGTH = 0.3f; |
| 444 | 445 | for (int i = 0; i < 2; i++) { |
| 445 | − float velocity = fabs(eyeBlinks[i] - _lastEyeBlinks[i]) / _averageMessageTime; | |
| 446 | + float velocity = fabsf(eyeBlinks[i] - _lastEyeBlinks[i]) / _averageMessageTime; | |
| 446 | 447 | float velocityFilter = glm::clamp(velocity * BLINK_VELOCITY_FILTER_STRENGTH, 0.0f, 1.0f); |
| 447 | 448 | _filteredEyeBlinks[i] = velocityFilter * eyeBlinks[i] + (1.0f - velocityFilter) * _filteredEyeBlinks[i]; |
| 448 | 449 | _lastEyeBlinks[i] = eyeBlinks[i]; |
| @@ -479,9 +480,9 @@ void DdeFaceTracker::decodePacket(const QByteArray& buffer) { · 30 unmodified lines | ||
| 479 | 480 | if (_eyeStates[i] == EYE_CLOSING) { |
| 480 | 481 | // Close eyelid until it's fully closed |
| 481 | 482 | float closingValue = _lastEyeCoefficients[i] + EYELID_MOVEMENT_RATE * _averageMessageTime; |
| 482 | − if (closingValue >= 1.0) { | |
| 483 | + if (closingValue >= 1.0f) { | |
| 483 | 484 | _eyeStates[i] = EYE_CLOSED; |
| 484 | − eyeCoefficients[i] = 1.0; | |
| 485 | + eyeCoefficients[i] = 1.0f; | |
| 485 | 486 | } else { |
| 486 | 487 | eyeCoefficients[i] = closingValue; |
| 487 | 488 | } |
| @@ -11,13 +11,13 @@ · 10 unmodified lines | ||
| 11 | 11 | // |
| 12 | 12 | |
| 13 | 13 | #include "InterfaceConfig.h" |
| 14 | − | |
| 15 | 14 | #include "OculusManager.h" |
| 16 | 15 | #include "ui/overlays/Text3DOverlay.h" |
| 17 | 16 | |
| 17 | +#include <CursorManager.h> | |
| 18 | 18 | #include <QDesktopWidget> |
| 19 | 19 | #include <QGuiApplication> |
| 20 | −#include <QScreen> | |
| 20 | +#include <QScreen> | |
| 21 | 21 | #include <QOpenGLTimerQuery> |
| 22 | 22 | |
| 23 | 23 | #include <glm/glm.hpp> |
| @@ -25,6 +25,9 @@ · 1 unmodified line | ||
| 25 | 25 | #include <avatar/AvatarManager.h> |
| 26 | 26 | #include <avatar/MyAvatar.h> |
| 27 | 27 | #include <GlowEffect.h> |
| 28 | +#include <GlWindow.h> | |
| 29 | +#include <gpu/GLBackend.h> | |
| 30 | +#include <OglplusHelpers.h> | |
| 28 | 31 | #include <PathUtils.h> |
| 29 | 32 | #include <SharedUtil.h> |
| 30 | 33 | #include <UserActivityLogger.h> |
| @@ -34,8 +37,6 @@ · 3 unmodified lines | ||
| 34 | 37 | #include "InterfaceLogging.h" |
| 35 | 38 | #include "Application.h" |
| 36 | 39 | |
| 37 | −#include <gpu/GLBackend.h> | |
| 38 | − | |
| 39 | 40 | template <typename Function> |
| 40 | 41 | void for_each_eye(Function function) { |
| 41 | 42 | for (ovrEyeType eye = ovrEyeType::ovrEye_Left; |
| @@ -52,202 +53,413 @@ void for_each_eye(const ovrHmd & hmd, Function function) { · 10 unmodified lines | ||
| 52 | 53 | function(eye); |
| 53 | 54 | } |
| 54 | 55 | } |
| 56 | +enum CalibrationState { | |
| 57 | + UNCALIBRATED, | |
| 58 | + WAITING_FOR_DELTA, | |
| 59 | + WAITING_FOR_ZERO, | |
| 60 | + WAITING_FOR_ZERO_HELD, | |
| 61 | + CALIBRATED | |
| 62 | +}; | |
| 63 | + | |
| 64 | +inline glm::mat4 toGlm(const ovrMatrix4f & om) { | |
| 65 | + return glm::transpose(glm::make_mat4(&om.M[0][0])); | |
| 66 | +} | |
| 55 | 67 | |
| 56 | −#ifdef OVR_CLIENT_DISTORTION | |
| 57 | −ProgramObject OculusManager::_program; | |
| 58 | −int OculusManager::_textureLocation; | |
| 59 | −int OculusManager::_eyeToSourceUVScaleLocation; | |
| 60 | −int OculusManager::_eyeToSourceUVOffsetLocation; | |
| 61 | −int OculusManager::_eyeRotationStartLocation; | |
| 62 | −int OculusManager::_eyeRotationEndLocation; | |
| 63 | −int OculusManager::_positionAttributeLocation; | |
| 64 | −int OculusManager::_colorAttributeLocation; | |
| 65 | −int OculusManager::_texCoord0AttributeLocation; | |
| 66 | −int OculusManager::_texCoord1AttributeLocation; | |
| 67 | −int OculusManager::_texCoord2AttributeLocation; | |
| 68 | −ovrVector2f OculusManager::_UVScaleOffset[ovrEye_Count][2]; | |
| 69 | −GLuint OculusManager::_vertices[ovrEye_Count] = { 0, 0 }; | |
| 70 | −GLuint OculusManager::_indices[ovrEye_Count] = { 0, 0 }; | |
| 71 | −GLsizei OculusManager::_meshSize[ovrEye_Count] = { 0, 0 }; | |
| 72 | −ovrFrameTiming OculusManager::_hmdFrameTiming; | |
| 73 | −bool OculusManager::_programInitialized = false; | |
| 74 | −#endif | |
| 68 | +inline glm::mat4 toGlm(const ovrFovPort & fovport, float nearPlane = 0.01f, float farPlane = 10000.0f) { | |
| 69 | + return toGlm(ovrMatrix4f_Projection(fovport, nearPlane, farPlane, true)); | |
| 70 | +} | |
| 75 | 71 | |
| 76 | −ovrTexture OculusManager::_eyeTextures[ovrEye_Count]; | |
| 77 | −bool OculusManager::_isConnected = false; | |
| 78 | −ovrHmd OculusManager::_ovrHmd; | |
| 79 | −ovrFovPort OculusManager::_eyeFov[ovrEye_Count]; | |
| 80 | −ovrVector3f OculusManager::_eyeOffset[ovrEye_Count]; | |
| 81 | −ovrEyeRenderDesc OculusManager::_eyeRenderDesc[ovrEye_Count]; | |
| 82 | −ovrSizei OculusManager::_renderTargetSize; | |
| 83 | −glm::mat4 OculusManager::_eyeProjection[ovrEye_Count]; | |
| 84 | −unsigned int OculusManager::_frameIndex = 0; | |
| 85 | −bool OculusManager::_frameTimingActive = false; | |
| 86 | −Camera* OculusManager::_camera = NULL; | |
| 87 | −ovrEyeType OculusManager::_activeEye = ovrEye_Count; | |
| 88 | −bool OculusManager::_hswDismissed = false; | |
| 89 | − | |
| 90 | −float OculusManager::CALIBRATION_DELTA_MINIMUM_LENGTH = 0.02f; | |
| 91 | −float OculusManager::CALIBRATION_DELTA_MINIMUM_ANGLE = 5.0f * RADIANS_PER_DEGREE; | |
| 92 | −float OculusManager::CALIBRATION_ZERO_MAXIMUM_LENGTH = 0.01f; | |
| 93 | −float OculusManager::CALIBRATION_ZERO_MAXIMUM_ANGLE = 2.0f * RADIANS_PER_DEGREE; | |
| 94 | −quint64 OculusManager::CALIBRATION_ZERO_HOLD_TIME = 3000000; // usec | |
| 95 | −float OculusManager::CALIBRATION_MESSAGE_DISTANCE = 2.5f; | |
| 96 | −OculusManager::CalibrationState OculusManager::_calibrationState; | |
| 97 | −glm::vec3 OculusManager::_calibrationPosition; | |
| 98 | −glm::quat OculusManager::_calibrationOrientation; | |
| 99 | −quint64 OculusManager::_calibrationStartTime; | |
| 100 | −int OculusManager::_calibrationMessage = 0; | |
| 101 | −glm::vec3 OculusManager::_eyePositions[ovrEye_Count]; | |
| 102 | −// TODO expose this as a developer toggle | |
| 103 | −bool OculusManager::_eyePerFrameMode = false; | |
| 104 | −ovrEyeType OculusManager::_lastEyeRendered = ovrEye_Count; | |
| 105 | −ovrSizei OculusManager::_recommendedTexSize = { 0, 0 }; | |
| 106 | −float OculusManager::_offscreenRenderScale = 1.0; | |
| 72 | +inline glm::vec3 toGlm(const ovrVector3f & ov) { | |
| 73 | + return glm::make_vec3(&ov.x); | |
| 74 | +} | |
| 107 | 75 | |
| 76 | +inline glm::vec2 toGlm(const ovrVector2f & ov) { | |
| 77 | + return glm::make_vec2(&ov.x); | |
| 78 | +} | |
| 108 | 79 | |
| 109 | −void OculusManager::initSdk() { | |
| 110 | − ovr_Initialize(); | |
| 111 | − _ovrHmd = ovrHmd_Create(0); | |
| 112 | − if (!_ovrHmd) { | |
| 113 | − _ovrHmd = ovrHmd_CreateDebug(ovrHmd_DK2); | |
| 114 | − } | |
| 80 | +inline glm::ivec2 toGlm(const ovrVector2i & ov) { | |
| 81 | + return glm::ivec2(ov.x, ov.y); | |
| 115 | 82 | } |
| 116 | 83 | |
| 117 | −void OculusManager::shutdownSdk() { | |
| 118 | − if (_ovrHmd) { | |
| 119 | − ovrHmd_Destroy(_ovrHmd); | |
| 120 | − _ovrHmd = nullptr; | |
| 121 | − ovr_Shutdown(); | |
| 122 | − } | |
| 84 | +inline glm::uvec2 toGlm(const ovrSizei & ov) { | |
| 85 | + return glm::uvec2(ov.w, ov.h); | |
| 123 | 86 | } |
| 124 | 87 | |
| 125 | −void OculusManager::init() { | |
| 126 | −#ifdef OVR_DIRECT_MODE | |
| 127 | − initSdk(); | |
| 128 | −#endif | |
| 88 | +inline glm::quat toGlm(const ovrQuatf & oq) { | |
| 89 | + return glm::make_quat(&oq.x); | |
| 129 | 90 | } |
| 130 | 91 | |
| 131 | −void OculusManager::deinit() { | |
| 132 | −#ifdef OVR_DIRECT_MODE | |
| 133 | − shutdownSdk(); | |
| 134 | −#endif | |
| 92 | +inline glm::mat4 toGlm(const ovrPosef & op) { | |
| 93 | + glm::mat4 orientation = glm::mat4_cast(toGlm(op.Orientation)); | |
| 94 | + glm::mat4 translation = glm::translate(glm::mat4(), toGlm(op.Position)); | |
| 95 | + return translation * orientation; | |
| 135 | 96 | } |
| 136 | 97 | |
| 137 | −void OculusManager::connect() { | |
| 138 | −#ifndef OVR_DIRECT_MODE | |
| 139 | − initSdk(); | |
| 140 | −#endif | |
| 141 | − _calibrationState = UNCALIBRATED; | |
| 142 | − qCDebug(interfaceapp) << "Oculus SDK" << OVR_VERSION_STRING; | |
| 143 | − if (_ovrHmd) { | |
| 144 | − if (!_isConnected) { | |
| 145 | − UserActivityLogger::getInstance().connectedDevice("hmd", "oculus"); | |
| 98 | +inline ovrMatrix4f ovrFromGlm(const glm::mat4 & m) { | |
| 99 | + ovrMatrix4f result; | |
| 100 | + glm::mat4 transposed(glm::transpose(m)); | |
| 101 | + memcpy(result.M, &(transposed[0][0]), sizeof(float) * 16); | |
| 102 | + return result; | |
| 103 | +} | |
| 104 | + | |
| 105 | +inline ovrVector3f ovrFromGlm(const glm::vec3 & v) { | |
| 106 | + return{ v.x, v.y, v.z }; | |
| 107 | +} | |
| 108 | + | |
| 109 | +inline ovrVector2f ovrFromGlm(const glm::vec2 & v) { | |
| 110 | + return{ v.x, v.y }; | |
| 111 | +} | |
| 112 | + | |
| 113 | +inline ovrSizei ovrFromGlm(const glm::uvec2 & v) { | |
| 114 | + return{ (int)v.x, (int)v.y }; | |
| 115 | +} | |
| 116 | + | |
| 117 | +inline ovrQuatf ovrFromGlm(const glm::quat & q) { | |
| 118 | + return{ q.x, q.y, q.z, q.w }; | |
| 119 | +} | |
| 120 | + | |
| 121 | + | |
| 122 | + | |
| 123 | +#ifdef Q_OS_WIN | |
| 124 | + | |
| 125 | +// A base class for FBO wrappers that need to use the Oculus C | |
| 126 | +// API to manage textures via ovrHmd_CreateSwapTextureSetGL, | |
| 127 | +// ovrHmd_CreateMirrorTextureGL, etc | |
| 128 | +template <typename C> | |
| 129 | +struct RiftFramebufferWrapper : public FramebufferWrapper<C, char> { | |
| 130 | + ovrHmd hmd; | |
| 131 | + RiftFramebufferWrapper(const ovrHmd & hmd) : hmd(hmd) { | |
| 132 | + color = 0; | |
| 133 | + depth = 0; | |
| 134 | + }; | |
| 135 | + | |
| 136 | + void Resize(const uvec2 & size) { | |
| 137 | + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, oglplus::GetName(fbo)); | |
| 138 | + glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0); | |
| 139 | + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); | |
| 140 | + this->size = size; | |
| 141 | + initColor(); | |
| 142 | + initDone(); | |
| 143 | + } | |
| 144 | + | |
| 145 | +protected: | |
| 146 | + virtual void initDepth() override final { | |
| 147 | + } | |
| 148 | +}; | |
| 149 | + | |
| 150 | +// A wrapper for constructing and using a swap texture set, | |
| 151 | +// where each frame you draw to a texture via the FBO, | |
| 152 | +// then submit it and increment to the next texture. | |
| 153 | +// The Oculus SDK manages the creation and destruction of | |
| 154 | +// the textures | |
| 155 | +struct SwapFramebufferWrapper : public RiftFramebufferWrapper<ovrSwapTextureSet*> { | |
| 156 | + SwapFramebufferWrapper(const ovrHmd & hmd) | |
| 157 | + : RiftFramebufferWrapper(hmd) { | |
| 158 | + } | |
| 159 | + | |
| 160 | + ~SwapFramebufferWrapper() { | |
| 161 | + if (color) { | |
| 162 | + ovrHmd_DestroySwapTextureSet(hmd, color); | |
| 163 | + color = nullptr; | |
| 146 | 164 | } |
| 147 | − _isConnected = true; | |
| 148 | − | |
| 149 | − for_each_eye([&](ovrEyeType eye) { | |
| 150 | − _eyeFov[eye] = _ovrHmd->DefaultEyeFov[eye]; | |
| 151 | − }); | |
| 152 | − | |
| 153 | − ovrGLConfig cfg; | |
| 154 | − memset(&cfg, 0, sizeof(cfg)); | |
| 155 | − cfg.OGL.Header.API = ovrRenderAPI_OpenGL; | |
| 156 | − cfg.OGL.Header.BackBufferSize = _ovrHmd->Resolution; | |
| 157 | − cfg.OGL.Header.Multisample = 1; | |
| 158 | − | |
| 159 | − int distortionCaps = 0 | |
| 160 | − | ovrDistortionCap_Vignette | |
| 161 | − | ovrDistortionCap_Overdrive | |
| 162 | − | ovrDistortionCap_TimeWarp; | |
| 163 | − | |
| 164 | − int configResult = ovrHmd_ConfigureRendering(_ovrHmd, &cfg.Config, | |
| 165 | − distortionCaps, _eyeFov, _eyeRenderDesc); | |
| 166 | − assert(configResult); | |
| 167 | − | |
| 168 | − | |
| 169 | − _recommendedTexSize = ovrHmd_GetFovTextureSize(_ovrHmd, ovrEye_Left, _eyeFov[ovrEye_Left], 1.0f); | |
| 170 | − _renderTargetSize = { _recommendedTexSize.w * 2, _recommendedTexSize.h }; | |
| 171 | − for_each_eye([&](ovrEyeType eye) { | |
| 172 | − //Get texture size | |
| 173 | − _eyeTextures[eye].Header.API = ovrRenderAPI_OpenGL; | |
| 174 | − _eyeTextures[eye].Header.TextureSize = _renderTargetSize; | |
| 175 | − _eyeTextures[eye].Header.RenderViewport.Pos = { 0, 0 }; | |
| 176 | − }); | |
| 177 | − _eyeTextures[ovrEye_Right].Header.RenderViewport.Pos.x = _recommendedTexSize.w; | |
| 178 | − | |
| 179 | − ovrHmd_SetEnabledCaps(_ovrHmd, ovrHmdCap_LowPersistence | ovrHmdCap_DynamicPrediction); | |
| 180 | − | |
| 181 | − ovrHmd_ConfigureTracking(_ovrHmd, ovrTrackingCap_Orientation | ovrTrackingCap_Position | | |
| 182 | − ovrTrackingCap_MagYawCorrection, | |
| 183 | − ovrTrackingCap_Orientation); | |
| 184 | − | |
| 185 | − if (!_camera) { | |
| 186 | − _camera = new Camera; | |
| 187 | − configureCamera(*_camera); // no need to use screen dimensions; they're ignored | |
| 165 | + } | |
| 166 | + | |
| 167 | + void Increment() { | |
| 168 | + ++color->CurrentIndex; | |
| 169 | + color->CurrentIndex %= color->TextureCount; | |
| 170 | + } | |
| 171 | + | |
| 172 | +protected: | |
| 173 | + virtual void initColor() override { | |
| 174 | + if (color) { | |
| 175 | + ovrHmd_DestroySwapTextureSet(hmd, color); | |
| 176 | + color = nullptr; | |
| 177 | + } | |
| 178 | + | |
| 179 | + ovrResult result = ovrHmd_CreateSwapTextureSetGL(hmd, GL_RGBA, size.x, size.y, &color); | |
| 180 | + Q_ASSERT(OVR_SUCCESS(result)); | |
| 181 | + | |
| 182 | + for (int i = 0; i < color->TextureCount; ++i) { | |
| 183 | + ovrGLTexture& ovrTex = (ovrGLTexture&)color->Textures[i]; | |
| 184 | + glBindTexture(GL_TEXTURE_2D, ovrTex.OGL.TexId); | |
| 185 | + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); | |
| 186 | + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); | |
| 187 | + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); | |
| 188 | + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); | |
| 189 | + } | |
| 190 | + glBindTexture(GL_TEXTURE_2D, 0); | |
| 191 | + } | |
| 192 | + | |
| 193 | + virtual void initDone() override { | |
| 194 | + } | |
| 195 | + | |
| 196 | + virtual void onBind(oglplus::Framebuffer::Target target) override { | |
| 197 | + ovrGLTexture& tex = (ovrGLTexture&)(color->Textures[color->CurrentIndex]); | |
| 198 | + glFramebufferTexture2D(toEnum(target), GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tex.OGL.TexId, 0); | |
| 199 | + } | |
| 200 | + | |
| 201 | + virtual void onUnbind(oglplus::Framebuffer::Target target) override { | |
| 202 | + glFramebufferTexture2D(toEnum(target), GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0); | |
| 203 | + } | |
| 204 | +}; | |
| 205 | + | |
| 206 | + | |
| 207 | +// We use a FBO to wrap the mirror texture because it makes it easier to | |
| 208 | +// render to the screen via glBlitFramebuffer | |
| 209 | +struct MirrorFramebufferWrapper : public RiftFramebufferWrapper<ovrGLTexture*> { | |
| 210 | + MirrorFramebufferWrapper(const ovrHmd & hmd) | |
| 211 | + : RiftFramebufferWrapper(hmd) { | |
| 212 | + } | |
| 213 | + | |
| 214 | + virtual ~MirrorFramebufferWrapper() { | |
| 215 | + if (color) { | |
| 216 | + ovrHmd_DestroyMirrorTexture(hmd, (ovrTexture*)color); | |
| 217 | + color = nullptr; | |
| 188 | 218 | } |
| 189 | −#ifdef OVR_CLIENT_DISTORTION | |
| 190 | − if (!_programInitialized) { | |
| 191 | − // Shader program | |
| 192 | − _programInitialized = true; | |
| 193 | − _program.addShaderFromSourceFile(QGLShader::Vertex, PathUtils::resourcesPath() + "shaders/oculus.vert"); | |
| 194 | − _program.addShaderFromSourceFile(QGLShader::Fragment, PathUtils::resourcesPath() + "shaders/oculus.frag"); | |
| 195 | − _program.link(); | |
| 196 | − | |
| 197 | − // Uniforms | |
| 198 | − _textureLocation = _program.uniformLocation("texture"); | |
| 199 | − _eyeToSourceUVScaleLocation = _program.uniformLocation("EyeToSourceUVScale"); | |
| 200 | − _eyeToSourceUVOffsetLocation = _program.uniformLocation("EyeToSourceUVOffset"); | |
| 201 | − _eyeRotationStartLocation = _program.uniformLocation("EyeRotationStart"); | |
| 202 | − _eyeRotationEndLocation = _program.uniformLocation("EyeRotationEnd"); | |
| 203 | − | |
| 204 | − // Attributes | |
| 205 | − _positionAttributeLocation = _program.attributeLocation("position"); | |
| 206 | − _colorAttributeLocation = _program.attributeLocation("color"); | |
| 207 | − _texCoord0AttributeLocation = _program.attributeLocation("texCoord0"); | |
| 208 | − _texCoord1AttributeLocation = _program.attributeLocation("texCoord1"); | |
| 209 | − _texCoord2AttributeLocation = _program.attributeLocation("texCoord2"); | |
| 219 | + } | |
| 220 | + | |
| 221 | +private: | |
| 222 | + void initColor() override { | |
| 223 | + if (color) { | |
| 224 | + ovrHmd_DestroyMirrorTexture(hmd, (ovrTexture*)color); | |
| 225 | + color = nullptr; | |
| 210 | 226 | } |
| 227 | + ovrResult result = ovrHmd_CreateMirrorTextureGL(hmd, GL_RGBA, size.x, size.y, (ovrTexture**)&color); | |
| 228 | + Q_ASSERT(OVR_SUCCESS(result)); | |
| 229 | + } | |
| 230 | + | |
| 231 | + void initDone() override { | |
| 232 | + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, oglplus::GetName(fbo)); | |
| 233 | + glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, color->OGL.TexId, 0); | |
| 234 | + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); | |
| 235 | + } | |
| 236 | +}; | |
| 237 | + | |
| 238 | +static SwapFramebufferWrapper* _swapFbo{ nullptr }; | |
| 239 | +static MirrorFramebufferWrapper* _mirrorFbo{ nullptr }; | |
| 240 | +static ovrLayerEyeFov _sceneLayer; | |
| 241 | + | |
| 242 | +#else | |
| 243 | + | |
| 244 | +static ovrTexture _eyeTextures[ovrEye_Count]; | |
| 245 | +static GlWindow* _outputWindow{ nullptr }; | |
| 211 | 246 | |
| 212 | − //Generate the distortion VBOs | |
| 213 | − generateDistortionMesh(); | |
| 214 | 247 | #endif |
| 215 | − } else { | |
| 248 | + | |
| 249 | +static bool _isConnected = false; | |
| 250 | +static ovrHmd _ovrHmd; | |
| 251 | +static ovrFovPort _eyeFov[ovrEye_Count]; | |
| 252 | +static ovrVector3f _eyeOffset[ovrEye_Count]; | |
| 253 | +static ovrEyeRenderDesc _eyeRenderDesc[ovrEye_Count]; | |
| 254 | +static ovrSizei _renderTargetSize; | |
| 255 | +static glm::mat4 _eyeProjection[ovrEye_Count]; | |
| 256 | +static unsigned int _frameIndex = 0; | |
| 257 | +static bool _frameTimingActive = false; | |
| 258 | +static Camera* _camera = NULL; | |
| 259 | +static ovrEyeType _activeEye = ovrEye_Count; | |
| 260 | +static bool _hswDismissed = false; | |
| 261 | + | |
| 262 | +static const float CALIBRATION_DELTA_MINIMUM_LENGTH = 0.02f; | |
| 263 | +static const float CALIBRATION_DELTA_MINIMUM_ANGLE = 5.0f * RADIANS_PER_DEGREE; | |
| 264 | +static const float CALIBRATION_ZERO_MAXIMUM_LENGTH = 0.01f; | |
| 265 | +static const float CALIBRATION_ZERO_MAXIMUM_ANGLE = 2.0f * RADIANS_PER_DEGREE; | |
| 266 | +static const quint64 CALIBRATION_ZERO_HOLD_TIME = 3000000; // usec | |
| 267 | +static const float CALIBRATION_MESSAGE_DISTANCE = 2.5f; | |
| 268 | +static CalibrationState _calibrationState; | |
| 269 | +static glm::vec3 _calibrationPosition; | |
| 270 | +static glm::quat _calibrationOrientation; | |
| 271 | +static quint64 _calibrationStartTime; | |
| 272 | +static int _calibrationMessage = 0; | |
| 273 | +static glm::vec3 _eyePositions[ovrEye_Count]; | |
| 274 | +// TODO expose this as a developer toggle | |
| 275 | +static bool _eyePerFrameMode = false; | |
| 276 | +static ovrEyeType _lastEyeRendered = ovrEye_Count; | |
| 277 | +static ovrSizei _recommendedTexSize = { 0, 0 }; | |
| 278 | +static float _offscreenRenderScale = 1.0; | |
| 279 | +static glm::mat4 _combinedProjection; | |
| 280 | +static ovrPosef _eyeRenderPoses[ovrEye_Count]; | |
| 281 | +static ovrRecti _eyeViewports[ovrEye_Count]; | |
| 282 | +static ovrVector3f _eyeOffsets[ovrEye_Count]; | |
| 283 | + | |
| 284 | +glm::vec3 OculusManager::getLeftEyePosition() { return _eyePositions[ovrEye_Left]; } | |
| 285 | +glm::vec3 OculusManager::getRightEyePosition() { return _eyePositions[ovrEye_Right]; } | |
| 286 | + | |
| 287 | +void OculusManager::connect(QOpenGLContext* shareContext) { | |
| 288 | + qCDebug(interfaceapp) << "Oculus SDK" << OVR_VERSION_STRING; | |
| 289 | + | |
| 290 | + ovrInitParams initParams; memset(&initParams, 0, sizeof(initParams)); | |
| 291 | + | |
| 292 | +#ifdef DEBUG | |
| 293 | + initParams.Flags |= ovrInit_Debug; | |
| 294 | +#endif | |
| 295 | + | |
| 296 | + ovr_Initialize(&initParams); | |
| 297 | + | |
| 298 | +#ifdef Q_OS_WIN | |
| 299 | + | |
| 300 | + ovrResult res = ovrHmd_Create(0, &_ovrHmd); | |
| 301 | +#ifdef DEBUG | |
| 302 | + if (!OVR_SUCCESS(res)) { | |
| 303 | + res = ovrHmd_CreateDebug(ovrHmd_DK2, &_ovrHmd); | |
| 304 | + Q_ASSERT(OVR_SUCCESS(res)); | |
| 305 | + } | |
| 306 | +#endif | |
| 307 | + | |
| 308 | +#else | |
| 309 | + | |
| 310 | + _ovrHmd = ovrHmd_Create(0); | |
| 311 | +#ifdef DEBUG | |
| 312 | + if (!_ovrHmd) { | |
| 313 | + _ovrHmd = ovrHmd_CreateDebug(ovrHmd_DK2); | |
| 314 | + } | |
| 315 | +#endif | |
| 316 | + | |
| 317 | +#endif | |
| 318 | + | |
| 319 | + if (!_ovrHmd) { | |
| 216 | 320 | _isConnected = false; |
| 217 | − | |
| 321 | + | |
| 218 | 322 | // we're definitely not in "VR mode" so tell the menu that |
| 219 | 323 | Menu::getInstance()->getActionForOption(MenuOption::EnableVRMode)->setChecked(false); |
| 324 | + ovr_Shutdown(); | |
| 325 | + return; | |
| 326 | + } | |
| 327 | + | |
| 328 | + _calibrationState = UNCALIBRATED; | |
| 329 | + if (!_isConnected) { | |
| 330 | + UserActivityLogger::getInstance().connectedDevice("hmd", "oculus"); | |
| 331 | + } | |
| 332 | + _isConnected = true; | |
| 333 | + | |
| 334 | + for_each_eye([&](ovrEyeType eye) { | |
| 335 | + _eyeFov[eye] = _ovrHmd->DefaultEyeFov[eye]; | |
| 336 | + _eyeProjection[eye] = toGlm(ovrMatrix4f_Projection(_eyeFov[eye], | |
| 337 | + DEFAULT_NEAR_CLIP, DEFAULT_FAR_CLIP, ovrProjection_RightHanded)); | |
| 338 | + ovrEyeRenderDesc erd = ovrHmd_GetRenderDesc(_ovrHmd, eye, _eyeFov[eye]); | |
| 339 | + _eyeOffsets[eye] = erd.HmdToEyeViewOffset; | |
| 340 | + }); | |
| 341 | + ovrFovPort combinedFov = _ovrHmd->MaxEyeFov[0]; | |
| 342 | + combinedFov.RightTan = _ovrHmd->MaxEyeFov[1].RightTan; | |
| 343 | + _combinedProjection = toGlm(ovrMatrix4f_Projection(combinedFov, | |
| 344 | + DEFAULT_NEAR_CLIP, DEFAULT_FAR_CLIP, ovrProjection_RightHanded)); | |
| 345 | + | |
| 346 | + _recommendedTexSize = ovrHmd_GetFovTextureSize(_ovrHmd, ovrEye_Left, _eyeFov[ovrEye_Left], 1.0f); | |
| 347 | + _renderTargetSize = { _recommendedTexSize.w * 2, _recommendedTexSize.h }; | |
| 348 | + | |
| 349 | +#ifdef Q_OS_WIN | |
| 350 | + | |
| 351 | + _mirrorFbo = new MirrorFramebufferWrapper(_ovrHmd); | |
| 352 | + _swapFbo = new SwapFramebufferWrapper(_ovrHmd); | |
| 353 | + _swapFbo->Init(toGlm(_renderTargetSize)); | |
| 354 | + _sceneLayer.ColorTexture[0] = _swapFbo->color; | |
| 355 | + _sceneLayer.ColorTexture[1] = nullptr; | |
| 356 | + _sceneLayer.Viewport[0].Pos = { 0, 0 }; | |
| 357 | + _sceneLayer.Viewport[0].Size = _recommendedTexSize; | |
| 358 | + _sceneLayer.Viewport[1].Pos = { _recommendedTexSize.w, 0 }; | |
| 359 | + _sceneLayer.Viewport[1].Size = _recommendedTexSize; | |
| 360 | + _sceneLayer.Header.Type = ovrLayerType_EyeFov; | |
| 361 | + _sceneLayer.Header.Flags = ovrLayerFlag_TextureOriginAtBottomLeft; | |
| 362 | + for_each_eye([&](ovrEyeType eye) { | |
| 363 | + _eyeViewports[eye] = _sceneLayer.Viewport[eye]; | |
| 364 | + _sceneLayer.Fov[eye] = _eyeFov[eye]; | |
| 365 | + }); | |
| 366 | + | |
| 367 | + | |
| 368 | + | |
| 369 | +#else | |
| 370 | + _outputWindow = new GlWindow(shareContext); | |
| 371 | + _outputWindow->show(); | |
| 372 | +// _outputWindow->setFlags(Qt::FramelessWindowHint ); | |
| 373 | +// _outputWindow->resize(_ovrHmd->Resolution.w, _ovrHmd->Resolution.h); | |
| 374 | +// _outputWindow->setPosition(_ovrHmd->WindowsPos.x, _ovrHmd->WindowsPos.y); | |
| 375 | + ivec2 desiredPosition = toGlm(_ovrHmd->WindowsPos); | |
| 376 | + foreach(QScreen* screen, qGuiApp->screens()) { | |
| 377 | + ivec2 screenPosition = toGlm(screen->geometry().topLeft()); | |
| 378 | + if (screenPosition == desiredPosition) { | |
| 379 | + _outputWindow->setScreen(screen); | |
| 380 | + break; | |
| 381 | + } | |
| 382 | + } | |
| 383 | + _outputWindow->showFullScreen(); | |
| 384 | + _outputWindow->makeCurrent(); | |
| 385 | + | |
| 386 | + ovrGLConfig cfg; | |
| 387 | + memset(&cfg, 0, sizeof(cfg)); | |
| 388 | + cfg.OGL.Header.API = ovrRenderAPI_OpenGL; | |
| 389 | + cfg.OGL.Header.BackBufferSize = _ovrHmd->Resolution; | |
| 390 | + cfg.OGL.Header.Multisample = 0; | |
| 391 | + | |
| 392 | + int distortionCaps = 0 | |
| 393 | + | ovrDistortionCap_Vignette | |
| 394 | + | ovrDistortionCap_Overdrive | |
| 395 | + | ovrDistortionCap_TimeWarp; | |
| 396 | + | |
| 397 | + int configResult = ovrHmd_ConfigureRendering(_ovrHmd, &cfg.Config, | |
| 398 | + distortionCaps, _eyeFov, _eyeRenderDesc); | |
| 399 | + assert(configResult); | |
| 400 | + _outputWindow->doneCurrent(); | |
| 401 | + | |
| 402 | + for_each_eye([&](ovrEyeType eye) { | |
| 403 | + //Get texture size | |
| 404 | + _eyeTextures[eye].Header.API = ovrRenderAPI_OpenGL; | |
| 405 | + _eyeTextures[eye].Header.TextureSize = _renderTargetSize; | |
| 406 | + _eyeTextures[eye].Header.RenderViewport.Pos = { 0, 0 }; | |
| 407 | + _eyeTextures[eye].Header.RenderViewport.Size = _renderTargetSize; | |
| 408 | + _eyeTextures[eye].Header.RenderViewport.Size.w /= 2; | |
| 409 | + }); | |
| 410 | + _eyeTextures[ovrEye_Right].Header.RenderViewport.Pos.x = _recommendedTexSize.w; | |
| 411 | + for_each_eye([&](ovrEyeType eye) { | |
| 412 | + _eyeViewports[eye] = _eyeTextures[eye].Header.RenderViewport; | |
| 413 | + }); | |
| 414 | +#endif | |
| 415 | + | |
| 416 | + ovrHmd_SetEnabledCaps(_ovrHmd, | |
| 417 | + ovrHmdCap_LowPersistence | ovrHmdCap_DynamicPrediction); | |
| 418 | + | |
| 419 | + ovrHmd_ConfigureTracking(_ovrHmd, | |
| 420 | + ovrTrackingCap_Orientation | ovrTrackingCap_Position | ovrTrackingCap_MagYawCorrection, | |
| 421 | + ovrTrackingCap_Orientation); | |
| 422 | + | |
| 423 | + if (!_camera) { | |
| 424 | + _camera = new Camera; | |
| 425 | + configureCamera(*_camera); // no need to use screen dimensions; they're ignored | |
| 220 | 426 | } |
| 221 | 427 | } |
| 222 | 428 | |
| 223 | 429 | //Disconnects and deallocates the OR |
| 224 | 430 | void OculusManager::disconnect() { |
| 225 | 431 | if (_isConnected) { |
| 432 | + | |
| 433 | +#ifdef Q_OS_WIN | |
| 434 | + if (_swapFbo) { | |
| 435 | + delete _swapFbo; | |
| 436 | + _swapFbo = nullptr; | |
| 437 | + } | |
| 438 | + | |
| 439 | + if (_mirrorFbo) { | |
| 440 | + delete _mirrorFbo; | |
| 441 | + _mirrorFbo = nullptr; | |
| 442 | + } | |
| 443 | +#else | |
| 444 | + _outputWindow->showNormal(); | |
| 445 | + _outputWindow->deleteLater(); | |
| 446 | + _outputWindow = nullptr; | |
| 447 | +#endif | |
| 448 | + | |
| 449 | + if (_ovrHmd) { | |
| 450 | + ovrHmd_Destroy(_ovrHmd); | |
| 451 | + _ovrHmd = nullptr; | |
| 452 | + } | |
| 453 | + ovr_Shutdown(); | |
| 454 | + | |
| 226 | 455 | _isConnected = false; |
| 227 | 456 | // Prepare to potentially have to dismiss the HSW again |
| 228 | 457 | // if the user re-enables VR |
| 229 | 458 | _hswDismissed = false; |
| 230 | −#ifndef OVR_DIRECT_MODE | |
| 231 | − shutdownSdk(); | |
| 232 | −#endif | |
| 233 | − | |
| 234 | −#ifdef OVR_CLIENT_DISTORTION | |
| 235 | − //Free the distortion mesh data | |
| 236 | − for (int i = 0; i < ovrEye_Count; i++) { | |
| 237 | − if (_vertices[i] != 0) { | |
| 238 | − glDeleteBuffers(1, &(_vertices[i])); | |
| 239 | − _vertices[i] = 0; | |
| 240 | − } | |
| 241 | − if (_indices[i] != 0) { | |
| 242 | − glDeleteBuffers(1, &(_indices[i])); | |
| 243 | − _indices[i] = 0; | |
| 244 | − } | |
| 245 | − } | |
| 246 | −#endif | |
| 247 | 459 | } |
| 248 | 460 | } |
| 249 | 461 | |
| 250 | −void OculusManager::positionCalibrationBillboard(Text3DOverlay* billboard) { | |
| 462 | +void positionCalibrationBillboard(Text3DOverlay* billboard) { | |
| 251 | 463 | MyAvatar* myAvatar = DependencyManager::get<AvatarManager>()->getMyAvatar(); |
| 252 | 464 | glm::quat headOrientation = myAvatar->getHeadOrientation(); |
| 253 | 465 | headOrientation.x = 0; |
| @@ -258,7 +470,7 @@ void OculusManager::positionCalibrationBillboard(Text3DOverlay* billboard) { · 4 unmodified lines | ||
| 258 | 470 | billboard->setRotation(headOrientation); |
| 259 | 471 | } |
| 260 | 472 | |
| 261 | −void OculusManager::calibrate(glm::vec3 position, glm::quat orientation) { | |
| 473 | +void calibrate(const glm::vec3& position, const glm::quat& orientation) { | |
| 262 | 474 | static QString instructionMessage = "Hold still to calibrate"; |
| 263 | 475 | static QString progressMessage; |
| 264 | 476 | static Text3DOverlay* billboard; |
| @@ -346,7 +558,7 @@ void OculusManager::calibrate(glm::vec3 position, glm::quat orientation) { · 81 unmodified lines | ||
| 346 | 558 | break; |
| 347 | 559 | default: |
| 348 | 560 | break; |
| 349 | − | |
| 561 | + | |
| 350 | 562 | } |
| 351 | 563 | } |
| 352 | 564 | |
| @@ -363,64 +575,9 @@ void OculusManager::abandonCalibration() { · 10 unmodified lines | ||
| 363 | 575 | } |
| 364 | 576 | } |
| 365 | 577 | |
| 366 | −#ifdef OVR_CLIENT_DISTORTION | |
| 367 | −void OculusManager::generateDistortionMesh() { | |
| 368 | − | |
| 369 | − //Check if we already have the distortion mesh | |
| 370 | − if (_vertices[0] != 0) { | |
| 371 | − printf("WARNING: Tried to generate Oculus distortion mesh twice without freeing the VBOs."); | |
| 372 | − return; | |
| 373 | − } | |
| 374 | − | |
| 375 | − for (int eyeNum = 0; eyeNum < ovrEye_Count; eyeNum++) { | |
| 376 | − // Allocate and generate distortion mesh vertices | |
| 377 | − ovrDistortionMesh meshData; | |
| 378 | − ovrHmd_CreateDistortionMesh(_ovrHmd, _eyeRenderDesc[eyeNum].Eye, _eyeRenderDesc[eyeNum].Fov, _ovrHmd->DistortionCaps, &meshData); | |
| 379 | − | |
| 380 | − // Parse the vertex data and create a render ready vertex buffer | |
| 381 | − DistortionVertex* pVBVerts = new DistortionVertex[meshData.VertexCount]; | |
| 382 | − _meshSize[eyeNum] = meshData.IndexCount; | |
| 383 | − | |
| 384 | − // Convert the oculus vertex data to the DistortionVertex format. | |
| 385 | − DistortionVertex* v = pVBVerts; | |
| 386 | − ovrDistortionVertex* ov = meshData.pVertexData; | |
| 387 | − for (unsigned int vertNum = 0; vertNum < meshData.VertexCount; vertNum++) { | |
| 388 | − v->pos.x = ov->ScreenPosNDC.x; | |
| 389 | − v->pos.y = ov->ScreenPosNDC.y; | |
| 390 | − v->texR.x = ov->TanEyeAnglesR.x; | |
| 391 | − v->texR.y = ov->TanEyeAnglesR.y; | |
| 392 | − v->texG.x = ov->TanEyeAnglesG.x; | |
| 393 | − v->texG.y = ov->TanEyeAnglesG.y; | |
| 394 | − v->texB.x = ov->TanEyeAnglesB.x; | |
| 395 | − v->texB.y = ov->TanEyeAnglesB.y; | |
| 396 | − v->color.r = v->color.g = v->color.b = (GLubyte)(ov->VignetteFactor * 255.99f); | |
| 397 | − v->color.a = (GLubyte)(ov->TimeWarpFactor * 255.99f); | |
| 398 | − v++; | |
| 399 | − ov++; | |
| 400 | − } | |
| 401 | − | |
| 402 | − //vertices | |
| 403 | − glGenBuffers(1, &(_vertices[eyeNum])); | |
| 404 | − glBindBuffer(GL_ARRAY_BUFFER, _vertices[eyeNum]); | |
| 405 | − glBufferData(GL_ARRAY_BUFFER, sizeof(DistortionVertex) * meshData.VertexCount, pVBVerts, GL_STATIC_DRAW); | |
| 406 | − glBindBuffer(GL_ARRAY_BUFFER, 0); | |
| 407 | − | |
| 408 | − //indices | |
| 409 | − glGenBuffers(1, &(_indices[eyeNum])); | |
| 410 | − glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _indices[eyeNum]); | |
| 411 | − glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(unsigned short) * meshData.IndexCount, meshData.pIndexData, GL_STATIC_DRAW); | |
| 412 | − glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); | |
| 413 | − | |
| 414 | − //Now that we have the VBOs we can get rid of the mesh data | |
| 415 | − delete [] pVBVerts; | |
| 416 | − ovrHmd_DestroyDistortionMesh(&meshData); | |
| 417 | − } | |
| 418 | − | |
| 419 | −} | |
| 420 | −#endif | |
| 421 | 578 | |
| 422 | 579 | bool OculusManager::isConnected() { |
| 423 | − return _isConnected && Menu::getInstance()->isOptionChecked(MenuOption::EnableVRMode); | |
| 580 | + return _isConnected; | |
| 424 | 581 | } |
| 425 | 582 | |
| 426 | 583 | //Begins the frame timing for oculus prediction purposes |
| @@ -428,10 +585,6 @@ void OculusManager::beginFrameTiming() { · 1 unmodified line | ||
| 428 | 585 | if (_frameTimingActive) { |
| 429 | 586 | printf("WARNING: Called OculusManager::beginFrameTiming() twice in a row, need to call OculusManager::endFrameTiming()."); |
| 430 | 587 | } |
| 431 | − | |
| 432 | −#ifdef OVR_CLIENT_DISTORTION | |
| 433 | − _hmdFrameTiming = ovrHmd_BeginFrameTiming(_ovrHmd, _frameIndex); | |
| 434 | −#endif | |
| 435 | 588 | _frameTimingActive = true; |
| 436 | 589 | } |
| 437 | 590 | |
| @@ -441,27 +594,18 @@ bool OculusManager::allowSwap() { · 3 unmodified lines | ||
| 441 | 594 | |
| 442 | 595 | //Ends frame timing |
| 443 | 596 | void OculusManager::endFrameTiming() { |
| 444 | −#ifdef OVR_CLIENT_DISTORTION | |
| 445 | − ovrHmd_EndFrameTiming(_ovrHmd); | |
| 446 | −#endif | |
| 447 | 597 | _frameIndex++; |
| 448 | 598 | _frameTimingActive = false; |
| 449 | 599 | } |
| 450 | 600 | |
| 451 | 601 | //Sets the camera FoV and aspect ratio |
| 452 | 602 | void OculusManager::configureCamera(Camera& camera) { |
| 453 | − ovrFovPort fov; | |
| 454 | 603 | if (_activeEye == ovrEye_Count) { |
| 455 | 604 | // When not rendering, provide a FOV encompasing both eyes |
| 456 | − fov = _eyeFov[0]; | |
| 457 | − fov.RightTan = _eyeFov[1].RightTan; | |
| 458 | − } else { | |
| 459 | − // When rendering, provide the exact FOV | |
| 460 | − fov = _eyeFov[_activeEye]; | |
| 461 | − } | |
| 462 | − // Convert the FOV to the correct projection matrix | |
| 463 | − glm::mat4 projection = toGlm(ovrMatrix4f_Projection(fov, DEFAULT_NEAR_CLIP, DEFAULT_FAR_CLIP, ovrProjection_RightHanded)); | |
| 464 | − camera.setProjection(projection); | |
| 605 | + camera.setProjection(_combinedProjection); | |
| 606 | + return; | |
| 607 | + } | |
| 608 | + camera.setProjection(_eyeProjection[_activeEye]); | |
| 465 | 609 | } |
| 466 | 610 | |
| 467 | 611 | //Displays everything for the oculus, frame timing must be active |
| @@ -473,40 +617,9 @@ void OculusManager::display(QGLWidget * glCanvas, RenderArgs* renderArgs, const · 5 unmodified lines | ||
| 473 | 617 | assert(oldFrameIndex == -1 || (unsigned int)oldFrameIndex == _frameIndex - 1); |
| 474 | 618 | oldFrameIndex = _frameIndex; |
| 475 | 619 | #endif |
| 476 | − | |
| 477 | − // Every so often do some additional timing calculations and debug output | |
| 478 | − bool debugFrame = 0 == _frameIndex % 400; | |
| 479 | 620 | |
| 480 | −#if 0 | |
| 481 | − // Try to measure the amount of time taken to do the distortion | |
| 482 | − // (does not seem to work on OSX with SDK based distortion) | |
| 483 | − // FIXME can't use a static object here, because it will cause a crash when the | |
| 484 | − // query attempts deconstruct after the GL context is gone. | |
| 485 | − static bool timerActive = false; | |
| 486 | − static QOpenGLTimerQuery timerQuery; | |
| 487 | − if (!timerQuery.isCreated()) { | |
| 488 | − timerQuery.create(); | |
| 489 | − } | |
| 490 | − | |
| 491 | − if (timerActive && timerQuery.isResultAvailable()) { | |
| 492 | − auto result = timerQuery.waitForResult(); | |
| 493 | − if (result) { qCDebug(interfaceapp) << "Distortion took " << result << "ns"; }; | |
| 494 | − timerActive = false; | |
| 495 | − } | |
| 496 | −#endif | |
| 497 | − | |
| 498 | −#ifdef OVR_DIRECT_MODE | |
| 499 | − static bool attached = false; | |
| 500 | − if (!attached) { | |
| 501 | − attached = true; | |
| 502 | − void * nativeWindowHandle = (void*)(size_t)glCanvas->effectiveWinId(); | |
| 503 | − if (nullptr != nativeWindowHandle) { | |
| 504 | − ovrHmd_AttachToWindow(_ovrHmd, nativeWindowHandle, nullptr, nullptr); | |
| 505 | − } | |
| 506 | − } | |
| 507 | −#endif | |
| 508 | − | |
| 509 | −#ifndef OVR_CLIENT_DISTORTION | |
| 621 | +#ifndef Q_OS_WIN | |
| 622 | + | |
| 510 | 623 | // FIXME: we need a better way of responding to the HSW. In particular |
| 511 | 624 | // we need to ensure that it's only displayed once per session, rather than |
| 512 | 625 | // every time the user toggles VR mode, and we need to hook it up to actual |
| @@ -522,7 +635,7 @@ void OculusManager::display(QGLWidget * glCanvas, RenderArgs* renderArgs, const · 9 unmodified lines | ||
| 522 | 635 | } |
| 523 | 636 | } |
| 524 | 637 | #endif |
| 525 | − | |
| 638 | + | |
| 526 | 639 | |
| 527 | 640 | //beginFrameTiming must be called before display |
| 528 | 641 | if (!_frameTimingActive) { |
| @@ -545,14 +658,14 @@ void OculusManager::display(QGLWidget * glCanvas, RenderArgs* renderArgs, const · 16 unmodified lines | ||
| 545 | 658 | |
| 546 | 659 | glMatrixMode(GL_MODELVIEW); |
| 547 | 660 | glPushMatrix(); |
| 548 | − | |
| 661 | + | |
| 549 | 662 | glm::quat orientation; |
| 550 | 663 | glm::vec3 trackerPosition; |
| 551 | 664 | auto deviceSize = qApp->getDeviceSize(); |
| 552 | 665 | |
| 553 | 666 | ovrTrackingState ts = ovrHmd_GetTrackingState(_ovrHmd, ovr_GetTimeInSeconds()); |
| 554 | 667 | ovrVector3f ovrHeadPosition = ts.HeadPose.ThePose.Position; |
| 555 | − | |
| 668 | + | |
| 556 | 669 | trackerPosition = glm::vec3(ovrHeadPosition.x, ovrHeadPosition.y, ovrHeadPosition.z); |
| 557 | 670 | |
| 558 | 671 | if (_calibrationState != CALIBRATED) { |
| @@ -562,11 +675,11 @@ void OculusManager::display(QGLWidget * glCanvas, RenderArgs* renderArgs, const · 3 unmodified lines | ||
| 562 | 675 | } |
| 563 | 676 | |
| 564 | 677 | trackerPosition = bodyOrientation * trackerPosition; |
| 565 | − static ovrVector3f eyeOffsets[2] = { { 0, 0, 0 }, { 0, 0, 0 } }; | |
| 566 | 678 | ovrPosef eyePoses[ovrEye_Count]; |
| 567 | − ovrHmd_GetEyePoses(_ovrHmd, _frameIndex, eyeOffsets, eyePoses, nullptr); | |
| 679 | + ovrHmd_GetEyePoses(_ovrHmd, _frameIndex, _eyeOffsets, eyePoses, nullptr); | |
| 680 | +#ifndef Q_OS_WIN | |
| 568 | 681 | ovrHmd_BeginFrame(_ovrHmd, _frameIndex); |
| 569 | − static ovrPosef eyeRenderPose[ovrEye_Count]; | |
| 682 | +#endif | |
| 570 | 683 | //Render each eye into an fbo |
| 571 | 684 | for_each_eye(_ovrHmd, [&](ovrEyeType eye){ |
| 572 | 685 | // If we're in eye-per-frame mode, only render one eye |
| @@ -576,29 +689,17 @@ void OculusManager::display(QGLWidget * glCanvas, RenderArgs* renderArgs, const · 3 unmodified lines | ||
| 576 | 689 | return; |
| 577 | 690 | } |
| 578 | 691 | _lastEyeRendered = _activeEye = eye; |
| 579 | − eyeRenderPose[eye] = eyePoses[eye]; | |
| 692 | + _eyeRenderPoses[eye] = eyePoses[eye]; | |
| 580 | 693 | // Set the camera rotation for this eye |
| 581 | − orientation.x = eyeRenderPose[eye].Orientation.x; | |
| 582 | − orientation.y = eyeRenderPose[eye].Orientation.y; | |
| 583 | − orientation.z = eyeRenderPose[eye].Orientation.z; | |
| 584 | − orientation.w = eyeRenderPose[eye].Orientation.w; | |
| 585 | − | |
| 586 | − // Update the application camera with the latest HMD position | |
| 587 | − whichCamera.setHmdPosition(trackerPosition); | |
| 588 | − whichCamera.setHmdRotation(orientation); | |
| 589 | − | |
| 590 | 694 | |
| 695 | + vec3 eyePosition = toGlm(_eyeRenderPoses[eye].Position); | |
| 696 | + eyePosition = whichCamera.getRotation() * eyePosition; | |
| 697 | + quat eyeRotation = toGlm(_eyeRenderPoses[eye].Orientation); | |
| 698 | + | |
| 591 | 699 | // Update our camera to what the application camera is doing |
| 592 | − _camera->setRotation(whichCamera.getRotation()); | |
| 593 | − _camera->setPosition(whichCamera.getPosition()); | |
| 700 | + _camera->setRotation(whichCamera.getRotation() * eyeRotation); | |
| 701 | + _camera->setPosition(whichCamera.getPosition() + eyePosition); | |
| 594 | 702 | configureCamera(*_camera); |
| 595 | − | |
| 596 | − // Store the latest left and right eye render locations for things that need to know | |
| 597 | − glm::vec3 thisEyePosition = position + trackerPosition + | |
| 598 | − (bodyOrientation * glm::quat(orientation.x, orientation.y, orientation.z, orientation.w) * | |
| 599 | − glm::vec3(_eyeRenderDesc[eye].HmdToEyeViewOffset.x, _eyeRenderDesc[eye].HmdToEyeViewOffset.y, _eyeRenderDesc[eye].HmdToEyeViewOffset.z)); | |
| 600 | − | |
| 601 | − _eyePositions[eye] = thisEyePosition; | |
| 602 | 703 | _camera->update(1.0f / Application::getInstance()->getFps()); |
| 603 | 704 | |
| 604 | 705 | glMatrixMode(GL_PROJECTION); |
| @@ -607,15 +708,14 @@ void OculusManager::display(QGLWidget * glCanvas, RenderArgs* renderArgs, const · 2 unmodified lines | ||
| 607 | 708 | glMatrixMode(GL_MODELVIEW); |
| 608 | 709 | glLoadIdentity(); |
| 609 | 710 | |
| 610 | − ovrRecti & vp = _eyeTextures[eye].Header.RenderViewport; | |
| 711 | + ovrRecti & vp = _eyeViewports[eye]; | |
| 611 | 712 | vp.Size.h = _recommendedTexSize.h * _offscreenRenderScale; |
| 612 | 713 | vp.Size.w = _recommendedTexSize.w * _offscreenRenderScale; |
| 613 | − | |
| 614 | 714 | glViewport(vp.Pos.x, vp.Pos.y, vp.Size.w, vp.Size.h); |
| 615 | 715 | |
| 616 | 716 | renderArgs->_renderSide = RenderArgs::MONO; |
| 617 | − qApp->displaySide(renderArgs, *_camera, false); | |
| 618 | − qApp->getApplicationOverlay().displayOverlayTextureHmd(*_camera); | |
| 717 | + qApp->displaySide(renderArgs, *_camera); | |
| 718 | + qApp->getApplicationCompositor().displayOverlayTextureHmd(renderArgs, eye); | |
| 619 | 719 | }); |
| 620 | 720 | _activeEye = ovrEye_Count; |
| 621 | 721 | |
| @@ -628,7 +728,7 @@ void OculusManager::display(QGLWidget * glCanvas, RenderArgs* renderArgs, const · 6 unmodified lines | ||
| 628 | 728 | glViewport(0, 0, _renderTargetSize.w, _renderTargetSize.h); |
| 629 | 729 | finalFbo = DependencyManager::get<GlowEffect>()->render(renderArgs); |
| 630 | 730 | } else { |
| 631 | − finalFbo = DependencyManager::get<TextureCache>()->getPrimaryFramebuffer(); | |
| 731 | + finalFbo = DependencyManager::get<TextureCache>()->getPrimaryFramebuffer(); | |
| 632 | 732 | glBindFramebuffer(GL_FRAMEBUFFER, 0); |
| 633 | 733 | } |
| 634 | 734 | |
| @@ -638,141 +738,73 @@ void OculusManager::display(QGLWidget * glCanvas, RenderArgs* renderArgs, const · 3 unmodified lines | ||
| 638 | 738 | // restore our normal viewport |
| 639 | 739 | glViewport(0, 0, deviceSize.width(), deviceSize.height()); |
| 640 | 740 | |
| 641 | −#if 0 | |
| 642 | − if (debugFrame && !timerActive) { | |
| 643 | − timerQuery.begin(); | |
| 644 | − } | |
| 645 | −#endif | |
| 741 | +#ifdef Q_OS_WIN | |
| 742 | + auto srcFboSize = finalFbo->getSize(); | |
| 646 | 743 | |
| 647 | −#ifdef OVR_CLIENT_DISTORTION | |
| 648 | − | |
| 649 | − //Wait till time-warp to reduce latency | |
| 650 | − ovr_WaitTillTime(_hmdFrameTiming.TimewarpPointSeconds); | |
| 651 | 744 | |
| 652 | −#ifdef DEBUG_RENDER_WITHOUT_DISTORTION | |
| 653 | − auto fboSize = finalFbo->getSize(); | |
| 745 | + // Blit to the oculus provided texture | |
| 654 | 746 | glBindFramebuffer(GL_READ_FRAMEBUFFER, gpu::GLBackend::getFramebufferID(finalFbo)); |
| 747 | + _swapFbo->Bound(oglplus::Framebuffer::Target::Draw, [&] { | |
| 748 | + glBlitFramebuffer( | |
| 749 | + 0, 0, srcFboSize.x, srcFboSize.y, | |
| 750 | + 0, 0, _swapFbo->size.x, _swapFbo->size.y, | |
| 751 | + GL_COLOR_BUFFER_BIT, GL_NEAREST); | |
| 752 | + }); | |
| 753 | + | |
| 754 | + // Blit to the onscreen window | |
| 755 | + auto destWindowSize = qApp->getDeviceSize(); | |
| 655 | 756 | glBlitFramebuffer( |
| 656 | − 0, 0, fboSize.x, fboSize.y, | |
| 657 | − 0, 0, deviceSize.width(), deviceSize.height(), | |
| 757 | + 0, 0, srcFboSize.x, srcFboSize.y, | |
| 758 | + 0, 0, destWindowSize.width(), destWindowSize.height(), | |
| 658 | 759 | GL_COLOR_BUFFER_BIT, GL_NEAREST); |
| 760 | + glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); | |
| 761 | + | |
| 762 | + // Submit the frame to the Oculus SDK for timewarp and distortion | |
| 763 | + for_each_eye([&](ovrEyeType eye) { | |
| 764 | + _sceneLayer.RenderPose[eye] = _eyeRenderPoses[eye]; | |
| 765 | + }); | |
| 766 | + auto header = &_sceneLayer.Header; | |
| 767 | + ovrResult res = ovrHmd_SubmitFrame(_ovrHmd, _frameIndex, nullptr, &header, 1); | |
| 768 | + Q_ASSERT(OVR_SUCCESS(res)); | |
| 769 | + _swapFbo->Increment(); | |
| 659 | 770 | #else |
| 660 | − //Clear the color buffer to ensure that there isnt any residual color | |
| 661 | − //Left over from when OR was not connected. | |
| 662 | − glClear(GL_COLOR_BUFFER_BIT); | |
| 663 | − glBindTexture(GL_TEXTURE_2D, gpu::GLBackend::getTextureID(finalFbo->getRenderBuffer(0))); | |
| 664 | − //Renders the distorted mesh onto the screen | |
| 665 | − renderDistortionMesh(eyeRenderPose); | |
| 666 | − glBindTexture(GL_TEXTURE_2D, 0); | |
| 667 | −#endif | |
| 668 | − glCanvas->swapBuffers(); | |
| 771 | + GLsync syncObject = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0); | |
| 772 | + glFlush(); | |
| 669 | 773 | |
| 670 | −#else | |
| 671 | 774 | |
| 775 | + _outputWindow->makeCurrent(); | |
| 776 | + // force the compositing context to wait for the texture | |
| 777 | + // rendering to complete before it starts the distortion rendering, | |
| 778 | + // but without triggering a CPU/GPU synchronization | |
| 779 | + glWaitSync(syncObject, 0, GL_TIMEOUT_IGNORED); | |
| 780 | + glDeleteSync(syncObject); | |
| 781 | + | |
| 782 | + GLuint textureId = gpu::GLBackend::getTextureID(finalFbo->getRenderBuffer(0)); | |
| 672 | 783 | for_each_eye([&](ovrEyeType eye) { |
| 673 | 784 | ovrGLTexture & glEyeTexture = reinterpret_cast<ovrGLTexture&>(_eyeTextures[eye]); |
| 674 | − glEyeTexture.OGL.TexId = finalFbo->texture(); | |
| 675 | − | |
| 676 | − }); | |
| 785 | + glEyeTexture.OGL.TexId = textureId; | |
| 677 | 786 | |
| 678 | − ovrHmd_EndFrame(_ovrHmd, eyeRenderPose, _eyeTextures); | |
| 787 | + }); | |
| 679 | 788 | |
| 789 | + // restore our normal viewport | |
| 790 | + ovrHmd_EndFrame(_ovrHmd, _eyeRenderPoses, _eyeTextures); | |
| 791 | + glCanvas->makeCurrent(); | |
| 680 | 792 | #endif |
| 681 | 793 | |
| 682 | −#if 0 | |
| 683 | − if (debugFrame && !timerActive) { | |
| 684 | − timerQuery.end(); | |
| 685 | − timerActive = true; | |
| 686 | − } | |
| 687 | −#endif | |
| 688 | 794 | |
| 689 | − // No DK2, no message. | |
| 795 | + // in order to account account for changes in the pick ray caused by head movement | |
| 796 | + // we need to force a mouse move event on every frame (perhaps we could change this | |
| 797 | + // to based on the head moving a minimum distance from the last position in which we | |
| 798 | + // sent?) | |
| 690 | 799 | { |
| 691 | − float latencies[5] = {}; | |
| 692 | − if (debugFrame && ovrHmd_GetFloatArray(_ovrHmd, "DK2Latency", latencies, 5) == 5) | |
| 693 | − { | |
| 694 | − bool nonZero = false; | |
| 695 | − for (int i = 0; i < 5; ++i) | |
| 696 | − { | |
| 697 | − nonZero |= (latencies[i] != 0.f); | |
| 698 | − } | |
| 699 | − | |
| 700 | − if (nonZero) | |
| 701 | − { | |
| 702 | − qCDebug(interfaceapp) << QString().sprintf("M2P Latency: Ren: %4.2fms TWrp: %4.2fms PostPresent: %4.2fms Err: %4.2fms %4.2fms", | |
| 703 | − latencies[0], latencies[1], latencies[2], latencies[3], latencies[4]); | |
| 704 | − } | |
| 705 | − } | |
| 800 | + QMouseEvent mouseEvent(QEvent::MouseMove, glCanvas->mapFromGlobal(QCursor::pos()), | |
| 801 | + Qt::NoButton, Qt::NoButton, 0); | |
| 802 | + qApp->mouseMoveEvent(&mouseEvent, 0); | |
| 706 | 803 | } |
| 707 | − | |
| 708 | −} | |
| 709 | − | |
| 710 | −#ifdef OVR_CLIENT_DISTORTION | |
| 711 | −void OculusManager::renderDistortionMesh(ovrPosef eyeRenderPose[ovrEye_Count]) { | |
| 712 | 804 | |
| 713 | − glLoadIdentity(); | |
| 714 | − auto deviceSize = qApp->getDeviceSize(); | |
| 715 | − glOrtho(0, deviceSize.width(), 0, deviceSize.height(), -1.0, 1.0); | |
| 716 | − | |
| 717 | − glDisable(GL_DEPTH_TEST); | |
| 718 | − | |
| 719 | − glDisable(GL_BLEND); | |
| 720 | − _program.bind(); | |
| 721 | − _program.setUniformValue(_textureLocation, 0); | |
| 722 | − | |
| 723 | − _program.enableAttributeArray(_positionAttributeLocation); | |
| 724 | − _program.enableAttributeArray(_colorAttributeLocation); | |
| 725 | − _program.enableAttributeArray(_texCoord0AttributeLocation); | |
| 726 | − _program.enableAttributeArray(_texCoord1AttributeLocation); | |
| 727 | − _program.enableAttributeArray(_texCoord2AttributeLocation); | |
| 728 | − | |
| 729 | − //Render the distortion meshes for each eye | |
| 730 | − for (int eyeNum = 0; eyeNum < ovrEye_Count; eyeNum++) { | |
| 731 | − | |
| 732 | − ovrHmd_GetRenderScaleAndOffset(_eyeRenderDesc[eyeNum].Fov, _renderTargetSize, _eyeTextures[eyeNum].Header.RenderViewport, | |
| 733 | − _UVScaleOffset[eyeNum]); | |
| 734 | − | |
| 735 | − GLfloat uvScale[2] = { _UVScaleOffset[eyeNum][0].x, _UVScaleOffset[eyeNum][0].y }; | |
| 736 | − _program.setUniformValueArray(_eyeToSourceUVScaleLocation, uvScale, 1, 2); | |
| 737 | − GLfloat uvOffset[2] = { _UVScaleOffset[eyeNum][1].x, 1.0f - _UVScaleOffset[eyeNum][1].y }; | |
| 738 | − _program.setUniformValueArray(_eyeToSourceUVOffsetLocation, uvOffset, 1, 2); | |
| 739 | − | |
| 740 | − ovrMatrix4f timeWarpMatrices[2]; | |
| 741 | − glm::mat4 transposeMatrices[2]; | |
| 742 | − //Grabs the timewarp matrices to be used in the shader | |
| 743 | − ovrHmd_GetEyeTimewarpMatrices(_ovrHmd, (ovrEyeType)eyeNum, eyeRenderPose[eyeNum], timeWarpMatrices); | |
| 744 | − //Have to transpose the matrices before using them | |
| 745 | − transposeMatrices[0] = glm::transpose(toGlm(timeWarpMatrices[0])); | |
| 746 | − transposeMatrices[1] = glm::transpose(toGlm(timeWarpMatrices[1])); | |
| 747 | 805 | |
| 748 | − glUniformMatrix4fv(_eyeRotationStartLocation, 1, GL_FALSE, (GLfloat *)&transposeMatrices[0][0][0]); | |
| 749 | − glUniformMatrix4fv(_eyeRotationEndLocation, 1, GL_FALSE, (GLfloat *)&transposeMatrices[1][0][0]); | |
| 750 | 806 | |
| 751 | − glBindBuffer(GL_ARRAY_BUFFER, _vertices[eyeNum]); | |
| 752 | − | |
| 753 | − //Set vertex attribute pointers | |
| 754 | − glVertexAttribPointer(_positionAttributeLocation, 2, GL_FLOAT, GL_FALSE, sizeof(DistortionVertex), (void *)0); | |
| 755 | − glVertexAttribPointer(_texCoord0AttributeLocation, 2, GL_FLOAT, GL_FALSE, sizeof(DistortionVertex), (void *)8); | |
| 756 | − glVertexAttribPointer(_texCoord1AttributeLocation, 2, GL_FLOAT, GL_FALSE, sizeof(DistortionVertex), (void *)16); | |
| 757 | − glVertexAttribPointer(_texCoord2AttributeLocation, 2, GL_FLOAT, GL_FALSE, sizeof(DistortionVertex), (void *)24); | |
| 758 | − glVertexAttribPointer(_colorAttributeLocation, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(DistortionVertex), (void *)32); | |
| 759 | − | |
| 760 | − glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _indices[eyeNum]); | |
| 761 | − glDrawElements(GL_TRIANGLES, _meshSize[eyeNum], GL_UNSIGNED_SHORT, 0); | |
| 762 | − } | |
| 763 | − | |
| 764 | − _program.disableAttributeArray(_positionAttributeLocation); | |
| 765 | − _program.disableAttributeArray(_colorAttributeLocation); | |
| 766 | − _program.disableAttributeArray(_texCoord0AttributeLocation); | |
| 767 | − _program.disableAttributeArray(_texCoord1AttributeLocation); | |
| 768 | − _program.disableAttributeArray(_texCoord2AttributeLocation); | |
| 769 | − | |
| 770 | − glEnable(GL_BLEND); | |
| 771 | − glEnable(GL_DEPTH_TEST); | |
| 772 | − _program.release(); | |
| 773 | − glBindBuffer(GL_ARRAY_BUFFER, 0); | |
| 774 | 807 | } |
| 775 | −#endif | |
| 776 | 808 | |
| 777 | 809 | //Tries to reconnect to the sensors |
| 778 | 810 | void OculusManager::reset() { |
| @@ -781,21 +813,6 @@ void OculusManager::reset() { · 2 unmodified lines | ||
| 781 | 813 | } |
| 782 | 814 | } |
| 783 | 815 | |
| 784 | −//Gets the current predicted angles from the oculus sensors | |
| 785 | −void OculusManager::getEulerAngles(float& yaw, float& pitch, float& roll) { | |
| 786 | − ovrTrackingState ts = ovrHmd_GetTrackingState(_ovrHmd, ovr_GetTimeInSeconds()); | |
| 787 | − if (ts.StatusFlags & (ovrStatus_OrientationTracked | ovrStatus_PositionTracked)) { | |
| 788 | − glm::vec3 euler = glm::eulerAngles(toGlm(ts.HeadPose.ThePose.Orientation)); | |
| 789 | − yaw = euler.y; | |
| 790 | − pitch = euler.x; | |
| 791 | − roll = euler.z; | |
| 792 | − } else { | |
| 793 | − yaw = 0.0f; | |
| 794 | − pitch = 0.0f; | |
| 795 | − roll = 0.0f; | |
| 796 | − } | |
| 797 | −} | |
| 798 | − | |
| 799 | 816 | glm::vec3 OculusManager::getRelativePosition() { |
| 800 | 817 | ovrTrackingState trackingState = ovrHmd_GetTrackingState(_ovrHmd, ovr_GetTimeInSeconds()); |
| 801 | 818 | return toGlm(trackingState.HeadPose.ThePose.Position); |
| @@ -826,6 +843,9 @@ void OculusManager::overrideOffAxisFrustum(float& left, float& right, float& bot · 24 unmodified lines | ||
| 826 | 843 | } |
| 827 | 844 | |
| 828 | 845 | int OculusManager::getHMDScreen() { |
| 846 | +#ifdef Q_OS_WIN | |
| 847 | + return -1; | |
| 848 | +#else | |
| 829 | 849 | int hmdScreenIndex = -1; // unknown |
| 830 | 850 | // TODO: it might be smarter to handle multiple HMDs connected in this case. but for now, |
| 831 | 851 | // we will simply assume the initialization code that set up _ovrHmd picked the best hmd |
| @@ -844,7 +864,7 @@ int OculusManager::getHMDScreen() { · 12 unmodified lines | ||
| 844 | 864 | const int SIMILAR_NAMES = 10; |
| 845 | 865 | const int EXACT_LOCATION_MATCH = 50; |
| 846 | 866 | const int EXACT_RESOLUTION_MATCH = 25; |
| 847 | − | |
| 867 | + | |
| 848 | 868 | int bestMatchScore = 0; |
| 849 | 869 | |
| 850 | 870 | // look at the display list and see if we can find the best match |
| @@ -853,7 +873,7 @@ int OculusManager::getHMDScreen() { · 2 unmodified lines | ||
| 853 | 873 | foreach (QScreen* screen, QGuiApplication::screens()) { |
| 854 | 874 | QString screenName = screen->name(); |
| 855 | 875 | QRect screenRect = desktop->screenGeometry(screenNumber); |
| 856 | − | |
| 876 | + | |
| 857 | 877 | int screenScore = 0; |
| 858 | 878 | if (screenName == productNameFromOVR) { |
| 859 | 879 | screenScore += EXACT_NAME_MATCH; |
| @@ -876,5 +896,18 @@ int OculusManager::getHMDScreen() { · 16 unmodified lines | ||
| 876 | 896 | } |
| 877 | 897 | } |
| 878 | 898 | return hmdScreenIndex; |
| 899 | +#endif | |
| 900 | +} | |
| 901 | + | |
| 902 | +mat4 OculusManager::getEyeProjection(int eye) { | |
| 903 | + return _eyeProjection[eye]; | |
| 879 | 904 | } |
| 880 | 905 | |
| 906 | +mat4 OculusManager::getEyePose(int eye) { | |
| 907 | + return toGlm(_eyeRenderPoses[eye]); | |
| 908 | +} | |
| 909 | + | |
| 910 | +mat4 OculusManager::getHeadPose() { | |
| 911 | + ovrTrackingState ts = ovrHmd_GetTrackingState(_ovrHmd, ovr_GetTimeInSeconds()); | |
| 912 | + return toGlm(ts.HeadPose.ThePose); | |
| 913 | +} | |
| @@ -13,8 +13,6 @@ · 12 unmodified lines | ||
| 13 | 13 | #ifndef hifi_OculusManager_h |
| 14 | 14 | #define hifi_OculusManager_h |
| 15 | 15 | |
| 16 | −#include <OVR_CAPI.h> | |
| 17 | − | |
| 18 | 16 | #include <ProgramObject.h> |
| 19 | 17 | #include <glm/glm.hpp> |
| 20 | 18 | #include <glm/gtc/matrix_transform.hpp> |
| @@ -22,39 +20,13 @@ · 1 unmodified line | ||
| 22 | 20 | |
| 23 | 21 | #include "RenderArgs.h" |
| 24 | 22 | |
| 23 | +class QOpenGLContext; | |
| 25 | 24 | class Camera; |
| 26 | −class PalmData; | |
| 27 | −class Text3DOverlay; | |
| 28 | − | |
| 29 | −// Uncomment this to enable client side distortion. NOT recommended since | |
| 30 | −// the Oculus SDK will ideally provide the best practices for distortion in | |
| 31 | −// in terms of performance and quality, and by using it we will get updated | |
| 32 | −// best practices for free with new runtime releases. | |
| 33 | −#define OVR_CLIENT_DISTORTION 1 | |
| 34 | − | |
| 35 | − | |
| 36 | −// Direct HMD mode is currently only supported on windows and some linux systems will | |
| 37 | −// misbehave if we try to enable the Oculus SDK at all, so isolate support for Direct | |
| 38 | −// mode only to windows for now | |
| 39 | −#ifdef Q_OS_WIN | |
| 40 | −// On Win32 platforms, enabling Direct HMD requires that the SDK be | |
| 41 | −// initialized before the GL context is set up, but this breaks v-sync | |
| 42 | −// for any application that has a Direct mode enable Rift connected | |
| 43 | −// but is not rendering to it. For the time being I'm setting this as | |
| 44 | −// a macro enabled mechanism which changes where the SDK is initialized. | |
| 45 | −// To enable Direct HMD mode, you can un-comment this, but with the | |
| 46 | −// caveat that it will break v-sync in NON-VR mode if you have an Oculus | |
| 47 | −// Rift connect and in Direct mode | |
| 48 | −#define OVR_DIRECT_MODE 1 | |
| 49 | −#endif | |
| 50 | − | |
| 51 | 25 | |
| 52 | 26 | /// Handles interaction with the Oculus Rift. |
| 53 | 27 | class OculusManager { |
| 54 | 28 | public: |
| 55 | − static void init(); | |
| 56 | − static void deinit(); | |
| 57 | − static void connect(); | |
| 29 | + static void connect(QOpenGLContext* shareContext); | |
| 58 | 30 | static void disconnect(); |
| 59 | 31 | static bool isConnected(); |
| 60 | 32 | static void recalibrate(); |
| @@ -66,10 +38,6 @@ public: · 5 unmodified lines | ||
| 66 | 38 | static void display(QGLWidget * glCanvas, RenderArgs* renderArgs, const glm::quat &bodyOrientation, const glm::vec3 &position, Camera& whichCamera); |
| 67 | 39 | static void reset(); |
| 68 | 40 | |
| 69 | − /// param \yaw[out] yaw in radians | |
| 70 | − /// param \pitch[out] pitch in radians | |
| 71 | − /// param \roll[out] roll in radians | |
| 72 | − static void getEulerAngles(float& yaw, float& pitch, float& roll); | |
| 73 | 41 | static glm::vec3 getRelativePosition(); |
| 74 | 42 | static glm::quat getOrientation(); |
| 75 | 43 | static QSize getRenderTargetSize(); |
| @@ -77,145 +45,14 @@ public: · 1 unmodified line | ||
| 77 | 45 | static void overrideOffAxisFrustum(float& left, float& right, float& bottom, float& top, float& nearVal, |
| 78 | 46 | float& farVal, glm::vec4& nearClipPlane, glm::vec4& farClipPlane); |
| 79 | 47 | |
| 80 | − static glm::vec3 getLeftEyePosition() { return _eyePositions[ovrEye_Left]; } | |
| 81 | − static glm::vec3 getRightEyePosition() { return _eyePositions[ovrEye_Right]; } | |
| 48 | + static glm::vec3 getLeftEyePosition(); | |
| 49 | + static glm::vec3 getRightEyePosition(); | |
| 82 | 50 | |
| 83 | 51 | static int getHMDScreen(); |
| 84 | − | |
| 85 | −private: | |
| 86 | − static void initSdk(); | |
| 87 | − static void shutdownSdk(); | |
| 88 | −#ifdef OVR_CLIENT_DISTORTION | |
| 89 | − static void generateDistortionMesh(); | |
| 90 | − static void renderDistortionMesh(ovrPosef eyeRenderPose[ovrEye_Count]); | |
| 91 | − struct DistortionVertex { | |
| 92 | − glm::vec2 pos; | |
| 93 | − glm::vec2 texR; | |
| 94 | − glm::vec2 texG; | |
| 95 | − glm::vec2 texB; | |
| 96 | − struct { | |
| 97 | − GLubyte r; | |
| 98 | − GLubyte g; | |
| 99 | − GLubyte b; | |
| 100 | − GLubyte a; | |
| 101 | − } color; | |
| 102 | − }; | |
| 103 | 52 | |
| 104 | − static ProgramObject _program; | |
| 105 | − //Uniforms | |
| 106 | − static int _textureLocation; | |
| 107 | − static int _eyeToSourceUVScaleLocation; | |
| 108 | − static int _eyeToSourceUVOffsetLocation; | |
| 109 | − static int _eyeRotationStartLocation; | |
| 110 | − static int _eyeRotationEndLocation; | |
| 111 | − //Attributes | |
| 112 | − static int _positionAttributeLocation; | |
| 113 | − static int _colorAttributeLocation; | |
| 114 | − static int _texCoord0AttributeLocation; | |
| 115 | − static int _texCoord1AttributeLocation; | |
| 116 | − static int _texCoord2AttributeLocation; | |
| 117 | − static ovrVector2f _UVScaleOffset[ovrEye_Count][2]; | |
| 118 | − static GLuint _vertices[ovrEye_Count]; | |
| 119 | − static GLuint _indices[ovrEye_Count]; | |
| 120 | − static GLsizei _meshSize[ovrEye_Count]; | |
| 121 | − static ovrFrameTiming _hmdFrameTiming; | |
| 122 | − static bool _programInitialized; | |
| 123 | −#endif | |
| 124 | − | |
| 125 | − static ovrTexture _eyeTextures[ovrEye_Count]; | |
| 126 | − static bool _isConnected; | |
| 127 | − static glm::vec3 _eyePositions[ovrEye_Count]; | |
| 128 | − static ovrHmd _ovrHmd; | |
| 129 | − static ovrFovPort _eyeFov[ovrEye_Count]; | |
| 130 | − static ovrVector3f _eyeOffset[ovrEye_Count]; | |
| 131 | − static glm::mat4 _eyeProjection[ovrEye_Count]; | |
| 132 | − static ovrEyeRenderDesc _eyeRenderDesc[ovrEye_Count]; | |
| 133 | − static ovrSizei _renderTargetSize; | |
| 134 | − static unsigned int _frameIndex; | |
| 135 | − static bool _frameTimingActive; | |
| 136 | − static Camera* _camera; | |
| 137 | − static ovrEyeType _activeEye; | |
| 138 | − static bool _hswDismissed; | |
| 139 | − | |
| 140 | − static void calibrate(const glm::vec3 position, const glm::quat orientation); | |
| 141 | − enum CalibrationState { | |
| 142 | − UNCALIBRATED, | |
| 143 | − WAITING_FOR_DELTA, | |
| 144 | − WAITING_FOR_ZERO, | |
| 145 | − WAITING_FOR_ZERO_HELD, | |
| 146 | − CALIBRATED | |
| 147 | − }; | |
| 148 | − static void positionCalibrationBillboard(Text3DOverlay* message); | |
| 149 | − static float CALIBRATION_DELTA_MINIMUM_LENGTH; | |
| 150 | − static float CALIBRATION_DELTA_MINIMUM_ANGLE; | |
| 151 | − static float CALIBRATION_ZERO_MAXIMUM_LENGTH; | |
| 152 | − static float CALIBRATION_ZERO_MAXIMUM_ANGLE; | |
| 153 | − static quint64 CALIBRATION_ZERO_HOLD_TIME; | |
| 154 | − static float CALIBRATION_MESSAGE_DISTANCE; | |
| 155 | − static CalibrationState _calibrationState; | |
| 156 | − static glm::vec3 _calibrationPosition; | |
| 157 | − static glm::quat _calibrationOrientation; | |
| 158 | − static quint64 _calibrationStartTime; | |
| 159 | − static int _calibrationMessage; | |
| 160 | − // TODO drop this variable and use the existing 'Developer | Render | Scale Resolution' value | |
| 161 | − static ovrSizei _recommendedTexSize; | |
| 162 | − static float _offscreenRenderScale; | |
| 163 | − static bool _eyePerFrameMode; | |
| 164 | − static ovrEyeType _lastEyeRendered; | |
| 53 | + static glm::mat4 getEyeProjection(int eye); | |
| 54 | + static glm::mat4 getEyePose(int eye); | |
| 55 | + static glm::mat4 getHeadPose(); | |
| 165 | 56 | }; |
| 166 | 57 | |
| 167 | − | |
| 168 | −inline glm::mat4 toGlm(const ovrMatrix4f & om) { | |
| 169 | − return glm::transpose(glm::make_mat4(&om.M[0][0])); | |
| 170 | −} | |
| 171 | − | |
| 172 | −inline glm::mat4 toGlm(const ovrFovPort & fovport, float nearPlane = 0.01f, float farPlane = 10000.0f) { | |
| 173 | − return toGlm(ovrMatrix4f_Projection(fovport, nearPlane, farPlane, true)); | |
| 174 | −} | |
| 175 | − | |
| 176 | −inline glm::vec3 toGlm(const ovrVector3f & ov) { | |
| 177 | − return glm::make_vec3(&ov.x); | |
| 178 | −} | |
| 179 | − | |
| 180 | −inline glm::vec2 toGlm(const ovrVector2f & ov) { | |
| 181 | − return glm::make_vec2(&ov.x); | |
| 182 | −} | |
| 183 | − | |
| 184 | −inline glm::uvec2 toGlm(const ovrSizei & ov) { | |
| 185 | − return glm::uvec2(ov.w, ov.h); | |
| 186 | −} | |
| 187 | − | |
| 188 | −inline glm::quat toGlm(const ovrQuatf & oq) { | |
| 189 | − return glm::make_quat(&oq.x); | |
| 190 | −} | |
| 191 | − | |
| 192 | −inline glm::mat4 toGlm(const ovrPosef & op) { | |
| 193 | − glm::mat4 orientation = glm::mat4_cast(toGlm(op.Orientation)); | |
| 194 | − glm::mat4 translation = glm::translate(glm::mat4(), toGlm(op.Position)); | |
| 195 | − return translation * orientation; | |
| 196 | −} | |
| 197 | − | |
| 198 | −inline ovrMatrix4f ovrFromGlm(const glm::mat4 & m) { | |
| 199 | − ovrMatrix4f result; | |
| 200 | − glm::mat4 transposed(glm::transpose(m)); | |
| 201 | − memcpy(result.M, &(transposed[0][0]), sizeof(float) * 16); | |
| 202 | − return result; | |
| 203 | −} | |
| 204 | − | |
| 205 | −inline ovrVector3f ovrFromGlm(const glm::vec3 & v) { | |
| 206 | − return{ v.x, v.y, v.z }; | |
| 207 | −} | |
| 208 | − | |
| 209 | −inline ovrVector2f ovrFromGlm(const glm::vec2 & v) { | |
| 210 | − return{ v.x, v.y }; | |
| 211 | −} | |
| 212 | − | |
| 213 | −inline ovrSizei ovrFromGlm(const glm::uvec2 & v) { | |
| 214 | − return{ (int)v.x, (int)v.y }; | |
| 215 | −} | |
| 216 | − | |
| 217 | −inline ovrQuatf ovrFromGlm(const glm::quat & q) { | |
| 218 | − return{ q.x, q.y, q.z, q.w }; | |
| 219 | −} | |
| 220 | − | |
| 221 | 58 | #endif // hifi_OculusManager_h |
| @@ -74,9 +74,11 @@ SDL2Manager* SDL2Manager::getInstance() { · 73 unmodified lines | ||
| 74 | 74 | } |
| 75 | 75 | |
| 76 | 76 | void SDL2Manager::focusOutEvent() { |
| 77 | +#ifdef HAVE_SDL2 | |
| 77 | 78 | for (auto joystick : _openJoysticks) { |
| 78 | 79 | joystick->focusOutEvent(); |
| 79 | 80 | } |
| 81 | +#endif | |
| 80 | 82 | } |
| 81 | 83 | |
| 82 | 84 | void SDL2Manager::update() { |
| @@ -36,6 +36,8 @@ const float NECK_X = 0.25f; // meters · 35 unmodified lines | ||
| 36 | 36 | const float NECK_Y = 0.3f; // meters |
| 37 | 37 | const float NECK_Z = 0.3f; // meters |
| 38 | 38 | |
| 39 | +const float CONTROLLER_THRESHOLD = 0.35f; | |
| 40 | + | |
| 39 | 41 | #ifdef __APPLE__ |
| 40 | 42 | typedef int (*SixenseBaseFunction)(); |
| 41 | 43 | typedef int (*SixenseTakeIntFunction)(int); |
| @@ -71,25 +73,25 @@ SixenseManager::SixenseManager() : · 29 unmodified lines | ||
| 71 | 73 | |
| 72 | 74 | SixenseManager::~SixenseManager() { |
| 73 | 75 | #ifdef HAVE_SIXENSE_ |
| 74 | − | |
| 76 | + | |
| 75 | 77 | if (_isInitialized) { |
| 76 | 78 | #ifdef __APPLE__ |
| 77 | 79 | SixenseBaseFunction sixenseExit = (SixenseBaseFunction) _sixenseLibrary->resolve("sixenseExit"); |
| 78 | 80 | #endif |
| 79 | − | |
| 81 | + | |
| 80 | 82 | sixenseExit(); |
| 81 | 83 | } |
| 82 | − | |
| 84 | + | |
| 83 | 85 | #ifdef __APPLE__ |
| 84 | 86 | delete _sixenseLibrary; |
| 85 | 87 | #endif |
| 86 | − | |
| 88 | + | |
| 87 | 89 | #endif |
| 88 | 90 | } |
| 89 | 91 | |
| 90 | 92 | void SixenseManager::initialize() { |
| 91 | 93 | #ifdef HAVE_SIXENSE |
| 92 | − | |
| 94 | + | |
| 93 | 95 | if (!_isInitialized) { |
| 94 | 96 | _lowVelocityFilter = false; |
| 95 | 97 | _controllersAtBase = true; |
| @@ -97,22 +99,22 @@ void SixenseManager::initialize() { · 1 unmodified line | ||
| 97 | 99 | // By default we assume the _neckBase (in orb frame) is as high above the orb |
| 98 | 100 | // as the "torso" is below it. |
| 99 | 101 | _neckBase = glm::vec3(NECK_X, -NECK_Y, NECK_Z); |
| 100 | − | |
| 102 | + | |
| 101 | 103 | #ifdef __APPLE__ |
| 102 | − | |
| 104 | + | |
| 103 | 105 | if (!_sixenseLibrary) { |
| 104 | − | |
| 106 | + | |
| 105 | 107 | #ifdef SIXENSE_LIB_FILENAME |
| 106 | 108 | _sixenseLibrary = new QLibrary(SIXENSE_LIB_FILENAME); |
| 107 | 109 | #else |
| 108 | 110 | const QString SIXENSE_LIBRARY_NAME = "libsixense_x64"; |
| 109 | 111 | QString frameworkSixenseLibrary = QCoreApplication::applicationDirPath() + "/../Frameworks/" |
| 110 | 112 | + SIXENSE_LIBRARY_NAME; |
| 111 | − | |
| 113 | + | |
| 112 | 114 | _sixenseLibrary = new QLibrary(frameworkSixenseLibrary); |
| 113 | 115 | #endif |
| 114 | 116 | } |
| 115 | − | |
| 117 | + | |
| 116 | 118 | if (_sixenseLibrary->load()){ |
| 117 | 119 | qCDebug(interfaceapp) << "Loaded sixense library for hydra support -" << _sixenseLibrary->fileName(); |
| 118 | 120 | } else { |
| @@ -120,14 +122,14 @@ void SixenseManager::initialize() { · 1 unmodified line | ||
| 120 | 122 | << "Continuing without hydra support."; |
| 121 | 123 | return; |
| 122 | 124 | } |
| 123 | − | |
| 125 | + | |
| 124 | 126 | SixenseBaseFunction sixenseInit = (SixenseBaseFunction) _sixenseLibrary->resolve("sixenseInit"); |
| 125 | 127 | #endif |
| 126 | 128 | sixenseInit(); |
| 127 | − | |
| 129 | + | |
| 128 | 130 | _isInitialized = true; |
| 129 | 131 | } |
| 130 | − | |
| 132 | + | |
| 131 | 133 | #endif |
| 132 | 134 | } |
| 133 | 135 | |
| @@ -138,7 +140,7 @@ void SixenseManager::setFilter(bool filter) { · 4 unmodified lines | ||
| 138 | 140 | #ifdef __APPLE__ |
| 139 | 141 | SixenseTakeIntFunction sixenseSetFilterEnabled = (SixenseTakeIntFunction) _sixenseLibrary->resolve("sixenseSetFilterEnabled"); |
| 140 | 142 | #endif |
| 141 | − | |
| 143 | + | |
| 142 | 144 | if (filter) { |
| 143 | 145 | sixenseSetFilterEnabled(1); |
| 144 | 146 | } else { |
| @@ -158,7 +160,7 @@ void SixenseManager::update(float deltaTime) { · 13 unmodified lines | ||
| 158 | 160 | SixenseBaseFunction sixenseGetNumActiveControllers = |
| 159 | 161 | (SixenseBaseFunction) _sixenseLibrary->resolve("sixenseGetNumActiveControllers"); |
| 160 | 162 | #endif |
| 161 | − | |
| 163 | + | |
| 162 | 164 | if (sixenseGetNumActiveControllers() == 0) { |
| 163 | 165 | _hydrasConnected = false; |
| 164 | 166 | if (_deviceID != 0) { |
| @@ -173,7 +175,7 @@ void SixenseManager::update(float deltaTime) { · 8 unmodified lines | ||
| 173 | 175 | } |
| 174 | 176 | return; |
| 175 | 177 | } |
| 176 | − | |
| 178 | + | |
| 177 | 179 | PerformanceTimer perfTimer("sixense"); |
| 178 | 180 | if (!_hydrasConnected) { |
| 179 | 181 | _hydrasConnected = true; |
| @@ -181,21 +183,21 @@ void SixenseManager::update(float deltaTime) { · 1 unmodified line | ||
| 181 | 183 | getInstance().assignDefaultInputMapping(*Application::getUserInputMapper()); |
| 182 | 184 | UserActivityLogger::getInstance().connectedDevice("spatial_controller", "hydra"); |
| 183 | 185 | } |
| 184 | − | |
| 186 | + | |
| 185 | 187 | #ifdef __APPLE__ |
| 186 | 188 | SixenseBaseFunction sixenseGetMaxControllers = |
| 187 | 189 | (SixenseBaseFunction) _sixenseLibrary->resolve("sixenseGetMaxControllers"); |
| 188 | 190 | #endif |
| 189 | − | |
| 191 | + | |
| 190 | 192 | int maxControllers = sixenseGetMaxControllers(); |
| 191 | − | |
| 193 | + | |
| 192 | 194 | // we only support two controllers |
| 193 | 195 | sixenseControllerData controllers[2]; |
| 194 | − | |
| 196 | + | |
| 195 | 197 | #ifdef __APPLE__ |
| 196 | 198 | SixenseTakeIntFunction sixenseIsControllerEnabled = |
| 197 | 199 | (SixenseTakeIntFunction) _sixenseLibrary->resolve("sixenseIsControllerEnabled"); |
| 198 | − | |
| 200 | + | |
| 199 | 201 | SixenseTakeIntAndSixenseControllerData sixenseGetNewestData = |
| 200 | 202 | (SixenseTakeIntAndSixenseControllerData) _sixenseLibrary->resolve("sixenseGetNewestData"); |
| 201 | 203 | #endif |
| @@ -208,9 +210,9 @@ void SixenseManager::update(float deltaTime) { · 6 unmodified lines | ||
| 208 | 210 | sixenseControllerData* data = controllers + numActiveControllers; |
| 209 | 211 | ++numActiveControllers; |
| 210 | 212 | sixenseGetNewestData(i, data); |
| 211 | − | |
| 213 | + | |
| 212 | 214 | // Set palm position and normal based on Hydra position/orientation |
| 213 | − | |
| 215 | + | |
| 214 | 216 | // Either find a palm matching the sixense controller, or make a new one |
| 215 | 217 | PalmData* palm; |
| 216 | 218 | bool foundHand = false; |
| @@ -229,47 +231,47 @@ void SixenseManager::update(float deltaTime) { · 12 unmodified lines | ||
| 229 | 231 | _prevPalms[numActiveControllers - 1] = palm; |
| 230 | 232 | qCDebug(interfaceapp, "Found new Sixense controller, ID %i", data->controller_index); |
| 231 | 233 | } |
| 232 | − | |
| 234 | + | |
| 233 | 235 | // Disable the hands (and return to default pose) if both controllers are at base station |
| 234 | 236 | if (foundHand) { |
| 235 | 237 | palm->setActive(!_controllersAtBase); |
| 236 | 238 | } else { |
| 237 | 239 | palm->setActive(false); // if this isn't a Sixsense ID palm, always make it inactive |
| 238 | 240 | } |
| 239 | − | |
| 241 | + | |
| 240 | 242 | // Read controller buttons and joystick into the hand |
| 241 | 243 | palm->setControllerButtons(data->buttons); |
| 242 | 244 | palm->setTrigger(data->trigger); |
| 243 | 245 | palm->setJoystick(data->joystick_x, data->joystick_y); |
| 244 | − | |
| 246 | + | |
| 245 | 247 | handleButtonEvent(data->buttons, numActiveControllers - 1); |
| 246 | 248 | handleAxisEvent(data->joystick_x, data->joystick_y, data->trigger, numActiveControllers - 1); |
| 247 | − | |
| 249 | + | |
| 248 | 250 | // Emulate the mouse so we can use scripts |
| 249 | 251 | if (Menu::getInstance()->isOptionChecked(MenuOption::SixenseMouseInput) && !_controllersAtBase) { |
| 250 | 252 | emulateMouse(palm, numActiveControllers - 1); |
| 251 | 253 | } |
| 252 | − | |
| 254 | + | |
| 253 | 255 | // NOTE: Sixense API returns pos data in millimeters but we IMMEDIATELY convert to meters. |
| 254 | 256 | glm::vec3 position(data->pos[0], data->pos[1], data->pos[2]); |
| 255 | 257 | position *= METERS_PER_MILLIMETER; |
| 256 | − | |
| 258 | + | |
| 257 | 259 | // Check to see if this hand/controller is on the base |
| 258 | 260 | const float CONTROLLER_AT_BASE_DISTANCE = 0.075f; |
| 259 | 261 | if (glm::length(position) < CONTROLLER_AT_BASE_DISTANCE) { |
| 260 | 262 | numControllersAtBase++; |
| 261 | 263 | } |
| 262 | − | |
| 264 | + | |
| 263 | 265 | // Transform the measured position into body frame. |
| 264 | 266 | glm::vec3 neck = _neckBase; |
| 265 | 267 | // Zeroing y component of the "neck" effectively raises the measured position a little bit. |
| 266 | 268 | neck.y = 0.0f; |
| 267 | 269 | position = _orbRotation * (position - neck); |
| 268 | − | |
| 270 | + | |
| 269 | 271 | // Rotation of Palm |
| 270 | 272 | glm::quat rotation(data->rot_quat[3], -data->rot_quat[0], data->rot_quat[1], -data->rot_quat[2]); |
| 271 | 273 | rotation = glm::angleAxis(PI, glm::vec3(0.0f, 1.0f, 0.0f)) * _orbRotation * rotation; |
| 272 | − | |
| 274 | + | |
| 273 | 275 | // Compute current velocity from position change |
| 274 | 276 | glm::vec3 rawVelocity; |
| 275 | 277 | if (deltaTime > 0.0f) { |
| @@ -278,11 +280,11 @@ void SixenseManager::update(float deltaTime) { · 2 unmodified lines | ||
| 278 | 280 | rawVelocity = glm::vec3(0.0f); |
| 279 | 281 | } |
| 280 | 282 | palm->setRawVelocity(rawVelocity); // meters/sec |
| 281 | − | |
| 283 | + | |
| 282 | 284 | // adjustment for hydra controllers fit into hands |
| 283 | 285 | float sign = (i == 0) ? -1.0f : 1.0f; |
| 284 | 286 | rotation *= glm::angleAxis(sign * PI/4.0f, glm::vec3(0.0f, 0.0f, 1.0f)); |
| 285 | − | |
| 287 | + | |
| 286 | 288 | // Angular Velocity of Palm |
| 287 | 289 | glm::quat deltaRotation = rotation * glm::inverse(palm->getRawRotation()); |
| 288 | 290 | glm::vec3 angularVelocity(0.0f); |
| @@ -294,7 +296,7 @@ void SixenseManager::update(float deltaTime) { · 5 unmodified lines | ||
| 294 | 296 | } else { |
| 295 | 297 | palm->setRawAngularVelocity(glm::vec3(0.0f)); |
| 296 | 298 | } |
| 297 | − | |
| 299 | + | |
| 298 | 300 | if (_lowVelocityFilter) { |
| 299 | 301 | // Use a velocity sensitive filter to damp small motions and preserve large ones with |
| 300 | 302 | // no latency. |
| @@ -307,7 +309,7 @@ void SixenseManager::update(float deltaTime) { · 6 unmodified lines | ||
| 307 | 309 | palm->setRawPosition(position); |
| 308 | 310 | palm->setRawRotation(rotation); |
| 309 | 311 | } |
| 310 | − | |
| 312 | + | |
| 311 | 313 | // Store the one fingertip in the palm structure so we can track velocity |
| 312 | 314 | const float FINGER_LENGTH = 0.3f; // meters |
| 313 | 315 | const glm::vec3 FINGER_VECTOR(0.0f, 0.0f, FINGER_LENGTH); |
| @@ -320,19 +322,25 @@ void SixenseManager::update(float deltaTime) { · 6 unmodified lines | ||
| 320 | 322 | } |
| 321 | 323 | palm->setTipPosition(newTipPosition); |
| 322 | 324 | } |
| 323 | − | |
| 325 | + | |
| 324 | 326 | if (numActiveControllers == 2) { |
| 325 | 327 | updateCalibration(controllers); |
| 326 | 328 | } |
| 327 | 329 | _controllersAtBase = (numControllersAtBase == 2); |
| 328 | 330 | } |
| 331 | + | |
| 332 | + for (auto axisState : _axisStateMap) { | |
| 333 | + if (fabsf(axisState.second) < CONTROLLER_THRESHOLD) { | |
| 334 | + _axisStateMap[axisState.first] = 0.0f; | |
| 335 | + } | |
| 336 | + } | |
| 329 | 337 | #endif // HAVE_SIXENSE |
| 330 | 338 | } |
| 331 | 339 | |
| 332 | 340 | //Constants for getCursorPixelRangeMultiplier() |
| 333 | 341 | const float MIN_PIXEL_RANGE_MULT = 0.4f; |
| 334 | 342 | const float MAX_PIXEL_RANGE_MULT = 2.0f; |
| 335 | −const float RANGE_MULT = (MAX_PIXEL_RANGE_MULT - MIN_PIXEL_RANGE_MULT) * 0.01; | |
| 343 | +const float RANGE_MULT = (MAX_PIXEL_RANGE_MULT - MIN_PIXEL_RANGE_MULT) * 0.01f; | |
| 336 | 344 | |
| 337 | 345 | //Returns a multiplier to be applied to the cursor range for the controllers |
| 338 | 346 | float SixenseManager::getCursorPixelRangeMult() const { |
| @@ -421,7 +429,7 @@ void SixenseManager::updateCalibration(const sixenseControllerData* controllers) · 82 unmodified lines | ||
| 421 | 429 | _calibrationState = CALIBRATION_STATE_X; |
| 422 | 430 | } |
| 423 | 431 | return; |
| 424 | − } | |
| 432 | + } | |
| 425 | 433 | |
| 426 | 434 | quint64 now = usecTimestampNow() + LOCK_DURATION; |
| 427 | 435 | // these are weighted running averages |
| @@ -431,7 +439,7 @@ void SixenseManager::updateCalibration(const sixenseControllerData* controllers) · 3 unmodified lines | ||
| 431 | 439 | if (_calibrationState == CALIBRATION_STATE_X) { |
| 432 | 440 | // compute new sliding average |
| 433 | 441 | float distance = glm::distance(_averageLeft, _averageRight); |
| 434 | − if (fabs(distance - _lastDistance) > MAXIMUM_NOISE_LEVEL) { | |
| 442 | + if (fabsf(distance - _lastDistance) > MAXIMUM_NOISE_LEVEL) { | |
| 435 | 443 | // distance is increasing so acquire the data and push the expiry out |
| 436 | 444 | _reachLeft = _averageLeft; |
| 437 | 445 | _reachRight = _averageRight; |
| @@ -450,7 +458,7 @@ void SixenseManager::updateCalibration(const sixenseControllerData* controllers) · 12 unmodified lines | ||
| 450 | 458 | glm::vec3 torso = 0.5f * (_reachLeft + _reachRight); |
| 451 | 459 | glm::vec3 averagePosition = 0.5f * (_averageLeft + _averageRight); |
| 452 | 460 | float distance = (averagePosition - torso).y; |
| 453 | − if (fabs(distance) > fabs(_lastDistance) + MAXIMUM_NOISE_LEVEL) { | |
| 461 | + if (fabsf(distance) > fabsf(_lastDistance) + MAXIMUM_NOISE_LEVEL) { | |
| 454 | 462 | // distance is increasing so acquire the data and push the expiry out |
| 455 | 463 | _reachUp = averagePosition; |
| 456 | 464 | _lastDistance = distance; |
| @@ -481,11 +489,11 @@ void SixenseManager::updateCalibration(const sixenseControllerData* controllers) · 24 unmodified lines | ||
| 481 | 489 | _lastDistance = distance; |
| 482 | 490 | _lockExpiry = now + LOCK_DURATION; |
| 483 | 491 | } else if (now > _lockExpiry) { |
| 484 | − if (fabs(_lastDistance) > 0.05f * MINIMUM_ARM_REACH) { | |
| 492 | + if (fabsf(_lastDistance) > 0.05f * MINIMUM_ARM_REACH) { | |
| 485 | 493 | // lock has expired so clamp the data and move on |
| 486 | 494 | _calibrationState = CALIBRATION_STATE_COMPLETE; |
| 487 | 495 | qCDebug(interfaceapp, "success: sixense calibration: forward"); |
| 488 | − // TODO: it is theoretically possible to detect that the controllers have been | |
| 496 | + // TODO: it is theoretically possible to detect that the controllers have been | |
| 489 | 497 | // accidentally switched (left hand is holding right controller) and to swap the order. |
| 490 | 498 | } |
| 491 | 499 | } |
| @@ -496,7 +504,7 @@ void SixenseManager::updateCalibration(const sixenseControllerData* controllers) · 4 unmodified lines | ||
| 496 | 504 | void SixenseManager::emulateMouse(PalmData* palm, int index) { |
| 497 | 505 | MyAvatar* avatar = DependencyManager::get<AvatarManager>()->getMyAvatar(); |
| 498 | 506 | QPoint pos; |
| 499 | − | |
| 507 | + | |
| 500 | 508 | Qt::MouseButton bumperButton; |
| 501 | 509 | Qt::MouseButton triggerButton; |
| 502 | 510 | |
| @@ -510,16 +518,16 @@ void SixenseManager::emulateMouse(PalmData* palm, int index) { · 7 unmodified lines | ||
| 510 | 518 | triggerButton = Qt::LeftButton; |
| 511 | 519 | } |
| 512 | 520 | |
| 513 | − if (Menu::getInstance()->isOptionChecked(MenuOption::SixenseLasers) | |
| 521 | + if (Menu::getInstance()->isOptionChecked(MenuOption::SixenseLasers) | |
| 514 | 522 | || Menu::getInstance()->isOptionChecked(MenuOption::EnableVRMode)) { |
| 515 | − pos = qApp->getApplicationOverlay().getPalmClickLocation(palm); | |
| 523 | + pos = qApp->getApplicationCompositor().getPalmClickLocation(palm); | |
| 516 | 524 | } else { |
| 517 | 525 | // Get directon relative to avatar orientation |
| 518 | 526 | glm::vec3 direction = glm::inverse(avatar->getOrientation()) * palm->getFingerDirection(); |
| 519 | 527 | |
| 520 | 528 | // Get the angles, scaled between (-0.5,0.5) |
| 521 | 529 | float xAngle = (atan2(direction.z, direction.x) + M_PI_2); |
| 522 | − float yAngle = 0.5f - ((atan2(direction.z, direction.y) + M_PI_2)); | |
| 530 | + float yAngle = 0.5f - ((atan2f(direction.z, direction.y) + (float)M_PI_2)); | |
| 523 | 531 | auto canvasSize = qApp->getCanvasSize(); |
| 524 | 532 | // Get the pixel range over which the xAngle and yAngle are scaled |
| 525 | 533 | float cursorRange = canvasSize.x * getCursorPixelRangeMult(); |
| @@ -562,11 +570,11 @@ void SixenseManager::emulateMouse(PalmData* palm, int index) { · 36 unmodified lines | ||
| 562 | 570 | if (!_bumperPressed[(int)(!index)]) { |
| 563 | 571 | qApp->mouseMoveEvent(&mouseEvent, deviceID); |
| 564 | 572 | } |
| 565 | − } | |
| 573 | + } | |
| 566 | 574 | } |
| 567 | 575 | _oldX[index] = pos.x(); |
| 568 | 576 | _oldY[index] = pos.y(); |
| 569 | − | |
| 577 | + | |
| 570 | 578 | |
| 571 | 579 | //We need separate coordinates for clicks, since we need to check if |
| 572 | 580 | //a magnification window was clicked on |
| @@ -580,7 +588,7 @@ void SixenseManager::emulateMouse(PalmData* palm, int index) { · 7 unmodified lines | ||
| 580 | 588 | if (palm->getControllerButtons() & BUTTON_FWD) { |
| 581 | 589 | if (!_bumperPressed[index]) { |
| 582 | 590 | _bumperPressed[index] = true; |
| 583 | − | |
| 591 | + | |
| 584 | 592 | QMouseEvent mouseEvent(QEvent::MouseButtonPress, pos, bumperButton, bumperButton, 0); |
| 585 | 593 | |
| 586 | 594 | qApp->mousePressEvent(&mouseEvent, deviceID); |
| @@ -12,6 +12,7 @@ · 11 unmodified lines | ||
| 12 | 12 | #include "InterfaceConfig.h" |
| 13 | 13 | |
| 14 | 14 | #include <glm/glm.hpp> |
| 15 | +#include <glm/gtc/type_ptr.hpp> | |
| 15 | 16 | |
| 16 | 17 | #include <GlowEffect.h> |
| 17 | 18 | #include "gpu/GLBackend.h" |
| @@ -106,21 +107,20 @@ void TV3DManager::display(RenderArgs* renderArgs, Camera& whichCamera) { · 88 unmodified lines | ||
| 106 | 107 | _activeEye = &eye; |
| 107 | 108 | glViewport(portalX, portalY, portalW, portalH); |
| 108 | 109 | glScissor(portalX, portalY, portalW, portalH); |
| 110 | + | |
| 111 | + glm::mat4 projection = glm::frustum<float>(eye.left, eye.right, eye.bottom, eye.top, nearZ, farZ); | |
| 112 | + float fov = atan(1.0f / projection[1][1]); | |
| 113 | + projection = glm::translate(projection, vec3(eye.modelTranslation, 0, 0)); | |
| 114 | + eyeCamera.setProjection(projection); | |
| 115 | + | |
| 109 | 116 | glMatrixMode(GL_PROJECTION); |
| 110 | 117 | glLoadIdentity(); // reset projection matrix |
| 111 | − glFrustum(eye.left, eye.right, eye.bottom, eye.top, nearZ, farZ); // set left view frustum | |
| 112 | − GLfloat p[4][4]; | |
| 113 | − // Really? | |
| 114 | − glGetFloatv(GL_PROJECTION_MATRIX, &(p[0][0])); | |
| 115 | − float cotangent = p[1][1]; | |
| 116 | − GLfloat fov = atan(1.0f / cotangent); | |
| 117 | − glTranslatef(eye.modelTranslation, 0.0, 0.0); // translate to cancel parallax | |
| 118 | − | |
| 118 | + glLoadMatrixf(glm::value_ptr(projection)); | |
| 119 | 119 | glMatrixMode(GL_MODELVIEW); |
| 120 | 120 | glLoadIdentity(); |
| 121 | 121 | renderArgs->_renderSide = RenderArgs::MONO; |
| 122 | 122 | qApp->displaySide(renderArgs, eyeCamera, false); |
| 123 | − qApp->getApplicationOverlay().displayOverlayTextureStereo(whichCamera, _aspect, fov); | |
| 123 | + qApp->getApplicationCompositor().displayOverlayTexture(renderArgs); | |
| 124 | 124 | _activeEye = NULL; |
| 125 | 125 | }, [&]{ |
| 126 | 126 | // render right side view |
| @@ -23,7 +23,7 @@ · 22 unmodified lines | ||
| 23 | 23 | #ifdef Q_OS_WIN |
| 24 | 24 | static BOOL CALLBACK enumWindowsCallback(HWND hWnd, LPARAM lParam) { |
| 25 | 25 | const UINT TIMEOUT = 200; // ms |
| 26 | − DWORD response; | |
| 26 | + DWORD_PTR response; | |
| 27 | 27 | LRESULT result = SendMessageTimeout(hWnd, UWM_IDENTIFY_INSTANCES, 0, 0, SMTO_BLOCK | SMTO_ABORTIFHUNG, TIMEOUT, &response); |
| 28 | 28 | if (result == 0) { // Timeout; continue search. |
| 29 | 29 | return TRUE; |
| @@ -463,7 +463,7 @@ void ControllerScriptingInterface::resetDevice(unsigned int device) { · 462 unmodified lines | ||
| 463 | 463 | } |
| 464 | 464 | |
| 465 | 465 | int ControllerScriptingInterface::findDevice(QString name) { |
| 466 | − Application::getUserInputMapper()->findDevice(name); | |
| 466 | + return Application::getUserInputMapper()->findDevice(name); | |
| 467 | 467 | } |
| 468 | 468 | |
| 469 | 469 | InputController::InputController(int deviceTrackerId, int subTrackerId, QObject* parent) : |
| @@ -65,6 +65,7 @@ public: · 64 unmodified lines | ||
| 65 | 65 | |
| 66 | 66 | void emitMouseMoveEvent(QMouseEvent* event, unsigned int deviceID = 0) { emit mouseMoveEvent(MouseEvent(*event, deviceID)); } |
| 67 | 67 | void emitMousePressEvent(QMouseEvent* event, unsigned int deviceID = 0) { emit mousePressEvent(MouseEvent(*event, deviceID)); } |
| 68 | + void emitMouseDoublePressEvent(QMouseEvent* event, unsigned int deviceID = 0) { emit mouseDoublePressEvent(MouseEvent(*event, deviceID)); } | |
| 68 | 69 | void emitMouseReleaseEvent(QMouseEvent* event, unsigned int deviceID = 0) { emit mouseReleaseEvent(MouseEvent(*event, deviceID)); } |
| 69 | 70 | |
| 70 | 71 | void emitTouchBeginEvent(const TouchEvent& event) { emit touchBeginEvent(event); } |
| @@ -25,9 +25,9 @@ bool HMDScriptingInterface::getHUDLookAtPosition3D(glm::vec3& result) const { · 24 unmodified lines | ||
| 25 | 25 | |
| 26 | 26 | glm::vec3 direction = orientation * glm::vec3(0.0f, 0.0f, -1.0f); |
| 27 | 27 | |
| 28 | − ApplicationOverlay& applicationOverlay = Application::getInstance()->getApplicationOverlay(); | |
| 28 | + const auto& compositor = Application::getInstance()->getApplicationCompositor(); | |
| 29 | 29 | |
| 30 | − return applicationOverlay.calculateRayUICollisionPoint(position, direction, result); | |
| 30 | + return compositor.calculateRayUICollisionPoint(position, direction, result); | |
| 31 | 31 | } |
| 32 | 32 | |
| 33 | 33 | QScriptValue HMDScriptingInterface::getHUDLookAtPosition2D(QScriptContext* context, QScriptEngine* engine) { |
| @@ -40,7 +40,7 @@ QScriptValue HMDScriptingInterface::getHUDLookAtPosition2D(QScriptContext* conte · 6 unmodified lines | ||
| 40 | 40 | glm::vec3 direction = glm::inverse(myAvatar->getOrientation()) * (hudIntersection - sphereCenter); |
| 41 | 41 | glm::quat rotation = ::rotationBetween(glm::vec3(0.0f, 0.0f, -1.0f), direction); |
| 42 | 42 | glm::vec3 eulers = ::safeEulerAngles(rotation); |
| 43 | − return qScriptValueFromValue<glm::vec2>(engine, Application::getInstance()->getApplicationOverlay() | |
| 43 | + return qScriptValueFromValue<glm::vec2>(engine, Application::getInstance()->getApplicationCompositor() | |
| 44 | 44 | .sphericalToOverlay(glm::vec2(eulers.y, -eulers.x))); |
| 45 | 45 | } |
| 46 | 46 | return QScriptValue::NullValue; |
| @@ -27,11 +27,11 @@ public: · 26 unmodified lines | ||
| 27 | 27 | static QScriptValue getHUDLookAtPosition3D(QScriptContext* context, QScriptEngine* engine); |
| 28 | 28 | |
| 29 | 29 | public slots: |
| 30 | − void toggleMagnifier() { Application::getInstance()->getApplicationOverlay().toggleMagnifier(); }; | |
| 30 | + void toggleMagnifier() { Application::getInstance()->getApplicationCompositor().toggleMagnifier(); }; | |
| 31 | 31 | |
| 32 | 32 | private: |
| 33 | 33 | HMDScriptingInterface() {}; |
| 34 | − bool getMagnifier() const { return Application::getInstance()->getApplicationOverlay().hasMagnifier(); }; | |
| 34 | + bool getMagnifier() const { return Application::getInstance()->getApplicationCompositor().hasMagnifier(); }; | |
| 35 | 35 | bool isHMDMode() const { return Application::getInstance()->isHMDMode(); } |
| 36 | 36 | |
| 37 | 37 | bool getHUDLookAtPosition3D(glm::vec3& result) const; |
| @@ -11,6 +11,7 @@ · 10 unmodified lines | ||
| 11 | 11 | // |
| 12 | 12 | |
| 13 | 13 | #include "starfield/renderer/Renderer.h" |
| 14 | +#include "Application.h" | |
| 14 | 15 | |
| 15 | 16 | using namespace starfield; |
| 16 | 17 | |
| @@ -52,6 +53,10 @@ void Renderer::render(float perspective, float aspect, mat4 const& orientation, · 35 unmodified lines | ||
| 52 | 53 | matrix[3][1] = 0.0f; |
| 53 | 54 | matrix[3][2] = 0.0f; |
| 54 | 55 | |
| 56 | + glMatrixMode(GL_PROJECTION); | |
| 57 | + glPushMatrix(); | |
| 58 | + glLoadMatrixf(glm::value_ptr(qApp->getDisplayViewFrustum()->getProjection())); | |
| 59 | + glMatrixMode(GL_MODELVIEW); | |
| 55 | 60 | // extract local z vector |
| 56 | 61 | vec3 ahead = vec3(matrix[2]); |
| 57 | 62 | |
| @@ -74,6 +79,10 @@ void Renderer::render(float perspective, float aspect, mat4 const& orientation, · 16 unmodified lines | ||
| 74 | 79 | floodFill(cursor, TileSelection(*this, _tileArray, _tileArray + _tiling.getTileCount(), (TileSelection::Cursor*) _batchCountArray)); |
| 75 | 80 | |
| 76 | 81 | this->glBatch(glm::value_ptr(matrix), prepareBatch((unsigned*) _batchOffs, _outIndexPos), alpha); |
| 82 | + glMatrixMode(GL_PROJECTION); | |
| 83 | + glPopMatrix(); | |
| 84 | + glMatrixMode(GL_MODELVIEW); | |
| 85 | + | |
| 77 | 86 | } |
| 78 | 87 | |
| 79 | 88 | // renderer construction |
| @@ -22,6 +22,20 @@ AddressBarDialog::AddressBarDialog(QQuickItem* parent) : OffscreenQmlDialog(pare · 21 unmodified lines | ||
| 22 | 22 | connect(addressManager.data(), &AddressManager::lookupResultIsOffline, this, &AddressBarDialog::displayAddressOfflineMessage); |
| 23 | 23 | connect(addressManager.data(), &AddressManager::lookupResultIsNotFound, this, &AddressBarDialog::displayAddressNotFoundMessage); |
| 24 | 24 | connect(addressManager.data(), &AddressManager::lookupResultsFinished, this, &AddressBarDialog::hide); |
| 25 | + connect(addressManager.data(), &AddressManager::goBackPossible, this, [this] (bool isPossible) { | |
| 26 | + if (isPossible != _backEnabled) { | |
| 27 | + _backEnabled = isPossible; | |
| 28 | + emit backEnabledChanged(); | |
| 29 | + } | |
| 30 | + }); | |
| 31 | + connect(addressManager.data(), &AddressManager::goForwardPossible, this, [this] (bool isPossible) { | |
| 32 | + if (isPossible != _forwardEnabled) { | |
| 33 | + _forwardEnabled = isPossible; | |
| 34 | + emit forwardEnabledChanged(); | |
| 35 | + } | |
| 36 | + }); | |
| 37 | + _backEnabled = !(DependencyManager::get<AddressManager>()->getBackStack().isEmpty()); | |
| 38 | + _forwardEnabled = !(DependencyManager::get<AddressManager>()->getForwardStack().isEmpty()); | |
| 25 | 39 | } |
| 26 | 40 | |
| 27 | 41 | void AddressBarDialog::hide() { |
| @@ -35,6 +49,16 @@ void AddressBarDialog::loadAddress(const QString& address) { · 7 unmodified lines | ||
| 35 | 49 | } |
| 36 | 50 | } |
| 37 | 51 | |
| 52 | +void AddressBarDialog::loadBack() { | |
| 53 | + qDebug() << "Called LoadBack"; | |
| 54 | + DependencyManager::get<AddressManager>()->goBack(); | |
| 55 | +} | |
| 56 | + | |
| 57 | +void AddressBarDialog::loadForward() { | |
| 58 | + qDebug() << "Called LoadForward"; | |
| 59 | + DependencyManager::get<AddressManager>()->goForward(); | |
| 60 | +} | |
| 61 | + | |
| 38 | 62 | void AddressBarDialog::displayAddressOfflineMessage() { |
| 39 | 63 | OffscreenUi::error("That user or place is currently offline"); |
| 40 | 64 | } |
| @@ -18,9 +18,17 @@ class AddressBarDialog : public OffscreenQmlDialog · 17 unmodified lines | ||
| 18 | 18 | { |
| 19 | 19 | Q_OBJECT |
| 20 | 20 | HIFI_QML_DECL |
| 21 | + Q_PROPERTY(bool backEnabled READ backEnabled NOTIFY backEnabledChanged) | |
| 22 | + Q_PROPERTY(bool forwardEnabled READ forwardEnabled NOTIFY forwardEnabledChanged) | |
| 21 | 23 | |
| 22 | 24 | public: |
| 23 | 25 | AddressBarDialog(QQuickItem* parent = nullptr); |
| 26 | + bool backEnabled() { return _backEnabled; } | |
| 27 | + bool forwardEnabled() { return _forwardEnabled; } | |
| 28 | + | |
| 29 | +signals: | |
| 30 | + void backEnabledChanged(); | |
| 31 | + void forwardEnabledChanged(); | |
| 24 | 32 | |
| 25 | 33 | protected: |
| 26 | 34 | void displayAddressOfflineMessage(); |
| @@ -28,6 +36,11 @@ protected: · 1 unmodified line | ||
| 28 | 36 | void hide(); |
| 29 | 37 | |
| 30 | 38 | Q_INVOKABLE void loadAddress(const QString& address); |
| 39 | + Q_INVOKABLE void loadBack(); | |
| 40 | + Q_INVOKABLE void loadForward(); | |
| 41 | + | |
| 42 | + bool _backEnabled; | |
| 43 | + bool _forwardEnabled; | |
| 31 | 44 | }; |
| 32 | 45 | |
| 33 | 46 | #endif |
| @@ -0,0 +1,761 @@ | ||
| 1 | +// | |
| 2 | +// ApplicationCompositor.cpp | |
| 3 | +// interface/src/ui/overlays | |
| 4 | +// | |
| 5 | +// Created by Benjamin Arnold on 5/27/14. | |
| 6 | +// Copyright 2014 High Fidelity, Inc. | |
| 7 | +// | |
| 8 | +// Distributed under the Apache License, Version 2.0. | |
| 9 | +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html | |
| 10 | +// | |
| 11 | + | |
| 12 | +#include "InterfaceConfig.h" | |
| 13 | + | |
| 14 | +#include "ApplicationCompositor.h" | |
| 15 | + | |
| 16 | +#include <glm/gtc/type_ptr.hpp> | |
| 17 | + | |
| 18 | +#include <avatar/AvatarManager.h> | |
| 19 | +#include <gpu/GLBackend.h> | |
| 20 | +#include <CursorManager.h> | |
| 21 | +#include <Tooltip.h> | |
| 22 | + | |
| 23 | +#include "Application.h" | |
| 24 | + | |
| 25 | + | |
| 26 | +// Used to animate the magnification windows | |
| 27 | +static const float MAG_SPEED = 0.08f; | |
| 28 | + | |
| 29 | +static const quint64 MSECS_TO_USECS = 1000ULL; | |
| 30 | +static const quint64 TOOLTIP_DELAY = 500 * MSECS_TO_USECS; | |
| 31 | + | |
| 32 | +static const float WHITE_TEXT[] = { 0.93f, 0.93f, 0.93f }; | |
| 33 | +static const float RETICLE_COLOR[] = { 0.0f, 198.0f / 255.0f, 244.0f / 255.0f }; | |
| 34 | +static const float reticleSize = TWO_PI / 100.0f; | |
| 35 | + | |
| 36 | +static const float CONNECTION_STATUS_BORDER_COLOR[] = { 1.0f, 0.0f, 0.0f }; | |
| 37 | +static const float CONNECTION_STATUS_BORDER_LINE_WIDTH = 4.0f; | |
| 38 | + | |
| 39 | +static const float CURSOR_PIXEL_SIZE = 32.0f; | |
| 40 | +static const float MOUSE_PITCH_RANGE = 1.0f * PI; | |
| 41 | +static const float MOUSE_YAW_RANGE = 0.5f * TWO_PI; | |
| 42 | +static const glm::vec2 MOUSE_RANGE(MOUSE_YAW_RANGE, MOUSE_PITCH_RANGE); | |
| 43 | + | |
| 44 | +static gpu::BufferPointer _hemiVertices; | |
| 45 | +static gpu::BufferPointer _hemiIndices; | |
| 46 | +static int _hemiIndexCount{ 0 }; | |
| 47 | +EntityItemID ApplicationCompositor::_noItemId; | |
| 48 | +static QString _tooltipId; | |
| 49 | + | |
| 50 | +// Return a point's cartesian coordinates on a sphere from pitch and yaw | |
| 51 | +glm::vec3 getPoint(float yaw, float pitch) { | |
| 52 | + return glm::vec3(glm::cos(-pitch) * (-glm::sin(yaw)), | |
| 53 | + glm::sin(-pitch), | |
| 54 | + glm::cos(-pitch) * (-glm::cos(yaw))); | |
| 55 | +} | |
| 56 | + | |
| 57 | +//Checks if the given ray intersects the sphere at the origin. result will store a multiplier that should | |
| 58 | +//be multiplied by dir and added to origin to get the location of the collision | |
| 59 | +bool raySphereIntersect(const glm::vec3 &dir, const glm::vec3 &origin, float r, float* result) | |
| 60 | +{ | |
| 61 | + //Source: http://wiki.cgsociety.org/index.php/Ray_Sphere_Intersection | |
| 62 | + | |
| 63 | + //Compute A, B and C coefficients | |
| 64 | + float a = glm::dot(dir, dir); | |
| 65 | + float b = 2 * glm::dot(dir, origin); | |
| 66 | + float c = glm::dot(origin, origin) - (r * r); | |
| 67 | + | |
| 68 | + //Find discriminant | |
| 69 | + float disc = b * b - 4 * a * c; | |
| 70 | + | |
| 71 | + // if discriminant is negative there are no real roots, so return | |
| 72 | + // false as ray misses sphere | |
| 73 | + if (disc < 0) { | |
| 74 | + return false; | |
| 75 | + } | |
| 76 | + | |
| 77 | + // compute q as described above | |
| 78 | + float distSqrt = sqrtf(disc); | |
| 79 | + float q; | |
| 80 | + if (b < 0) { | |
| 81 | + q = (-b - distSqrt) / 2.0f; | |
| 82 | + } else { | |
| 83 | + q = (-b + distSqrt) / 2.0f; | |
| 84 | + } | |
| 85 | + | |
| 86 | + // compute t0 and t1 | |
| 87 | + float t0 = q / a; | |
| 88 | + float t1 = c / q; | |
| 89 | + | |
| 90 | + // make sure t0 is smaller than t1 | |
| 91 | + if (t0 > t1) { | |
| 92 | + // if t0 is bigger than t1 swap them around | |
| 93 | + float temp = t0; | |
| 94 | + t0 = t1; | |
| 95 | + t1 = temp; | |
| 96 | + } | |
| 97 | + | |
| 98 | + // if t1 is less than zero, the object is in the ray's negative direction | |
| 99 | + // and consequently the ray misses the sphere | |
| 100 | + if (t1 < 0) { | |
| 101 | + return false; | |
| 102 | + } | |
| 103 | + | |
| 104 | + // if t0 is less than zero, the intersection point is at t1 | |
| 105 | + if (t0 < 0) { | |
| 106 | + *result = t1; | |
| 107 | + return true; | |
| 108 | + } else { // else the intersection point is at t0 | |
| 109 | + *result = t0; | |
| 110 | + return true; | |
| 111 | + } | |
| 112 | +} | |
| 113 | + | |
| 114 | +ApplicationCompositor::ApplicationCompositor() { | |
| 115 | + memset(_reticleActive, 0, sizeof(_reticleActive)); | |
| 116 | + memset(_magActive, 0, sizeof(_reticleActive)); | |
| 117 | + memset(_magSizeMult, 0, sizeof(_magSizeMult)); | |
| 118 | + | |
| 119 | + auto geometryCache = DependencyManager::get<GeometryCache>(); | |
| 120 | + | |
| 121 | + _reticleQuad = geometryCache->allocateID(); | |
| 122 | + _magnifierQuad = geometryCache->allocateID(); | |
| 123 | + _magnifierBorder = geometryCache->allocateID(); | |
| 124 | + | |
| 125 | + auto entityScriptingInterface = DependencyManager::get<EntityScriptingInterface>(); | |
| 126 | + connect(entityScriptingInterface.data(), &EntityScriptingInterface::hoverEnterEntity, [=](const EntityItemID& entityItemID, const MouseEvent& event) { | |
| 127 | + if (_hoverItemId != entityItemID) { | |
| 128 | + _hoverItemId = entityItemID; | |
| 129 | + _hoverItemEnterUsecs = usecTimestampNow(); | |
| 130 | + auto properties = entityScriptingInterface->getEntityProperties(_hoverItemId); | |
| 131 | + _hoverItemHref = properties.getHref(); | |
| 132 | + auto cursor = Cursor::Manager::instance().getCursor(); | |
| 133 | + if (!_hoverItemHref.isEmpty()) { | |
| 134 | + cursor->setIcon(Cursor::Icon::LINK); | |
| 135 | + } else { | |
| 136 | + cursor->setIcon(Cursor::Icon::DEFAULT); | |
| 137 | + } | |
| 138 | + } | |
| 139 | + }); | |
| 140 | + | |
| 141 | + connect(entityScriptingInterface.data(), &EntityScriptingInterface::hoverLeaveEntity, [=](const EntityItemID& entityItemID, const MouseEvent& event) { | |
| 142 | + if (_hoverItemId == entityItemID) { | |
| 143 | + _hoverItemId = _noItemId; | |
| 144 | + _hoverItemHref.clear(); | |
| 145 | + auto cursor = Cursor::Manager::instance().getCursor(); | |
| 146 | + cursor->setIcon(Cursor::Icon::DEFAULT); | |
| 147 | + if (!_tooltipId.isEmpty()) { | |
| 148 | + qDebug() << "Closing tooltip " << _tooltipId; | |
| 149 | + Tooltip::closeTip(_tooltipId); | |
| 150 | + _tooltipId.clear(); | |
| 151 | + } | |
| 152 | + } | |
| 153 | + }); | |
| 154 | +} | |
| 155 | + | |
| 156 | +ApplicationCompositor::~ApplicationCompositor() { | |
| 157 | +} | |
| 158 | + | |
| 159 | + | |
| 160 | +void ApplicationCompositor::bindCursorTexture(gpu::Batch& batch, uint8_t cursorIndex) { | |
| 161 | + auto& cursorManager = Cursor::Manager::instance(); | |
| 162 | + auto cursor = cursorManager.getCursor(cursorIndex); | |
| 163 | + auto iconId = cursor->getIcon(); | |
| 164 | + if (!_cursors.count(iconId)) { | |
| 165 | + auto iconPath = cursorManager.getIconImage(cursor->getIcon()); | |
| 166 | + _cursors[iconId] = DependencyManager::get<TextureCache>()-> | |
| 167 | + getImageTexture(iconPath); | |
| 168 | + } | |
| 169 | + batch.setUniformTexture(0, _cursors[iconId]); | |
| 170 | +} | |
| 171 | + | |
| 172 | +// Draws the FBO texture for the screen | |
| 173 | +void ApplicationCompositor::displayOverlayTexture(RenderArgs* renderArgs) { | |
| 174 | + if (_alpha == 0.0f) { | |
| 175 | + return; | |
| 176 | + } | |
| 177 | + | |
| 178 | + GLuint texture = qApp->getApplicationOverlay().getOverlayTexture(); | |
| 179 | + if (!texture) { | |
| 180 | + return; | |
| 181 | + } | |
| 182 | + | |
| 183 | + updateTooltips(); | |
| 184 | + | |
| 185 | + vec2 canvasSize = qApp->getCanvasSize(); | |
| 186 | + | |
| 187 | + //Handle fading and deactivation/activation of UI | |
| 188 | + gpu::Batch batch; | |
| 189 | + | |
| 190 | + renderArgs->_context->syncCache(); | |
| 191 | + auto geometryCache = DependencyManager::get<GeometryCache>(); | |
| 192 | + | |
| 193 | + geometryCache->useSimpleDrawPipeline(batch); | |
| 194 | + batch.setModelTransform(Transform()); | |
| 195 | + batch.setViewTransform(Transform()); | |
| 196 | + batch.setProjectionTransform(mat4()); | |
| 197 | + batch._glBindTexture(GL_TEXTURE_2D, texture); | |
| 198 | + batch._glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); | |
| 199 | + batch._glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); | |
| 200 | + geometryCache->renderUnitQuad(batch, vec4(vec3(1), _alpha)); | |
| 201 | + | |
| 202 | + // Doesn't actually render | |
| 203 | + renderPointers(batch); | |
| 204 | + | |
| 205 | + //draw the mouse pointer | |
| 206 | + // Get the mouse coordinates and convert to NDC [-1, 1] | |
| 207 | + vec2 mousePosition = toNormalizedDeviceScale(vec2(qApp->getMouse()), canvasSize); | |
| 208 | + // Invert the Y axis | |
| 209 | + mousePosition.y *= -1.0f; | |
| 210 | + | |
| 211 | + Transform model; | |
| 212 | + model.setTranslation(vec3(mousePosition, 0)); | |
| 213 | + vec2 mouseSize = CURSOR_PIXEL_SIZE / canvasSize; | |
| 214 | + model.setScale(vec3(mouseSize, 1.0f)); | |
| 215 | + batch.setModelTransform(model); | |
| 216 | + bindCursorTexture(batch); | |
| 217 | + vec4 reticleColor = { RETICLE_COLOR[0], RETICLE_COLOR[1], RETICLE_COLOR[2], 1.0f }; | |
| 218 | + geometryCache->renderUnitQuad(batch, vec4(1)); | |
| 219 | + renderArgs->_context->render(batch); | |
| 220 | +} | |
| 221 | + | |
| 222 | + | |
| 223 | +vec2 getPolarCoordinates(const PalmData& palm) { | |
| 224 | + MyAvatar* myAvatar = DependencyManager::get<AvatarManager>()->getMyAvatar(); | |
| 225 | + auto avatarOrientation = myAvatar->getOrientation(); | |
| 226 | + auto eyePos = myAvatar->getDefaultEyePosition(); | |
| 227 | + glm::vec3 tip = myAvatar->getLaserPointerTipPosition(&palm); | |
| 228 | + // Direction of the tip relative to the eye | |
| 229 | + glm::vec3 tipDirection = tip - eyePos; | |
| 230 | + // orient into avatar space | |
| 231 | + tipDirection = glm::inverse(avatarOrientation) * tipDirection; | |
| 232 | + // Normalize for trig functions | |
| 233 | + tipDirection = glm::normalize(tipDirection); | |
| 234 | + // Convert to polar coordinates | |
| 235 | + glm::vec2 polar(glm::atan(tipDirection.x, -tipDirection.z), glm::asin(tipDirection.y)); | |
| 236 | + return polar; | |
| 237 | +} | |
| 238 | + | |
| 239 | +// Draws the FBO texture for Oculus rift. | |
| 240 | +void ApplicationCompositor::displayOverlayTextureHmd(RenderArgs* renderArgs, int eye) { | |
| 241 | + if (_alpha == 0.0f) { | |
| 242 | + return; | |
| 243 | + } | |
| 244 | + | |
| 245 | + GLuint texture = qApp->getApplicationOverlay().getOverlayTexture(); | |
| 246 | + if (!texture) { | |
| 247 | + return; | |
| 248 | + } | |
| 249 | + | |
| 250 | + updateTooltips(); | |
| 251 | + | |
| 252 | + vec2 canvasSize = qApp->getCanvasSize(); | |
| 253 | + _textureAspectRatio = aspect(canvasSize); | |
| 254 | + | |
| 255 | + renderArgs->_context->syncCache(); | |
| 256 | + auto geometryCache = DependencyManager::get<GeometryCache>(); | |
| 257 | + | |
| 258 | + gpu::Batch batch; | |
| 259 | + geometryCache->useSimpleDrawPipeline(batch); | |
| 260 | + batch._glDisable(GL_DEPTH_TEST); | |
| 261 | + batch._glDisable(GL_CULL_FACE); | |
| 262 | + batch._glBindTexture(GL_TEXTURE_2D, texture); | |
| 263 | + batch._glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); | |
| 264 | + batch._glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); | |
| 265 | + batch.setViewTransform(Transform()); | |
| 266 | + batch.setProjectionTransform(qApp->getEyeProjection(eye)); | |
| 267 | + | |
| 268 | + mat4 eyePose = qApp->getEyePose(eye); | |
| 269 | + glm::mat4 overlayXfm = glm::inverse(eyePose); | |
| 270 | + | |
| 271 | +#ifdef DEBUG_OVERLAY | |
| 272 | + { | |
| 273 | + batch.setModelTransform(glm::translate(mat4(), vec3(0, 0, -2))); | |
| 274 | + geometryCache->renderUnitQuad(batch, glm::vec4(1)); | |
| 275 | + } | |
| 276 | +#else | |
| 277 | + { | |
| 278 | + batch.setModelTransform(overlayXfm); | |
| 279 | + drawSphereSection(batch); | |
| 280 | + } | |
| 281 | +#endif | |
| 282 | + | |
| 283 | + // Doesn't actually render | |
| 284 | + renderPointers(batch); | |
| 285 | + vec3 reticleScale = vec3(Cursor::Manager::instance().getScale() * reticleSize); | |
| 286 | + | |
| 287 | + bindCursorTexture(batch); | |
| 288 | + | |
| 289 | + MyAvatar* myAvatar = DependencyManager::get<AvatarManager>()->getMyAvatar(); | |
| 290 | + //Controller Pointers | |
| 291 | + for (int i = 0; i < (int)myAvatar->getHand()->getNumPalms(); i++) { | |
| 292 | + PalmData& palm = myAvatar->getHand()->getPalms()[i]; | |
| 293 | + if (palm.isActive()) { | |
| 294 | + glm::vec2 polar = getPolarCoordinates(palm); | |
| 295 | + // Convert to quaternion | |
| 296 | + mat4 pointerXfm = glm::mat4_cast(quat(vec3(polar.y, -polar.x, 0.0f))) * glm::translate(mat4(), vec3(0, 0, -1)); | |
| 297 | + mat4 reticleXfm = overlayXfm * pointerXfm; | |
| 298 | + reticleXfm = glm::scale(reticleXfm, reticleScale); | |
| 299 | + batch.setModelTransform(reticleXfm); | |
| 300 | + // Render reticle at location | |
| 301 | + geometryCache->renderUnitQuad(batch, glm::vec4(1), _reticleQuad); | |
| 302 | + } | |
| 303 | + } | |
| 304 | + | |
| 305 | + //Mouse Pointer | |
| 306 | + if (_reticleActive[MOUSE]) { | |
| 307 | + glm::vec2 projection = screenToSpherical(glm::vec2(_reticlePosition[MOUSE].x(), | |
| 308 | + _reticlePosition[MOUSE].y())); | |
| 309 | + mat4 pointerXfm = glm::mat4_cast(quat(vec3(-projection.y, projection.x, 0.0f))) * glm::translate(mat4(), vec3(0, 0, -1)); | |
| 310 | + mat4 reticleXfm = overlayXfm * pointerXfm; | |
| 311 | + reticleXfm = glm::scale(reticleXfm, reticleScale); | |
| 312 | + batch.setModelTransform(reticleXfm); | |
| 313 | + geometryCache->renderUnitQuad(batch, glm::vec4(1), _reticleQuad); | |
| 314 | + } | |
| 315 | + | |
| 316 | + renderArgs->_context->render(batch); | |
| 317 | +} | |
| 318 | + | |
| 319 | + | |
| 320 | +void ApplicationCompositor::computeHmdPickRay(glm::vec2 cursorPos, glm::vec3& origin, glm::vec3& direction) const { | |
| 321 | + cursorPos *= qApp->getCanvasSize(); | |
| 322 | + const glm::vec2 projection = screenToSpherical(cursorPos); | |
| 323 | + // The overlay space orientation of the mouse coordinates | |
| 324 | + const glm::quat orientation(glm::vec3(-projection.y, projection.x, 0.0f)); | |
| 325 | + // FIXME We now have the direction of the ray FROM THE DEFAULT HEAD POSE. | |
| 326 | + // Now we need to account for the actual camera position relative to the overlay | |
| 327 | + glm::vec3 overlaySpaceDirection = glm::normalize(orientation * IDENTITY_FRONT); | |
| 328 | + | |
| 329 | + | |
| 330 | + // We need the RAW camera orientation and position, because this is what the overlay is | |
| 331 | + // rendered relative to | |
| 332 | + const glm::vec3 overlayPosition = qApp->getCamera()->getPosition(); | |
| 333 | + const glm::quat overlayOrientation = qApp->getCamera()->getRotation(); | |
| 334 | + | |
| 335 | + // Intersection UI overlay space | |
| 336 | + glm::vec3 worldSpaceDirection = overlayOrientation * overlaySpaceDirection; | |
| 337 | + glm::vec3 worldSpaceIntersection = (glm::normalize(worldSpaceDirection) * _oculusUIRadius) + overlayPosition; | |
| 338 | + glm::vec3 worldSpaceHeadPosition = (overlayOrientation * glm::vec3(qApp->getHeadPose()[3])) + overlayPosition; | |
| 339 | + | |
| 340 | + // Intersection in world space | |
| 341 | + origin = worldSpaceHeadPosition; | |
| 342 | + direction = glm::normalize(worldSpaceIntersection - worldSpaceHeadPosition); | |
| 343 | +} | |
| 344 | + | |
| 345 | +//Caculate the click location using one of the sixense controllers. Scale is not applied | |
| 346 | +QPoint ApplicationCompositor::getPalmClickLocation(const PalmData *palm) const { | |
| 347 | + QPoint rv; | |
| 348 | + auto canvasSize = qApp->getCanvasSize(); | |
| 349 | + if (qApp->isHMDMode()) { | |
| 350 | + glm::vec2 polar = getPolarCoordinates(*palm); | |
| 351 | + glm::vec2 point = sphericalToScreen(-polar); | |
| 352 | + rv.rx() = point.x; | |
| 353 | + rv.ry() = point.y; | |
| 354 | + } else { | |
| 355 | + MyAvatar* myAvatar = DependencyManager::get<AvatarManager>()->getMyAvatar(); | |
| 356 | + glm::dmat4 projection; | |
| 357 | + qApp->getProjectionMatrix(&projection); | |
| 358 | + glm::quat invOrientation = glm::inverse(myAvatar->getOrientation()); | |
| 359 | + glm::vec3 eyePos = myAvatar->getDefaultEyePosition(); | |
| 360 | + glm::vec3 tip = myAvatar->getLaserPointerTipPosition(palm); | |
| 361 | + glm::vec3 tipPos = invOrientation * (tip - eyePos); | |
| 362 | + | |
| 363 | + glm::vec4 clipSpacePos = glm::vec4(projection * glm::dvec4(tipPos, 1.0)); | |
| 364 | + glm::vec3 ndcSpacePos; | |
| 365 | + if (clipSpacePos.w != 0) { | |
| 366 | + ndcSpacePos = glm::vec3(clipSpacePos) / clipSpacePos.w; | |
| 367 | + } | |
| 368 | + | |
| 369 | + rv.setX(((ndcSpacePos.x + 1.0) / 2.0) * canvasSize.x); | |
| 370 | + rv.setY((1.0 - ((ndcSpacePos.y + 1.0) / 2.0)) * canvasSize.y); | |
| 371 | + } | |
| 372 | + return rv; | |
| 373 | +} | |
| 374 | + | |
| 375 | +//Finds the collision point of a world space ray | |
| 376 | +bool ApplicationCompositor::calculateRayUICollisionPoint(const glm::vec3& position, const glm::vec3& direction, glm::vec3& result) const { | |
| 377 | + MyAvatar* myAvatar = DependencyManager::get<AvatarManager>()->getMyAvatar(); | |
| 378 | + | |
| 379 | + glm::quat inverseOrientation = glm::inverse(myAvatar->getOrientation()); | |
| 380 | + | |
| 381 | + glm::vec3 relativePosition = inverseOrientation * (position - myAvatar->getDefaultEyePosition()); | |
| 382 | + glm::vec3 relativeDirection = glm::normalize(inverseOrientation * direction); | |
| 383 | + | |
| 384 | + float t; | |
| 385 | + if (raySphereIntersect(relativeDirection, relativePosition, _oculusUIRadius * myAvatar->getScale(), &t)){ | |
| 386 | + result = position + direction * t; | |
| 387 | + return true; | |
| 388 | + } | |
| 389 | + | |
| 390 | + return false; | |
| 391 | +} | |
| 392 | + | |
| 393 | +//Renders optional pointers | |
| 394 | +void ApplicationCompositor::renderPointers(gpu::Batch& batch) { | |
| 395 | + if (qApp->isHMDMode() && !qApp->getLastMouseMoveWasSimulated() && !qApp->isMouseHidden()) { | |
| 396 | + //If we are in oculus, render reticle later | |
| 397 | + QPoint position = QPoint(qApp->getTrueMouseX(), qApp->getTrueMouseY()); | |
| 398 | + _reticlePosition[MOUSE] = position; | |
| 399 | + _reticleActive[MOUSE] = true; | |
| 400 | + _magActive[MOUSE] = _magnifier; | |
| 401 | + _reticleActive[LEFT_CONTROLLER] = false; | |
| 402 | + _reticleActive[RIGHT_CONTROLLER] = false; | |
| 403 | + } else if (qApp->getLastMouseMoveWasSimulated() && Menu::getInstance()->isOptionChecked(MenuOption::SixenseMouseInput)) { | |
| 404 | + //only render controller pointer if we aren't already rendering a mouse pointer | |
| 405 | + _reticleActive[MOUSE] = false; | |
| 406 | + _magActive[MOUSE] = false; | |
| 407 | + renderControllerPointers(batch); | |
| 408 | + } | |
| 409 | +} | |
| 410 | + | |
| 411 | + | |
| 412 | +void ApplicationCompositor::renderControllerPointers(gpu::Batch& batch) { | |
| 413 | + MyAvatar* myAvatar = DependencyManager::get<AvatarManager>()->getMyAvatar(); | |
| 414 | + | |
| 415 | + //Static variables used for storing controller state | |
| 416 | + static quint64 pressedTime[NUMBER_OF_RETICLES] = { 0ULL, 0ULL, 0ULL }; | |
| 417 | + static bool isPressed[NUMBER_OF_RETICLES] = { false, false, false }; | |
| 418 | + static bool stateWhenPressed[NUMBER_OF_RETICLES] = { false, false, false }; | |
| 419 | + | |
| 420 | + const HandData* handData = DependencyManager::get<AvatarManager>()->getMyAvatar()->getHandData(); | |
| 421 | + | |
| 422 | + for (unsigned int palmIndex = 2; palmIndex < 4; palmIndex++) { | |
| 423 | + const int index = palmIndex - 1; | |
| 424 | + | |
| 425 | + const PalmData* palmData = NULL; | |
| 426 | + | |
| 427 | + if (palmIndex >= handData->getPalms().size()) { | |
| 428 | + return; | |
| 429 | + } | |
| 430 | + | |
| 431 | + if (handData->getPalms()[palmIndex].isActive()) { | |
| 432 | + palmData = &handData->getPalms()[palmIndex]; | |
| 433 | + } else { | |
| 434 | + continue; | |
| 435 | + } | |
| 436 | + | |
| 437 | + int controllerButtons = palmData->getControllerButtons(); | |
| 438 | + | |
| 439 | + //Check for if we should toggle or drag the magnification window | |
| 440 | + if (controllerButtons & BUTTON_3) { | |
| 441 | + if (isPressed[index] == false) { | |
| 442 | + //We are now dragging the window | |
| 443 | + isPressed[index] = true; | |
| 444 | + //set the pressed time in us | |
| 445 | + pressedTime[index] = usecTimestampNow(); | |
| 446 | + stateWhenPressed[index] = _magActive[index]; | |
| 447 | + } | |
| 448 | + } else if (isPressed[index]) { | |
| 449 | + isPressed[index] = false; | |
| 450 | + //If the button was only pressed for < 250 ms | |
| 451 | + //then disable it. | |
| 452 | + | |
| 453 | + const int MAX_BUTTON_PRESS_TIME = 250 * MSECS_TO_USECS; | |
| 454 | + if (usecTimestampNow() < pressedTime[index] + MAX_BUTTON_PRESS_TIME) { | |
| 455 | + _magActive[index] = !stateWhenPressed[index]; | |
| 456 | + } | |
| 457 | + } | |
| 458 | + | |
| 459 | + //if we have the oculus, we should make the cursor smaller since it will be | |
| 460 | + //magnified | |
| 461 | + if (qApp->isHMDMode()) { | |
| 462 | + | |
| 463 | + QPoint point = getPalmClickLocation(palmData); | |
| 464 | + | |
| 465 | + _reticlePosition[index] = point; | |
| 466 | + | |
| 467 | + //When button 2 is pressed we drag the mag window | |
| 468 | + if (isPressed[index]) { | |
| 469 | + _magActive[index] = true; | |
| 470 | + } | |
| 471 | + | |
| 472 | + // If oculus is enabled, we draw the crosshairs later | |
| 473 | + continue; | |
| 474 | + } | |
| 475 | + | |
| 476 | + auto canvasSize = qApp->getCanvasSize(); | |
| 477 | + int mouseX, mouseY; | |
| 478 | + if (Menu::getInstance()->isOptionChecked(MenuOption::SixenseLasers)) { | |
| 479 | + QPoint res = getPalmClickLocation(palmData); | |
| 480 | + mouseX = res.x(); | |
| 481 | + mouseY = res.y(); | |
| 482 | + } else { | |
| 483 | + // Get directon relative to avatar orientation | |
| 484 | + glm::vec3 direction = glm::inverse(myAvatar->getOrientation()) * palmData->getFingerDirection(); | |
| 485 | + | |
| 486 | + // Get the angles, scaled between (-0.5,0.5) | |
| 487 | + float xAngle = (atan2(direction.z, direction.x) + M_PI_2); | |
| 488 | + float yAngle = 0.5f - ((atan2(direction.z, direction.y) + M_PI_2)); | |
| 489 | + | |
| 490 | + // Get the pixel range over which the xAngle and yAngle are scaled | |
| 491 | + float cursorRange = canvasSize.x * SixenseManager::getInstance().getCursorPixelRangeMult(); | |
| 492 | + | |
| 493 | + mouseX = (canvasSize.x / 2.0f + cursorRange * xAngle); | |
| 494 | + mouseY = (canvasSize.y / 2.0f + cursorRange * yAngle); | |
| 495 | + } | |
| 496 | + | |
| 497 | + //If the cursor is out of the screen then don't render it | |
| 498 | + if (mouseX < 0 || mouseX >= (int)canvasSize.x || mouseY < 0 || mouseY >= (int)canvasSize.y) { | |
| 499 | + _reticleActive[index] = false; | |
| 500 | + continue; | |
| 501 | + } | |
| 502 | + _reticleActive[index] = true; | |
| 503 | + | |
| 504 | + | |
| 505 | + const float reticleSize = 40.0f; | |
| 506 | + | |
| 507 | + mouseX -= reticleSize / 2.0f; | |
| 508 | + mouseY += reticleSize / 2.0f; | |
| 509 | + | |
| 510 | + | |
| 511 | + glm::vec2 topLeft(mouseX, mouseY); | |
| 512 | + glm::vec2 bottomRight(mouseX + reticleSize, mouseY - reticleSize); | |
| 513 | + glm::vec2 texCoordTopLeft(0.0f, 0.0f); | |
| 514 | + glm::vec2 texCoordBottomRight(1.0f, 1.0f); | |
| 515 | + | |
| 516 | + DependencyManager::get<GeometryCache>()->renderQuad(topLeft, bottomRight, texCoordTopLeft, texCoordBottomRight, | |
| 517 | + glm::vec4(RETICLE_COLOR[0], RETICLE_COLOR[1], RETICLE_COLOR[2], 1.0f)); | |
| 518 | + | |
| 519 | + } | |
| 520 | +} | |
| 521 | + | |
| 522 | +//Renders a small magnification of the currently bound texture at the coordinates | |
| 523 | +void ApplicationCompositor::renderMagnifier(gpu::Batch& batch, const glm::vec2& magPos, float sizeMult, bool showBorder) { | |
| 524 | + if (!_magnifier) { | |
| 525 | + return; | |
| 526 | + } | |
| 527 | + auto canvasSize = qApp->getCanvasSize(); | |
| 528 | + | |
| 529 | + const int widgetWidth = canvasSize.x; | |
| 530 | + const int widgetHeight = canvasSize.y; | |
| 531 | + | |
| 532 | + const float halfWidth = (MAGNIFY_WIDTH / _textureAspectRatio) * sizeMult / 2.0f; | |
| 533 | + const float halfHeight = MAGNIFY_HEIGHT * sizeMult / 2.0f; | |
| 534 | + // Magnification Texture Coordinates | |
| 535 | + const float magnifyULeft = (magPos.x - halfWidth) / (float)widgetWidth; | |
| 536 | + const float magnifyURight = (magPos.x + halfWidth) / (float)widgetWidth; | |
| 537 | + const float magnifyVTop = 1.0f - (magPos.y - halfHeight) / (float)widgetHeight; | |
| 538 | + const float magnifyVBottom = 1.0f - (magPos.y + halfHeight) / (float)widgetHeight; | |
| 539 | + | |
| 540 | + const float newHalfWidth = halfWidth * MAGNIFY_MULT; | |
| 541 | + const float newHalfHeight = halfHeight * MAGNIFY_MULT; | |
| 542 | + //Get yaw / pitch value for the corners | |
| 543 | + const glm::vec2 topLeftYawPitch = overlayToSpherical(glm::vec2(magPos.x - newHalfWidth, | |
| 544 | + magPos.y - newHalfHeight)); | |
| 545 | + const glm::vec2 bottomRightYawPitch = overlayToSpherical(glm::vec2(magPos.x + newHalfWidth, | |
| 546 | + magPos.y + newHalfHeight)); | |
| 547 | + | |
| 548 | + const glm::vec3 bottomLeft = getPoint(topLeftYawPitch.x, bottomRightYawPitch.y); | |
| 549 | + const glm::vec3 bottomRight = getPoint(bottomRightYawPitch.x, bottomRightYawPitch.y); | |
| 550 | + const glm::vec3 topLeft = getPoint(topLeftYawPitch.x, topLeftYawPitch.y); | |
| 551 | + const glm::vec3 topRight = getPoint(bottomRightYawPitch.x, topLeftYawPitch.y); | |
| 552 | + | |
| 553 | + auto geometryCache = DependencyManager::get<GeometryCache>(); | |
| 554 | + | |
| 555 | + if (bottomLeft != _previousMagnifierBottomLeft || bottomRight != _previousMagnifierBottomRight | |
| 556 | + || topLeft != _previousMagnifierTopLeft || topRight != _previousMagnifierTopRight) { | |
| 557 | + QVector<glm::vec3> border; | |
| 558 | + border << topLeft; | |
| 559 | + border << bottomLeft; | |
| 560 | + border << bottomRight; | |
| 561 | + border << topRight; | |
| 562 | + border << topLeft; | |
| 563 | + geometryCache->updateVertices(_magnifierBorder, border, glm::vec4(1.0f, 0.0f, 0.0f, _alpha)); | |
| 564 | + | |
| 565 | + _previousMagnifierBottomLeft = bottomLeft; | |
| 566 | + _previousMagnifierBottomRight = bottomRight; | |
| 567 | + _previousMagnifierTopLeft = topLeft; | |
| 568 | + _previousMagnifierTopRight = topRight; | |
| 569 | + } | |
| 570 | + | |
| 571 | + glPushMatrix(); { | |
| 572 | + if (showBorder) { | |
| 573 | + glDisable(GL_TEXTURE_2D); | |
| 574 | + glLineWidth(1.0f); | |
| 575 | + //Outer Line | |
| 576 | + geometryCache->renderVertices(gpu::LINE_STRIP, _magnifierBorder); | |
| 577 | + glEnable(GL_TEXTURE_2D); | |
| 578 | + } | |
| 579 | + glm::vec4 magnifierColor = { 1.0f, 1.0f, 1.0f, _alpha }; | |
| 580 | + | |
| 581 | + DependencyManager::get<GeometryCache>()->renderQuad(bottomLeft, bottomRight, topRight, topLeft, | |
| 582 | + glm::vec2(magnifyULeft, magnifyVBottom), | |
| 583 | + glm::vec2(magnifyURight, magnifyVBottom), | |
| 584 | + glm::vec2(magnifyURight, magnifyVTop), | |
| 585 | + glm::vec2(magnifyULeft, magnifyVTop), | |
| 586 | + magnifierColor, _magnifierQuad); | |
| 587 | + | |
| 588 | + } glPopMatrix(); | |
| 589 | +} | |
| 590 | + | |
| 591 | +void ApplicationCompositor::buildHemiVertices( | |
| 592 | + const float fov, const float aspectRatio, const int slices, const int stacks) { | |
| 593 | + static float textureFOV = 0.0f, textureAspectRatio = 1.0f; | |
| 594 | + if (textureFOV == fov && textureAspectRatio == aspectRatio) { | |
| 595 | + return; | |
| 596 | + } | |
| 597 | + | |
| 598 | + textureFOV = fov; | |
| 599 | + textureAspectRatio = aspectRatio; | |
| 600 | + | |
| 601 | + auto geometryCache = DependencyManager::get<GeometryCache>(); | |
| 602 | + | |
| 603 | + _hemiVertices = gpu::BufferPointer(new gpu::Buffer()); | |
| 604 | + _hemiIndices = gpu::BufferPointer(new gpu::Buffer()); | |
| 605 | + | |
| 606 | + | |
| 607 | + if (fov >= PI) { | |
| 608 | + qDebug() << "TexturedHemisphere::buildVBO(): FOV greater or equal than Pi will create issues"; | |
| 609 | + } | |
| 610 | + | |
| 611 | + //UV mapping source: http://www.mvps.org/directx/articles/spheremap.htm | |
| 612 | + | |
| 613 | + vec3 pos; | |
| 614 | + vec2 uv; | |
| 615 | + // Compute vertices positions and texture UV coordinate | |
| 616 | + // Create and write to buffer | |
| 617 | + for (int i = 0; i < stacks; i++) { | |
| 618 | + uv.y = (float)i / (float)(stacks - 1); // First stack is 0.0f, last stack is 1.0f | |
| 619 | + // abs(theta) <= fov / 2.0f | |
| 620 | + float pitch = -fov * (uv.y - 0.5f); | |
| 621 | + for (int j = 0; j < slices; j++) { | |
| 622 | + uv.x = (float)j / (float)(slices - 1); // First slice is 0.0f, last slice is 1.0f | |
| 623 | + // abs(phi) <= fov * aspectRatio / 2.0f | |
| 624 | + float yaw = -fov * aspectRatio * (uv.x - 0.5f); | |
| 625 | + pos = getPoint(yaw, pitch); | |
| 626 | + static const vec4 color(1); | |
| 627 | + _hemiVertices->append(sizeof(pos), (gpu::Byte*)&pos); | |
| 628 | + _hemiVertices->append(sizeof(vec2), (gpu::Byte*)&uv); | |
| 629 | + _hemiVertices->append(sizeof(vec4), (gpu::Byte*)&color); | |
| 630 | + } | |
| 631 | + } | |
| 632 | + | |
| 633 | + // Compute number of indices needed | |
| 634 | + static const int VERTEX_PER_TRANGLE = 3; | |
| 635 | + static const int TRIANGLE_PER_RECTANGLE = 2; | |
| 636 | + int numberOfRectangles = (slices - 1) * (stacks - 1); | |
| 637 | + _hemiIndexCount = numberOfRectangles * TRIANGLE_PER_RECTANGLE * VERTEX_PER_TRANGLE; | |
| 638 | + | |
| 639 | + // Compute indices order | |
| 640 | + std::vector<GLushort> indices; | |
| 641 | + for (int i = 0; i < stacks - 1; i++) { | |
| 642 | + for (int j = 0; j < slices - 1; j++) { | |
| 643 | + GLushort bottomLeftIndex = i * slices + j; | |
| 644 | + GLushort bottomRightIndex = bottomLeftIndex + 1; | |
| 645 | + GLushort topLeftIndex = bottomLeftIndex + slices; | |
| 646 | + GLushort topRightIndex = topLeftIndex + 1; | |
| 647 | + // FIXME make a z-order curve for better vertex cache locality | |
| 648 | + indices.push_back(topLeftIndex); | |
| 649 | + indices.push_back(bottomLeftIndex); | |
| 650 | + indices.push_back(topRightIndex); | |
| 651 | + | |
| 652 | + indices.push_back(topRightIndex); | |
| 653 | + indices.push_back(bottomLeftIndex); | |
| 654 | + indices.push_back(bottomRightIndex); | |
| 655 | + } | |
| 656 | + } | |
| 657 | + _hemiIndices->append(sizeof(GLushort) * indices.size(), (gpu::Byte*)&indices[0]); | |
| 658 | +} | |
| 659 | + | |
| 660 | + | |
| 661 | +void ApplicationCompositor::drawSphereSection(gpu::Batch& batch) { | |
| 662 | + buildHemiVertices(_textureFov, _textureAspectRatio, 80, 80); | |
| 663 | + static const int VERTEX_DATA_SLOT = 0; | |
| 664 | + static const int TEXTURE_DATA_SLOT = 1; | |
| 665 | + static const int COLOR_DATA_SLOT = 2; | |
| 666 | + gpu::Stream::FormatPointer streamFormat(new gpu::Stream::Format()); // 1 for everyone | |
| 667 | + streamFormat->setAttribute(gpu::Stream::POSITION, VERTEX_DATA_SLOT, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ), 0); | |
| 668 | + streamFormat->setAttribute(gpu::Stream::TEXCOORD, TEXTURE_DATA_SLOT, gpu::Element(gpu::VEC2, gpu::FLOAT, gpu::UV)); | |
| 669 | + streamFormat->setAttribute(gpu::Stream::COLOR, COLOR_DATA_SLOT, gpu::Element(gpu::VEC4, gpu::FLOAT, gpu::RGBA)); | |
| 670 | + batch.setInputFormat(streamFormat); | |
| 671 | + | |
| 672 | + static const int VERTEX_STRIDE = sizeof(vec3) + sizeof(vec2) + sizeof(vec4); | |
| 673 | + gpu::BufferView posView(_hemiVertices, 0, _hemiVertices->getSize(), VERTEX_STRIDE, streamFormat->getAttributes().at(gpu::Stream::POSITION)._element); | |
| 674 | + gpu::BufferView uvView(_hemiVertices, sizeof(vec3), _hemiVertices->getSize(), VERTEX_STRIDE, streamFormat->getAttributes().at(gpu::Stream::TEXCOORD)._element); | |
| 675 | + gpu::BufferView colView(_hemiVertices, sizeof(vec3) + sizeof(vec2), _hemiVertices->getSize(), VERTEX_STRIDE, streamFormat->getAttributes().at(gpu::Stream::COLOR)._element); | |
| 676 | + batch.setInputBuffer(VERTEX_DATA_SLOT, posView); | |
| 677 | + batch.setInputBuffer(TEXTURE_DATA_SLOT, uvView); | |
| 678 | + batch.setInputBuffer(COLOR_DATA_SLOT, colView); | |
| 679 | + batch.setIndexBuffer(gpu::UINT16, _hemiIndices, 0); | |
| 680 | + batch.drawIndexed(gpu::TRIANGLES, _hemiIndexCount); | |
| 681 | +} | |
| 682 | + | |
| 683 | +glm::vec2 ApplicationCompositor::directionToSpherical(const glm::vec3& direction) { | |
| 684 | + glm::vec2 result; | |
| 685 | + // Compute yaw | |
| 686 | + glm::vec3 normalProjection = glm::normalize(glm::vec3(direction.x, 0.0f, direction.z)); | |
| 687 | + result.x = glm::acos(glm::dot(IDENTITY_FRONT, normalProjection)); | |
| 688 | + if (glm::dot(IDENTITY_RIGHT, normalProjection) > 0.0f) { | |
| 689 | + result.x = -glm::abs(result.x); | |
| 690 | + } else { | |
| 691 | + result.x = glm::abs(result.x); | |
| 692 | + } | |
| 693 | + // Compute pitch | |
| 694 | + result.y = angleBetween(IDENTITY_UP, direction) - PI_OVER_TWO; | |
| 695 | + | |
| 696 | + return result; | |
| 697 | +} | |
| 698 | + | |
| 699 | +glm::vec3 ApplicationCompositor::sphericalToDirection(const glm::vec2& sphericalPos) { | |
| 700 | + glm::quat rotation(glm::vec3(sphericalPos.y, sphericalPos.x, 0.0f)); | |
| 701 | + return rotation * IDENTITY_FRONT; | |
| 702 | +} | |
| 703 | + | |
| 704 | +glm::vec2 ApplicationCompositor::screenToSpherical(const glm::vec2& screenPos) { | |
| 705 | + auto screenSize = qApp->getCanvasSize(); | |
| 706 | + glm::vec2 result; | |
| 707 | + result.x = -(screenPos.x / screenSize.x - 0.5f); | |
| 708 | + result.y = (screenPos.y / screenSize.y - 0.5f); | |
| 709 | + result.x *= MOUSE_YAW_RANGE; | |
| 710 | + result.y *= MOUSE_PITCH_RANGE; | |
| 711 | + | |
| 712 | + return result; | |
| 713 | +} | |
| 714 | + | |
| 715 | +glm::vec2 ApplicationCompositor::sphericalToScreen(const glm::vec2& sphericalPos) { | |
| 716 | + glm::vec2 result = sphericalPos; | |
| 717 | + result.x *= -1.0; | |
| 718 | + result /= MOUSE_RANGE; | |
| 719 | + result += 0.5f; | |
| 720 | + result *= qApp->getCanvasSize(); | |
| 721 | + return result; | |
| 722 | +} | |
| 723 | + | |
| 724 | +glm::vec2 ApplicationCompositor::sphericalToOverlay(const glm::vec2& sphericalPos) const { | |
| 725 | + glm::vec2 result = sphericalPos; | |
| 726 | + result.x *= -1.0; | |
| 727 | + result /= _textureFov; | |
| 728 | + result.x /= _textureAspectRatio; | |
| 729 | + result += 0.5f; | |
| 730 | + result *= qApp->getCanvasSize(); | |
| 731 | + return result; | |
| 732 | +} | |
| 733 | + | |
| 734 | +glm::vec2 ApplicationCompositor::overlayToSpherical(const glm::vec2& overlayPos) const { | |
| 735 | + glm::vec2 result = overlayPos; | |
| 736 | + result /= qApp->getCanvasSize(); | |
| 737 | + result -= 0.5f; | |
| 738 | + result *= _textureFov; | |
| 739 | + result.x *= _textureAspectRatio; | |
| 740 | + result.x *= -1.0f; | |
| 741 | + return result; | |
| 742 | +} | |
| 743 | + | |
| 744 | +glm::vec2 ApplicationCompositor::screenToOverlay(const glm::vec2& screenPos) const { | |
| 745 | + return sphericalToOverlay(screenToSpherical(screenPos)); | |
| 746 | +} | |
| 747 | + | |
| 748 | +glm::vec2 ApplicationCompositor::overlayToScreen(const glm::vec2& overlayPos) const { | |
| 749 | + return sphericalToScreen(overlayToSpherical(overlayPos)); | |
| 750 | +} | |
| 751 | + | |
| 752 | +void ApplicationCompositor::updateTooltips() { | |
| 753 | + if (_hoverItemId != _noItemId) { | |
| 754 | + quint64 hoverDuration = usecTimestampNow() - _hoverItemEnterUsecs; | |
| 755 | + if (_hoverItemEnterUsecs != UINT64_MAX && !_hoverItemHref.isEmpty() && hoverDuration > TOOLTIP_DELAY) { | |
| 756 | + // TODO Enable and position the tooltip | |
| 757 | + _hoverItemEnterUsecs = UINT64_MAX; | |
| 758 | + _tooltipId = Tooltip::showTip("URL: " + _hoverItemHref); | |
| 759 | + } | |
| 760 | + } | |
| 761 | +} | |
| @@ -0,0 +1,120 @@ | ||
| 1 | +// | |
| 2 | +// Created by Bradley Austin Davis Arnold on 2015/06/13 | |
| 3 | +// Copyright 2015 High Fidelity, Inc. | |
| 4 | +// | |
| 5 | +// Distributed under the Apache License, Version 2.0. | |
| 6 | +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html | |
| 7 | +// | |
| 8 | + | |
| 9 | +#ifndef hifi_ApplicationCompositor_h | |
| 10 | +#define hifi_ApplicationCompositor_h | |
| 11 | + | |
| 12 | +#include <QObject> | |
| 13 | +#include <cstdint> | |
| 14 | + | |
| 15 | +#include <EntityItemID.h> | |
| 16 | +#include <GeometryCache.h> | |
| 17 | +#include <GLMHelpers.h> | |
| 18 | +#include <gpu/Batch.h> | |
| 19 | +#include <gpu/Texture.h> | |
| 20 | + | |
| 21 | +class Camera; | |
| 22 | +class PalmData; | |
| 23 | +class RenderArgs; | |
| 24 | + | |
| 25 | +const float MAGNIFY_WIDTH = 220.0f; | |
| 26 | +const float MAGNIFY_HEIGHT = 100.0f; | |
| 27 | +const float MAGNIFY_MULT = 2.0f; | |
| 28 | + | |
| 29 | +const float DEFAULT_HMD_UI_ANGULAR_SIZE = 72.0f; | |
| 30 | + | |
| 31 | +// Handles the drawing of the overlays to the screen | |
| 32 | +// TODO, move divide up the rendering, displaying and input handling | |
| 33 | +// facilities of this class | |
| 34 | +class ApplicationCompositor : public QObject { | |
| 35 | + Q_OBJECT | |
| 36 | +public: | |
| 37 | + ApplicationCompositor(); | |
| 38 | + ~ApplicationCompositor(); | |
| 39 | + | |
| 40 | + void displayOverlayTexture(RenderArgs* renderArgs); | |
| 41 | + void displayOverlayTextureHmd(RenderArgs* renderArgs, int eye); | |
| 42 | + | |
| 43 | + QPoint getPalmClickLocation(const PalmData *palm) const; | |
| 44 | + bool calculateRayUICollisionPoint(const glm::vec3& position, const glm::vec3& direction, glm::vec3& result) const; | |
| 45 | + | |
| 46 | + bool hasMagnifier() const { return _magnifier; } | |
| 47 | + void toggleMagnifier() { _magnifier = !_magnifier; } | |
| 48 | + | |
| 49 | + float getHmdUIAngularSize() const { return _hmdUIAngularSize; } | |
| 50 | + void setHmdUIAngularSize(float hmdUIAngularSize) { _hmdUIAngularSize = hmdUIAngularSize; } | |
| 51 | + | |
| 52 | + // Converter from one frame of reference to another. | |
| 53 | + // Frame of reference: | |
| 54 | + // Direction: Ray that represents the spherical values | |
| 55 | + // Screen: Position on the screen (x,y) | |
| 56 | + // Spherical: Pitch and yaw that gives the position on the sphere we project on (yaw,pitch) | |
| 57 | + // Overlay: Position on the overlay (x,y) | |
| 58 | + // (x,y) in Overlay are similar than (x,y) in Screen except they can be outside of the bound of te screen. | |
| 59 | + // This allows for picking outside of the screen projection in 3D. | |
| 60 | + glm::vec2 sphericalToOverlay(const glm::vec2 & sphericalPos) const; | |
| 61 | + glm::vec2 overlayToSpherical(const glm::vec2 & overlayPos) const; | |
| 62 | + glm::vec2 screenToOverlay(const glm::vec2 & screenPos) const; | |
| 63 | + glm::vec2 overlayToScreen(const glm::vec2 & overlayPos) const; | |
| 64 | + void computeHmdPickRay(glm::vec2 cursorPos, glm::vec3& origin, glm::vec3& direction) const; | |
| 65 | + GLuint getOverlayTexture() const; | |
| 66 | + | |
| 67 | + static glm::vec2 directionToSpherical(const glm::vec3 & direction); | |
| 68 | + static glm::vec3 sphericalToDirection(const glm::vec2 & sphericalPos); | |
| 69 | + static glm::vec2 screenToSpherical(const glm::vec2 & screenPos); | |
| 70 | + static glm::vec2 sphericalToScreen(const glm::vec2 & sphericalPos); | |
| 71 | + | |
| 72 | +private: | |
| 73 | + void displayOverlayTextureStereo(RenderArgs* renderArgs, float aspectRatio, float fov); | |
| 74 | + void bindCursorTexture(gpu::Batch& batch, uint8_t cursorId = 0); | |
| 75 | + void buildHemiVertices(const float fov, const float aspectRatio, const int slices, const int stacks); | |
| 76 | + void drawSphereSection(gpu::Batch& batch); | |
| 77 | + void updateTooltips(); | |
| 78 | + | |
| 79 | + void renderPointers(gpu::Batch& batch); | |
| 80 | + void renderMagnifier(gpu::Batch& batch, const glm::vec2& magPos, float sizeMult, bool showBorder); | |
| 81 | + void renderControllerPointers(gpu::Batch& batch); | |
| 82 | + void renderPointersOculus(gpu::Batch& batch); | |
| 83 | + | |
| 84 | + // Support for hovering and tooltips | |
| 85 | + static EntityItemID _noItemId; | |
| 86 | + EntityItemID _hoverItemId{ _noItemId }; | |
| 87 | + QString _hoverItemHref; | |
| 88 | + quint64 _hoverItemEnterUsecs{ 0 }; | |
| 89 | + | |
| 90 | + float _hmdUIAngularSize = DEFAULT_HMD_UI_ANGULAR_SIZE; | |
| 91 | + float _textureFov{ glm::radians(DEFAULT_HMD_UI_ANGULAR_SIZE) }; | |
| 92 | + float _textureAspectRatio{ 1.0f }; | |
| 93 | + int _hemiVerticesID{ GeometryCache::UNKNOWN_ID }; | |
| 94 | + | |
| 95 | + enum Reticles { MOUSE, LEFT_CONTROLLER, RIGHT_CONTROLLER, NUMBER_OF_RETICLES }; | |
| 96 | + bool _reticleActive[NUMBER_OF_RETICLES]; | |
| 97 | + QPoint _reticlePosition[NUMBER_OF_RETICLES]; | |
| 98 | + bool _magActive[NUMBER_OF_RETICLES]; | |
| 99 | + float _magSizeMult[NUMBER_OF_RETICLES]; | |
| 100 | + bool _magnifier{ true }; | |
| 101 | + | |
| 102 | + float _alpha{ 1.0f }; | |
| 103 | + float _oculusUIRadius{ 1.0f }; | |
| 104 | + | |
| 105 | + QMap<uint16_t, gpu::TexturePointer> _cursors; | |
| 106 | + | |
| 107 | + int _reticleQuad; | |
| 108 | + int _magnifierQuad; | |
| 109 | + int _magnifierBorder; | |
| 110 | + | |
| 111 | + int _previousBorderWidth{ -1 }; | |
| 112 | + int _previousBorderHeight{ -1 }; | |
| 113 | + | |
| 114 | + glm::vec3 _previousMagnifierBottomLeft; | |
| 115 | + glm::vec3 _previousMagnifierBottomRight; | |
| 116 | + glm::vec3 _previousMagnifierTopLeft; | |
| 117 | + glm::vec3 _previousMagnifierTopRight; | |
| 118 | +}; | |
| 119 | + | |
| 120 | +#endif // hifi_ApplicationCompositor_h | |
| @@ -14,166 +14,58 @@ · 13 unmodified lines | ||
| 14 | 14 | #include <QOpenGLFramebufferObject> |
| 15 | 15 | #include <QOpenGLTexture> |
| 16 | 16 | |
| 17 | +#include <glm/gtc/type_ptr.hpp> | |
| 18 | + | |
| 17 | 19 | #include <avatar/AvatarManager.h> |
| 20 | +#include <DeferredLightingEffect.h> | |
| 18 | 21 | #include <GLMHelpers.h> |
| 19 | −#include <PathUtils.h> | |
| 20 | 22 | #include <gpu/GLBackend.h> |
| 23 | +#include <gpu/GLBackendShared.h> | |
| 21 | 24 | #include <GLMHelpers.h> |
| 22 | −#include <PerfStat.h> | |
| 23 | 25 | #include <OffscreenUi.h> |
| 26 | +#include <CursorManager.h> | |
| 27 | +#include <PerfStat.h> | |
| 24 | 28 | |
| 25 | 29 | #include "AudioClient.h" |
| 26 | 30 | #include "audio/AudioIOStatsRenderer.h" |
| 27 | 31 | #include "audio/AudioScope.h" |
| 28 | −#include "audio/AudioToolBox.h" | |
| 29 | 32 | #include "Application.h" |
| 30 | 33 | #include "ApplicationOverlay.h" |
| 31 | −#include "devices/CameraToolBox.h" | |
| 32 | 34 | |
| 33 | 35 | #include "Util.h" |
| 34 | 36 | #include "ui/Stats.h" |
| 35 | − | |
| 36 | −// Used to animate the magnification windows | |
| 37 | −const float MAG_SPEED = 0.08f; | |
| 38 | − | |
| 39 | −const quint64 MSECS_TO_USECS = 1000ULL; | |
| 37 | +#include "ui/AvatarInputs.h" | |
| 40 | 38 | |
| 41 | 39 | const float WHITE_TEXT[] = { 0.93f, 0.93f, 0.93f }; |
| 42 | −const float RETICLE_COLOR[] = { 0.0f, 198.0f / 255.0f, 244.0f / 255.0f }; | |
| 43 | −const float reticleSize = TWO_PI / 100.0f; | |
| 44 | − | |
| 45 | − | |
| 46 | −const float CONNECTION_STATUS_BORDER_COLOR[] = { 1.0f, 0.0f, 0.0f }; | |
| 40 | +const int AUDIO_METER_GAP = 5; | |
| 41 | +const int MUTE_ICON_PADDING = 10; | |
| 42 | +const vec4 CONNECTION_STATUS_BORDER_COLOR{ 1.0f, 0.0f, 0.0f, 0.8f }; | |
| 47 | 43 | const float CONNECTION_STATUS_BORDER_LINE_WIDTH = 4.0f; |
| 44 | +static const float ORTHO_NEAR_CLIP = -10000; | |
| 45 | +static const float ORTHO_FAR_CLIP = 10000; | |
| 48 | 46 | |
| 49 | −static const float MOUSE_PITCH_RANGE = 1.0f * PI; | |
| 50 | −static const float MOUSE_YAW_RANGE = 0.5f * TWO_PI; | |
| 51 | −static const glm::vec2 MOUSE_RANGE(MOUSE_YAW_RANGE, MOUSE_PITCH_RANGE); | |
| 52 | − | |
| 53 | −// Return a point's cartesian coordinates on a sphere from pitch and yaw | |
| 54 | −glm::vec3 getPoint(float yaw, float pitch) { | |
| 55 | − return glm::vec3(glm::cos(-pitch) * (-glm::sin(yaw)), | |
| 56 | − glm::sin(-pitch), | |
| 57 | − glm::cos(-pitch) * (-glm::cos(yaw))); | |
| 47 | +// TODO move somewhere useful | |
| 48 | +static void fboViewport(QOpenGLFramebufferObject* fbo) { | |
| 49 | + auto size = fbo->size(); | |
| 50 | + glViewport(0, 0, size.width(), size.height()); | |
| 58 | 51 | } |
| 59 | 52 | |
| 60 | −//Checks if the given ray intersects the sphere at the origin. result will store a multiplier that should | |
| 61 | −//be multiplied by dir and added to origin to get the location of the collision | |
| 62 | −bool raySphereIntersect(const glm::vec3 &dir, const glm::vec3 &origin, float r, float* result) | |
| 53 | +ApplicationOverlay::ApplicationOverlay() | |
| 63 | 54 | { |
| 64 | − //Source: http://wiki.cgsociety.org/index.php/Ray_Sphere_Intersection | |
| 65 | − | |
| 66 | − //Compute A, B and C coefficients | |
| 67 | − float a = glm::dot(dir, dir); | |
| 68 | − float b = 2 * glm::dot(dir, origin); | |
| 69 | − float c = glm::dot(origin, origin) - (r * r); | |
| 70 | − | |
| 71 | − //Find discriminant | |
| 72 | − float disc = b * b - 4 * a * c; | |
| 73 | − | |
| 74 | − // if discriminant is negative there are no real roots, so return | |
| 75 | − // false as ray misses sphere | |
| 76 | − if (disc < 0) { | |
| 77 | − return false; | |
| 78 | − } | |
| 79 | − | |
| 80 | − // compute q as described above | |
| 81 | − float distSqrt = sqrtf(disc); | |
| 82 | − float q; | |
| 83 | − if (b < 0) { | |
| 84 | − q = (-b - distSqrt) / 2.0; | |
| 85 | − } else { | |
| 86 | − q = (-b + distSqrt) / 2.0; | |
| 87 | − } | |
| 88 | − | |
| 89 | − // compute t0 and t1 | |
| 90 | − float t0 = q / a; | |
| 91 | − float t1 = c / q; | |
| 92 | − | |
| 93 | − // make sure t0 is smaller than t1 | |
| 94 | − if (t0 > t1) { | |
| 95 | − // if t0 is bigger than t1 swap them around | |
| 96 | − float temp = t0; | |
| 97 | − t0 = t1; | |
| 98 | − t1 = temp; | |
| 99 | − } | |
| 100 | − | |
| 101 | − // if t1 is less than zero, the object is in the ray's negative direction | |
| 102 | − // and consequently the ray misses the sphere | |
| 103 | − if (t1 < 0) { | |
| 104 | − return false; | |
| 105 | − } | |
| 106 | − | |
| 107 | − // if t0 is less than zero, the intersection point is at t1 | |
| 108 | − if (t0 < 0) { | |
| 109 | − *result = t1; | |
| 110 | − return true; | |
| 111 | − } else { // else the intersection point is at t0 | |
| 112 | − *result = t0; | |
| 113 | − return true; | |
| 114 | − } | |
| 115 | −} | |
| 116 | − | |
| 117 | −void ApplicationOverlay::renderReticle(glm::quat orientation, float alpha) { | |
| 118 | − glPushMatrix(); { | |
| 119 | − glm::vec3 axis = glm::axis(orientation); | |
| 120 | − glRotatef(glm::degrees(glm::angle(orientation)), axis.x, axis.y, axis.z); | |
| 121 | − glm::vec3 topLeft = getPoint(reticleSize / 2.0f, -reticleSize / 2.0f); | |
| 122 | − glm::vec3 topRight = getPoint(-reticleSize / 2.0f, -reticleSize / 2.0f); | |
| 123 | − glm::vec3 bottomLeft = getPoint(reticleSize / 2.0f, reticleSize / 2.0f); | |
| 124 | − glm::vec3 bottomRight = getPoint(-reticleSize / 2.0f, reticleSize / 2.0f); | |
| 125 | − | |
| 126 | − // TODO: this version of renderQuad() needs to take a color | |
| 127 | − glm::vec4 reticleColor = { RETICLE_COLOR[0], RETICLE_COLOR[1], RETICLE_COLOR[2], alpha }; | |
| 128 | − | |
| 129 | − | |
| 130 | − | |
| 131 | − DependencyManager::get<GeometryCache>()->renderQuad(topLeft, bottomLeft, bottomRight, topRight, | |
| 132 | − glm::vec2(0.0f, 0.0f), glm::vec2(1.0f, 0.0f), | |
| 133 | − glm::vec2(1.0f, 1.0f), glm::vec2(0.0f, 1.0f), | |
| 134 | − reticleColor, _reticleQuad); | |
| 135 | − } glPopMatrix(); | |
| 136 | −} | |
| 137 | − | |
| 138 | −ApplicationOverlay::ApplicationOverlay() : | |
| 139 | − _textureFov(glm::radians(DEFAULT_HMD_UI_ANGULAR_SIZE)), | |
| 140 | − _textureAspectRatio(1.0f), | |
| 141 | − _lastMouseMove(0), | |
| 142 | − _magnifier(true), | |
| 143 | − _alpha(1.0f), | |
| 144 | − _oculusUIRadius(1.0f), | |
| 145 | − _trailingAudioLoudness(0.0f), | |
| 146 | − _previousBorderWidth(-1), | |
| 147 | − _previousBorderHeight(-1), | |
| 148 | − _previousMagnifierBottomLeft(), | |
| 149 | − _previousMagnifierBottomRight(), | |
| 150 | − _previousMagnifierTopLeft(), | |
| 151 | − _previousMagnifierTopRight() | |
| 152 | −{ | |
| 153 | − memset(_reticleActive, 0, sizeof(_reticleActive)); | |
| 154 | − memset(_magActive, 0, sizeof(_reticleActive)); | |
| 155 | − memset(_magSizeMult, 0, sizeof(_magSizeMult)); | |
| 156 | − | |
| 157 | 55 | auto geometryCache = DependencyManager::get<GeometryCache>(); |
| 158 | − | |
| 159 | − _reticleQuad = geometryCache->allocateID(); | |
| 160 | − _magnifierQuad = geometryCache->allocateID(); | |
| 161 | − _audioRedQuad = geometryCache->allocateID(); | |
| 162 | − _audioGreenQuad = geometryCache->allocateID(); | |
| 163 | − _audioBlueQuad = geometryCache->allocateID(); | |
| 164 | 56 | _domainStatusBorder = geometryCache->allocateID(); |
| 165 | 57 | _magnifierBorder = geometryCache->allocateID(); |
| 166 | − | |
| 58 | + | |
| 167 | 59 | // Once we move UI rendering and screen rendering to different |
| 168 | 60 | // threads, we need to use a sync object to deteremine when |
| 169 | − // the current UI texture is no longer being read from, and only | |
| 61 | + // the current UI texture is no longer being read from, and only | |
| 170 | 62 | // then release it back to the UI for re-use |
| 171 | 63 | auto offscreenUi = DependencyManager::get<OffscreenUi>(); |
| 172 | 64 | connect(offscreenUi.data(), &OffscreenUi::textureUpdated, this, [&](GLuint textureId) { |
| 173 | 65 | auto offscreenUi = DependencyManager::get<OffscreenUi>(); |
| 174 | 66 | offscreenUi->lockTexture(textureId); |
| 175 | 67 | assert(!glGetError()); |
| 176 | − std::swap(_newUiTexture, textureId); | |
| 68 | + std::swap(_uiTexture, textureId); | |
| 177 | 69 | if (textureId) { |
| 178 | 70 | offscreenUi->releaseTexture(textureId); |
| 179 | 71 | } |
| @@ -185,846 +77,81 @@ ApplicationOverlay::~ApplicationOverlay() { · 5 unmodified lines | ||
| 185 | 77 | |
| 186 | 78 | // Renders the overlays either to a texture or to the screen |
| 187 | 79 | void ApplicationOverlay::renderOverlay(RenderArgs* renderArgs) { |
| 80 | + CHECK_GL_ERROR(); | |
| 188 | 81 | PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), "ApplicationOverlay::displayOverlay()"); |
| 189 | − Overlays& overlays = qApp->getOverlays(); | |
| 190 | − | |
| 191 | − _textureFov = glm::radians(_hmdUIAngularSize); | |
| 192 | − glm::vec2 size = qApp->getCanvasSize(); | |
| 193 | − _textureAspectRatio = aspect(size); | |
| 194 | 82 | |
| 195 | − //Handle fading and deactivation/activation of UI | |
| 196 | − | |
| 197 | − // Render 2D overlay | |
| 198 | − glMatrixMode(GL_PROJECTION); | |
| 199 | − glDisable(GL_DEPTH_TEST); | |
| 200 | − glDisable(GL_LIGHTING); | |
| 201 | − glEnable(GL_BLEND); | |
| 202 | − glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); | |
| 203 | − _overlays.buildFramebufferObject(); | |
| 204 | − _overlays.bind(); | |
| 205 | − glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); | |
| 206 | − glViewport(0, 0, size.x, size.y); | |
| 83 | + // TODO move to Application::idle()? | |
| 84 | + Stats::getInstance()->updateStats(); | |
| 85 | + AvatarInputs::getInstance()->update(); | |
| 207 | 86 | |
| 208 | − glPushMatrix(); { | |
| 209 | − const float NEAR_CLIP = -10000; | |
| 210 | − const float FAR_CLIP = 10000; | |
| 211 | − glLoadIdentity(); | |
| 212 | − glOrtho(0, size.x, size.y, 0, NEAR_CLIP, FAR_CLIP); | |
| 87 | + buildFramebufferObject(); | |
| 213 | 88 | |
| 214 | − glMatrixMode(GL_MODELVIEW); | |
| 215 | − | |
| 216 | − renderAudioMeter(); | |
| 217 | − renderCameraToggle(); | |
| 218 | − | |
| 219 | − renderStatsAndLogs(); | |
| 220 | − | |
| 221 | − // give external parties a change to hook in | |
| 222 | − emit qApp->renderingOverlay(); | |
| 223 | − | |
| 224 | − overlays.renderHUD(renderArgs); | |
| 225 | − | |
| 226 | − renderPointers(); | |
| 227 | − | |
| 228 | − renderDomainConnectionStatusBorder(); | |
| 229 | − | |
| 230 | − glMatrixMode(GL_PROJECTION); | |
| 231 | − } glPopMatrix(); | |
| 232 | − | |
| 233 | − glMatrixMode(GL_MODELVIEW); | |
| 234 | − glEnable(GL_DEPTH_TEST); | |
| 235 | − glEnable(GL_LIGHTING); | |
| 236 | − glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_CONSTANT_ALPHA, GL_ONE); | |
| 237 | − | |
| 238 | − _overlays.release(); | |
| 239 | −} | |
| 89 | + // Execute the batch into our framebuffer | |
| 90 | + _overlayFramebuffer->bind(); | |
| 91 | + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); | |
| 92 | + fboViewport(_overlayFramebuffer); | |
| 240 | 93 | |
| 241 | −// A quick and dirty solution for compositing the old overlay | |
| 242 | −// texture with the new one | |
| 243 | −template <typename F> | |
| 244 | −void with_each_texture(GLuint firstPassTexture, GLuint secondPassTexture, F f) { | |
| 245 | − glEnable(GL_TEXTURE_2D); | |
| 246 | − glActiveTexture(GL_TEXTURE0); | |
| 247 | − if (firstPassTexture) { | |
| 248 | − glBindTexture(GL_TEXTURE_2D, firstPassTexture); | |
| 249 | − f(); | |
| 250 | − } | |
| 251 | − if (secondPassTexture) { | |
| 252 | − glBindTexture(GL_TEXTURE_2D, secondPassTexture); | |
| 253 | − f(); | |
| 254 | − } | |
| 255 | − glBindTexture(GL_TEXTURE_2D, 0); | |
| 256 | − glDisable(GL_TEXTURE_2D); | |
| 94 | + // Now render the overlay components together into a single texture | |
| 95 | + renderOverlays(renderArgs); | |
| 96 | + renderStatsAndLogs(renderArgs); | |
| 97 | + renderDomainConnectionStatusBorder(renderArgs); | |
| 98 | + renderQmlUi(renderArgs); | |
| 99 | + _overlayFramebuffer->release(); | |
| 100 | + CHECK_GL_ERROR(); | |
| 257 | 101 | } |
| 258 | 102 | |
| 259 | −// Draws the FBO texture for the screen | |
| 260 | −void ApplicationOverlay::displayOverlayTexture() { | |
| 261 | − if (_alpha == 0.0f) { | |
| 262 | − return; | |
| 103 | +void ApplicationOverlay::renderQmlUi(RenderArgs* renderArgs) { | |
| 104 | + if (_uiTexture) { | |
| 105 | + gpu::Batch batch; | |
| 106 | + auto geometryCache = DependencyManager::get<GeometryCache>(); | |
| 107 | + geometryCache->useSimpleDrawPipeline(batch); | |
| 108 | + batch.setProjectionTransform(mat4()); | |
| 109 | + batch.setModelTransform(mat4()); | |
| 110 | + batch._glBindTexture(GL_TEXTURE_2D, _uiTexture); | |
| 111 | + geometryCache->renderUnitQuad(batch, glm::vec4(1)); | |
| 112 | + renderArgs->_context->syncCache(); | |
| 113 | + renderArgs->_context->render(batch); | |
| 263 | 114 | } |
| 264 | − glMatrixMode(GL_PROJECTION); | |
| 265 | − glPushMatrix(); { | |
| 266 | − glLoadIdentity(); | |
| 267 | − glDisable(GL_DEPTH_TEST); | |
| 268 | − glDisable(GL_LIGHTING); | |
| 269 | − glEnable(GL_BLEND); | |
| 270 | − glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); | |
| 271 | − glViewport(0, 0, qApp->getDeviceSize().width(), qApp->getDeviceSize().height()); | |
| 272 | − | |
| 273 | − static const glm::vec2 topLeft(-1, 1); | |
| 274 | − static const glm::vec2 bottomRight(1, -1); | |
| 275 | − static const glm::vec2 texCoordTopLeft(0.0f, 1.0f); | |
| 276 | − static const glm::vec2 texCoordBottomRight(1.0f, 0.0f); | |
| 277 | − with_each_texture(_overlays.getTexture(), _newUiTexture, [&] { | |
| 278 | − DependencyManager::get<GeometryCache>()->renderQuad( | |
| 279 | − topLeft, bottomRight, | |
| 280 | − texCoordTopLeft, texCoordBottomRight, | |
| 281 | − glm::vec4(1.0f, 1.0f, 1.0f, _alpha)); | |
| 282 | − }); | |
| 283 | − | |
| 284 | − if (!_crosshairTexture) { | |
| 285 | − _crosshairTexture = DependencyManager::get<TextureCache>()-> | |
| 286 | − getImageTexture(PathUtils::resourcesPath() + "images/sixense-reticle.png"); | |
| 287 | − } | |
| 288 | − | |
| 289 | − //draw the mouse pointer | |
| 290 | − glm::vec2 canvasSize = qApp->getCanvasSize(); | |
| 291 | − glm::vec2 mouseSize = 32.0f / canvasSize; | |
| 292 | − auto mouseTopLeft = topLeft * mouseSize; | |
| 293 | − auto mouseBottomRight = bottomRight * mouseSize; | |
| 294 | − vec2 mousePosition = vec2(qApp->getMouseX(), qApp->getMouseY()); | |
| 295 | − mousePosition /= canvasSize; | |
| 296 | − mousePosition *= 2.0f; | |
| 297 | − mousePosition -= 1.0f; | |
| 298 | − mousePosition.y *= -1.0f; | |
| 299 | − | |
| 300 | − glEnable(GL_TEXTURE_2D); | |
| 301 | − glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); | |
| 302 | − glBindTexture(GL_TEXTURE_2D, gpu::GLBackend::getTextureID(_crosshairTexture)); | |
| 303 | − glm::vec4 reticleColor = { RETICLE_COLOR[0], RETICLE_COLOR[1], RETICLE_COLOR[2], 1.0f }; | |
| 304 | − DependencyManager::get<GeometryCache>()->renderQuad( | |
| 305 | − mouseTopLeft + mousePosition, mouseBottomRight + mousePosition, | |
| 306 | − texCoordTopLeft, texCoordBottomRight, | |
| 307 | − reticleColor); | |
| 308 | − glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_CONSTANT_ALPHA, GL_ONE); | |
| 309 | − glDisable(GL_TEXTURE_2D); | |
| 310 | − } glPopMatrix(); | |
| 311 | 115 | } |
| 312 | 116 | |
| 313 | −// Draws the FBO texture for Oculus rift. | |
| 314 | −void ApplicationOverlay::displayOverlayTextureHmd(Camera& whichCamera) { | |
| 315 | − if (_alpha == 0.0f) { | |
| 316 | − return; | |
| 317 | − } | |
| 318 | − | |
| 319 | − glEnable(GL_BLEND); | |
| 320 | − glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_CONSTANT_ALPHA, GL_ONE); | |
| 321 | − glEnable(GL_DEPTH_TEST); | |
| 322 | − glDepthMask(GL_TRUE); | |
| 323 | − glDisable(GL_LIGHTING); | |
| 324 | − glEnable(GL_ALPHA_TEST); | |
| 325 | − glAlphaFunc(GL_GREATER, 0.01f); | |
| 326 | − | |
| 117 | +void ApplicationOverlay::renderOverlays(RenderArgs* renderArgs) { | |
| 118 | + glm::vec2 size = qApp->getCanvasSize(); | |
| 327 | 119 | |
| 328 | − //Update and draw the magnifiers | |
| 329 | − MyAvatar* myAvatar = DependencyManager::get<AvatarManager>()->getMyAvatar(); | |
| 330 | − const glm::quat& orientation = myAvatar->getOrientation(); | |
| 331 | − // Always display the HMD overlay relative to the camera position but | |
| 332 | − // remove the HMD pose offset. This results in an overlay that sticks with you | |
| 333 | − // even in third person mode, but isn't drawn at a fixed distance. | |
| 334 | − glm::vec3 position = whichCamera.getPosition(); | |
| 335 | − position -= qApp->getCamera()->getHmdPosition(); | |
| 336 | − const float scale = myAvatar->getScale() * _oculusUIRadius; | |
| 337 | − | |
| 338 | −// glm::vec3 eyeOffset = setEyeOffsetPosition; | |
| 120 | + mat4 legacyProjection = glm::ortho<float>(0, size.x, size.y, 0, ORTHO_NEAR_CLIP, ORTHO_FAR_CLIP); | |
| 121 | + glMatrixMode(GL_PROJECTION); | |
| 122 | + glPushMatrix(); | |
| 123 | + glLoadMatrixf(glm::value_ptr(legacyProjection)); | |
| 339 | 124 | glMatrixMode(GL_MODELVIEW); |
| 340 | − glPushMatrix(); { | |
| 341 | − glTranslatef(position.x, position.y, position.z); | |
| 342 | − glm::mat4 rotation = glm::toMat4(orientation); | |
| 343 | − glMultMatrixf(&rotation[0][0]); | |
| 344 | − glScalef(scale, scale, scale); | |
| 345 | − for (int i = 0; i < NUMBER_OF_RETICLES; i++) { | |
| 346 | − | |
| 347 | − if (_magActive[i]) { | |
| 348 | − _magSizeMult[i] += MAG_SPEED; | |
| 349 | − if (_magSizeMult[i] > 1.0f) { | |
| 350 | − _magSizeMult[i] = 1.0f; | |
| 351 | − } | |
| 352 | − } else { | |
| 353 | − _magSizeMult[i] -= MAG_SPEED; | |
| 354 | − if (_magSizeMult[i] < 0.0f) { | |
| 355 | − _magSizeMult[i] = 0.0f; | |
| 356 | − } | |
| 357 | − } | |
| 358 | − | |
| 359 | − if (_magSizeMult[i] > 0.0f) { | |
| 360 | − //Render magnifier, but dont show border for mouse magnifier | |
| 361 | − glm::vec2 projection = screenToOverlay(glm::vec2(_reticlePosition[MOUSE].x(), | |
| 362 | − _reticlePosition[MOUSE].y())); | |
| 363 | − with_each_texture(_overlays.getTexture(), 0, [&] { | |
| 364 | − renderMagnifier(projection, _magSizeMult[i], i != MOUSE); | |
| 365 | − }); | |
| 366 | − } | |
| 367 | − } | |
| 368 | − | |
| 369 | − glDepthMask(GL_FALSE); | |
| 370 | − glDisable(GL_ALPHA_TEST); | |
| 371 | − | |
| 372 | − static float textureFOV = 0.0f, textureAspectRatio = 1.0f; | |
| 373 | − if (textureFOV != _textureFov || | |
| 374 | − textureAspectRatio != _textureAspectRatio) { | |
| 375 | − textureFOV = _textureFov; | |
| 376 | − textureAspectRatio = _textureAspectRatio; | |
| 377 | − | |
| 378 | − _overlays.buildVBO(_textureFov, _textureAspectRatio, 80, 80); | |
| 379 | − } | |
| 380 | 125 | |
| 381 | − with_each_texture(_overlays.getTexture(), _newUiTexture, [&] { | |
| 382 | − _overlays.render(); | |
| 383 | − }); | |
| 384 | − | |
| 385 | − if (!Application::getInstance()->isMouseHidden()) { | |
| 386 | − renderPointersOculus(); | |
| 387 | − } | |
| 388 | − glDepthMask(GL_TRUE); | |
| 389 | − glDisable(GL_TEXTURE_2D); | |
| 390 | − | |
| 391 | − glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_CONSTANT_ALPHA, GL_ONE); | |
| 392 | − glEnable(GL_LIGHTING); | |
| 393 | − } glPopMatrix(); | |
| 394 | −} | |
| 395 | − | |
| 396 | −// Draws the FBO texture for 3DTV. | |
| 397 | −void ApplicationOverlay::displayOverlayTextureStereo(Camera& whichCamera, float aspectRatio, float fov) { | |
| 398 | − if (_alpha == 0.0f) { | |
| 399 | − return; | |
| 400 | − } | |
| 401 | − | |
| 402 | − MyAvatar* myAvatar = DependencyManager::get<AvatarManager>()->getMyAvatar(); | |
| 403 | − const glm::vec3& viewMatrixTranslation = qApp->getViewMatrixTranslation(); | |
| 404 | − | |
| 405 | − glEnable(GL_BLEND); | |
| 406 | − glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_CONSTANT_ALPHA, GL_ONE); | |
| 407 | − glEnable(GL_DEPTH_TEST); | |
| 408 | − glDisable(GL_LIGHTING); | |
| 409 | − | |
| 410 | − glMatrixMode(GL_MODELVIEW); | |
| 411 | − | |
| 412 | − glPushMatrix(); | |
| 413 | − glLoadIdentity(); | |
| 414 | − // Transform to world space | |
| 415 | − glm::quat rotation = whichCamera.getRotation(); | |
| 416 | − glm::vec3 axis2 = glm::axis(rotation); | |
| 417 | − glRotatef(-glm::degrees(glm::angle(rotation)), axis2.x, axis2.y, axis2.z); | |
| 418 | − glTranslatef(viewMatrixTranslation.x, viewMatrixTranslation.y, viewMatrixTranslation.z); | |
| 419 | − | |
| 420 | − // Translate to the front of the camera | |
| 421 | − glm::vec3 pos = whichCamera.getPosition(); | |
| 422 | − glm::quat rot = myAvatar->getOrientation(); | |
| 423 | − glm::vec3 axis = glm::axis(rot); | |
| 424 | − | |
| 425 | − glTranslatef(pos.x, pos.y, pos.z); | |
| 426 | − glRotatef(glm::degrees(glm::angle(rot)), axis.x, axis.y, axis.z); | |
| 427 | − | |
| 428 | − glm::vec4 overlayColor = {1.0f, 1.0f, 1.0f, _alpha}; | |
| 429 | − | |
| 430 | − //Render | |
| 431 | − const GLfloat distance = 1.0f; | |
| 432 | − | |
| 433 | − const GLfloat halfQuadHeight = distance * tan(fov); | |
| 434 | − const GLfloat halfQuadWidth = halfQuadHeight * aspectRatio; | |
| 435 | − const GLfloat quadWidth = halfQuadWidth * 2.0f; | |
| 436 | − const GLfloat quadHeight = halfQuadHeight * 2.0f; | |
| 437 | − | |
| 438 | − GLfloat x = -halfQuadWidth; | |
| 439 | − GLfloat y = -halfQuadHeight; | |
| 440 | 126 | glDisable(GL_DEPTH_TEST); |
| 441 | − | |
| 442 | − with_each_texture(_overlays.getTexture(), _newUiTexture, [&] { | |
| 443 | − DependencyManager::get<GeometryCache>()->renderQuad(glm::vec3(x, y + quadHeight, -distance), | |
| 444 | − glm::vec3(x + quadWidth, y + quadHeight, -distance), | |
| 445 | − glm::vec3(x + quadWidth, y, -distance), | |
| 446 | − glm::vec3(x, y, -distance), | |
| 447 | − glm::vec2(0.0f, 1.0f), glm::vec2(1.0f, 1.0f), | |
| 448 | − glm::vec2(1.0f, 0.0f), glm::vec2(0.0f, 0.0f), | |
| 449 | − overlayColor); | |
| 450 | − }); | |
| 451 | − | |
| 452 | − if (!_crosshairTexture) { | |
| 453 | − _crosshairTexture = TextureCache::getImageTexture(PathUtils::resourcesPath() + | |
| 454 | − "images/sixense-reticle.png"); | |
| 455 | − } | |
| 456 | − | |
| 457 | − //draw the mouse pointer | |
| 127 | + glDisable(GL_LIGHTING); | |
| 458 | 128 | glEnable(GL_BLEND); |
| 459 | 129 | glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); |
| 460 | − glEnable(GL_TEXTURE_2D); | |
| 461 | − glBindTexture(GL_TEXTURE_2D, gpu::GLBackend::getTextureID(_crosshairTexture)); | |
| 462 | − glm::vec2 canvasSize = qApp->getCanvasSize(); | |
| 463 | − const float reticleSize = 40.0f / canvasSize.x * quadWidth; | |
| 464 | − x -= reticleSize / 2.0f; | |
| 465 | − y += reticleSize / 2.0f; | |
| 466 | − const float mouseX = (qApp->getMouseX() / (float)canvasSize.x) * quadWidth; | |
| 467 | − const float mouseY = (1.0 - (qApp->getMouseY() / (float)canvasSize.y)) * quadHeight; | |
| 468 | − | |
| 469 | − glm::vec4 reticleColor = { RETICLE_COLOR[0], RETICLE_COLOR[1], RETICLE_COLOR[2], 1.0f }; | |
| 470 | 130 | |
| 471 | − DependencyManager::get<GeometryCache>()->renderQuad(glm::vec3(x + mouseX, y + mouseY, -distance), | |
| 472 | − glm::vec3(x + mouseX + reticleSize, y + mouseY, -distance), | |
| 473 | − glm::vec3(x + mouseX + reticleSize, y + mouseY - reticleSize, -distance), | |
| 474 | − glm::vec3(x + mouseX, y + mouseY - reticleSize, -distance), | |
| 475 | − glm::vec2(0.0f, 0.0f), glm::vec2(1.0f, 0.0f), | |
| 476 | − glm::vec2(1.0f, 1.0f), glm::vec2(0.0f, 1.0f), | |
| 477 | − reticleColor, _reticleQuad); | |
| 131 | + // give external parties a change to hook in | |
| 132 | + emit qApp->renderingOverlay(); | |
| 133 | + qApp->getOverlays().renderHUD(renderArgs); | |
| 478 | 134 | |
| 479 | − glEnable(GL_DEPTH_TEST); | |
| 480 | − | |
| 135 | + glMatrixMode(GL_PROJECTION); | |
| 481 | 136 | glPopMatrix(); |
| 482 | − | |
| 483 | − glDepthMask(GL_TRUE); | |
| 484 | − glBindTexture(GL_TEXTURE_2D, 0); | |
| 485 | − glDisable(GL_TEXTURE_2D); | |
| 486 | − | |
| 487 | − glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_CONSTANT_ALPHA, GL_ONE); | |
| 488 | − glEnable(GL_LIGHTING); | |
| 489 | −} | |
| 490 | − | |
| 491 | −void ApplicationOverlay::computeHmdPickRay(glm::vec2 cursorPos, glm::vec3& origin, glm::vec3& direction) const { | |
| 492 | − cursorPos *= qApp->getCanvasSize(); | |
| 493 | − const glm::vec2 projection = screenToSpherical(cursorPos); | |
| 494 | − // The overlay space orientation of the mouse coordinates | |
| 495 | − const glm::quat orientation(glm::vec3(-projection.y, projection.x, 0.0f)); | |
| 496 | − // FIXME We now have the direction of the ray FROM THE DEFAULT HEAD POSE. | |
| 497 | − // Now we need to account for the actual camera position relative to the overlay | |
| 498 | − glm::vec3 overlaySpaceDirection = glm::normalize(orientation * IDENTITY_FRONT); | |
| 499 | − | |
| 500 | − | |
| 501 | − const glm::vec3& hmdPosition = qApp->getCamera()->getHmdPosition(); | |
| 502 | − const glm::quat& hmdOrientation = qApp->getCamera()->getHmdRotation(); | |
| 503 | − | |
| 504 | − // We need the RAW camera orientation and position, because this is what the overlay is | |
| 505 | − // rendered relative to | |
| 506 | − const glm::vec3 overlayPosition = qApp->getCamera()->getPosition() - hmdPosition; | |
| 507 | − const glm::quat overlayOrientation = qApp->getCamera()->getRotation() * glm::inverse(hmdOrientation); | |
| 508 | − | |
| 509 | − // Intersection UI overlay space | |
| 510 | − glm::vec3 worldSpaceDirection = overlayOrientation * overlaySpaceDirection; | |
| 511 | − glm::vec3 intersectionWithUi = glm::normalize(worldSpaceDirection) * _oculusUIRadius; | |
| 512 | − intersectionWithUi += overlayPosition; | |
| 513 | − | |
| 514 | − // Intersection in world space | |
| 515 | − origin = overlayPosition + hmdPosition; | |
| 516 | − direction = glm::normalize(intersectionWithUi - origin); | |
| 517 | −} | |
| 518 | − | |
| 519 | −glm::vec2 getPolarCoordinates(const PalmData& palm) { | |
| 520 | − MyAvatar* myAvatar = DependencyManager::get<AvatarManager>()->getMyAvatar(); | |
| 521 | − auto avatarOrientation = myAvatar->getOrientation(); | |
| 522 | − auto eyePos = myAvatar->getDefaultEyePosition(); | |
| 523 | − glm::vec3 tip = myAvatar->getLaserPointerTipPosition(&palm); | |
| 524 | − // Direction of the tip relative to the eye | |
| 525 | − glm::vec3 tipDirection = tip - eyePos; | |
| 526 | − // orient into avatar space | |
| 527 | − tipDirection = glm::inverse(avatarOrientation) * tipDirection; | |
| 528 | − // Normalize for trig functions | |
| 529 | − tipDirection = glm::normalize(tipDirection); | |
| 530 | − // Convert to polar coordinates | |
| 531 | − glm::vec2 polar(glm::atan(tipDirection.x, -tipDirection.z), glm::asin(tipDirection.y)); | |
| 532 | − return polar; | |
| 533 | −} | |
| 534 | − | |
| 535 | −//Caculate the click location using one of the sixense controllers. Scale is not applied | |
| 536 | −QPoint ApplicationOverlay::getPalmClickLocation(const PalmData *palm) const { | |
| 537 | − QPoint rv; | |
| 538 | − auto canvasSize = qApp->getCanvasSize(); | |
| 539 | − if (qApp->isHMDMode()) { | |
| 540 | − glm::vec2 polar = getPolarCoordinates(*palm); | |
| 541 | − glm::vec2 point = sphericalToScreen(-polar); | |
| 542 | − rv.rx() = point.x; | |
| 543 | − rv.ry() = point.y; | |
| 544 | − } else { | |
| 545 | − MyAvatar* myAvatar = DependencyManager::get<AvatarManager>()->getMyAvatar(); | |
| 546 | − glm::dmat4 projection; | |
| 547 | − qApp->getProjectionMatrix(&projection); | |
| 548 | − glm::quat invOrientation = glm::inverse(myAvatar->getOrientation()); | |
| 549 | − glm::vec3 eyePos = myAvatar->getDefaultEyePosition(); | |
| 550 | − glm::vec3 tip = myAvatar->getLaserPointerTipPosition(palm); | |
| 551 | − glm::vec3 tipPos = invOrientation * (tip - eyePos); | |
| 552 | − | |
| 553 | − glm::vec4 clipSpacePos = glm::vec4(projection * glm::dvec4(tipPos, 1.0)); | |
| 554 | − glm::vec3 ndcSpacePos; | |
| 555 | − if (clipSpacePos.w != 0) { | |
| 556 | − ndcSpacePos = glm::vec3(clipSpacePos) / clipSpacePos.w; | |
| 557 | − } | |
| 558 | − | |
| 559 | − rv.setX(((ndcSpacePos.x + 1.0) / 2.0) * canvasSize.x); | |
| 560 | − rv.setY((1.0 - ((ndcSpacePos.y + 1.0) / 2.0)) * canvasSize.y); | |
| 561 | − } | |
| 562 | − return rv; | |
| 563 | −} | |
| 564 | − | |
| 565 | −//Finds the collision point of a world space ray | |
| 566 | −bool ApplicationOverlay::calculateRayUICollisionPoint(const glm::vec3& position, const glm::vec3& direction, glm::vec3& result) const { | |
| 567 | − MyAvatar* myAvatar = DependencyManager::get<AvatarManager>()->getMyAvatar(); | |
| 568 | − | |
| 569 | − glm::quat inverseOrientation = glm::inverse(myAvatar->getOrientation()); | |
| 570 | − | |
| 571 | − glm::vec3 relativePosition = inverseOrientation * (position - myAvatar->getDefaultEyePosition()); | |
| 572 | − glm::vec3 relativeDirection = glm::normalize(inverseOrientation * direction); | |
| 573 | − | |
| 574 | − float t; | |
| 575 | − if (raySphereIntersect(relativeDirection, relativePosition, _oculusUIRadius * myAvatar->getScale(), &t)){ | |
| 576 | − result = position + direction * t; | |
| 577 | − return true; | |
| 578 | − } | |
| 579 | − | |
| 580 | − return false; | |
| 581 | −} | |
| 582 | − | |
| 583 | −//Renders optional pointers | |
| 584 | −void ApplicationOverlay::renderPointers() { | |
| 585 | − //lazily load crosshair texture | |
| 586 | − if (_crosshairTexture == 0) { | |
| 587 | − _crosshairTexture = TextureCache::getImageTexture(PathUtils::resourcesPath() + "images/sixense-reticle.png"); | |
| 588 | − } | |
| 589 | − glEnable(GL_TEXTURE_2D); | |
| 590 | − glEnable(GL_BLEND); | |
| 591 | − glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); | |
| 592 | − | |
| 593 | − //glActiveTexture(GL_TEXTURE0); | |
| 594 | − //bindCursorTexture(); | |
| 595 | − | |
| 596 | − if (qApp->isHMDMode() && !qApp->getLastMouseMoveWasSimulated() && !qApp->isMouseHidden()) { | |
| 597 | − //If we are in oculus, render reticle later | |
| 598 | − if (_lastMouseMove == 0) { | |
| 599 | − _lastMouseMove = usecTimestampNow(); | |
| 600 | − } | |
| 601 | − QPoint position = QPoint(qApp->getTrueMouseX(), qApp->getTrueMouseY()); | |
| 602 | − | |
| 603 | − static const int MAX_IDLE_TIME = 3; | |
| 604 | − if (_reticlePosition[MOUSE] != position) { | |
| 605 | − _lastMouseMove = usecTimestampNow(); | |
| 606 | − } else if (usecTimestampNow() - _lastMouseMove > MAX_IDLE_TIME * USECS_PER_SECOND) { | |
| 607 | − //float pitch = 0.0f, yaw = 0.0f, roll = 0.0f; // radians | |
| 608 | − //OculusManager::getEulerAngles(yaw, pitch, roll); | |
| 609 | − glm::quat orientation = qApp->getHeadOrientation(); // (glm::vec3(pitch, yaw, roll)); | |
| 610 | − glm::vec3 result; | |
| 611 | − | |
| 612 | − MyAvatar* myAvatar = DependencyManager::get<AvatarManager>()->getMyAvatar(); | |
| 613 | − if (calculateRayUICollisionPoint(myAvatar->getEyePosition(), | |
| 614 | − myAvatar->getOrientation() * orientation * IDENTITY_FRONT, | |
| 615 | − result)) { | |
| 616 | − glm::vec3 lookAtDirection = glm::inverse(myAvatar->getOrientation()) * (result - myAvatar->getDefaultEyePosition()); | |
| 617 | − glm::vec2 spericalPos = directionToSpherical(glm::normalize(lookAtDirection)); | |
| 618 | − glm::vec2 screenPos = sphericalToScreen(spericalPos); | |
| 619 | − position = QPoint(screenPos.x, screenPos.y); | |
| 620 | − // FIXME | |
| 621 | − //glCanvas->cursor().setPos(glCanvas->mapToGlobal(position)); | |
| 622 | − } else { | |
| 623 | − qDebug() << "No collision point"; | |
| 624 | − } | |
| 625 | − } | |
| 626 | − | |
| 627 | − _reticlePosition[MOUSE] = position; | |
| 628 | − _reticleActive[MOUSE] = true; | |
| 629 | − _magActive[MOUSE] = _magnifier; | |
| 630 | − _reticleActive[LEFT_CONTROLLER] = false; | |
| 631 | − _reticleActive[RIGHT_CONTROLLER] = false; | |
| 632 | − } else if (qApp->getLastMouseMoveWasSimulated() && Menu::getInstance()->isOptionChecked(MenuOption::SixenseMouseInput)) { | |
| 633 | − _lastMouseMove = 0; | |
| 634 | − //only render controller pointer if we aren't already rendering a mouse pointer | |
| 635 | − _reticleActive[MOUSE] = false; | |
| 636 | − _magActive[MOUSE] = false; | |
| 637 | − renderControllerPointers(); | |
| 638 | − } | |
| 639 | − //glBindTexture(GL_TEXTURE_2D, 0); | |
| 640 | − //glDisable(GL_TEXTURE_2D); | |
| 641 | −} | |
| 642 | − | |
| 643 | −void ApplicationOverlay::renderControllerPointers() { | |
| 644 | − MyAvatar* myAvatar = DependencyManager::get<AvatarManager>()->getMyAvatar(); | |
| 645 | − | |
| 646 | − //Static variables used for storing controller state | |
| 647 | − static quint64 pressedTime[NUMBER_OF_RETICLES] = { 0ULL, 0ULL, 0ULL }; | |
| 648 | − static bool isPressed[NUMBER_OF_RETICLES] = { false, false, false }; | |
| 649 | − static bool stateWhenPressed[NUMBER_OF_RETICLES] = { false, false, false }; | |
| 650 | − | |
| 651 | − const HandData* handData = DependencyManager::get<AvatarManager>()->getMyAvatar()->getHandData(); | |
| 652 | − | |
| 653 | − for (unsigned int palmIndex = 2; palmIndex < 4; palmIndex++) { | |
| 654 | − const int index = palmIndex - 1; | |
| 655 | − | |
| 656 | − const PalmData* palmData = NULL; | |
| 657 | − | |
| 658 | − if (palmIndex >= handData->getPalms().size()) { | |
| 659 | − return; | |
| 660 | − } | |
| 661 | − | |
| 662 | − if (handData->getPalms()[palmIndex].isActive()) { | |
| 663 | − palmData = &handData->getPalms()[palmIndex]; | |
| 664 | − } else { | |
| 665 | − continue; | |
| 666 | − } | |
| 667 | − | |
| 668 | − int controllerButtons = palmData->getControllerButtons(); | |
| 669 | − | |
| 670 | − //Check for if we should toggle or drag the magnification window | |
| 671 | − if (controllerButtons & BUTTON_3) { | |
| 672 | − if (isPressed[index] == false) { | |
| 673 | − //We are now dragging the window | |
| 674 | − isPressed[index] = true; | |
| 675 | − //set the pressed time in us | |
| 676 | − pressedTime[index] = usecTimestampNow(); | |
| 677 | − stateWhenPressed[index] = _magActive[index]; | |
| 678 | − } | |
| 679 | − } else if (isPressed[index]) { | |
| 680 | − isPressed[index] = false; | |
| 681 | − //If the button was only pressed for < 250 ms | |
| 682 | − //then disable it. | |
| 683 | − | |
| 684 | − const int MAX_BUTTON_PRESS_TIME = 250 * MSECS_TO_USECS; | |
| 685 | − if (usecTimestampNow() < pressedTime[index] + MAX_BUTTON_PRESS_TIME) { | |
| 686 | − _magActive[index] = !stateWhenPressed[index]; | |
| 687 | − } | |
| 688 | − } | |
| 689 | − | |
| 690 | − //if we have the oculus, we should make the cursor smaller since it will be | |
| 691 | − //magnified | |
| 692 | − if (qApp->isHMDMode()) { | |
| 693 | − | |
| 694 | − QPoint point = getPalmClickLocation(palmData); | |
| 695 | − | |
| 696 | − _reticlePosition[index] = point; | |
| 697 | − | |
| 698 | − //When button 2 is pressed we drag the mag window | |
| 699 | − if (isPressed[index]) { | |
| 700 | − _magActive[index] = true; | |
| 701 | − } | |
| 702 | − | |
| 703 | − // If oculus is enabled, we draw the crosshairs later | |
| 704 | − continue; | |
| 705 | − } | |
| 706 | − | |
| 707 | − auto canvasSize = qApp->getCanvasSize(); | |
| 708 | − int mouseX, mouseY; | |
| 709 | − if (Menu::getInstance()->isOptionChecked(MenuOption::SixenseLasers)) { | |
| 710 | − QPoint res = getPalmClickLocation(palmData); | |
| 711 | − mouseX = res.x(); | |
| 712 | − mouseY = res.y(); | |
| 713 | − } else { | |
| 714 | − // Get directon relative to avatar orientation | |
| 715 | − glm::vec3 direction = glm::inverse(myAvatar->getOrientation()) * palmData->getFingerDirection(); | |
| 716 | − | |
| 717 | − // Get the angles, scaled between (-0.5,0.5) | |
| 718 | − float xAngle = (atan2(direction.z, direction.x) + M_PI_2); | |
| 719 | − float yAngle = 0.5f - ((atan2(direction.z, direction.y) + M_PI_2)); | |
| 720 | − | |
| 721 | − // Get the pixel range over which the xAngle and yAngle are scaled | |
| 722 | − float cursorRange = canvasSize.x * SixenseManager::getInstance().getCursorPixelRangeMult(); | |
| 723 | − | |
| 724 | − mouseX = (canvasSize.x / 2.0f + cursorRange * xAngle); | |
| 725 | − mouseY = (canvasSize.y / 2.0f + cursorRange * yAngle); | |
| 726 | − } | |
| 727 | − | |
| 728 | − //If the cursor is out of the screen then don't render it | |
| 729 | − if (mouseX < 0 || mouseX >= (int)canvasSize.x || mouseY < 0 || mouseY >= (int)canvasSize.y) { | |
| 730 | − _reticleActive[index] = false; | |
| 731 | − continue; | |
| 732 | − } | |
| 733 | − _reticleActive[index] = true; | |
| 734 | − | |
| 735 | − | |
| 736 | − const float reticleSize = 40.0f; | |
| 737 | − | |
| 738 | − mouseX -= reticleSize / 2.0f; | |
| 739 | − mouseY += reticleSize / 2.0f; | |
| 740 | − | |
| 741 | − | |
| 742 | − glm::vec2 topLeft(mouseX, mouseY); | |
| 743 | − glm::vec2 bottomRight(mouseX + reticleSize, mouseY - reticleSize); | |
| 744 | − glm::vec2 texCoordTopLeft(0.0f, 0.0f); | |
| 745 | − glm::vec2 texCoordBottomRight(1.0f, 1.0f); | |
| 746 | − | |
| 747 | − DependencyManager::get<GeometryCache>()->renderQuad(topLeft, bottomRight, texCoordTopLeft, texCoordBottomRight, | |
| 748 | − glm::vec4(RETICLE_COLOR[0], RETICLE_COLOR[1], RETICLE_COLOR[2], 1.0f)); | |
| 749 | − | |
| 750 | − } | |
| 751 | −} | |
| 752 | − | |
| 753 | −void ApplicationOverlay::renderPointersOculus() { | |
| 754 | − | |
| 755 | − glEnable(GL_BLEND); | |
| 756 | − glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); | |
| 757 | − glEnable(GL_TEXTURE_2D); | |
| 758 | − | |
| 759 | − glBindTexture(GL_TEXTURE_2D, gpu::GLBackend::getTextureID(_crosshairTexture)); | |
| 760 | − glDisable(GL_DEPTH_TEST); | |
| 761 | − | |
| 762 | 137 | glMatrixMode(GL_MODELVIEW); |
| 763 | − | |
| 764 | − //Controller Pointers | |
| 765 | − MyAvatar* myAvatar = DependencyManager::get<AvatarManager>()->getMyAvatar(); | |
| 766 | − for (int i = 0; i < (int)myAvatar->getHand()->getNumPalms(); i++) { | |
| 767 | − PalmData& palm = myAvatar->getHand()->getPalms()[i]; | |
| 768 | − if (palm.isActive()) { | |
| 769 | − glm::vec2 polar = getPolarCoordinates(palm); | |
| 770 | − // Convert to quaternion | |
| 771 | − glm::quat orientation = glm::quat(glm::vec3(polar.y, -polar.x, 0.0f)); | |
| 772 | − // Render reticle at location | |
| 773 | − renderReticle(orientation, _alpha); | |
| 774 | − } | |
| 775 | − } | |
| 776 | − | |
| 777 | − //Mouse Pointer | |
| 778 | − if (_reticleActive[MOUSE]) { | |
| 779 | − glm::vec2 projection = screenToSpherical(glm::vec2(_reticlePosition[MOUSE].x(), | |
| 780 | − _reticlePosition[MOUSE].y())); | |
| 781 | − glm::quat orientation(glm::vec3(-projection.y, projection.x, 0.0f)); | |
| 782 | − renderReticle(orientation, _alpha); | |
| 783 | − } | |
| 784 | 138 | |
| 785 | − glEnable(GL_DEPTH_TEST); | |
| 786 | − glDisable(GL_TEXTURE_2D); | |
| 787 | − glDisable(GL_BLEND); | |
| 139 | + renderArgs->_context->syncCache(); | |
| 140 | + fboViewport(_overlayFramebuffer); | |
| 788 | 141 | } |
| 789 | 142 | |
| 790 | −//Renders a small magnification of the currently bound texture at the coordinates | |
| 791 | −void ApplicationOverlay::renderMagnifier(glm::vec2 magPos, float sizeMult, bool showBorder) { | |
| 792 | − if (!_magnifier) { | |
| 793 | − return; | |
| 794 | − } | |
| 795 | − auto canvasSize = qApp->getCanvasSize(); | |
| 796 | − | |
| 797 | − const int widgetWidth = canvasSize.x; | |
| 798 | − const int widgetHeight = canvasSize.y; | |
| 799 | − | |
| 800 | − const float halfWidth = (MAGNIFY_WIDTH / _textureAspectRatio) * sizeMult / 2.0f; | |
| 801 | − const float halfHeight = MAGNIFY_HEIGHT * sizeMult / 2.0f; | |
| 802 | − // Magnification Texture Coordinates | |
| 803 | − const float magnifyULeft = (magPos.x - halfWidth) / (float)widgetWidth; | |
| 804 | − const float magnifyURight = (magPos.x + halfWidth) / (float)widgetWidth; | |
| 805 | − const float magnifyVTop = 1.0f - (magPos.y - halfHeight) / (float)widgetHeight; | |
| 806 | − const float magnifyVBottom = 1.0f - (magPos.y + halfHeight) / (float)widgetHeight; | |
| 807 | − | |
| 808 | − const float newHalfWidth = halfWidth * MAGNIFY_MULT; | |
| 809 | − const float newHalfHeight = halfHeight * MAGNIFY_MULT; | |
| 810 | − //Get yaw / pitch value for the corners | |
| 811 | − const glm::vec2 topLeftYawPitch = overlayToSpherical(glm::vec2(magPos.x - newHalfWidth, | |
| 812 | − magPos.y - newHalfHeight)); | |
| 813 | − const glm::vec2 bottomRightYawPitch = overlayToSpherical(glm::vec2(magPos.x + newHalfWidth, | |
| 814 | − magPos.y + newHalfHeight)); | |
| 815 | − | |
| 816 | − const glm::vec3 bottomLeft = getPoint(topLeftYawPitch.x, bottomRightYawPitch.y); | |
| 817 | − const glm::vec3 bottomRight = getPoint(bottomRightYawPitch.x, bottomRightYawPitch.y); | |
| 818 | − const glm::vec3 topLeft = getPoint(topLeftYawPitch.x, topLeftYawPitch.y); | |
| 819 | − const glm::vec3 topRight = getPoint(bottomRightYawPitch.x, topLeftYawPitch.y); | |
| 820 | − | |
| 821 | − auto geometryCache = DependencyManager::get<GeometryCache>(); | |
| 822 | − | |
| 823 | − if (bottomLeft != _previousMagnifierBottomLeft || bottomRight != _previousMagnifierBottomRight | |
| 824 | − || topLeft != _previousMagnifierTopLeft || topRight != _previousMagnifierTopRight) { | |
| 825 | − QVector<glm::vec3> border; | |
| 826 | − border << topLeft; | |
| 827 | − border << bottomLeft; | |
| 828 | − border << bottomRight; | |
| 829 | − border << topRight; | |
| 830 | − border << topLeft; | |
| 831 | − geometryCache->updateVertices(_magnifierBorder, border, glm::vec4(1.0f, 0.0f, 0.0f, _alpha)); | |
| 832 | − | |
| 833 | − _previousMagnifierBottomLeft = bottomLeft; | |
| 834 | − _previousMagnifierBottomRight = bottomRight; | |
| 835 | − _previousMagnifierTopLeft = topLeft; | |
| 836 | − _previousMagnifierTopRight = topRight; | |
| 837 | − } | |
| 838 | − | |
| 839 | − glPushMatrix(); { | |
| 840 | − if (showBorder) { | |
| 841 | − glDisable(GL_TEXTURE_2D); | |
| 842 | − glLineWidth(1.0f); | |
| 843 | − //Outer Line | |
| 844 | − geometryCache->renderVertices(gpu::LINE_STRIP, _magnifierBorder); | |
| 845 | − glEnable(GL_TEXTURE_2D); | |
| 846 | − } | |
| 847 | − glm::vec4 magnifierColor = { 1.0f, 1.0f, 1.0f, _alpha }; | |
| 848 | − | |
| 849 | − DependencyManager::get<GeometryCache>()->renderQuad(bottomLeft, bottomRight, topRight, topLeft, | |
| 850 | − glm::vec2(magnifyULeft, magnifyVBottom), | |
| 851 | − glm::vec2(magnifyURight, magnifyVBottom), | |
| 852 | − glm::vec2(magnifyURight, magnifyVTop), | |
| 853 | − glm::vec2(magnifyULeft, magnifyVTop), | |
| 854 | − magnifierColor, _magnifierQuad); | |
| 855 | − | |
| 856 | − } glPopMatrix(); | |
| 143 | +void ApplicationOverlay::renderRearViewToFbo(RenderArgs* renderArgs) { | |
| 857 | 144 | } |
| 858 | 145 | |
| 859 | −const int AUDIO_METER_GAP = 5; | |
| 860 | −const int MUTE_ICON_PADDING = 10; | |
| 861 | − | |
| 862 | −void ApplicationOverlay::renderCameraToggle() { | |
| 863 | − if (Menu::getInstance()->isOptionChecked(MenuOption::NoFaceTracking)) { | |
| 864 | − return; | |
| 865 | − } | |
| 866 | − | |
| 867 | − int audioMeterY; | |
| 868 | − bool smallMirrorVisible = Menu::getInstance()->isOptionChecked(MenuOption::Mirror) && !qApp->isHMDMode(); | |
| 869 | − bool boxed = smallMirrorVisible && | |
| 870 | − !Menu::getInstance()->isOptionChecked(MenuOption::FullscreenMirror); | |
| 871 | − if (boxed) { | |
| 872 | − audioMeterY = MIRROR_VIEW_HEIGHT + AUDIO_METER_GAP + MUTE_ICON_PADDING; | |
| 873 | − } else { | |
| 874 | − audioMeterY = AUDIO_METER_GAP + MUTE_ICON_PADDING; | |
| 875 | − } | |
| 876 | − | |
| 877 | − DependencyManager::get<CameraToolBox>()->render(MIRROR_VIEW_LEFT_PADDING + AUDIO_METER_GAP, audioMeterY, boxed); | |
| 146 | +void ApplicationOverlay::renderRearView(RenderArgs* renderArgs) { | |
| 878 | 147 | } |
| 879 | 148 | |
| 880 | −void ApplicationOverlay::renderAudioMeter() { | |
| 881 | − auto audio = DependencyManager::get<AudioClient>(); | |
| 882 | − | |
| 883 | − // Audio VU Meter and Mute Icon | |
| 884 | − const int MUTE_ICON_SIZE = 24; | |
| 885 | − const int AUDIO_METER_HEIGHT = 8; | |
| 886 | − const int INTER_ICON_GAP = 2; | |
| 887 | − | |
| 888 | − int cameraSpace = 0; | |
| 889 | − int audioMeterWidth = MIRROR_VIEW_WIDTH - MUTE_ICON_SIZE - MUTE_ICON_PADDING; | |
| 890 | − int audioMeterScaleWidth = audioMeterWidth - 2; | |
| 891 | − int audioMeterX = MIRROR_VIEW_LEFT_PADDING + MUTE_ICON_SIZE + AUDIO_METER_GAP; | |
| 892 | − if (!Menu::getInstance()->isOptionChecked(MenuOption::NoFaceTracking)) { | |
| 893 | − cameraSpace = MUTE_ICON_SIZE + INTER_ICON_GAP; | |
| 894 | − audioMeterWidth -= cameraSpace; | |
| 895 | − audioMeterScaleWidth -= cameraSpace; | |
| 896 | − audioMeterX += cameraSpace; | |
| 897 | − } | |
| 898 | − | |
| 899 | − int audioMeterY; | |
| 900 | − bool smallMirrorVisible = Menu::getInstance()->isOptionChecked(MenuOption::Mirror) && !qApp->isHMDMode(); | |
| 901 | − bool boxed = smallMirrorVisible && | |
| 902 | − !Menu::getInstance()->isOptionChecked(MenuOption::FullscreenMirror); | |
| 903 | − if (boxed) { | |
| 904 | − audioMeterY = MIRROR_VIEW_HEIGHT + AUDIO_METER_GAP + MUTE_ICON_PADDING; | |
| 905 | − } else { | |
| 906 | − audioMeterY = AUDIO_METER_GAP + MUTE_ICON_PADDING; | |
| 907 | − } | |
| 908 | − | |
| 909 | − const glm::vec4 AUDIO_METER_BLUE = { 0.0, 0.0, 1.0, 1.0 }; | |
| 910 | − const glm::vec4 AUDIO_METER_GREEN = { 0.0, 1.0, 0.0, 1.0 }; | |
| 911 | − const glm::vec4 AUDIO_METER_RED = { 1.0, 0.0, 0.0, 1.0 }; | |
| 912 | − const float CLIPPING_INDICATOR_TIME = 1.0f; | |
| 913 | − const float AUDIO_METER_AVERAGING = 0.5; | |
| 914 | − const float LOG2 = log(2.0f); | |
| 915 | − const float METER_LOUDNESS_SCALE = 2.8f / 5.0f; | |
| 916 | − const float LOG2_LOUDNESS_FLOOR = 11.0f; | |
| 917 | − float audioGreenStart = 0.25f * audioMeterScaleWidth; | |
| 918 | − float audioRedStart = 0.8f * audioMeterScaleWidth; | |
| 919 | − float audioLevel = 0.0f; | |
| 920 | − float loudness = audio->getLastInputLoudness() + 1.0f; | |
| 921 | − | |
| 922 | − _trailingAudioLoudness = AUDIO_METER_AVERAGING * _trailingAudioLoudness + (1.0f - AUDIO_METER_AVERAGING) * loudness; | |
| 923 | − float log2loudness = log(_trailingAudioLoudness) / LOG2; | |
| 924 | − | |
| 925 | − if (log2loudness <= LOG2_LOUDNESS_FLOOR) { | |
| 926 | − audioLevel = (log2loudness / LOG2_LOUDNESS_FLOOR) * METER_LOUDNESS_SCALE * audioMeterScaleWidth; | |
| 927 | − } else { | |
| 928 | − audioLevel = (log2loudness - (LOG2_LOUDNESS_FLOOR - 1.0f)) * METER_LOUDNESS_SCALE * audioMeterScaleWidth; | |
| 929 | − } | |
| 930 | − if (audioLevel > audioMeterScaleWidth) { | |
| 931 | − audioLevel = audioMeterScaleWidth; | |
| 932 | − } | |
| 933 | − bool isClipping = ((audio->getTimeSinceLastClip() > 0.0f) && (audio->getTimeSinceLastClip() < CLIPPING_INDICATOR_TIME)); | |
| 934 | − | |
| 935 | − DependencyManager::get<AudioToolBox>()->render(MIRROR_VIEW_LEFT_PADDING + AUDIO_METER_GAP, audioMeterY, cameraSpace, boxed); | |
| 936 | − | |
| 937 | − auto canvasSize = qApp->getCanvasSize(); | |
| 938 | − DependencyManager::get<AudioScope>()->render(canvasSize.x, canvasSize.y); | |
| 939 | − DependencyManager::get<AudioIOStatsRenderer>()->render(WHITE_TEXT, canvasSize.x, canvasSize.y); | |
| 940 | − | |
| 941 | − audioMeterY += AUDIO_METER_HEIGHT; | |
| 942 | − | |
| 943 | − // Draw audio meter background Quad | |
| 944 | − DependencyManager::get<GeometryCache>()->renderQuad(audioMeterX, audioMeterY, audioMeterWidth, AUDIO_METER_HEIGHT, | |
| 945 | − glm::vec4(0.0f, 0.0f, 0.0f, 1.0f)); | |
| 946 | − | |
| 947 | − if (audioLevel > audioRedStart) { | |
| 948 | − glm::vec4 quadColor; | |
| 949 | − if (!isClipping) { | |
| 950 | − quadColor = AUDIO_METER_RED; | |
| 951 | − } else { | |
| 952 | − quadColor = glm::vec4(1, 1, 1, 1); | |
| 953 | − } | |
| 954 | − // Draw Red Quad | |
| 955 | − DependencyManager::get<GeometryCache>()->renderQuad(audioMeterX + audioRedStart, | |
| 956 | − audioMeterY, | |
| 957 | − audioLevel - audioRedStart, | |
| 958 | − AUDIO_METER_HEIGHT, quadColor, | |
| 959 | − _audioRedQuad); | |
| 960 | − | |
| 961 | − audioLevel = audioRedStart; | |
| 962 | − } | |
| 963 | − | |
| 964 | − if (audioLevel > audioGreenStart) { | |
| 965 | − glm::vec4 quadColor; | |
| 966 | − if (!isClipping) { | |
| 967 | − quadColor = AUDIO_METER_GREEN; | |
| 968 | − } else { | |
| 969 | − quadColor = glm::vec4(1, 1, 1, 1); | |
| 970 | − } | |
| 971 | − // Draw Green Quad | |
| 972 | − DependencyManager::get<GeometryCache>()->renderQuad(audioMeterX + audioGreenStart, | |
| 973 | − audioMeterY, | |
| 974 | − audioLevel - audioGreenStart, | |
| 975 | − AUDIO_METER_HEIGHT, quadColor, | |
| 976 | − _audioGreenQuad); | |
| 977 | − | |
| 978 | − audioLevel = audioGreenStart; | |
| 979 | − } | |
| 980 | − | |
| 981 | − if (audioLevel >= 0) { | |
| 982 | − glm::vec4 quadColor; | |
| 983 | − if (!isClipping) { | |
| 984 | − quadColor = AUDIO_METER_BLUE; | |
| 985 | − } else { | |
| 986 | − quadColor = glm::vec4(1, 1, 1, 1); | |
| 987 | − } | |
| 988 | − // Draw Blue (low level) quad | |
| 989 | − DependencyManager::get<GeometryCache>()->renderQuad(audioMeterX, | |
| 990 | − audioMeterY, | |
| 991 | − audioLevel, AUDIO_METER_HEIGHT, quadColor, | |
| 992 | − _audioBlueQuad); | |
| 993 | − } | |
| 994 | −} | |
| 995 | − | |
| 996 | −void ApplicationOverlay::renderStatsAndLogs() { | |
| 997 | − Application* application = Application::getInstance(); | |
| 998 | − QSharedPointer<BandwidthRecorder> bandwidthRecorder = DependencyManager::get<BandwidthRecorder>(); | |
| 999 | − | |
| 1000 | − const OctreePacketProcessor& octreePacketProcessor = application->getOctreePacketProcessor(); | |
| 1001 | − NodeBounds& nodeBoundsDisplay = application->getNodeBoundsDisplay(); | |
| 1002 | − | |
| 149 | +void ApplicationOverlay::renderStatsAndLogs(RenderArgs* renderArgs) { | |
| 1003 | 150 | // Display stats and log text onscreen |
| 1004 | − glLineWidth(1.0f); | |
| 1005 | − glPointSize(1.0f); | |
| 1006 | 151 | |
| 1007 | 152 | // Determine whether to compute timing details |
| 1008 | − bool shouldDisplayTimingDetail = Menu::getInstance()->isOptionChecked(MenuOption::DisplayDebugTimingDetails) && | |
| 1009 | − Menu::getInstance()->isOptionChecked(MenuOption::Stats) && | |
| 1010 | − Stats::getInstance()->isExpanded(); | |
| 1011 | − if (shouldDisplayTimingDetail != PerformanceTimer::isActive()) { | |
| 1012 | − PerformanceTimer::setActive(shouldDisplayTimingDetail); | |
| 1013 | − } | |
| 1014 | − | |
| 1015 | − if (Menu::getInstance()->isOptionChecked(MenuOption::Stats)) { | |
| 1016 | − // let's set horizontal offset to give stats some margin to mirror | |
| 1017 | − int horizontalOffset = MIRROR_VIEW_WIDTH + MIRROR_VIEW_LEFT_PADDING * 2; | |
| 1018 | − int voxelPacketsToProcess = octreePacketProcessor.packetsToProcessCount(); | |
| 1019 | − // Onscreen text about position, servers, etc | |
| 1020 | − Stats::getInstance()->display(WHITE_TEXT, horizontalOffset, application->getFps(), | |
| 1021 | − bandwidthRecorder->getCachedTotalAverageInputPacketsPerSecond(), | |
| 1022 | − bandwidthRecorder->getCachedTotalAverageOutputPacketsPerSecond(), | |
| 1023 | − bandwidthRecorder->getCachedTotalAverageInputKilobitsPerSecond(), | |
| 1024 | − bandwidthRecorder->getCachedTotalAverageOutputKilobitsPerSecond(), | |
| 1025 | − voxelPacketsToProcess); | |
| 1026 | − } | |
| 1027 | 153 | |
| 154 | + /* | |
| 1028 | 155 | // Show on-screen msec timer |
| 1029 | 156 | if (Menu::getInstance()->isOptionChecked(MenuOption::FrameTimer)) { |
| 1030 | 157 | auto canvasSize = qApp->getCanvasSize(); |
| @@ -1036,159 +163,77 @@ void ApplicationOverlay::renderStatsAndLogs() { · 5 unmodified lines | ||
| 1036 | 163 | drawText(canvasSize.x - 100, canvasSize.y - timerBottom, |
| 1037 | 164 | 0.30f, 0.0f, 0, frameTimer.toUtf8().constData(), WHITE_TEXT); |
| 1038 | 165 | } |
| 166 | + | |
| 167 | + glPointSize(1.0f); | |
| 168 | + glDisable(GL_DEPTH_TEST); | |
| 169 | + glDisable(GL_LIGHTING); | |
| 170 | + glEnable(GL_BLEND); | |
| 171 | + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); | |
| 172 | + NodeBounds& nodeBoundsDisplay = qApp->getNodeBoundsDisplay(); | |
| 1039 | 173 | nodeBoundsDisplay.drawOverlay(); |
| 174 | + glEnable(GL_DEPTH_TEST); | |
| 175 | + glEnable(GL_LIGHTING); | |
| 176 | + glEnable(GL_BLEND); | |
| 177 | + glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_CONSTANT_ALPHA, GL_ONE); | |
| 178 | + fboViewport(_overlayFramebuffer); | |
| 179 | + */ | |
| 1040 | 180 | } |
| 1041 | 181 | |
| 1042 | −void ApplicationOverlay::renderDomainConnectionStatusBorder() { | |
| 182 | +void ApplicationOverlay::renderDomainConnectionStatusBorder(RenderArgs* renderArgs) { | |
| 183 | + auto geometryCache = DependencyManager::get<GeometryCache>(); | |
| 184 | + static std::once_flag once; | |
| 185 | + std::call_once(once, [&] { | |
| 186 | + QVector<vec2> points; | |
| 187 | + static const float B = 0.99f; | |
| 188 | + points.push_back(vec2(-B)); | |
| 189 | + points.push_back(vec2(B, -B)); | |
| 190 | + points.push_back(vec2(B)); | |
| 191 | + points.push_back(vec2(-B, B)); | |
| 192 | + points.push_back(vec2(-B)); | |
| 193 | + geometryCache->updateVertices(_domainStatusBorder, points, CONNECTION_STATUS_BORDER_COLOR); | |
| 194 | + }); | |
| 1043 | 195 | auto nodeList = DependencyManager::get<NodeList>(); |
| 1044 | − | |
| 1045 | 196 | if (nodeList && !nodeList->getDomainHandler().isConnected()) { |
| 197 | + gpu::Batch batch; | |
| 1046 | 198 | auto geometryCache = DependencyManager::get<GeometryCache>(); |
| 1047 | − auto canvasSize = qApp->getCanvasSize(); | |
| 1048 | − if ((int)canvasSize.x != _previousBorderWidth || (int)canvasSize.y != _previousBorderHeight) { | |
| 1049 | − glm::vec4 color(CONNECTION_STATUS_BORDER_COLOR[0], | |
| 1050 | − CONNECTION_STATUS_BORDER_COLOR[1], | |
| 1051 | − CONNECTION_STATUS_BORDER_COLOR[2], 1.0f); | |
| 1052 | − | |
| 1053 | − QVector<glm::vec2> border; | |
| 1054 | − border << glm::vec2(0, 0); | |
| 1055 | − border << glm::vec2(0, canvasSize.y); | |
| 1056 | − border << glm::vec2(canvasSize.x, canvasSize.y); | |
| 1057 | − border << glm::vec2(canvasSize.x, 0); | |
| 1058 | − border << glm::vec2(0, 0); | |
| 1059 | − geometryCache->updateVertices(_domainStatusBorder, border, color); | |
| 1060 | − _previousBorderWidth = canvasSize.x; | |
| 1061 | − _previousBorderHeight = canvasSize.y; | |
| 1062 | − } | |
| 1063 | − | |
| 1064 | − glLineWidth(CONNECTION_STATUS_BORDER_LINE_WIDTH); | |
| 1065 | − | |
| 1066 | − geometryCache->renderVertices(gpu::LINE_STRIP, _domainStatusBorder); | |
| 1067 | − } | |
| 1068 | −} | |
| 199 | + geometryCache->useSimpleDrawPipeline(batch); | |
| 200 | + batch.setProjectionTransform(mat4()); | |
| 201 | + batch.setModelTransform(mat4()); | |
| 202 | + batch.setUniformTexture(0, DependencyManager::get<TextureCache>()->getWhiteTexture()); | |
| 203 | + batch._glLineWidth(CONNECTION_STATUS_BORDER_LINE_WIDTH); | |
| 1069 | 204 | |
| 1070 | −ApplicationOverlay::TexturedHemisphere::TexturedHemisphere() : | |
| 1071 | − _vertices(0), | |
| 1072 | − _indices(0), | |
| 1073 | − _framebufferObject(NULL), | |
| 1074 | − _vbo(0, 0) { | |
| 1075 | −} | |
| 1076 | − | |
| 1077 | −ApplicationOverlay::TexturedHemisphere::~TexturedHemisphere() { | |
| 1078 | − cleanupVBO(); | |
| 1079 | − if (_framebufferObject != NULL) { | |
| 1080 | − delete _framebufferObject; | |
| 1081 | − } | |
| 1082 | −} | |
| 1083 | − | |
| 1084 | −void ApplicationOverlay::TexturedHemisphere::bind() { | |
| 1085 | − _framebufferObject->bind(); | |
| 1086 | −} | |
| 1087 | − | |
| 1088 | −void ApplicationOverlay::TexturedHemisphere::release() { | |
| 1089 | − _framebufferObject->release(); | |
| 1090 | −} | |
| 205 | + // TODO animate the disconnect border for some excitement while not connected? | |
| 206 | + //double usecs = usecTimestampNow(); | |
| 207 | + //double secs = usecs / 1000000.0; | |
| 208 | + //float scaleAmount = 1.0f + (0.01f * sin(secs * 5.0f)); | |
| 209 | + //batch.setModelTransform(glm::scale(mat4(), vec3(scaleAmount))); | |
| 1091 | 210 | |
| 1092 | −void ApplicationOverlay::TexturedHemisphere::buildVBO(const float fov, | |
| 1093 | − const float aspectRatio, | |
| 1094 | − const int slices, | |
| 1095 | − const int stacks) { | |
| 1096 | − if (fov >= PI) { | |
| 1097 | − qDebug() << "TexturedHemisphere::buildVBO(): FOV greater or equal than Pi will create issues"; | |
| 1098 | − } | |
| 1099 | − // Cleanup old VBO if necessary | |
| 1100 | − cleanupVBO(); | |
| 1101 | − | |
| 1102 | − //UV mapping source: http://www.mvps.org/directx/articles/spheremap.htm | |
| 1103 | − | |
| 1104 | − // Compute number of vertices needed | |
| 1105 | − _vertices = slices * stacks; | |
| 1106 | − | |
| 1107 | − // Compute vertices positions and texture UV coordinate | |
| 1108 | − TextureVertex* vertexData = new TextureVertex[_vertices]; | |
| 1109 | − TextureVertex* vertexPtr = &vertexData[0]; | |
| 1110 | − for (int i = 0; i < stacks; i++) { | |
| 1111 | − float stacksRatio = (float)i / (float)(stacks - 1); // First stack is 0.0f, last stack is 1.0f | |
| 1112 | − // abs(theta) <= fov / 2.0f | |
| 1113 | − float pitch = -fov * (stacksRatio - 0.5f); | |
| 1114 | − | |
| 1115 | − for (int j = 0; j < slices; j++) { | |
| 1116 | − float slicesRatio = (float)j / (float)(slices - 1); // First slice is 0.0f, last slice is 1.0f | |
| 1117 | − // abs(phi) <= fov * aspectRatio / 2.0f | |
| 1118 | − float yaw = -fov * aspectRatio * (slicesRatio - 0.5f); | |
| 1119 | − | |
| 1120 | − vertexPtr->position = getPoint(yaw, pitch); | |
| 1121 | − vertexPtr->uv.x = slicesRatio; | |
| 1122 | − vertexPtr->uv.y = stacksRatio; | |
| 1123 | − vertexPtr++; | |
| 1124 | − } | |
| 1125 | − } | |
| 1126 | − // Create and write to buffer | |
| 1127 | − glGenBuffers(1, &_vbo.first); | |
| 1128 | − glBindBuffer(GL_ARRAY_BUFFER, _vbo.first); | |
| 1129 | − static const int BYTES_PER_VERTEX = sizeof(TextureVertex); | |
| 1130 | − glBufferData(GL_ARRAY_BUFFER, _vertices * BYTES_PER_VERTEX, vertexData, GL_STATIC_DRAW); | |
| 1131 | − delete[] vertexData; | |
| 1132 | − | |
| 1133 | − | |
| 1134 | − // Compute number of indices needed | |
| 1135 | − static const int VERTEX_PER_TRANGLE = 3; | |
| 1136 | − static const int TRIANGLE_PER_RECTANGLE = 2; | |
| 1137 | − int numberOfRectangles = (slices - 1) * (stacks - 1); | |
| 1138 | − _indices = numberOfRectangles * TRIANGLE_PER_RECTANGLE * VERTEX_PER_TRANGLE; | |
| 1139 | − | |
| 1140 | − // Compute indices order | |
| 1141 | − GLushort* indexData = new GLushort[_indices]; | |
| 1142 | − GLushort* indexPtr = indexData; | |
| 1143 | − for (int i = 0; i < stacks - 1; i++) { | |
| 1144 | − for (int j = 0; j < slices - 1; j++) { | |
| 1145 | − GLushort bottomLeftIndex = i * slices + j; | |
| 1146 | − GLushort bottomRightIndex = bottomLeftIndex + 1; | |
| 1147 | − GLushort topLeftIndex = bottomLeftIndex + slices; | |
| 1148 | − GLushort topRightIndex = topLeftIndex + 1; | |
| 1149 | − | |
| 1150 | − *(indexPtr++) = topLeftIndex; | |
| 1151 | − *(indexPtr++) = bottomLeftIndex; | |
| 1152 | − *(indexPtr++) = topRightIndex; | |
| 1153 | − | |
| 1154 | − *(indexPtr++) = topRightIndex; | |
| 1155 | − *(indexPtr++) = bottomLeftIndex; | |
| 1156 | − *(indexPtr++) = bottomRightIndex; | |
| 1157 | − } | |
| 211 | + geometryCache->renderVertices(batch, gpu::LINE_STRIP, _domainStatusBorder); | |
| 212 | + renderArgs->_context->syncCache(); | |
| 213 | + renderArgs->_context->render(batch); | |
| 1158 | 214 | } |
| 1159 | − // Create and write to buffer | |
| 1160 | − glGenBuffers(1, &_vbo.second); | |
| 1161 | − glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _vbo.second); | |
| 1162 | − static const int BYTES_PER_INDEX = sizeof(GLushort); | |
| 1163 | − glBufferData(GL_ELEMENT_ARRAY_BUFFER, _indices * BYTES_PER_INDEX, indexData, GL_STATIC_DRAW); | |
| 1164 | − delete[] indexData; | |
| 1165 | 215 | } |
| 1166 | 216 | |
| 1167 | −void ApplicationOverlay::TexturedHemisphere::cleanupVBO() { | |
| 1168 | − if (_vbo.first != 0) { | |
| 1169 | − glDeleteBuffers(1, &_vbo.first); | |
| 1170 | − _vbo.first = 0; | |
| 1171 | − } | |
| 1172 | − if (_vbo.second != 0) { | |
| 1173 | − glDeleteBuffers(1, &_vbo.second); | |
| 1174 | − _vbo.second = 0; | |
| 217 | +GLuint ApplicationOverlay::getOverlayTexture() { | |
| 218 | + if (!_overlayFramebuffer) { | |
| 219 | + return 0; | |
| 1175 | 220 | } |
| 221 | + return _overlayFramebuffer->texture(); | |
| 1176 | 222 | } |
| 1177 | 223 | |
| 1178 | −void ApplicationOverlay::TexturedHemisphere::buildFramebufferObject() { | |
| 1179 | − auto canvasSize = qApp->getCanvasSize(); | |
| 1180 | − QSize fboSize = QSize(canvasSize.x, canvasSize.y); | |
| 1181 | − if (_framebufferObject != NULL && fboSize == _framebufferObject->size()) { | |
| 1182 | − // Already build | |
| 224 | +void ApplicationOverlay::buildFramebufferObject() { | |
| 225 | + QSize fboSize = qApp->getDeviceSize(); | |
| 226 | + if (_overlayFramebuffer && fboSize == _overlayFramebuffer->size()) { | |
| 227 | + // Already built | |
| 1183 | 228 | return; |
| 1184 | 229 | } |
| 1185 | 230 | |
| 1186 | − if (_framebufferObject != NULL) { | |
| 1187 | − delete _framebufferObject; | |
| 231 | + if (_overlayFramebuffer) { | |
| 232 | + delete _overlayFramebuffer; | |
| 1188 | 233 | } |
| 1189 | 234 | |
| 1190 | − _framebufferObject = new QOpenGLFramebufferObject(fboSize, QOpenGLFramebufferObject::Depth); | |
| 1191 | − glBindTexture(GL_TEXTURE_2D, getTexture()); | |
| 235 | + _overlayFramebuffer = new QOpenGLFramebufferObject(fboSize, QOpenGLFramebufferObject::Depth); | |
| 236 | + glBindTexture(GL_TEXTURE_2D, getOverlayTexture()); | |
| 1192 | 237 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); |
| 1193 | 238 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); |
| 1194 | 239 | glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER); |
| @@ -1197,104 +242,3 @@ void ApplicationOverlay::TexturedHemisphere::buildFramebufferObject() { · 2 unmodified lines | ||
| 1197 | 242 | glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, borderColor); |
| 1198 | 243 | glBindTexture(GL_TEXTURE_2D, 0); |
| 1199 | 244 | } |
| 1200 | − | |
| 1201 | −//Renders a hemisphere with texture coordinates. | |
| 1202 | −void ApplicationOverlay::TexturedHemisphere::render() { | |
| 1203 | − if (_framebufferObject == NULL || _vbo.first == 0 || _vbo.second == 0) { | |
| 1204 | − qDebug() << "TexturedHemisphere::render(): Incorrect initialisation"; | |
| 1205 | − return; | |
| 1206 | − } | |
| 1207 | − | |
| 1208 | − glBindBuffer(GL_ARRAY_BUFFER, _vbo.first); | |
| 1209 | − glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _vbo.second); | |
| 1210 | − | |
| 1211 | − glEnableClientState(GL_VERTEX_ARRAY); | |
| 1212 | − glEnableClientState(GL_TEXTURE_COORD_ARRAY); | |
| 1213 | − | |
| 1214 | − static const int STRIDE = sizeof(TextureVertex); | |
| 1215 | − static const void* VERTEX_POINTER = 0; | |
| 1216 | − static const void* TEX_COORD_POINTER = (void*)sizeof(glm::vec3); | |
| 1217 | − glVertexPointer(3, GL_FLOAT, STRIDE, VERTEX_POINTER); | |
| 1218 | − glTexCoordPointer(2, GL_FLOAT, STRIDE, TEX_COORD_POINTER); | |
| 1219 | − | |
| 1220 | − glDrawRangeElements(GL_TRIANGLES, 0, _vertices - 1, _indices, GL_UNSIGNED_SHORT, 0); | |
| 1221 | − | |
| 1222 | − glDisableClientState(GL_VERTEX_ARRAY); | |
| 1223 | − glDisableClientState(GL_TEXTURE_COORD_ARRAY); | |
| 1224 | − | |
| 1225 | − glBindBuffer(GL_ARRAY_BUFFER, 0); | |
| 1226 | − glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); | |
| 1227 | −} | |
| 1228 | − | |
| 1229 | −GLuint ApplicationOverlay::TexturedHemisphere::getTexture() { | |
| 1230 | − return _framebufferObject->texture(); | |
| 1231 | −} | |
| 1232 | − | |
| 1233 | −glm::vec2 ApplicationOverlay::directionToSpherical(const glm::vec3& direction) { | |
| 1234 | − glm::vec2 result; | |
| 1235 | − // Compute yaw | |
| 1236 | − glm::vec3 normalProjection = glm::normalize(glm::vec3(direction.x, 0.0f, direction.z)); | |
| 1237 | − result.x = glm::acos(glm::dot(IDENTITY_FRONT, normalProjection)); | |
| 1238 | − if (glm::dot(IDENTITY_RIGHT, normalProjection) > 0.0f) { | |
| 1239 | − result.x = -glm::abs(result.x); | |
| 1240 | − } else { | |
| 1241 | − result.x = glm::abs(result.x); | |
| 1242 | − } | |
| 1243 | − // Compute pitch | |
| 1244 | − result.y = angleBetween(IDENTITY_UP, direction) - PI_OVER_TWO; | |
| 1245 | − | |
| 1246 | − return result; | |
| 1247 | −} | |
| 1248 | − | |
| 1249 | −glm::vec3 ApplicationOverlay::sphericalToDirection(const glm::vec2& sphericalPos) { | |
| 1250 | − glm::quat rotation(glm::vec3(sphericalPos.y, sphericalPos.x, 0.0f)); | |
| 1251 | − return rotation * IDENTITY_FRONT; | |
| 1252 | −} | |
| 1253 | − | |
| 1254 | −glm::vec2 ApplicationOverlay::screenToSpherical(const glm::vec2& screenPos) { | |
| 1255 | − auto screenSize = qApp->getCanvasSize(); | |
| 1256 | − glm::vec2 result; | |
| 1257 | − result.x = -(screenPos.x / screenSize.x - 0.5f); | |
| 1258 | − result.y = (screenPos.y / screenSize.y - 0.5f); | |
| 1259 | − result.x *= MOUSE_YAW_RANGE; | |
| 1260 | − result.y *= MOUSE_PITCH_RANGE; | |
| 1261 | − | |
| 1262 | − return result; | |
| 1263 | −} | |
| 1264 | − | |
| 1265 | −glm::vec2 ApplicationOverlay::sphericalToScreen(const glm::vec2& sphericalPos) { | |
| 1266 | − glm::vec2 result = sphericalPos; | |
| 1267 | − result.x *= -1.0; | |
| 1268 | − result /= MOUSE_RANGE; | |
| 1269 | − result += 0.5f; | |
| 1270 | − result *= qApp->getCanvasSize(); | |
| 1271 | − return result; | |
| 1272 | −} | |
| 1273 | − | |
| 1274 | −glm::vec2 ApplicationOverlay::sphericalToOverlay(const glm::vec2& sphericalPos) const { | |
| 1275 | − glm::vec2 result = sphericalPos; | |
| 1276 | − result.x *= -1.0; | |
| 1277 | − result /= _textureFov; | |
| 1278 | − result.x /= _textureAspectRatio; | |
| 1279 | − result += 0.5f; | |
| 1280 | − result *= qApp->getCanvasSize(); | |
| 1281 | − return result; | |
| 1282 | −} | |
| 1283 | − | |
| 1284 | −glm::vec2 ApplicationOverlay::overlayToSpherical(const glm::vec2& overlayPos) const { | |
| 1285 | − glm::vec2 result = overlayPos; | |
| 1286 | − result /= qApp->getCanvasSize(); | |
| 1287 | − result -= 0.5f; | |
| 1288 | − result *= _textureFov; | |
| 1289 | − result.x *= _textureAspectRatio; | |
| 1290 | − result.x *= -1.0f; | |
| 1291 | − return result; | |
| 1292 | −} | |
| 1293 | − | |
| 1294 | −glm::vec2 ApplicationOverlay::screenToOverlay(const glm::vec2& screenPos) const { | |
| 1295 | − return sphericalToOverlay(screenToSpherical(screenPos)); | |
| 1296 | −} | |
| 1297 | − | |
| 1298 | −glm::vec2 ApplicationOverlay::overlayToScreen(const glm::vec2& overlayPos) const { | |
| 1299 | − return sphericalToScreen(overlayToSpherical(overlayPos)); | |
| 1300 | −} | |
| @@ -13,16 +13,8 @@ · 12 unmodified lines | ||
| 13 | 13 | #define hifi_ApplicationOverlay_h |
| 14 | 14 | |
| 15 | 15 | #include <gpu/Texture.h> |
| 16 | −class Camera; | |
| 17 | −class Overlays; | |
| 18 | 16 | class QOpenGLFramebufferObject; |
| 19 | 17 | |
| 20 | −const float MAGNIFY_WIDTH = 220.0f; | |
| 21 | −const float MAGNIFY_HEIGHT = 100.0f; | |
| 22 | −const float MAGNIFY_MULT = 2.0f; | |
| 23 | − | |
| 24 | −const float DEFAULT_HMD_UI_ANGULAR_SIZE = 72.0f; | |
| 25 | − | |
| 26 | 18 | // Handles the drawing of the overlays to the screen |
| 27 | 19 | // TODO, move divide up the rendering, displaying and input handling |
| 28 | 20 | // facilities of this class |
| @@ -33,122 +25,26 @@ public: · 4 unmodified lines | ||
| 33 | 25 | ~ApplicationOverlay(); |
| 34 | 26 | |
| 35 | 27 | void renderOverlay(RenderArgs* renderArgs); |
| 36 | − void displayOverlayTexture(); | |
| 37 | − void displayOverlayTextureStereo(Camera& whichCamera, float aspectRatio, float fov); | |
| 38 | − void displayOverlayTextureHmd(Camera& whichCamera); | |
| 39 | − | |
| 40 | − QPoint getPalmClickLocation(const PalmData *palm) const; | |
| 41 | − bool calculateRayUICollisionPoint(const glm::vec3& position, const glm::vec3& direction, glm::vec3& result) const; | |
| 42 | − | |
| 43 | − bool hasMagnifier() const { return _magnifier; } | |
| 44 | − void toggleMagnifier() { _magnifier = !_magnifier; } | |
| 28 | + GLuint getOverlayTexture(); | |
| 45 | 29 | |
| 46 | − float getHmdUIAngularSize() const { return _hmdUIAngularSize; } | |
| 47 | − void setHmdUIAngularSize(float hmdUIAngularSize) { _hmdUIAngularSize = hmdUIAngularSize; } | |
| 48 | − | |
| 49 | − // Converter from one frame of reference to another. | |
| 50 | − // Frame of reference: | |
| 51 | − // Direction: Ray that represents the spherical values | |
| 52 | − // Screen: Position on the screen (x,y) | |
| 53 | − // Spherical: Pitch and yaw that gives the position on the sphere we project on (yaw,pitch) | |
| 54 | − // Overlay: Position on the overlay (x,y) | |
| 55 | − // (x,y) in Overlay are similar than (x,y) in Screen except they can be outside of the bound of te screen. | |
| 56 | − // This allows for picking outside of the screen projection in 3D. | |
| 57 | − glm::vec2 sphericalToOverlay(const glm::vec2 & sphericalPos) const; | |
| 58 | − glm::vec2 overlayToSpherical(const glm::vec2 & overlayPos) const; | |
| 59 | − glm::vec2 screenToOverlay(const glm::vec2 & screenPos) const; | |
| 60 | − glm::vec2 overlayToScreen(const glm::vec2 & overlayPos) const; | |
| 61 | − void computeHmdPickRay(glm::vec2 cursorPos, glm::vec3& origin, glm::vec3& direction) const; | |
| 62 | − | |
| 63 | − static glm::vec2 directionToSpherical(const glm::vec3 & direction); | |
| 64 | − static glm::vec3 sphericalToDirection(const glm::vec2 & sphericalPos); | |
| 65 | − static glm::vec2 screenToSpherical(const glm::vec2 & screenPos); | |
| 66 | − static glm::vec2 sphericalToScreen(const glm::vec2 & sphericalPos); | |
| 67 | − | |
| 68 | 30 | private: |
| 69 | − // Interleaved vertex data | |
| 70 | − struct TextureVertex { | |
| 71 | − glm::vec3 position; | |
| 72 | − glm::vec2 uv; | |
| 73 | − }; | |
| 74 | − | |
| 75 | − typedef QPair<GLuint, GLuint> VerticesIndices; | |
| 76 | − class TexturedHemisphere { | |
| 77 | − public: | |
| 78 | − TexturedHemisphere(); | |
| 79 | − ~TexturedHemisphere(); | |
| 80 | − | |
| 81 | − void bind(); | |
| 82 | − void release(); | |
| 83 | − GLuint getTexture(); | |
| 84 | − | |
| 85 | − void buildFramebufferObject(); | |
| 86 | − void buildVBO(const float fov, const float aspectRatio, const int slices, const int stacks); | |
| 87 | − void render(); | |
| 88 | − | |
| 89 | − private: | |
| 90 | − void cleanupVBO(); | |
| 91 | − | |
| 92 | − GLuint _vertices; | |
| 93 | − GLuint _indices; | |
| 94 | − QOpenGLFramebufferObject* _framebufferObject; | |
| 95 | − VerticesIndices _vbo; | |
| 96 | − }; | |
| 97 | − | |
| 98 | − float _hmdUIAngularSize = DEFAULT_HMD_UI_ANGULAR_SIZE; | |
| 99 | − void renderReticle(glm::quat orientation, float alpha); | |
| 100 | − void renderPointers();; | |
| 101 | − void renderMagnifier(glm::vec2 magPos, float sizeMult, bool showBorder); | |
| 102 | − | |
| 103 | − void renderControllerPointers(); | |
| 104 | − void renderPointersOculus(); | |
| 105 | − | |
| 106 | − void renderAudioMeter(); | |
| 107 | − void renderCameraToggle(); | |
| 108 | − void renderStatsAndLogs(); | |
| 109 | − void renderDomainConnectionStatusBorder(); | |
| 110 | − void bindCursorTexture(gpu::Batch& batch, uint8_t cursorId = 0); | |
| 31 | + void renderStatsAndLogs(RenderArgs* renderArgs); | |
| 32 | + void renderDomainConnectionStatusBorder(RenderArgs* renderArgs); | |
| 33 | + void renderRearViewToFbo(RenderArgs* renderArgs); | |
| 34 | + void renderRearView(RenderArgs* renderArgs); | |
| 35 | + void renderQmlUi(RenderArgs* renderArgs); | |
| 36 | + void renderOverlays(RenderArgs* renderArgs); | |
| 37 | + void buildFramebufferObject(); | |
| 38 | + | |
| 39 | + float _alpha{ 1.0f }; | |
| 40 | + float _trailingAudioLoudness{ 0.0f }; | |
| 41 | + GLuint _uiTexture{ 0 }; | |
| 111 | 42 | |
| 112 | − TexturedHemisphere _overlays; | |
| 113 | − | |
| 114 | − float _textureFov; | |
| 115 | − float _textureAspectRatio; | |
| 116 | − | |
| 117 | − enum Reticles { MOUSE, LEFT_CONTROLLER, RIGHT_CONTROLLER, NUMBER_OF_RETICLES }; | |
| 118 | − bool _reticleActive[NUMBER_OF_RETICLES]; | |
| 119 | − QPoint _reticlePosition[NUMBER_OF_RETICLES]; | |
| 120 | − bool _magActive[NUMBER_OF_RETICLES]; | |
| 121 | − float _magSizeMult[NUMBER_OF_RETICLES]; | |
| 122 | − quint64 _lastMouseMove; | |
| 123 | − bool _magnifier; | |
| 124 | − | |
| 125 | − float _alpha = 1.0f; | |
| 126 | − float _oculusUIRadius; | |
| 127 | − float _trailingAudioLoudness; | |
| 128 | − | |
| 129 | − gpu::TexturePointer _crosshairTexture; | |
| 130 | − | |
| 131 | − | |
| 132 | − QMap<uint16_t, gpu::TexturePointer> _cursors; | |
| 133 | − | |
| 134 | − GLuint _newUiTexture{ 0 }; | |
| 135 | − | |
| 136 | − int _reticleQuad; | |
| 137 | − int _magnifierQuad; | |
| 138 | − int _audioRedQuad; | |
| 139 | − int _audioGreenQuad; | |
| 140 | − int _audioBlueQuad; | |
| 141 | 43 | int _domainStatusBorder; |
| 142 | 44 | int _magnifierBorder; |
| 143 | 45 | |
| 144 | − int _previousBorderWidth; | |
| 145 | − int _previousBorderHeight; | |
| 146 | − | |
| 147 | − glm::vec3 _previousMagnifierBottomLeft; | |
| 148 | − glm::vec3 _previousMagnifierBottomRight; | |
| 149 | − glm::vec3 _previousMagnifierTopLeft; | |
| 150 | − glm::vec3 _previousMagnifierTopRight; | |
| 151 | − | |
| 46 | + ivec2 _previousBorderSize{ -1 }; | |
| 47 | + QOpenGLFramebufferObject* _overlayFramebuffer{ nullptr }; | |
| 152 | 48 | }; |
| 153 | 49 | |
| 154 | 50 | #endif // hifi_ApplicationOverlay_h |
| @@ -0,0 +1,134 @@ | ||
| 1 | +// | |
| 2 | +// Created by Bradley Austin Davis 2015/06/19 | |
| 3 | +// Copyright 2013 High Fidelity, Inc. | |
| 4 | +// | |
| 5 | +// Distributed under the Apache License, Version 2.0. | |
| 6 | +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html | |
| 7 | +// | |
| 8 | + | |
| 9 | + | |
| 10 | +#include "Application.h" | |
| 11 | +#include "AvatarInputs.h" | |
| 12 | + | |
| 13 | +#include <SettingHandle.h> | |
| 14 | + | |
| 15 | +#include "Menu.h" | |
| 16 | +#include "devices/FaceTracker.h" | |
| 17 | + | |
| 18 | +HIFI_QML_DEF(AvatarInputs) | |
| 19 | + | |
| 20 | + | |
| 21 | +static AvatarInputs* INSTANCE{ nullptr }; | |
| 22 | +static const char SETTINGS_GROUP_NAME[] = "Rear View Tools"; | |
| 23 | +static const char ZOOM_LEVEL_SETTINGS[] = "ZoomLevel"; | |
| 24 | + | |
| 25 | +static Setting::Handle<int> rearViewZoomLevel(QStringList() << SETTINGS_GROUP_NAME << ZOOM_LEVEL_SETTINGS, 0); | |
| 26 | + | |
| 27 | +AvatarInputs* AvatarInputs::getInstance() { | |
| 28 | + if (!INSTANCE) { | |
| 29 | + AvatarInputs::registerType(); | |
| 30 | + AvatarInputs::show(); | |
| 31 | + Q_ASSERT(INSTANCE); | |
| 32 | + } | |
| 33 | + return INSTANCE; | |
| 34 | +} | |
| 35 | + | |
| 36 | +AvatarInputs::AvatarInputs(QQuickItem* parent) : QQuickItem(parent) { | |
| 37 | + INSTANCE = this; | |
| 38 | + int zoomSetting = rearViewZoomLevel.get(); | |
| 39 | + _mirrorZoomed = zoomSetting == 0; | |
| 40 | +} | |
| 41 | + | |
| 42 | +#define AI_UPDATE(name, src) \ | |
| 43 | + { \ | |
| 44 | + auto val = src; \ | |
| 45 | + if (_##name != val) { \ | |
| 46 | + _##name = val; \ | |
| 47 | + emit name##Changed(); \ | |
| 48 | + } \ | |
| 49 | + } | |
| 50 | + | |
| 51 | +#define AI_UPDATE_FLOAT(name, src, epsilon) \ | |
| 52 | + { \ | |
| 53 | + float val = src; \ | |
| 54 | + if (fabs(_##name - val) >= epsilon) { \ | |
| 55 | + _##name = val; \ | |
| 56 | + emit name##Changed(); \ | |
| 57 | + } \ | |
| 58 | + } | |
| 59 | + | |
| 60 | +void AvatarInputs::update() { | |
| 61 | + if (!Menu::getInstance()) { | |
| 62 | + return; | |
| 63 | + } | |
| 64 | + AI_UPDATE(mirrorVisible, Menu::getInstance()->isOptionChecked(MenuOption::Mirror) && !qApp->isHMDMode() | |
| 65 | + && !Menu::getInstance()->isOptionChecked(MenuOption::FullscreenMirror)); | |
| 66 | + AI_UPDATE(cameraEnabled, !Menu::getInstance()->isOptionChecked(MenuOption::NoFaceTracking)); | |
| 67 | + AI_UPDATE(cameraMuted, Menu::getInstance()->isOptionChecked(MenuOption::MuteFaceTracking)); | |
| 68 | + | |
| 69 | + auto audioIO = DependencyManager::get<AudioClient>(); | |
| 70 | + const float CLIPPING_INDICATOR_TIME = 1.0f; | |
| 71 | + const float AUDIO_METER_AVERAGING = 0.5; | |
| 72 | + const float LOG2 = log(2.0f); | |
| 73 | + const float METER_LOUDNESS_SCALE = 2.8f / 5.0f; | |
| 74 | + const float LOG2_LOUDNESS_FLOOR = 11.0f; | |
| 75 | + float audioLevel = 0.0f; | |
| 76 | + auto audio = DependencyManager::get<AudioClient>(); | |
| 77 | + float loudness = audio->getLastInputLoudness() + 1.0f; | |
| 78 | + | |
| 79 | + _trailingAudioLoudness = AUDIO_METER_AVERAGING * _trailingAudioLoudness + (1.0f - AUDIO_METER_AVERAGING) * loudness; | |
| 80 | + | |
| 81 | + float log2loudness = logf(_trailingAudioLoudness) / LOG2; | |
| 82 | + | |
| 83 | + if (log2loudness <= LOG2_LOUDNESS_FLOOR) { | |
| 84 | + audioLevel = (log2loudness / LOG2_LOUDNESS_FLOOR) * METER_LOUDNESS_SCALE; | |
| 85 | + } else { | |
| 86 | + audioLevel = (log2loudness - (LOG2_LOUDNESS_FLOOR - 1.0f)) * METER_LOUDNESS_SCALE; | |
| 87 | + } | |
| 88 | + if (audioLevel > 1.0) { | |
| 89 | + audioLevel = 1.0; | |
| 90 | + } | |
| 91 | + AI_UPDATE_FLOAT(audioLevel, audioLevel, 0.01); | |
| 92 | + AI_UPDATE(audioClipping, ((audioIO->getTimeSinceLastClip() > 0.0f) && (audioIO->getTimeSinceLastClip() < 1.0f))); | |
| 93 | + AI_UPDATE(audioMuted, audioIO->isMuted()); | |
| 94 | + | |
| 95 | + //// Make muted icon pulsate | |
| 96 | + //static const float PULSE_MIN = 0.4f; | |
| 97 | + //static const float PULSE_MAX = 1.0f; | |
| 98 | + //static const float PULSE_FREQUENCY = 1.0f; // in Hz | |
| 99 | + //qint64 now = usecTimestampNow(); | |
| 100 | + //if (now - _iconPulseTimeReference > (qint64)USECS_PER_SECOND) { | |
| 101 | + // // Prevents t from getting too big, which would diminish glm::cos precision | |
| 102 | + // _iconPulseTimeReference = now - ((now - _iconPulseTimeReference) % USECS_PER_SECOND); | |
| 103 | + //} | |
| 104 | + //float t = (float)(now - _iconPulseTimeReference) / (float)USECS_PER_SECOND; | |
| 105 | + //float pulseFactor = (glm::cos(t * PULSE_FREQUENCY * 2.0f * PI) + 1.0f) / 2.0f; | |
| 106 | + //iconColor = PULSE_MIN + (PULSE_MAX - PULSE_MIN) * pulseFactor; | |
| 107 | +} | |
| 108 | + | |
| 109 | +void AvatarInputs::toggleCameraMute() { | |
| 110 | + FaceTracker* faceTracker = Application::getInstance()->getSelectedFaceTracker(); | |
| 111 | + if (faceTracker) { | |
| 112 | + faceTracker->toggleMute(); | |
| 113 | + } | |
| 114 | +} | |
| 115 | + | |
| 116 | +void AvatarInputs::toggleAudioMute() { | |
| 117 | + DependencyManager::get<AudioClient>()->toggleMute(); | |
| 118 | +} | |
| 119 | + | |
| 120 | +void AvatarInputs::resetSensors() { | |
| 121 | + qApp->resetSensors(); | |
| 122 | +} | |
| 123 | + | |
| 124 | +void AvatarInputs::toggleZoom() { | |
| 125 | + _mirrorZoomed = !_mirrorZoomed; | |
| 126 | + rearViewZoomLevel.set(_mirrorZoomed ? 0 : 1); | |
| 127 | + emit mirrorZoomedChanged(); | |
| 128 | +} | |
| 129 | + | |
| 130 | +void AvatarInputs::closeMirror() { | |
| 131 | + if (Menu::getInstance()->isOptionChecked(MenuOption::Mirror)) { | |
| 132 | + Menu::getInstance()->triggerOption(MenuOption::Mirror); | |
| 133 | + } | |
| 134 | +} | |
| @@ -0,0 +1,59 @@ | ||
| 1 | +// | |
| 2 | +// Created by Bradley Austin Davis 2015/06/19 | |
| 3 | +// Copyright 2013 High Fidelity, Inc. | |
| 4 | +// | |
| 5 | +// Distributed under the Apache License, Version 2.0. | |
| 6 | +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html | |
| 7 | +// | |
| 8 | + | |
| 9 | +#ifndef hifi_AvatarInputs_h | |
| 10 | +#define hifi_AvatarInputs_h | |
| 11 | + | |
| 12 | +#include <QQuickItem> | |
| 13 | +#include <OffscreenUi.h> | |
| 14 | + | |
| 15 | +#define AI_PROPERTY(type, name, initialValue) \ | |
| 16 | + Q_PROPERTY(type name READ name NOTIFY name##Changed) \ | |
| 17 | +public: \ | |
| 18 | + type name() { return _##name; }; \ | |
| 19 | +private: \ | |
| 20 | + type _##name{ initialValue }; | |
| 21 | + | |
| 22 | +class AvatarInputs : public QQuickItem { | |
| 23 | + Q_OBJECT | |
| 24 | + HIFI_QML_DECL | |
| 25 | + | |
| 26 | + AI_PROPERTY(bool, cameraEnabled, false) | |
| 27 | + AI_PROPERTY(bool, cameraMuted, false) | |
| 28 | + AI_PROPERTY(bool, audioMuted, false) | |
| 29 | + AI_PROPERTY(bool, audioClipping, false) | |
| 30 | + AI_PROPERTY(float, audioLevel, 0) | |
| 31 | + AI_PROPERTY(bool, mirrorVisible, false) | |
| 32 | + AI_PROPERTY(bool, mirrorZoomed, true) | |
| 33 | + | |
| 34 | +public: | |
| 35 | + static AvatarInputs* getInstance(); | |
| 36 | + AvatarInputs(QQuickItem* parent = nullptr); | |
| 37 | + void update(); | |
| 38 | + | |
| 39 | +signals: | |
| 40 | + void cameraEnabledChanged(); | |
| 41 | + void cameraMutedChanged(); | |
| 42 | + void audioMutedChanged(); | |
| 43 | + void audioClippingChanged(); | |
| 44 | + void audioLevelChanged(); | |
| 45 | + void mirrorVisibleChanged(); | |
| 46 | + void mirrorZoomedChanged(); | |
| 47 | + | |
| 48 | +protected: | |
| 49 | + Q_INVOKABLE void resetSensors(); | |
| 50 | + Q_INVOKABLE void toggleCameraMute(); | |
| 51 | + Q_INVOKABLE void toggleAudioMute(); | |
| 52 | + Q_INVOKABLE void toggleZoom(); | |
| 53 | + Q_INVOKABLE void closeMirror(); | |
| 54 | + | |
| 55 | +private: | |
| 56 | + float _trailingAudioLoudness{ 0 }; | |
| 57 | +}; | |
| 58 | + | |
| 59 | +#endif // hifi_AvatarInputs_h | |
| @@ -38,8 +38,17 @@ · 37 unmodified lines | ||
| 38 | 38 | ** |
| 39 | 39 | ****************************************************************************/ |
| 40 | 40 | |
| 41 | +#ifdef __GNUC__ | |
| 42 | +#pragma GCC diagnostic push | |
| 43 | +#pragma GCC diagnostic ignored "-Wdouble-promotion" | |
| 44 | +#endif | |
| 45 | + | |
| 41 | 46 | #include <QtWidgets> |
| 42 | 47 | |
| 48 | +#ifdef __GNUC__ | |
| 49 | +#pragma GCC diagnostic pop | |
| 50 | +#endif | |
| 51 | + | |
| 43 | 52 | #include "FlowLayout.h" |
| 44 | 53 | //! [1] |
| 45 | 54 | FlowLayout::FlowLayout(QWidget *parent, int margin, int hSpacing, int vSpacing) |
| @@ -56,8 +56,6 @@ HMDToolsDialog::HMDToolsDialog(QWidget* parent) : · 55 unmodified lines | ||
| 56 | 56 | |
| 57 | 57 | this->QDialog::setLayout(form); |
| 58 | 58 | |
| 59 | − _wasMoved = false; | |
| 60 | − _previousRect = Application::getInstance()->getWindow()->rect(); | |
| 61 | 59 | Application::getInstance()->getWindow()->activateWindow(); |
| 62 | 60 | |
| 63 | 61 | // watch for our application window moving screens. If it does we want to update our screen details |
| @@ -136,24 +134,6 @@ void HMDToolsDialog::enterHDMMode() { · 72 unmodified lines | ||
| 136 | 134 | if (!_inHDMMode) { |
| 137 | 135 | _switchModeButton->setText("Leave HMD Mode"); |
| 138 | 136 | _debugDetails->setText(getDebugDetails()); |
| 139 | − | |
| 140 | − _hmdScreenNumber = OculusManager::getHMDScreen(); | |
| 141 | − | |
| 142 | − if (_hmdScreenNumber >= 0) { | |
| 143 | − QWindow* mainWindow = Application::getInstance()->getWindow()->windowHandle(); | |
| 144 | − _hmdScreen = QGuiApplication::screens()[_hmdScreenNumber]; | |
| 145 | − | |
| 146 | − _previousRect = Application::getInstance()->getWindow()->rect(); | |
| 147 | − _previousRect = QRect(mainWindow->mapToGlobal(_previousRect.topLeft()), | |
| 148 | − mainWindow->mapToGlobal(_previousRect.bottomRight())); | |
| 149 | − _previousScreen = mainWindow->screen(); | |
| 150 | − QRect rect = QApplication::desktop()->screenGeometry(_hmdScreenNumber); | |
| 151 | − mainWindow->setScreen(_hmdScreen); | |
| 152 | − mainWindow->setGeometry(rect); | |
| 153 | − | |
| 154 | − _wasMoved = true; | |
| 155 | − } | |
| 156 | − | |
| 157 | 137 | |
| 158 | 138 | // if we're on a single screen setup, then hide our tools window when entering HMD mode |
| 159 | 139 | if (QApplication::desktop()->screenCount() == 1) { |
| @@ -161,58 +141,21 @@ void HMDToolsDialog::enterHDMMode() { · 1 unmodified line | ||
| 161 | 141 | } |
| 162 | 142 | |
| 163 | 143 | Application::getInstance()->setEnableVRMode(true); |
| 164 | − | |
| 165 | − const int SLIGHT_DELAY = 500; | |
| 166 | − // If we go to fullscreen immediately, it ends up on the primary monitor, | |
| 167 | − // even though we've already moved the window. By adding this delay, the | |
| 168 | − // fullscreen target screen ends up correct. | |
| 169 | − QTimer::singleShot(SLIGHT_DELAY, this, [&]{ | |
| 170 | − Application::getInstance()->setFullscreen(true); | |
| 171 | − activateWindowAfterEnterMode(); | |
| 172 | − }); | |
| 173 | − | |
| 144 | + | |
| 174 | 145 | _inHDMMode = true; |
| 175 | 146 | } |
| 176 | 147 | } |
| 177 | 148 | |
| 178 | −void HMDToolsDialog::activateWindowAfterEnterMode() { | |
| 179 | − Application::getInstance()->getWindow()->activateWindow(); | |
| 180 | − | |
| 181 | − // center the cursor on the main application window | |
| 182 | − centerCursorOnWidget(Application::getInstance()->getWindow()); | |
| 183 | −} | |
| 184 | − | |
| 185 | 149 | void HMDToolsDialog::leaveHDMMode() { |
| 186 | 150 | if (_inHDMMode) { |
| 187 | 151 | _switchModeButton->setText("Enter HMD Mode"); |
| 188 | 152 | _debugDetails->setText(getDebugDetails()); |
| 189 | − | |
| 190 | 153 | Application::getInstance()->setEnableVRMode(false); |
| 191 | − Application::getInstance()->setFullscreen(false); | |
| 192 | 154 | Application::getInstance()->getWindow()->activateWindow(); |
| 193 | − | |
| 194 | − if (_wasMoved) { | |
| 195 | − QWindow* mainWindow = Application::getInstance()->getWindow()->windowHandle(); | |
| 196 | − mainWindow->setScreen(_previousScreen); | |
| 197 | − mainWindow->setGeometry(_previousRect); | |
| 198 | − | |
| 199 | − const int SLIGHT_DELAY = 1500; | |
| 200 | − QTimer::singleShot(SLIGHT_DELAY, this, SLOT(moveWindowAfterLeaveMode())); | |
| 201 | − } | |
| 202 | − _wasMoved = false; | |
| 203 | 155 | _inHDMMode = false; |
| 204 | 156 | } |
| 205 | 157 | } |
| 206 | 158 | |
| 207 | −void HMDToolsDialog::moveWindowAfterLeaveMode() { | |
| 208 | − QWindow* mainWindow = Application::getInstance()->getWindow()->windowHandle(); | |
| 209 | − mainWindow->setScreen(_previousScreen); | |
| 210 | − mainWindow->setGeometry(_previousRect); | |
| 211 | − Application::getInstance()->getWindow()->activateWindow(); | |
| 212 | − Application::getInstance()->resetSensors(); | |
| 213 | −} | |
| 214 | − | |
| 215 | − | |
| 216 | 159 | void HMDToolsDialog::reject() { |
| 217 | 160 | // Just regularly close upon ESC |
| 218 | 161 | close(); |
| @@ -244,13 +187,15 @@ void HMDToolsDialog::hideEvent(QHideEvent* event) { · 25 unmodified lines | ||
| 244 | 187 | |
| 245 | 188 | void HMDToolsDialog::aboutToQuit() { |
| 246 | 189 | if (_inHDMMode) { |
| 190 | + // FIXME this is ineffective because it doesn't trigger the menu to | |
| 191 | + // save the fact that VR Mode is not checked. | |
| 247 | 192 | leaveHDMMode(); |
| 248 | 193 | } |
| 249 | 194 | } |
| 250 | 195 | |
| 251 | 196 | void HMDToolsDialog::screenCountChanged(int newCount) { |
| 252 | 197 | if (!OculusManager::isConnected()) { |
| 253 | − OculusManager::connect(); | |
| 198 | + //OculusManager::connect(); | |
| 254 | 199 | } |
| 255 | 200 | int hmdScreenNumber = OculusManager::getHMDScreen(); |
| 256 | 201 | |
| @@ -35,8 +35,6 @@ signals: · 34 unmodified lines | ||
| 35 | 35 | public slots: |
| 36 | 36 | void reject(); |
| 37 | 37 | void switchModeClicked(bool checked); |
| 38 | − void activateWindowAfterEnterMode(); | |
| 39 | − void moveWindowAfterLeaveMode(); | |
| 40 | 38 | void applicationWindowScreenChanged(QScreen* screen); |
| 41 | 39 | void aboutToQuit(); |
| 42 | 40 | void screenCountChanged(int newCount); |
| @@ -51,8 +49,6 @@ private: · 8 unmodified lines | ||
| 51 | 49 | void enterHDMMode(); |
| 52 | 50 | void leaveHDMMode(); |
| 53 | 51 | |
| 54 | − bool _wasMoved; | |
| 55 | − QRect _previousRect; | |
| 56 | 52 | QScreen* _previousScreen; |
| 57 | 53 | QScreen* _hmdScreen; |
| 58 | 54 | int _hmdScreenNumber; |
| @@ -11,10 +11,19 @@ · 10 unmodified lines | ||
| 11 | 11 | |
| 12 | 12 | #include "InterfaceConfig.h" |
| 13 | 13 | |
| 14 | +#ifdef __GNUC__ | |
| 15 | +#pragma GCC diagnostic push | |
| 16 | +#pragma GCC diagnostic ignored "-Wdouble-promotion" | |
| 17 | +#endif | |
| 18 | + | |
| 14 | 19 | #include <QDesktopWidget> |
| 15 | 20 | #include <QTextBlock> |
| 16 | 21 | #include <QtGui> |
| 17 | 22 | |
| 23 | +#ifdef __GNUC__ | |
| 24 | +#pragma GCC diagnostic pop | |
| 25 | +#endif | |
| 26 | + | |
| 18 | 27 | #include <PathUtils.h> |
| 19 | 28 | #include <SharedUtil.h> |
| 20 | 29 | |
| @@ -175,7 +175,7 @@ void PreferencesDialog::loadPreferences() { · 174 unmodified lines | ||
| 175 | 175 | |
| 176 | 176 | ui.maxOctreePPSSpin->setValue(qApp->getMaxOctreePacketsPerSecond()); |
| 177 | 177 | |
| 178 | − ui.oculusUIAngularSizeSpin->setValue(qApp->getApplicationOverlay().getHmdUIAngularSize()); | |
| 178 | + ui.oculusUIAngularSizeSpin->setValue(qApp->getApplicationCompositor().getHmdUIAngularSize()); | |
| 179 | 179 | |
| 180 | 180 | SixenseManager& sixense = SixenseManager::getInstance(); |
| 181 | 181 | ui.sixenseReticleMoveSpeedSpin->setValue(sixense.getReticleMoveSpeed()); |
| @@ -239,7 +239,7 @@ void PreferencesDialog::savePreferences() { · 57 unmodified lines | ||
| 239 | 239 | |
| 240 | 240 | qApp->setMaxOctreePacketsPerSecond(ui.maxOctreePPSSpin->value()); |
| 241 | 241 | |
| 242 | − qApp->getApplicationOverlay().setHmdUIAngularSize(ui.oculusUIAngularSizeSpin->value()); | |
| 242 | + qApp->getApplicationCompositor().setHmdUIAngularSize(ui.oculusUIAngularSizeSpin->value()); | |
| 243 | 243 | |
| 244 | 244 | SixenseManager& sixense = SixenseManager::getInstance(); |
| 245 | 245 | sixense.setReticleMoveSpeed(ui.sixenseReticleMoveSpeedSpin->value()); |
| @@ -1,134 +0,0 @@ | ||
| 1 | −// | |
| 2 | −// RearMirrorTools.cpp | |
| 3 | −// interface/src/ui | |
| 4 | −// | |
| 5 | −// Created by Stojce Slavkovski on 10/23/2013. | |
| 6 | −// Copyright 2013 High Fidelity, Inc. | |
| 7 | −// | |
| 8 | −// Distributed under the Apache License, Version 2.0. | |
| 9 | −// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html | |
| 10 | −// | |
| 11 | − | |
| 12 | −#include "InterfaceConfig.h" | |
| 13 | − | |
| 14 | −#include <QMouseEvent> | |
| 15 | − | |
| 16 | −#include <PathUtils.h> | |
| 17 | −#include <SharedUtil.h> | |
| 18 | −#include <gpu/GLBackend.h> | |
| 19 | − | |
| 20 | −#include "Application.h" | |
| 21 | −#include "RearMirrorTools.h" | |
| 22 | −#include "Util.h" | |
| 23 | − | |
| 24 | −const int ICON_SIZE = 24; | |
| 25 | −const int ICON_PADDING = 5; | |
| 26 | − | |
| 27 | −const char SETTINGS_GROUP_NAME[] = "Rear View Tools"; | |
| 28 | −const char ZOOM_LEVEL_SETTINGS[] = "ZoomLevel"; | |
| 29 | −Setting::Handle<int> RearMirrorTools::rearViewZoomLevel(QStringList() << SETTINGS_GROUP_NAME << ZOOM_LEVEL_SETTINGS, | |
| 30 | − ZoomLevel::HEAD); | |
| 31 | − | |
| 32 | −RearMirrorTools::RearMirrorTools(QRect& bounds) : | |
| 33 | − _bounds(bounds), | |
| 34 | − _windowed(false), | |
| 35 | − _fullScreen(false) | |
| 36 | −{ | |
| 37 | − _closeTexture = TextureCache::getImageTexture(PathUtils::resourcesPath() + "images/close.svg"); | |
| 38 | − | |
| 39 | − _zoomHeadTexture = TextureCache::getImageTexture(PathUtils::resourcesPath() + "images/plus.svg"); | |
| 40 | − _zoomBodyTexture = TextureCache::getImageTexture(PathUtils::resourcesPath() + "images/minus.svg"); | |
| 41 | − | |
| 42 | − _shrinkIconRect = QRect(ICON_PADDING, ICON_PADDING, ICON_SIZE, ICON_SIZE); | |
| 43 | − _closeIconRect = QRect(_bounds.left() + ICON_PADDING, _bounds.top() + ICON_PADDING, ICON_SIZE, ICON_SIZE); | |
| 44 | − _resetIconRect = QRect(_bounds.width() - ICON_SIZE - ICON_PADDING, _bounds.top() + ICON_PADDING, ICON_SIZE, ICON_SIZE); | |
| 45 | − _bodyZoomIconRect = QRect(_bounds.width() - ICON_SIZE - ICON_PADDING, _bounds.bottom() - ICON_PADDING - ICON_SIZE, ICON_SIZE, ICON_SIZE); | |
| 46 | − _headZoomIconRect = QRect(_bounds.left() + ICON_PADDING, _bounds.bottom() - ICON_PADDING - ICON_SIZE, ICON_SIZE, ICON_SIZE); | |
| 47 | −} | |
| 48 | − | |
| 49 | −void RearMirrorTools::render(RenderArgs* renderArgs, bool fullScreen, const QPoint & mousePosition) { | |
| 50 | − if (fullScreen) { | |
| 51 | − _fullScreen = true; | |
| 52 | − displayIcon(QRect(QPoint(), qApp->getDeviceSize()), _shrinkIconRect, _closeTexture); | |
| 53 | − } else { | |
| 54 | − // render rear view tools if mouse is in the bounds | |
| 55 | − _windowed = _bounds.contains(mousePosition); | |
| 56 | − if (_windowed) { | |
| 57 | − displayIcon(_bounds, _closeIconRect, _closeTexture); | |
| 58 | − | |
| 59 | − ZoomLevel zoomLevel = (ZoomLevel)rearViewZoomLevel.get(); | |
| 60 | − displayIcon(_bounds, _headZoomIconRect, _zoomHeadTexture, zoomLevel == HEAD); | |
| 61 | − displayIcon(_bounds, _bodyZoomIconRect, _zoomBodyTexture, zoomLevel == BODY); | |
| 62 | − } | |
| 63 | − } | |
| 64 | −} | |
| 65 | − | |
| 66 | −bool RearMirrorTools::mousePressEvent(int x, int y) { | |
| 67 | − if (_windowed) { | |
| 68 | − if (_closeIconRect.contains(x, y)) { | |
| 69 | − _windowed = false; | |
| 70 | − emit closeView(); | |
| 71 | − return true; | |
| 72 | − } | |
| 73 | − | |
| 74 | − if (_headZoomIconRect.contains(x, y)) { | |
| 75 | − rearViewZoomLevel.set(HEAD); | |
| 76 | − return true; | |
| 77 | − } | |
| 78 | − | |
| 79 | − if (_bodyZoomIconRect.contains(x, y)) { | |
| 80 | − rearViewZoomLevel.set(BODY); | |
| 81 | − return true; | |
| 82 | − } | |
| 83 | − | |
| 84 | − if (_bounds.contains(x, y)) { | |
| 85 | − _windowed = false; | |
| 86 | − emit restoreView(); | |
| 87 | − return true; | |
| 88 | − } | |
| 89 | − } | |
| 90 | − | |
| 91 | − if (_fullScreen) { | |
| 92 | − if (_shrinkIconRect.contains(x, y)) { | |
| 93 | − _fullScreen = false; | |
| 94 | − emit shrinkView(); | |
| 95 | − return true; | |
| 96 | − } | |
| 97 | − } | |
| 98 | − return false; | |
| 99 | −} | |
| 100 | − | |
| 101 | −void RearMirrorTools::displayIcon(QRect bounds, QRect iconBounds, const gpu::TexturePointer& texture, bool selected) { | |
| 102 | − | |
| 103 | − glMatrixMode(GL_PROJECTION); | |
| 104 | − glPushMatrix(); | |
| 105 | − glLoadIdentity(); | |
| 106 | − | |
| 107 | − glOrtho(bounds.left(), bounds.right(), bounds.bottom(), bounds.top(), -1.0, 1.0); | |
| 108 | − glDisable(GL_DEPTH_TEST); | |
| 109 | − glDisable(GL_LIGHTING); | |
| 110 | − glEnable(GL_TEXTURE_2D); | |
| 111 | − | |
| 112 | − glm::vec4 quadColor; | |
| 113 | − if (selected) { | |
| 114 | − quadColor = glm::vec4(.5f, .5f, .5f, 1.0f); | |
| 115 | − } else { | |
| 116 | − quadColor = glm::vec4(1, 1, 1, 1); | |
| 117 | − } | |
| 118 | − | |
| 119 | − glBindTexture(GL_TEXTURE_2D, gpu::GLBackend::getTextureID(texture)); | |
| 120 | − | |
| 121 | − glm::vec2 topLeft(iconBounds.left(), iconBounds.top()); | |
| 122 | − glm::vec2 bottomRight(iconBounds.right(), iconBounds.bottom()); | |
| 123 | − static const glm::vec2 texCoordTopLeft(0.0f, 1.0f); | |
| 124 | − static const glm::vec2 texCoordBottomRight(1.0f, 0.0f); | |
| 125 | − | |
| 126 | − DependencyManager::get<GeometryCache>()->renderQuad(topLeft, bottomRight, texCoordTopLeft, texCoordBottomRight, quadColor); | |
| 127 | − | |
| 128 | − glPopMatrix(); | |
| 129 | − | |
| 130 | − glMatrixMode(GL_MODELVIEW); | |
| 131 | − | |
| 132 | − glBindTexture(GL_TEXTURE_2D, 0); | |
| 133 | − glDisable(GL_TEXTURE_2D); | |
| 134 | −} | |
| @@ -1,56 +0,0 @@ | ||
| 1 | −// | |
| 2 | −// RearMirrorTools.h | |
| 3 | −// interface/src/ui | |
| 4 | −// | |
| 5 | −// Created by Stojce Slavkovski on 10/23/2013. | |
| 6 | −// Copyright 2013 High Fidelity, Inc. | |
| 7 | −// | |
| 8 | −// Distributed under the Apache License, Version 2.0. | |
| 9 | −// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html | |
| 10 | −// | |
| 11 | − | |
| 12 | −#ifndef hifi_RearMirrorTools_h | |
| 13 | −#define hifi_RearMirrorTools_h | |
| 14 | − | |
| 15 | −#include <gpu/Texture.h> | |
| 16 | −#include <SettingHandle.h> | |
| 17 | − | |
| 18 | −enum ZoomLevel { | |
| 19 | − HEAD = 0, | |
| 20 | − BODY = 1 | |
| 21 | −}; | |
| 22 | − | |
| 23 | −class RearMirrorTools : public QObject { | |
| 24 | − Q_OBJECT | |
| 25 | −public: | |
| 26 | − RearMirrorTools(QRect& bounds); | |
| 27 | − void render(RenderArgs* renderArgs, bool fullScreen, const QPoint & mousePos); | |
| 28 | − bool mousePressEvent(int x, int y); | |
| 29 | − | |
| 30 | − static Setting::Handle<int> rearViewZoomLevel; | |
| 31 | − | |
| 32 | −signals: | |
| 33 | − void closeView(); | |
| 34 | − void shrinkView(); | |
| 35 | − void resetView(); | |
| 36 | − void restoreView(); | |
| 37 | − | |
| 38 | −private: | |
| 39 | − QRect _bounds; | |
| 40 | − gpu::TexturePointer _closeTexture; | |
| 41 | − gpu::TexturePointer _zoomBodyTexture; | |
| 42 | − gpu::TexturePointer _zoomHeadTexture; | |
| 43 | − | |
| 44 | − QRect _closeIconRect; | |
| 45 | − QRect _resetIconRect; | |
| 46 | − QRect _shrinkIconRect; | |
| 47 | − QRect _headZoomIconRect; | |
| 48 | − QRect _bodyZoomIconRect; | |
| 49 | − | |
| 50 | − bool _windowed; | |
| 51 | − bool _fullScreen; | |
| 52 | − | |
| 53 | − void displayIcon(QRect bounds, QRect iconBounds, const gpu::TexturePointer& texture, bool selected = false); | |
| 54 | −}; | |
| 55 | − | |
| 56 | −#endif // hifi_RearMirrorTools_h | |
| @@ -1,17 +1,17 @@ | ||
| 1 | 1 | // |
| 2 | −// Stats.cpp | |
| 3 | −// interface/src/ui | |
| 4 | −// | |
| 5 | −// Created by Lucas Crisman on 22/03/14. | |
| 2 | +// Created by Bradley Austin Davis 2015/06/17 | |
| 6 | 3 | // Copyright 2013 High Fidelity, Inc. |
| 7 | 4 | // |
| 8 | 5 | // Distributed under the Apache License, Version 2.0. |
| 9 | 6 | // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html |
| 10 | 7 | // |
| 11 | 8 | |
| 12 | −#include <sstream> | |
| 9 | +#include <gpu/GPUConfig.h> | |
| 13 | 10 | |
| 14 | −#include <stdlib.h> | |
| 11 | +#include "Stats.h" | |
| 12 | + | |
| 13 | +#include <sstream> | |
| 14 | +#include <QFontDatabase> | |
| 15 | 15 | |
| 16 | 16 | #include <glm/glm.hpp> |
| 17 | 17 | #include <glm/gtx/component_wise.hpp> |
| @@ -25,147 +25,31 @@ · 7 unmodified lines | ||
| 25 | 25 | #include <LODManager.h> |
| 26 | 26 | #include <PerfStat.h> |
| 27 | 27 | |
| 28 | −#include "Stats.h" | |
| 29 | 28 | #include "BandwidthRecorder.h" |
| 30 | 29 | #include "InterfaceConfig.h" |
| 31 | 30 | #include "Menu.h" |
| 32 | 31 | #include "Util.h" |
| 33 | 32 | #include "SequenceNumberStats.h" |
| 34 | 33 | |
| 35 | −using namespace std; | |
| 34 | +HIFI_QML_DEF(Stats) | |
| 36 | 35 | |
| 37 | −const int STATS_PELS_PER_LINE = 16; | |
| 38 | −const int STATS_PELS_INITIALOFFSET = 12; | |
| 36 | +using namespace std; | |
| 39 | 37 | |
| 40 | −const int STATS_GENERAL_MIN_WIDTH = 165; | |
| 41 | −const int STATS_PING_MIN_WIDTH = 190; | |
| 42 | −const int STATS_GEO_MIN_WIDTH = 240; | |
| 43 | −const int STATS_OCTREE_MIN_WIDTH = 410; | |
| 38 | +static Stats* INSTANCE{ nullptr }; | |
| 44 | 39 | |
| 45 | 40 | Stats* Stats::getInstance() { |
| 46 | − static Stats stats; | |
| 47 | − return &stats; | |
| 48 | −} | |
| 49 | − | |
| 50 | −Stats::Stats(): | |
| 51 | − _expanded(false), | |
| 52 | − _recentMaxPackets(0), | |
| 53 | − _resetRecentMaxPacketsSoon(true), | |
| 54 | − _generalStatsWidth(STATS_GENERAL_MIN_WIDTH), | |
| 55 | − _pingStatsWidth(STATS_PING_MIN_WIDTH), | |
| 56 | − _geoStatsWidth(STATS_GEO_MIN_WIDTH), | |
| 57 | − _octreeStatsWidth(STATS_OCTREE_MIN_WIDTH), | |
| 58 | − _lastHorizontalOffset(0) | |
| 59 | −{ | |
| 60 | − auto canvasSize = Application::getInstance()->getCanvasSize(); | |
| 61 | − resetWidth(canvasSize.x, 0); | |
| 62 | −} | |
| 63 | − | |
| 64 | −void Stats::toggleExpanded() { | |
| 65 | − _expanded = !_expanded; | |
| 66 | −} | |
| 67 | − | |
| 68 | −// called on mouse click release | |
| 69 | −// check for clicks over stats in order to expand or contract them | |
| 70 | −void Stats::checkClick(int mouseX, int mouseY, int mouseDragStartedX, int mouseDragStartedY, int horizontalOffset) { | |
| 71 | − auto canvasSize = Application::getInstance()->getCanvasSize(); | |
| 72 | − | |
| 73 | − if (0 != glm::compMax(glm::abs(glm::ivec2(mouseX - mouseDragStartedX, mouseY - mouseDragStartedY)))) { | |
| 74 | − // not worried about dragging on stats | |
| 75 | − return; | |
| 76 | − } | |
| 77 | − | |
| 78 | − int statsHeight = 0, | |
| 79 | − statsWidth = 0, | |
| 80 | − statsX = 0, | |
| 81 | − statsY = 0, | |
| 82 | − lines = 0; | |
| 83 | − | |
| 84 | − statsX = horizontalOffset; | |
| 85 | − | |
| 86 | − // top-left stats click | |
| 87 | − lines = _expanded ? 5 : 3; | |
| 88 | − statsHeight = lines * STATS_PELS_PER_LINE + 10; | |
| 89 | − if (mouseX > statsX && mouseX < statsX + _generalStatsWidth && mouseY > statsY && mouseY < statsY + statsHeight) { | |
| 90 | − toggleExpanded(); | |
| 91 | − return; | |
| 92 | − } | |
| 93 | − statsX += _generalStatsWidth; | |
| 94 | − | |
| 95 | − // ping stats click | |
| 96 | − if (Menu::getInstance()->isOptionChecked(MenuOption::TestPing)) { | |
| 97 | − lines = _expanded ? 4 : 3; | |
| 98 | − statsHeight = lines * STATS_PELS_PER_LINE + 10; | |
| 99 | − if (mouseX > statsX && mouseX < statsX + _pingStatsWidth && mouseY > statsY && mouseY < statsY + statsHeight) { | |
| 100 | − toggleExpanded(); | |
| 101 | − return; | |
| 102 | − } | |
| 103 | − statsX += _pingStatsWidth; | |
| 104 | − } | |
| 105 | − | |
| 106 | − // geo stats panel click | |
| 107 | − lines = _expanded ? 4 : 3; | |
| 108 | − statsHeight = lines * STATS_PELS_PER_LINE + 10; | |
| 109 | − if (mouseX > statsX && mouseX < statsX + _geoStatsWidth && mouseY > statsY && mouseY < statsY + statsHeight) { | |
| 110 | − toggleExpanded(); | |
| 111 | − return; | |
| 112 | − } | |
| 113 | − statsX += _geoStatsWidth; | |
| 114 | − | |
| 115 | − // top-right stats click | |
| 116 | − lines = _expanded ? 11 : 3; | |
| 117 | − statsHeight = lines * STATS_PELS_PER_LINE + 10; | |
| 118 | − statsWidth = canvasSize.x - statsX; | |
| 119 | − if (mouseX > statsX && mouseX < statsX + statsWidth && mouseY > statsY && mouseY < statsY + statsHeight) { | |
| 120 | − toggleExpanded(); | |
| 121 | − return; | |
| 122 | − } | |
| 123 | −} | |
| 124 | − | |
| 125 | −void Stats::resetWidth(int width, int horizontalOffset) { | |
| 126 | − auto canvasSize = Application::getInstance()->getCanvasSize(); | |
| 127 | − int extraSpace = canvasSize.x - horizontalOffset - 2 | |
| 128 | − - STATS_GENERAL_MIN_WIDTH | |
| 129 | − - (Menu::getInstance()->isOptionChecked(MenuOption::TestPing) ? STATS_PING_MIN_WIDTH -1 : 0) | |
| 130 | − - STATS_GEO_MIN_WIDTH | |
| 131 | − - STATS_OCTREE_MIN_WIDTH; | |
| 132 | − | |
| 133 | − int panels = 4; | |
| 134 | − | |
| 135 | − _generalStatsWidth = STATS_GENERAL_MIN_WIDTH; | |
| 136 | − if (Menu::getInstance()->isOptionChecked(MenuOption::TestPing)) { | |
| 137 | − _pingStatsWidth = STATS_PING_MIN_WIDTH; | |
| 138 | − } else { | |
| 139 | − _pingStatsWidth = 0; | |
| 140 | − panels = 3; | |
| 141 | − } | |
| 142 | − _geoStatsWidth = STATS_GEO_MIN_WIDTH; | |
| 143 | − _octreeStatsWidth = STATS_OCTREE_MIN_WIDTH; | |
| 144 | − | |
| 145 | − if (extraSpace > panels) { | |
| 146 | − _generalStatsWidth += (int) extraSpace / panels; | |
| 147 | − if (Menu::getInstance()->isOptionChecked(MenuOption::TestPing)) { | |
| 148 | − _pingStatsWidth += (int) extraSpace / panels; | |
| 149 | − } | |
| 150 | − _geoStatsWidth += (int) extraSpace / panels; | |
| 151 | − _octreeStatsWidth += canvasSize.x - | |
| 152 | − (_generalStatsWidth + _pingStatsWidth + _geoStatsWidth + 3); | |
| 41 | + if (!INSTANCE) { | |
| 42 | + Stats::registerType(); | |
| 43 | + Stats::show(); | |
| 44 | + Q_ASSERT(INSTANCE); | |
| 153 | 45 | } |
| 46 | + return INSTANCE; | |
| 154 | 47 | } |
| 155 | 48 | |
| 156 | − | |
| 157 | −// translucent background box that makes stats more readable | |
| 158 | −void Stats::drawBackground(unsigned int rgba, int x, int y, int width, int height) { | |
| 159 | − glm::vec4 color(((rgba >> 24) & 0xff) / 255.0f, | |
| 160 | − ((rgba >> 16) & 0xff) / 255.0f, | |
| 161 | − ((rgba >> 8) & 0xff) / 255.0f, | |
| 162 | − (rgba & 0xff) / 255.0f); | |
| 163 | − | |
| 164 | − // FIX ME: is this correct? It seems to work to fix textures bleeding into us... | |
| 165 | − glBindTexture(GL_TEXTURE_2D, 0); | |
| 166 | − glDisable(GL_TEXTURE_2D); | |
| 167 | − | |
| 168 | − DependencyManager::get<GeometryCache>()->renderQuad(x, y, width, height, color); | |
| 49 | +Stats::Stats(QQuickItem* parent) : QQuickItem(parent) { | |
| 50 | + INSTANCE = this; | |
| 51 | + const QFont font = QFontDatabase::systemFont(QFontDatabase::FixedFont); | |
| 52 | + _monospaceFont = font.family(); | |
| 169 | 53 | } |
| 170 | 54 | |
| 171 | 55 | bool Stats::includeTimingRecord(const QString& name) { |
| @@ -190,161 +74,70 @@ bool Stats::includeTimingRecord(const QString& name) { · 18 unmodified lines | ||
| 190 | 74 | return false; |
| 191 | 75 | } |
| 192 | 76 | |
| 193 | −// display expanded or contracted stats | |
| 194 | −void Stats::display( | |
| 195 | − const float* color, | |
| 196 | − int horizontalOffset, | |
| 197 | − float fps, | |
| 198 | − int inPacketsPerSecond, | |
| 199 | − int outPacketsPerSecond, | |
| 200 | − int inKbitsPerSecond, | |
| 201 | − int outKbitsPerSecond, | |
| 202 | − int voxelPacketsToProcess) | |
| 203 | −{ | |
| 204 | − auto canvasSize = Application::getInstance()->getCanvasSize(); | |
| 205 | − | |
| 206 | − unsigned int backgroundColor = 0x33333399; | |
| 207 | − int verticalOffset = 0, lines = 0; | |
| 208 | − float scale = 0.10f; | |
| 209 | − float rotation = 0.0f; | |
| 210 | − int font = 2; | |
| 211 | − | |
| 212 | − QLocale locale(QLocale::English); | |
| 213 | − std::stringstream octreeStats; | |
| 214 | − | |
| 215 | − QSharedPointer<BandwidthRecorder> bandwidthRecorder = DependencyManager::get<BandwidthRecorder>(); | |
| 216 | − | |
| 217 | − if (_lastHorizontalOffset != horizontalOffset) { | |
| 218 | − resetWidth(canvasSize.x, horizontalOffset); | |
| 219 | − _lastHorizontalOffset = horizontalOffset; | |
| 77 | +#define STAT_UPDATE(name, src) \ | |
| 78 | + { \ | |
| 79 | + auto val = src; \ | |
| 80 | + if (_##name != val) { \ | |
| 81 | + _##name = val; \ | |
| 82 | + emit name##Changed(); \ | |
| 83 | + } \ | |
| 220 | 84 | } |
| 221 | 85 | |
| 222 | − glPointSize(1.0f); | |
| 223 | − | |
| 224 | − // we need to take one avatar out so we don't include ourselves | |
| 225 | − int totalAvatars = DependencyManager::get<AvatarManager>()->size() - 1; | |
| 226 | − int totalServers = DependencyManager::get<NodeList>()->size(); | |
| 227 | − | |
| 228 | − lines = 5; | |
| 229 | − int columnOneWidth = _generalStatsWidth; | |
| 230 | − | |
| 231 | − bool performanceTimerIsActive = PerformanceTimer::isActive(); | |
| 232 | − bool displayPerf = _expanded && Menu::getInstance()->isOptionChecked(MenuOption::DisplayDebugTimingDetails); | |
| 233 | − if (displayPerf && performanceTimerIsActive) { | |
| 234 | − PerformanceTimer::tallyAllTimerRecords(); // do this even if we're not displaying them, so they don't stack up | |
| 235 | − | |
| 236 | − columnOneWidth = _generalStatsWidth + _pingStatsWidth + _geoStatsWidth; // 3 columns wide... | |
| 237 | − // we will also include room for 1 line per timing record and a header of 4 lines | |
| 238 | − lines += 4; | |
| 239 | − | |
| 240 | − const QMap<QString, PerformanceTimerRecord>& allRecords = PerformanceTimer::getAllTimerRecords(); | |
| 241 | − QMapIterator<QString, PerformanceTimerRecord> i(allRecords); | |
| 242 | − bool onlyDisplayTopTen = Menu::getInstance()->isOptionChecked(MenuOption::OnlyDisplayTopTen); | |
| 243 | − int statsLines = 0; | |
| 244 | − while (i.hasNext()) { | |
| 245 | − i.next(); | |
| 246 | − if (includeTimingRecord(i.key())) { | |
| 247 | − lines++; | |
| 248 | − statsLines++; | |
| 249 | − if (onlyDisplayTopTen && statsLines == 10) { | |
| 250 | − break; | |
| 251 | − } | |
| 252 | − } | |
| 253 | − } | |
| 86 | +#define STAT_UPDATE_FLOAT(name, src, epsilon) \ | |
| 87 | + { \ | |
| 88 | + float val = src; \ | |
| 89 | + if (fabs(_##name - val) >= epsilon) { \ | |
| 90 | + _##name = val; \ | |
| 91 | + emit name##Changed(); \ | |
| 92 | + } \ | |
| 254 | 93 | } |
| 255 | − | |
| 256 | − drawBackground(backgroundColor, horizontalOffset, 0, columnOneWidth, (lines + 1) * STATS_PELS_PER_LINE); | |
| 257 | − horizontalOffset += 5; | |
| 258 | − | |
| 259 | − int columnOneHorizontalOffset = horizontalOffset; | |
| 260 | − | |
| 261 | − QString serverNodes = QString("Servers: %1").arg(totalServers); | |
| 262 | − QString avatarNodes = QString("Avatars: %1").arg(totalAvatars); | |
| 263 | − QString framesPerSecond = QString("Framerate: %1 FPS").arg(fps, 3, 'f', 0); | |
| 264 | − | |
| 265 | − verticalOffset = STATS_PELS_INITIALOFFSET; // first one is offset by less than a line | |
| 266 | − drawText(horizontalOffset, verticalOffset, scale, rotation, font, serverNodes.toUtf8().constData(), color); | |
| 267 | − verticalOffset += STATS_PELS_PER_LINE; | |
| 268 | − drawText(horizontalOffset, verticalOffset, scale, rotation, font, avatarNodes.toUtf8().constData(), color); | |
| 269 | − verticalOffset += STATS_PELS_PER_LINE; | |
| 270 | − drawText(horizontalOffset, verticalOffset, scale, rotation, font, framesPerSecond.toUtf8().constData(), color); | |
| 271 | − | |
| 272 | − QString packetsPerSecondString = QString("Packets In/Out: %1/%2").arg(inPacketsPerSecond).arg(outPacketsPerSecond); | |
| 273 | − QString averageMegabitsPerSecond = QString("Mbps In/Out: %1/%2"). | |
| 274 | − arg((float)inKbitsPerSecond * 1.0f / 1000.0f). | |
| 275 | − arg((float)outKbitsPerSecond * 1.0f / 1000.0f); | |
| 276 | − | |
| 277 | − verticalOffset += STATS_PELS_PER_LINE; | |
| 278 | − drawText(horizontalOffset, verticalOffset, scale, rotation, font, packetsPerSecondString.toUtf8().constData(), color); | |
| 279 | − verticalOffset += STATS_PELS_PER_LINE; | |
| 280 | − drawText(horizontalOffset, verticalOffset, scale, rotation, font, averageMegabitsPerSecond.toUtf8().constData(), color); | |
| 281 | 94 | |
| 282 | − | |
| 283 | − // TODO: the display of these timing details should all be moved to JavaScript | |
| 284 | − if (displayPerf && performanceTimerIsActive) { | |
| 285 | − bool onlyDisplayTopTen = Menu::getInstance()->isOptionChecked(MenuOption::OnlyDisplayTopTen); | |
| 286 | − // Timing details... | |
| 287 | − verticalOffset += STATS_PELS_PER_LINE * 4; // skip 3 lines to be under the other columns | |
| 288 | − drawText(columnOneHorizontalOffset, verticalOffset, scale, rotation, font, | |
| 289 | − "-------------------------------------------------------- Function " | |
| 290 | − "------------------------------------------------------- --msecs- -calls--", color); | |
| 291 | − | |
| 292 | − // First iterate all the records, and for the ones that should be included, insert them into | |
| 293 | − // a new Map sorted by average time... | |
| 294 | − QMap<float, QString> sortedRecords; | |
| 295 | − const QMap<QString, PerformanceTimerRecord>& allRecords = PerformanceTimer::getAllTimerRecords(); | |
| 296 | − QMapIterator<QString, PerformanceTimerRecord> i(allRecords); | |
| 297 | 95 | |
| 298 | − while (i.hasNext()) { | |
| 299 | − i.next(); | |
| 300 | − if (includeTimingRecord(i.key())) { | |
| 301 | − float averageTime = (float)i.value().getMovingAverage() / (float)USECS_PER_MSEC; | |
| 302 | − sortedRecords.insertMulti(averageTime, i.key()); | |
| 303 | − } | |
| 96 | +void Stats::updateStats() { | |
| 97 | + if (!Menu::getInstance()->isOptionChecked(MenuOption::Stats)) { | |
| 98 | + if (isVisible()) { | |
| 99 | + setVisible(false); | |
| 304 | 100 | } |
| 305 | − | |
| 306 | − int linesDisplayed = 0; | |
| 307 | − QMapIterator<float, QString> j(sortedRecords); | |
| 308 | − j.toBack(); | |
| 309 | − while (j.hasPrevious()) { | |
| 310 | − j.previous(); | |
| 311 | − QChar noBreakingSpace = QChar::Nbsp; | |
| 312 | − QString functionName = j.value(); | |
| 313 | − const PerformanceTimerRecord& record = allRecords.value(functionName); | |
| 314 | − | |
| 315 | − QString perfLine = QString("%1: %2 [%3]"). | |
| 316 | − arg(QString(qPrintable(functionName)), 120, noBreakingSpace). | |
| 317 | − arg((float)record.getMovingAverage() / (float)USECS_PER_MSEC, 8, 'f', 3, noBreakingSpace). | |
| 318 | − arg((int)record.getCount(), 6, 10, noBreakingSpace); | |
| 319 | − | |
| 320 | − verticalOffset += STATS_PELS_PER_LINE; | |
| 321 | − drawText(columnOneHorizontalOffset, verticalOffset, scale, rotation, font, perfLine.toUtf8().constData(), color); | |
| 322 | − linesDisplayed++; | |
| 323 | − if (onlyDisplayTopTen && linesDisplayed == 10) { | |
| 324 | − break; | |
| 325 | − } | |
| 101 | + return; | |
| 102 | + } else { | |
| 103 | + if (!isVisible()) { | |
| 104 | + setVisible(true); | |
| 326 | 105 | } |
| 327 | 106 | } |
| 328 | 107 | |
| 108 | + bool shouldDisplayTimingDetail = Menu::getInstance()->isOptionChecked(MenuOption::DisplayDebugTimingDetails) && | |
| 109 | + Menu::getInstance()->isOptionChecked(MenuOption::Stats) && isExpanded(); | |
| 110 | + if (shouldDisplayTimingDetail != PerformanceTimer::isActive()) { | |
| 111 | + PerformanceTimer::setActive(shouldDisplayTimingDetail); | |
| 112 | + } | |
| 329 | 113 | |
| 330 | − verticalOffset = STATS_PELS_INITIALOFFSET; | |
| 331 | − horizontalOffset = _lastHorizontalOffset + _generalStatsWidth + 1; | |
| 332 | 114 | |
| 333 | − if (Menu::getInstance()->isOptionChecked(MenuOption::TestPing)) { | |
| 334 | − int pingAudio = -1, pingAvatar = -1, pingVoxel = -1, pingOctreeMax = -1; | |
| 115 | + auto nodeList = DependencyManager::get<NodeList>(); | |
| 116 | + auto avatarManager = DependencyManager::get<AvatarManager>(); | |
| 117 | + // we need to take one avatar out so we don't include ourselves | |
| 118 | + STAT_UPDATE(avatarCount, avatarManager->size() - 1); | |
| 119 | + STAT_UPDATE(serverCount, nodeList->size()); | |
| 120 | + STAT_UPDATE(framerate, (int)qApp->getFps()); | |
| 121 | + | |
| 122 | + auto bandwidthRecorder = DependencyManager::get<BandwidthRecorder>(); | |
| 123 | + STAT_UPDATE(packetInCount, bandwidthRecorder->getCachedTotalAverageInputPacketsPerSecond()); | |
| 124 | + STAT_UPDATE(packetOutCount, bandwidthRecorder->getCachedTotalAverageOutputPacketsPerSecond()); | |
| 125 | + STAT_UPDATE_FLOAT(mbpsIn, (float)bandwidthRecorder->getCachedTotalAverageOutputKilobitsPerSecond() / 1000.0f, 0.01f); | |
| 126 | + STAT_UPDATE_FLOAT(mbpsOut, (float)bandwidthRecorder->getCachedTotalAverageInputKilobitsPerSecond() / 1000.0f, 0.01f); | |
| 335 | 127 | |
| 336 | − auto nodeList = DependencyManager::get<NodeList>(); | |
| 128 | + // Second column: ping | |
| 129 | + if (Menu::getInstance()->isOptionChecked(MenuOption::TestPing)) { | |
| 337 | 130 | SharedNodePointer audioMixerNode = nodeList->soloNodeOfType(NodeType::AudioMixer); |
| 338 | 131 | SharedNodePointer avatarMixerNode = nodeList->soloNodeOfType(NodeType::AvatarMixer); |
| 132 | + STAT_UPDATE(audioPing, audioMixerNode ? audioMixerNode->getPingMs() : -1); | |
| 133 | + STAT_UPDATE(avatarPing, avatarMixerNode ? avatarMixerNode->getPingMs() : -1); | |
| 339 | 134 | |
| 340 | − pingAudio = audioMixerNode ? audioMixerNode->getPingMs() : -1; | |
| 341 | − pingAvatar = avatarMixerNode ? avatarMixerNode->getPingMs() : -1; | |
| 342 | − | |
| 343 | − // Now handle voxel servers, since there could be more than one, we average their ping times | |
| 135 | + //// Now handle voxel servers, since there could be more than one, we average their ping times | |
| 344 | 136 | unsigned long totalPingOctree = 0; |
| 345 | 137 | int octreeServerCount = 0; |
| 346 | − | |
| 347 | − nodeList->eachNode([&totalPingOctree, &pingOctreeMax, &octreeServerCount](const SharedNodePointer& node){ | |
| 138 | + int pingOctreeMax = 0; | |
| 139 | + int pingVoxel; | |
| 140 | + nodeList->eachNode([&](const SharedNodePointer& node) { | |
| 348 | 141 | // TODO: this should also support entities |
| 349 | 142 | if (node->getType() == NodeType::EntityServer) { |
| 350 | 143 | totalPingOctree += node->getPingMs(); |
| @@ -359,168 +152,85 @@ void Stats::display( · 8 unmodified lines | ||
| 359 | 152 | pingVoxel = totalPingOctree / octreeServerCount; |
| 360 | 153 | } |
| 361 | 154 | |
| 362 | − lines = _expanded ? 4 : 3; | |
| 363 | − | |
| 364 | − // only draw our background if column one didn't draw a wide background | |
| 365 | − if (columnOneWidth == _generalStatsWidth) { | |
| 366 | − drawBackground(backgroundColor, horizontalOffset, 0, _pingStatsWidth, (lines + 1) * STATS_PELS_PER_LINE); | |
| 367 | − } | |
| 368 | − horizontalOffset += 5; | |
| 369 | − | |
| 370 | − | |
| 371 | − QString audioPing; | |
| 372 | − if (pingAudio >= 0) { | |
| 373 | − audioPing = QString("Audio ping: %1").arg(pingAudio); | |
| 374 | − } else { | |
| 375 | − audioPing = QString("Audio ping: --"); | |
| 376 | − } | |
| 377 | − | |
| 378 | − QString avatarPing; | |
| 379 | − if (pingAvatar >= 0) { | |
| 380 | − avatarPing = QString("Avatar ping: %1").arg(pingAvatar); | |
| 381 | − } else { | |
| 382 | − avatarPing = QString("Avatar ping: --"); | |
| 383 | − } | |
| 384 | − | |
| 385 | − QString voxelAvgPing; | |
| 386 | − if (pingVoxel >= 0) { | |
| 387 | − voxelAvgPing = QString("Entities avg ping: %1").arg(pingVoxel); | |
| 388 | − } else { | |
| 389 | − voxelAvgPing = QString("Entities avg ping: --"); | |
| 390 | − } | |
| 391 | − | |
| 392 | − drawText(horizontalOffset, verticalOffset, scale, rotation, font, audioPing.toUtf8().constData(), color); | |
| 393 | − verticalOffset += STATS_PELS_PER_LINE; | |
| 394 | − drawText(horizontalOffset, verticalOffset, scale, rotation, font, avatarPing.toUtf8().constData(), color); | |
| 395 | − verticalOffset += STATS_PELS_PER_LINE; | |
| 396 | − drawText(horizontalOffset, verticalOffset, scale, rotation, font, voxelAvgPing.toUtf8().constData(), color); | |
| 397 | − | |
| 398 | − if (_expanded) { | |
| 399 | − QString voxelMaxPing; | |
| 400 | − if (pingVoxel >= 0) { // Average is only meaningful if pingVoxel is valid. | |
| 401 | − voxelMaxPing = QString("Voxel max ping: %1").arg(pingOctreeMax); | |
| 402 | − } else { | |
| 403 | − voxelMaxPing = QString("Voxel max ping: --"); | |
| 404 | − } | |
| 405 | − | |
| 406 | − verticalOffset += STATS_PELS_PER_LINE; | |
| 407 | − drawText(horizontalOffset, verticalOffset, scale, rotation, font, voxelMaxPing.toUtf8().constData(), color); | |
| 408 | − } | |
| 409 | − | |
| 410 | − verticalOffset = STATS_PELS_INITIALOFFSET; | |
| 411 | − horizontalOffset = _lastHorizontalOffset + _generalStatsWidth + _pingStatsWidth + 2; | |
| 155 | + //STAT_UPDATE(entitiesPing, pingVoxel); | |
| 156 | + //if (_expanded) { | |
| 157 | + // QString voxelMaxPing; | |
| 158 | + // if (pingVoxel >= 0) { // Average is only meaningful if pingVoxel is valid. | |
| 159 | + // voxelMaxPing = QString("Voxel max ping: %1").arg(pingOctreeMax); | |
| 160 | + // } else { | |
| 161 | + // voxelMaxPing = QString("Voxel max ping: --"); | |
| 162 | + // } | |
| 163 | + } else { | |
| 164 | + // -2 causes the QML to hide the ping column | |
| 165 | + STAT_UPDATE(audioPing, -2); | |
| 412 | 166 | } |
| 413 | 167 | |
| 414 | − MyAvatar* myAvatar = DependencyManager::get<AvatarManager>()->getMyAvatar(); | |
| 415 | − glm::vec3 avatarPos = myAvatar->getPosition(); | |
| 416 | − | |
| 417 | − lines = _expanded ? 7 : 3; | |
| 418 | − | |
| 419 | − if (columnOneWidth == _generalStatsWidth) { | |
| 420 | − drawBackground(backgroundColor, horizontalOffset, 0, _geoStatsWidth, (lines + 1) * STATS_PELS_PER_LINE); | |
| 421 | − } | |
| 422 | − horizontalOffset += 5; | |
| 423 | − | |
| 424 | − QString avatarPosition = QString("Position: %1, %2, %3"). | |
| 425 | − arg(avatarPos.x, -1, 'f', 1). | |
| 426 | − arg(avatarPos.y, -1, 'f', 1). | |
| 427 | − arg(avatarPos.z, -1, 'f', 1); | |
| 428 | − QString avatarVelocity = QString("Velocity: %1").arg(glm::length(myAvatar->getVelocity()), -1, 'f', 1); | |
| 429 | − QString avatarBodyYaw = QString("Yaw: %1").arg(myAvatar->getBodyYaw(), -1, 'f', 1); | |
| 430 | − QString avatarMixerStats; | |
| 431 | − | |
| 432 | − drawText(horizontalOffset, verticalOffset, scale, rotation, font, avatarPosition.toUtf8().constData(), color); | |
| 433 | − verticalOffset += STATS_PELS_PER_LINE; | |
| 434 | − drawText(horizontalOffset, verticalOffset, scale, rotation, font, avatarVelocity.toUtf8().constData(), color); | |
| 435 | − verticalOffset += STATS_PELS_PER_LINE; | |
| 436 | − drawText(horizontalOffset, verticalOffset, scale, rotation, font, avatarBodyYaw.toUtf8().constData(), color); | |
| 437 | 168 | |
| 169 | + // Third column, avatar stats | |
| 170 | + MyAvatar* myAvatar = avatarManager->getMyAvatar(); | |
| 171 | + glm::vec3 avatarPos = myAvatar->getPosition(); | |
| 172 | + STAT_UPDATE(position, QVector3D(avatarPos.x, avatarPos.y, avatarPos.z)); | |
| 173 | + STAT_UPDATE_FLOAT(velocity, glm::length(myAvatar->getVelocity()), 0.1f); | |
| 174 | + STAT_UPDATE_FLOAT(yaw, myAvatar->getBodyYaw(), 0.1f); | |
| 438 | 175 | if (_expanded) { |
| 439 | − SharedNodePointer avatarMixer = DependencyManager::get<NodeList>()->soloNodeOfType(NodeType::AvatarMixer); | |
| 176 | + SharedNodePointer avatarMixer = nodeList->soloNodeOfType(NodeType::AvatarMixer); | |
| 440 | 177 | if (avatarMixer) { |
| 441 | − avatarMixerStats = QString("Avatar Mixer: %1 kbps, %2 pps"). | |
| 442 | − arg(roundf(bandwidthRecorder->getAverageInputKilobitsPerSecond(NodeType::AudioMixer) + | |
| 443 | − bandwidthRecorder->getAverageOutputKilobitsPerSecond(NodeType::AudioMixer))). | |
| 444 | − arg(roundf(bandwidthRecorder->getAverageInputPacketsPerSecond(NodeType::AudioMixer) + | |
| 445 | − bandwidthRecorder->getAverageOutputPacketsPerSecond(NodeType::AudioMixer))); | |
| 178 | + STAT_UPDATE(avatarMixerKbps, roundf( | |
| 179 | + bandwidthRecorder->getAverageInputKilobitsPerSecond(NodeType::AvatarMixer) + | |
| 180 | + bandwidthRecorder->getAverageOutputKilobitsPerSecond(NodeType::AvatarMixer))); | |
| 181 | + STAT_UPDATE(avatarMixerPps, roundf( | |
| 182 | + bandwidthRecorder->getAverageInputPacketsPerSecond(NodeType::AvatarMixer) + | |
| 183 | + bandwidthRecorder->getAverageOutputPacketsPerSecond(NodeType::AvatarMixer))); | |
| 446 | 184 | } else { |
| 447 | − avatarMixerStats = QString("No Avatar Mixer"); | |
| 185 | + STAT_UPDATE(avatarMixerKbps, -1); | |
| 186 | + STAT_UPDATE(avatarMixerPps, -1); | |
| 448 | 187 | } |
| 449 | − | |
| 450 | − verticalOffset += STATS_PELS_PER_LINE; | |
| 451 | − drawText(horizontalOffset, verticalOffset, scale, rotation, font, avatarMixerStats.toUtf8().constData(), color); | |
| 452 | − | |
| 453 | − stringstream downloads; | |
| 454 | − downloads << "Downloads: "; | |
| 455 | − foreach (Resource* resource, ResourceCache::getLoadingRequests()) { | |
| 456 | − downloads << (int)(resource->getProgress() * 100.0f) << "% "; | |
| 188 | + SharedNodePointer audioMixerNode = nodeList->soloNodeOfType(NodeType::AudioMixer); | |
| 189 | + if (audioMixerNode) { | |
| 190 | + STAT_UPDATE(audioMixerKbps, roundf( | |
| 191 | + bandwidthRecorder->getAverageInputKilobitsPerSecond(NodeType::AudioMixer) + | |
| 192 | + bandwidthRecorder->getAverageOutputKilobitsPerSecond(NodeType::AudioMixer))); | |
| 193 | + STAT_UPDATE(audioMixerPps, roundf( | |
| 194 | + bandwidthRecorder->getAverageInputPacketsPerSecond(NodeType::AudioMixer) + | |
| 195 | + bandwidthRecorder->getAverageOutputPacketsPerSecond(NodeType::AudioMixer))); | |
| 196 | + } else { | |
| 197 | + STAT_UPDATE(audioMixerKbps, -1); | |
| 198 | + STAT_UPDATE(audioMixerPps, -1); | |
| 457 | 199 | } |
| 458 | − downloads << "(" << ResourceCache::getPendingRequestCount() << " pending)"; | |
| 459 | − | |
| 460 | − verticalOffset += STATS_PELS_PER_LINE; | |
| 461 | − drawText(horizontalOffset, verticalOffset, scale, rotation, font, downloads.str().c_str(), color); | |
| 462 | − } | |
| 463 | 200 | |
| 464 | − verticalOffset = STATS_PELS_INITIALOFFSET; | |
| 465 | − horizontalOffset = _lastHorizontalOffset + _generalStatsWidth + _pingStatsWidth + _geoStatsWidth + 3; | |
| 466 | − | |
| 467 | − lines = _expanded ? 10 : 3; | |
| 468 | − | |
| 469 | − drawBackground(backgroundColor, horizontalOffset, 0, canvasSize.x - horizontalOffset, | |
| 470 | − (lines + 1) * STATS_PELS_PER_LINE); | |
| 471 | − horizontalOffset += 5; | |
| 472 | − | |
| 473 | − // Model/Entity render details | |
| 474 | − octreeStats.str(""); | |
| 475 | − octreeStats << "Triangles: " << _renderDetails._trianglesRendered | |
| 476 | − << " / Quads:" << _renderDetails._quadsRendered | |
| 477 | − << " / Material Switches:" << _renderDetails._materialSwitches; | |
| 478 | − drawText(horizontalOffset, verticalOffset, scale, rotation, font, (char*)octreeStats.str().c_str(), color); | |
| 479 | − | |
| 480 | − if (_expanded) { | |
| 481 | − octreeStats.str(""); | |
| 482 | − octreeStats << " Mesh Parts Rendered Opaque: " << _renderDetails._opaque._rendered | |
| 483 | − << " / Translucent:" << _renderDetails._translucent._rendered; | |
| 484 | − verticalOffset += STATS_PELS_PER_LINE; | |
| 485 | − drawText(horizontalOffset, verticalOffset, scale, rotation, font, (char*)octreeStats.str().c_str(), color); | |
| 486 | − | |
| 487 | − octreeStats.str(""); | |
| 488 | − octreeStats << " Opaque considered: " << _renderDetails._opaque._considered | |
| 489 | − << " / Out of view:" << _renderDetails._opaque._outOfView | |
| 490 | − << " / Too small:" << _renderDetails._opaque._tooSmall; | |
| 491 | − verticalOffset += STATS_PELS_PER_LINE; | |
| 492 | − drawText(horizontalOffset, verticalOffset, scale, rotation, font, (char*)octreeStats.str().c_str(), color); | |
| 493 | − | |
| 494 | − octreeStats.str(""); | |
| 495 | − octreeStats << " Translucent considered: " << _renderDetails._translucent._considered | |
| 496 | − << " / Out of view:" << _renderDetails._translucent._outOfView | |
| 497 | − << " / Too small:" << _renderDetails._translucent._tooSmall; | |
| 498 | − verticalOffset += STATS_PELS_PER_LINE; | |
| 499 | − drawText(horizontalOffset, verticalOffset, scale, rotation, font, (char*)octreeStats.str().c_str(), color); | |
| 500 | − } | |
| 501 | − | |
| 502 | − // iterate all the current voxel stats, and list their sending modes, and total voxel counts | |
| 503 | − std::stringstream sendingMode(""); | |
| 504 | − sendingMode << "Octree Sending Mode: ["; | |
| 201 | + STAT_UPDATE(downloads, ResourceCache::getLoadingRequests().size()); | |
| 202 | + STAT_UPDATE(downloadsPending, ResourceCache::getPendingRequestCount()); | |
| 203 | + // TODO fix to match original behavior | |
| 204 | + //stringstream downloads; | |
| 205 | + //downloads << "Downloads: "; | |
| 206 | + //foreach(Resource* resource, ) { | |
| 207 | + // downloads << (int)(resource->getProgress() * 100.0f) << "% "; | |
| 208 | + //} | |
| 209 | + //downloads << "(" << << " pending)"; | |
| 210 | + } // expanded avatar column | |
| 211 | + | |
| 212 | + // Fourth column, octree stats | |
| 505 | 213 | int serverCount = 0; |
| 506 | 214 | int movingServerCount = 0; |
| 507 | 215 | unsigned long totalNodes = 0; |
| 508 | 216 | unsigned long totalInternal = 0; |
| 509 | 217 | unsigned long totalLeaves = 0; |
| 218 | + std::stringstream sendingModeStream(""); | |
| 219 | + sendingModeStream << "["; | |
| 510 | 220 | NodeToOctreeSceneStats* octreeServerSceneStats = Application::getInstance()->getOcteeSceneStats(); |
| 511 | − for(NodeToOctreeSceneStatsIterator i = octreeServerSceneStats->begin(); i != octreeServerSceneStats->end(); i++) { | |
| 221 | + for (NodeToOctreeSceneStatsIterator i = octreeServerSceneStats->begin(); i != octreeServerSceneStats->end(); i++) { | |
| 512 | 222 | //const QUuid& uuid = i->first; |
| 513 | 223 | OctreeSceneStats& stats = i->second; |
| 514 | 224 | serverCount++; |
| 515 | 225 | if (_expanded) { |
| 516 | 226 | if (serverCount > 1) { |
| 517 | − sendingMode << ","; | |
| 227 | + sendingModeStream << ","; | |
| 518 | 228 | } |
| 519 | 229 | if (stats.isMoving()) { |
| 520 | − sendingMode << "M"; | |
| 230 | + sendingModeStream << "M"; | |
| 521 | 231 | movingServerCount++; |
| 522 | 232 | } else { |
| 523 | − sendingMode << "S"; | |
| 233 | + sendingModeStream << "S"; | |
| 524 | 234 | } |
| 525 | 235 | } |
| 526 | 236 | |
| @@ -528,32 +238,35 @@ void Stats::display( · 1 unmodified line | ||
| 528 | 238 | totalNodes += stats.getTotalElements(); |
| 529 | 239 | if (_expanded) { |
| 530 | 240 | totalInternal += stats.getTotalInternal(); |
| 531 | − totalLeaves += stats.getTotalLeaves(); | |
| 241 | + totalLeaves += stats.getTotalLeaves(); | |
| 532 | 242 | } |
| 533 | 243 | } |
| 534 | 244 | if (_expanded) { |
| 535 | 245 | if (serverCount == 0) { |
| 536 | − sendingMode << "---"; | |
| 246 | + sendingModeStream << "---"; | |
| 537 | 247 | } |
| 538 | − sendingMode << "] " << serverCount << " servers"; | |
| 248 | + sendingModeStream << "] " << serverCount << " servers"; | |
| 539 | 249 | if (movingServerCount > 0) { |
| 540 | − sendingMode << " <SCENE NOT STABLE>"; | |
| 250 | + sendingModeStream << " <SCENE NOT STABLE>"; | |
| 541 | 251 | } else { |
| 542 | − sendingMode << " <SCENE STABLE>"; | |
| 252 | + sendingModeStream << " <SCENE STABLE>"; | |
| 543 | 253 | } |
| 544 | − verticalOffset += STATS_PELS_PER_LINE; | |
| 545 | − drawText(horizontalOffset, verticalOffset, scale, rotation, font, (char*)sendingMode.str().c_str(), color); | |
| 254 | + QString sendingModeResult = sendingModeStream.str().c_str(); | |
| 255 | + STAT_UPDATE(sendingMode, sendingModeResult); | |
| 546 | 256 | } |
| 547 | 257 | |
| 548 | 258 | // Incoming packets |
| 259 | + QLocale locale(QLocale::English); | |
| 260 | + auto voxelPacketsToProcess = qApp->getOctreePacketProcessor().packetsToProcessCount(); | |
| 549 | 261 | if (_expanded) { |
| 550 | − octreeStats.str(""); | |
| 262 | + std::stringstream octreeStats; | |
| 551 | 263 | QString packetsString = locale.toString((int)voxelPacketsToProcess); |
| 552 | 264 | QString maxString = locale.toString((int)_recentMaxPackets); |
| 553 | 265 | octreeStats << "Octree Packets to Process: " << qPrintable(packetsString) |
| 554 | − << " [Recent Max: " << qPrintable(maxString) << "]"; | |
| 555 | − verticalOffset += STATS_PELS_PER_LINE; | |
| 556 | − drawText(horizontalOffset, verticalOffset, scale, rotation, font, (char*)octreeStats.str().c_str(), color); | |
| 266 | + << " [Recent Max: " << qPrintable(maxString) << "]"; | |
| 267 | + QString str = octreeStats.str().c_str(); | |
| 268 | + STAT_UPDATE(packetStats, str); | |
| 269 | + // drawText(horizontalOffset, verticalOffset, scale, rotation, font, (char*)octreeStats.str().c_str(), color); | |
| 557 | 270 | } |
| 558 | 271 | |
| 559 | 272 | if (_resetRecentMaxPacketsSoon && voxelPacketsToProcess > 0) { |
| @@ -562,60 +275,102 @@ void Stats::display( · 2 unmodified lines | ||
| 562 | 275 | } |
| 563 | 276 | if (voxelPacketsToProcess == 0) { |
| 564 | 277 | _resetRecentMaxPacketsSoon = true; |
| 565 | − } else { | |
| 566 | − if (voxelPacketsToProcess > _recentMaxPackets) { | |
| 567 | − _recentMaxPackets = voxelPacketsToProcess; | |
| 568 | − } | |
| 278 | + } else if (voxelPacketsToProcess > _recentMaxPackets) { | |
| 279 | + _recentMaxPackets = voxelPacketsToProcess; | |
| 569 | 280 | } |
| 570 | 281 | |
| 571 | − QString serversTotalString = locale.toString((uint)totalNodes); // consider adding: .rightJustified(10, ' '); | |
| 572 | − unsigned long localTotal = OctreeElement::getNodeCount(); | |
| 573 | − QString localTotalString = locale.toString((uint)localTotal); // consider adding: .rightJustified(10, ' '); | |
| 574 | − | |
| 575 | 282 | // Server Octree Elements |
| 576 | − if (!_expanded) { | |
| 577 | − octreeStats.str(""); | |
| 578 | − octreeStats << "Octree Elements Server: " << qPrintable(serversTotalString) | |
| 579 | − << " Local:" << qPrintable(localTotalString); | |
| 580 | − verticalOffset += STATS_PELS_PER_LINE; | |
| 581 | − drawText(horizontalOffset, verticalOffset, scale, rotation, font, (char*)octreeStats.str().c_str(), color); | |
| 582 | − } | |
| 283 | + STAT_UPDATE(serverElements, totalNodes); | |
| 284 | + STAT_UPDATE(localElements, OctreeElement::getNodeCount()); | |
| 583 | 285 | |
| 584 | 286 | if (_expanded) { |
| 585 | − octreeStats.str(""); | |
| 586 | − octreeStats << "Octree Elements -"; | |
| 587 | − verticalOffset += STATS_PELS_PER_LINE; | |
| 588 | − drawText(horizontalOffset, verticalOffset, scale, rotation, font, (char*)octreeStats.str().c_str(), color); | |
| 287 | + STAT_UPDATE(serverInternal, totalInternal); | |
| 288 | + STAT_UPDATE(serverLeaves, totalLeaves); | |
| 289 | + // Local Voxels | |
| 290 | + STAT_UPDATE(localInternal, OctreeElement::getInternalNodeCount()); | |
| 291 | + STAT_UPDATE(localLeaves, OctreeElement::getLeafNodeCount()); | |
| 292 | + // LOD Details | |
| 293 | + STAT_UPDATE(lodStatus, "You can see " + DependencyManager::get<LODManager>()->getLODFeedbackText()); | |
| 294 | + } | |
| 589 | 295 | |
| 590 | − QString serversInternalString = locale.toString((uint)totalInternal); | |
| 591 | − QString serversLeavesString = locale.toString((uint)totalLeaves); | |
| 296 | + bool performanceTimerIsActive = PerformanceTimer::isActive(); | |
| 297 | + bool displayPerf = _expanded && Menu::getInstance()->isOptionChecked(MenuOption::DisplayDebugTimingDetails); | |
| 298 | + if (displayPerf && performanceTimerIsActive) { | |
| 299 | + if (!_timingExpanded) { | |
| 300 | + _timingExpanded = true; | |
| 301 | + emit timingExpandedChanged(); | |
| 302 | + } | |
| 303 | + PerformanceTimer::tallyAllTimerRecords(); // do this even if we're not displaying them, so they don't stack up | |
| 592 | 304 | |
| 593 | − octreeStats.str(""); | |
| 594 | − octreeStats << " Server: " << qPrintable(serversTotalString) << | |
| 595 | − " Internal: " << qPrintable(serversInternalString) << | |
| 596 | − " Leaves: " << qPrintable(serversLeavesString); | |
| 597 | − verticalOffset += STATS_PELS_PER_LINE; | |
| 598 | − drawText(horizontalOffset, verticalOffset, scale, rotation, font, (char*)octreeStats.str().c_str(), color); | |
| 305 | + // we will also include room for 1 line per timing record and a header of 4 lines | |
| 306 | + // Timing details... | |
| 599 | 307 | |
| 600 | − // Local Voxels | |
| 601 | − unsigned long localInternal = OctreeElement::getInternalNodeCount(); | |
| 602 | − unsigned long localLeaves = OctreeElement::getLeafNodeCount(); | |
| 603 | − QString localInternalString = locale.toString((uint)localInternal); | |
| 604 | − QString localLeavesString = locale.toString((uint)localLeaves); | |
| 605 | − | |
| 606 | − octreeStats.str(""); | |
| 607 | − octreeStats << " Local: " << qPrintable(serversTotalString) << | |
| 608 | − " Internal: " << qPrintable(localInternalString) << | |
| 609 | − " Leaves: " << qPrintable(localLeavesString) << ""; | |
| 610 | − verticalOffset += STATS_PELS_PER_LINE; | |
| 611 | − drawText(horizontalOffset, verticalOffset, scale, rotation, font, (char*)octreeStats.str().c_str(), color); | |
| 308 | + // First iterate all the records, and for the ones that should be included, insert them into | |
| 309 | + // a new Map sorted by average time... | |
| 310 | + bool onlyDisplayTopTen = Menu::getInstance()->isOptionChecked(MenuOption::OnlyDisplayTopTen); | |
| 311 | + QMap<float, QString> sortedRecords; | |
| 312 | + const QMap<QString, PerformanceTimerRecord>& allRecords = PerformanceTimer::getAllTimerRecords(); | |
| 313 | + QMapIterator<QString, PerformanceTimerRecord> i(allRecords); | |
| 314 | + | |
| 315 | + while (i.hasNext()) { | |
| 316 | + i.next(); | |
| 317 | + if (includeTimingRecord(i.key())) { | |
| 318 | + float averageTime = (float)i.value().getMovingAverage() / (float)USECS_PER_MSEC; | |
| 319 | + sortedRecords.insertMulti(averageTime, i.key()); | |
| 320 | + } | |
| 321 | + } | |
| 322 | + | |
| 323 | + int linesDisplayed = 0; | |
| 324 | + QMapIterator<float, QString> j(sortedRecords); | |
| 325 | + j.toBack(); | |
| 326 | + QString perfLines; | |
| 327 | + while (j.hasPrevious()) { | |
| 328 | + j.previous(); | |
| 329 | + static const QChar noBreakingSpace = QChar::Nbsp; | |
| 330 | + QString functionName = j.value(); | |
| 331 | + const PerformanceTimerRecord& record = allRecords.value(functionName); | |
| 332 | + perfLines += QString("%1: %2 [%3]\n"). | |
| 333 | + arg(QString(qPrintable(functionName)), 90, noBreakingSpace). | |
| 334 | + arg((float)record.getMovingAverage() / (float)USECS_PER_MSEC, 8, 'f', 3, noBreakingSpace). | |
| 335 | + arg((int)record.getCount(), 6, 10, noBreakingSpace); | |
| 336 | + linesDisplayed++; | |
| 337 | + if (onlyDisplayTopTen && linesDisplayed == 10) { | |
| 338 | + break; | |
| 339 | + } | |
| 340 | + } | |
| 341 | + _timingStats = perfLines; | |
| 342 | + emit timingStatsChanged(); | |
| 343 | + } else if (_timingExpanded) { | |
| 344 | + _timingExpanded = false; | |
| 345 | + emit timingExpandedChanged(); | |
| 612 | 346 | } |
| 347 | +} | |
| 348 | + | |
| 349 | +void Stats::setRenderDetails(const RenderDetails& details) { | |
| 350 | + STAT_UPDATE(triangles, details._trianglesRendered); | |
| 351 | + STAT_UPDATE(quads, details._quadsRendered); | |
| 352 | + STAT_UPDATE(materialSwitches, details._materialSwitches); | |
| 353 | + if (_expanded) { | |
| 354 | + STAT_UPDATE(meshOpaque, details._opaque._rendered); | |
| 355 | + STAT_UPDATE(meshTranslucent, details._opaque._rendered); | |
| 356 | + STAT_UPDATE(opaqueConsidered, details._opaque._considered); | |
| 357 | + STAT_UPDATE(opaqueOutOfView, details._opaque._outOfView); | |
| 358 | + STAT_UPDATE(opaqueTooSmall, details._opaque._tooSmall); | |
| 359 | + STAT_UPDATE(translucentConsidered, details._translucent._considered); | |
| 360 | + STAT_UPDATE(translucentOutOfView, details._translucent._outOfView); | |
| 361 | + STAT_UPDATE(translucentTooSmall, details._translucent._tooSmall); | |
| 362 | + } | |
| 363 | +} | |
| 364 | + | |
| 365 | + | |
| 366 | +/* | |
| 367 | +// display expanded or contracted stats | |
| 368 | +void Stats::display( | |
| 369 | + int voxelPacketsToProcess) | |
| 370 | +{ | |
| 371 | + // iterate all the current voxel stats, and list their sending modes, and total voxel counts | |
| 613 | 372 | |
| 614 | − // LOD Details | |
| 615 | − octreeStats.str(""); | |
| 616 | − QString displayLODDetails = DependencyManager::get<LODManager>()->getLODFeedbackText(); | |
| 617 | − octreeStats << "LOD: You can see " << qPrintable(displayLODDetails.trimmed()); | |
| 618 | − verticalOffset += STATS_PELS_PER_LINE; | |
| 619 | − drawText(horizontalOffset, verticalOffset, scale, rotation, font, (char*)octreeStats.str().c_str(), color); | |
| 620 | 373 | } |
| 621 | 374 | |
| 375 | + | |
| 376 | +*/ | |
| @@ -1,8 +1,5 @@ | ||
| 1 | 1 | // |
| 2 | −// Stats.h | |
| 3 | −// interface/src/ui | |
| 4 | −// | |
| 5 | −// Created by Lucas Crisman on 22/03/14. | |
| 2 | +// Created by Bradley Austin Davis 2015/06/17 | |
| 6 | 3 | // Copyright 2013 High Fidelity, Inc. |
| 7 | 4 | // |
| 8 | 5 | // Distributed under the Apache License, Version 2.0. |
| @@ -13,47 +10,139 @@ · 4 unmodified lines | ||
| 13 | 10 | #define hifi_Stats_h |
| 14 | 11 | |
| 15 | 12 | #include <QObject> |
| 13 | +#include <QQuickItem> | |
| 14 | +#include <QVector3D> | |
| 16 | 15 | |
| 16 | +#include <OffscreenUi.h> | |
| 17 | 17 | #include <RenderArgs.h> |
| 18 | 18 | |
| 19 | −class Stats: public QObject { | |
| 19 | +#define STATS_PROPERTY(type, name, initialValue) \ | |
| 20 | + Q_PROPERTY(type name READ name NOTIFY name##Changed) \ | |
| 21 | +public: \ | |
| 22 | + type name() { return _##name; }; \ | |
| 23 | +private: \ | |
| 24 | + type _##name{ initialValue }; | |
| 25 | + | |
| 26 | + | |
| 27 | +class Stats : public QQuickItem { | |
| 20 | 28 | Q_OBJECT |
| 29 | + HIFI_QML_DECL | |
| 30 | + Q_PROPERTY(bool expanded READ isExpanded WRITE setExpanded NOTIFY expandedChanged) | |
| 31 | + Q_PROPERTY(bool timingExpanded READ isTimingExpanded NOTIFY timingExpandedChanged) | |
| 32 | + Q_PROPERTY(QString monospaceFont READ monospaceFont) | |
| 33 | + | |
| 34 | + STATS_PROPERTY(int, serverCount, 0) | |
| 35 | + STATS_PROPERTY(int, framerate, 0) | |
| 36 | + STATS_PROPERTY(int, avatarCount, 0) | |
| 37 | + STATS_PROPERTY(int, packetInCount, 0) | |
| 38 | + STATS_PROPERTY(int, packetOutCount, 0) | |
| 39 | + STATS_PROPERTY(float, mbpsIn, 0) | |
| 40 | + STATS_PROPERTY(float, mbpsOut, 0) | |
| 41 | + STATS_PROPERTY(int, audioPing, 0) | |
| 42 | + STATS_PROPERTY(int, avatarPing, 0) | |
| 43 | + STATS_PROPERTY(int, entitiesPing, 0) | |
| 44 | + STATS_PROPERTY(QVector3D, position, QVector3D(0, 0, 0) ) | |
| 45 | + STATS_PROPERTY(float, velocity, 0) | |
| 46 | + STATS_PROPERTY(float, yaw, 0) | |
| 47 | + STATS_PROPERTY(int, avatarMixerKbps, 0) | |
| 48 | + STATS_PROPERTY(int, avatarMixerPps, 0) | |
| 49 | + STATS_PROPERTY(int, audioMixerKbps, 0) | |
| 50 | + STATS_PROPERTY(int, audioMixerPps, 0) | |
| 51 | + STATS_PROPERTY(int, downloads, 0) | |
| 52 | + STATS_PROPERTY(int, downloadsPending, 0) | |
| 53 | + STATS_PROPERTY(int, triangles, 0) | |
| 54 | + STATS_PROPERTY(int, quads, 0) | |
| 55 | + STATS_PROPERTY(int, materialSwitches, 0) | |
| 56 | + STATS_PROPERTY(int, meshOpaque, 0) | |
| 57 | + STATS_PROPERTY(int, meshTranslucent, 0) | |
| 58 | + STATS_PROPERTY(int, opaqueConsidered, 0) | |
| 59 | + STATS_PROPERTY(int, opaqueOutOfView, 0) | |
| 60 | + STATS_PROPERTY(int, opaqueTooSmall, 0) | |
| 61 | + STATS_PROPERTY(int, translucentConsidered, 0) | |
| 62 | + STATS_PROPERTY(int, translucentOutOfView, 0) | |
| 63 | + STATS_PROPERTY(int, translucentTooSmall, 0) | |
| 64 | + STATS_PROPERTY(QString, sendingMode, QString()) | |
| 65 | + STATS_PROPERTY(QString, packetStats, QString()) | |
| 66 | + STATS_PROPERTY(QString, lodStatus, QString()) | |
| 67 | + STATS_PROPERTY(QString, timingStats, QString()) | |
| 68 | + STATS_PROPERTY(int, serverElements, 0) | |
| 69 | + STATS_PROPERTY(int, serverInternal, 0) | |
| 70 | + STATS_PROPERTY(int, serverLeaves, 0) | |
| 71 | + STATS_PROPERTY(int, localElements, 0) | |
| 72 | + STATS_PROPERTY(int, localInternal, 0) | |
| 73 | + STATS_PROPERTY(int, localLeaves, 0) | |
| 21 | 74 | |
| 22 | 75 | public: |
| 23 | 76 | static Stats* getInstance(); |
| 24 | 77 | |
| 25 | − Stats(); | |
| 26 | − | |
| 27 | − static void drawBackground(unsigned int rgba, int x, int y, int width, int height); | |
| 28 | − | |
| 29 | − void toggleExpanded(); | |
| 30 | − bool isExpanded() { return _expanded; } | |
| 31 | − | |
| 32 | − void checkClick(int mouseX, int mouseY, int mouseDragStartedX, int mouseDragStartedY, int horizontalOffset); | |
| 33 | − void resetWidth(int width, int horizontalOffset); | |
| 34 | − void display(const float* color, int horizontalOffset, float fps, int inPacketsPerSecond, int outPacketsPerSecond, | |
| 35 | − int inKbitsPerSecond, int outKbitsPerSecond, int voxelPacketsToProcess); | |
| 78 | + Stats(QQuickItem* parent = nullptr); | |
| 36 | 79 | bool includeTimingRecord(const QString& name); |
| 37 | − | |
| 38 | − void setRenderDetails(const RenderDetails& details) { _renderDetails = details; } | |
| 39 | − | |
| 40 | −private: | |
| 41 | − static Stats* _sharedInstance; | |
| 80 | + void setRenderDetails(const RenderDetails& details); | |
| 81 | + const QString& monospaceFont() { | |
| 82 | + return _monospaceFont; | |
| 83 | + } | |
| 84 | + void updateStats(); | |
| 42 | 85 | |
| 43 | − bool _expanded; | |
| 86 | + bool isExpanded() { return _expanded; } | |
| 87 | + bool isTimingExpanded() { return _timingExpanded; } | |
| 44 | 88 | |
| 45 | − int _recentMaxPackets; // recent max incoming voxel packets to process | |
| 46 | − bool _resetRecentMaxPacketsSoon; | |
| 89 | + void setExpanded(bool expanded) { | |
| 90 | + if (_expanded != expanded) { | |
| 91 | + _expanded = expanded; | |
| 92 | + emit expandedChanged(); | |
| 93 | + } | |
| 94 | + } | |
| 47 | 95 | |
| 48 | − int _generalStatsWidth; | |
| 49 | − int _bandwidthStatsWidth; | |
| 50 | − int _pingStatsWidth; | |
| 51 | − int _geoStatsWidth; | |
| 52 | − int _octreeStatsWidth; | |
| 96 | +signals: | |
| 97 | + void expandedChanged(); | |
| 98 | + void timingExpandedChanged(); | |
| 99 | + void serverCountChanged(); | |
| 100 | + void framerateChanged(); | |
| 101 | + void avatarCountChanged(); | |
| 102 | + void packetInCountChanged(); | |
| 103 | + void packetOutCountChanged(); | |
| 104 | + void mbpsInChanged(); | |
| 105 | + void mbpsOutChanged(); | |
| 106 | + void audioPingChanged(); | |
| 107 | + void avatarPingChanged(); | |
| 108 | + void entitiesPingChanged(); | |
| 109 | + void positionChanged(); | |
| 110 | + void velocityChanged(); | |
| 111 | + void yawChanged(); | |
| 112 | + void avatarMixerKbpsChanged(); | |
| 113 | + void avatarMixerPpsChanged(); | |
| 114 | + void audioMixerKbpsChanged(); | |
| 115 | + void audioMixerPpsChanged(); | |
| 116 | + void downloadsChanged(); | |
| 117 | + void downloadsPendingChanged(); | |
| 118 | + void trianglesChanged(); | |
| 119 | + void quadsChanged(); | |
| 120 | + void materialSwitchesChanged(); | |
| 121 | + void meshOpaqueChanged(); | |
| 122 | + void meshTranslucentChanged(); | |
| 123 | + void opaqueConsideredChanged(); | |
| 124 | + void opaqueOutOfViewChanged(); | |
| 125 | + void opaqueTooSmallChanged(); | |
| 126 | + void translucentConsideredChanged(); | |
| 127 | + void translucentOutOfViewChanged(); | |
| 128 | + void translucentTooSmallChanged(); | |
| 129 | + void sendingModeChanged(); | |
| 130 | + void packetStatsChanged(); | |
| 131 | + void lodStatusChanged(); | |
| 132 | + void serverElementsChanged(); | |
| 133 | + void serverInternalChanged(); | |
| 134 | + void serverLeavesChanged(); | |
| 135 | + void localElementsChanged(); | |
| 136 | + void localInternalChanged(); | |
| 137 | + void localLeavesChanged(); | |
| 138 | + void timingStatsChanged(); | |
| 53 | 139 | |
| 54 | − int _lastHorizontalOffset; | |
| 55 | − | |
| 56 | − RenderDetails _renderDetails; | |
| 140 | +private: | |
| 141 | + int _recentMaxPackets{ 0 } ; // recent max incoming voxel packets to process | |
| 142 | + bool _resetRecentMaxPacketsSoon{ true }; | |
| 143 | + bool _expanded{ false }; | |
| 144 | + bool _timingExpanded{ false }; | |
| 145 | + QString _monospaceFont; | |
| 57 | 146 | }; |
| 58 | 147 | |
| 59 | 148 | #endif // hifi_Stats_h |
| @@ -53,7 +53,7 @@ void UserInputMapper::resetDevice(uint16 deviceID) { · 52 unmodified lines | ||
| 53 | 53 | |
| 54 | 54 | int UserInputMapper::findDevice(QString name) { |
| 55 | 55 | for (auto device : _registeredDevices) { |
| 56 | − if (device.second->_name == name) { | |
| 56 | + if (device.second->_name.split(" (")[0] == name) { | |
| 57 | 57 | return device.first; |
| 58 | 58 | } |
| 59 | 59 | } |
| @@ -11,6 +11,7 @@ · 10 unmodified lines | ||
| 11 | 11 | // include this before QGLWidget, which includes an earlier version of OpenGL |
| 12 | 12 | #include "InterfaceConfig.h" |
| 13 | 13 | |
| 14 | +#include <DeferredLightingEffect.h> | |
| 14 | 15 | #include <GeometryCache.h> |
| 15 | 16 | #include <GlowEffect.h> |
| 16 | 17 | #include <SharedUtil.h> |
| @@ -75,20 +76,20 @@ void Circle3DOverlay::render(RenderArgs* args) { · 58 unmodified lines | ||
| 75 | 76 | |
| 76 | 77 | float alpha = getAlpha(); |
| 77 | 78 | |
| 78 | − if (alpha == 0.0) { | |
| 79 | + if (alpha == 0.0f) { | |
| 79 | 80 | return; // do nothing if our alpha is 0, we're not visible |
| 80 | 81 | } |
| 81 | − | |
| 82 | + | |
| 82 | 83 | // Create the circle in the coordinates origin |
| 83 | 84 | float outerRadius = getOuterRadius(); |
| 84 | 85 | float innerRadius = getInnerRadius(); // only used in solid case |
| 85 | 86 | float startAt = getStartAt(); |
| 86 | 87 | float endAt = getEndAt(); |
| 87 | − | |
| 88 | + | |
| 88 | 89 | bool geometryChanged = (startAt != _lastStartAt || endAt != _lastEndAt || |
| 89 | 90 | innerRadius != _lastInnerRadius || outerRadius != _lastOuterRadius); |
| 90 | 91 | |
| 91 | − | |
| 92 | + | |
| 92 | 93 | const float FULL_CIRCLE = 360.0f; |
| 93 | 94 | const float SLICES = 180.0f; // The amount of segment to create the circle |
| 94 | 95 | const float SLICE_ANGLE = FULL_CIRCLE / SLICES; |
| @@ -101,195 +102,178 @@ void Circle3DOverlay::render(RenderArgs* args) { · 6 unmodified lines | ||
| 101 | 102 | bool colorChanged = colorX.red != _lastColor.red || colorX.green != _lastColor.green || colorX.blue != _lastColor.blue; |
| 102 | 103 | _lastColor = colorX; |
| 103 | 104 | |
| 104 | − glDisable(GL_LIGHTING); | |
| 105 | − | |
| 106 | − glm::vec3 position = getPosition(); | |
| 107 | − glm::vec3 center = getCenter(); | |
| 108 | − glm::vec2 dimensions = getDimensions(); | |
| 109 | − glm::quat rotation = getRotation(); | |
| 110 | − | |
| 111 | − float glowLevel = getGlowLevel(); | |
| 112 | − Glower* glower = NULL; | |
| 113 | − if (glowLevel > 0.0f) { | |
| 114 | − glower = new Glower(glowLevel); | |
| 115 | − } | |
| 116 | − | |
| 117 | − glPushMatrix(); | |
| 118 | − glTranslatef(position.x, position.y, position.z); | |
| 119 | − glm::vec3 axis = glm::axis(rotation); | |
| 120 | − glRotatef(glm::degrees(glm::angle(rotation)), axis.x, axis.y, axis.z); | |
| 121 | − glPushMatrix(); | |
| 122 | − glm::vec3 positionToCenter = center - position; | |
| 123 | − glTranslatef(positionToCenter.x, positionToCenter.y, positionToCenter.z); | |
| 124 | − glScalef(dimensions.x / 2.0f, dimensions.y / 2.0f, 1.0f); | |
| 105 | + auto geometryCache = DependencyManager::get<GeometryCache>(); | |
| 125 | 106 | |
| 126 | − glLineWidth(_lineWidth); | |
| 127 | − | |
| 128 | − auto geometryCache = DependencyManager::get<GeometryCache>(); | |
| 107 | + Transform transform; | |
| 108 | + transform.setTranslation(getCenter()); | |
| 109 | + transform.setRotation(getRotation()); | |
| 110 | + transform.setScale(glm::vec3(getDimensions(), 0.01f)); | |
| 111 | + | |
| 112 | + | |
| 113 | + auto& batch = *args->_batch; | |
| 114 | + batch._glLineWidth(_lineWidth); | |
| 115 | + batch.setModelTransform(transform); | |
| 116 | + DependencyManager::get<DeferredLightingEffect>()->bindSimpleProgram(batch, false, false); | |
| 117 | + | |
| 118 | + // for our overlay, is solid means we draw a ring between the inner and outer radius of the circle, otherwise | |
| 119 | + // we just draw a line... | |
| 120 | + if (getIsSolid()) { | |
| 121 | + if (_quadVerticesID == GeometryCache::UNKNOWN_ID) { | |
| 122 | + _quadVerticesID = geometryCache->allocateID(); | |
| 123 | + } | |
| 124 | + | |
| 125 | + if (geometryChanged || colorChanged) { | |
| 129 | 126 | |
| 130 | − // for our overlay, is solid means we draw a ring between the inner and outer radius of the circle, otherwise | |
| 131 | − // we just draw a line... | |
| 132 | − if (getIsSolid()) { | |
| 133 | − if (_quadVerticesID == GeometryCache::UNKNOWN_ID) { | |
| 134 | − _quadVerticesID = geometryCache->allocateID(); | |
| 135 | − } | |
| 127 | + QVector<glm::vec2> points; | |
| 128 | + | |
| 129 | + float angle = startAt; | |
| 130 | + float angleInRadians = glm::radians(angle); | |
| 131 | + glm::vec2 firstInnerPoint(cosf(angleInRadians) * innerRadius, sinf(angleInRadians) * innerRadius); | |
| 132 | + glm::vec2 firstOuterPoint(cosf(angleInRadians) * outerRadius, sinf(angleInRadians) * outerRadius); | |
| 133 | + | |
| 134 | + points << firstInnerPoint << firstOuterPoint; | |
| 135 | + | |
| 136 | + while (angle < endAt) { | |
| 137 | + angleInRadians = glm::radians(angle); | |
| 138 | + glm::vec2 thisInnerPoint(cosf(angleInRadians) * innerRadius, sinf(angleInRadians) * innerRadius); | |
| 139 | + glm::vec2 thisOuterPoint(cosf(angleInRadians) * outerRadius, sinf(angleInRadians) * outerRadius); | |
| 136 | 140 | |
| 137 | − if (geometryChanged || colorChanged) { | |
| 138 | − | |
| 139 | − QVector<glm::vec2> points; | |
| 140 | − | |
| 141 | − float angle = startAt; | |
| 142 | − float angleInRadians = glm::radians(angle); | |
| 143 | − glm::vec2 firstInnerPoint(cos(angleInRadians) * innerRadius, sin(angleInRadians) * innerRadius); | |
| 144 | − glm::vec2 firstOuterPoint(cos(angleInRadians) * outerRadius, sin(angleInRadians) * outerRadius); | |
| 145 | − | |
| 146 | − points << firstInnerPoint << firstOuterPoint; | |
| 147 | − | |
| 148 | − while (angle < endAt) { | |
| 149 | − angleInRadians = glm::radians(angle); | |
| 150 | − glm::vec2 thisInnerPoint(cos(angleInRadians) * innerRadius, sin(angleInRadians) * innerRadius); | |
| 151 | − glm::vec2 thisOuterPoint(cos(angleInRadians) * outerRadius, sin(angleInRadians) * outerRadius); | |
| 152 | − | |
| 153 | − points << thisOuterPoint << thisInnerPoint; | |
| 141 | + points << thisOuterPoint << thisInnerPoint; | |
| 154 | 142 | |
| 155 | − angle += SLICE_ANGLE; | |
| 156 | − } | |
| 143 | + angle += SLICE_ANGLE; | |
| 144 | + } | |
| 157 | 145 | |
| 158 | − // get the last slice portion.... | |
| 159 | − angle = endAt; | |
| 160 | − angleInRadians = glm::radians(angle); | |
| 161 | − glm::vec2 lastInnerPoint(cos(angleInRadians) * innerRadius, sin(angleInRadians) * innerRadius); | |
| 162 | − glm::vec2 lastOuterPoint(cos(angleInRadians) * outerRadius, sin(angleInRadians) * outerRadius); | |
| 146 | + // get the last slice portion.... | |
| 147 | + angle = endAt; | |
| 148 | + angleInRadians = glm::radians(angle); | |
| 149 | + glm::vec2 lastInnerPoint(cosf(angleInRadians) * innerRadius, sinf(angleInRadians) * innerRadius); | |
| 150 | + glm::vec2 lastOuterPoint(cosf(angleInRadians) * outerRadius, sinf(angleInRadians) * outerRadius); | |
| 163 | 151 | |
| 164 | − points << lastOuterPoint << lastInnerPoint; | |
| 165 | − | |
| 166 | − geometryCache->updateVertices(_quadVerticesID, points, color); | |
| 167 | − } | |
| 168 | − | |
| 169 | − geometryCache->renderVertices(gpu::QUAD_STRIP, _quadVerticesID); | |
| 170 | − | |
| 171 | − } else { | |
| 172 | − if (_lineVerticesID == GeometryCache::UNKNOWN_ID) { | |
| 173 | − _lineVerticesID = geometryCache->allocateID(); | |
| 174 | − } | |
| 175 | − | |
| 176 | − if (geometryChanged || colorChanged) { | |
| 177 | − QVector<glm::vec2> points; | |
| 178 | − | |
| 179 | − float angle = startAt; | |
| 180 | − float angleInRadians = glm::radians(angle); | |
| 181 | − glm::vec2 firstPoint(cos(angleInRadians) * outerRadius, sin(angleInRadians) * outerRadius); | |
| 182 | − points << firstPoint; | |
| 183 | − | |
| 184 | − while (angle < endAt) { | |
| 185 | − angle += SLICE_ANGLE; | |
| 186 | − angleInRadians = glm::radians(angle); | |
| 187 | − glm::vec2 thisPoint(cos(angleInRadians) * outerRadius, sin(angleInRadians) * outerRadius); | |
| 188 | − points << thisPoint; | |
| 189 | − | |
| 190 | − if (getIsDashedLine()) { | |
| 191 | − angle += SLICE_ANGLE / 2.0f; // short gap | |
| 192 | − angleInRadians = glm::radians(angle); | |
| 193 | − glm::vec2 dashStartPoint(cos(angleInRadians) * outerRadius, sin(angleInRadians) * outerRadius); | |
| 194 | − points << dashStartPoint; | |
| 195 | − } | |
| 196 | − } | |
| 152 | + points << lastOuterPoint << lastInnerPoint; | |
| 197 | 153 | |
| 198 | − // get the last slice portion.... | |
| 199 | − angle = endAt; | |
| 200 | − angleInRadians = glm::radians(angle); | |
| 201 | − glm::vec2 lastPoint(cos(angleInRadians) * outerRadius, sin(angleInRadians) * outerRadius); | |
| 202 | − points << lastPoint; | |
| 203 | − | |
| 204 | − geometryCache->updateVertices(_lineVerticesID, points, color); | |
| 205 | − } | |
| 206 | − | |
| 154 | + geometryCache->updateVertices(_quadVerticesID, points, color); | |
| 155 | + } | |
| 156 | + | |
| 157 | + geometryCache->renderVertices(batch, gpu::QUAD_STRIP, _quadVerticesID); | |
| 158 | + | |
| 159 | + } else { | |
| 160 | + if (_lineVerticesID == GeometryCache::UNKNOWN_ID) { | |
| 161 | + _lineVerticesID = geometryCache->allocateID(); | |
| 162 | + } | |
| 163 | + | |
| 164 | + if (geometryChanged || colorChanged) { | |
| 165 | + QVector<glm::vec2> points; | |
| 166 | + | |
| 167 | + float angle = startAt; | |
| 168 | + float angleInRadians = glm::radians(angle); | |
| 169 | + glm::vec2 firstPoint(cosf(angleInRadians) * outerRadius, sinf(angleInRadians) * outerRadius); | |
| 170 | + points << firstPoint; | |
| 171 | + | |
| 172 | + while (angle < endAt) { | |
| 173 | + angle += SLICE_ANGLE; | |
| 174 | + angleInRadians = glm::radians(angle); | |
| 175 | + glm::vec2 thisPoint(cosf(angleInRadians) * outerRadius, sinf(angleInRadians) * outerRadius); | |
| 176 | + points << thisPoint; | |
| 177 | + | |
| 207 | 178 | if (getIsDashedLine()) { |
| 208 | − geometryCache->renderVertices(gpu::LINES, _lineVerticesID); | |
| 209 | − } else { | |
| 210 | − geometryCache->renderVertices(gpu::LINE_STRIP, _lineVerticesID); | |
| 179 | + angle += SLICE_ANGLE / 2.0f; // short gap | |
| 180 | + angleInRadians = glm::radians(angle); | |
| 181 | + glm::vec2 dashStartPoint(cosf(angleInRadians) * outerRadius, sinf(angleInRadians) * outerRadius); | |
| 182 | + points << dashStartPoint; | |
| 211 | 183 | } |
| 212 | 184 | } |
| 213 | 185 | |
| 214 | − // draw our tick marks | |
| 215 | − // for our overlay, is solid means we draw a ring between the inner and outer radius of the circle, otherwise | |
| 216 | − // we just draw a line... | |
| 217 | − if (getHasTickMarks()) { | |
| 218 | − | |
| 219 | − if (_majorTicksVerticesID == GeometryCache::UNKNOWN_ID) { | |
| 220 | − _majorTicksVerticesID = geometryCache->allocateID(); | |
| 221 | − } | |
| 222 | − if (_minorTicksVerticesID == GeometryCache::UNKNOWN_ID) { | |
| 223 | − _minorTicksVerticesID = geometryCache->allocateID(); | |
| 224 | − } | |
| 225 | − | |
| 226 | − if (geometryChanged) { | |
| 227 | − QVector<glm::vec2> majorPoints; | |
| 228 | − QVector<glm::vec2> minorPoints; | |
| 229 | − | |
| 230 | − // draw our major tick marks | |
| 231 | − if (getMajorTickMarksAngle() > 0.0f && getMajorTickMarksLength() != 0.0f) { | |
| 186 | + // get the last slice portion.... | |
| 187 | + angle = endAt; | |
| 188 | + angleInRadians = glm::radians(angle); | |
| 189 | + glm::vec2 lastPoint(cosf(angleInRadians) * outerRadius, sinf(angleInRadians) * outerRadius); | |
| 190 | + points << lastPoint; | |
| 191 | + | |
| 192 | + geometryCache->updateVertices(_lineVerticesID, points, color); | |
| 193 | + } | |
| 194 | + | |
| 195 | + if (getIsDashedLine()) { | |
| 196 | + geometryCache->renderVertices(batch, gpu::LINES, _lineVerticesID); | |
| 197 | + } else { | |
| 198 | + geometryCache->renderVertices(batch, gpu::LINE_STRIP, _lineVerticesID); | |
| 199 | + } | |
| 200 | + } | |
| 201 | + | |
| 202 | + // draw our tick marks | |
| 203 | + // for our overlay, is solid means we draw a ring between the inner and outer radius of the circle, otherwise | |
| 204 | + // we just draw a line... | |
| 205 | + if (getHasTickMarks()) { | |
| 206 | + | |
| 207 | + if (_majorTicksVerticesID == GeometryCache::UNKNOWN_ID) { | |
| 208 | + _majorTicksVerticesID = geometryCache->allocateID(); | |
| 209 | + } | |
| 210 | + if (_minorTicksVerticesID == GeometryCache::UNKNOWN_ID) { | |
| 211 | + _minorTicksVerticesID = geometryCache->allocateID(); | |
| 212 | + } | |
| 213 | + | |
| 214 | + if (geometryChanged) { | |
| 215 | + QVector<glm::vec2> majorPoints; | |
| 216 | + QVector<glm::vec2> minorPoints; | |
| 217 | + | |
| 218 | + // draw our major tick marks | |
| 219 | + if (getMajorTickMarksAngle() > 0.0f && getMajorTickMarksLength() != 0.0f) { | |
| 232 | 220 | |
| 233 | − float tickMarkAngle = getMajorTickMarksAngle(); | |
| 234 | − float angle = startAt - fmod(startAt, tickMarkAngle) + tickMarkAngle; | |
| 235 | − float angleInRadians = glm::radians(angle); | |
| 236 | − float tickMarkLength = getMajorTickMarksLength(); | |
| 237 | − float startRadius = (tickMarkLength > 0.0f) ? innerRadius : outerRadius; | |
| 238 | − float endRadius = startRadius + tickMarkLength; | |
| 239 | − | |
| 240 | − while (angle <= endAt) { | |
| 241 | − angleInRadians = glm::radians(angle); | |
| 242 | − | |
| 243 | − glm::vec2 thisPointA(cos(angleInRadians) * startRadius, sin(angleInRadians) * startRadius); | |
| 244 | − glm::vec2 thisPointB(cos(angleInRadians) * endRadius, sin(angleInRadians) * endRadius); | |
| 245 | − | |
| 246 | − majorPoints << thisPointA << thisPointB; | |
| 221 | + float tickMarkAngle = getMajorTickMarksAngle(); | |
| 222 | + float angle = startAt - fmodf(startAt, tickMarkAngle) + tickMarkAngle; | |
| 223 | + float angleInRadians = glm::radians(angle); | |
| 224 | + float tickMarkLength = getMajorTickMarksLength(); | |
| 225 | + float startRadius = (tickMarkLength > 0.0f) ? innerRadius : outerRadius; | |
| 226 | + float endRadius = startRadius + tickMarkLength; | |
| 247 | 227 | |
| 248 | − angle += tickMarkAngle; | |
| 249 | − } | |
| 250 | − } | |
| 251 | − | |
| 252 | − // draw our minor tick marks | |
| 253 | − if (getMinorTickMarksAngle() > 0.0f && getMinorTickMarksLength() != 0.0f) { | |
| 228 | + while (angle <= endAt) { | |
| 229 | + angleInRadians = glm::radians(angle); | |
| 230 | + | |
| 231 | + glm::vec2 thisPointA(cosf(angleInRadians) * startRadius, sinf(angleInRadians) * startRadius); | |
| 232 | + glm::vec2 thisPointB(cosf(angleInRadians) * endRadius, sinf(angleInRadians) * endRadius); | |
| 233 | + | |
| 234 | + majorPoints << thisPointA << thisPointB; | |
| 235 | + | |
| 236 | + angle += tickMarkAngle; | |
| 237 | + } | |
| 238 | + } | |
| 239 | + | |
| 240 | + // draw our minor tick marks | |
| 241 | + if (getMinorTickMarksAngle() > 0.0f && getMinorTickMarksLength() != 0.0f) { | |
| 254 | 242 | |
| 255 | − float tickMarkAngle = getMinorTickMarksAngle(); | |
| 256 | − float angle = startAt - fmod(startAt, tickMarkAngle) + tickMarkAngle; | |
| 257 | − float angleInRadians = glm::radians(angle); | |
| 258 | − float tickMarkLength = getMinorTickMarksLength(); | |
| 259 | − float startRadius = (tickMarkLength > 0.0f) ? innerRadius : outerRadius; | |
| 260 | − float endRadius = startRadius + tickMarkLength; | |
| 261 | − | |
| 262 | − while (angle <= endAt) { | |
| 263 | − angleInRadians = glm::radians(angle); | |
| 264 | − | |
| 265 | − glm::vec2 thisPointA(cos(angleInRadians) * startRadius, sin(angleInRadians) * startRadius); | |
| 266 | − glm::vec2 thisPointB(cos(angleInRadians) * endRadius, sin(angleInRadians) * endRadius); | |
| 267 | − | |
| 268 | − minorPoints << thisPointA << thisPointB; | |
| 243 | + float tickMarkAngle = getMinorTickMarksAngle(); | |
| 244 | + float angle = startAt - fmodf(startAt, tickMarkAngle) + tickMarkAngle; | |
| 245 | + float angleInRadians = glm::radians(angle); | |
| 246 | + float tickMarkLength = getMinorTickMarksLength(); | |
| 247 | + float startRadius = (tickMarkLength > 0.0f) ? innerRadius : outerRadius; | |
| 248 | + float endRadius = startRadius + tickMarkLength; | |
| 269 | 249 | |
| 270 | − angle += tickMarkAngle; | |
| 271 | − } | |
| 272 | − } | |
| 273 | − | |
| 274 | − xColor majorColorX = getMajorTickMarksColor(); | |
| 275 | − glm::vec4 majorColor(majorColorX.red / MAX_COLOR, majorColorX.green / MAX_COLOR, majorColorX.blue / MAX_COLOR, alpha); | |
| 276 | − | |
| 277 | − geometryCache->updateVertices(_majorTicksVerticesID, majorPoints, majorColor); | |
| 278 | − | |
| 279 | − xColor minorColorX = getMinorTickMarksColor(); | |
| 280 | − glm::vec4 minorColor(minorColorX.red / MAX_COLOR, minorColorX.green / MAX_COLOR, minorColorX.blue / MAX_COLOR, alpha); | |
| 281 | − | |
| 282 | − geometryCache->updateVertices(_minorTicksVerticesID, minorPoints, minorColor); | |
| 250 | + while (angle <= endAt) { | |
| 251 | + angleInRadians = glm::radians(angle); | |
| 252 | + | |
| 253 | + glm::vec2 thisPointA(cosf(angleInRadians) * startRadius, sinf(angleInRadians) * startRadius); | |
| 254 | + glm::vec2 thisPointB(cosf(angleInRadians) * endRadius, sinf(angleInRadians) * endRadius); | |
| 255 | + | |
| 256 | + minorPoints << thisPointA << thisPointB; | |
| 257 | + | |
| 258 | + angle += tickMarkAngle; | |
| 283 | 259 | } |
| 284 | − | |
| 285 | − geometryCache->renderVertices(gpu::LINES, _majorTicksVerticesID); | |
| 286 | − | |
| 287 | − geometryCache->renderVertices(gpu::LINES, _minorTicksVerticesID); | |
| 288 | 260 | } |
| 289 | 261 | |
| 290 | − | |
| 291 | − glPopMatrix(); | |
| 292 | − glPopMatrix(); | |
| 262 | + xColor majorColorX = getMajorTickMarksColor(); | |
| 263 | + glm::vec4 majorColor(majorColorX.red / MAX_COLOR, majorColorX.green / MAX_COLOR, majorColorX.blue / MAX_COLOR, alpha); | |
| 264 | + | |
| 265 | + geometryCache->updateVertices(_majorTicksVerticesID, majorPoints, majorColor); | |
| 266 | + | |
| 267 | + xColor minorColorX = getMinorTickMarksColor(); | |
| 268 | + glm::vec4 minorColor(minorColorX.red / MAX_COLOR, minorColorX.green / MAX_COLOR, minorColorX.blue / MAX_COLOR, alpha); | |
| 269 | + | |
| 270 | + geometryCache->updateVertices(_minorTicksVerticesID, minorPoints, minorColor); | |
| 271 | + } | |
| 272 | + | |
| 273 | + geometryCache->renderVertices(batch, gpu::LINES, _majorTicksVerticesID); | |
| 274 | + | |
| 275 | + geometryCache->renderVertices(batch, gpu::LINES, _minorTicksVerticesID); | |
| 276 | + } | |
| 293 | 277 | |
| 294 | 278 | if (geometryChanged) { |
| 295 | 279 | _lastStartAt = startAt; |
| @@ -297,15 +281,11 @@ void Circle3DOverlay::render(RenderArgs* args) { · 1 unmodified line | ||
| 297 | 281 | _lastInnerRadius = innerRadius; |
| 298 | 282 | _lastOuterRadius = outerRadius; |
| 299 | 283 | } |
| 300 | − | |
| 301 | − if (glower) { | |
| 302 | − delete glower; | |
| 303 | − } | |
| 304 | 284 | } |
| 305 | 285 | |
| 306 | 286 | void Circle3DOverlay::setProperties(const QScriptValue &properties) { |
| 307 | 287 | Planar3DOverlay::setProperties(properties); |
| 308 | − | |
| 288 | + | |
| 309 | 289 | QScriptValue startAt = properties.property("startAt"); |
| 310 | 290 | if (startAt.isValid()) { |
| 311 | 291 | setStartAt(startAt.toVariant().toFloat()); |
| @@ -415,7 +395,7 @@ QScriptValue Circle3DOverlay::getProperty(const QString& property) { · 103 unmodified lines | ||
| 415 | 395 | } |
| 416 | 396 | |
| 417 | 397 | |
| 418 | −bool Circle3DOverlay::findRayIntersection(const glm::vec3& origin, | |
| 398 | +bool Circle3DOverlay::findRayIntersection(const glm::vec3& origin, | |
| 419 | 399 | const glm::vec3& direction, float& distance, BoxFace& face) { |
| 420 | 400 | |
| 421 | 401 | bool intersects = Planar3DOverlay::findRayIntersection(origin, direction, distance, face); |
| @@ -32,6 +32,16 @@ Line3DOverlay::Line3DOverlay(const Line3DOverlay* line3DOverlay) : · 31 unmodified lines | ||
| 32 | 32 | Line3DOverlay::~Line3DOverlay() { |
| 33 | 33 | } |
| 34 | 34 | |
| 35 | +AABox Line3DOverlay::getBounds() const { | |
| 36 | + auto start = _position + _start; | |
| 37 | + auto end = _position + _end; | |
| 38 | + | |
| 39 | + auto min = glm::min(start, end); | |
| 40 | + auto max = glm::max(start, end); | |
| 41 | + | |
| 42 | + return AABox(min, max - min); | |
| 43 | +} | |
| 44 | + | |
| 35 | 45 | void Line3DOverlay::render(RenderArgs* args) { |
| 36 | 46 | if (!_visible) { |
| 37 | 47 | return; // do nothing if we're not visible |
| @@ -21,6 +21,7 @@ public: · 20 unmodified lines | ||
| 21 | 21 | Line3DOverlay(const Line3DOverlay* line3DOverlay); |
| 22 | 22 | ~Line3DOverlay(); |
| 23 | 23 | virtual void render(RenderArgs* args); |
| 24 | + virtual AABox getBounds() const override; | |
| 24 | 25 | |
| 25 | 26 | // getters |
| 26 | 27 | const glm::vec3& getStart() const { return _start; } |
| @@ -258,7 +258,7 @@ void Overlays::deleteOverlay(unsigned int id) { · 257 unmodified lines | ||
| 258 | 258 | unsigned int Overlays::getOverlayAtPoint(const glm::vec2& point) { |
| 259 | 259 | glm::vec2 pointCopy = point; |
| 260 | 260 | if (qApp->isHMDMode()) { |
| 261 | − pointCopy = qApp->getApplicationOverlay().screenToOverlay(point); | |
| 261 | + pointCopy = qApp->getApplicationCompositor().screenToOverlay(point); | |
| 262 | 262 | } |
| 263 | 263 | |
| 264 | 264 | QReadLocker lock(&_lock); |
| @@ -80,6 +80,7 @@ void TextOverlay::render(RenderArgs* args) { · 79 unmodified lines | ||
| 80 | 80 | |
| 81 | 81 | glm::vec2 topLeft(left, top); |
| 82 | 82 | glm::vec2 bottomRight(right, bottom); |
| 83 | + glBindTexture(GL_TEXTURE_2D, 0); | |
| 83 | 84 | DependencyManager::get<GeometryCache>()->renderQuad(topLeft, bottomRight, quadColor); |
| 84 | 85 | |
| 85 | 86 | const int leftAdjust = -1; // required to make text render relative to left edge of bounds |