diff --git a/cmake/modules/FindLibOVR.cmake b/cmake/modules/FindLibOVR.cmake index c07b4c14c1..415eeeb1c5 100644 --- a/cmake/modules/FindLibOVR.cmake +++ b/cmake/modules/FindLibOVR.cmake @@ -49,7 +49,7 @@ else (LIBOVR_LIBRARIES AND LIBOVR_INCLUDE_DIRS) set(WINDOWS_LIBOVR_NAME "libovr.lib") endif() - find_library(LIBOVR_LIBRARIES "Lib/Win32/${LIBOVR_NAME}" HINTS ${LIBOVR_SEARCH_DIRS}) + find_library(LIBOVR_LIBRARIES "Lib/Win32/VS2010/${LIBOVR_NAME}" HINTS ${LIBOVR_SEARCH_DIRS}) endif () if (LIBOVR_INCLUDE_DIRS AND LIBOVR_LIBRARIES) diff --git a/interface/resources/sounds/mention/Mentioned A.wav b/interface/resources/mention-sounds/Mentioned A.wav similarity index 100% rename from interface/resources/sounds/mention/Mentioned A.wav rename to interface/resources/mention-sounds/Mentioned A.wav diff --git a/interface/resources/sounds/mention/Mentioned B.wav b/interface/resources/mention-sounds/Mentioned B.wav similarity index 100% rename from interface/resources/sounds/mention/Mentioned B.wav rename to interface/resources/mention-sounds/Mentioned B.wav diff --git a/interface/resources/sounds/mention/Mentioned C.wav b/interface/resources/mention-sounds/Mentioned C.wav similarity index 100% rename from interface/resources/sounds/mention/Mentioned C.wav rename to interface/resources/mention-sounds/Mentioned C.wav diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 0b59fc3aa2..8858b6d324 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -686,11 +686,8 @@ void Application::resizeGL(int width, int height) { glLoadIdentity(); // update Stats width - int horizontalOffset = 0; - if (Menu::getInstance()->isOptionChecked(MenuOption::Mirror)) { - // mirror is enabled, let's set horizontal offset to give stats some margin - horizontalOffset += MIRROR_VIEW_WIDTH + MIRROR_VIEW_LEFT_PADDING * 2; - } + // let's set horizontal offset to give stats some margin to mirror + int horizontalOffset = MIRROR_VIEW_WIDTH + MIRROR_VIEW_LEFT_PADDING * 2; Stats::getInstance()->resetWidth(width, horizontalOffset); } @@ -1164,10 +1161,8 @@ void Application::mouseReleaseEvent(QMouseEvent* event) { _mousePressed = false; checkBandwidthMeterClick(); if (Menu::getInstance()->isOptionChecked(MenuOption::Stats)) { - int horizontalOffset = 0; - if (Menu::getInstance()->isOptionChecked(MenuOption::Mirror)) { - horizontalOffset = MIRROR_VIEW_WIDTH; - } + // let's set horizontal offset to give stats some margin to mirror + int horizontalOffset = MIRROR_VIEW_WIDTH; Stats::getInstance()->checkClick(_mouseX, _mouseY, _mouseDragStartedX, _mouseDragStartedY, horizontalOffset); } } @@ -2732,11 +2727,8 @@ void Application::displayOverlay() { glPointSize(1.0f); if (Menu::getInstance()->isOptionChecked(MenuOption::Stats)) { - int horizontalOffset = 0; - if (Menu::getInstance()->isOptionChecked(MenuOption::Mirror)) { - // mirror is enabled, let's set horizontal offset to give stats some margin - horizontalOffset += MIRROR_VIEW_WIDTH + MIRROR_VIEW_LEFT_PADDING * 2; - } + // let's set horizontal offset to give stats some margin to mirror + int horizontalOffset = MIRROR_VIEW_WIDTH + MIRROR_VIEW_LEFT_PADDING * 2; int voxelPacketsToProcess = _voxelProcessor.packetsToProcessCount(); // Onscreen text about position, servers, etc Stats::getInstance()->display(WHITE_TEXT, horizontalOffset, _fps, _packetsPerSecond, _bytesPerSecond, voxelPacketsToProcess); diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index e1d0c6a574..2daf5b0240 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -889,7 +889,7 @@ void Menu::goToDomainDialog() { } void Menu::goToOrientation(QString orientation) { - LocationManager::getInstance().goToDestination(orientation); + LocationManager::getInstance().goToOrientation(orientation); } bool Menu::goToDestination(QString destination) { diff --git a/interface/src/ModelUploader.cpp b/interface/src/ModelUploader.cpp index ce8691998d..ec7fcee6f2 100644 --- a/interface/src/ModelUploader.cpp +++ b/interface/src/ModelUploader.cpp @@ -49,7 +49,7 @@ static const QString TRANSLATION_Z_FIELD = "tz"; static const QString JOINT_FIELD = "joint"; static const QString FREE_JOINT_FIELD = "freeJoint"; -static const QString S3_URL = "http://highfidelity-public.s3-us-west-1.amazonaws.com"; +static const QString S3_URL = "http://public.highfidelity.io"; static const QString DATA_SERVER_URL = "https://data-web.highfidelity.io"; static const QString MODEL_URL = "/api/v1/models"; @@ -201,12 +201,15 @@ bool ModelUploader::zip() { mapping = properties.getMapping(); QByteArray nameField = mapping.value(NAME_FIELD).toByteArray(); + QString urlBase; if (!nameField.isEmpty()) { QHttpPart textPart; textPart.setHeader(QNetworkRequest::ContentDispositionHeader, "form-data; name=\"model_name\""); textPart.setBody(nameField); _dataMultiPart->append(textPart); - _url = S3_URL + "/models/" + MODEL_TYPE_NAMES[_modelType] + "/" + nameField + ".fst"; + urlBase = S3_URL + "/models/" + MODEL_TYPE_NAMES[_modelType] + "/" + nameField; + _url = urlBase + ".fst"; + } else { QMessageBox::warning(NULL, QString("ModelUploader::zip()"), @@ -218,6 +221,7 @@ bool ModelUploader::zip() { QByteArray texdirField = mapping.value(TEXDIR_FIELD).toByteArray(); QString texDir; + _textureBase = urlBase + "/textures/"; if (!texdirField.isEmpty()) { texDir = basePath + "/" + texdirField; QFileInfo texInfo(texDir); @@ -407,6 +411,10 @@ void ModelUploader::processCheck() { QString("ModelUploader::processCheck()"), QString("Your model is now available in the browser."), QMessageBox::Ok); + Application::getInstance()->getGeometryCache()->refresh(_url); + foreach (const QByteArray& filename, _textureFilenames) { + Application::getInstance()->getTextureCache()->refresh(_textureBase + filename); + } deleteLater(); break; case QNetworkReply::ContentNotFoundError: @@ -428,32 +436,31 @@ void ModelUploader::processCheck() { } bool ModelUploader::addTextures(const QString& texdir, const FBXGeometry& geometry) { - QSet added; foreach (FBXMesh mesh, geometry.meshes) { foreach (FBXMeshPart part, mesh.parts) { if (!part.diffuseTexture.filename.isEmpty() && part.diffuseTexture.content.isEmpty() && - !added.contains(part.diffuseTexture.filename)) { + !_textureFilenames.contains(part.diffuseTexture.filename)) { if (!addPart(texdir + "/" + part.diffuseTexture.filename, QString("texture%1").arg(++_texturesCount), true)) { return false; } - added.insert(part.diffuseTexture.filename); + _textureFilenames.insert(part.diffuseTexture.filename); } if (!part.normalTexture.filename.isEmpty() && part.normalTexture.content.isEmpty() && - !added.contains(part.normalTexture.filename)) { + !_textureFilenames.contains(part.normalTexture.filename)) { if (!addPart(texdir + "/" + part.normalTexture.filename, QString("texture%1").arg(++_texturesCount), true)) { return false; } - added.insert(part.normalTexture.filename); + _textureFilenames.insert(part.normalTexture.filename); } if (!part.specularTexture.filename.isEmpty() && part.specularTexture.content.isEmpty() && - !added.contains(part.specularTexture.filename)) { + !_textureFilenames.contains(part.specularTexture.filename)) { if (!addPart(texdir + "/" + part.specularTexture.filename, QString("texture%1").arg(++_texturesCount), true)) { return false; } - added.insert(part.specularTexture.filename); + _textureFilenames.insert(part.specularTexture.filename); } } } diff --git a/interface/src/ModelUploader.h b/interface/src/ModelUploader.h index 766bd55318..634de05640 100644 --- a/interface/src/ModelUploader.h +++ b/interface/src/ModelUploader.h @@ -49,6 +49,8 @@ private slots: private: QString _url; + QString _textureBase; + QSet _textureFilenames; int _lodCount; int _texturesCount; int _totalSize; diff --git a/interface/src/XmppClient.cpp b/interface/src/XmppClient.cpp index 2d421b1afa..666906681c 100644 --- a/interface/src/XmppClient.cpp +++ b/interface/src/XmppClient.cpp @@ -16,7 +16,7 @@ #include "XmppClient.h" const QString DEFAULT_XMPP_SERVER = "chat.highfidelity.io"; -const QString DEFAULT_CHAT_ROOM = "test@public-chat.highfidelity.io"; +const QString DEFAULT_CHAT_ROOM = "public@public-chat.highfidelity.io"; XmppClient::XmppClient() : _xmppClient(), diff --git a/interface/src/avatar/Hand.cpp b/interface/src/avatar/Hand.cpp index ee7a633a54..5f168c4f45 100644 --- a/interface/src/avatar/Hand.cpp +++ b/interface/src/avatar/Hand.cpp @@ -161,9 +161,9 @@ void Hand::render(bool isMine, Model::RenderMode renderMode) { } void Hand::renderHandTargets(bool isMine) { + glPushMatrix(); const float alpha = 1.0f; - const glm::vec3 handColor(1.0, 0.0, 0.0); // Color the hand targets red to be different than skin glEnable(GL_DEPTH_TEST); diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 52eff6e2ce..36c51dc9fd 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -520,8 +520,9 @@ void MyAvatar::saveAttachmentData(const AttachmentData& attachment) const { settings->beginGroup("savedAttachmentData"); settings->beginGroup(_skeletonModel.getURL().toString()); settings->beginGroup(attachment.modelURL.toString()); - settings->setValue("jointName", attachment.jointName); + + settings->beginGroup(attachment.jointName); settings->setValue("translation_x", attachment.translation.x); settings->setValue("translation_y", attachment.translation.y); settings->setValue("translation_z", attachment.translation.z); @@ -534,10 +535,11 @@ void MyAvatar::saveAttachmentData(const AttachmentData& attachment) const { settings->endGroup(); settings->endGroup(); settings->endGroup(); + settings->endGroup(); Application::getInstance()->unlockSettings(); } -AttachmentData MyAvatar::loadAttachmentData(const QUrl& modelURL) const { +AttachmentData MyAvatar::loadAttachmentData(const QUrl& modelURL, const QString& jointName) const { QSettings* settings = Application::getInstance()->lockSettings(); settings->beginGroup("savedAttachmentData"); settings->beginGroup(_skeletonModel.getURL().toString()); @@ -545,20 +547,30 @@ AttachmentData MyAvatar::loadAttachmentData(const QUrl& modelURL) const { AttachmentData attachment; attachment.modelURL = modelURL; - attachment.jointName = settings->value("jointName").toString(); - attachment.translation.x = loadSetting(settings, "translation_x", 0.0f); - attachment.translation.y = loadSetting(settings, "translation_y", 0.0f); - attachment.translation.z = loadSetting(settings, "translation_z", 0.0f); - glm::vec3 eulers; - eulers.x = loadSetting(settings, "rotation_x", 0.0f); - eulers.y = loadSetting(settings, "rotation_y", 0.0f); - eulers.z = loadSetting(settings, "rotation_z", 0.0f); - attachment.rotation = glm::quat(eulers); - attachment.scale = loadSetting(settings, "scale", 1.0f); + if (jointName.isEmpty()) { + attachment.jointName = settings->value("jointName").toString(); + } else { + attachment.jointName = jointName; + } + settings->beginGroup(attachment.jointName); + if (settings->contains("translation_x")) { + attachment.translation.x = loadSetting(settings, "translation_x", 0.0f); + attachment.translation.y = loadSetting(settings, "translation_y", 0.0f); + attachment.translation.z = loadSetting(settings, "translation_z", 0.0f); + glm::vec3 eulers; + eulers.x = loadSetting(settings, "rotation_x", 0.0f); + eulers.y = loadSetting(settings, "rotation_y", 0.0f); + eulers.z = loadSetting(settings, "rotation_z", 0.0f); + attachment.rotation = glm::quat(eulers); + attachment.scale = loadSetting(settings, "scale", 1.0f); + } else { + attachment = AttachmentData(); + } settings->endGroup(); settings->endGroup(); settings->endGroup(); + settings->endGroup(); Application::getInstance()->unlockSettings(); return attachment; @@ -650,8 +662,8 @@ void MyAvatar::attach(const QString& modelURL, const QString& jointName, const g return; } if (useSaved) { - AttachmentData attachment = loadAttachmentData(modelURL); - if (!attachment.jointName.isEmpty()) { + AttachmentData attachment = loadAttachmentData(modelURL, jointName); + if (attachment.isValid()) { Avatar::attach(modelURL, attachment.jointName, attachment.translation, attachment.rotation, attachment.scale, allowDuplicates, useSaved); return; @@ -1490,7 +1502,7 @@ void MyAvatar::updateMotionBehaviorsFromMenu() { } void MyAvatar::renderAttachments(RenderMode renderMode) { - if (!Application::getInstance()->getCamera()->getMode() == CAMERA_MODE_FIRST_PERSON || renderMode == MIRROR_RENDER_MODE) { + if (Application::getInstance()->getCamera()->getMode() != CAMERA_MODE_FIRST_PERSON || renderMode == MIRROR_RENDER_MODE) { Avatar::renderAttachments(renderMode); return; } diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index 2e47d9c973..d446c2e895 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -67,7 +67,7 @@ public: void loadData(QSettings* settings); void saveAttachmentData(const AttachmentData& attachment) const; - AttachmentData loadAttachmentData(const QUrl& modelURL) const; + AttachmentData loadAttachmentData(const QUrl& modelURL, const QString& jointName = QString()) const; // Set what driving keys are being pressed to control thrust levels void setDriveKeys(int key, float val) { _driveKeys[key] = val; }; diff --git a/interface/src/devices/SixenseManager.cpp b/interface/src/devices/SixenseManager.cpp index 1698cebcf9..547642a1be 100644 --- a/interface/src/devices/SixenseManager.cpp +++ b/interface/src/devices/SixenseManager.cpp @@ -106,7 +106,7 @@ void SixenseManager::update(float deltaTime) { palm->setControllerButtons(data->buttons); palm->setTrigger(data->trigger); palm->setJoystick(data->joystick_x, data->joystick_y); - + // NOTE: Sixense API returns pos data in millimeters but we IMMEDIATELY convert to meters. glm::vec3 position(data->pos[0], data->pos[1], data->pos[2]); position *= METERS_PER_MILLIMETER; diff --git a/interface/src/devices/Visage.cpp b/interface/src/devices/Visage.cpp index a467d2d4a8..8173519478 100644 --- a/interface/src/devices/Visage.cpp +++ b/interface/src/devices/Visage.cpp @@ -41,7 +41,11 @@ Visage::Visage() : _headOrigin(DEFAULT_HEAD_ORIGIN) { #ifdef HAVE_VISAGE +#ifdef WIN32 + QByteArray licensePath = Application::resourcesPath().toLatin1() + "visage"; +#else QByteArray licensePath = Application::resourcesPath().toLatin1() + "visage/license.vlc"; +#endif initializeLicenseManager(licensePath.data()); _tracker = new VisageTracker2(Application::resourcesPath().toLatin1() + "visage/tracker.cfg"); _data = new FaceData(); diff --git a/interface/src/renderer/GeometryCache.cpp b/interface/src/renderer/GeometryCache.cpp index 8d31cdce1d..ec68c87a76 100644 --- a/interface/src/renderer/GeometryCache.cpp +++ b/interface/src/renderer/GeometryCache.cpp @@ -506,6 +506,15 @@ void GeometryReader::run() { _reply->deleteLater(); } +void NetworkGeometry::init() { + _mapping = QVariantHash(); + _geometry = FBXGeometry(); + _meshes.clear(); + _lods.clear(); + _request.setUrl(_url); + Resource::init(); +} + void NetworkGeometry::downloadFinished(QNetworkReply* reply) { QUrl url = reply->url(); if (url.path().toLower().endsWith(".fst")) { diff --git a/interface/src/renderer/GeometryCache.h b/interface/src/renderer/GeometryCache.h index a9b274fedc..deecfd56c5 100644 --- a/interface/src/renderer/GeometryCache.h +++ b/interface/src/renderer/GeometryCache.h @@ -96,6 +96,7 @@ public: protected: + virtual void init(); virtual void downloadFinished(QNetworkReply* reply); virtual void reinsert(); diff --git a/interface/src/renderer/Model.cpp b/interface/src/renderer/Model.cpp index 0c688865f3..68eccc8f49 100644 --- a/interface/src/renderer/Model.cpp +++ b/interface/src/renderer/Model.cpp @@ -319,6 +319,9 @@ bool Model::updateGeometry() { _jointStates = createJointStates(fbxGeometry); needToRebuild = true; } + } else if (!geometry->isLoaded()) { + deleteGeometry(); + _dilatedTextures.clear(); } _geometry->setLoadPriority(this, -_lodDistance); _geometry->ensureLoading(); diff --git a/interface/src/ui/AttachmentsDialog.cpp b/interface/src/ui/AttachmentsDialog.cpp index f9f49738e9..44dd2452e6 100644 --- a/interface/src/ui/AttachmentsDialog.cpp +++ b/interface/src/ui/AttachmentsDialog.cpp @@ -97,7 +97,8 @@ static QDoubleSpinBox* createRotationBox(AttachmentPanel* panel, float value) { } AttachmentPanel::AttachmentPanel(AttachmentsDialog* dialog, const AttachmentData& data) : - _dialog(dialog) { + _dialog(dialog), + _applying(false) { setFrameStyle(QFrame::StyledPanel); QFormLayout* layout = new QFormLayout(); @@ -121,7 +122,7 @@ AttachmentPanel::AttachmentPanel(AttachmentsDialog* dialog, const AttachmentData } } _jointName->setCurrentText(data.jointName); - connect(_jointName, SIGNAL(currentIndexChanged(int)), SLOT(updateAttachmentData())); + connect(_jointName, SIGNAL(currentIndexChanged(int)), SLOT(jointNameChanged())); QHBoxLayout* translationBox = new QHBoxLayout(); translationBox->addWidget(_translationX = createTranslationBox(this, data.translation.x)); @@ -171,25 +172,57 @@ void AttachmentPanel::setModelURL(const QString& url) { void AttachmentPanel::modelURLChanged() { // check for saved attachment data + if (_modelURL->text().isEmpty()) { + _dialog->updateAttachmentData(); + return; + } AttachmentData attachment = Application::getInstance()->getAvatar()->loadAttachmentData(_modelURL->text()); - if (!attachment.jointName.isEmpty()) { + if (attachment.isValid()) { + _applying = true; _jointName->setCurrentText(attachment.jointName); - _translationX->setValue(attachment.translation.x); - _translationY->setValue(attachment.translation.y); - _translationZ->setValue(attachment.translation.z); - glm::vec3 eulers = glm::degrees(safeEulerAngles(attachment.rotation)); - _rotationX->setValue(eulers.x); - _rotationY->setValue(eulers.y); - _rotationZ->setValue(eulers.z); - _scale->setValue(attachment.scale); + applyAttachmentData(attachment); } _dialog->updateAttachmentData(); } +void AttachmentPanel::jointNameChanged() { + if (_applying) { + return; + } + // check for saved attachment data specific to this joint + if (_modelURL->text().isEmpty()) { + _dialog->updateAttachmentData(); + return; + } + AttachmentData attachment = Application::getInstance()->getAvatar()->loadAttachmentData( + _modelURL->text(), _jointName->currentText()); + if (attachment.isValid()) { + applyAttachmentData(attachment); + } + updateAttachmentData(); +} + void AttachmentPanel::updateAttachmentData() { + if (_applying) { + return; + } // save the attachment data under the model URL (if any) if (!_modelURL->text().isEmpty()) { Application::getInstance()->getAvatar()->saveAttachmentData(getAttachmentData()); } _dialog->updateAttachmentData(); } + +void AttachmentPanel::applyAttachmentData(const AttachmentData& attachment) { + _applying = true; + _translationX->setValue(attachment.translation.x); + _translationY->setValue(attachment.translation.y); + _translationZ->setValue(attachment.translation.z); + glm::vec3 eulers = glm::degrees(safeEulerAngles(attachment.rotation)); + _rotationX->setValue(eulers.x); + _rotationY->setValue(eulers.y); + _rotationZ->setValue(eulers.z); + _scale->setValue(attachment.scale); + _applying = false; + _dialog->updateAttachmentData(); +} diff --git a/interface/src/ui/AttachmentsDialog.h b/interface/src/ui/AttachmentsDialog.h index 7e9319fba8..59696c96f1 100644 --- a/interface/src/ui/AttachmentsDialog.h +++ b/interface/src/ui/AttachmentsDialog.h @@ -61,10 +61,13 @@ private slots: void chooseModelURL(); void setModelURL(const QString& url); void modelURLChanged(); + void jointNameChanged(); void updateAttachmentData(); private: + void applyAttachmentData(const AttachmentData& attachment); + AttachmentsDialog* _dialog; QLineEdit* _modelURL; QComboBox* _jointName; @@ -75,6 +78,7 @@ private: QDoubleSpinBox* _rotationY; QDoubleSpinBox* _rotationZ; QDoubleSpinBox* _scale; + bool _applying; }; #endif // hifi_AttachmentsDialog_h diff --git a/interface/src/ui/ChatWindow.cpp b/interface/src/ui/ChatWindow.cpp index fce900f352..611f955031 100644 --- a/interface/src/ui/ChatWindow.cpp +++ b/interface/src/ui/ChatWindow.cpp @@ -32,7 +32,7 @@ const int NUM_MESSAGES_TO_TIME_STAMP = 20; const QRegularExpression regexLinks("((?:(?:ftp)|(?:https?)|(?:hifi))://\\S+)"); const QRegularExpression regexHifiLinks("([#@]\\S+)"); -const QString mentionSoundsPath("/sounds/mention/"); +const QString mentionSoundsPath("/mention-sounds/"); const QString mentionRegex("@(\\b%1\\b)"); ChatWindow::ChatWindow(QWidget* parent) : diff --git a/libraries/avatars/src/AvatarData.h b/libraries/avatars/src/AvatarData.h index dd604d06f5..072070e98c 100755 --- a/libraries/avatars/src/AvatarData.h +++ b/libraries/avatars/src/AvatarData.h @@ -352,6 +352,8 @@ public: AttachmentData(); + bool isValid() const { return modelURL.isValid(); } + bool operator==(const AttachmentData& other) const; }; diff --git a/libraries/avatars/src/HandData.cpp b/libraries/avatars/src/HandData.cpp index 0105145466..c0553a2b57 100644 --- a/libraries/avatars/src/HandData.cpp +++ b/libraries/avatars/src/HandData.cpp @@ -114,7 +114,7 @@ glm::vec3 PalmData::getFingerTipPosition() const { glm::vec3 palmOffset(0.0f, -0.08f, 0.0f); return getPosition() + _owningHandData->localToWorldDirection(_rawRotation * (fingerOffset + palmOffset)); } - + glm::vec3 PalmData::getFingerDirection() const { const glm::vec3 LOCAL_FINGER_DIRECTION(0.0f, 0.0f, 1.0f); return _owningHandData->localToWorldDirection(_rawRotation * LOCAL_FINGER_DIRECTION); diff --git a/libraries/avatars/src/HandData.h b/libraries/avatars/src/HandData.h index 505b1b600a..7e8622f518 100755 --- a/libraries/avatars/src/HandData.h +++ b/libraries/avatars/src/HandData.h @@ -45,7 +45,7 @@ public: glm::vec3 localToWorldDirection(const glm::vec3& localVector) { return getBaseOrientation() * localVector; - } + } glm::vec3 worldToLocalVector(const glm::vec3& worldVector) const; diff --git a/libraries/shared/src/ResourceCache.cpp b/libraries/shared/src/ResourceCache.cpp index 2f26e344fd..14998232d6 100644 --- a/libraries/shared/src/ResourceCache.cpp +++ b/libraries/shared/src/ResourceCache.cpp @@ -30,6 +30,13 @@ ResourceCache::~ResourceCache() { } } +void ResourceCache::refresh(const QUrl& url) { + QSharedPointer resource = _resources.value(url); + if (!resource.isNull()) { + resource->refresh(); + } +} + QSharedPointer ResourceCache::getResource(const QUrl& url, const QUrl& fallback, bool delayLoad, void* extra) { if (!url.isValid() && !url.isEmpty() && fallback.isValid()) { return getResource(fallback, QUrl(), delayLoad); @@ -107,25 +114,15 @@ QList ResourceCache::_loadingRequests; Resource::Resource(const QUrl& url, bool delayLoad) : _url(url), _request(url), - _startedLoading(false), - _failedToLoad(false), - _loaded(false), _lruKey(0), - _reply(NULL), - _attempts(0) { + _reply(NULL) { + + init(); - if (url.isEmpty()) { - _startedLoading = _loaded = true; - return; - - } else if (!(url.isValid() && ResourceCache::getNetworkAccessManager())) { - _startedLoading = _failedToLoad = true; - return; - } _request.setAttribute(QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::PreferCache); // start loading immediately unless instructed otherwise - if (!delayLoad) { + if (!(_startedLoading || delayLoad)) { attemptRequest(); } } @@ -178,6 +175,22 @@ float Resource::getLoadPriority() { return highestPriority; } +void Resource::refresh() { + if (_reply == NULL && !(_loaded || _failedToLoad)) { + return; + } + if (_reply) { + ResourceCache::requestCompleted(this); + delete _reply; + _reply = NULL; + } + init(); + _request.setAttribute(QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::AlwaysNetwork); + if (!_startedLoading) { + attemptRequest(); + } +} + void Resource::allReferencesCleared() { if (QThread::currentThread() != thread()) { QMetaObject::invokeMethod(this, "allReferencesCleared"); @@ -197,6 +210,20 @@ void Resource::allReferencesCleared() { } } +void Resource::init() { + _startedLoading = false; + _failedToLoad = false; + _loaded = false; + _attempts = 0; + + if (_url.isEmpty()) { + _startedLoading = _loaded = true; + + } else if (!(_url.isValid() && ResourceCache::getNetworkAccessManager())) { + _startedLoading = _failedToLoad = true; + } +} + void Resource::attemptRequest() { _startedLoading = true; ResourceCache::attemptRequest(this); diff --git a/libraries/shared/src/ResourceCache.h b/libraries/shared/src/ResourceCache.h index 0cfabd26fc..2404485c46 100644 --- a/libraries/shared/src/ResourceCache.h +++ b/libraries/shared/src/ResourceCache.h @@ -47,6 +47,8 @@ public: ResourceCache(QObject* parent = NULL); virtual ~ResourceCache(); + void refresh(const QUrl& url); + protected: QMap > _unusedResources; @@ -119,6 +121,9 @@ public: /// For loading resources, returns the load progress. float getProgress() const { return (_bytesTotal == 0) ? 0.0f : (float)_bytesReceived / _bytesTotal; } + /// Refreshes the resource. + void refresh(); + void setSelf(const QWeakPointer& self) { _self = self; } void setCache(ResourceCache* cache) { _cache = cache; } @@ -131,6 +136,8 @@ protected slots: protected: + virtual void init(); + /// Called when the download has finished. The recipient should delete the reply when done with it. virtual void downloadFinished(QNetworkReply* reply) = 0;