diff --git a/interface/resources/images/close.png b/interface/resources/images/close.png new file mode 100644 index 0000000000..8090e3d3d0 Binary files /dev/null and b/interface/resources/images/close.png differ diff --git a/interface/resources/images/close.svg b/interface/resources/images/close.svg new file mode 100644 index 0000000000..9c573564e6 --- /dev/null +++ b/interface/resources/images/close.svg @@ -0,0 +1,16 @@ + + + close + Created with Sketch (http://www.bohemiancoding.com/sketch) + + + + + + + + + + + + \ No newline at end of file diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 1809c71d43..b310803336 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -85,6 +85,12 @@ const int STARTUP_JITTER_SAMPLES = PACKET_LENGTH_SAMPLES_PER_CHANNEL / 2; // Startup optimistically with small jitter buffer that // will start playback on the second received audio packet. +const int MIRROR_VIEW_TOP_PADDING = 5; +const int MIRROR_VIEW_LEFT_PADDING = 10; +const int MIRROR_VIEW_WIDTH = 265; +const int MIRROR_VIEW_HEIGHT = 215; +const int MIRROR_ICON_SIZE = 16; +const int MIRROR_CLOSE_ICON_PADDING = 5; void messageHandler(QtMsgType type, const QMessageLogContext& context, const QString &message) { fprintf(stdout, "%s", message.toLocal8Bit().constData()); @@ -253,12 +259,12 @@ void Application::restoreSizeAndPosition() { settings->beginGroup("Window"); - float x = loadSetting(settings, "x", 0); - float y = loadSetting(settings, "y", 0); + int x = (int)loadSetting(settings, "x", 0); + int y = (int)loadSetting(settings, "y", 0); _window->move(x, y); - int width = loadSetting(settings, "width", available.width()); - int height = loadSetting(settings, "height", available.height()); + int width = (int)loadSetting(settings, "width", available.width()); + int height = (int)loadSetting(settings, "height", available.height()); _window->resize(width, height); settings->endGroup(); @@ -361,20 +367,7 @@ void Application::paintGL() { glEnable(GL_LINE_SMOOTH); - if (_myCamera.getMode() == CAMERA_MODE_MIRROR) { - _myCamera.setTightness (100.0f); - glm::vec3 targetPosition = _myAvatar.getUprightHeadPosition(); - if (_myAvatar.getHead().getBlendFace().isActive()) { - // make sure we're aligned to the blend face eyes - glm::vec3 leftEyePosition, rightEyePosition; - if (_myAvatar.getHead().getBlendFace().getEyePositions(leftEyePosition, rightEyePosition, true)) { - targetPosition = (leftEyePosition + rightEyePosition) * 0.5f; - } - } - _myCamera.setTargetPosition(targetPosition); - _myCamera.setTargetRotation(_myAvatar.getWorldAlignedOrientation() * glm::quat(glm::vec3(0.0f, PIf, 0.0f))); - - } else if (OculusManager::isConnected()) { + if (OculusManager::isConnected()) { _myCamera.setUpShift (0.0f); _myCamera.setDistance (0.0f); _myCamera.setTightness (0.0f); // Camera is directly connected to head without smoothing @@ -435,6 +428,37 @@ void Application::paintGL() { _glowEffect.render(); + if (Menu::getInstance()->isOptionChecked(MenuOption::Mirror)) { + glm::vec3 targetPosition = _myAvatar.getUprightHeadPosition(); + _mirrorCamera.setDistance(0.2f); + _mirrorCamera.setTargetPosition(targetPosition); + _mirrorCamera.setTargetRotation(_myAvatar.getWorldAlignedOrientation() * glm::quat(glm::vec3(0.0f, PIf, 0.0f))); + _mirrorCamera.update(1.0f/_fps); + + // set the bounds of rear mirror view + glViewport(_mirrorViewRect.x(), _glWidget->height() - _mirrorViewRect.y() - _mirrorViewRect.height(), _mirrorViewRect.width(), _mirrorViewRect.height()); + glScissor(_mirrorViewRect.x(), _glWidget->height() - _mirrorViewRect.y() - _mirrorViewRect.height(), _mirrorViewRect.width(), _mirrorViewRect.height()); + updateProjectionMatrix(_mirrorCamera); + glEnable(GL_SCISSOR_TEST); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + // render rear mirror view + glPushMatrix(); + displaySide(_mirrorCamera); + glPopMatrix(); + + // render rear view tools if mouse is in the bounds + QPoint mousePosition = _glWidget->mapFromGlobal(QCursor::pos()); + if (_mirrorViewRect.contains(mousePosition.x(), mousePosition.y())) { + displayRearMirrorTools(); + } + + // reset Viewport and projection matrix + glViewport(0, 0, _glWidget->width(), _glWidget->height()); + glDisable(GL_SCISSOR_TEST); + updateProjectionMatrix(); + } + displayOverlay(); } @@ -457,6 +481,8 @@ void Application::resetCamerasOnResizeGL(Camera& camera, int width, int height) void Application::resizeGL(int width, int height) { resetCamerasOnResizeGL(_viewFrustumOffsetCamera, width, height); resetCamerasOnResizeGL(_myCamera, width, height); + + _mirrorViewRect = QRect(MIRROR_VIEW_LEFT_PADDING, MIRROR_VIEW_TOP_PADDING, MIRROR_VIEW_WIDTH, MIRROR_VIEW_HEIGHT); glViewport(0, 0, width, height); // shouldn't this account for the menu??? @@ -465,11 +491,15 @@ void Application::resizeGL(int width, int height) { } void Application::updateProjectionMatrix() { + updateProjectionMatrix(_myCamera); +} + +void Application::updateProjectionMatrix(Camera& camera) { glMatrixMode(GL_PROJECTION); glLoadIdentity(); // Tell our viewFrustum about this change, using the application camera - loadViewFrustum(_myCamera, _viewFrustum); + loadViewFrustum(camera, _viewFrustum); float left, right, bottom, top, nearVal, farVal; glm::vec4 nearClipPlane, farClipPlane; @@ -999,7 +1029,7 @@ void Application::mouseMoveEvent(QMouseEvent* event) { if (activeWindow() == _window) { _mouseX = event->x(); _mouseY = event->y(); - + // detect drag glm::vec3 mouseVoxelPos(_mouseVoxel.x, _mouseVoxel.y, _mouseVoxel.z); if (!_justEditedVoxel && mouseVoxelPos != _lastMouseVoxelPos) { @@ -1037,6 +1067,14 @@ void Application::mousePressEvent(QMouseEvent* event) { return; } + if (Menu::getInstance()->isOptionChecked(MenuOption::Mirror)) { + QRect closeIconRect = QRect(MIRROR_CLOSE_ICON_PADDING + _mirrorViewRect.left(), MIRROR_CLOSE_ICON_PADDING + _mirrorViewRect.top(), MIRROR_ICON_SIZE, MIRROR_ICON_SIZE); + + if (closeIconRect.contains(_mouseX, _mouseY)) { + Menu::getInstance()->triggerOption(MenuOption::Mirror); + } + } + if (!_palette.isActive() && (!_isHoverVoxel || _lookatTargetAvatar)) { _pieMenu.mousePressEvent(_mouseX, _mouseY); } @@ -1613,8 +1651,15 @@ void Application::init() { _myAvatar.setPosition(START_LOCATION); _myCamera.setMode(CAMERA_MODE_FIRST_PERSON); _myCamera.setModeShiftRate(1.0f); - _myAvatar.setDisplayingLookatVectors(false); + _myAvatar.setDisplayingLookatVectors(false); + _mirrorCamera.setMode(CAMERA_MODE_MIRROR); + _mirrorCamera.setAspectRatio((float)MIRROR_VIEW_WIDTH / (float)MIRROR_VIEW_HEIGHT); + _mirrorCamera.setFieldOfView(70); + _mirrorViewRect = QRect(MIRROR_VIEW_LEFT_PADDING, MIRROR_VIEW_TOP_PADDING, MIRROR_VIEW_WIDTH, MIRROR_VIEW_HEIGHT); + + switchToResourcesParentIfRequired(); + _closeTextureId = _glWidget->bindTexture(QImage("./resources/images/close.png")); OculusManager::connect(); if (OculusManager::isConnected()) { @@ -2080,12 +2125,7 @@ void Application::update(float deltaTime) { } if (!OculusManager::isConnected()) { - if (Menu::getInstance()->isOptionChecked(MenuOption::Mirror)) { - if (_myCamera.getMode() != CAMERA_MODE_MIRROR) { - _myCamera.setMode(CAMERA_MODE_MIRROR); - _myCamera.setModeShiftRate(100.0f); - } - } else if (Menu::getInstance()->isOptionChecked(MenuOption::FirstPerson)) { + if (Menu::getInstance()->isOptionChecked(MenuOption::FirstPerson)) { if (_myCamera.getMode() != CAMERA_MODE_FIRST_PERSON) { _myCamera.setMode(CAMERA_MODE_FIRST_PERSON); _myCamera.setModeShiftRate(1.0f); @@ -2098,7 +2138,7 @@ void Application::update(float deltaTime) { } if (Menu::getInstance()->isOptionChecked(MenuOption::OffAxisProjection)) { - float xSign = Menu::getInstance()->isOptionChecked(MenuOption::Mirror) ? 1.0f : -1.0f; + float xSign = _myCamera.getMode() == CAMERA_MODE_MIRROR ? 1.0f : -1.0f; if (_faceshift.isActive()) { const float EYE_OFFSET_SCALE = 0.025f; glm::vec3 position = _faceshift.getHeadTranslation() * EYE_OFFSET_SCALE; @@ -2389,7 +2429,7 @@ void Application::displayOculus(Camera& whichCamera) { glMatrixMode(GL_PROJECTION); glLoadIdentity(); - gluOrtho2D(0, _glWidget->width(), 0, _glWidget->height()); + gluOrtho2D(0, _glWidget->width(), 0, _glWidget->height()); glDisable(GL_DEPTH_TEST); // for reference on setting these values, see SDK file Samples/OculusRoomTiny/RenderTiny_Device.cpp @@ -2466,13 +2506,6 @@ void Application::computeOffAxisFrustum(float& left, float& right, float& bottom float& far, glm::vec4& nearClipPlane, glm::vec4& farClipPlane) const { _viewFrustum.computeOffAxisFrustum(left, right, bottom, top, near, far, nearClipPlane, farClipPlane); - - // when mirrored, we must flip left and right - if (Menu::getInstance()->isOptionChecked(MenuOption::Mirror)) { - float tmp = left; - left = -right; - right = -tmp; - } } void Application::displaySide(Camera& whichCamera) { @@ -2480,7 +2513,7 @@ void Application::displaySide(Camera& whichCamera) { // transform by eye offset // flip x if in mirror mode (also requires reversing winding order for backface culling) - if (Menu::getInstance()->isOptionChecked(MenuOption::Mirror)) { + if (whichCamera.getMode() == CAMERA_MODE_MIRROR) { glScalef(-1.0f, 1.0f, 1.0f); glFrontFace(GL_CW); @@ -2601,7 +2634,7 @@ void Application::displaySide(Camera& whichCamera) { glMaterialfv(GL_FRONT, GL_SPECULAR, WHITE_SPECULAR_COLOR); // indicate what we'll be adding/removing in mouse mode, if anything - if (_mouseVoxel.s != 0) { + if (_mouseVoxel.s != 0 && whichCamera.getMode() != CAMERA_MODE_MIRROR) { PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), "Application::displaySide() ... voxels TOOLS UX..."); @@ -2649,7 +2682,7 @@ void Application::displaySide(Camera& whichCamera) { glEnable(GL_LIGHTING); } - if (Menu::getInstance()->isOptionChecked(MenuOption::VoxelSelectMode) && _pasteMode) { + if (Menu::getInstance()->isOptionChecked(MenuOption::VoxelSelectMode) && _pasteMode && whichCamera.getMode() != CAMERA_MODE_MIRROR) { PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), "Application::displaySide() ... PASTE Preview..."); @@ -2685,7 +2718,7 @@ void Application::displaySide(Camera& whichCamera) { } // Set lookAt to myCamera on client side if other avatars are looking at client if (isLookingAtMyAvatar(avatar)) { - avatar->getHead().setLookAtPosition(_myCamera.getPosition()); + avatar->getHead().setLookAtPosition(whichCamera.getPosition()); } avatar->render(false, Menu::getInstance()->isOptionChecked(MenuOption::AvatarAsBalls)); avatar->setDisplayingLookatVectors(Menu::getInstance()->isOptionChecked(MenuOption::LookAtVectors)); @@ -2695,10 +2728,10 @@ void Application::displaySide(Camera& whichCamera) { } // Render my own Avatar - if (_myCamera.getMode() == CAMERA_MODE_MIRROR && !_faceshift.isActive()) { - _myAvatar.getHead().setLookAtPosition(_myCamera.getPosition()); + if (whichCamera.getMode() == CAMERA_MODE_MIRROR && !_faceshift.isActive()) { + _myAvatar.getHead().setLookAtPosition(whichCamera.getPosition()); } - _myAvatar.render(Menu::getInstance()->isOptionChecked(MenuOption::Mirror), + _myAvatar.render(whichCamera.getMode() == CAMERA_MODE_MIRROR, Menu::getInstance()->isOptionChecked(MenuOption::AvatarAsBalls)); _myAvatar.setDisplayingLookatVectors(Menu::getInstance()->isOptionChecked(MenuOption::LookAtVectors)); @@ -2710,7 +2743,7 @@ void Application::displaySide(Camera& whichCamera) { _myAvatar.renderScreenTint(SCREEN_TINT_AFTER_AVATARS, whichCamera); // Render the world box - if (!Menu::getInstance()->isOptionChecked(MenuOption::Mirror) && Menu::getInstance()->isOptionChecked(MenuOption::Stats)) { + if (whichCamera.getMode() != CAMERA_MODE_MIRROR && Menu::getInstance()->isOptionChecked(MenuOption::Stats)) { renderWorldBox(); } @@ -2722,7 +2755,7 @@ void Application::displaySide(Camera& whichCamera) { } // brad's frustum for debugging - if (Menu::getInstance()->isOptionChecked(MenuOption::DisplayFrustum)) { + if (Menu::getInstance()->isOptionChecked(MenuOption::DisplayFrustum) && whichCamera.getMode() != CAMERA_MODE_MIRROR) { PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), "Application::displaySide() ... renderViewFrustum..."); renderViewFrustum(_viewFrustum); @@ -2803,7 +2836,6 @@ void Application::displayOverlay() { //noiseTest(_glWidget->width(), _glWidget->height()); if (Menu::getInstance()->isOptionChecked(MenuOption::HeadMouse) - && !Menu::getInstance()->isOptionChecked(MenuOption::Mirror) && USING_INVENSENSE_MPU9150) { // Display small target box at center or head mouse target that can also be used to measure LOD glColor3f(1.0, 1.0, 1.0); @@ -2955,7 +2987,7 @@ void Application::displayOverlay() { if (_pieMenu.isDisplayed()) { _pieMenu.render(); } - + glPopMatrix(); } @@ -3782,3 +3814,42 @@ void* Application::networkReceive(void* args) { void Application::packetSentNotification(ssize_t length) { _bandwidthMeter.outputStream(BandwidthMeter::VOXELS).updateValue(length); } + +void Application::displayRearMirrorTools() { + + glMatrixMode(GL_PROJECTION); + glPushMatrix(); + glLoadIdentity(); + gluOrtho2D(_mirrorViewRect.left(), _mirrorViewRect.right(), _mirrorViewRect.bottom(), _mirrorViewRect.top()); + glDisable(GL_DEPTH_TEST); + glDisable(GL_LIGHTING); + + glEnable(GL_TEXTURE_2D); + glBindTexture(GL_TEXTURE_2D, _closeTextureId); + + glColor3f(1, 1, 1); + glBegin(GL_QUADS); + + int lp = MIRROR_CLOSE_ICON_PADDING + _mirrorViewRect.left(); + int tp = MIRROR_CLOSE_ICON_PADDING + _mirrorViewRect.top(); + int lwp = MIRROR_ICON_SIZE + lp; + int twp = MIRROR_ICON_SIZE + tp; + + glTexCoord2f(1, 1); + glVertex2f(lp, tp); + + glTexCoord2f(0, 1); + glVertex2f(lwp, tp); + + glTexCoord2f(0, 0); + glVertex2f(lwp, twp); + + glTexCoord2f(1, 0); + glVertex2f(lp, twp); + + glEnd(); + + glPopMatrix(); + + glDisable(GL_TEXTURE_2D); +} diff --git a/interface/src/Application.h b/interface/src/Application.h index 0a563105c1..ed0522c409 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -196,6 +196,7 @@ private slots: private: void resetCamerasOnResizeGL(Camera& camera, int width, int height); void updateProjectionMatrix(); + void updateProjectionMatrix(Camera& camera); static bool sendVoxelsOperation(VoxelNode* node, void* extraData); static void processAvatarURLsMessage(unsigned char* packetData, size_t dataBytes); @@ -240,7 +241,9 @@ private: static void attachNewHeadToNode(Node *newNode); static void* networkReceive(void* args); // network receive thread - void findAxisAlignment(); + void findAxisAlignment(); + + void displayRearMirrorTools(); QMainWindow* _window; QGLWidget* _glWidget; @@ -292,6 +295,9 @@ private: Camera _myCamera; // My view onto the world Camera _viewFrustumOffsetCamera; // The camera we use to sometimes show the view frustum from an offset mode + Camera _mirrorCamera; // Cammera for mirror view + QRect _mirrorViewRect; + GLuint _closeTextureId; Environment _environment; diff --git a/interface/src/Audio.cpp b/interface/src/Audio.cpp index 246ae16b45..4006b484b4 100644 --- a/interface/src/Audio.cpp +++ b/interface/src/Audio.cpp @@ -840,9 +840,9 @@ bool Audio::eventuallyAnalyzePing() { return true; } -void Audio::renderToolIcon(int screenHeigh) { +void Audio::renderToolIcon(int screenHeight) { - _iconBounds = QRect(ICON_LEFT, screenHeigh - BOTTOM_PADDING, ICON_SIZE, ICON_SIZE); + _iconBounds = QRect(ICON_LEFT, screenHeight - BOTTOM_PADDING, ICON_SIZE, ICON_SIZE); glEnable(GL_TEXTURE_2D); glBindTexture(GL_TEXTURE_2D, _micTextureId); diff --git a/interface/src/Camera.cpp b/interface/src/Camera.cpp index 6b99f9db2e..94bc693c2b 100644 --- a/interface/src/Camera.cpp +++ b/interface/src/Camera.cpp @@ -23,7 +23,7 @@ const float CAMERA_THIRD_PERSON_MODE_DISTANCE = 1.5f; const float CAMERA_THIRD_PERSON_MODE_TIGHTNESS = 8.0f; const float CAMERA_MIRROR_MODE_UP_SHIFT = 0.0f; -const float CAMERA_MIRROR_MODE_DISTANCE = 0.3f; +const float CAMERA_MIRROR_MODE_DISTANCE = 0.17f; const float CAMERA_MIRROR_MODE_TIGHTNESS = 100.0f; diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index e1c18089fd..c59f12044f 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -597,7 +597,7 @@ float MyAvatar::getBallRenderAlpha(int ball, bool lookingInMirror) const { void MyAvatar::renderBody(bool lookingInMirror, bool renderAvatarBalls) { - if (Application::getInstance()->getCamera()->getMode() == CAMERA_MODE_FIRST_PERSON) { + if (Application::getInstance()->getCamera()->getMode() == CAMERA_MODE_FIRST_PERSON && !lookingInMirror) { // Dont display body, only the hand _hand.render(lookingInMirror);