diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index bb717e7f9e..f5d7a1eb19 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -199,6 +199,7 @@ Application::Application(int& argc, char** argv, timeval &startup_time) : _mousePressed(false), _mouseVoxelScale(1.0f / 1024.0f), _justEditedVoxel(false), + _isLookingAtOtherAvatar(false), _paintOn(false), _dominantColor(0), _perfStatsOn(false), @@ -235,6 +236,31 @@ Application::Application(int& argc, char** argv, timeval &startup_time) : NodeList::getInstance()->getNodeSocket()->setBlocking(false); } + // setup QSettings +#ifdef Q_WS_MAC + QString resourcesPath = QCoreApplication::applicationDirPath() + "/../Resources"; +#else + QString resourcesPath = QCoreApplication::applicationDirPath() + "/resources"; +#endif + + // read the ApplicationInfo.ini file for Name/Version/Domain information + QSettings applicationInfo(resourcesPath + "/info/ApplicationInfo.ini", QSettings::IniFormat); + + // set the associated application properties + applicationInfo.beginGroup("INFO"); + + setApplicationName(applicationInfo.value("name").toString()); + setApplicationVersion(applicationInfo.value("version").toString()); + setOrganizationName(applicationInfo.value("organizationName").toString()); + setOrganizationDomain(applicationInfo.value("organizationDomain").toString()); + + _settings = new QSettings(this); + + // check if there is a saved domain server hostname + // this must be done now instead of with the other setting checks to allow manual override with + // --domain or --local options + NodeList::getInstance()->loadData(_settings); + const char* domainIP = getCmdOption(argc, constArgv, "--domain"); if (domainIP) { NodeList::getInstance()->setDomainIP(domainIP); @@ -268,23 +294,6 @@ Application::Application(int& argc, char** argv, timeval &startup_time) : _window->setCentralWidget(_glWidget); -#ifdef Q_WS_MAC - QString resourcesPath = QCoreApplication::applicationDirPath() + "/../Resources"; -#else - QString resourcesPath = QCoreApplication::applicationDirPath() + "/resources"; -#endif - - // read the ApplicationInfo.ini file for Name/Version/Domain information - QSettings applicationInfo(resourcesPath + "/info/ApplicationInfo.ini", QSettings::IniFormat); - - // set the associated application properties - applicationInfo.beginGroup("INFO"); - - setApplicationName(applicationInfo.value("name").toString()); - setApplicationVersion(applicationInfo.value("version").toString()); - setOrganizationName(applicationInfo.value("organizationName").toString()); - setOrganizationDomain(applicationInfo.value("organizationDomain").toString()); - #if defined(Q_WS_MAC) && defined(QT_NO_DEBUG) // if this is a release OS X build use fervor to check for an update FvUpdater::sharedUpdater()->SetFeedURL("https://s3-us-west-1.amazonaws.com/highfidelity/appcast.xml"); @@ -1186,11 +1195,18 @@ void Application::editPreferences() { return; } - char newHostname[MAX_HOSTNAME_BYTES] = {}; - memcpy(newHostname, domainServerHostname->text().toAscii().data(), domainServerHostname->text().size()); + QByteArray newHostname; + + if (domainServerHostname->text().size() > 0) { + // the user input a new hostname, use that + newHostname = domainServerHostname->text().toAscii(); + } else { + // the user left the field blank, use the default hostname + newHostname = QByteArray(DEFAULT_DOMAIN_HOSTNAME); + } // check if the domain server hostname is new - if (memcmp(NodeList::getInstance()->getDomainHostname(), newHostname, strlen(newHostname)) != 0) { + if (memcmp(NodeList::getInstance()->getDomainHostname(), newHostname.constData(), newHostname.size()) != 0) { NodeList::getInstance()->clear(); @@ -1200,7 +1216,8 @@ void Application::editPreferences() { // reset the environment to default _environment.resetToDefault(); - NodeList::getInstance()->setDomainHostname(newHostname); + // set the new hostname + NodeList::getInstance()->setDomainHostname(newHostname.constData()); } QUrl url(avatarURL->text()); @@ -1713,6 +1730,8 @@ void Application::initMenu() { _renderFrameTimerOn->setChecked(false); (_renderLookatOn = renderMenu->addAction("Lookat Vectors"))->setCheckable(true); _renderLookatOn->setChecked(false); + (_renderLookatIndicatorOn = renderMenu->addAction("Lookat Indicator"))->setCheckable(true); + _renderLookatIndicatorOn->setChecked(true); (_manualFirstPerson = renderMenu->addAction( "First Person", this, SLOT(setRenderFirstPerson(bool)), Qt::Key_P))->setCheckable(true); (_manualThirdPerson = renderMenu->addAction( @@ -1825,7 +1844,6 @@ void Application::initMenu() { settingsMenu->addAction("Export settings", this, SLOT(exportSettings())); _networkAccessManager = new QNetworkAccessManager(this); - _settings = new QSettings(this); } void Application::updateFrustumRenderModeAction() { @@ -1924,6 +1942,7 @@ bool Application::isLookingAtOtherAvatar(glm::vec3& mouseRayOrigin, glm::vec3& m glm::vec3 headPosition = avatar->getHead().getPosition(); if (rayIntersectsSphere(mouseRayOrigin, mouseRayDirection, headPosition, HEAD_SPHERE_RADIUS)) { eyePosition = avatar->getHead().getEyeLevelPosition(); + _lookatOtherPosition = headPosition; return true; } } @@ -1931,6 +1950,15 @@ bool Application::isLookingAtOtherAvatar(glm::vec3& mouseRayOrigin, glm::vec3& m return false; } +void Application::renderLookatIndicator(glm::vec3 pointOfInterest, Camera& whichCamera) { + + const float DISTANCE_FROM_HEAD_SPHERE = 0.1f; + const float YELLOW[] = { 1.0f, 1.0f, 0.0f }; + glm::vec3 haloOrigin(pointOfInterest.x, pointOfInterest.y + DISTANCE_FROM_HEAD_SPHERE, pointOfInterest.z); + glColor3f(YELLOW[0], YELLOW[1], YELLOW[2]); + renderCircle(haloOrigin, 0.1f, glm::vec3(0.0f, 1.0f, 0.0f), 30); +} + void Application::update(float deltaTime) { // Use Transmitter Hand to move hand if connected, else use mouse if (_myTransmitter.isConnected()) { @@ -1958,7 +1986,7 @@ void Application::update(float deltaTime) { // Set where I am looking based on my mouse ray (so that other people can see) glm::vec3 eyePosition; - if (isLookingAtOtherAvatar(mouseRayOrigin, mouseRayDirection, eyePosition)) { + if (_isLookingAtOtherAvatar = isLookingAtOtherAvatar(mouseRayOrigin, mouseRayDirection, eyePosition)) { // If the mouse is over another avatar's head... glm::vec3 myLookAtFromMouse(eyePosition); _myAvatar.getHead().setLookAtPosition(myLookAtFromMouse); @@ -1975,7 +2003,7 @@ void Application::update(float deltaTime) { glm::vec3 front = orientation * IDENTITY_FRONT; glm::vec3 up = orientation * IDENTITY_UP; glm::vec3 towardVoxel = getMouseVoxelWorldCoordinates(_mouseVoxelDragging) - - _myAvatar.getCameraPosition(); + - _myAvatar.getCameraPosition(); // is this an error? getCameraPosition dne towardVoxel = front * glm::length(towardVoxel); glm::vec3 lateralToVoxel = glm::cross(up, glm::normalize(towardVoxel)) * glm::length(towardVoxel); _voxelThrust = glm::vec3(0, 0, 0); @@ -2222,7 +2250,7 @@ void Application::updateAvatar(float deltaTime) { _viewFrustum.computePickRay(MIDPOINT_OF_SCREEN, MIDPOINT_OF_SCREEN, screenCenterRayOrigin, screenCenterRayDirection); glm::vec3 eyePosition; - if (isLookingAtOtherAvatar(screenCenterRayOrigin, screenCenterRayDirection, eyePosition)) { + if (_isLookingAtOtherAvatar = isLookingAtOtherAvatar(screenCenterRayOrigin, screenCenterRayDirection, eyePosition)) { glm::vec3 myLookAtFromMouse(eyePosition); _myAvatar.getHead().setLookAtPosition(myLookAtFromMouse); } @@ -2250,7 +2278,7 @@ void Application::updateAvatar(float deltaTime) { // actually need to calculate the view frustum planes to send these details // to the server. loadViewFrustum(_myCamera, _viewFrustum); - _myAvatar.setCameraPosition(_viewFrustum.getPosition()); + _myAvatar.setCameraPosition(_viewFrustum.getPosition()); // setCameraPosition() dne _myAvatar.setCameraOrientation(_viewFrustum.getOrientation()); _myAvatar.setCameraFov(_viewFrustum.getFieldOfView()); _myAvatar.setCameraAspectRatio(_viewFrustum.getAspectRatio()); @@ -2621,6 +2649,10 @@ void Application::displaySide(Camera& whichCamera) { } _myAvatar.render(_lookingInMirror->isChecked(), _renderAvatarBalls->isChecked()); _myAvatar.setDisplayingLookatVectors(_renderLookatOn->isChecked()); + + if (_renderLookatIndicatorOn->isChecked() && _isLookingAtOtherAvatar) { + renderLookatIndicator(_lookatOtherPosition, whichCamera); + } } if (TESTING_PARTICLE_SYSTEM) { @@ -3498,7 +3530,7 @@ void Application::saveSettings(QSettings* settings) { if (!settings) { settings = getSettings(); } - + settings->setValue("headCameraPitchYawScale", _headCameraPitchYawScale); settings->setValue("audioJitterBufferSamples", _audioJitterBufferSamples); settings->setValue("horizontalFieldOfView", _horizontalFieldOfView); @@ -3513,6 +3545,9 @@ void Application::saveSettings(QSettings* settings) { scanMenuBar(&Application::saveAction, settings); getAvatar()->saveData(settings); _swatch.saveData(settings); + + // ask the NodeList to save its data + NodeList::getInstance()->saveData(settings); } void Application::importSettings() { diff --git a/interface/src/Application.h b/interface/src/Application.h index 37eadb04f8..d29328c0b5 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -200,6 +200,7 @@ private: void update(float deltaTime); bool isLookingAtOtherAvatar(glm::vec3& mouseRayOrigin, glm::vec3& mouseRayDirection, glm::vec3& eyePosition); + void renderLookatIndicator(glm::vec3 pointOfInterest, Camera& whichCamera); void updateAvatar(float deltaTime); void loadViewFrustum(Camera& camera, ViewFrustum& viewFrustum); @@ -255,6 +256,7 @@ private: QAction* _renderStatsOn; // Whether to show onscreen text overlay with stats QAction* _renderFrameTimerOn; // Whether to show onscreen text overlay with stats QAction* _renderLookatOn; // Whether to show lookat vectors from avatar eyes if looking at something + QAction* _renderLookatIndicatorOn; QAction* _manualFirstPerson; // Whether to force first-person mode QAction* _manualThirdPerson; // Whether to force third-person mode QAction* _logOn; // Whether to show on-screen log @@ -368,6 +370,9 @@ private: float _mouseVoxelScale; // the scale for adding/removing voxels glm::vec3 _lastMouseVoxelPos; // the position of the last mouse voxel edit bool _justEditedVoxel; // set when we've just added/deleted/colored a voxel + + bool _isLookingAtOtherAvatar; + glm::vec3 _lookatOtherPosition; bool _paintOn; // Whether to paint voxels as you fly around unsigned char _dominantColor; // The dominant color of the voxel we're painting diff --git a/interface/src/Util.cpp b/interface/src/Util.cpp index 6aff15240e..0f2c3a8955 100644 --- a/interface/src/Util.cpp +++ b/interface/src/Util.cpp @@ -541,8 +541,6 @@ void runTimingTests() { gettimeofday(&endTime, NULL); elapsedMsecs = diffclock(&startTime, &endTime); qDebug("vec3 assign and dot() usecs: %f\n", 1000.0f * elapsedMsecs / (float) numTests); - - } float loadSetting(QSettings* settings, const char* name, float defaultValue) { diff --git a/interface/src/Util.h b/interface/src/Util.h index 8bc77a98ea..fe59637a42 100644 --- a/interface/src/Util.h +++ b/interface/src/Util.h @@ -71,7 +71,6 @@ void renderCircle(glm::vec3 position, float radius, glm::vec3 surfaceNormal, int void runTimingTests(); - float loadSetting(QSettings* settings, const char* name, float defaultValue); bool rayIntersectsSphere(glm::vec3& rayStarting, glm::vec3& rayNormalizedDirection, glm::vec3& sphereCenter, double sphereRadius); diff --git a/interface/src/avatar/Head.cpp b/interface/src/avatar/Head.cpp index 8ebd5d33df..b8393e26ab 100644 --- a/interface/src/avatar/Head.cpp +++ b/interface/src/avatar/Head.cpp @@ -272,7 +272,7 @@ void Head::calculateGeometry() { + up * _scale * BODY_BALL_RADIUS_HEAD_BASE * EYE_UP_OFFSET + front * _scale * BODY_BALL_RADIUS_HEAD_BASE * EYE_FRONT_OFFSET; - _eyeLevelPosition = _position + up * _scale * EYE_UP_OFFSET; + _eyeLevelPosition = _position + up * _scale * BODY_BALL_RADIUS_HEAD_BASE * EYE_UP_OFFSET; //calculate the eyebrow positions _leftEyeBrowPosition = _leftEyePosition; diff --git a/libraries/shared/src/NodeList.cpp b/libraries/shared/src/NodeList.cpp index 91fe1f4a21..9406c6b14d 100644 --- a/libraries/shared/src/NodeList.cpp +++ b/libraries/shared/src/NodeList.cpp @@ -499,6 +499,37 @@ void NodeList::startSilentNodeRemovalThread() { void NodeList::stopSilentNodeRemovalThread() { silentNodeThreadStopFlag = true; pthread_join(removeSilentNodesThread, NULL); + +} + +const QString QSETTINGS_GROUP_NAME = "NodeList"; +const QString DOMAIN_SERVER_SETTING_KEY = "domainServerHostname"; + +void NodeList::loadData(QSettings *settings) { + settings->beginGroup(DOMAIN_SERVER_SETTING_KEY); + + QString domainServerHostname = settings->value(DOMAIN_SERVER_SETTING_KEY).toString(); + + if (domainServerHostname.size() > 0) { + memset(_domainHostname, 0, MAX_HOSTNAME_BYTES); + memcpy(_domainHostname, domainServerHostname.toAscii().constData(), domainServerHostname.size()); + } + + settings->endGroup(); +} + +void NodeList::saveData(QSettings* settings) { + settings->beginGroup(DOMAIN_SERVER_SETTING_KEY); + + if (memcmp(_domainHostname, DEFAULT_DOMAIN_HOSTNAME, strlen(DEFAULT_DOMAIN_HOSTNAME)) != 0) { + // the user is using a different hostname, store it + settings->setValue(DOMAIN_SERVER_SETTING_KEY, QVariant(_domainHostname)); + } else { + // the user has switched back to default, remove the current setting + settings->remove(DOMAIN_SERVER_SETTING_KEY); + } + + settings->endGroup(); } NodeList::iterator NodeList::begin() const { diff --git a/libraries/shared/src/NodeList.h b/libraries/shared/src/NodeList.h index 0c8a68d38c..2a66fc7374 100644 --- a/libraries/shared/src/NodeList.h +++ b/libraries/shared/src/NodeList.h @@ -14,6 +14,8 @@ #include #include +#include + #include "Node.h" #include "UDPSocket.h" @@ -99,6 +101,9 @@ public: void startSilentNodeRemovalThread(); void stopSilentNodeRemovalThread(); + void loadData(QSettings* settings); + void saveData(QSettings* settings); + friend class NodeListIterator; private: static NodeList* _sharedInstance; diff --git a/libraries/voxels/src/ViewFrustum.cpp b/libraries/voxels/src/ViewFrustum.cpp index c13da815f8..ae48dbbe7d 100644 --- a/libraries/voxels/src/ViewFrustum.cpp +++ b/libraries/voxels/src/ViewFrustum.cpp @@ -364,8 +364,6 @@ bool ViewFrustum::matches(const ViewFrustum& compareTo, bool debug) const { return result; } - - void ViewFrustum::computePickRay(float x, float y, glm::vec3& origin, glm::vec3& direction) const { origin = _nearTopLeft + x*(_nearTopRight - _nearTopLeft) + y*(_nearBottomLeft - _nearTopLeft); direction = glm::normalize(origin - _position);