Merge pull request #2832 from ey6es/master

After uploading new models, refresh locally cached versions so that the change is immediately apparent.
This commit is contained in:
AndrewMeadows 2014-05-12 14:32:23 -07:00
commit 5a0f4e99a5
12 changed files with 157 additions and 50 deletions

View file

@ -49,7 +49,7 @@ static const QString TRANSLATION_Z_FIELD = "tz";
static const QString JOINT_FIELD = "joint"; static const QString JOINT_FIELD = "joint";
static const QString FREE_JOINT_FIELD = "freeJoint"; 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 DATA_SERVER_URL = "https://data-web.highfidelity.io";
static const QString MODEL_URL = "/api/v1/models"; static const QString MODEL_URL = "/api/v1/models";
@ -201,12 +201,15 @@ bool ModelUploader::zip() {
mapping = properties.getMapping(); mapping = properties.getMapping();
QByteArray nameField = mapping.value(NAME_FIELD).toByteArray(); QByteArray nameField = mapping.value(NAME_FIELD).toByteArray();
QString urlBase;
if (!nameField.isEmpty()) { if (!nameField.isEmpty()) {
QHttpPart textPart; QHttpPart textPart;
textPart.setHeader(QNetworkRequest::ContentDispositionHeader, "form-data; name=\"model_name\""); textPart.setHeader(QNetworkRequest::ContentDispositionHeader, "form-data; name=\"model_name\"");
textPart.setBody(nameField); textPart.setBody(nameField);
_dataMultiPart->append(textPart); _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 { } else {
QMessageBox::warning(NULL, QMessageBox::warning(NULL,
QString("ModelUploader::zip()"), QString("ModelUploader::zip()"),
@ -218,6 +221,7 @@ bool ModelUploader::zip() {
QByteArray texdirField = mapping.value(TEXDIR_FIELD).toByteArray(); QByteArray texdirField = mapping.value(TEXDIR_FIELD).toByteArray();
QString texDir; QString texDir;
_textureBase = urlBase + "/textures/";
if (!texdirField.isEmpty()) { if (!texdirField.isEmpty()) {
texDir = basePath + "/" + texdirField; texDir = basePath + "/" + texdirField;
QFileInfo texInfo(texDir); QFileInfo texInfo(texDir);
@ -407,6 +411,10 @@ void ModelUploader::processCheck() {
QString("ModelUploader::processCheck()"), QString("ModelUploader::processCheck()"),
QString("Your model is now available in the browser."), QString("Your model is now available in the browser."),
QMessageBox::Ok); QMessageBox::Ok);
Application::getInstance()->getGeometryCache()->refresh(_url);
foreach (const QByteArray& filename, _textureFilenames) {
Application::getInstance()->getTextureCache()->refresh(_textureBase + filename);
}
deleteLater(); deleteLater();
break; break;
case QNetworkReply::ContentNotFoundError: case QNetworkReply::ContentNotFoundError:
@ -428,32 +436,31 @@ void ModelUploader::processCheck() {
} }
bool ModelUploader::addTextures(const QString& texdir, const FBXGeometry& geometry) { bool ModelUploader::addTextures(const QString& texdir, const FBXGeometry& geometry) {
QSet<QByteArray> added;
foreach (FBXMesh mesh, geometry.meshes) { foreach (FBXMesh mesh, geometry.meshes) {
foreach (FBXMeshPart part, mesh.parts) { foreach (FBXMeshPart part, mesh.parts) {
if (!part.diffuseTexture.filename.isEmpty() && part.diffuseTexture.content.isEmpty() && 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, if (!addPart(texdir + "/" + part.diffuseTexture.filename,
QString("texture%1").arg(++_texturesCount), true)) { QString("texture%1").arg(++_texturesCount), true)) {
return false; return false;
} }
added.insert(part.diffuseTexture.filename); _textureFilenames.insert(part.diffuseTexture.filename);
} }
if (!part.normalTexture.filename.isEmpty() && part.normalTexture.content.isEmpty() && 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, if (!addPart(texdir + "/" + part.normalTexture.filename,
QString("texture%1").arg(++_texturesCount), true)) { QString("texture%1").arg(++_texturesCount), true)) {
return false; return false;
} }
added.insert(part.normalTexture.filename); _textureFilenames.insert(part.normalTexture.filename);
} }
if (!part.specularTexture.filename.isEmpty() && part.specularTexture.content.isEmpty() && 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, if (!addPart(texdir + "/" + part.specularTexture.filename,
QString("texture%1").arg(++_texturesCount), true)) { QString("texture%1").arg(++_texturesCount), true)) {
return false; return false;
} }
added.insert(part.specularTexture.filename); _textureFilenames.insert(part.specularTexture.filename);
} }
} }
} }

