diff --git a/interface/src/ModelPackager.cpp b/interface/src/ModelPackager.cpp index 11a6bf4378..e997095bcd 100644 --- a/interface/src/ModelPackager.cpp +++ b/interface/src/ModelPackager.cpp @@ -89,12 +89,12 @@ bool ModelPackager::loadModel() { qCDebug(interfaceapp) << "Reading FST file"; _mapping = FSTReader::readMapping(fst.readAll()); fst.close(); - + _fbxInfo = QFileInfo(_modelFile.path() + "/" + _mapping.value(FILENAME_FIELD).toString()); } else { _fbxInfo = QFileInfo(_modelFile.filePath()); } - + // open the fbx file QFile fbx(_fbxInfo.filePath()); if (!_fbxInfo.exists() || !_fbxInfo.isFile() || !fbx.open(QIODevice::ReadOnly)) { @@ -132,7 +132,7 @@ bool ModelPackager::editProperties() { QVariantHash joints = _mapping.value(JOINT_FIELD).toHash(); if (!joints.contains("jointRoot")) { qWarning() << "root joint not configured for skeleton."; - + QString message = "Your did not configure a root joint for your skeleton model.\n\nPackaging will be canceled."; QMessageBox msgBox; msgBox.setWindowTitle("Model Packager"); @@ -140,10 +140,10 @@ bool ModelPackager::editProperties() { msgBox.setStandardButtons(QMessageBox::Ok); msgBox.setIcon(QMessageBox::Warning); msgBox.exec(); - + return false; } - + return true; } @@ -151,7 +151,7 @@ bool ModelPackager::zipModel() { QTemporaryDir dir; dir.setAutoRemove(true); QDir tempDir(dir.path()); - + QByteArray nameField = _mapping.value(NAME_FIELD).toByteArray(); tempDir.mkpath(nameField + "/textures"); tempDir.mkpath(nameField + "/scripts"); @@ -179,11 +179,11 @@ bool ModelPackager::zipModel() { auto list = wdir.entryList(QDir::NoDotAndDotDot | QDir::AllEntries); for (auto script : list) { auto sc = tempDir.relativeFilePath(scriptDir.path()) + "/" + QUrl(script).fileName(); - _mapping.insertMulti(SCRIPT_FIELD, sc); + _mapping.insert(SCRIPT_FIELD, sc); } copyDirectoryContent(wdir, scriptDir); - } - + } + // Copy LODs QVariantHash lodField = _mapping.value(LOD_FIELD).toHash(); if (!lodField.empty()) { @@ -196,16 +196,16 @@ bool ModelPackager::zipModel() { } } } - + // Copy FBX QFile fbx(_fbxInfo.filePath()); QByteArray filenameField = _mapping.value(FILENAME_FIELD).toByteArray(); QString newPath = fbxDir.path() + "/" + QFileInfo(filenameField).fileName(); fbx.copy(newPath); - + // Correct FST - _mapping[FILENAME_FIELD] = tempDir.relativeFilePath(newPath); - _mapping[TEXDIR_FIELD] = tempDir.relativeFilePath(texDir.path()); + _mapping.replace(FILENAME_FIELD, tempDir.relativeFilePath(newPath)); + _mapping.replace(TEXDIR_FIELD, tempDir.relativeFilePath(texDir.path())); for (auto multi : _mapping.values(SCRIPT_FIELD)) { multi.fromValue(tempDir.relativeFilePath(scriptDir.path()) + multi.toString()); @@ -219,15 +219,15 @@ bool ModelPackager::zipModel() { qCDebug(interfaceapp) << "Couldn't write FST file" << fst.fileName(); return false; } - - + + QString saveDirPath = QFileDialog::getExistingDirectory(nullptr, "Save Model", "", QFileDialog::ShowDirsOnly); if (saveDirPath.isEmpty()) { qCDebug(interfaceapp) << "Invalid directory" << saveDirPath; return false; } - + QDir saveDir(saveDirPath); copyDirectoryContent(tempDir, saveDir); return true; @@ -243,11 +243,11 @@ void ModelPackager::populateBasicMapping(QVariantHash& mapping, QString filename hfmModel.blendshapeChannelNames.contains("Blink_Left") && hfmModel.blendshapeChannelNames.contains("Blink_Right") && hfmModel.blendshapeChannelNames.contains("Squint_Right")); - + if (!mapping.contains(NAME_FIELD)) { mapping.insert(NAME_FIELD, QFileInfo(filename).baseName()); } - + if (!mapping.contains(FILENAME_FIELD)) { QDir root(_modelFile.path()); mapping.insert(FILENAME_FIELD, root.relativeFilePath(filename)); @@ -274,7 +274,7 @@ void ModelPackager::populateBasicMapping(QVariantHash& mapping, QString filename if (!joints.contains("jointNeck")) { joints.insert("jointNeck", hfmModel.jointIndices.contains("jointNeck") ? "jointNeck" : "Neck"); } - + if (!joints.contains("jointRoot")) { joints.insert("jointRoot", "Hips"); } @@ -287,68 +287,68 @@ void ModelPackager::populateBasicMapping(QVariantHash& mapping, QString filename if (!joints.contains("jointRightHand")) { joints.insert("jointRightHand", "RightHand"); } - + if (!joints.contains("jointHead")) { const char* topName = likelyMixamoFile ? "HeadTop_End" : "HeadEnd"; joints.insert("jointHead", hfmModel.jointIndices.contains(topName) ? topName : "Head"); } mapping.insert(JOINT_FIELD, joints); - + // If there are no blendshape mappings, and we detect that this is likely a mixamo file, // then we can add the default mixamo to blendshape mappings. if (!mapping.contains(BLENDSHAPE_FIELD) && likelyMixamoFile) { QVariantHash blendshapes; - blendshapes.insertMulti("BrowsD_L", QVariantList() << "BrowsDown_Left" << 1.0); - blendshapes.insertMulti("BrowsD_R", QVariantList() << "BrowsDown_Right" << 1.0); - blendshapes.insertMulti("BrowsU_C", QVariantList() << "BrowsUp_Left" << 1.0); - blendshapes.insertMulti("BrowsU_C", QVariantList() << "BrowsUp_Right" << 1.0); - blendshapes.insertMulti("BrowsU_L", QVariantList() << "BrowsUp_Left" << 1.0); - blendshapes.insertMulti("BrowsU_R", QVariantList() << "BrowsUp_Right" << 1.0); - blendshapes.insertMulti("ChinLowerRaise", QVariantList() << "Jaw_Up" << 1.0); - blendshapes.insertMulti("ChinUpperRaise", QVariantList() << "UpperLipUp_Left" << 0.5); - blendshapes.insertMulti("ChinUpperRaise", QVariantList() << "UpperLipUp_Right" << 0.5); - blendshapes.insertMulti("EyeBlink_L", QVariantList() << "Blink_Left" << 1.0); - blendshapes.insertMulti("EyeBlink_R", QVariantList() << "Blink_Right" << 1.0); - blendshapes.insertMulti("EyeOpen_L", QVariantList() << "EyesWide_Left" << 1.0); - blendshapes.insertMulti("EyeOpen_R", QVariantList() << "EyesWide_Right" << 1.0); - blendshapes.insertMulti("EyeSquint_L", QVariantList() << "Squint_Left" << 1.0); - blendshapes.insertMulti("EyeSquint_R", QVariantList() << "Squint_Right" << 1.0); - blendshapes.insertMulti("JawFwd", QVariantList() << "JawForeward" << 1.0); - blendshapes.insertMulti("JawLeft", QVariantList() << "JawRotateY_Left" << 0.5); - blendshapes.insertMulti("JawOpen", QVariantList() << "MouthOpen" << 0.7); - blendshapes.insertMulti("JawRight", QVariantList() << "Jaw_Right" << 1.0); - blendshapes.insertMulti("LipsFunnel", QVariantList() << "JawForeward" << 0.39); - blendshapes.insertMulti("LipsFunnel", QVariantList() << "Jaw_Down" << 0.36); - blendshapes.insertMulti("LipsFunnel", QVariantList() << "MouthNarrow_Left" << 1.0); - blendshapes.insertMulti("LipsFunnel", QVariantList() << "MouthNarrow_Right" << 1.0); - blendshapes.insertMulti("LipsFunnel", QVariantList() << "MouthWhistle_NarrowAdjust_Left" << 0.5); - blendshapes.insertMulti("LipsFunnel", QVariantList() << "MouthWhistle_NarrowAdjust_Right" << 0.5); - blendshapes.insertMulti("LipsFunnel", QVariantList() << "TongueUp" << 1.0); - blendshapes.insertMulti("LipsLowerClose", QVariantList() << "LowerLipIn" << 1.0); - blendshapes.insertMulti("LipsLowerDown", QVariantList() << "LowerLipDown_Left" << 0.7); - blendshapes.insertMulti("LipsLowerDown", QVariantList() << "LowerLipDown_Right" << 0.7); - blendshapes.insertMulti("LipsLowerOpen", QVariantList() << "LowerLipOut" << 1.0); - blendshapes.insertMulti("LipsPucker", QVariantList() << "MouthNarrow_Left" << 1.0); - blendshapes.insertMulti("LipsPucker", QVariantList() << "MouthNarrow_Right" << 1.0); - blendshapes.insertMulti("LipsUpperClose", QVariantList() << "UpperLipIn" << 1.0); - blendshapes.insertMulti("LipsUpperOpen", QVariantList() << "UpperLipOut" << 1.0); - blendshapes.insertMulti("LipsUpperUp", QVariantList() << "UpperLipUp_Left" << 0.7); - blendshapes.insertMulti("LipsUpperUp", QVariantList() << "UpperLipUp_Right" << 0.7); - blendshapes.insertMulti("MouthDimple_L", QVariantList() << "Smile_Left" << 0.25); - blendshapes.insertMulti("MouthDimple_R", QVariantList() << "Smile_Right" << 0.25); - blendshapes.insertMulti("MouthFrown_L", QVariantList() << "Frown_Left" << 1.0); - blendshapes.insertMulti("MouthFrown_R", QVariantList() << "Frown_Right" << 1.0); - blendshapes.insertMulti("MouthLeft", QVariantList() << "Midmouth_Left" << 1.0); - blendshapes.insertMulti("MouthRight", QVariantList() << "Midmouth_Right" << 1.0); - blendshapes.insertMulti("MouthSmile_L", QVariantList() << "Smile_Left" << 1.0); - blendshapes.insertMulti("MouthSmile_R", QVariantList() << "Smile_Right" << 1.0); - blendshapes.insertMulti("Puff", QVariantList() << "CheekPuff_Left" << 1.0); - blendshapes.insertMulti("Puff", QVariantList() << "CheekPuff_Right" << 1.0); - blendshapes.insertMulti("Sneer", QVariantList() << "NoseScrunch_Left" << 0.75); - blendshapes.insertMulti("Sneer", QVariantList() << "NoseScrunch_Right" << 0.75); - blendshapes.insertMulti("Sneer", QVariantList() << "Squint_Left" << 0.5); - blendshapes.insertMulti("Sneer", QVariantList() << "Squint_Right" << 0.5); + blendshapes.insert("BrowsD_L", QVariantList() << "BrowsDown_Left" << 1.0); + blendshapes.insert("BrowsD_R", QVariantList() << "BrowsDown_Right" << 1.0); + blendshapes.insert("BrowsU_C", QVariantList() << "BrowsUp_Left" << 1.0); + blendshapes.insert("BrowsU_C", QVariantList() << "BrowsUp_Right" << 1.0); + blendshapes.insert("BrowsU_L", QVariantList() << "BrowsUp_Left" << 1.0); + blendshapes.insert("BrowsU_R", QVariantList() << "BrowsUp_Right" << 1.0); + blendshapes.insert("ChinLowerRaise", QVariantList() << "Jaw_Up" << 1.0); + blendshapes.insert("ChinUpperRaise", QVariantList() << "UpperLipUp_Left" << 0.5); + blendshapes.insert("ChinUpperRaise", QVariantList() << "UpperLipUp_Right" << 0.5); + blendshapes.insert("EyeBlink_L", QVariantList() << "Blink_Left" << 1.0); + blendshapes.insert("EyeBlink_R", QVariantList() << "Blink_Right" << 1.0); + blendshapes.insert("EyeOpen_L", QVariantList() << "EyesWide_Left" << 1.0); + blendshapes.insert("EyeOpen_R", QVariantList() << "EyesWide_Right" << 1.0); + blendshapes.insert("EyeSquint_L", QVariantList() << "Squint_Left" << 1.0); + blendshapes.insert("EyeSquint_R", QVariantList() << "Squint_Right" << 1.0); + blendshapes.insert("JawFwd", QVariantList() << "JawForeward" << 1.0); + blendshapes.insert("JawLeft", QVariantList() << "JawRotateY_Left" << 0.5); + blendshapes.insert("JawOpen", QVariantList() << "MouthOpen" << 0.7); + blendshapes.insert("JawRight", QVariantList() << "Jaw_Right" << 1.0); + blendshapes.insert("LipsFunnel", QVariantList() << "JawForeward" << 0.39); + blendshapes.insert("LipsFunnel", QVariantList() << "Jaw_Down" << 0.36); + blendshapes.insert("LipsFunnel", QVariantList() << "MouthNarrow_Left" << 1.0); + blendshapes.insert("LipsFunnel", QVariantList() << "MouthNarrow_Right" << 1.0); + blendshapes.insert("LipsFunnel", QVariantList() << "MouthWhistle_NarrowAdjust_Left" << 0.5); + blendshapes.insert("LipsFunnel", QVariantList() << "MouthWhistle_NarrowAdjust_Right" << 0.5); + blendshapes.insert("LipsFunnel", QVariantList() << "TongueUp" << 1.0); + blendshapes.insert("LipsLowerClose", QVariantList() << "LowerLipIn" << 1.0); + blendshapes.insert("LipsLowerDown", QVariantList() << "LowerLipDown_Left" << 0.7); + blendshapes.insert("LipsLowerDown", QVariantList() << "LowerLipDown_Right" << 0.7); + blendshapes.insert("LipsLowerOpen", QVariantList() << "LowerLipOut" << 1.0); + blendshapes.insert("LipsPucker", QVariantList() << "MouthNarrow_Left" << 1.0); + blendshapes.insert("LipsPucker", QVariantList() << "MouthNarrow_Right" << 1.0); + blendshapes.insert("LipsUpperClose", QVariantList() << "UpperLipIn" << 1.0); + blendshapes.insert("LipsUpperOpen", QVariantList() << "UpperLipOut" << 1.0); + blendshapes.insert("LipsUpperUp", QVariantList() << "UpperLipUp_Left" << 0.7); + blendshapes.insert("LipsUpperUp", QVariantList() << "UpperLipUp_Right" << 0.7); + blendshapes.insert("MouthDimple_L", QVariantList() << "Smile_Left" << 0.25); + blendshapes.insert("MouthDimple_R", QVariantList() << "Smile_Right" << 0.25); + blendshapes.insert("MouthFrown_L", QVariantList() << "Frown_Left" << 1.0); + blendshapes.insert("MouthFrown_R", QVariantList() << "Frown_Right" << 1.0); + blendshapes.insert("MouthLeft", QVariantList() << "Midmouth_Left" << 1.0); + blendshapes.insert("MouthRight", QVariantList() << "Midmouth_Right" << 1.0); + blendshapes.insert("MouthSmile_L", QVariantList() << "Smile_Left" << 1.0); + blendshapes.insert("MouthSmile_R", QVariantList() << "Smile_Right" << 1.0); + blendshapes.insert("Puff", QVariantList() << "CheekPuff_Left" << 1.0); + blendshapes.insert("Puff", QVariantList() << "CheekPuff_Right" << 1.0); + blendshapes.insert("Sneer", QVariantList() << "NoseScrunch_Left" << 0.75); + blendshapes.insert("Sneer", QVariantList() << "NoseScrunch_Right" << 0.75); + blendshapes.insert("Sneer", QVariantList() << "Squint_Left" << 0.5); + blendshapes.insert("Sneer", QVariantList() << "Squint_Right" << 0.5); mapping.insert(BLENDSHAPE_FIELD, blendshapes); } } @@ -362,7 +362,7 @@ void ModelPackager::listTextures() { } if (!mat.normalTexture.filename.isEmpty() && mat.normalTexture.content.isEmpty() && !_textures.contains(mat.normalTexture.filename)) { - + _textures << mat.normalTexture.filename; } if (!mat.specularTexture.filename.isEmpty() && mat.specularTexture.content.isEmpty() && @@ -387,7 +387,7 @@ bool ModelPackager::copyTextures(const QString& oldDir, const QDir& newDir) { QString dirPath = newDir.relativeFilePath(QFileInfo(newPath).path()); newDir.mkpath(dirPath); } - + QFile texFile(oldPath); if (texFile.exists() && texFile.open(QIODevice::ReadOnly)) { // Check if texture needs to be recoded @@ -402,7 +402,7 @@ bool ModelPackager::copyTextures(const QString& oldDir, const QDir& newDir) { image = image.scaled(MAX_TEXTURE_SIZE, MAX_TEXTURE_SIZE, Qt::KeepAspectRatio); mustRecode = true; } - + // Copy texture if (mustRecode) { QFile newTexFile(newPath); @@ -415,14 +415,14 @@ bool ModelPackager::copyTextures(const QString& oldDir, const QDir& newDir) { errors += QString("\n%1").arg(oldPath); } } - + if (!errors.isEmpty()) { OffscreenUi::asyncWarning(nullptr, "ModelPackager::copyTextures()", "Missing textures:" + errors); qCDebug(interfaceapp) << "ModelPackager::copyTextures():" << errors; return false; } - + return true; } diff --git a/interface/src/ModelPackager.h b/interface/src/ModelPackager.h index 58d3d6bfee..9a2a49562a 100644 --- a/interface/src/ModelPackager.h +++ b/interface/src/ModelPackager.h @@ -15,7 +15,7 @@ #include #include -#include +#include #include "ui/ModelsBrowser.h" @@ -44,7 +44,7 @@ private: QString _texDir; QString _scriptDir; - QVariantHash _mapping; + QMultiHash _mapping; std::shared_ptr _hfmModel; QStringList _textures; QStringList _scripts; diff --git a/interface/src/ui/Stats.cpp b/interface/src/ui/Stats.cpp index b013bbff0d..0e3a329375 100644 --- a/interface/src/ui/Stats.cpp +++ b/interface/src/ui/Stats.cpp @@ -199,7 +199,7 @@ void Stats::updateStats(bool force) { } // Second column: ping - STAT_UPDATE(audioPing, audioMixerNode ? audioMixerNode->getPingMs() : -1); + STAT_UPDATE(audioPing, audioMixerNode ? audioMixerNode->getPingMs() : -1); const int mixerLossRate = (int)roundf(_audioStats->data()->getMixerStream()->lossRateWindow() * 100.0f); const int clientLossRate = (int)roundf(_audioStats->data()->getClientStream()->lossRateWindow() * 100.0f); const int largestLossRate = mixerLossRate > clientLossRate ? mixerLossRate : clientLossRate; @@ -484,7 +484,7 @@ void Stats::updateStats(bool force) { // First iterate all the records, and for the ones that should be included, insert them into // a new Map sorted by average time... bool onlyDisplayTopTen = Menu::getInstance()->isOptionChecked(MenuOption::OnlyDisplayTopTen); - QMap sortedRecords; + QMultiMap sortedRecords; auto allRecords = PerformanceTimer::getAllTimerRecords(); QMapIterator i(allRecords); @@ -492,7 +492,7 @@ void Stats::updateStats(bool force) { i.next(); if (includeTimingRecord(i.key())) { float averageTime = (float)i.value().getMovingAverage() / (float)USECS_PER_MSEC; - sortedRecords.insertMulti(averageTime, i.key()); + sortedRecords.insert(averageTime, i.key()); } } diff --git a/libraries/model-networking/src/model-networking/ModelCache.cpp b/libraries/model-networking/src/model-networking/ModelCache.cpp index 1fcfcfcc70..273073b8b5 100644 --- a/libraries/model-networking/src/model-networking/ModelCache.cpp +++ b/libraries/model-networking/src/model-networking/ModelCache.cpp @@ -140,9 +140,9 @@ void GeometryReader::run() { } HFMModel::Pointer hfmModel; - QVariantHash serializerMapping = _mapping.second; - serializerMapping["combineParts"] = _combineParts; - serializerMapping["deduplicateIndices"] = true; + QMultiHash serializerMapping = _mapping.second; + serializerMapping.replace("combineParts",_combineParts); + serializerMapping.replace("deduplicateIndices", true); if (_url.path().toLower().endsWith(".gz")) { QByteArray uncompressedData; @@ -247,7 +247,7 @@ void GeometryResource::downloadFinished(const QByteArray& data) { if (scripts.size() > 0) { _mapping.remove(SCRIPT_FIELD); for (auto &scriptPath : scripts) { - _mapping.insertMulti(SCRIPT_FIELD, scriptPath); + _mapping.insert(SCRIPT_FIELD, scriptPath); } } diff --git a/libraries/model-serializers/src/FBXSerializer.cpp b/libraries/model-serializers/src/FBXSerializer.cpp index a18e305a80..1445012761 100644 --- a/libraries/model-serializers/src/FBXSerializer.cpp +++ b/libraries/model-serializers/src/FBXSerializer.cpp @@ -417,7 +417,7 @@ HFMModel* FBXSerializer::extractHFMModel(const hifi::VariantHash& mapping, const std::map lights; - hifi::VariantHash blendshapeMappings = mapping.value("bs").toHash(); + hifi::VariantMultiHash blendshapeMappings = mapping.value("bs").toHash(); QMultiHash blendshapeIndices; for (int i = 0;; i++) { diff --git a/libraries/model-serializers/src/FST.cpp b/libraries/model-serializers/src/FST.cpp index fd07409960..41e5107912 100644 --- a/libraries/model-serializers/src/FST.cpp +++ b/libraries/model-serializers/src/FST.cpp @@ -17,11 +17,11 @@ constexpr float DEFAULT_SCALE { 1.0f }; -FST::FST(QString fstPath, QVariantHash data) : _fstPath(std::move(fstPath)) { +FST::FST(QString fstPath, QMultiHash data) : _fstPath(std::move(fstPath)) { auto setValueFromFSTData = [&data] (const QString& propertyID, auto &targetProperty) mutable { if (data.contains(propertyID)) { - targetProperty = data[propertyID].toString(); + targetProperty = data.value(propertyID).toString(); data.remove(propertyID); } }; @@ -87,56 +87,56 @@ FST* FST::createFSTFromModel(const QString& fstPath, const QString& modelFilePat // then we can add the default mixamo to blendshape mappings. if (likelyMixamoFile) { QVariantHash blendshapes; - blendshapes.insertMulti("BrowsD_L", QVariantList() << "BrowsDown_Left" << 1.0); - blendshapes.insertMulti("BrowsD_R", QVariantList() << "BrowsDown_Right" << 1.0); - blendshapes.insertMulti("BrowsU_C", QVariantList() << "BrowsUp_Left" << 1.0); - blendshapes.insertMulti("BrowsU_C", QVariantList() << "BrowsUp_Right" << 1.0); - blendshapes.insertMulti("BrowsU_L", QVariantList() << "BrowsUp_Left" << 1.0); - blendshapes.insertMulti("BrowsU_R", QVariantList() << "BrowsUp_Right" << 1.0); - blendshapes.insertMulti("ChinLowerRaise", QVariantList() << "Jaw_Up" << 1.0); - blendshapes.insertMulti("ChinUpperRaise", QVariantList() << "UpperLipUp_Left" << 0.5); - blendshapes.insertMulti("ChinUpperRaise", QVariantList() << "UpperLipUp_Right" << 0.5); - blendshapes.insertMulti("EyeBlink_L", QVariantList() << "Blink_Left" << 1.0); - blendshapes.insertMulti("EyeBlink_R", QVariantList() << "Blink_Right" << 1.0); - blendshapes.insertMulti("EyeOpen_L", QVariantList() << "EyesWide_Left" << 1.0); - blendshapes.insertMulti("EyeOpen_R", QVariantList() << "EyesWide_Right" << 1.0); - blendshapes.insertMulti("EyeSquint_L", QVariantList() << "Squint_Left" << 1.0); - blendshapes.insertMulti("EyeSquint_R", QVariantList() << "Squint_Right" << 1.0); - blendshapes.insertMulti("JawFwd", QVariantList() << "JawForeward" << 1.0); - blendshapes.insertMulti("JawLeft", QVariantList() << "JawRotateY_Left" << 0.5); - blendshapes.insertMulti("JawOpen", QVariantList() << "MouthOpen" << 0.7); - blendshapes.insertMulti("JawRight", QVariantList() << "Jaw_Right" << 1.0); - blendshapes.insertMulti("LipsFunnel", QVariantList() << "JawForeward" << 0.39); - blendshapes.insertMulti("LipsFunnel", QVariantList() << "Jaw_Down" << 0.36); - blendshapes.insertMulti("LipsFunnel", QVariantList() << "MouthNarrow_Left" << 1.0); - blendshapes.insertMulti("LipsFunnel", QVariantList() << "MouthNarrow_Right" << 1.0); - blendshapes.insertMulti("LipsFunnel", QVariantList() << "MouthWhistle_NarrowAdjust_Left" << 0.5); - blendshapes.insertMulti("LipsFunnel", QVariantList() << "MouthWhistle_NarrowAdjust_Right" << 0.5); - blendshapes.insertMulti("LipsFunnel", QVariantList() << "TongueUp" << 1.0); - blendshapes.insertMulti("LipsLowerClose", QVariantList() << "LowerLipIn" << 1.0); - blendshapes.insertMulti("LipsLowerDown", QVariantList() << "LowerLipDown_Left" << 0.7); - blendshapes.insertMulti("LipsLowerDown", QVariantList() << "LowerLipDown_Right" << 0.7); - blendshapes.insertMulti("LipsLowerOpen", QVariantList() << "LowerLipOut" << 1.0); - blendshapes.insertMulti("LipsPucker", QVariantList() << "MouthNarrow_Left" << 1.0); - blendshapes.insertMulti("LipsPucker", QVariantList() << "MouthNarrow_Right" << 1.0); - blendshapes.insertMulti("LipsUpperClose", QVariantList() << "UpperLipIn" << 1.0); - blendshapes.insertMulti("LipsUpperOpen", QVariantList() << "UpperLipOut" << 1.0); - blendshapes.insertMulti("LipsUpperUp", QVariantList() << "UpperLipUp_Left" << 0.7); - blendshapes.insertMulti("LipsUpperUp", QVariantList() << "UpperLipUp_Right" << 0.7); - blendshapes.insertMulti("MouthDimple_L", QVariantList() << "Smile_Left" << 0.25); - blendshapes.insertMulti("MouthDimple_R", QVariantList() << "Smile_Right" << 0.25); - blendshapes.insertMulti("MouthFrown_L", QVariantList() << "Frown_Left" << 1.0); - blendshapes.insertMulti("MouthFrown_R", QVariantList() << "Frown_Right" << 1.0); - blendshapes.insertMulti("MouthLeft", QVariantList() << "Midmouth_Left" << 1.0); - blendshapes.insertMulti("MouthRight", QVariantList() << "Midmouth_Right" << 1.0); - blendshapes.insertMulti("MouthSmile_L", QVariantList() << "Smile_Left" << 1.0); - blendshapes.insertMulti("MouthSmile_R", QVariantList() << "Smile_Right" << 1.0); - blendshapes.insertMulti("Puff", QVariantList() << "CheekPuff_Left" << 1.0); - blendshapes.insertMulti("Puff", QVariantList() << "CheekPuff_Right" << 1.0); - blendshapes.insertMulti("Sneer", QVariantList() << "NoseScrunch_Left" << 0.75); - blendshapes.insertMulti("Sneer", QVariantList() << "NoseScrunch_Right" << 0.75); - blendshapes.insertMulti("Sneer", QVariantList() << "Squint_Left" << 0.5); - blendshapes.insertMulti("Sneer", QVariantList() << "Squint_Right" << 0.5); + blendshapes.insert("BrowsD_L", QVariantList() << "BrowsDown_Left" << 1.0); + blendshapes.insert("BrowsD_R", QVariantList() << "BrowsDown_Right" << 1.0); + blendshapes.insert("BrowsU_C", QVariantList() << "BrowsUp_Left" << 1.0); + blendshapes.insert("BrowsU_C", QVariantList() << "BrowsUp_Right" << 1.0); + blendshapes.insert("BrowsU_L", QVariantList() << "BrowsUp_Left" << 1.0); + blendshapes.insert("BrowsU_R", QVariantList() << "BrowsUp_Right" << 1.0); + blendshapes.insert("ChinLowerRaise", QVariantList() << "Jaw_Up" << 1.0); + blendshapes.insert("ChinUpperRaise", QVariantList() << "UpperLipUp_Left" << 0.5); + blendshapes.insert("ChinUpperRaise", QVariantList() << "UpperLipUp_Right" << 0.5); + blendshapes.insert("EyeBlink_L", QVariantList() << "Blink_Left" << 1.0); + blendshapes.insert("EyeBlink_R", QVariantList() << "Blink_Right" << 1.0); + blendshapes.insert("EyeOpen_L", QVariantList() << "EyesWide_Left" << 1.0); + blendshapes.insert("EyeOpen_R", QVariantList() << "EyesWide_Right" << 1.0); + blendshapes.insert("EyeSquint_L", QVariantList() << "Squint_Left" << 1.0); + blendshapes.insert("EyeSquint_R", QVariantList() << "Squint_Right" << 1.0); + blendshapes.insert("JawFwd", QVariantList() << "JawForeward" << 1.0); + blendshapes.insert("JawLeft", QVariantList() << "JawRotateY_Left" << 0.5); + blendshapes.insert("JawOpen", QVariantList() << "MouthOpen" << 0.7); + blendshapes.insert("JawRight", QVariantList() << "Jaw_Right" << 1.0); + blendshapes.insert("LipsFunnel", QVariantList() << "JawForeward" << 0.39); + blendshapes.insert("LipsFunnel", QVariantList() << "Jaw_Down" << 0.36); + blendshapes.insert("LipsFunnel", QVariantList() << "MouthNarrow_Left" << 1.0); + blendshapes.insert("LipsFunnel", QVariantList() << "MouthNarrow_Right" << 1.0); + blendshapes.insert("LipsFunnel", QVariantList() << "MouthWhistle_NarrowAdjust_Left" << 0.5); + blendshapes.insert("LipsFunnel", QVariantList() << "MouthWhistle_NarrowAdjust_Right" << 0.5); + blendshapes.insert("LipsFunnel", QVariantList() << "TongueUp" << 1.0); + blendshapes.insert("LipsLowerClose", QVariantList() << "LowerLipIn" << 1.0); + blendshapes.insert("LipsLowerDown", QVariantList() << "LowerLipDown_Left" << 0.7); + blendshapes.insert("LipsLowerDown", QVariantList() << "LowerLipDown_Right" << 0.7); + blendshapes.insert("LipsLowerOpen", QVariantList() << "LowerLipOut" << 1.0); + blendshapes.insert("LipsPucker", QVariantList() << "MouthNarrow_Left" << 1.0); + blendshapes.insert("LipsPucker", QVariantList() << "MouthNarrow_Right" << 1.0); + blendshapes.insert("LipsUpperClose", QVariantList() << "UpperLipIn" << 1.0); + blendshapes.insert("LipsUpperOpen", QVariantList() << "UpperLipOut" << 1.0); + blendshapes.insert("LipsUpperUp", QVariantList() << "UpperLipUp_Left" << 0.7); + blendshapes.insert("LipsUpperUp", QVariantList() << "UpperLipUp_Right" << 0.7); + blendshapes.insert("MouthDimple_L", QVariantList() << "Smile_Left" << 0.25); + blendshapes.insert("MouthDimple_R", QVariantList() << "Smile_Right" << 0.25); + blendshapes.insert("MouthFrown_L", QVariantList() << "Frown_Left" << 1.0); + blendshapes.insert("MouthFrown_R", QVariantList() << "Frown_Right" << 1.0); + blendshapes.insert("MouthLeft", QVariantList() << "Midmouth_Left" << 1.0); + blendshapes.insert("MouthRight", QVariantList() << "Midmouth_Right" << 1.0); + blendshapes.insert("MouthSmile_L", QVariantList() << "Smile_Left" << 1.0); + blendshapes.insert("MouthSmile_R", QVariantList() << "Smile_Right" << 1.0); + blendshapes.insert("Puff", QVariantList() << "CheekPuff_Left" << 1.0); + blendshapes.insert("Puff", QVariantList() << "CheekPuff_Right" << 1.0); + blendshapes.insert("Sneer", QVariantList() << "NoseScrunch_Left" << 0.75); + blendshapes.insert("Sneer", QVariantList() << "NoseScrunch_Right" << 0.75); + blendshapes.insert("Sneer", QVariantList() << "Squint_Left" << 0.5); + blendshapes.insert("Sneer", QVariantList() << "Squint_Right" << 0.5); mapping.insert(BLENDSHAPE_FIELD, blendshapes); } return new FST(fstPath, mapping); @@ -158,14 +158,14 @@ void FST::setModelPath(const QString& modelPath) { emit modelPathChanged(modelPath); } -QVariantHash FST::getMapping() const { - QVariantHash mapping; +QMultiHash FST::getMapping() const { + QMultiHash mapping; mapping.unite(_other); mapping.insert(NAME_FIELD, _name); mapping.insert(FILENAME_FIELD, _modelPath); mapping.insert(MARKETPLACE_ID_FIELD, _marketplaceID); for (const auto& scriptPath : _scriptPaths) { - mapping.insertMulti(SCRIPT_FIELD, scriptPath); + mapping.insert(SCRIPT_FIELD, scriptPath); } return mapping; } diff --git a/libraries/model-serializers/src/FST.h b/libraries/model-serializers/src/FST.h index 0f4c1ecd3a..9804a5f1e8 100644 --- a/libraries/model-serializers/src/FST.h +++ b/libraries/model-serializers/src/FST.h @@ -26,7 +26,7 @@ class FST : public QObject { Q_PROPERTY(QUuid marketplaceID READ getMarketplaceID) Q_PROPERTY(bool hasMarketplaceID READ getHasMarketplaceID NOTIFY marketplaceIDChanged) public: - FST(QString fstPath, QVariantHash data); + FST(QString fstPath, QMultiHash data); static FST* createFSTFromModel(const QString& fstPath, const QString& modelFilePath, const hfm::Model& hfmModel); @@ -47,7 +47,7 @@ public: QString getPath() const { return _fstPath; } - QVariantHash getMapping() const; + QMultiHash getMapping() const; bool write(); diff --git a/libraries/model-serializers/src/FSTReader.cpp b/libraries/model-serializers/src/FSTReader.cpp index cd3b8d268c..c06e163136 100644 --- a/libraries/model-serializers/src/FSTReader.cpp +++ b/libraries/model-serializers/src/FSTReader.cpp @@ -34,10 +34,10 @@ QVariantHash FSTReader::parseMapping(QIODevice* device) { } QByteArray name = sections.at(0).trimmed(); if (sections.size() == 2) { - properties.insertMulti(name, sections.at(1).trimmed()); + properties.insert(name, sections.at(1).trimmed()); } else if (sections.size() == 3) { QVariantHash heading = properties.value(name).toHash(); - heading.insertMulti(sections.at(1).trimmed(), sections.at(2).trimmed()); + heading.insert(sections.at(1).trimmed(), sections.at(2).trimmed()); properties.insert(name, heading); } else if (sections.size() >= 4) { QVariantHash heading = properties.value(name).toHash(); @@ -45,7 +45,7 @@ QVariantHash FSTReader::parseMapping(QIODevice* device) { for (int i = 2; i < sections.size(); i++) { contents.append(sections.at(i).trimmed()); } - heading.insertMulti(sections.at(1).trimmed(), contents); + heading.insert(sections.at(1).trimmed(), contents); properties.insert(name, heading); } } @@ -59,7 +59,7 @@ static void removeBlendshape(QVariantHash& bs, const QString& key) { } } -static void splitBlendshapes(QVariantHash& bs, const QString& key, const QString& leftKey, const QString& rightKey) { +static void splitBlendshapes(hifi::VariantMultiHash& bs, const QString& key, const QString& leftKey, const QString& rightKey) { if (bs.contains(key) && !(bs.contains(leftKey) || bs.contains(rightKey))) { // key has been split into leftKey and rightKey blendshapes QVariantList origShapes = bs.values(key); @@ -69,15 +69,15 @@ static void splitBlendshapes(QVariantHash& bs, const QString& key, const QString QVariantList halfShape; halfShape.append(origShape[0]); halfShape.append(QVariant(0.5f * origShape[1].toFloat())); - bs.insertMulti(leftKey, halfShape); - bs.insertMulti(rightKey, halfShape); + bs.insert(leftKey, halfShape); + bs.insert(rightKey, halfShape); } } } // convert legacy blendshapes to arkit blendshapes -static void fixUpLegacyBlendshapes(QVariantHash& properties) { - QVariantHash bs = properties.value("bs").toHash(); +static void fixUpLegacyBlendshapes(QVariantHash & properties) { + hifi::VariantMultiHash bs = properties.value("bs").toHash(); // These blendshapes have no ARKit equivalent, so we remove them. removeBlendshape(bs, "JawChew"); @@ -125,7 +125,7 @@ void FSTReader::writeVariant(QBuffer& buffer, QVariantHash::const_iterator& it) } } -QByteArray FSTReader::writeMapping(const QVariantHash& mapping) { +QByteArray FSTReader::writeMapping(const hifi::VariantMultiHash& mapping) { static const QStringList PREFERED_ORDER = QStringList() << NAME_FIELD << TYPE_FIELD << SCALE_FIELD << FILENAME_FIELD << MARKETPLACE_ID_FIELD << TEXDIR_FIELD << SCRIPT_FIELD << JOINT_FIELD << BLENDSHAPE_FIELD << JOINT_INDEX_FIELD; @@ -175,9 +175,9 @@ FSTReader::ModelType FSTReader::getTypeFromName(const QString& name) { _namesToTypes["head"] = HEAD_MODEL ; _namesToTypes["body"] = BODY_ONLY_MODEL; _namesToTypes["body+head"] = HEAD_AND_BODY_MODEL; - + // NOTE: this is not yet implemented, but will be used to allow you to attach fully independent models to your avatar - _namesToTypes["attachment"] = ATTACHMENT_MODEL; + _namesToTypes["attachment"] = ATTACHMENT_MODEL; } return _namesToTypes[name]; } @@ -194,7 +194,7 @@ FSTReader::ModelType FSTReader::predictModelType(const QVariantHash& mapping) { if (mapping.contains(TYPE_FIELD)) { return FSTReader::getTypeFromName(mapping[TYPE_FIELD].toString()); } - + // check for blendshapes bool hasBlendshapes = mapping.contains(BLENDSHAPE_FIELD); @@ -210,15 +210,15 @@ FSTReader::ModelType FSTReader::predictModelType(const QVariantHash& mapping) { //joint = jointNeck = Neck //joint = jointHead = HeadTop_End - bool hasBodyMinimumJoints = joints.contains("jointRoot") && joints.contains("jointLean") && joints.contains("jointNeck") + bool hasBodyMinimumJoints = joints.contains("jointRoot") && joints.contains("jointLean") && joints.contains("jointNeck") && joints.contains("jointHead"); - + bool isLikelyHead = hasBlendshapes || hasHeadMinimum; if (isLikelyHead && hasBodyMinimumJoints) { return HEAD_AND_BODY_MODEL; } - + if (isLikelyHead) { return HEAD_MODEL; } @@ -226,11 +226,11 @@ FSTReader::ModelType FSTReader::predictModelType(const QVariantHash& mapping) { if (hasBodyMinimumJoints) { return BODY_ONLY_MODEL; } - + return ENTITY_MODEL; } -QVector FSTReader::getScripts(const QUrl& url, const QVariantHash& mapping) { +QVector FSTReader::getScripts(const QUrl& url, const hifi::VariantMultiHash& mapping) { auto fstMapping = mapping.isEmpty() ? downloadMapping(url.toString()) : mapping; QVector scriptPaths; @@ -250,7 +250,7 @@ QVector FSTReader::getScripts(const QUrl& url, const QVariantHash& mapp return scriptPaths; } -QVariantHash FSTReader::downloadMapping(const QString& url) { +hifi::VariantMultiHash FSTReader::downloadMapping(const QString& url) { QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance(); QNetworkRequest networkRequest = QNetworkRequest(url); networkRequest.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true); diff --git a/libraries/model-serializers/src/FSTReader.h b/libraries/model-serializers/src/FSTReader.h index 3945fe1d8b..f9fd883f84 100644 --- a/libraries/model-serializers/src/FSTReader.h +++ b/libraries/model-serializers/src/FSTReader.h @@ -14,6 +14,7 @@ #include #include +#include "shared/HifiTypes.h" static const unsigned int FST_VERSION = 1; static const QString FST_VERSION_FIELD = "version"; @@ -50,16 +51,16 @@ public: static QVariantHash readMapping(const QByteArray& data); /// Writes an FST mapping to a byte array. - static QByteArray writeMapping(const QVariantHash& mapping); + static QByteArray writeMapping(const hifi::VariantMultiHash& mapping); - /// Predicts the type of model by examining the mapping + /// Predicts the type of model by examining the mapping static ModelType predictModelType(const QVariantHash& mapping); - static QVector getScripts(const QUrl& fstUrl, const QVariantHash& mapping = QVariantHash()); + static QVector getScripts(const QUrl& fstUrl, const hifi::VariantMultiHash& mapping = QVariantHash()); static QString getNameFromType(ModelType modelType); static FSTReader::ModelType getTypeFromName(const QString& name); - static QVariantHash downloadMapping(const QString& url); + static hifi::VariantMultiHash downloadMapping(const QString& url); private: static void writeVariant(QBuffer& buffer, QVariantHash::const_iterator& it); diff --git a/libraries/model-serializers/src/GLTFSerializer.cpp b/libraries/model-serializers/src/GLTFSerializer.cpp index 9b0145c112..9aadf951cc 100755 --- a/libraries/model-serializers/src/GLTFSerializer.cpp +++ b/libraries/model-serializers/src/GLTFSerializer.cpp @@ -1548,7 +1548,7 @@ bool GLTFSerializer::buildGeometry(HFMModel& hfmModel, const hifi::VariantHash& // Build list of blendshapes from FST and model. typedef QPair WeightedIndex; - hifi::VariantHash blendshapeMappings = mapping.value("bs").toHash(); + hifi::VariantMultiHash blendshapeMappings = mapping.value("bs").toHash(); QMultiHash blendshapeIndices; for (int i = 0;; ++i) { auto blendshapeName = QString(BLENDSHAPE_NAMES[i]); @@ -1583,7 +1583,7 @@ bool GLTFSerializer::buildGeometry(HFMModel& hfmModel, const hifi::VariantHash& && fileTargetNames.contains("viseme_O") && fileTargetNames.contains("mouthShrugLower"); if (blendshapeMappings.count() == 0 && likelyReadyPlayerMeFile) { - QHash>::const_iterator synonym + QHash>::const_iterator synonym = READYPLAYERME_BLENDSHAPES_MAP.constBegin(); while (synonym != READYPLAYERME_BLENDSHAPES_MAP.constEnd()) { if (fileTargetNames.contains(synonym.key())) { diff --git a/libraries/networking/src/ResourceCache.cpp b/libraries/networking/src/ResourceCache.cpp index 54297415c0..35a9bd83bc 100644 --- a/libraries/networking/src/ResourceCache.cpp +++ b/libraries/networking/src/ResourceCache.cpp @@ -301,7 +301,7 @@ void ResourceCache::refreshAll() { clearUnusedResources(); resetUnusedResourceCounter(); - QHash>> allResources; + QHash>> allResources; { QReadLocker locker(&_resourcesLock); allResources = _resources; @@ -339,7 +339,7 @@ QVariantList ResourceCache::getResourceList() { return list; } - + void ResourceCache::setRequestLimit(uint32_t limit) { auto sharedItems = DependencyManager::get(); sharedItems->setRequestLimit(limit); @@ -418,7 +418,7 @@ void ResourceCache::addUnusedResource(const QSharedPointer& resource) return; } reserveUnusedResource(resource->getBytes()); - + resource->setLRUKey(++_lastLRUKey); { @@ -447,7 +447,7 @@ void ResourceCache::reserveUnusedResource(qint64 resourceSize) { _unusedResourcesSize + resourceSize > _unusedResourcesMaxSize) { // unload the oldest resource QMap >::iterator it = _unusedResources.begin(); - + it.value()->setCache(nullptr); auto size = it.value()->getBytes(); @@ -654,7 +654,7 @@ void Resource::refresh() { _request = nullptr; ResourceCache::requestCompleted(_self); } - + _activeUrl = _url; init(); ensureLoading(); @@ -668,7 +668,7 @@ void Resource::allReferencesCleared() { } if (_cache && isCacheable()) { - // create and reinsert new shared pointer + // create and reinsert new shared pointer QSharedPointer self(this, &Resource::deleter); setSelf(self); reinsert(); @@ -693,10 +693,10 @@ void Resource::init(bool resetLoaded) { _loaded = false; } _attempts = 0; - + if (_url.isEmpty()) { _startedLoading = _loaded = true; - + } else if (!(_url.isValid())) { _startedLoading = _failedToLoad = true; } @@ -820,7 +820,7 @@ void Resource::handleReplyFinished() { } else { handleFailedRequest(result); } - + _request->disconnect(this); _request->deleteLater(); _request = nullptr; diff --git a/libraries/networking/src/ResourceCache.h b/libraries/networking/src/ResourceCache.h index a49f5b3f61..b78665a7a6 100644 --- a/libraries/networking/src/ResourceCache.h +++ b/libraries/networking/src/ResourceCache.h @@ -91,7 +91,7 @@ private: class ScriptableResource : public QObject { /*@jsdoc - * Information about a cached resource. Created by {@link AnimationCache.prefetch}, {@link MaterialCache.prefetch}, + * Information about a cached resource. Created by {@link AnimationCache.prefetch}, {@link MaterialCache.prefetch}, * {@link ModelCache.prefetch}, {@link SoundCache.prefetch}, or {@link TextureCache.prefetch}. * * @class ResourceObject @@ -212,7 +212,7 @@ public: static void setRequestLimit(uint32_t limit); static uint32_t getRequestLimit() { return DependencyManager::get()->getRequestLimit(); } - + void setUnusedResourceCacheSize(qint64 unusedResourcesMaxSize); qint64 getUnusedResourceCacheSize() const { return _unusedResourcesMaxSize; } @@ -222,7 +222,7 @@ public: ResourceCache(QObject* parent = nullptr); virtual ~ResourceCache(); - + void refreshAll(); void clearUnusedResources(); @@ -284,7 +284,7 @@ private: void resetResourceCounters(); // Resources - QHash>> _resources; + QHash>> _resources; QReadWriteLock _resourcesLock { QReadWriteLock::Recursive }; int _lastLRUKey = 0; @@ -304,7 +304,7 @@ private: class ScriptableResourceCache : public QObject { Q_OBJECT - // JSDoc 3.5.5 doesn't augment name spaces with @property definitions so the following properties JSDoc is copied to the + // JSDoc 3.5.5 doesn't augment name spaces with @property definitions so the following properties JSDoc is copied to the // different exposed cache classes. /*@jsdoc @@ -357,10 +357,10 @@ public: * @example Prefetch a resource and wait until it has loaded. * // Replace AnimationCache with MaterialCache, ModelCache, SoundCache, or TextureCache as appropriate. * // TextureCache has its own version of this function. - * + * * var resourceURL = "https://cdn-1.vircadia.com/eu-c-1/vircadia-public/clement/production/animations/sitting_idle.fbx"; * var resourceObject = AnimationCache.prefetch(resourceURL); - * + * * function checkIfResourceLoaded(state) { * if (state === Resource.State.FINISHED) { * print("Resource loaded and ready."); @@ -368,11 +368,11 @@ public: * print("Resource not loaded."); * } * } - * + * * // Resource may have already been loaded. * print("Resource state: " + resourceObject.state); * checkIfResourceLoaded(resourceObject.state); - * + * * // Resource may still be loading. * resourceObject.stateChanged.connect(function (state) { * print("Resource state changed to: " + state); @@ -380,7 +380,7 @@ public: * }); */ Q_INVOKABLE ScriptableResource* prefetch(const QUrl& url) { return prefetch(url, nullptr, std::numeric_limits::max()); } - + // FIXME: This function variation shouldn't be in the API. Q_INVOKABLE ScriptableResource* prefetch(const QUrl& url, void* extra, size_t extraHash); @@ -443,7 +443,7 @@ public: /// For loading resources, returns the number of bytes received. qint64 getBytesReceived() const { return _bytesReceived; } - + /// For loading resources, returns the number of total bytes (<= zero if unknown). qint64 getBytesTotal() const { return _bytesTotal; } @@ -452,7 +452,7 @@ public: /// For loading resources, returns the load progress. float getProgress() const { return (_bytesTotal <= 0) ? 0.0f : (float)_bytesReceived / _bytesTotal; } - + /// Refreshes the resource. virtual void refresh(); @@ -461,7 +461,7 @@ public: void setCache(ResourceCache* cache) { _cache = cache; } virtual void deleter() { allReferencesCleared(); } - + const QUrl& getURL() const { return _url; } unsigned int getDownloadAttempts() { return _attempts; } @@ -557,15 +557,15 @@ public slots: private: friend class ResourceCache; friend class ScriptableResource; - + void setLRUKey(int lruKey) { _lruKey = lruKey; } - + void retry(); void reinsert(); bool isInScript() const { return _isInScript; } void setInScript(bool isInScript) { _isInScript = isInScript; } - + int _lruKey{ 0 }; QTimer* _replyTimer{ nullptr }; unsigned int _attempts{ 0 }; diff --git a/libraries/script-engine/src/ScriptEngines.cpp b/libraries/script-engine/src/ScriptEngines.cpp index ab47f80731..0e62297905 100644 --- a/libraries/script-engine/src/ScriptEngines.cpp +++ b/libraries/script-engine/src/ScriptEngines.cpp @@ -69,7 +69,7 @@ ScriptEngines::ScriptEngines(ScriptEngine::Context context, const QUrl& defaultS : _context(context), _defaultScriptsOverride(defaultScriptsOverride) { scriptGatekeeper.initialize(); - + _scriptsModelFilter.setSourceModel(&_scriptsModel); _scriptsModelFilter.sort(0, Qt::AscendingOrder); _scriptsModelFilter.setDynamicSortFilter(true); @@ -198,7 +198,7 @@ void ScriptEngines::shutdownScripting() { * @typedef {object} ScriptDiscoveryService.PublicScript * @property {string} name - The script's file name. * @property {string} type - "script" or "folder". - *

