diff --git a/interface/interface_en.ts b/interface/interface_en.ts index f5c7f225df..da8827d89d 100644 --- a/interface/interface_en.ts +++ b/interface/interface_en.ts @@ -14,12 +14,12 @@ - + Open Script - + JavaScript Files (*.js) @@ -113,18 +113,18 @@ Menu - + Open .ini config file - - + + Text files (*.ini) - + Save .ini config file diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 549d1f04e2..864be460e7 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2712,7 +2712,7 @@ void Application::displayStats() { glm::vec3 avatarPos = _myAvatar->getPosition(); - lines = _statsExpanded ? 4 : 3; + lines = _statsExpanded ? 5 : 3; displayStatsBackground(backgroundColor, horizontalOffset, 0, _glWidget->width() - (mirrorEnabled ? 301 : 411) - horizontalOffset, lines * STATS_PELS_PER_LINE + 10); horizontalOffset += 5; @@ -2749,12 +2749,23 @@ void Application::displayStats() { verticalOffset += STATS_PELS_PER_LINE; drawText(horizontalOffset, verticalOffset, 0.10f, 0.f, 2.f, avatarMixerStats, WHITE_TEXT); + + stringstream downloadStats; + downloadStats << "Downloads: "; + foreach (Resource* resource, ResourceCache::getLoadingRequests()) { + const float MAXIMUM_PERCENTAGE = 100.0f; + downloadStats << roundf(resource->getProgress() * MAXIMUM_PERCENTAGE) << "% "; + } + downloadStats << "(" << ResourceCache::getPendingRequestCount() << " pending)"; + + verticalOffset += STATS_PELS_PER_LINE; + drawText(horizontalOffset, verticalOffset, 0.10f, 0.f, 2.f, downloadStats.str().c_str(), WHITE_TEXT); } verticalOffset = 0; horizontalOffset = _glWidget->width() - (mirrorEnabled ? 300 : 410); - lines = _statsExpanded ? 11 : 3; + lines = _statsExpanded ? 12 : 3; displayStatsBackground(backgroundColor, horizontalOffset, 0, _glWidget->width() - horizontalOffset, lines * STATS_PELS_PER_LINE + 10); horizontalOffset += 5; diff --git a/interface/src/Audio.cpp b/interface/src/Audio.cpp index 35b431896c..612785ff80 100644 --- a/interface/src/Audio.cpp +++ b/interface/src/Audio.cpp @@ -144,6 +144,28 @@ QAudioDeviceInfo defaultAudioDeviceForMode(QAudio::Mode mode) { } } #endif +#ifdef WIN32 + QString deviceName; + if (mode == QAudio::AudioInput) { + WAVEINCAPS wic; + // first use WAVE_MAPPER to get the default devices manufacturer ID + waveInGetDevCaps(WAVE_MAPPER, &wic, sizeof(wic)); + //Use the received manufacturer id to get the device's real name + waveInGetDevCaps(wic.wMid, &wic, sizeof(wic)); + qDebug() << "input device:" << wic.szPname; + deviceName = wic.szPname; + } else { + WAVEOUTCAPS woc; + // first use WAVE_MAPPER to get the default devices manufacturer ID + waveOutGetDevCaps(WAVE_MAPPER, &woc, sizeof(woc)); + //Use the received manufacturer id to get the device's real name + waveOutGetDevCaps(woc.wMid, &woc, sizeof(woc)); + qDebug() << "output device:" << woc.szPname; + deviceName = woc.szPname; + } + return getNamedAudioDeviceForMode(mode, deviceName); +#endif + // fallback for failed lookup is the default device return (mode == QAudio::AudioInput) ? QAudioDeviceInfo::defaultInputDevice() : QAudioDeviceInfo::defaultOutputDevice(); @@ -510,7 +532,7 @@ void Audio::handleAudioInput() { if (audioMixer && audioMixer->getActiveSocket()) { MyAvatar* interfaceAvatar = Application::getInstance()->getAvatar(); glm::vec3 headPosition = interfaceAvatar->getHead()->getPosition(); - glm::quat headOrientation = interfaceAvatar->getHead()->getOrientation(); + glm::quat headOrientation = interfaceAvatar->getHead()->getTweakedOrientation(); // we need the amount of bytes in the buffer + 1 for type // + 12 for 3 floats for position + float for bearing + 1 attenuation byte @@ -850,7 +872,6 @@ bool Audio::switchOutputToAudioDevice(const QAudioDeviceInfo& outputDeviceInfo) // cleanup any previously initialized device if (_audioOutput) { _audioOutput->stop(); - disconnect(_outputDevice, 0, 0, 0); _outputDevice = NULL; delete _audioOutput; diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 30be26ee96..79b0a23ce5 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -62,7 +62,8 @@ Menu* Menu::getInstance() { const ViewFrustumOffset DEFAULT_FRUSTUM_OFFSET = {-135.0f, 0.0f, 0.0f, 25.0f, 0.0f}; const float DEFAULT_FACESHIFT_EYE_DEFLECTION = 0.25f; const float DEFAULT_AVATAR_LOD_DISTANCE_MULTIPLIER = 1.0f; -const int FIVE_SECONDS_OF_FRAMES = 5 * 60; +const int ONE_SECOND_OF_FRAMES = 60; +const int FIVE_SECONDS_OF_FRAMES = 5 * ONE_SECOND_OF_FRAMES; Menu::Menu() : _actionHash(), @@ -82,6 +83,7 @@ Menu::Menu() : _lastAdjust(usecTimestampNow()), _lastAvatarDetailDrop(usecTimestampNow()), _fpsAverage(FIVE_SECONDS_OF_FRAMES), + _fastFPSAverage(ONE_SECOND_OF_FRAMES), _loginAction(NULL) { Application *appInstance = Application::getInstance(); @@ -1192,19 +1194,21 @@ void Menu::autoAdjustLOD(float currentFPS) { currentFPS = ASSUMED_FPS; } _fpsAverage.updateAverage(currentFPS); + _fastFPSAverage.updateAverage(currentFPS); quint64 now = usecTimestampNow(); - if (_fpsAverage.getAverage() < ADJUST_LOD_DOWN_FPS) { - if (now - _lastAvatarDetailDrop > ADJUST_LOD_DOWN_DELAY) { + const quint64 ADJUST_AVATAR_LOD_DOWN_DELAY = 1000 * 1000; + if (_fastFPSAverage.getAverage() < ADJUST_LOD_DOWN_FPS) { + if (now - _lastAvatarDetailDrop > ADJUST_AVATAR_LOD_DOWN_DELAY) { // attempt to lower the detail in proportion to the fps difference float targetFps = (ADJUST_LOD_DOWN_FPS + ADJUST_LOD_UP_FPS) * 0.5f; - _avatarLODDistanceMultiplier *= (targetFps / _fpsAverage.getAverage()); + _avatarLODDistanceMultiplier *= (targetFps / _fastFPSAverage.getAverage()); _lastAvatarDetailDrop = now; } - } else if (_fpsAverage.getAverage() > ADJUST_LOD_UP_FPS) { + } else if (_fastFPSAverage.getAverage() > ADJUST_LOD_UP_FPS) { // let the detail level creep slowly upwards - const float DISTANCE_DECREASE_RATE = 0.01f; + const float DISTANCE_DECREASE_RATE = 0.02f; const float MINIMUM_DISTANCE_MULTIPLIER = 0.1f; _avatarLODDistanceMultiplier = qMax(MINIMUM_DISTANCE_MULTIPLIER, _avatarLODDistanceMultiplier - DISTANCE_DECREASE_RATE); diff --git a/interface/src/Menu.h b/interface/src/Menu.h index 9452ba220d..cab5645304 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -66,8 +66,6 @@ public: static Menu* getInstance(); ~Menu(); - bool isOptionChecked(const QString& menuOption); - void setIsOptionChecked(const QString& menuOption, bool isChecked); void triggerOption(const QString& menuOption); QAction* getActionForOption(const QString& menuOption); @@ -133,6 +131,8 @@ public slots: void removeSeparator(const QString& menuName, const QString& separatorName); void addMenuItem(const MenuItemProperties& properties); void removeMenuItem(const QString& menuName, const QString& menuitem); + bool isOptionChecked(const QString& menuOption); + void setIsOptionChecked(const QString& menuOption, bool isChecked); private slots: void aboutApp(); @@ -211,6 +211,7 @@ private: quint64 _lastAdjust; quint64 _lastAvatarDetailDrop; SimpleMovingAverage _fpsAverage; + SimpleMovingAverage _fastFPSAverage; QAction* _loginAction; QAction* _chatAction; }; diff --git a/interface/src/avatar/Head.cpp b/interface/src/avatar/Head.cpp index b1265a1e51..fc18eed885 100644 --- a/interface/src/avatar/Head.cpp +++ b/interface/src/avatar/Head.cpp @@ -55,9 +55,6 @@ void Head::reset() { _faceModel.reset(); } - - - void Head::simulate(float deltaTime, bool isMine, bool billboard) { // Update audio trailing average for rendering facial animations diff --git a/interface/src/scripting/MenuScriptingInterface.cpp b/interface/src/scripting/MenuScriptingInterface.cpp index ccb3fe5eb9..4f9003b288 100644 --- a/interface/src/scripting/MenuScriptingInterface.cpp +++ b/interface/src/scripting/MenuScriptingInterface.cpp @@ -65,9 +65,15 @@ void MenuScriptingInterface::removeMenuItem(const QString& menu, const QString& }; bool MenuScriptingInterface::isOptionChecked(const QString& menuOption) { - return Menu::getInstance()->isOptionChecked(menuOption); + bool result; + QMetaObject::invokeMethod(Menu::getInstance(), "isOptionChecked", Qt::BlockingQueuedConnection, + Q_RETURN_ARG(bool, result), + Q_ARG(const QString&, menuOption)); + return result; } void MenuScriptingInterface::setIsOptionChecked(const QString& menuOption, bool isChecked) { - return Menu::getInstance()->setIsOptionChecked(menuOption, isChecked); + QMetaObject::invokeMethod(Menu::getInstance(), "setIsOptionChecked", Qt::BlockingQueuedConnection, + Q_ARG(const QString&, menuOption), + Q_ARG(bool, isChecked)); } diff --git a/libraries/script-engine/src/ScriptEngine.cpp b/libraries/script-engine/src/ScriptEngine.cpp index c0834aad9d..1f1eab6baf 100644 --- a/libraries/script-engine/src/ScriptEngine.cpp +++ b/libraries/script-engine/src/ScriptEngine.cpp @@ -463,7 +463,6 @@ void ScriptEngine::timerFired() { if (!callingTimer->isActive()) { // this timer is done, we can kill it - qDebug() << "Deleting a single shot timer"; delete callingTimer; } } diff --git a/libraries/shared/src/ResourceCache.cpp b/libraries/shared/src/ResourceCache.cpp index 6cca856b78..c7858e6e20 100644 --- a/libraries/shared/src/ResourceCache.cpp +++ b/libraries/shared/src/ResourceCache.cpp @@ -63,10 +63,12 @@ void ResourceCache::attemptRequest(Resource* resource) { return; } _requestLimit--; + _loadingRequests.append(resource); resource->makeRequest(); } -void ResourceCache::requestCompleted() { +void ResourceCache::requestCompleted(Resource* resource) { + _loadingRequests.removeOne(resource); _requestLimit++; // look for the highest priority pending request @@ -96,6 +98,7 @@ const int DEFAULT_REQUEST_LIMIT = 10; int ResourceCache::_requestLimit = DEFAULT_REQUEST_LIMIT; QList > ResourceCache::_pendingRequests; +QList ResourceCache::_loadingRequests; Resource::Resource(const QUrl& url, bool delayLoad) : _url(url), @@ -121,7 +124,7 @@ Resource::Resource(const QUrl& url, bool delayLoad) : Resource::~Resource() { if (_reply) { - ResourceCache::requestCompleted(); + ResourceCache::requestCompleted(this); delete _reply; } } @@ -215,7 +218,7 @@ void Resource::handleDownloadProgress(qint64 bytesReceived, qint64 bytesTotal) { _replyTimer->disconnect(this); _replyTimer->deleteLater(); _replyTimer = NULL; - ResourceCache::requestCompleted(); + ResourceCache::requestCompleted(this); downloadFinished(reply); } @@ -250,7 +253,7 @@ void Resource::handleReplyError(QNetworkReply::NetworkError error, QDebug debug) _replyTimer->disconnect(this); _replyTimer->deleteLater(); _replyTimer = NULL; - ResourceCache::requestCompleted(); + ResourceCache::requestCompleted(this); // retry for certain types of failures switch (error) { diff --git a/libraries/shared/src/ResourceCache.h b/libraries/shared/src/ResourceCache.h index a544f43731..2fcda0bb98 100644 --- a/libraries/shared/src/ResourceCache.h +++ b/libraries/shared/src/ResourceCache.h @@ -37,6 +37,10 @@ public: static void setRequestLimit(int limit) { _requestLimit = limit; } static int getRequestLimit() { return _requestLimit; } + static const QList& getLoadingRequests() { return _loadingRequests; } + + static int getPendingRequestCount() { return _pendingRequests.size(); } + ResourceCache(QObject* parent = NULL); virtual ~ResourceCache(); @@ -58,7 +62,7 @@ protected: void addUnusedResource(const QSharedPointer& resource); static void attemptRequest(Resource* resource); - static void requestCompleted(); + static void requestCompleted(Resource* resource); private: @@ -70,6 +74,7 @@ private: static QNetworkAccessManager* _networkAccessManager; static int _requestLimit; static QList > _pendingRequests; + static QList _loadingRequests; }; /// Base class for resources. @@ -102,6 +107,15 @@ public: /// Checks whether the resource has loaded. bool isLoaded() const { return _loaded; } + /// For loading resources, returns the number of bytes received. + qint64 getBytesReceived() const { return _bytesReceived; } + + /// For loading resources, returns the number of total bytes (or zero if unknown). + qint64 getBytesTotal() const { return _bytesTotal; } + + /// For loading resources, returns the load progress. + float getProgress() const { return (_bytesTotal == 0) ? 0.0f : (float)_bytesReceived / _bytesTotal; } + void setSelf(const QWeakPointer& self) { _self = self; } void setCache(ResourceCache* cache) { _cache = cache; } @@ -152,6 +166,7 @@ private: int _lruKey; QNetworkReply* _reply; QTimer* _replyTimer; + int _index; qint64 _bytesReceived; qint64 _bytesTotal; int _attempts;