View file

@ -49,6 +49,8 @@ private slots:
private: private:
QString _url; QString _url;
QString _textureBase;
QSet<QByteArray> _textureFilenames;
int _lodCount; int _lodCount;
int _texturesCount; int _texturesCount;
int _totalSize; int _totalSize;

View file

@ -520,8 +520,9 @@ void MyAvatar::saveAttachmentData(const AttachmentData& attachment) const {
settings->beginGroup("savedAttachmentData"); settings->beginGroup("savedAttachmentData");
settings->beginGroup(_skeletonModel.getURL().toString()); settings->beginGroup(_skeletonModel.getURL().toString());
settings->beginGroup(attachment.modelURL.toString()); settings->beginGroup(attachment.modelURL.toString());
settings->setValue("jointName", attachment.jointName); settings->setValue("jointName", attachment.jointName);
settings->beginGroup(attachment.jointName);
settings->setValue("translation_x", attachment.translation.x); settings->setValue("translation_x", attachment.translation.x);
settings->setValue("translation_y", attachment.translation.y); settings->setValue("translation_y", attachment.translation.y);
settings->setValue("translation_z", attachment.translation.z); 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();
settings->endGroup(); settings->endGroup();
settings->endGroup();
Application::getInstance()->unlockSettings(); 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(); QSettings* settings = Application::getInstance()->lockSettings();
settings->beginGroup("savedAttachmentData"); settings->beginGroup("savedAttachmentData");
settings->beginGroup(_skeletonModel.getURL().toString()); settings->beginGroup(_skeletonModel.getURL().toString());
@ -545,20 +547,30 @@ AttachmentData MyAvatar::loadAttachmentData(const QUrl& modelURL) const {
AttachmentData attachment; AttachmentData attachment;
attachment.modelURL = modelURL; attachment.modelURL = modelURL;
attachment.jointName = settings->value("jointName").toString(); if (jointName.isEmpty()) {
attachment.translation.x = loadSetting(settings, "translation_x", 0.0f); attachment.jointName = settings->value("jointName").toString();
attachment.translation.y = loadSetting(settings, "translation_y", 0.0f); } else {
attachment.translation.z = loadSetting(settings, "translation_z", 0.0f); attachment.jointName = jointName;
glm::vec3 eulers; }
eulers.x = loadSetting(settings, "rotation_x", 0.0f); settings->beginGroup(attachment.jointName);
eulers.y = loadSetting(settings, "rotation_y", 0.0f); if (settings->contains("translation_x")) {
eulers.z = loadSetting(settings, "rotation_z", 0.0f); attachment.translation.x = loadSetting(settings, "translation_x", 0.0f);
attachment.rotation = glm::quat(eulers); attachment.translation.y = loadSetting(settings, "translation_y", 0.0f);
attachment.scale = loadSetting(settings, "scale", 1.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();
settings->endGroup(); settings->endGroup();
settings->endGroup();
Application::getInstance()->unlockSettings(); Application::getInstance()->unlockSettings();
return attachment; return attachment;
@ -650,8 +662,8 @@ void MyAvatar::attach(const QString& modelURL, const QString& jointName, const g
return; return;
} }
if (useSaved) { if (useSaved) {
AttachmentData attachment = loadAttachmentData(modelURL); AttachmentData attachment = loadAttachmentData(modelURL, jointName);
if (!attachment.jointName.isEmpty()) { if (attachment.isValid()) {
Avatar::attach(modelURL, attachment.jointName, attachment.translation, Avatar::attach(modelURL, attachment.jointName, attachment.translation,
attachment.rotation, attachment.scale, allowDuplicates, useSaved); attachment.rotation, attachment.scale, allowDuplicates, useSaved);
return; return;
@ -1490,7 +1502,7 @@ void MyAvatar::updateMotionBehaviorsFromMenu() {
} }
void MyAvatar::renderAttachments(RenderMode renderMode) { 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); Avatar::renderAttachments(renderMode);
return; return;
} }

View file

@ -67,7 +67,7 @@ public:
void loadData(QSettings* settings); void loadData(QSettings* settings);
void saveAttachmentData(const AttachmentData& attachment) const; 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 // Set what driving keys are being pressed to control thrust levels
void setDriveKeys(int key, float val) { _driveKeys[key] = val; }; void setDriveKeys(int key, float val) { _driveKeys[key] = val; };

View file

@ -506,6 +506,15 @@ void GeometryReader::run() {
_reply->deleteLater(); _reply->deleteLater();
} }
void NetworkGeometry::init() {
_mapping = QVariantHash();
_geometry = FBXGeometry();
_meshes.clear();
_lods.clear();
_request.setUrl(_url);
Resource::init();
}
void NetworkGeometry::downloadFinished(QNetworkReply* reply) { void NetworkGeometry::downloadFinished(QNetworkReply* reply) {
QUrl url = reply->url(); QUrl url = reply->url();
if (url.path().toLower().endsWith(".fst")) { if (url.path().toLower().endsWith(".fst")) {

View file

@ -96,6 +96,7 @@ public:
protected: protected:
virtual void init();
virtual void downloadFinished(QNetworkReply* reply); virtual void downloadFinished(QNetworkReply* reply);
virtual void reinsert(); virtual void reinsert();

View file

@ -319,6 +319,9 @@ bool Model::updateGeometry() {
_jointStates = createJointStates(fbxGeometry); _jointStates = createJointStates(fbxGeometry);
needToRebuild = true; needToRebuild = true;
} }
} else if (!geometry->isLoaded()) {
deleteGeometry();
_dilatedTextures.clear();
} }
_geometry->setLoadPriority(this, -_lodDistance); _geometry->setLoadPriority(this, -_lodDistance);
_geometry->ensureLoading(); _geometry->ensureLoading();

View file

@ -97,7 +97,8 @@ static QDoubleSpinBox* createRotationBox(AttachmentPanel* panel, float value) {
} }
AttachmentPanel::AttachmentPanel(AttachmentsDialog* dialog, const AttachmentData& data) : AttachmentPanel::AttachmentPanel(AttachmentsDialog* dialog, const AttachmentData& data) :
_dialog(dialog) { _dialog(dialog),
_applying(false) {
setFrameStyle(QFrame::StyledPanel); setFrameStyle(QFrame::StyledPanel);
QFormLayout* layout = new QFormLayout(); QFormLayout* layout = new QFormLayout();
@ -121,7 +122,7 @@ AttachmentPanel::AttachmentPanel(AttachmentsDialog* dialog, const AttachmentData
} }
} }
_jointName->setCurrentText(data.jointName); _jointName->setCurrentText(data.jointName);
connect(_jointName, SIGNAL(currentIndexChanged(int)), SLOT(updateAttachmentData())); connect(_jointName, SIGNAL(currentIndexChanged(int)), SLOT(jointNameChanged()));
QHBoxLayout* translationBox = new QHBoxLayout(); QHBoxLayout* translationBox = new QHBoxLayout();
translationBox->addWidget(_translationX = createTranslationBox(this, data.translation.x)); translationBox->addWidget(_translationX = createTranslationBox(this, data.translation.x));
@ -171,25 +172,57 @@ void AttachmentPanel::setModelURL(const QString& url) {
void AttachmentPanel::modelURLChanged() { void AttachmentPanel::modelURLChanged() {
// check for saved attachment data // check for saved attachment data
if (_modelURL->text().isEmpty()) {
_dialog->updateAttachmentData();
return;
}
AttachmentData attachment = Application::getInstance()->getAvatar()->loadAttachmentData(_modelURL->text()); AttachmentData attachment = Application::getInstance()->getAvatar()->loadAttachmentData(_modelURL->text());
if (!attachment.jointName.isEmpty()) { if (attachment.isValid()) {
_applying = true;
_jointName->setCurrentText(attachment.jointName); _jointName->setCurrentText(attachment.jointName);
_translationX->setValue(attachment.translation.x); applyAttachmentData(attachment);
_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);
} }
_dialog->updateAttachmentData(); _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() { void AttachmentPanel::updateAttachmentData() {
if (_applying) {
return;
}
// save the attachment data under the model URL (if any) // save the attachment data under the model URL (if any)
if (!_modelURL->text().isEmpty()) { if (!_modelURL->text().isEmpty()) {
Application::getInstance()->getAvatar()->saveAttachmentData(getAttachmentData()); Application::getInstance()->getAvatar()->saveAttachmentData(getAttachmentData());
} }
_dialog->updateAttachmentData(); _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();
}

View file

@ -61,10 +61,13 @@ private slots:
void chooseModelURL(); void chooseModelURL();
void setModelURL(const QString& url); void setModelURL(const QString& url);
void modelURLChanged(); void modelURLChanged();
void jointNameChanged();
void updateAttachmentData(); void updateAttachmentData();
private: private:
void applyAttachmentData(const AttachmentData& attachment);
AttachmentsDialog* _dialog; AttachmentsDialog* _dialog;
QLineEdit* _modelURL; QLineEdit* _modelURL;
QComboBox* _jointName; QComboBox* _jointName;
@ -75,6 +78,7 @@ private:
QDoubleSpinBox* _rotationY; QDoubleSpinBox* _rotationY;
QDoubleSpinBox* _rotationZ; QDoubleSpinBox* _rotationZ;
QDoubleSpinBox* _scale; QDoubleSpinBox* _scale;
bool _applying;
}; };
#endif // hifi_AttachmentsDialog_h #endif // hifi_AttachmentsDialog_h

View file

@ -352,6 +352,8 @@ public:
AttachmentData(); AttachmentData();
bool isValid() const { return modelURL.isValid(); }
bool operator==(const AttachmentData& other) const; bool operator==(const AttachmentData& other) const;
}; };

View file

@ -30,6 +30,13 @@ ResourceCache::~ResourceCache() {
} }
} }
void ResourceCache::refresh(const QUrl& url) {
QSharedPointer<Resource> resource = _resources.value(url);
if (!resource.isNull()) {
resource->refresh();
}
}
QSharedPointer<Resource> ResourceCache::getResource(const QUrl& url, const QUrl& fallback, bool delayLoad, void* extra) { QSharedPointer<Resource> ResourceCache::getResource(const QUrl& url, const QUrl& fallback, bool delayLoad, void* extra) {
if (!url.isValid() && !url.isEmpty() && fallback.isValid()) { if (!url.isValid() && !url.isEmpty() && fallback.isValid()) {
return getResource(fallback, QUrl(), delayLoad); return getResource(fallback, QUrl(), delayLoad);
@ -107,25 +114,15 @@ QList<Resource*> ResourceCache::_loadingRequests;
Resource::Resource(const QUrl& url, bool delayLoad) : Resource::Resource(const QUrl& url, bool delayLoad) :
_url(url), _url(url),
_request(url), _request(url),
_startedLoading(false),
_failedToLoad(false),
_loaded(false),
_lruKey(0), _lruKey(0),
_reply(NULL), _reply(NULL) {
_attempts(0) {
init();
if (url.isEmpty()) {
_startedLoading = _loaded = true;
return;
} else if (!(url.isValid() && ResourceCache::getNetworkAccessManager())) {
_startedLoading = _failedToLoad = true;
return;
}
_request.setAttribute(QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::PreferCache); _request.setAttribute(QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::PreferCache);
// start loading immediately unless instructed otherwise // start loading immediately unless instructed otherwise
if (!delayLoad) { if (!(_startedLoading || delayLoad)) {
attemptRequest(); attemptRequest();
} }
} }
@ -178,6 +175,22 @@ float Resource::getLoadPriority() {
return highestPriority; 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() { void Resource::allReferencesCleared() {
if (QThread::currentThread() != thread()) { if (QThread::currentThread() != thread()) {
QMetaObject::invokeMethod(this, "allReferencesCleared"); 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() { void Resource::attemptRequest() {
_startedLoading = true; _startedLoading = true;
ResourceCache::attemptRequest(this); ResourceCache::attemptRequest(this);

View file

@ -47,6 +47,8 @@ public:
ResourceCache(QObject* parent = NULL); ResourceCache(QObject* parent = NULL);
virtual ~ResourceCache(); virtual ~ResourceCache();
void refresh(const QUrl& url);
protected: protected:
QMap<int, QSharedPointer<Resource> > _unusedResources; QMap<int, QSharedPointer<Resource> > _unusedResources;
@ -119,6 +121,9 @@ public:
/// For loading resources, returns the load progress. /// For loading resources, returns the load progress.
float getProgress() const { return (_bytesTotal == 0) ? 0.0f : (float)_bytesReceived / _bytesTotal; } float getProgress() const { return (_bytesTotal == 0) ? 0.0f : (float)_bytesReceived / _bytesTotal; }
/// Refreshes the resource.
void refresh();
void setSelf(const QWeakPointer<Resource>& self) { _self = self; } void setSelf(const QWeakPointer<Resource>& self) { _self = self; }
void setCache(ResourceCache* cache) { _cache = cache; } void setCache(ResourceCache* cache) { _cache = cache; }
@ -131,6 +136,8 @@ protected slots:
protected: protected:
virtual void init();
/// Called when the download has finished. The recipient should delete the reply when done with it. /// Called when the download has finished. The recipient should delete the reply when done with it.
virtual void downloadFinished(QNetworkReply* reply) = 0; virtual void downloadFinished(QNetworkReply* reply) = 0;