Deprecated: This property is deprecated and will be removed. It currently always has the value, + *

Deprecated: This property is deprecated and will be removed. It currently always has the value, * "script".

* @property {ScriptDiscoveryService.PublicScript[]} [children] - Only present if type == "folder". *

Deprecated: This property is deprecated and will be removed. It currently is never present. @@ -266,7 +266,7 @@ QVariantList ScriptEngines::getLocal() { /*@jsdoc * Information on a running script. * @typedef {object} ScriptDiscoveryService.RunningScript - * @property {boolean} local - true if the script is a local file (i.e., the scheme is "file"), false + * @property {boolean} local - true if the script is a local file (i.e., the scheme is "file"), false * if it isn't (e.g., the scheme is "http"). * @property {string} name - The script's file name. * @property {string} path - The script's path and file name — excluding the scheme if a local file. @@ -448,7 +448,7 @@ bool ScriptEngines::stopScript(const QString& rawScriptURL, bool restart) { QReadLocker lock(&_scriptEnginesHashLock); if (_scriptEnginesHash.contains(scriptURL)) { - ScriptEnginePointer scriptEngine = _scriptEnginesHash[scriptURL]; + ScriptEnginePointer scriptEngine = _scriptEnginesHash.value(scriptURL); if (restart) { bool isUserLoaded = scriptEngine->isUserLoaded(); ScriptEngine::Type type = scriptEngine->getType(); @@ -561,7 +561,7 @@ void ScriptEngines::onScriptEngineLoaded(const QString& rawScriptURL) { QWriteLocker lock(&_scriptEnginesHashLock); QUrl url = QUrl(rawScriptURL); QUrl normalized = normalizeScriptURL(url); - _scriptEnginesHash.insertMulti(normalized, scriptEngine); + _scriptEnginesHash.insert(normalized, scriptEngine); } // Update settings with new script diff --git a/libraries/script-engine/src/ScriptEngines.h b/libraries/script-engine/src/ScriptEngines.h index 61d8f95442..bc41fb8ab4 100644 --- a/libraries/script-engine/src/ScriptEngines.h +++ b/libraries/script-engine/src/ScriptEngines.h @@ -41,15 +41,15 @@ class ScriptEngine; * @hifi-avatar * @hifi-client-entity * - * @property {string} debugScriptUrl="" - The path and name of a script to debug using the "API Debugger" developer tool - * (currentAPI.js). If set, the API Debugger dialog displays the objects and values exposed by the script using + * @property {string} debugScriptUrl="" - The path and name of a script to debug using the "API Debugger" developer tool + * (currentAPI.js). If set, the API Debugger dialog displays the objects and values exposed by the script using * {@link Script.registerValue} and similar. - * @property {string} defaultScriptsPath - The path where the default scripts are located in the Interface installation. + * @property {string} defaultScriptsPath - The path where the default scripts are located in the Interface installation. * Read-only. - * @property {ScriptsModel} scriptsModel - Information on the scripts that are in the default scripts directory of the + * @property {ScriptsModel} scriptsModel - Information on the scripts that are in the default scripts directory of the * Interface installation. * Read-only. - * @property {ScriptsModelFilter} scriptsModelFilter - Sorted and filtered information on the scripts that are in the default + * @property {ScriptsModelFilter} scriptsModelFilter - Sorted and filtered information on the scripts that are in the default * scripts directory of the Interface installation. * Read-only. */ @@ -83,13 +83,13 @@ public: QString getDefaultScriptsLocation() const; /*@jsdoc - * Starts running an Interface script, if it isn't already running. The script is automatically loaded next time Interface + * Starts running an Interface script, if it isn't already running. The script is automatically loaded next time Interface * starts. *

This is a synonym for calling {@link ScriptDiscoveryService.loadScript|loadScript} with just the script URL.

*

Supported Script Types: Interface Scripts • Avatar Scripts

*

See also, {@link Script.load}.

* @function ScriptDiscoveryService.loadOneScript - * @param {string} url - The path and name of the script. If a local file, including the "file:///" scheme is + * @param {string} url - The path and name of the script. If a local file, including the "file:///" scheme is * optional. */ Q_INVOKABLE void loadOneScript(const QString& scriptFilename); @@ -99,15 +99,15 @@ public: *

Supported Script Types: Interface Scripts • Avatar Scripts

*

See also, {@link Script.load}.

* @function ScriptDiscoveryService.loadScript - * @param {string} [url=""] - The path and name of the script. If a local file, including the "file:///" + * @param {string} [url=""] - The path and name of the script. If a local file, including the "file:///" * scheme is optional. - * @param {boolean} [isUserLoaded=true] - true if the user specifically loaded it, false if not + * @param {boolean} [isUserLoaded=true] - true if the user specifically loaded it, false if not * (e.g., a script loaded it). If false, the script is not automatically loaded next time Interface starts. * @param {boolean} [loadScriptFromEditor=false] - Not used. * @param {boolean} [activateMainWindow=false] - Not used. - * @param {boolean} [reload=false] - true to redownload the script, false to use the copy from + * @param {boolean} [reload=false] - true to redownload the script, false to use the copy from * the cache if available. - * @param {boolean} [quitWhenFinished=false] - true to close Interface when the script finishes, + * @param {boolean} [quitWhenFinished=false] - true to close Interface when the script finishes, * false to not close Interface. * @returns {object} An empty object, {}. */ @@ -117,11 +117,11 @@ public: /*@jsdoc * Stops or restarts an Interface script. * @function ScriptDiscoveryService.stopScript - * @param {string} url - The path and name of the script. If a local file, including the "file:///" scheme is + * @param {string} url - The path and name of the script. If a local file, including the "file:///" scheme is * optional. - * @param {boolean} [restart=false] - true to redownload and restart the script, false to stop + * @param {boolean} [restart=false] - true to redownload and restart the script, false to stop * it. - * @returns {boolean} true if the script was successfully stopped or restarted, false if it + * @returns {boolean} true if the script was successfully stopped or restarted, false if it * wasn't (e.g., the script couldn't be found). */ Q_INVOKABLE bool stopScript(const QString& scriptHash, bool restart = false); @@ -134,7 +134,7 @@ public: Q_INVOKABLE void reloadAllScripts(); /*@jsdoc - * Stops or restarts all Interface scripts. The scripts cache is not cleared. If restarting, avatar and client entity + * Stops or restarts all Interface scripts. The scripts cache is not cleared. If restarting, avatar and client entity * scripts are also restarted. * @function ScriptDiscoveryService.stopAllScripts * @param {boolean} [restart=false] - true to restart the scripts, false to stop them. @@ -158,7 +158,7 @@ public: /*@jsdoc * Gets a list of all script files that are in the default scripts directory of the Interface installation. * @function ScriptDiscoveryService.getPublic - * @returns {ScriptDiscoveryService.PublicScript[]} All scripts in the "scripts" directory of the Interface + * @returns {ScriptDiscoveryService.PublicScript[]} All scripts in the "scripts" directory of the Interface * installation. */ Q_INVOKABLE QVariantList getPublic(); @@ -181,7 +181,7 @@ public: bool isStopped() const { return _isStopped; } void addScriptEngine(ScriptEnginePointer); - + ScriptGatekeeper scriptGatekeeper; signals: @@ -199,7 +199,7 @@ signals: /*@jsdoc * Triggered when Interface, avatar, and client entity scripts are restarting as a result of - * {@link ScriptDiscoveryService.reloadAllScripts|reloadAllScripts} or + * {@link ScriptDiscoveryService.reloadAllScripts|reloadAllScripts} or * {@link ScriptDiscoveryService.stopAllScripts|stopAllScripts}. * @function ScriptDiscoveryService.scriptsReloading * @returns {Signal} @@ -344,7 +344,7 @@ protected: ScriptEngine::Context _context; QReadWriteLock _scriptEnginesHashLock; - QHash _scriptEnginesHash; + QMultiHash _scriptEnginesHash; QSet _allKnownScriptEngines; QMutex _allScriptsMutex; ScriptsModel _scriptsModel; diff --git a/libraries/shared/src/HifiConfigVariantMap.cpp b/libraries/shared/src/HifiConfigVariantMap.cpp index 91ec056f1a..71748ffd10 100644 --- a/libraries/shared/src/HifiConfigVariantMap.cpp +++ b/libraries/shared/src/HifiConfigVariantMap.cpp @@ -26,7 +26,7 @@ QVariantMap HifiConfigVariantMap::mergeCLParametersWithJSONConfig(const QStringList& argumentList) { - QVariantMap mergedMap; + QMultiMap mergedMap; // Add anything in the CL parameter list to the variant map. // Take anything with a dash in it as a key, and the values after it as the value. @@ -49,7 +49,7 @@ QVariantMap HifiConfigVariantMap::mergeCLParametersWithJSONConfig(const QStringL if (nextKeyIndex == keyIndex + 1 || keyIndex == argumentList.size() - 1) { // this option is simply a switch, so add it to the map with a value of `true` - mergedMap.insertMulti(key, QVariant(true)); + mergedMap.insert(key, QVariant(true)); } else { int maxIndex = (nextKeyIndex == -1) ? argumentList.size() : nextKeyIndex; diff --git a/libraries/shared/src/shared/HifiTypes.h b/libraries/shared/src/shared/HifiTypes.h index 500170c88b..8fdeeeb3f5 100644 --- a/libraries/shared/src/shared/HifiTypes.h +++ b/libraries/shared/src/shared/HifiTypes.h @@ -15,10 +15,14 @@ #include #include #include +#include +#include namespace hifi { using ByteArray = QByteArray; using VariantHash = QVariantHash; + using VariantMultiHash = QMultiHash; + using VariantMultiMap = QMultiMap; using URL = QUrl; }; diff --git a/libraries/task/src/task/Config.h b/libraries/task/src/task/Config.h index c4a7b8ebbe..785f94d428 100644 --- a/libraries/task/src/task/Config.h +++ b/libraries/task/src/task/Config.h @@ -59,7 +59,7 @@ public: auto preset = _preset.get(); if (preset != _preset.getDefault() && _presets.contains(preset)) { // Load the persisted configuration - C::load(_presets[preset].toMap()); + C::load(_presets.value(preset).toMap()); } } @@ -79,8 +79,8 @@ public: } protected: - QVariantMap _default; - QVariantMap _presets; + QMultiMap _default; + QMultiMap _presets; Setting::Handle _preset; };