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 13c05fa702..edeb454f11 100644
--- a/interface/src/Application.cpp
+++ b/interface/src/Application.cpp
@@ -2676,7 +2676,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;
@@ -2713,12 +2713,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/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 983264ea55..cab5645304 100644
--- a/interface/src/Menu.h
+++ b/interface/src/Menu.h
@@ -211,6 +211,7 @@ private:
quint64 _lastAdjust;
quint64 _lastAvatarDetailDrop;
SimpleMovingAverage _fpsAverage;
+ SimpleMovingAverage _fastFPSAverage;
QAction* _loginAction;
QAction* _chatAction;
};
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;