diff --git a/interface/resources/qml/LoginDialog/LinkAccountBody.qml b/interface/resources/qml/LoginDialog/LinkAccountBody.qml index 103761236d..3e4614c342 100644 --- a/interface/resources/qml/LoginDialog/LinkAccountBody.qml +++ b/interface/resources/qml/LoginDialog/LinkAccountBody.qml @@ -23,6 +23,8 @@ Item { width: root.pane.width property bool failAfterSignUp: false + onWidthChanged: d.resize(); + function login() { flavorText.visible = false mainTextContainer.visible = false @@ -127,7 +129,7 @@ Item { Column { id: form width: parent.width - onHeightChanged: d.resize(); onWidthChanged: d.resize(); + onHeightChanged: d.resize(); anchors { top: mainTextContainer.bottom diff --git a/interface/resources/qml/controlsUit/Keyboard.qml b/interface/resources/qml/controlsUit/Keyboard.qml index c38631ff79..a55523f34a 100644 --- a/interface/resources/qml/controlsUit/Keyboard.qml +++ b/interface/resources/qml/controlsUit/Keyboard.qml @@ -44,14 +44,14 @@ Rectangle { onPasswordChanged: { - var use3DKeyboard = (typeof MenuInterface === "undefined") ? false : MenuInterface.isOptionChecked("Use 3D Keyboard"); + var use3DKeyboard = (typeof KeyboardScriptingInterface === "undefined") ? false : KeyboardScriptingInterface.use3DKeyboard; if (use3DKeyboard) { KeyboardScriptingInterface.password = password; } } onRaisedChanged: { - var use3DKeyboard = (typeof MenuInterface === "undefined") ? false : MenuInterface.isOptionChecked("Use 3D Keyboard"); + var use3DKeyboard = (typeof KeyboardScriptingInterface === "undefined") ? false : KeyboardScriptingInterface.use3DKeyboard; if (!use3DKeyboard) { keyboardBase.height = raised ? raisedHeight : 0; keyboardBase.visible = raised; diff --git a/interface/resources/qml/hifi/tablet/TabletHome.qml b/interface/resources/qml/hifi/tablet/TabletHome.qml index f1f54e8419..1b0165ea94 100644 --- a/interface/resources/qml/hifi/tablet/TabletHome.qml +++ b/interface/resources/qml/hifi/tablet/TabletHome.qml @@ -61,7 +61,7 @@ Item { RalewaySemiBold { text: Account.loggedIn ? qsTr("Log out") : qsTr("Log in") horizontalAlignment: Text.AlignRight - anchors.right: parent.right + Layout.alignment: Qt.AlignRight font.pixelSize: 20 color: "#afafaf" } @@ -71,7 +71,7 @@ Item { height: Account.loggedIn ? parent.height/2 - parent.spacing/2 : 0 text: Account.loggedIn ? "[" + tabletRoot.usernameShort + "]" : "" horizontalAlignment: Text.AlignRight - anchors.right: parent.right + Layout.alignment: Qt.AlignRight font.pixelSize: 20 color: "#afafaf" } diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 21af28ffcb..cb41a8c240 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2572,6 +2572,8 @@ void Application::cleanupBeforeQuit() { QString webengineRemoteDebugging = QProcessEnvironment::systemEnvironment().value("QTWEBENGINE_REMOTE_DEBUGGING", "false"); qCDebug(interfaceapp) << "QTWEBENGINE_REMOTE_DEBUGGING =" << webengineRemoteDebugging; + DependencyManager::prepareToExit(); + if (tracing::enabled()) { auto tracer = DependencyManager::get(); tracer->stopTracing(); @@ -2684,6 +2686,7 @@ void Application::cleanupBeforeQuit() { // destroy Audio so it and its threads have a chance to go down safely // this must happen after QML, as there are unexplained audio crashes originating in qtwebengine + QMetaObject::invokeMethod(DependencyManager::get().data(), "stop"); DependencyManager::destroy(); DependencyManager::destroy(); DependencyManager::destroy(); @@ -2775,7 +2778,7 @@ Application::~Application() { // quit the thread used by the closure event sender closeEventSender->thread()->quit(); - // Can't log to file passed this point, FileLogger about to be deleted + // Can't log to file past this point, FileLogger about to be deleted qInstallMessageHandler(LogHandler::verboseMessageHandler); _renderEventHandler->deleteLater(); @@ -6304,6 +6307,11 @@ void Application::update(float deltaTime) { PerformanceTimer perfTimer("enqueueFrame"); getMain3DScene()->enqueueFrame(); } + + // If the display plugin is inactive then the frames won't be processed so process them here. + if (!getActiveDisplayPlugin()->isActive()) { + getMain3DScene()->processTransactionQueue(); + } } void Application::updateRenderArgs(float deltaTime) { diff --git a/interface/src/AvatarBookmarks.cpp b/interface/src/AvatarBookmarks.cpp index 534fb15d93..099171a427 100644 --- a/interface/src/AvatarBookmarks.cpp +++ b/interface/src/AvatarBookmarks.cpp @@ -247,25 +247,35 @@ QVariantMap AvatarBookmarks::getAvatarDataToBookmark() { bookmark.insert(ENTRY_AVATAR_URL, avatarUrl); bookmark.insert(ENTRY_AVATAR_SCALE, avatarScale); - QScriptEngine scriptEngine; QVariantList wearableEntities; auto treeRenderer = DependencyManager::get(); EntityTreePointer entityTree = treeRenderer ? treeRenderer->getTree() : nullptr; - auto avatarEntities = myAvatar->getAvatarEntityData(); - for (auto entityID : avatarEntities.keys()) { - auto entity = entityTree->findEntityByID(entityID); - if (!entity || !isWearableEntity(entity)) { - continue; + + if (entityTree) { + QScriptEngine scriptEngine; + auto avatarEntities = myAvatar->getAvatarEntityData(); + for (auto entityID : avatarEntities.keys()) { + auto entity = entityTree->findEntityByID(entityID); + if (!entity || !isWearableEntity(entity)) { + continue; + } + + QVariantMap avatarEntityData; + + EncodeBitstreamParams params; + auto desiredProperties = entity->getEntityProperties(params); + desiredProperties += PROP_LOCAL_POSITION; + desiredProperties += PROP_LOCAL_ROTATION; + desiredProperties -= PROP_JOINT_ROTATIONS_SET; + desiredProperties -= PROP_JOINT_ROTATIONS; + desiredProperties -= PROP_JOINT_TRANSLATIONS_SET; + desiredProperties -= PROP_JOINT_TRANSLATIONS; + + EntityItemProperties entityProperties = entity->getProperties(desiredProperties); + QScriptValue scriptProperties = EntityItemPropertiesToScriptValue(&scriptEngine, entityProperties); + avatarEntityData["properties"] = scriptProperties.toVariant(); + wearableEntities.append(QVariant(avatarEntityData)); } - QVariantMap avatarEntityData; - EncodeBitstreamParams params; - auto desiredProperties = entity->getEntityProperties(params); - desiredProperties += PROP_LOCAL_POSITION; - desiredProperties += PROP_LOCAL_ROTATION; - EntityItemProperties entityProperties = entity->getProperties(desiredProperties); - QScriptValue scriptProperties = EntityItemPropertiesToScriptValue(&scriptEngine, entityProperties); - avatarEntityData["properties"] = scriptProperties.toVariant(); - wearableEntities.append(QVariant(avatarEntityData)); } bookmark.insert(ENTRY_AVATAR_ENTITIES, wearableEntities); return bookmark; diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 13c622627d..e9a44b1e87 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -364,8 +364,6 @@ Menu::Menu() { qApp->setHmdTabletBecomesToolbarSetting(action->isChecked()); }); - addCheckableActionToQMenuAndActionHash(uiOptionsMenu, MenuOption::Use3DKeyboard, 0, true); - // Developer > Render >>> MenuWrapper* renderOptionsMenu = developerMenu->addMenu("Render"); diff --git a/interface/src/Menu.h b/interface/src/Menu.h index d3d9e5e674..e0e48ff32c 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -213,7 +213,6 @@ namespace MenuOption { const QString TurnWithHead = "Turn using Head"; const QString UseAudioForMouth = "Use Audio for Mouth"; const QString UseCamera = "Use Camera"; - const QString Use3DKeyboard = "Use 3D Keyboard"; const QString VelocityFilter = "Velocity Filter"; const QString VisibleToEveryone = "Everyone"; const QString VisibleToFriends = "Friends"; diff --git a/interface/src/ModelPackager.cpp b/interface/src/ModelPackager.cpp index c4f8ef5ddd..84325da473 100644 --- a/interface/src/ModelPackager.cpp +++ b/interface/src/ModelPackager.cpp @@ -17,6 +17,7 @@ #include #include +#include #include #include "ModelSelector.h" @@ -108,7 +109,7 @@ bool ModelPackager::loadModel() { qCDebug(interfaceapp) << "Reading FBX file : " << _fbxInfo.filePath(); QByteArray fbxContents = fbx.readAll(); - _hfmModel.reset(readFBX(fbxContents, QVariantHash(), _fbxInfo.filePath())); + _hfmModel = FBXSerializer().read(fbxContents, QVariantHash(), _fbxInfo.filePath()); // make sure we have some basic mappings populateBasicMapping(_mapping, _fbxInfo.filePath(), *_hfmModel); diff --git a/interface/src/ModelPackager.h b/interface/src/ModelPackager.h index 09dab5039f..58d3d6bfee 100644 --- a/interface/src/ModelPackager.h +++ b/interface/src/ModelPackager.h @@ -45,7 +45,7 @@ private: QString _scriptDir; QVariantHash _mapping; - std::unique_ptr _hfmModel; + std::shared_ptr _hfmModel; QStringList _textures; QStringList _scripts; }; diff --git a/interface/src/ModelPropertiesDialog.h b/interface/src/ModelPropertiesDialog.h index 1058dbfa4e..7019d239ff 100644 --- a/interface/src/ModelPropertiesDialog.h +++ b/interface/src/ModelPropertiesDialog.h @@ -14,7 +14,7 @@ #include -#include +#include #include #include "ui/ModelsBrowser.h" diff --git a/interface/src/ModelSelector.cpp b/interface/src/ModelSelector.cpp index 7e428a294d..3223e3ab9c 100644 --- a/interface/src/ModelSelector.cpp +++ b/interface/src/ModelSelector.cpp @@ -19,7 +19,6 @@ #include static const QString AVATAR_HEAD_AND_BODY_STRING = "Avatar Body with Head"; -static const QString AVATAR_ATTACHEMENT_STRING = "Avatar Attachment"; static const QString ENTITY_MODEL_STRING = "Entity Model"; ModelSelector::ModelSelector() { diff --git a/interface/src/raypick/CollisionPick.cpp b/interface/src/raypick/CollisionPick.cpp index dfb0db1da1..d30f98051e 100644 --- a/interface/src/raypick/CollisionPick.cpp +++ b/interface/src/raypick/CollisionPick.cpp @@ -149,7 +149,7 @@ void CollisionPick::computeShapeInfo(const CollisionRegion& pick, ShapeInfo& sha uint32_t numIndices = (uint32_t)meshPart.triangleIndices.size(); // TODO: assert rather than workaround after we start sanitizing HFMMesh higher up //assert(numIndices % TRIANGLE_STRIDE == 0); - numIndices -= numIndices % TRIANGLE_STRIDE; // WORKAROUND lack of sanity checking in FBXReader + numIndices -= numIndices % TRIANGLE_STRIDE; // WORKAROUND lack of sanity checking in FBXSerializer for (uint32_t j = 0; j < numIndices; j += TRIANGLE_STRIDE) { glm::vec3 p0 = mesh.vertices[meshPart.triangleIndices[j]]; @@ -170,7 +170,7 @@ void CollisionPick::computeShapeInfo(const CollisionRegion& pick, ShapeInfo& sha numIndices = (uint32_t)meshPart.quadIndices.size(); // TODO: assert rather than workaround after we start sanitizing HFMMesh higher up //assert(numIndices % QUAD_STRIDE == 0); - numIndices -= numIndices % QUAD_STRIDE; // WORKAROUND lack of sanity checking in FBXReader + numIndices -= numIndices % QUAD_STRIDE; // WORKAROUND lack of sanity checking in FBXSerializer for (uint32_t j = 0; j < numIndices; j += QUAD_STRIDE) { glm::vec3 p0 = mesh.vertices[meshPart.quadIndices[j]]; @@ -305,7 +305,7 @@ void CollisionPick::computeShapeInfo(const CollisionRegion& pick, ShapeInfo& sha auto numIndices = meshPart.triangleIndices.count(); // TODO: assert rather than workaround after we start sanitizing HFMMesh higher up //assert(numIndices% TRIANGLE_STRIDE == 0); - numIndices -= numIndices % TRIANGLE_STRIDE; // WORKAROUND lack of sanity checking in FBXReader + numIndices -= numIndices % TRIANGLE_STRIDE; // WORKAROUND lack of sanity checking in FBXSerializer auto indexItr = meshPart.triangleIndices.cbegin(); while (indexItr != meshPart.triangleIndices.cend()) { diff --git a/interface/src/scripting/KeyboardScriptingInterface.cpp b/interface/src/scripting/KeyboardScriptingInterface.cpp index b26e1ec378..d86bb56e64 100644 --- a/interface/src/scripting/KeyboardScriptingInterface.cpp +++ b/interface/src/scripting/KeyboardScriptingInterface.cpp @@ -32,3 +32,7 @@ void KeyboardScriptingInterface::setPassword(bool password) { void KeyboardScriptingInterface::loadKeyboardFile(const QString& keyboardFile) { DependencyManager::get()->loadKeyboardFile(keyboardFile); } + +bool KeyboardScriptingInterface::getUse3DKeyboard() { + return DependencyManager::get()->getUse3DKeyboard(); +} diff --git a/interface/src/scripting/KeyboardScriptingInterface.h b/interface/src/scripting/KeyboardScriptingInterface.h index 1ab91ea7c3..709dfe01de 100644 --- a/interface/src/scripting/KeyboardScriptingInterface.h +++ b/interface/src/scripting/KeyboardScriptingInterface.h @@ -30,6 +30,7 @@ class KeyboardScriptingInterface : public QObject, public Dependency { Q_OBJECT Q_PROPERTY(bool raised READ isRaised WRITE setRaised) Q_PROPERTY(bool password READ isPassword WRITE setPassword) + Q_PROPERTY(bool use3DKeyboard READ getUse3DKeyboard); public: Q_INVOKABLE void loadKeyboardFile(const QString& string); @@ -39,5 +40,7 @@ private: bool isPassword(); void setPassword(bool password); + + bool getUse3DKeyboard(); }; #endif diff --git a/interface/src/ui/Keyboard.cpp b/interface/src/ui/Keyboard.cpp index 6852691634..d647851a80 100644 --- a/interface/src/ui/Keyboard.cpp +++ b/interface/src/ui/Keyboard.cpp @@ -60,7 +60,7 @@ static const float MALLET_TOUCH_Y_OFFSET = 0.050f; static const float MALLET_Y_OFFSET = 0.160f; static const glm::quat MALLET_ROTATION_OFFSET{0.70710678f, 0.0f, -0.70710678f, 0.0f}; -static const glm::vec3 MALLET_MODEL_DIMENSIONS{0.03f, MALLET_LENGTH, 0.03f}; +static const glm::vec3 MALLET_MODEL_DIMENSIONS{0.01f, MALLET_LENGTH, 0.01f}; static const glm::vec3 MALLET_POSITION_OFFSET{0.0f, -MALLET_Y_OFFSET / 2.0f, 0.0f}; static const glm::vec3 MALLET_TIP_OFFSET{0.0f, MALLET_LENGTH - MALLET_TOUCH_Y_OFFSET, 0.0f}; @@ -241,6 +241,17 @@ void Keyboard::registerKeyboardHighlighting() { selection->enableListToScene(KEY_PRESSED_HIGHLIGHT); } +bool Keyboard::getUse3DKeyboard() const { + return _use3DKeyboardLock.resultWithReadLock([&] { + return _use3DKeyboard.get(); + }); +} + +void Keyboard::setUse3DKeyboard(bool use) { + _use3DKeyboardLock.withWriteLock([&] { + _use3DKeyboard.set(use); + }); +} void Keyboard::createKeyboard() { auto pointerManager = DependencyManager::get(); diff --git a/interface/src/ui/Keyboard.h b/interface/src/ui/Keyboard.h index 18db38b2ae..9c0c8c40f2 100644 --- a/interface/src/ui/Keyboard.h +++ b/interface/src/ui/Keyboard.h @@ -23,6 +23,7 @@ #include #include #include +#include #include "ui/overlays/Overlay.h" @@ -97,6 +98,9 @@ public: bool isPassword() const; void setPassword(bool password); + bool getUse3DKeyboard() const; + void setUse3DKeyboard(bool use); + void loadKeyboardFile(const QString& keyboardFile); QVector getKeysID(); @@ -143,6 +147,9 @@ private: SharedSoundPointer _keySound { nullptr }; std::shared_ptr _layerSwitchTimer { std::make_shared() }; + mutable ReadWriteLockable _use3DKeyboardLock; + Setting::Handle _use3DKeyboard { "use3DKeyboard", true }; + QString _typedCharacters; TextDisplay _textDisplay; Anchor _anchor; diff --git a/interface/src/ui/PreferencesDialog.cpp b/interface/src/ui/PreferencesDialog.cpp index 5f8b191a4f..d1fbe02759 100644 --- a/interface/src/ui/PreferencesDialog.cpp +++ b/interface/src/ui/PreferencesDialog.cpp @@ -24,6 +24,7 @@ #include "Snapshot.h" #include "SnapshotAnimated.h" #include "UserActivityLogger.h" +#include "ui/Keyboard.h" void setupPreferences() { auto preferences = DependencyManager::get(); @@ -119,6 +120,12 @@ void setupPreferences() { preferences->addPreference(new CheckPreference(UI_CATEGORY, "Use reticle cursor instead of arrow", getter, setter)); } + { + auto getter = []()->bool { return DependencyManager::get()->getUse3DKeyboard(); }; + auto setter = [](bool value) { DependencyManager::get()->setUse3DKeyboard(value); }; + preferences->addPreference(new CheckPreference(UI_CATEGORY, "Use Virtual Keyboard", getter, setter)); + } + { auto getter = []()->bool { return qApp->getMiniTabletEnabled(); }; auto setter = [](bool value) { qApp->setMiniTabletEnabled(value); }; diff --git a/libraries/animation/src/AnimSkeleton.h b/libraries/animation/src/AnimSkeleton.h index ab89eb643d..14f39eedbc 100644 --- a/libraries/animation/src/AnimSkeleton.h +++ b/libraries/animation/src/AnimSkeleton.h @@ -15,7 +15,7 @@ #include #include -#include +#include #include "AnimPose.h" class AnimSkeleton { diff --git a/libraries/animation/src/AnimationCache.cpp b/libraries/animation/src/AnimationCache.cpp index 501b9e964d..ec26782d0e 100644 --- a/libraries/animation/src/AnimationCache.cpp +++ b/libraries/animation/src/AnimationCache.cpp @@ -71,7 +71,7 @@ void AnimationReader::run() { // Parse the FBX directly from the QNetworkReply HFMModel::Pointer hfmModel; if (_url.path().toLower().endsWith(".fbx")) { - hfmModel.reset(readFBX(_data, QVariantHash(), _url.path())); + hfmModel = FBXSerializer().read(_data, QVariantHash(), _url.path()); } else { QString errorStr("usupported format"); emit onError(299, errorStr); diff --git a/libraries/animation/src/AnimationCache.h b/libraries/animation/src/AnimationCache.h index 4423e8f18d..d4574d9d3b 100644 --- a/libraries/animation/src/AnimationCache.h +++ b/libraries/animation/src/AnimationCache.h @@ -17,7 +17,7 @@ #include #include -#include +#include #include class Animation; diff --git a/libraries/animation/src/AnimationObject.h b/libraries/animation/src/AnimationObject.h index 83880ed2ab..fc3a351832 100644 --- a/libraries/animation/src/AnimationObject.h +++ b/libraries/animation/src/AnimationObject.h @@ -15,7 +15,7 @@ #include #include -#include +#include class QScriptEngine; diff --git a/libraries/audio-client/src/AudioClient.cpp b/libraries/audio-client/src/AudioClient.cpp index 92f7a27853..9bad7e2f45 100644 --- a/libraries/audio-client/src/AudioClient.cpp +++ b/libraries/audio-client/src/AudioClient.cpp @@ -302,7 +302,6 @@ void AudioClient::customDeleter() { #if defined(Q_OS_ANDROID) _shouldRestartInputSetup = false; #endif - stop(); deleteLater(); } diff --git a/libraries/audio/src/AudioDynamics.h b/libraries/audio/src/AudioDynamics.h index 8dbc7a75cc..6bfd249bc9 100644 --- a/libraries/audio/src/AudioDynamics.h +++ b/libraries/audio/src/AudioDynamics.h @@ -51,7 +51,7 @@ #include // convert float to int using round-to-nearest FORCEINLINE static int32_t floatToInt(float x) { - return _mm_cvt_ss2si(_mm_load_ss(&x)); + return _mm_cvt_ss2si(_mm_set_ss(x)); } #else @@ -150,7 +150,7 @@ static const int IEEE754_EXPN_BIAS = 127; // // Peak detection and -log2(x) for float input (mono) // x < 2^(31-LOG2_HEADROOM) returns 0x7fffffff -// x > 2^LOG2_HEADROOM undefined +// x > 2^LOG2_HEADROOM returns 0 // FORCEINLINE static int32_t peaklog2(float* input) { @@ -161,12 +161,12 @@ FORCEINLINE static int32_t peaklog2(float* input) { uint32_t peak = u & IEEE754_FABS_MASK; // split into e and x - 1.0 - int e = IEEE754_EXPN_BIAS - (peak >> IEEE754_MANT_BITS) + LOG2_HEADROOM; + int32_t e = IEEE754_EXPN_BIAS - (peak >> IEEE754_MANT_BITS) + LOG2_HEADROOM; int32_t x = (peak << IEEE754_EXPN_BITS) & 0x7fffffff; - // saturate - if (e > 31) { - return 0x7fffffff; + // saturate when e > 31 or e < 0 + if ((uint32_t)e > 31) { + return 0x7fffffff & ~(e >> 31); } int k = x >> (31 - LOG2_TABBITS); @@ -186,7 +186,7 @@ FORCEINLINE static int32_t peaklog2(float* input) { // // Peak detection and -log2(x) for float input (stereo) // x < 2^(31-LOG2_HEADROOM) returns 0x7fffffff -// x > 2^LOG2_HEADROOM undefined +// x > 2^LOG2_HEADROOM returns 0 // FORCEINLINE static int32_t peaklog2(float* input0, float* input1) { @@ -200,12 +200,12 @@ FORCEINLINE static int32_t peaklog2(float* input0, float* input1) { uint32_t peak = MAX(u0, u1); // split into e and x - 1.0 - int e = IEEE754_EXPN_BIAS - (peak >> IEEE754_MANT_BITS) + LOG2_HEADROOM; + int32_t e = IEEE754_EXPN_BIAS - (peak >> IEEE754_MANT_BITS) + LOG2_HEADROOM; int32_t x = (peak << IEEE754_EXPN_BITS) & 0x7fffffff; - // saturate - if (e > 31) { - return 0x7fffffff; + // saturate when e > 31 or e < 0 + if ((uint32_t)e > 31) { + return 0x7fffffff & ~(e >> 31); } int k = x >> (31 - LOG2_TABBITS); @@ -225,7 +225,7 @@ FORCEINLINE static int32_t peaklog2(float* input0, float* input1) { // // Peak detection and -log2(x) for float input (quad) // x < 2^(31-LOG2_HEADROOM) returns 0x7fffffff -// x > 2^LOG2_HEADROOM undefined +// x > 2^LOG2_HEADROOM returns 0 // FORCEINLINE static int32_t peaklog2(float* input0, float* input1, float* input2, float* input3) { @@ -243,12 +243,12 @@ FORCEINLINE static int32_t peaklog2(float* input0, float* input1, float* input2, uint32_t peak = MAX(MAX(u0, u1), MAX(u2, u3)); // split into e and x - 1.0 - int e = IEEE754_EXPN_BIAS - (peak >> IEEE754_MANT_BITS) + LOG2_HEADROOM; + int32_t e = IEEE754_EXPN_BIAS - (peak >> IEEE754_MANT_BITS) + LOG2_HEADROOM; int32_t x = (peak << IEEE754_EXPN_BITS) & 0x7fffffff; - // saturate - if (e > 31) { - return 0x7fffffff; + // saturate when e > 31 or e < 0 + if ((uint32_t)e > 31) { + return 0x7fffffff & ~(e >> 31); } int k = x >> (31 - LOG2_TABBITS); diff --git a/libraries/audio/src/AudioInjector.cpp b/libraries/audio/src/AudioInjector.cpp index 4af6e79caf..1581990e0c 100644 --- a/libraries/audio/src/AudioInjector.cpp +++ b/libraries/audio/src/AudioInjector.cpp @@ -447,9 +447,9 @@ AudioInjectorPointer AudioInjector::playSound(SharedSoundPointer sound, const A using AudioConstants::AudioSample; using AudioConstants::SAMPLE_RATE; const int standardRate = SAMPLE_RATE; - // limit to 4 octaves - const int pitch = glm::clamp(options.pitch, 1 / 16.0f, 16.0f); - const int resampledRate = SAMPLE_RATE / pitch; + // limit pitch to 4 octaves + const float pitch = glm::clamp(options.pitch, 1 / 16.0f, 16.0f); + const int resampledRate = glm::round(SAMPLE_RATE / pitch); auto audioData = sound->getAudioData(); auto numChannels = audioData->getNumChannels(); @@ -499,9 +499,9 @@ AudioInjectorPointer AudioInjector::playSound(AudioDataPointer audioData, const using AudioConstants::AudioSample; using AudioConstants::SAMPLE_RATE; const int standardRate = SAMPLE_RATE; - // limit to 4 octaves - const int pitch = glm::clamp(options.pitch, 1 / 16.0f, 16.0f); - const int resampledRate = SAMPLE_RATE / pitch; + // limit pitch to 4 octaves + const float pitch = glm::clamp(options.pitch, 1 / 16.0f, 16.0f); + const int resampledRate = glm::round(SAMPLE_RATE / pitch); auto numChannels = audioData->getNumChannels(); auto numFrames = audioData->getNumFrames(); diff --git a/libraries/baking/src/FBXBaker.cpp b/libraries/baking/src/FBXBaker.cpp index cef6c9b900..afaca1dd62 100644 --- a/libraries/baking/src/FBXBaker.cpp +++ b/libraries/baking/src/FBXBaker.cpp @@ -27,7 +27,7 @@ #include -#include +#include #include #include "ModelBakingLoggingCategory.h" @@ -187,10 +187,10 @@ void FBXBaker::importScene() { return; } - FBXReader reader; + FBXSerializer fbxSerializer; qCDebug(model_baking) << "Parsing" << _modelURL; - _rootNode = reader._rootNode = reader.parseFBX(&fbxFile); + _rootNode = fbxSerializer._rootNode = fbxSerializer.parseFBX(&fbxFile); #ifdef HIFI_DUMP_FBX { @@ -206,8 +206,8 @@ void FBXBaker::importScene() { } #endif - _hfmModel = reader.extractHFMModel({}, _modelURL.toString()); - _textureContentMap = reader._textureContent; + _hfmModel = fbxSerializer.extractHFMModel({}, _modelURL.toString()); + _textureContentMap = fbxSerializer._textureContent; } void FBXBaker::rewriteAndBakeSceneModels() { @@ -232,7 +232,7 @@ void FBXBaker::rewriteAndBakeSceneModels() { if (objectChild.name == "Geometry") { // TODO Pull this out of _hfmModel instead so we don't have to reprocess it - auto extractedMesh = FBXReader::extractMesh(objectChild, meshIndex, false); + auto extractedMesh = FBXSerializer::extractMesh(objectChild, meshIndex, false); // Callback to get MaterialID GetMaterialIDCallback materialIDcallback = [&extractedMesh](int partIndex) { diff --git a/libraries/baking/src/ModelBaker.cpp b/libraries/baking/src/ModelBaker.cpp index ca352cebae..34f302b501 100644 --- a/libraries/baking/src/ModelBaker.cpp +++ b/libraries/baking/src/ModelBaker.cpp @@ -13,7 +13,6 @@ #include -#include #include #ifdef _WIN32 diff --git a/libraries/baking/src/OBJBaker.cpp b/libraries/baking/src/OBJBaker.cpp index d9f56b393e..5a1239f88f 100644 --- a/libraries/baking/src/OBJBaker.cpp +++ b/libraries/baking/src/OBJBaker.cpp @@ -14,7 +14,7 @@ #include #include -#include "OBJReader.h" +#include "OBJSerializer.h" #include "FBXWriter.h" const double UNIT_SCALE_FACTOR = 100.0; @@ -143,9 +143,10 @@ void OBJBaker::bakeOBJ() { QByteArray objData = objFile.readAll(); - bool combineParts = true; // set true so that OBJReader reads material info from material library - OBJReader reader; - auto geometry = reader.readOBJ(objData, QVariantHash(), combineParts, _modelURL); + OBJSerializer serializer; + QVariantHash mapping; + mapping["combineParts"] = true; // set true so that OBJSerializer reads material info from material library + auto geometry = serializer.read(objData, mapping, _modelURL); // Write OBJ Data as FBX tree nodes createFBXNodeTree(_rootNode, *geometry); @@ -219,7 +220,7 @@ void OBJBaker::createFBXNodeTree(FBXNode& rootNode, HFMModel& hfmModel) { FBXNode materialNode; materialNode.name = MATERIAL_NODE_NAME; if (hfmModel.materials.size() == 1) { - // case when no material information is provided, OBJReader considers it as a single default material + // case when no material information is provided, OBJSerializer considers it as a single default material for (auto& materialID : hfmModel.materials.keys()) { setMaterialNodeProperties(materialNode, materialID, hfmModel); } diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp index 9a68f81b66..2b1d70f4d0 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp @@ -421,7 +421,7 @@ void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& shapeInfo) { uint32_t numIndices = (uint32_t)meshPart.triangleIndices.size(); // TODO: assert rather than workaround after we start sanitizing HFMMesh higher up //assert(numIndices % TRIANGLE_STRIDE == 0); - numIndices -= numIndices % TRIANGLE_STRIDE; // WORKAROUND lack of sanity checking in FBXReader + numIndices -= numIndices % TRIANGLE_STRIDE; // WORKAROUND lack of sanity checking in FBXSerializer for (uint32_t j = 0; j < numIndices; j += TRIANGLE_STRIDE) { glm::vec3 p0 = mesh.vertices[meshPart.triangleIndices[j]]; @@ -442,7 +442,7 @@ void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& shapeInfo) { numIndices = (uint32_t)meshPart.quadIndices.size(); // TODO: assert rather than workaround after we start sanitizing HFMMesh higher up //assert(numIndices % QUAD_STRIDE == 0); - numIndices -= numIndices % QUAD_STRIDE; // WORKAROUND lack of sanity checking in FBXReader + numIndices -= numIndices % QUAD_STRIDE; // WORKAROUND lack of sanity checking in FBXSerializer for (uint32_t j = 0; j < numIndices; j += QUAD_STRIDE) { glm::vec3 p0 = mesh.vertices[meshPart.quadIndices[j]]; @@ -595,7 +595,7 @@ void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& shapeInfo) { if (partItr->_topology == graphics::Mesh::TRIANGLES) { // TODO: assert rather than workaround after we start sanitizing HFMMesh higher up //assert(numIndices % TRIANGLE_STRIDE == 0); - numIndices -= numIndices % TRIANGLE_STRIDE; // WORKAROUND lack of sanity checking in FBXReader + numIndices -= numIndices % TRIANGLE_STRIDE; // WORKAROUND lack of sanity checking in FBXSerializer auto indexItr = indices.cbegin() + partItr->_startIndex; auto indexEnd = indexItr + numIndices; @@ -652,7 +652,7 @@ void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& shapeInfo) { if (partItr->_topology == graphics::Mesh::TRIANGLES) { // TODO: assert rather than workaround after we start sanitizing HFMMesh higher up //assert(numIndices% TRIANGLE_STRIDE == 0); - numIndices -= numIndices % TRIANGLE_STRIDE; // WORKAROUND lack of sanity checking in FBXReader + numIndices -= numIndices % TRIANGLE_STRIDE; // WORKAROUND lack of sanity checking in FBXSerializer auto indexItr = indices.cbegin() + partItr->_startIndex; auto indexEnd = indexItr + numIndices; diff --git a/libraries/fbx/src/FBX.h b/libraries/fbx/src/FBX.h index 90de82e310..157ca5b282 100644 --- a/libraries/fbx/src/FBX.h +++ b/libraries/fbx/src/FBX.h @@ -33,7 +33,7 @@ using NormalType = glm::vec3; #define FBX_NORMAL_ELEMENT gpu::Element::VEC3F_XYZ #endif -// See comment in FBXReader::parseFBX(). +// See comment in FBXSerializer::parseFBX(). static const int FBX_HEADER_BYTES_BEFORE_VERSION = 23; static const QByteArray FBX_BINARY_PROLOG("Kaydara FBX Binary "); static const QByteArray FBX_BINARY_PROLOG2("\0\x1a\0", 3); diff --git a/libraries/fbx/src/FBXReader.cpp b/libraries/fbx/src/FBXSerializer.cpp similarity index 98% rename from libraries/fbx/src/FBXReader.cpp rename to libraries/fbx/src/FBXSerializer.cpp index dd10cd30b3..a9887cde15 100644 --- a/libraries/fbx/src/FBXReader.cpp +++ b/libraries/fbx/src/FBXSerializer.cpp @@ -1,6 +1,6 @@ // -// FBXReader.cpp -// interface/src/renderer +// FBXSerializer.cpp +// libraries/fbx/src // // Created by Andrzej Kapolka on 9/18/13. // Copyright 2013 High Fidelity, Inc. @@ -9,7 +9,7 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -#include "FBXReader.h" +#include "FBXSerializer.h" #include #include @@ -36,7 +36,7 @@ #include // TOOL: Uncomment the following line to enable the filtering of all the unkwnon fields of a node so we can break point easily while loading a model with problems... -//#define DEBUG_FBXREADER +//#define DEBUG_FBXSERIALIZER using namespace std; @@ -254,13 +254,13 @@ HFMBlendshape extractBlendshape(const FBXNode& object) { HFMBlendshape blendshape; foreach (const FBXNode& data, object.children) { if (data.name == "Indexes") { - blendshape.indices = FBXReader::getIntVector(data); + blendshape.indices = FBXSerializer::getIntVector(data); } else if (data.name == "Vertices") { - blendshape.vertices = FBXReader::createVec3Vector(FBXReader::getDoubleVector(data)); + blendshape.vertices = FBXSerializer::createVec3Vector(FBXSerializer::getDoubleVector(data)); } else if (data.name == "Normals") { - blendshape.normals = FBXReader::createVec3Vector(FBXReader::getDoubleVector(data)); + blendshape.normals = FBXSerializer::createVec3Vector(FBXSerializer::getDoubleVector(data)); } } return blendshape; @@ -384,7 +384,7 @@ HFMLight extractLight(const FBXNode& object) { if (propname == "Intensity") { light.intensity = 0.01f * property.properties.at(valIndex).value(); } else if (propname == "Color") { - light.color = FBXReader::getVec3(property.properties, valIndex); + light.color = FBXSerializer::getVec3(property.properties, valIndex); } } } @@ -392,7 +392,7 @@ HFMLight extractLight(const FBXNode& object) { || subobject.name == "TypeFlags") { } } -#if defined(DEBUG_FBXREADER) +#if defined(DEBUG_FBXSERIALIZER) QString type = object.properties.at(0).toString(); type = object.properties.at(1).toString(); @@ -441,7 +441,7 @@ QMap getJointRotationOffsets(const QVariantHash& mapping) { return jointRotationOffsets; } -HFMModel* FBXReader::extractHFMModel(const QVariantHash& mapping, const QString& url) { +HFMModel* FBXSerializer::extractHFMModel(const QVariantHash& mapping, const QString& url) { const FBXNode& node = _rootNode; QMap meshes; QHash modelIDsToNames; @@ -512,7 +512,7 @@ HFMModel* FBXReader::extractHFMModel(const QVariantHash& mapping, const QString& } } QMultiHash blendshapeChannelIndices; -#if defined(DEBUG_FBXREADER) +#if defined(DEBUG_FBXSERIALIZER) int unknown = 0; #endif HFMModel* hfmModelPtr = new HFMModel; @@ -760,7 +760,7 @@ HFMModel* FBXReader::extractHFMModel(const QVariantHash& mapping, const QString& extractBlendshape(subobject) }; blendshapes.append(blendshape); } -#if defined(DEBUG_FBXREADER) +#if defined(DEBUG_FBXSERIALIZER) else if (subobject.name == "TypeFlags") { QString attributetype = subobject.properties.at(0).toString(); if (!attributetype.empty()) { @@ -886,7 +886,7 @@ HFMModel* FBXReader::extractHFMModel(const QVariantHash& mapping, const QString& tex.scaling.z = 1.0f; } } -#if defined(DEBUG_FBXREADER) +#if defined(DEBUG_FBXSERIALIZER) else { QString propName = v; unknown++; @@ -895,7 +895,7 @@ HFMModel* FBXReader::extractHFMModel(const QVariantHash& mapping, const QString& } } } -#if defined(DEBUG_FBXREADER) +#if defined(DEBUG_FBXSERIALIZER) else { if (subobject.name == "Type") { } else if (subobject.name == "Version") { @@ -1068,7 +1068,7 @@ HFMModel* FBXReader::extractHFMModel(const QVariantHash& mapping, const QString& } } } -#if defined(DEBUG_FBXREADER) +#if defined(DEBUG_FBXSERIALIZER) else { QString propname = subobject.name.data(); int unknown = 0; @@ -1085,7 +1085,7 @@ HFMModel* FBXReader::extractHFMModel(const QVariantHash& mapping, const QString& } else if (object.name == "NodeAttribute") { -#if defined(DEBUG_FBXREADER) +#if defined(DEBUG_FBXSERIALIZER) std::vector properties; foreach(const QVariant& v, object.properties) { properties.push_back(v.toString()); @@ -1148,7 +1148,7 @@ HFMModel* FBXReader::extractHFMModel(const QVariantHash& mapping, const QString& animationCurves.insert(getID(object.properties), curve); } -#if defined(DEBUG_FBXREADER) +#if defined(DEBUG_FBXSERIALIZER) else { QString objectname = object.name.data(); if ( objectname == "Pose" @@ -1239,7 +1239,7 @@ HFMModel* FBXReader::extractHFMModel(const QVariantHash& mapping, const QString& } } } -#if defined(DEBUG_FBXREADER) +#if defined(DEBUG_FBXSERIALIZER) else { QString objectname = child.name.data(); if ( objectname == "Pose" @@ -1833,17 +1833,11 @@ HFMModel* FBXReader::extractHFMModel(const QVariantHash& mapping, const QString& return hfmModelPtr; } -HFMModel* readFBX(const QByteArray& data, const QVariantHash& mapping, const QString& url, bool loadLightmaps, float lightmapLevel) { +HFMModel::Pointer FBXSerializer::read(const QByteArray& data, const QVariantHash& mapping, const QUrl& url) { QBuffer buffer(const_cast(&data)); buffer.open(QIODevice::ReadOnly); - return readFBX(&buffer, mapping, url, loadLightmaps, lightmapLevel); -} -HFMModel* readFBX(QIODevice* device, const QVariantHash& mapping, const QString& url, bool loadLightmaps, float lightmapLevel) { - FBXReader reader; - reader._rootNode = FBXReader::parseFBX(device); - reader._loadLightmaps = loadLightmaps; - reader._lightmapLevel = lightmapLevel; + _rootNode = parseFBX(&buffer); - return reader.extractHFMModel(mapping, url); + return HFMModel::Pointer(extractHFMModel(mapping, url.toString())); } diff --git a/libraries/fbx/src/FBXReader.h b/libraries/fbx/src/FBXSerializer.h similarity index 85% rename from libraries/fbx/src/FBXReader.h rename to libraries/fbx/src/FBXSerializer.h index c74b4dc8ac..c69f75cc5c 100644 --- a/libraries/fbx/src/FBXReader.h +++ b/libraries/fbx/src/FBXSerializer.h @@ -1,6 +1,6 @@ // -// FBXReader.h -// interface/src/renderer +// FBXSerializer.h +// libraries/fbx/src // // Created by Andrzej Kapolka on 9/18/13. // Copyright 2013 High Fidelity, Inc. @@ -9,8 +9,8 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -#ifndef hifi_FBXReader_h -#define hifi_FBXReader_h +#ifndef hifi_FBXSerializer_h +#define hifi_FBXSerializer_h #include #include @@ -27,7 +27,7 @@ #include #include "FBX.h" -#include +#include #include #include @@ -35,14 +35,6 @@ class QIODevice; class FBXNode; -/// Reads HFMModel from the supplied model and mapping data. -/// \exception QString if an error occurs in parsing -HFMModel* readFBX(const QByteArray& data, const QVariantHash& mapping, const QString& url = "", bool loadLightmaps = true, float lightmapLevel = 1.0f); - -/// Reads HFMModel from the supplied model and mapping data. -/// \exception QString if an error occurs in parsing -HFMModel* readFBX(QIODevice* device, const QVariantHash& mapping, const QString& url = "", bool loadLightmaps = true, float lightmapLevel = 1.0f); - class TextureParam { public: glm::vec2 UVTranslation; @@ -102,9 +94,12 @@ public: class ExtractedMesh; -class FBXReader { +class FBXSerializer : public HFMSerializer { public: HFMModel* _hfmModel; + /// Reads HFMModel from the supplied model and mapping data. + /// \exception QString if an error occurs in parsing + HFMModel::Pointer read(const QByteArray& data, const QVariantHash& mapping, const QUrl& url = QUrl()) override; FBXNode _rootNode; static FBXNode parseFBX(QIODevice* device); @@ -147,9 +142,9 @@ public: void consolidateHFMMaterials(const QVariantHash& mapping); - bool _loadLightmaps = true; - float _lightmapOffset = 0.0f; - float _lightmapLevel; + bool _loadLightmaps { true }; + float _lightmapOffset { 0.0f }; + float _lightmapLevel { 1.0f }; QMultiMap _connectionParentMap; QMultiMap _connectionChildMap; @@ -166,4 +161,4 @@ public: static QVector getDoubleVector(const FBXNode& node); }; -#endif // hifi_FBXReader_h +#endif // hifi_FBXSerializer_h diff --git a/libraries/fbx/src/FBXReader_Material.cpp b/libraries/fbx/src/FBXSerializer_Material.cpp similarity index 98% rename from libraries/fbx/src/FBXReader_Material.cpp rename to libraries/fbx/src/FBXSerializer_Material.cpp index 2ec8cfde75..7713b36e57 100644 --- a/libraries/fbx/src/FBXReader_Material.cpp +++ b/libraries/fbx/src/FBXSerializer_Material.cpp @@ -1,5 +1,5 @@ // -// FBXReader_Material.cpp +// FBXSerializer_Material.cpp // interface/src/fbx // // Created by Sam Gateau on 8/27/2015. @@ -9,7 +9,7 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -#include "FBXReader.h" +#include "FBXSerializer.h" #include #include @@ -27,7 +27,7 @@ #include -HFMTexture FBXReader::getTexture(const QString& textureID) { +HFMTexture FBXSerializer::getTexture(const QString& textureID) { HFMTexture texture; const QByteArray& filepath = _textureFilepaths.value(textureID); texture.content = _textureContent.value(filepath); @@ -69,7 +69,7 @@ HFMTexture FBXReader::getTexture(const QString& textureID) { return texture; } -void FBXReader::consolidateHFMMaterials(const QVariantHash& mapping) { +void FBXSerializer::consolidateHFMMaterials(const QVariantHash& mapping) { QString materialMapString = mapping.value("materialMap").toString(); QJsonDocument materialMapDocument = QJsonDocument::fromJson(materialMapString.toUtf8()); diff --git a/libraries/fbx/src/FBXReader_Mesh.cpp b/libraries/fbx/src/FBXSerializer_Mesh.cpp similarity index 98% rename from libraries/fbx/src/FBXReader_Mesh.cpp rename to libraries/fbx/src/FBXSerializer_Mesh.cpp index 527e3aef75..38533dbc42 100644 --- a/libraries/fbx/src/FBXReader_Mesh.cpp +++ b/libraries/fbx/src/FBXSerializer_Mesh.cpp @@ -1,5 +1,5 @@ // -// FBXReader_Mesh.cpp +// FBXSerializer_Mesh.cpp // interface/src/fbx // // Created by Sam Gateau on 8/27/2015. @@ -33,7 +33,7 @@ #include #include -#include "FBXReader.h" +#include "FBXSerializer.h" #include @@ -191,7 +191,7 @@ void appendIndex(MeshData& data, QVector& indices, int index, bool deduplic } } -ExtractedMesh FBXReader::extractMesh(const FBXNode& object, unsigned int& meshIndex, bool deduplicate) { +ExtractedMesh FBXSerializer::extractMesh(const FBXNode& object, unsigned int& meshIndex, bool deduplicate) { MeshData data; data.extracted.mesh.meshIndex = meshIndex++; @@ -254,7 +254,7 @@ ExtractedMesh FBXReader::extractMesh(const FBXNode& object, unsigned int& meshIn data.colorsByVertex = true; } -#if defined(FBXREADER_KILL_BLACK_COLOR_ATTRIBUTE) +#if defined(FBXSERIALIZER_KILL_BLACK_COLOR_ATTRIBUTE) // Potential feature where we decide to kill the color attribute is to dark? // Tested with the model: // https://hifi-public.s3.amazonaws.com/ryan/gardenLight2.fbx @@ -281,7 +281,7 @@ ExtractedMesh FBXReader::extractMesh(const FBXNode& object, unsigned int& meshIn } else if (subdata.name == "Name") { attrib.name = subdata.properties.at(0).toString(); } -#if defined(DEBUG_FBXREADER) +#if defined(DEBUG_FBXSERIALIZER) else { int unknown = 0; QString subname = subdata.name.data(); @@ -307,7 +307,7 @@ ExtractedMesh FBXReader::extractMesh(const FBXNode& object, unsigned int& meshIn } else if (subdata.name == "Name") { attrib.name = subdata.properties.at(0).toString(); } -#if defined(DEBUG_FBXREADER) +#if defined(DEBUG_FBXSERIALIZER) else { int unknown = 0; QString subname = subdata.name.data(); @@ -557,7 +557,7 @@ ExtractedMesh FBXReader::extractMesh(const FBXNode& object, unsigned int& meshIn return data.extracted; } -glm::vec3 FBXReader::normalizeDirForPacking(const glm::vec3& dir) { +glm::vec3 FBXSerializer::normalizeDirForPacking(const glm::vec3& dir) { auto maxCoord = glm::max(fabsf(dir.x), glm::max(fabsf(dir.y), fabsf(dir.z))); if (maxCoord > 1e-6f) { return dir / maxCoord; @@ -565,7 +565,7 @@ glm::vec3 FBXReader::normalizeDirForPacking(const glm::vec3& dir) { return dir; } -void FBXReader::buildModelMesh(HFMMesh& extractedMesh, const QString& url) { +void FBXSerializer::buildModelMesh(HFMMesh& extractedMesh, const QString& url) { unsigned int totalSourceIndices = 0; foreach(const HFMMeshPart& part, extractedMesh.parts) { totalSourceIndices += (part.quadTrianglesIndices.size() + part.triangleIndices.size()); diff --git a/libraries/fbx/src/FBXReader_Node.cpp b/libraries/fbx/src/FBXSerializer_Node.cpp similarity index 94% rename from libraries/fbx/src/FBXReader_Node.cpp rename to libraries/fbx/src/FBXSerializer_Node.cpp index cd717998dd..c982dfc7cb 100644 --- a/libraries/fbx/src/FBXReader_Node.cpp +++ b/libraries/fbx/src/FBXSerializer_Node.cpp @@ -1,5 +1,5 @@ // -// FBXReader_Node.cpp +// FBXSerializer_Node.cpp // interface/src/fbx // // Created by Sam Gateau on 8/27/2015. @@ -9,7 +9,7 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -#include "FBXReader.h" +#include "FBXSerializer.h" #include #include @@ -345,7 +345,7 @@ FBXNode parseTextFBXNode(Tokenizer& tokenizer) { return node; } -FBXNode FBXReader::parseFBX(QIODevice* device) { +FBXNode FBXSerializer::parseFBX(QIODevice* device) { PROFILE_RANGE_EX(resource_parse, __FUNCTION__, 0xff0000ff, device); // verify the prolog if (device->peek(FBX_BINARY_PROLOG.size()) != FBX_BINARY_PROLOG) { @@ -398,12 +398,12 @@ FBXNode FBXReader::parseFBX(QIODevice* device) { } -glm::vec3 FBXReader::getVec3(const QVariantList& properties, int index) { +glm::vec3 FBXSerializer::getVec3(const QVariantList& properties, int index) { return glm::vec3(properties.at(index).value(), properties.at(index + 1).value(), properties.at(index + 2).value()); } -QVector FBXReader::createVec4Vector(const QVector& doubleVector) { +QVector FBXSerializer::createVec4Vector(const QVector& doubleVector) { QVector values; for (const double* it = doubleVector.constData(), *end = it + ((doubleVector.size() / 4) * 4); it != end; ) { float x = *it++; @@ -416,7 +416,7 @@ QVector FBXReader::createVec4Vector(const QVector& doubleVect } -QVector FBXReader::createVec4VectorRGBA(const QVector& doubleVector, glm::vec4& average) { +QVector FBXSerializer::createVec4VectorRGBA(const QVector& doubleVector, glm::vec4& average) { QVector values; for (const double* it = doubleVector.constData(), *end = it + ((doubleVector.size() / 4) * 4); it != end; ) { float x = *it++; @@ -433,7 +433,7 @@ QVector FBXReader::createVec4VectorRGBA(const QVector& double return values; } -QVector FBXReader::createVec3Vector(const QVector& doubleVector) { +QVector FBXSerializer::createVec3Vector(const QVector& doubleVector) { QVector values; for (const double* it = doubleVector.constData(), *end = it + ((doubleVector.size() / 3) * 3); it != end; ) { float x = *it++; @@ -444,7 +444,7 @@ QVector FBXReader::createVec3Vector(const QVector& doubleVect return values; } -QVector FBXReader::createVec2Vector(const QVector& doubleVector) { +QVector FBXSerializer::createVec2Vector(const QVector& doubleVector) { QVector values; for (const double* it = doubleVector.constData(), *end = it + ((doubleVector.size() / 2) * 2); it != end; ) { float s = *it++; @@ -454,14 +454,14 @@ QVector FBXReader::createVec2Vector(const QVector& doubleVect return values; } -glm::mat4 FBXReader::createMat4(const QVector& doubleVector) { +glm::mat4 FBXSerializer::createMat4(const QVector& doubleVector) { return glm::mat4(doubleVector.at(0), doubleVector.at(1), doubleVector.at(2), doubleVector.at(3), doubleVector.at(4), doubleVector.at(5), doubleVector.at(6), doubleVector.at(7), doubleVector.at(8), doubleVector.at(9), doubleVector.at(10), doubleVector.at(11), doubleVector.at(12), doubleVector.at(13), doubleVector.at(14), doubleVector.at(15)); } -QVector FBXReader::getIntVector(const FBXNode& node) { +QVector FBXSerializer::getIntVector(const FBXNode& node) { foreach (const FBXNode& child, node.children) { if (child.name == "a") { return getIntVector(child); @@ -480,7 +480,7 @@ QVector FBXReader::getIntVector(const FBXNode& node) { return vector; } -QVector FBXReader::getFloatVector(const FBXNode& node) { +QVector FBXSerializer::getFloatVector(const FBXNode& node) { foreach (const FBXNode& child, node.children) { if (child.name == "a") { return getFloatVector(child); @@ -499,7 +499,7 @@ QVector FBXReader::getFloatVector(const FBXNode& node) { return vector; } -QVector FBXReader::getDoubleVector(const FBXNode& node) { +QVector FBXSerializer::getDoubleVector(const FBXNode& node) { foreach (const FBXNode& child, node.children) { if (child.name == "a") { return getDoubleVector(child); diff --git a/libraries/fbx/src/GLTFReader.cpp b/libraries/fbx/src/GLTFSerializer.cpp similarity index 93% rename from libraries/fbx/src/GLTFReader.cpp rename to libraries/fbx/src/GLTFSerializer.cpp index eb763cce90..28d377c605 100644 --- a/libraries/fbx/src/GLTFReader.cpp +++ b/libraries/fbx/src/GLTFSerializer.cpp @@ -1,5 +1,5 @@ // -// GLTFReader.cpp +// GLTFSerializer.cpp // libraries/fbx/src // // Created by Luis Cuenca on 8/30/17. @@ -9,7 +9,7 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -#include "GLTFReader.h" +#include "GLTFSerializer.h" #include #include @@ -33,14 +33,14 @@ #include #include -#include "FBXReader.h" +#include "FBXSerializer.h" -GLTFReader::GLTFReader() { +GLTFSerializer::GLTFSerializer() { } -bool GLTFReader::getStringVal(const QJsonObject& object, const QString& fieldname, +bool GLTFSerializer::getStringVal(const QJsonObject& object, const QString& fieldname, QString& value, QMap& defined) { bool _defined = (object.contains(fieldname) && object[fieldname].isString()); if (_defined) { @@ -50,7 +50,7 @@ bool GLTFReader::getStringVal(const QJsonObject& object, const QString& fieldnam return _defined; } -bool GLTFReader::getBoolVal(const QJsonObject& object, const QString& fieldname, +bool GLTFSerializer::getBoolVal(const QJsonObject& object, const QString& fieldname, bool& value, QMap& defined) { bool _defined = (object.contains(fieldname) && object[fieldname].isBool()); if (_defined) { @@ -60,7 +60,7 @@ bool GLTFReader::getBoolVal(const QJsonObject& object, const QString& fieldname, return _defined; } -bool GLTFReader::getIntVal(const QJsonObject& object, const QString& fieldname, +bool GLTFSerializer::getIntVal(const QJsonObject& object, const QString& fieldname, int& value, QMap& defined) { bool _defined = (object.contains(fieldname) && !object[fieldname].isNull()); if (_defined) { @@ -70,7 +70,7 @@ bool GLTFReader::getIntVal(const QJsonObject& object, const QString& fieldname, return _defined; } -bool GLTFReader::getDoubleVal(const QJsonObject& object, const QString& fieldname, +bool GLTFSerializer::getDoubleVal(const QJsonObject& object, const QString& fieldname, double& value, QMap& defined) { bool _defined = (object.contains(fieldname) && object[fieldname].isDouble()); if (_defined) { @@ -79,7 +79,7 @@ bool GLTFReader::getDoubleVal(const QJsonObject& object, const QString& fieldnam defined.insert(fieldname, _defined); return _defined; } -bool GLTFReader::getObjectVal(const QJsonObject& object, const QString& fieldname, +bool GLTFSerializer::getObjectVal(const QJsonObject& object, const QString& fieldname, QJsonObject& value, QMap& defined) { bool _defined = (object.contains(fieldname) && object[fieldname].isObject()); if (_defined) { @@ -89,7 +89,7 @@ bool GLTFReader::getObjectVal(const QJsonObject& object, const QString& fieldnam return _defined; } -bool GLTFReader::getIntArrayVal(const QJsonObject& object, const QString& fieldname, +bool GLTFSerializer::getIntArrayVal(const QJsonObject& object, const QString& fieldname, QVector& values, QMap& defined) { bool _defined = (object.contains(fieldname) && object[fieldname].isArray()); if (_defined) { @@ -104,7 +104,7 @@ bool GLTFReader::getIntArrayVal(const QJsonObject& object, const QString& fieldn return _defined; } -bool GLTFReader::getDoubleArrayVal(const QJsonObject& object, const QString& fieldname, +bool GLTFSerializer::getDoubleArrayVal(const QJsonObject& object, const QString& fieldname, QVector& values, QMap& defined) { bool _defined = (object.contains(fieldname) && object[fieldname].isArray()); if (_defined) { @@ -119,7 +119,7 @@ bool GLTFReader::getDoubleArrayVal(const QJsonObject& object, const QString& fie return _defined; } -bool GLTFReader::getObjectArrayVal(const QJsonObject& object, const QString& fieldname, +bool GLTFSerializer::getObjectArrayVal(const QJsonObject& object, const QString& fieldname, QJsonArray& objects, QMap& defined) { bool _defined = (object.contains(fieldname) && object[fieldname].isArray()); if (_defined) { @@ -129,7 +129,7 @@ bool GLTFReader::getObjectArrayVal(const QJsonObject& object, const QString& fie return _defined; } -int GLTFReader::getMeshPrimitiveRenderingMode(const QString& type) +int GLTFSerializer::getMeshPrimitiveRenderingMode(const QString& type) { if (type == "POINTS") { return GLTFMeshPrimitivesRenderingMode::POINTS; @@ -155,7 +155,7 @@ int GLTFReader::getMeshPrimitiveRenderingMode(const QString& type) return GLTFMeshPrimitivesRenderingMode::TRIANGLES; } -int GLTFReader::getAccessorType(const QString& type) +int GLTFSerializer::getAccessorType(const QString& type) { if (type == "SCALAR") { return GLTFAccessorType::SCALAR; @@ -181,7 +181,7 @@ int GLTFReader::getAccessorType(const QString& type) return GLTFAccessorType::SCALAR; } -int GLTFReader::getMaterialAlphaMode(const QString& type) +int GLTFSerializer::getMaterialAlphaMode(const QString& type) { if (type == "OPAQUE") { return GLTFMaterialAlphaMode::OPAQUE; @@ -195,7 +195,7 @@ int GLTFReader::getMaterialAlphaMode(const QString& type) return GLTFMaterialAlphaMode::OPAQUE; } -int GLTFReader::getCameraType(const QString& type) +int GLTFSerializer::getCameraType(const QString& type) { if (type == "orthographic") { return GLTFCameraTypes::ORTHOGRAPHIC; @@ -206,7 +206,7 @@ int GLTFReader::getCameraType(const QString& type) return GLTFCameraTypes::PERSPECTIVE; } -int GLTFReader::getImageMimeType(const QString& mime) +int GLTFSerializer::getImageMimeType(const QString& mime) { if (mime == "image/jpeg") { return GLTFImageMimetype::JPEG; @@ -217,7 +217,7 @@ int GLTFReader::getImageMimeType(const QString& mime) return GLTFImageMimetype::JPEG; } -int GLTFReader::getAnimationSamplerInterpolation(const QString& interpolation) +int GLTFSerializer::getAnimationSamplerInterpolation(const QString& interpolation) { if (interpolation == "LINEAR") { return GLTFAnimationSamplerInterpolation::LINEAR; @@ -225,7 +225,7 @@ int GLTFReader::getAnimationSamplerInterpolation(const QString& interpolation) return GLTFAnimationSamplerInterpolation::LINEAR; } -bool GLTFReader::setAsset(const QJsonObject& object) { +bool GLTFSerializer::setAsset(const QJsonObject& object) { QJsonObject jsAsset; bool isAssetDefined = getObjectVal(object, "asset", jsAsset, _file.defined); if (isAssetDefined) { @@ -239,7 +239,7 @@ bool GLTFReader::setAsset(const QJsonObject& object) { return isAssetDefined; } -bool GLTFReader::addAccessor(const QJsonObject& object) { +bool GLTFSerializer::addAccessor(const QJsonObject& object) { GLTFAccessor accessor; getIntVal(object, "bufferView", accessor.bufferView, accessor.defined); @@ -259,7 +259,7 @@ bool GLTFReader::addAccessor(const QJsonObject& object) { return true; } -bool GLTFReader::addAnimation(const QJsonObject& object) { +bool GLTFSerializer::addAnimation(const QJsonObject& object) { GLTFAnimation animation; QJsonArray channels; @@ -297,7 +297,7 @@ bool GLTFReader::addAnimation(const QJsonObject& object) { return true; } -bool GLTFReader::addBufferView(const QJsonObject& object) { +bool GLTFSerializer::addBufferView(const QJsonObject& object) { GLTFBufferView bufferview; getIntVal(object, "buffer", bufferview.buffer, bufferview.defined); @@ -310,7 +310,7 @@ bool GLTFReader::addBufferView(const QJsonObject& object) { return true; } -bool GLTFReader::addBuffer(const QJsonObject& object) { +bool GLTFSerializer::addBuffer(const QJsonObject& object) { GLTFBuffer buffer; getIntVal(object, "byteLength", buffer.byteLength, buffer.defined); @@ -324,7 +324,7 @@ bool GLTFReader::addBuffer(const QJsonObject& object) { return true; } -bool GLTFReader::addCamera(const QJsonObject& object) { +bool GLTFSerializer::addCamera(const QJsonObject& object) { GLTFCamera camera; QJsonObject jsPerspective; @@ -352,7 +352,7 @@ bool GLTFReader::addCamera(const QJsonObject& object) { return true; } -bool GLTFReader::addImage(const QJsonObject& object) { +bool GLTFSerializer::addImage(const QJsonObject& object) { GLTFImage image; QString mime; @@ -367,7 +367,7 @@ bool GLTFReader::addImage(const QJsonObject& object) { return true; } -bool GLTFReader::getIndexFromObject(const QJsonObject& object, const QString& field, +bool GLTFSerializer::getIndexFromObject(const QJsonObject& object, const QString& field, int& outidx, QMap& defined) { QJsonObject subobject; if (getObjectVal(object, field, subobject, defined)) { @@ -377,7 +377,7 @@ bool GLTFReader::getIndexFromObject(const QJsonObject& object, const QString& fi return false; } -bool GLTFReader::addMaterial(const QJsonObject& object) { +bool GLTFSerializer::addMaterial(const QJsonObject& object) { GLTFMaterial material; getStringVal(object, "name", material.name, material.defined); @@ -413,7 +413,7 @@ bool GLTFReader::addMaterial(const QJsonObject& object) { return true; } -bool GLTFReader::addMesh(const QJsonObject& object) { +bool GLTFSerializer::addMesh(const QJsonObject& object) { GLTFMesh mesh; getStringVal(object, "name", mesh.name, mesh.defined); @@ -467,7 +467,7 @@ bool GLTFReader::addMesh(const QJsonObject& object) { return true; } -bool GLTFReader::addNode(const QJsonObject& object) { +bool GLTFSerializer::addNode(const QJsonObject& object) { GLTFNode node; getStringVal(object, "name", node.name, node.defined); @@ -487,7 +487,7 @@ bool GLTFReader::addNode(const QJsonObject& object) { return true; } -bool GLTFReader::addSampler(const QJsonObject& object) { +bool GLTFSerializer::addSampler(const QJsonObject& object) { GLTFSampler sampler; getIntVal(object, "magFilter", sampler.magFilter, sampler.defined); @@ -501,7 +501,7 @@ bool GLTFReader::addSampler(const QJsonObject& object) { } -bool GLTFReader::addScene(const QJsonObject& object) { +bool GLTFSerializer::addScene(const QJsonObject& object) { GLTFScene scene; getStringVal(object, "name", scene.name, scene.defined); @@ -511,7 +511,7 @@ bool GLTFReader::addScene(const QJsonObject& object) { return true; } -bool GLTFReader::addSkin(const QJsonObject& object) { +bool GLTFSerializer::addSkin(const QJsonObject& object) { GLTFSkin skin; getIntVal(object, "inverseBindMatrices", skin.inverseBindMatrices, skin.defined); @@ -523,7 +523,7 @@ bool GLTFReader::addSkin(const QJsonObject& object) { return true; } -bool GLTFReader::addTexture(const QJsonObject& object) { +bool GLTFSerializer::addTexture(const QJsonObject& object) { GLTFTexture texture; getIntVal(object, "sampler", texture.sampler, texture.defined); getIntVal(object, "source", texture.source, texture.defined); @@ -533,7 +533,7 @@ bool GLTFReader::addTexture(const QJsonObject& object) { return true; } -bool GLTFReader::parseGLTF(const QByteArray& data) { +bool GLTFSerializer::parseGLTF(const QByteArray& data) { PROFILE_RANGE_EX(resource_parse, __FUNCTION__, 0xffff0000, nullptr); QJsonDocument d = QJsonDocument::fromJson(data); @@ -664,7 +664,7 @@ bool GLTFReader::parseGLTF(const QByteArray& data) { return true; } -glm::mat4 GLTFReader::getModelTransform(const GLTFNode& node) { +glm::mat4 GLTFSerializer::getModelTransform(const GLTFNode& node) { glm::mat4 tmat = glm::mat4(1.0); if (node.defined["matrix"] && node.matrix.size() == 16) { @@ -697,7 +697,7 @@ glm::mat4 GLTFReader::getModelTransform(const GLTFNode& node) { return tmat; } -bool GLTFReader::buildGeometry(HFMModel& hfmModel, const QUrl& url) { +bool GLTFSerializer::buildGeometry(HFMModel& hfmModel, const QUrl& url) { //Build dependencies QVector> nodeDependencies(_file.nodes.size()); @@ -899,7 +899,7 @@ bool GLTFReader::buildGeometry(HFMModel& hfmModel, const QUrl& url) { } mesh.meshIndex = hfmModel.meshes.size(); - FBXReader::buildModelMesh(mesh, url.toString()); + FBXSerializer::buildModelMesh(mesh, url.toString()); } } @@ -910,13 +910,12 @@ bool GLTFReader::buildGeometry(HFMModel& hfmModel, const QUrl& url) { return true; } -HFMModel* GLTFReader::readGLTF(QByteArray& data, const QVariantHash& mapping, - const QUrl& url, bool loadLightmaps, float lightmapLevel) { +HFMModel::Pointer GLTFSerializer::read(const QByteArray& data, const QVariantHash& mapping, const QUrl& url) { _url = url; // Normalize url for local files - QUrl normalizeUrl = DependencyManager::get()->normalizeURL(url); + QUrl normalizeUrl = DependencyManager::get()->normalizeURL(_url); if (normalizeUrl.scheme().isEmpty() || (normalizeUrl.scheme() == "file")) { QString localFileName = PathUtils::expandToLocalDataAbsolutePath(normalizeUrl).toLocalFile(); _url = QUrl(QFileInfo(localFileName).absoluteFilePath()); @@ -924,17 +923,17 @@ HFMModel* GLTFReader::readGLTF(QByteArray& data, const QVariantHash& mapping, parseGLTF(data); //_file.dump(); - HFMModel* hfmModelPtr = new HFMModel(); + auto hfmModelPtr = std::make_shared(); HFMModel& hfmModel = *hfmModelPtr; - buildGeometry(hfmModel, url); + buildGeometry(hfmModel, _url); //hfmDebugDump(data); return hfmModelPtr; } -bool GLTFReader::readBinary(const QString& url, QByteArray& outdata) { +bool GLTFSerializer::readBinary(const QString& url, QByteArray& outdata) { QUrl binaryUrl = _url.resolved(url); bool success; @@ -943,7 +942,7 @@ bool GLTFReader::readBinary(const QString& url, QByteArray& outdata) { return success; } -bool GLTFReader::doesResourceExist(const QString& url) { +bool GLTFSerializer::doesResourceExist(const QString& url) { if (_url.isEmpty()) { return false; } @@ -951,9 +950,9 @@ bool GLTFReader::doesResourceExist(const QString& url) { return DependencyManager::get()->resourceExists(candidateUrl); } -std::tuple GLTFReader::requestData(QUrl& url) { +std::tuple GLTFSerializer::requestData(QUrl& url) { auto request = DependencyManager::get()->createResourceRequest( - nullptr, url, true, -1, "GLTFReader::requestData"); + nullptr, url, true, -1, "GLTFSerializer::requestData"); if (!request) { return std::make_tuple(false, QByteArray()); @@ -972,7 +971,7 @@ std::tuple GLTFReader::requestData(QUrl& url) { } -QNetworkReply* GLTFReader::request(QUrl& url, bool isTest) { +QNetworkReply* GLTFSerializer::request(QUrl& url, bool isTest) { if (!qApp) { return nullptr; } @@ -996,7 +995,7 @@ QNetworkReply* GLTFReader::request(QUrl& url, bool isTest) { return netReply; // trying to sync later on. } -HFMTexture GLTFReader::getHFMTexture(const GLTFTexture& texture) { +HFMTexture GLTFSerializer::getHFMTexture(const GLTFTexture& texture) { HFMTexture fbxtex = HFMTexture(); fbxtex.texcoordSet = 0; @@ -1011,7 +1010,7 @@ HFMTexture GLTFReader::getHFMTexture(const GLTFTexture& texture) { return fbxtex; } -void GLTFReader::setHFMMaterial(HFMMaterial& fbxmat, const GLTFMaterial& material) { +void GLTFSerializer::setHFMMaterial(HFMMaterial& fbxmat, const GLTFMaterial& material) { if (material.defined["name"]) { @@ -1074,7 +1073,7 @@ void GLTFReader::setHFMMaterial(HFMMaterial& fbxmat, const GLTFMaterial& materia } template -bool GLTFReader::readArray(const QByteArray& bin, int byteOffset, int count, +bool GLTFSerializer::readArray(const QByteArray& bin, int byteOffset, int count, QVector& outarray, int accessorType) { QDataStream blobstream(bin); @@ -1131,7 +1130,7 @@ bool GLTFReader::readArray(const QByteArray& bin, int byteOffset, int count, return true; } template -bool GLTFReader::addArrayOfType(const QByteArray& bin, int byteOffset, int count, +bool GLTFSerializer::addArrayOfType(const QByteArray& bin, int byteOffset, int count, QVector& outarray, int accessorType, int componentType) { switch (componentType) { @@ -1155,7 +1154,7 @@ bool GLTFReader::addArrayOfType(const QByteArray& bin, int byteOffset, int count return false; } -void GLTFReader::retriangulate(const QVector& inIndices, const QVector& in_vertices, +void GLTFSerializer::retriangulate(const QVector& inIndices, const QVector& in_vertices, const QVector& in_normals, QVector& outIndices, QVector& out_vertices, QVector& out_normals) { for (int i = 0; i < inIndices.size(); i = i + 3) { @@ -1178,7 +1177,7 @@ void GLTFReader::retriangulate(const QVector& inIndices, const QVector +#include "FBXSerializer.h" struct GLTFAsset { @@ -699,12 +700,11 @@ struct GLTFFile { } }; -class GLTFReader : public QObject { +class GLTFSerializer : public QObject, public HFMSerializer { Q_OBJECT public: - GLTFReader(); - HFMModel* readGLTF(QByteArray& data, const QVariantHash& mapping, - const QUrl& url, bool loadLightmaps = true, float lightmapLevel = 1.0f); + GLTFSerializer(); + HFMModel::Pointer read(const QByteArray& data, const QVariantHash& mapping, const QUrl& url = QUrl()) override; private: GLTFFile _file; QUrl _url; @@ -780,4 +780,4 @@ private: void hfmDebugDump(const HFMModel& hfmModel); }; -#endif // hifi_GLTFReader_h \ No newline at end of file +#endif // hifi_GLTFSerializer_h \ No newline at end of file diff --git a/libraries/fbx/src/OBJReader.cpp b/libraries/fbx/src/OBJSerializer.cpp similarity index 92% rename from libraries/fbx/src/OBJReader.cpp rename to libraries/fbx/src/OBJSerializer.cpp index e140f1b0b3..af8dfb5562 100644 --- a/libraries/fbx/src/OBJReader.cpp +++ b/libraries/fbx/src/OBJSerializer.cpp @@ -1,5 +1,5 @@ // -// OBJReader.cpp +// OBJSerializer.cpp // libraries/fbx/src/ // // Created by Seth Alves on 3/7/15. @@ -12,7 +12,7 @@ // http://www.scratchapixel.com/old/lessons/3d-advanced-lessons/obj-file-format/obj-file-format/ // http://paulbourke.net/dataformats/obj/ -#include "OBJReader.h" +#include "OBJSerializer.h" #include // .obj files are not locale-specific. The C/ASCII charset applies. #include @@ -27,7 +27,7 @@ #include #include -#include "FBXReader.h" +#include "FBXSerializer.h" #include #include @@ -238,7 +238,7 @@ void OBJFace::addFrom(const OBJFace* face, int index) { // add using data from f } } -bool OBJReader::isValidTexture(const QByteArray &filename) { +bool OBJSerializer::isValidTexture(const QByteArray &filename) { if (_url.isEmpty()) { return false; } @@ -247,7 +247,7 @@ bool OBJReader::isValidTexture(const QByteArray &filename) { return DependencyManager::get()->resourceExists(candidateUrl); } -void OBJReader::parseMaterialLibrary(QIODevice* device) { +void OBJSerializer::parseMaterialLibrary(QIODevice* device) { OBJTokenizer tokenizer(device); QString matName = SMART_DEFAULT_MATERIAL_NAME; OBJMaterial& currentMaterial = materials[matName]; @@ -255,7 +255,7 @@ void OBJReader::parseMaterialLibrary(QIODevice* device) { switch (tokenizer.nextToken()) { case OBJTokenizer::COMMENT_TOKEN: #ifdef WANT_DEBUG - qCDebug(modelformat) << "OBJ Reader MTLLIB comment:" << tokenizer.getComment(); + qCDebug(modelformat) << "OBJSerializer MTLLIB comment:" << tokenizer.getComment(); #endif break; case OBJTokenizer::DATUM_TOKEN: @@ -264,7 +264,7 @@ void OBJReader::parseMaterialLibrary(QIODevice* device) { materials[matName] = currentMaterial; #ifdef WANT_DEBUG qCDebug(modelformat) << - "OBJ Reader Last material illumination model:" << currentMaterial.illuminationModel << + "OBJSerializer Last material illumination model:" << currentMaterial.illuminationModel << " shininess:" << currentMaterial.shininess << " opacity:" << currentMaterial.opacity << " diffuse color:" << currentMaterial.diffuseColor << @@ -287,7 +287,7 @@ void OBJReader::parseMaterialLibrary(QIODevice* device) { matName = tokenizer.getDatum(); currentMaterial = materials[matName]; #ifdef WANT_DEBUG - qCDebug(modelformat) << "OBJ Reader Starting new material definition " << matName; + qCDebug(modelformat) << "OBJSerializer Starting new material definition " << matName; #endif currentMaterial.diffuseTextureFilename = ""; currentMaterial.emissiveTextureFilename = ""; @@ -299,7 +299,7 @@ void OBJReader::parseMaterialLibrary(QIODevice* device) { currentMaterial.shininess = tokenizer.getFloat(); } else if (token == "Ni") { #ifdef WANT_DEBUG - qCDebug(modelformat) << "OBJ Reader Ignoring material Ni " << tokenizer.getFloat(); + qCDebug(modelformat) << "OBJSerializer Ignoring material Ni " << tokenizer.getFloat(); #else tokenizer.getFloat(); #endif @@ -311,13 +311,13 @@ void OBJReader::parseMaterialLibrary(QIODevice* device) { currentMaterial.illuminationModel = tokenizer.getFloat(); } else if (token == "Tf") { #ifdef WANT_DEBUG - qCDebug(modelformat) << "OBJ Reader Ignoring material Tf " << tokenizer.getVec3(); + qCDebug(modelformat) << "OBJSerializer Ignoring material Tf " << tokenizer.getVec3(); #else tokenizer.getVec3(); #endif } else if (token == "Ka") { #ifdef WANT_DEBUG - qCDebug(modelformat) << "OBJ Reader Ignoring material Ka " << tokenizer.getVec3();; + qCDebug(modelformat) << "OBJSerializer Ignoring material Ka " << tokenizer.getVec3();; #else tokenizer.getVec3(); #endif @@ -334,7 +334,7 @@ void OBJReader::parseMaterialLibrary(QIODevice* device) { parseTextureLine(textureLine, filename, textureOptions); if (filename.endsWith(".tga")) { #ifdef WANT_DEBUG - qCDebug(modelformat) << "OBJ Reader WARNING: currently ignoring tga texture " << filename << " in " << _url; + qCDebug(modelformat) << "OBJSerializer WARNING: currently ignoring tga texture " << filename << " in " << _url; #endif break; } @@ -354,7 +354,7 @@ void OBJReader::parseMaterialLibrary(QIODevice* device) { } } -void OBJReader::parseTextureLine(const QByteArray& textureLine, QByteArray& filename, OBJMaterialTextureOptions& textureOptions) { +void OBJSerializer::parseTextureLine(const QByteArray& textureLine, QByteArray& filename, OBJMaterialTextureOptions& textureOptions) { // Texture options reference http://paulbourke.net/dataformats/mtl/ // and https://wikivisually.com/wiki/Material_Template_Library @@ -368,7 +368,7 @@ void OBJReader::parseTextureLine(const QByteArray& textureLine, QByteArray& file if (option == "-blendu" || option == "-blendv") { #ifdef WANT_DEBUG const std::string& onoff = parser[i++]; - qCDebug(modelformat) << "OBJ Reader WARNING: Ignoring texture option" << option.c_str() << onoff.c_str(); + qCDebug(modelformat) << "OBJSerializer WARNING: Ignoring texture option" << option.c_str() << onoff.c_str(); #endif } else if (option == "-bm") { const std::string& bm = parser[i++]; @@ -377,22 +377,22 @@ void OBJReader::parseTextureLine(const QByteArray& textureLine, QByteArray& file #ifdef WANT_DEBUG const std::string& boost = parser[i++]; float boostFloat = std::stof(boost); - qCDebug(modelformat) << "OBJ Reader WARNING: Ignoring texture option" << option.c_str() << boost.c_str(); + qCDebug(modelformat) << "OBJSerializer WARNING: Ignoring texture option" << option.c_str() << boost.c_str(); #endif } else if (option == "-cc") { #ifdef WANT_DEBUG const std::string& onoff = parser[i++]; - qCDebug(modelformat) << "OBJ Reader WARNING: Ignoring texture option" << option.c_str() << onoff.c_str(); + qCDebug(modelformat) << "OBJSerializer WARNING: Ignoring texture option" << option.c_str() << onoff.c_str(); #endif } else if (option == "-clamp") { #ifdef WANT_DEBUG const std::string& onoff = parser[i++]; - qCDebug(modelformat) << "OBJ Reader WARNING: Ignoring texture option" << option.c_str() << onoff.c_str(); + qCDebug(modelformat) << "OBJSerializer WARNING: Ignoring texture option" << option.c_str() << onoff.c_str(); #endif } else if (option == "-imfchan") { #ifdef WANT_DEBUG const std::string& imfchan = parser[i++]; - qCDebug(modelformat) << "OBJ Reader WARNING: Ignoring texture option" << option.c_str() << imfchan.c_str(); + qCDebug(modelformat) << "OBJSerializer WARNING: Ignoring texture option" << option.c_str() << imfchan.c_str(); #endif } else if (option == "-mm") { if (i + 1 < parser.size()) { @@ -401,7 +401,7 @@ void OBJReader::parseTextureLine(const QByteArray& textureLine, QByteArray& file const std::string& mmGain = parser[i++]; float mmBaseFloat = std::stof(mmBase); float mmGainFloat = std::stof(mmGain); - qCDebug(modelformat) << "OBJ Reader WARNING: Ignoring texture option" << option.c_str() << mmBase.c_str() << mmGain.c_str(); + qCDebug(modelformat) << "OBJSerializer WARNING: Ignoring texture option" << option.c_str() << mmBase.c_str() << mmGain.c_str(); #endif } } else if (option == "-o" || option == "-s" || option == "-t") { @@ -413,23 +413,23 @@ void OBJReader::parseTextureLine(const QByteArray& textureLine, QByteArray& file float uFloat = std::stof(u); float vFloat = std::stof(v); float wFloat = std::stof(w); - qCDebug(modelformat) << "OBJ Reader WARNING: Ignoring texture option" << option.c_str() << u.c_str() << v.c_str() << w.c_str(); + qCDebug(modelformat) << "OBJSerializer WARNING: Ignoring texture option" << option.c_str() << u.c_str() << v.c_str() << w.c_str(); #endif } } else if (option == "-texres") { #ifdef WANT_DEBUG const std::string& texres = parser[i++]; float texresFloat = std::stof(texres); - qCDebug(modelformat) << "OBJ Reader WARNING: Ignoring texture option" << option.c_str() << texres.c_str(); + qCDebug(modelformat) << "OBJSerializer WARNING: Ignoring texture option" << option.c_str() << texres.c_str(); #endif } else if (option == "-type") { #ifdef WANT_DEBUG const std::string& type = parser[i++]; - qCDebug(modelformat) << "OBJ Reader WARNING: Ignoring texture option" << option.c_str() << type.c_str(); + qCDebug(modelformat) << "OBJSerializer WARNING: Ignoring texture option" << option.c_str() << type.c_str(); #endif } else if (option[0] == '-') { #ifdef WANT_DEBUG - qCDebug(modelformat) << "OBJ Reader WARNING: Ignoring unsupported texture option" << option.c_str(); + qCDebug(modelformat) << "OBJSerializer WARNING: Ignoring unsupported texture option" << option.c_str(); #endif } } else { // assume filename at end when no more options @@ -444,7 +444,7 @@ void OBJReader::parseTextureLine(const QByteArray& textureLine, QByteArray& file std::tuple requestData(QUrl& url) { auto request = DependencyManager::get()->createResourceRequest( - nullptr, url, true, -1, "(OBJReader) requestData"); + nullptr, url, true, -1, "(OBJSerializer) requestData"); if (!request) { return std::make_tuple(false, QByteArray()); @@ -488,7 +488,7 @@ QNetworkReply* request(QUrl& url, bool isTest) { } -bool OBJReader::parseOBJGroup(OBJTokenizer& tokenizer, const QVariantHash& mapping, HFMModel& hfmModel, +bool OBJSerializer::parseOBJGroup(OBJTokenizer& tokenizer, const QVariantHash& mapping, HFMModel& hfmModel, float& scaleGuess, bool combineParts) { FaceGroup faces; HFMMesh& mesh = hfmModel.meshes[0]; @@ -557,7 +557,7 @@ bool OBJReader::parseOBJGroup(OBJTokenizer& tokenizer, const QVariantHash& mappi currentMaterialName = nextName; } #ifdef WANT_DEBUG - qCDebug(modelformat) << "OBJ Reader new current material:" << currentMaterialName; + qCDebug(modelformat) << "OBJSerializer new current material:" << currentMaterialName; #endif } } else if (token == "v") { @@ -652,12 +652,12 @@ done: } -HFMModel::Pointer OBJReader::readOBJ(QByteArray& data, const QVariantHash& mapping, bool combineParts, const QUrl& url) { +HFMModel::Pointer OBJSerializer::read(const QByteArray& data, const QVariantHash& mapping, const QUrl& url) { PROFILE_RANGE_EX(resource_parse, __FUNCTION__, 0xffff0000, nullptr); - QBuffer buffer { &data }; + QBuffer buffer { const_cast(&data) }; buffer.open(QIODevice::ReadOnly); - auto hfmModelPtr { std::make_shared() }; + auto hfmModelPtr = std::make_shared(); HFMModel& hfmModel { *hfmModelPtr }; OBJTokenizer tokenizer { &buffer }; float scaleGuess = 1.0f; @@ -665,6 +665,7 @@ HFMModel::Pointer OBJReader::readOBJ(QByteArray& data, const QVariantHash& mappi bool needsMaterialLibrary = false; _url = url; + bool combineParts = mapping.value("combineParts").toBool(); hfmModel.meshExtents.reset(); hfmModel.meshes.append(HFMMesh()); @@ -720,7 +721,7 @@ HFMModel::Pointer OBJReader::readOBJ(QByteArray& data, const QVariantHash& mappi QString groupMaterialName = face.materialName; if (groupMaterialName.isEmpty() && specifiesUV) { #ifdef WANT_DEBUG - qCDebug(modelformat) << "OBJ Reader WARNING: " << url + qCDebug(modelformat) << "OBJSerializer WARNING: " << url << " needs a texture that isn't specified. Using default mechanism."; #endif groupMaterialName = SMART_DEFAULT_MATERIAL_NAME; @@ -822,11 +823,11 @@ HFMModel::Pointer OBJReader::readOBJ(QByteArray& data, const QVariantHash& mappi } // Build the single mesh. - FBXReader::buildModelMesh(mesh, url.toString()); + FBXSerializer::buildModelMesh(mesh, _url.toString()); // hfmDebugDump(hfmModel); } catch(const std::exception& e) { - qCDebug(modelformat) << "OBJ reader fail: " << e.what(); + qCDebug(modelformat) << "OBJSerializer fail: " << e.what(); } QString queryPart = _url.query(); @@ -838,14 +839,14 @@ HFMModel::Pointer OBJReader::readOBJ(QByteArray& data, const QVariantHash& mappi } // Some .obj files use the convention that a group with uv coordinates that doesn't define a material, should use // a texture with the same basename as the .obj file. - if (preDefinedMaterial.userSpecifiesUV && !url.isEmpty()) { - QString filename = url.fileName(); + if (preDefinedMaterial.userSpecifiesUV && !_url.isEmpty()) { + QString filename = _url.fileName(); int extIndex = filename.lastIndexOf('.'); // by construction, this does not fail QString basename = filename.remove(extIndex + 1, sizeof("obj")); preDefinedMaterial.diffuseColor = glm::vec3(1.0f); QVector extensions = { "jpg", "jpeg", "png", "tga" }; QByteArray base = basename.toUtf8(), textName = ""; - qCDebug(modelformat) << "OBJ Reader looking for default texture"; + qCDebug(modelformat) << "OBJSerializer looking for default texture"; for (int i = 0; i < extensions.count(); i++) { QByteArray candidateString = base + extensions[i]; if (isValidTexture(candidateString)) { @@ -856,7 +857,7 @@ HFMModel::Pointer OBJReader::readOBJ(QByteArray& data, const QVariantHash& mappi if (!textName.isEmpty()) { #ifdef WANT_DEBUG - qCDebug(modelformat) << "OBJ Reader found a default texture: " << textName; + qCDebug(modelformat) << "OBJSerializer found a default texture: " << textName; #endif preDefinedMaterial.diffuseTextureFilename = textName; } @@ -866,7 +867,7 @@ HFMModel::Pointer OBJReader::readOBJ(QByteArray& data, const QVariantHash& mappi foreach (QString libraryName, librariesSeen.keys()) { // Throw away any path part of libraryName, and merge against original url. QUrl libraryUrl = _url.resolved(QUrl(libraryName).fileName()); - qCDebug(modelformat) << "OBJ Reader material library" << libraryName; + qCDebug(modelformat) << "OBJSerializer material library" << libraryName; bool success; QByteArray data; std::tie(success, data) = requestData(libraryUrl); @@ -875,7 +876,7 @@ HFMModel::Pointer OBJReader::readOBJ(QByteArray& data, const QVariantHash& mappi buffer.open(QIODevice::ReadOnly); parseMaterialLibrary(&buffer); } else { - qCDebug(modelformat) << "OBJ Reader WARNING:" << libraryName << "did not answer"; + qCDebug(modelformat) << "OBJSerializer WARNING:" << libraryName << "did not answer"; } } } diff --git a/libraries/fbx/src/OBJReader.h b/libraries/fbx/src/OBJSerializer.h similarity index 85% rename from libraries/fbx/src/OBJReader.h rename to libraries/fbx/src/OBJSerializer.h index 0088e8e9d7..a6fe3817ca 100644 --- a/libraries/fbx/src/OBJReader.h +++ b/libraries/fbx/src/OBJSerializer.h @@ -1,6 +1,20 @@ +// +// OBJSerializer.h +// libraries/fbx/src/ +// +// Created by Seth Alves on 3/6/15. +// Copyright 2015 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef hifi_OBJSerializer_h +#define hifi_OBJSerializer_h #include -#include "FBXReader.h" +#include +#include "FBXSerializer.h" class OBJTokenizer { public: @@ -75,7 +89,7 @@ public: OBJMaterial() : shininess(0.0f), opacity(1.0f), diffuseColor(0.9f), specularColor(0.9f), emissiveColor(0.0f), illuminationModel(-1) {} }; -class OBJReader: public QObject { // QObject so we can make network requests. +class OBJSerializer: public QObject, public HFMSerializer { // QObject so we can make network requests. Q_OBJECT public: typedef QVector FaceGroup; @@ -86,8 +100,8 @@ public: QVector faceGroups; QString currentMaterialName; QHash materials; - - HFMModel::Pointer readOBJ(QByteArray& data, const QVariantHash& mapping, bool combineParts, const QUrl& url = QUrl()); + + HFMModel::Pointer read(const QByteArray& data, const QVariantHash& mapping, const QUrl& url = QUrl()) override; private: QUrl _url; @@ -105,3 +119,5 @@ private: // What are these utilities doing here? One is used by fbx loading code in VHACD Utils, and the other a general debugging utility. void setMeshPartDefaults(HFMMeshPart& meshPart, QString materialID); void hfmDebugDump(const HFMModel& hfmModel); + +#endif // hifi_OBJSerializer_h diff --git a/libraries/hfm/src/hfm/HFMSerializer.h b/libraries/hfm/src/hfm/HFMSerializer.h new file mode 100644 index 0000000000..db18f21e06 --- /dev/null +++ b/libraries/hfm/src/hfm/HFMSerializer.h @@ -0,0 +1,29 @@ +// +// FBXSerializer.h +// libraries/hfm/src/hfm +// +// Created by Sabrina Shanman on 2018/11/07. +// Copyright 2018 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef hifi_HFMSerializer_h +#define hifi_HFMSerializer_h + +#include + +#include "HFM.h" + +namespace hfm { + +class Serializer { + virtual Model::Pointer read(const hifi::ByteArray& data, const hifi::VariantHash& mapping, const hifi::URL& url = hifi::URL()) = 0; +}; + +}; + +using HFMSerializer = hfm::Serializer; + +#endif // hifi_HFMSerializer_h diff --git a/libraries/model-networking/src/model-networking/ModelCache.cpp b/libraries/model-networking/src/model-networking/ModelCache.cpp index d3f24073c4..254f61eba9 100644 --- a/libraries/model-networking/src/model-networking/ModelCache.cpp +++ b/libraries/model-networking/src/model-networking/ModelCache.cpp @@ -12,9 +12,9 @@ #include "ModelCache.h" #include #include -#include "FBXReader.h" -#include "OBJReader.h" -#include "GLTFReader.h" +#include "FBXSerializer.h" +#include "OBJSerializer.h" +#include "GLTFSerializer.h" #include #include @@ -193,24 +193,26 @@ void GeometryReader::run() { HFMModel::Pointer hfmModel; + QVariantHash serializerMapping = _mapping; + serializerMapping["combineParts"] = _combineParts; + if (_url.path().toLower().endsWith(".fbx")) { - hfmModel.reset(readFBX(_data, _mapping, _url.path())); + hfmModel = FBXSerializer().read(_data, serializerMapping, _url); if (hfmModel->meshes.size() == 0 && hfmModel->joints.size() == 0) { throw QString("empty geometry, possibly due to an unsupported FBX version"); } } else if (_url.path().toLower().endsWith(".obj")) { - hfmModel = OBJReader().readOBJ(_data, _mapping, _combineParts, _url); + hfmModel = OBJSerializer().read(_data, serializerMapping, _url); } else if (_url.path().toLower().endsWith(".obj.gz")) { QByteArray uncompressedData; if (gunzip(_data, uncompressedData)){ - hfmModel = OBJReader().readOBJ(uncompressedData, _mapping, _combineParts, _url); + hfmModel = OBJSerializer().read(uncompressedData, serializerMapping, _url); } else { throw QString("failed to decompress .obj.gz"); } } else if (_url.path().toLower().endsWith(".gltf")) { - std::shared_ptr glreader = std::make_shared(); - hfmModel.reset(glreader->readGLTF(_data, _mapping, _url)); + hfmModel = GLTFSerializer().read(_data, serializerMapping, _url); if (hfmModel->meshes.size() == 0 && hfmModel->joints.size() == 0) { throw QString("empty geometry, possibly due to an unsupported GLTF version"); } diff --git a/libraries/model-networking/src/model-networking/ModelCache.h b/libraries/model-networking/src/model-networking/ModelCache.h index 1bb340b83c..9d458e7512 100644 --- a/libraries/model-networking/src/model-networking/ModelCache.h +++ b/libraries/model-networking/src/model-networking/ModelCache.h @@ -18,7 +18,7 @@ #include #include -#include "FBXReader.h" +#include "FBXSerializer.h" #include "TextureCache.h" // Alias instead of derive to avoid copying diff --git a/libraries/script-engine/src/ScriptEngines.cpp b/libraries/script-engine/src/ScriptEngines.cpp index 2cdfc20647..399ccf1919 100644 --- a/libraries/script-engine/src/ScriptEngines.cpp +++ b/libraries/script-engine/src/ScriptEngines.cpp @@ -191,7 +191,6 @@ void ScriptEngines::shutdownScripting() { // Gracefully stop the engine's scripting thread scriptEngine->stop(); - removeScriptEngine(scriptEngine); // We need to wait for the engine to be done running before we proceed, because we don't // want any of the scripts final "scriptEnding()" or pending "update()" methods from accessing @@ -370,13 +369,10 @@ QStringList ScriptEngines::getRunningScripts() { } void ScriptEngines::stopAllScripts(bool restart) { - QVector toReload; QReadLocker lock(&_scriptEnginesHashLock); if (_isReloading) { return; - } else { - _isReloading = true; } for (QHash::const_iterator it = _scriptEnginesHash.constBegin(); @@ -389,29 +385,27 @@ void ScriptEngines::stopAllScripts(bool restart) { // queue user scripts if restarting if (restart && scriptEngine->isUserLoaded()) { - toReload << it.key().toString(); + _isReloading = true; + bool lastScript = (it == _scriptEnginesHash.constEnd() - 1); + ScriptEngine::Type type = scriptEngine->getType(); + + connect(scriptEngine.data(), &ScriptEngine::finished, this, [this, type, lastScript] (QString scriptName) { + reloadScript(scriptName, true)->setType(type); + + if (lastScript) { + _isReloading = false; + } + }); } // stop all scripts scriptEngine->stop(); - removeScriptEngine(scriptEngine); } - // wait for engines to stop (ie: providing time for .scriptEnding cleanup handlers to run) before - // triggering reload of any Client scripts / Entity scripts - QTimer::singleShot(1000, this, [=]() { - for(const auto &scriptName : toReload) { - auto scriptEngine = getScriptEngine(scriptName); - if (scriptEngine && !scriptEngine->isFinished()) { - scriptEngine->waitTillDoneRunning(); - } - reloadScript(scriptName); - } - if (restart) { - qCDebug(scriptengine) << "stopAllScripts -- emitting scriptsReloading"; - emit scriptsReloading(); - } - _isReloading = false; - }); + + if (restart) { + qCDebug(scriptengine) << "stopAllScripts -- emitting scriptsReloading"; + emit scriptsReloading(); + } } bool ScriptEngines::stopScript(const QString& rawScriptURL, bool restart) { @@ -439,7 +433,6 @@ bool ScriptEngines::stopScript(const QString& rawScriptURL, bool restart) { } } scriptEngine->stop(); - removeScriptEngine(scriptEngine); stoppedScript = true; } } diff --git a/libraries/shared/src/DependencyManager.h b/libraries/shared/src/DependencyManager.h index 978732fd50..bda1077990 100644 --- a/libraries/shared/src/DependencyManager.h +++ b/libraries/shared/src/DependencyManager.h @@ -74,6 +74,9 @@ public: #endif return hashCode; } + + static void prepareToExit() { manager()._exiting = true; } + private: static DependencyManager& manager(); @@ -84,6 +87,8 @@ private: QHash> _instanceHash; QHash _inheritanceHash; + + bool _exiting { false }; }; template @@ -95,9 +100,17 @@ QSharedPointer DependencyManager::get() { instance = qSharedPointerCast(manager().safeGet(hashCode)); #ifndef QT_NO_DEBUG + // debug builds... if (instance.isNull()) { qWarning() << "DependencyManager::get(): No instance available for" << typeid(T).name(); } +#else + // for non-debug builds, don't print "No instance available" during shutdown, because + // the act of printing this often causes crashes (because the LogHandler has-been/is-being + // deleted). + if (!manager()._exiting && instance.isNull()) { + qWarning() << "DependencyManager::get(): No instance available for" << typeid(T).name(); + } #endif } diff --git a/libraries/shared/src/shared/HifiTypes.h b/libraries/shared/src/shared/HifiTypes.h new file mode 100644 index 0000000000..500170c88b --- /dev/null +++ b/libraries/shared/src/shared/HifiTypes.h @@ -0,0 +1,25 @@ +// +// HifiTypes.h +// libraries/shared/src/shared +// +// Created by Sabrina Shanman on 2018/11/12. +// Copyright 2018 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef hifi_HifiTypes_h +#define hifi_HifiTypes_h + +#include +#include +#include + +namespace hifi { + using ByteArray = QByteArray; + using VariantHash = QVariantHash; + using URL = QUrl; +}; + +#endif // hifi_HifiTypes_h diff --git a/scripts/system/controllers/controllerDispatcher.js b/scripts/system/controllers/controllerDispatcher.js index b657faefba..2658f11989 100644 --- a/scripts/system/controllers/controllerDispatcher.js +++ b/scripts/system/controllers/controllerDispatcher.js @@ -129,9 +129,6 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js"); return getControllerWorldLocation(Controller.Standard.RightHand, true); }; - Selection.enableListHighlight(DISPATCHER_HOVERING_LIST, DISPATCHER_HOVERING_STYLE); - Selection.enableListToScene(DISPATCHER_HOVERING_LIST); - this.updateTimings = function () { _this.intervalCount++; var thisInterval = Date.now(); @@ -525,7 +522,6 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js"); Controller.disableMapping(MAPPING_NAME); _this.pointerManager.removePointers(); Pointers.removePointer(this.mouseRayPick); - Selection.disableListHighlight(DISPATCHER_HOVERING_LIST); }; } diff --git a/scripts/system/controllers/controllerModules/equipEntity.js b/scripts/system/controllers/controllerModules/equipEntity.js index 12a69d7b27..c61e46c8eb 100644 --- a/scripts/system/controllers/controllerModules/equipEntity.js +++ b/scripts/system/controllers/controllerModules/equipEntity.js @@ -459,13 +459,7 @@ EquipHotspotBuddy.prototype.update = function(deltaTime, timestamp, controllerDa this.dropGestureReset(); this.clearEquipHaptics(); Controller.triggerHapticPulse(HAPTIC_PULSE_STRENGTH, HAPTIC_PULSE_DURATION, this.hand); - unhighlightTargetEntity(this.targetEntityID); - var message = { - hand: this.hand, - entityID: this.targetEntityID - }; - Messages.sendLocalMessage('Hifi-unhighlight-entity', JSON.stringify(message)); var grabbedProperties = Entities.getEntityProperties(this.targetEntityID, DISPATCHER_PROPERTIES); var grabData = getGrabbableData(grabbedProperties); diff --git a/scripts/system/controllers/controllerModules/farActionGrabEntity.js b/scripts/system/controllers/controllerModules/farActionGrabEntity.js index 91119a4292..1eaed44ce2 100644 --- a/scripts/system/controllers/controllerModules/farActionGrabEntity.js +++ b/scripts/system/controllers/controllerModules/farActionGrabEntity.js @@ -84,7 +84,6 @@ Script.include("/~/system/libraries/controllers.js"); this.entityWithContextOverlay = false; this.contextOverlayTimer = false; this.locked = false; - this.highlightedEntity = null; this.reticleMinX = MARGIN; this.reticleMaxX = null; this.reticleMinY = MARGIN; @@ -410,9 +409,6 @@ Script.include("/~/system/libraries/controllers.js"); if (controllerData.triggerValues[this.hand] < TRIGGER_OFF_VALUE || (this.notPointingAtEntity(controllerData) && Window.isPhysicsEnabled()) || this.targetIsNull()) { this.endFarGrabAction(); - Selection.removeFromSelectedItemsList(DISPATCHER_HOVERING_LIST, "entity", - this.highlightedEntity); - this.highlightedEntity = null; this.restoreIgnoredEntities(); return makeRunningValues(false, [], []); } @@ -466,9 +462,6 @@ Script.include("/~/system/libraries/controllers.js"); if (rayPickInfo.type === Picks.INTERSECTED_ENTITY) { if (controllerData.triggerClicks[this.hand]) { var entityID = rayPickInfo.objectID; - Selection.removeFromSelectedItemsList(DISPATCHER_HOVERING_LIST, "entity", - this.highlightedEntity); - this.highlightedEntity = null; var targetProps = Entities.getEntityProperties(entityID, DISPATCHER_PROPERTIES); if (targetProps.href !== "") { AddressManager.handleLookupString(targetProps.href); @@ -513,66 +506,43 @@ Script.include("/~/system/libraries/controllers.js"); this.startFarGrabAction(controllerData, targetProps); } } - } else { - var targetEntityID = rayPickInfo.objectID; - if (this.highlightedEntity !== targetEntityID) { - Selection.removeFromSelectedItemsList(DISPATCHER_HOVERING_LIST, "entity", - this.highlightedEntity); - var selectionTargetProps = Entities.getEntityProperties(targetEntityID, DISPATCHER_PROPERTIES); + } else if (!this.entityWithContextOverlay) { + var _this = this; - var selectionTargetObject = new TargetObject(targetEntityID, selectionTargetProps); - selectionTargetObject.parentProps = getEntityParents(selectionTargetProps); - var selectionTargetEntity = selectionTargetObject.getTargetEntity(); - - if (entityIsGrabbable(selectionTargetEntity.props) || - entityIsGrabbable(selectionTargetObject.entityProps)) { - - Selection.addToSelectedItemsList(DISPATCHER_HOVERING_LIST, "entity", rayPickInfo.objectID); + if (_this.potentialEntityWithContextOverlay !== rayPickInfo.objectID) { + if (_this.contextOverlayTimer) { + Script.clearTimeout(_this.contextOverlayTimer); } - this.highlightedEntity = rayPickInfo.objectID; + _this.contextOverlayTimer = false; + _this.potentialEntityWithContextOverlay = rayPickInfo.objectID; } - if (!this.entityWithContextOverlay) { - var _this = this; - - if (_this.potentialEntityWithContextOverlay !== rayPickInfo.objectID) { - if (_this.contextOverlayTimer) { - Script.clearTimeout(_this.contextOverlayTimer); + if (!_this.contextOverlayTimer) { + _this.contextOverlayTimer = Script.setTimeout(function () { + if (!_this.entityWithContextOverlay && + _this.contextOverlayTimer && + _this.potentialEntityWithContextOverlay === rayPickInfo.objectID) { + var props = Entities.getEntityProperties(rayPickInfo.objectID, DISPATCHER_PROPERTIES); + var pointerEvent = { + type: "Move", + id: _this.hand + 1, // 0 is reserved for hardware mouse + pos2D: projectOntoEntityXYPlane(rayPickInfo.objectID, + rayPickInfo.intersection, props), + pos3D: rayPickInfo.intersection, + normal: rayPickInfo.surfaceNormal, + direction: Vec3.subtract(ZERO_VEC, rayPickInfo.surfaceNormal), + button: "Secondary" + }; + if (ContextOverlay.createOrDestroyContextOverlay(rayPickInfo.objectID, pointerEvent)) { + _this.entityWithContextOverlay = rayPickInfo.objectID; + } } _this.contextOverlayTimer = false; - _this.potentialEntityWithContextOverlay = rayPickInfo.objectID; - } - - if (!_this.contextOverlayTimer) { - _this.contextOverlayTimer = Script.setTimeout(function () { - if (!_this.entityWithContextOverlay && - _this.contextOverlayTimer && - _this.potentialEntityWithContextOverlay === rayPickInfo.objectID) { - var props = Entities.getEntityProperties(rayPickInfo.objectID, DISPATCHER_PROPERTIES); - var pointerEvent = { - type: "Move", - id: _this.hand + 1, // 0 is reserved for hardware mouse - pos2D: projectOntoEntityXYPlane(rayPickInfo.objectID, - rayPickInfo.intersection, props), - pos3D: rayPickInfo.intersection, - normal: rayPickInfo.surfaceNormal, - direction: Vec3.subtract(ZERO_VEC, rayPickInfo.surfaceNormal), - button: "Secondary" - }; - if (ContextOverlay.createOrDestroyContextOverlay(rayPickInfo.objectID, pointerEvent)) { - _this.entityWithContextOverlay = rayPickInfo.objectID; - } - } - _this.contextOverlayTimer = false; - }, 500); - } + }, 500); } } } else if (this.distanceRotating) { this.distanceRotate(otherFarGrabModule); - } else if (this.highlightedEntity) { - Selection.removeFromSelectedItemsList(DISPATCHER_HOVERING_LIST, "entity", this.highlightedEntity); - this.highlightedEntity = null; } } return this.exitIfDisabled(controllerData); diff --git a/scripts/system/controllers/controllerModules/farParentGrabEntity.js b/scripts/system/controllers/controllerModules/farParentGrabEntity.js index f85869aa7f..230c4f06db 100644 --- a/scripts/system/controllers/controllerModules/farParentGrabEntity.js +++ b/scripts/system/controllers/controllerModules/farParentGrabEntity.js @@ -61,6 +61,8 @@ Script.include("/~/system/libraries/controllers.js"); this.reticleMinY = MARGIN; this.reticleMaxY = 0; this.lastUnexpectedChildrenCheckTime = 0; + this.endedGrab = 0; + this.MIN_HAPTIC_PULSE_INTERVAL = 500; // ms var FAR_GRAB_JOINTS = [65527, 65528]; // FARGRAB_LEFTHAND_INDEX, FARGRAB_RIGHTHAND_INDEX @@ -144,7 +146,12 @@ Script.include("/~/system/libraries/controllers.js"); // compute the mass for the purpose of energy and how quickly to move object this.mass = this.getMass(grabbedProperties.dimensions, grabbedProperties.density); - Controller.triggerHapticPulse(HAPTIC_PULSE_STRENGTH, HAPTIC_PULSE_DURATION, this.hand); + // Debounce haptic pules. Can occur as near grab controller module vacillates between being ready or not due to + // changing positions and floating point rounding. + if (Date.now() - this.endedGrab > this.MIN_HAPTIC_PULSE_INTERVAL) { + Controller.triggerHapticPulse(HAPTIC_PULSE_STRENGTH, HAPTIC_PULSE_DURATION, this.hand); + } + unhighlightTargetEntity(this.targetEntityID); var message = { hand: this.hand, @@ -256,7 +263,7 @@ Script.include("/~/system/libraries/controllers.js"); }; this.endFarParentGrab = function (controllerData) { - this.hapticTargetID = null; + this.endedGrab = Date.now(); // var endProps = controllerData.nearbyEntityPropertiesByID[this.targetEntityID]; var endProps = Entities.getEntityProperties(this.targetEntityID, DISPATCHER_PROPERTIES); if (this.thisFarGrabJointIsParent(endProps)) { @@ -410,11 +417,6 @@ Script.include("/~/system/libraries/controllers.js"); if (targetEntity) { var gtProps = Entities.getEntityProperties(targetEntity, DISPATCHER_PROPERTIES); if (entityIsGrabbable(gtProps)) { - // give haptic feedback - if (gtProps.id !== this.hapticTargetID) { - Controller.triggerHapticPulse(HAPTIC_PULSE_STRENGTH, HAPTIC_PULSE_DURATION, this.hand); - this.hapticTargetID = gtProps.id; - } // if we've attempted to grab a child, roll up to the root of the tree var groupRootProps = findGroupParent(controllerData, gtProps); if (entityIsGrabbable(groupRootProps)) { diff --git a/scripts/system/controllers/controllerModules/highlightNearbyEntities.js b/scripts/system/controllers/controllerModules/highlightNearbyEntities.js deleted file mode 100644 index 403b5d5149..0000000000 --- a/scripts/system/controllers/controllerModules/highlightNearbyEntities.js +++ /dev/null @@ -1,155 +0,0 @@ -// -// highlightNearbyEntities.js -// -// Created by Dante Ruiz 2018-4-10 -// Copyright 2017 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html - - -/* global Script, MyAvatar, entityIsCloneable, Messages, print */ - -"use strict"; - -(function () { - Script.include("/~/system/libraries/controllerDispatcherUtils.js"); - Script.include("/~/system/libraries/controllers.js"); - Script.include("/~/system/libraries/cloneEntityUtils.js"); - var dispatcherUtils = Script.require("/~/system/libraries/controllerDispatcherUtils.js"); - - function differenceInArrays(firstArray, secondArray) { - var differenceArray = firstArray.filter(function(element) { - return secondArray.indexOf(element) < 0; - }); - - return differenceArray; - } - - function HighlightNearbyEntities(hand) { - this.hand = hand; - this.otherHand = hand === dispatcherUtils.RIGHT_HAND ? dispatcherUtils.LEFT_HAND : - dispatcherUtils.RIGHT_HAND; - this.highlightedEntities = []; - - this.parameters = dispatcherUtils.makeDispatcherModuleParameters( - 480, - this.hand === dispatcherUtils.RIGHT_HAND ? ["rightHand"] : ["leftHand"], - [], - 100); - - - this.isGrabable = function(controllerData, props) { - var canGrabEntity = false; - if (dispatcherUtils.entityIsGrabbable(props) || entityIsCloneable(props)) { - // if we've attempted to grab a child, roll up to the root of the tree - var groupRootProps = dispatcherUtils.findGroupParent(controllerData, props); - canGrabEntity = true; - if (!dispatcherUtils.entityIsGrabbable(groupRootProps)) { - canGrabEntity = false; - } - } - return canGrabEntity; - }; - - this.clearAll = function() { - this.highlightedEntities.forEach(function(entity) { - dispatcherUtils.unhighlightTargetEntity(entity); - }); - }; - - this.hasHyperLink = function(props) { - return (props.href !== "" && props.href !== undefined); - }; - - this.removeEntityFromHighlightList = function(entityID) { - var index = this.highlightedEntities.indexOf(entityID); - if (index > -1) { - this.highlightedEntities.splice(index, 1); - } - }; - - this.getOtherModule = function() { - var otherModule = this.hand === dispatcherUtils.RIGHT_HAND ? leftHighlightNearbyEntities : - rightHighlightNearbyEntities; - return otherModule; - }; - - this.getOtherHandHighlightedEntities = function() { - return this.getOtherModule().highlightedEntities; - }; - - this.highlightEntities = function(controllerData) { - var nearbyEntitiesProperties = controllerData.nearbyEntityProperties[this.hand]; - var otherHandHighlightedEntities = this.getOtherHandHighlightedEntities(); - var newHighlightedEntities = []; - var sensorScaleFactor = MyAvatar.sensorToWorldScale; - for (var i = 0; i < nearbyEntitiesProperties.length; i++) { - var props = nearbyEntitiesProperties[i]; - if (props.distance > dispatcherUtils.NEAR_GRAB_RADIUS * sensorScaleFactor) { - continue; - } - if (this.isGrabable(controllerData, props) || this.hasHyperLink(props)) { - dispatcherUtils.highlightTargetEntity(props.id); - if (newHighlightedEntities.indexOf(props.id) < 0) { - newHighlightedEntities.push(props.id); - } - } - } - - var unhighlightEntities = differenceInArrays(this.highlightedEntities, newHighlightedEntities); - - unhighlightEntities.forEach(function(entityID) { - if (otherHandHighlightedEntities.indexOf(entityID) < 0 ) { - dispatcherUtils.unhighlightTargetEntity(entityID); - } - }); - this.highlightedEntities = newHighlightedEntities; - }; - - this.isReady = function(controllerData) { - this.highlightEntities(controllerData); - return dispatcherUtils.makeRunningValues(false, [], []); - }; - - this.run = function(controllerData) { - return this.isReady(controllerData); - }; - } - - var handleMessage = function(channel, message, sender) { - var data; - if (sender === MyAvatar.sessionUUID) { - if (channel === 'Hifi-unhighlight-entity') { - try { - data = JSON.parse(message); - var hand = data.hand; - if (hand === dispatcherUtils.LEFT_HAND) { - leftHighlightNearbyEntities.removeEntityFromHighlightList(data.entityID); - } else if (hand === dispatcherUtils.RIGHT_HAND) { - rightHighlightNearbyEntities.removeEntityFromHighlightList(data.entityID); - } - } catch (e) { - print("highlightNearbyEntities -- Failed to parse message: " + JSON.stringify(message)); - } - } else if (channel === 'Hifi-unhighlight-all') { - leftHighlightNearbyEntities.clearAll(); - rightHighlightNearbyEntities.clearAll(); - } - } - }; - var leftHighlightNearbyEntities = new HighlightNearbyEntities(dispatcherUtils.LEFT_HAND); - var rightHighlightNearbyEntities = new HighlightNearbyEntities(dispatcherUtils.RIGHT_HAND); - - dispatcherUtils.enableDispatcherModule("LeftHighlightNearbyEntities", leftHighlightNearbyEntities); - dispatcherUtils.enableDispatcherModule("RightHighlightNearbyEntities", rightHighlightNearbyEntities); - - function cleanup() { - dispatcherUtils.disableDispatcherModule("LeftHighlightNearbyEntities"); - dispatcherUtils.disableDispatcherModule("RightHighlightNearbyEntities"); - } - Messages.subscribe('Hifi-unhighlight-entity'); - Messages.subscribe('Hifi-unhighlight-all'); - Messages.messageReceived.connect(handleMessage); - Script.scriptEnding.connect(cleanup); -}()); diff --git a/scripts/system/controllers/controllerModules/mouseHighlightEntities.js b/scripts/system/controllers/controllerModules/mouseHighlightEntities.js deleted file mode 100644 index 59a68d98a4..0000000000 --- a/scripts/system/controllers/controllerModules/mouseHighlightEntities.js +++ /dev/null @@ -1,104 +0,0 @@ -// -// mouseHighlightEntities.js -// -// scripts/system/controllers/controllerModules/ -// -// Created by Dante Ruiz 2018-4-11 -// Copyright 2017 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -/* jslint bitwise: true */ - -/* global Script, print, Entities, Messages, Picks, HMD, MyAvatar, isInEditMode, DISPATCHER_PROPERTIES */ - - -(function() { - Script.include("/~/system/libraries/utils.js"); - var dispatcherUtils = Script.require("/~/system/libraries/controllerDispatcherUtils.js"); - - function MouseHighlightEntities() { - this.highlightedEntity = null; - this.grabbedEntity = null; - - this.parameters = dispatcherUtils.makeDispatcherModuleParameters( - 5, - ["mouse"], - [], - 100); - - this.setGrabbedEntity = function(entity) { - this.grabbedEntity = entity; - this.highlightedEntity = null; - }; - - this.isReady = function(controllerData) { - if (HMD.active) { - if (this.highlightedEntity) { - dispatcherUtils.unhighlightTargetEntity(this.highlightedEntity); - this.highlightedEntity = null; - } - } else if (!this.grabbedEntity && !isInEditMode()) { - var pickResult = controllerData.mouseRayPick; - if (pickResult.type === Picks.INTERSECTED_ENTITY) { - var targetEntityID = pickResult.objectID; - - if (this.highlightedEntity !== targetEntityID) { - var targetProps = Entities.getEntityProperties(targetEntityID, DISPATCHER_PROPERTIES); - - if (this.highlightedEntity) { - dispatcherUtils.unhighlightTargetEntity(this.highlightedEntity); - this.highlightedEntity = null; - } - - if (dispatcherUtils.entityIsGrabbable(targetProps)) { - // highlight entity - dispatcherUtils.highlightTargetEntity(targetEntityID); - this.highlightedEntity = targetEntityID; - } - } - } else if (this.highlightedEntity) { - dispatcherUtils.unhighlightTargetEntity(this.highlightedEntity); - this.highlightedEntity = null; - } - } - - return dispatcherUtils.makeRunningValues(false, [], []); - }; - - this.run = function(controllerData) { - return this.isReady(controllerData); - }; - } - - var mouseHighlightEntities = new MouseHighlightEntities(); - dispatcherUtils.enableDispatcherModule("MouseHighlightEntities", mouseHighlightEntities); - - var handleMessage = function(channel, message, sender) { - var data; - if (sender === MyAvatar.sessionUUID) { - if (channel === 'Hifi-Object-Manipulation') { - try { - data = JSON.parse(message); - if (data.action === 'grab') { - var grabbedEntity = data.grabbedEntity; - mouseHighlightEntities.setGrabbedEntity(grabbedEntity); - } else if (data.action === 'release') { - mouseHighlightEntities.setGrabbedEntity(null); - } - } catch (e) { - print("Warning: mouseHighlightEntities -- error parsing Hifi-Object-Manipulation: " + message); - } - } - } - }; - - function cleanup() { - dispatcherUtils.disableDispatcherModule("MouseHighlightEntities"); - } - Messages.subscribe('Hifi-Object-Manipulation'); - Messages.messageReceived.connect(handleMessage); - Script.scriptEnding.connect(cleanup); -})(); diff --git a/scripts/system/controllers/controllerModules/nearActionGrabEntity.js b/scripts/system/controllers/controllerModules/nearActionGrabEntity.js index 5ced6080a2..bb563a269c 100644 --- a/scripts/system/controllers/controllerModules/nearActionGrabEntity.js +++ b/scripts/system/controllers/controllerModules/nearActionGrabEntity.js @@ -24,7 +24,6 @@ Script.include("/~/system/libraries/cloneEntityUtils.js"); this.hand = hand; this.targetEntityID = null; this.actionID = null; // action this script created... - this.hapticTargetID = null; this.parameters = makeDispatcherModuleParameters( 500, @@ -115,13 +114,6 @@ Script.include("/~/system/libraries/cloneEntityUtils.js"); var args = [this.hand === RIGHT_HAND ? "right" : "left", MyAvatar.sessionUUID]; Entities.callEntityMethod(this.targetEntityID, "startNearGrab", args); - unhighlightTargetEntity(this.targetEntityID); - var message = { - hand: this.hand, - entityID: this.targetEntityID - }; - - Messages.sendLocalMessage('Hifi-unhighlight-entity', JSON.stringify(message)); }; // this is for when the action is going to time-out @@ -171,10 +163,6 @@ Script.include("/~/system/libraries/cloneEntityUtils.js"); break; } if (entityIsGrabbable(props) || entityIsCloneable(props)) { - if (props.id !== this.hapticTargetID) { - Controller.triggerHapticPulse(HAPTIC_PULSE_STRENGTH, HAPTIC_PULSE_DURATION, this.hand); - this.hapticTargetID = props.id; - } if (!entityIsCloneable(props)) { // if we've attempted to grab a non-cloneable child, roll up to the root of the tree var groupRootProps = findGroupParent(controllerData, props); @@ -206,7 +194,6 @@ Script.include("/~/system/libraries/cloneEntityUtils.js"); return makeRunningValues(true, [this.targetEntityID], []); } } else { - this.hapticTargetID = null; return makeRunningValues(false, [], []); } }; @@ -216,7 +203,6 @@ Script.include("/~/system/libraries/cloneEntityUtils.js"); if (controllerData.triggerClicks[this.hand] < TRIGGER_OFF_VALUE && controllerData.secondaryValues[this.hand] < TRIGGER_OFF_VALUE) { this.endNearGrabAction(); - this.hapticTargetID = null; return makeRunningValues(false, [], []); } diff --git a/scripts/system/controllers/controllerModules/nearParentGrabEntity.js b/scripts/system/controllers/controllerModules/nearParentGrabEntity.js index f354067a77..13557bdb7e 100644 --- a/scripts/system/controllers/controllerModules/nearParentGrabEntity.js +++ b/scripts/system/controllers/controllerModules/nearParentGrabEntity.js @@ -11,7 +11,7 @@ TRIGGER_OFF_VALUE, makeDispatcherModuleParameters, entityIsGrabbable, makeRunningValues, NEAR_GRAB_RADIUS, findGroupParent, Vec3, cloneEntity, entityIsCloneable, propsAreCloneDynamic, HAPTIC_PULSE_STRENGTH, HAPTIC_PULSE_DURATION, BUMPER_ON_VALUE, findHandChildEntities, TEAR_AWAY_DISTANCE, MSECS_PER_SEC, TEAR_AWAY_CHECK_TIME, - TEAR_AWAY_COUNT, distanceBetweenPointAndEntityBoundingBox, print, Uuid, highlightTargetEntity, unhighlightTargetEntity, + TEAR_AWAY_COUNT, distanceBetweenPointAndEntityBoundingBox, print, Uuid, NEAR_GRAB_DISTANCE, distanceBetweenEntityLocalPositionAndBoundingBox, getGrabbableData, getGrabPointSphereOffset, DISPATCHER_PROPERTIES */ @@ -24,15 +24,6 @@ Script.include("/~/system/libraries/controllers.js"); // XXX this.ignoreIK = (grabbableData.ignoreIK !== undefined) ? grabbableData.ignoreIK : true; // XXX this.kinematicGrab = (grabbableData.kinematic !== undefined) ? grabbableData.kinematic : NEAR_GRABBING_KINEMATIC; - // this offset needs to match the one in libraries/display-plugins/src/display-plugins/hmd/HmdDisplayPlugin.cpp:378 - var GRAB_POINT_SPHERE_OFFSET = { x: 0.04, y: 0.13, z: 0.039 }; // x = upward, y = forward, z = lateral - - function getGrabOffset(handController) { - var offset = getGrabPointSphereOffset(handController, true); - offset.y = -offset.y; - return Vec3.multiply(MyAvatar.sensorToWorldScale, offset); - } - function NearParentingGrabEntity(hand) { this.hand = hand; this.targetEntityID = null; @@ -40,12 +31,10 @@ Script.include("/~/system/libraries/controllers.js"); this.previousParentID = {}; this.previousParentJointIndex = {}; this.previouslyUnhooked = {}; - this.hapticTargetID = null; this.lastUnequipCheckTime = 0; this.autoUnequipCounter = 0; this.lastUnexpectedChildrenCheckTime = 0; this.robbed = false; - this.highlightedEntity = null; this.cloneAllowed = true; this.parameters = makeDispatcherModuleParameters( @@ -95,14 +84,7 @@ Script.include("/~/system/libraries/controllers.js"); this.startNearParentingGrabEntity = function (controllerData, targetProps) { var grabData = getGrabbableData(targetProps); Controller.triggerHapticPulse(HAPTIC_PULSE_STRENGTH, HAPTIC_PULSE_DURATION, this.hand); - unhighlightTargetEntity(this.targetEntityID); - this.highlightedEntity = null; - var message = { - hand: this.hand, - entityID: this.targetEntityID - }; - Messages.sendLocalMessage('Hifi-unhighlight-entity', JSON.stringify(message)); var handJointIndex; if (grabData.grabFollowsController) { handJointIndex = getControllerJointIndex(this.hand); @@ -146,7 +128,6 @@ Script.include("/~/system/libraries/controllers.js"); }; this.endNearParentingGrabEntity = function (controllerData) { - this.hapticTargetID = null; var props = controllerData.nearbyEntityPropertiesByID[this.targetEntityID]; if (this.thisHandIsParent(props) && !this.robbed) { Entities.editEntity(this.targetEntityID, { @@ -164,8 +145,7 @@ Script.include("/~/system/libraries/controllers.js"); grabbedEntity: this.targetEntityID, joint: this.hand === RIGHT_HAND ? "RightHand" : "LeftHand" })); - unhighlightTargetEntity(this.targetEntityID); - this.highlightedEntity = null; + this.grabbing = false; this.targetEntityID = null; this.robbed = false; @@ -178,8 +158,10 @@ Script.include("/~/system/libraries/controllers.js"); this.lastUnequipCheckTime = now; if (props.parentID === MyAvatar.SELF_ID) { var tearAwayDistance = TEAR_AWAY_DISTANCE * MyAvatar.sensorToWorldScale; - var controllerIndex = (this.hand === LEFT_HAND ? Controller.Standard.LeftHand : Controller.Standard.RightHand); - var controllerGrabOffset = getGrabOffset(controllerIndex); + var controllerIndex = + this.hand === LEFT_HAND ? Controller.Standard.LeftHand : Controller.Standard.RightHand; + var controllerGrabOffset = getGrabPointSphereOffset(controllerIndex, true); + controllerGrabOffset = Vec3.multiply(-MyAvatar.sensorToWorldScale, controllerGrabOffset); var distance = distanceBetweenEntityLocalPositionAndBoundingBox(props, controllerGrabOffset); if (distance > tearAwayDistance) { this.autoUnequipCounter++; @@ -242,21 +224,18 @@ Script.include("/~/system/libraries/controllers.js"); // nearbyEntityProperties is already sorted by length from controller var nearbyEntityProperties = controllerData.nearbyEntityProperties[this.hand]; var sensorScaleFactor = MyAvatar.sensorToWorldScale; + var nearGrabDistance = NEAR_GRAB_DISTANCE * sensorScaleFactor; + var nearGrabRadius = NEAR_GRAB_RADIUS * sensorScaleFactor; for (var i = 0; i < nearbyEntityProperties.length; i++) { var props = nearbyEntityProperties[i]; - var handPosition = controllerData.controllerLocations[this.hand].position; - var dist = distanceBetweenPointAndEntityBoundingBox(handPosition, props); - var distance = Vec3.distance(handPosition, props.position); - if ((dist > TEAR_AWAY_DISTANCE) || - (distance > NEAR_GRAB_RADIUS * sensorScaleFactor)) { + var grabPosition = controllerData.controllerLocations[this.hand].position; // Is offset from hand position. + var dist = distanceBetweenPointAndEntityBoundingBox(grabPosition, props); + var distance = Vec3.distance(grabPosition, props.position); + if ((dist > nearGrabDistance) || + (distance > nearGrabRadius)) { // Only smallish entities can be near grabbed. continue; } if (entityIsGrabbable(props) || entityIsCloneable(props)) { - // give haptic feedback - if (props.id !== this.hapticTargetID) { - Controller.triggerHapticPulse(HAPTIC_PULSE_STRENGTH, HAPTIC_PULSE_DURATION, this.hand); - this.hapticTargetID = props.id; - } if (!entityIsCloneable(props)) { // if we've attempted to grab a non-cloneable child, roll up to the root of the tree var groupRootProps = findGroupParent(controllerData, props); @@ -290,16 +269,9 @@ Script.include("/~/system/libraries/controllers.js"); return makeRunningValues(false, [], []); // let nearActionGrabEntity handle it } else { this.targetEntityID = targetProps.id; - this.highlightedEntity = this.targetEntityID; - highlightTargetEntity(this.targetEntityID); return makeRunningValues(true, [this.targetEntityID], []); } } else { - if (this.highlightedEntity) { - unhighlightTargetEntity(this.highlightedEntity); - this.highlightedEntity = null; - } - this.hapticTargetID = null; this.robbed = false; return makeRunningValues(false, [], []); } @@ -316,11 +288,8 @@ Script.include("/~/system/libraries/controllers.js"); var props = controllerData.nearbyEntityPropertiesByID[this.targetEntityID]; if (!props) { // entity was deleted - unhighlightTargetEntity(this.targetEntityID); - this.highlightedEntity = null; this.grabbing = false; this.targetEntityID = null; - this.hapticTargetID = null; this.robbed = false; return makeRunningValues(false, [], []); } @@ -335,12 +304,10 @@ Script.include("/~/system/libraries/controllers.js"); var args = [this.hand === RIGHT_HAND ? "right" : "left", MyAvatar.sessionUUID]; Entities.callEntityMethod(this.targetEntityID, "continueNearGrab", args); } else { - // still searching / highlighting + // still searching var readiness = this.isReady(controllerData); if (!readiness.active) { this.robbed = false; - unhighlightTargetEntity(this.highlightedEntity); - this.highlightedEntity = null; return readiness; } if (controllerData.triggerClicks[this.hand] || controllerData.secondaryValues[this.hand] > BUMPER_ON_VALUE) { diff --git a/scripts/system/controllers/controllerModules/nearTrigger.js b/scripts/system/controllers/controllerModules/nearTrigger.js index f4e39cfbb9..4bff4ea3f0 100644 --- a/scripts/system/controllers/controllerModules/nearTrigger.js +++ b/scripts/system/controllers/controllerModules/nearTrigger.js @@ -7,7 +7,7 @@ /* global Script, Entities, MyAvatar, RIGHT_HAND, LEFT_HAND, enableDispatcherModule, disableDispatcherModule, getGrabbableData, - Vec3, TRIGGER_OFF_VALUE, makeDispatcherModuleParameters, makeRunningValues, NEAR_GRAB_RADIUS, unhighlightTargetEntity + Vec3, TRIGGER_OFF_VALUE, makeDispatcherModuleParameters, makeRunningValues, NEAR_GRAB_RADIUS */ Script.include("/~/system/libraries/controllerDispatcherUtils.js"); @@ -55,7 +55,6 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js"); this.startNearTrigger = function (controllerData) { var args = [this.hand === RIGHT_HAND ? "right" : "left", MyAvatar.sessionUUID]; Entities.callEntityMethod(this.targetEntityID, "startNearTrigger", args); - unhighlightTargetEntity(this.targetEntityID); }; this.continueNearTrigger = function (controllerData) { diff --git a/scripts/system/controllers/controllerScripts.js b/scripts/system/controllers/controllerScripts.js index 999e448171..83fa455519 100644 --- a/scripts/system/controllers/controllerScripts.js +++ b/scripts/system/controllers/controllerScripts.js @@ -35,9 +35,7 @@ var CONTOLLER_SCRIPTS = [ "controllerModules/hudOverlayPointer.js", "controllerModules/mouseHMD.js", "controllerModules/scaleEntity.js", - "controllerModules/highlightNearbyEntities.js", "controllerModules/nearGrabHyperLinkEntity.js", - "controllerModules/mouseHighlightEntities.js", "controllerModules/nearTabletHighlight.js" ]; diff --git a/scripts/system/libraries/controllerDispatcherUtils.js b/scripts/system/libraries/controllerDispatcherUtils.js index e9d5255d28..ab2801087e 100644 --- a/scripts/system/libraries/controllerDispatcherUtils.js +++ b/scripts/system/libraries/controllerDispatcherUtils.js @@ -53,6 +53,7 @@ TEAR_AWAY_DISTANCE:true, TEAR_AWAY_COUNT:true, TEAR_AWAY_CHECK_TIME:true, + NEAR_GRAB_DISTANCE: true, distanceBetweenPointAndEntityBoundingBox:true, entityIsEquipped:true, entityIsFarGrabbedByOther:true, @@ -99,6 +100,10 @@ NEAR_GRAB_RADIUS = 1.0; TEAR_AWAY_DISTANCE = 0.15; // ungrab an entity if its bounding-box moves this far from the hand TEAR_AWAY_COUNT = 2; // multiply by TEAR_AWAY_CHECK_TIME to know how long the item must be away TEAR_AWAY_CHECK_TIME = 0.15; // seconds, duration between checks + +NEAR_GRAB_DISTANCE = 0.14; // Grab an entity if its bounding box is within this distance. +// Smaller than TEAR_AWAY_DISTANCE for hysteresis. + DISPATCHER_HOVERING_LIST = "dispactherHoveringList"; DISPATCHER_HOVERING_STYLE = { isOutlineSmooth: true, diff --git a/tests-manual/gpu/src/TestFbx.cpp b/tests-manual/gpu/src/TestFbx.cpp index 9253f8bc91..d3eab9e8e3 100644 --- a/tests-manual/gpu/src/TestFbx.cpp +++ b/tests-manual/gpu/src/TestFbx.cpp @@ -12,7 +12,7 @@ #include -#include +#include struct MyVertex { vec3 position; @@ -100,7 +100,7 @@ bool TestFbx::isReady() const { void TestFbx::parseFbx(const QByteArray& fbxData) { QVariantHash mapping; - HFMModel* hfmModel = readFBX(fbxData, mapping); + HFMModel::Pointer hfmModel = FBXSerializer().read(fbxData, mapping); size_t totalVertexCount = 0; size_t totalIndexCount = 0; size_t totalPartCount = 0; @@ -163,7 +163,6 @@ void TestFbx::parseFbx(const QByteArray& fbxData) { _vertexBuffer->append(vertices); _indexBuffer->append(indices); _indirectBuffer->append(parts); - delete hfmModel; } void TestFbx::renderTest(size_t testId, RenderArgs* args) { diff --git a/tools/nitpick/AppDataHighFidelity/domain-server/AccountInfo.bin b/tools/nitpick/AppDataHighFidelity/domain-server/AccountInfo.bin deleted file mode 100644 index 645e34895e..0000000000 Binary files a/tools/nitpick/AppDataHighFidelity/domain-server/AccountInfo.bin and /dev/null differ diff --git a/tools/nitpick/CMakeLists.txt b/tools/nitpick/CMakeLists.txt index 543b9c9b47..efb5125f69 100644 --- a/tools/nitpick/CMakeLists.txt +++ b/tools/nitpick/CMakeLists.txt @@ -50,10 +50,12 @@ if (WIN32) ) # add a custom command to copy the empty Apps/Data High Fidelity folder (i.e. - a valid folder with no entities) + # this also copied to the containing folder, to facilitate running from Visual Studio add_custom_command( TARGET ${TARGET_NAME} POST_BUILD COMMAND "${CMAKE_COMMAND}" -E copy_directory "${CMAKE_CURRENT_SOURCE_DIR}/AppDataHighFidelity" "$/AppDataHighFidelity" + COMMAND "${CMAKE_COMMAND}" -E copy_directory "${CMAKE_CURRENT_SOURCE_DIR}/AppDataHighFidelity" "AppDataHighFidelity" ) # add a custom command to copy the SSL DLLs @@ -62,5 +64,12 @@ if (WIN32) POST_BUILD COMMAND "${CMAKE_COMMAND}" -E copy_directory "$ENV{VCPKG_ROOT}/installed/x64-windows/bin" "$" ) +elseif (APPLE) + # add a custom command to copy the empty Apps/Data High Fidelity folder (i.e. - a valid folder with no entities) + add_custom_command( + TARGET ${TARGET_NAME} + POST_BUILD + COMMAND "${CMAKE_COMMAND}" -E copy_directory "${CMAKE_CURRENT_SOURCE_DIR}/AppDataHighFidelity" "$/AppDataHighFidelity" + ) +endif () -endif () \ No newline at end of file diff --git a/tools/nitpick/README.md b/tools/nitpick/README.md index e8129ae29e..7d75d660d7 100644 --- a/tools/nitpick/README.md +++ b/tools/nitpick/README.md @@ -1,6 +1,6 @@ # nitpick -Nitpick is a stand alone application that provides a mechanism for regression testing. The general idea is simple: +Nitpick is a stand alone application that provides a mechanism for regression testing. The general idea is simple: * Each test folder has a script that produces a set of snapshots. * The snapshots are compared to a 'canonical' set of images that have been produced beforehand. * The result, if any test failed, is a zipped folder describing the failure. @@ -12,70 +12,99 @@ Nitpick has 5 functions, separated into 4 tabs: 1. Evaluating the results of running tests 1. Web interface -## Installation -### Executable -1. On Windows: download the installer by browsing to [here](). -2. Double click on the installer and install to a convenient location +## Build (for developers) +Nitpick is built as part of the High Fidelity build. +### Creating installers +#### Windows +1. Verify that 7Zip is installed. +1. cd to the `build\tools\nitpick\Release` directory +1. Delete any existing installers (named nitpick-installer-###.exe) +1. Select all, right-click and select 7-Zip->Add to archive... +1. Set Archive format to 7z +1. Check "Create SFX archive +1. Enter installer name (i.e. `nitpick-installer-v1.1.exe`) +1. Click "OK" +1. Copy created installer to https://hifi-qa.s3.amazonaws.com/nitpick/Windows/nitpick-installer-v1.1.exe: aws s3 cp nitpick-installer-v1.1.exe s3://hifi-qa/nitpick/Mac/nitpick-installer-v1.1.exe +#### Mac +These steps assume the hifi repository has been cloned to `~/hifi`. +1. (first time) Install brew + In a terminal: `/usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)` +1. (First time) install create-dmg: + In a terminal: `brew install create-dmg` +1. In a terminal: cd to the `build/tools/nitpick/Release` folder +1. Copy the quazip dynamic library (note final period): + In a terminal: `cp ~/hifi/build/ext/Xcode/quazip/project/lib/libquazip5.1.dylib .` +1. Change the loader instruction to find the dynamic library locally + In a terminal: `install_name_tool -change ~/hifi/build/ext/Xcode/quazip/project/lib/libquazip5.1.dylib libquazip5.1.dylib nitpick` +1. Delete any existing disk images. In a terminal: `rm *.dmg` +1. Create installer (note final period).In a terminal: `create-dmg --volname nitpick-installer-v1.1 nitpick-installer-v1.1.dmg .` + Make sure to wait for completion. +1. Copy created installer to AWS: `~/Library/Python/3.7/bin/aws s3 cp nitpick-installer-v1.1.dmg s3://hifi-qa/nitpick/Mac/nitpick-installer-v1.1.dmg` +### Installation +#### Windows +1. (First time) download and install vc_redist.x64.exe (available at https://hifi-qa.s3.amazonaws.com/nitpick/Windows/nitpick-installer-v1.1.exe) +1. (First time) download and install Python 3 from https://hifi-qa.s3.amazonaws.com/nitpick/Windows/python-3.7.0-amd64.exe (also located at https://www.python.org/downloads/) + 1. After installation - create an environment variable called PYTHON_PATH and set it to the folder containing the Python executable. +1. (First time) download and install AWS CLI from https://hifi-qa.s3.amazonaws.com/nitpick/Windows/AWSCLI64PY3.msi (also available at https://aws.amazon.com/cli/ + 1. Open a new command prompt and run `aws configure` + 1. Enter the AWS account number + 1. Enter the secret key + 1. Leave region name and ouput format as default [None] + 1. Install the latest release of Boto3 via pip: `pip install boto3` + +1. Download the installer by browsing to [here]() +1. Double click on the installer and install to a convenient location ![](./setup_7z.PNG) -3. To run nitpick, double click **nitpick.exe**. -### Python -The TestRail interface requires Python 3 to be installed. Nitpick has been tested with Python 3.7.0 but should work with newer versions. - -Python 3 can be downloaded from: -1. Windows installer -2. Linux (source) (**Gzipped source tarball**) -3. Mac (**macOS 64-bit/32-bit installer** or **macOS 64-bit/32-bit installer**) - -#### Windows -After installation - create an environment variable called PYTHON_PATH and set it to the folder containing the Python executable. +1. __To run nitpick, double click **nitpick.exe**__ #### Mac -After installation - run `open "/Applications/Python 3.6/Install Certificates.command"`. This is needed because the Mac Python supplied no longer links with the deprecated Apple-supplied system OpenSSL libraries but rather supplies a private copy of OpenSSL 1.0.2 which does not automatically access the system default root certificates. -Verify that `/usr/local/bin/python3` exists. +1. (first time) Install brew + In a terminal: `/usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)` +1. (First time) install Qt: + In a terminal: `brew install qt` +1. (First time) install Python from https://www.python.org/downloads/release/python-370/ (**macOS 64-bit installer** or **macOS 64-bit/32-bit installer**) + 1. After installation - In a terminal: run `open "/Applications/Python 3.6/Install Certificates.command"`. This is needed because the Mac Python supplied no longer links with the deprecated Apple-supplied system OpenSSL libraries but rather supplies a private copy of OpenSSL 1.0.2 which does not automatically access the system default root certificates. + 1. Verify that `/usr/local/bin/python3` exists. +1. (First time - AWS interface) Install pip with the script provided by the Python Packaging Authority: +In a terminal: `curl -O https://bootstrap.pypa.io/get-pip.py` +In a terminal: `python3 get-pip.py --user` + 1. Use pip to install the AWS CLI. + `pip3 install awscli --upgrade --user` + This will install aws in your user. For user XXX, aws will be located in ~/Library/Python/3.7/bin + 1. Open a new command prompt and run `~/Library/Python/3.7/bin/aws configure` + 1. Enter the AWS account number + 1. Enter the secret key + 1. Leave region name and ouput format as default [None] + 1. Install the latest release of Boto3 via pip: pip3 install boto3 +1. Download the installer by browsing to [here](). +1. Double-click on the downloaded image to mount it +1. Create a folder for the nitpick files (e.g. ~/nitpick) + If this folder exists then delete all it's contents. +1. Copy the downloaded files to the folder + In a terminal: + `cd ~/nitpick` + `cp -r /Volumes/nitpick-installer-v1.1/* .` -### AWS interface -#### Windows -1. Download the AWS CLI from `https://aws.amazon.com/cli/` -1. Install (installer is named `AWSCLI64PY3.msi`) -1. Open a new command prompt and run `aws configure` -1. Enter the AWS account number -1. Enter the secret key -1. Leave region name and ouput format as default [None] -1. Install the latest release of Boto3 via pip: -pip install boto3 -#### Mac -1. Install pip with the script provided by the Python Packaging Authority: -$ curl -O https://bootstrap.pypa.io/get-pip.py -$ python3 get-pip.py --user - -1. Use pip to install the AWS CLI. -$ pip3 install awscli --upgrade --user -This will install aws in your user. For user XXX, aws will be located in /Users/XXX/Library/Python/3.7/bin -1. Open a new command prompt and run `aws configure` -1. Enter the AWS account number -1. Enter the secret key -1. Leave region name and ouput format as default [None] -1. Install the latest release of Boto3 via pip: -pip3 install boto3 - -# Create +1. __To run nitpick, cd to the folder that you copied to and run `./nitpick`__ +# Usage +## Create ![](./Create.PNG) The Create tab provides functions to create tests from snapshots, MD files, a test outline and recursive scripts. -## Create Tests -### Usage +### Create Tests +#### Usage This function is used to create/update Expected Images after a successful run of a test, or multiple tests. The user will be asked for the snapshot folder and then the tests root folder. All snapshots located in the snapshot folder will be used to create or update the expected images in the relevant tests. -### Details +#### Details As an example - if the snapshots folder contains an image named `tests.content.entity.zone.zoneOrientation.00003.png`, then this file will be copied to `tests/contente/enity/zone/zoneOrientation/ExpectedImage0003.png`. -## Create Tests Outline -### Usage +### Create Tests Outline +#### Usage This function creates an MD file in the (user-selected) tests root folder. The file provides links to both the tests and the MD files. -## Create MD file -### Usage +### Create MD file +#### Usage This function creates a file named `test.md` from a `test.js` script. The user will be asked for the folder containing the test script: -### Details +#### Details The process to produce the MD file is a simplistic parse of the test script. - The string in the `nitpick.perform(...)` function call will be the title of the file @@ -86,25 +115,25 @@ The process to produce the MD file is a simplistic parse of the test script. - The step description is the string in the addStep/addStepStepSnapshot commands - Image links are provided where applicable to the local Expected Images files -## Create all MD files -### Usage +### Create all MD files +#### Usage This function creates all MD files recursively from the user-selected root folder. This can be any folder in the tests hierarchy (e.g. all engine\material tests). The file provides a hierarchal list of all the tests -## Create testAuto script -### Usage +### Create testAuto script +#### Usage This function creates a script named `testAuto.js` in a user-selected test folder. -### Details +#### Details The script created runs the `test.js` script in the folder in automatic mode. The script is the same for all tests. -## Create all testAuto scripts -### Usage +### Create all testAuto scripts +#### Usage This function creates all testAuto scripts recursively from the user-selected root folder. This can be any folder in the tests hierarchy (e.g. all engine\material tests). The file provides a hierarchical list of all the tests -## Create Recursive Script -### Usage +### Create Recursive Script +#### Usage After the user selects a folder within the tests hierarchy, a script is created, named `testRecursive.js`. This script calls all `test.js` scripts in the sub-folders. -### Details +#### Details The various scripts are called in alphabetical order. An example of a recursive script is as follows: @@ -130,18 +159,18 @@ Script.include(testsRootPath + "content/overlay/layer/drawHUDLayer/test.js"); nitpick.runRecursive(); ``` -## Create all Recursive Scripts -### Usage +### Create all Recursive Scripts +#### Usage In this case all recursive scripts, from the selected folder down, are created. Running this function in the tests root folder will create (or update) all the recursive scripts. -# Windows +## Windows ![](./Windows.PNG) This tab is Windows-specific. It provides buttons to hide and show the task bar. The task bar should be hidden for all tests that use the primary camera. This is required to ensure that the snapshots are the right size. -# Run +## Run ![](./Run.PNG) The run tab is used to run tests in automatic mode. The tests require the location of a folder to store files in; this folder can safely be re-used for any number of runs (the "Working Folder"). The test script that is run is `https://github.com/highfidelity/hifi_tests/blob/master/tests/testRecursive.js`. The user can use a different branch' or even repository, if required. @@ -163,7 +192,7 @@ The working folder will ultimately contain the following: 1. The `dev-builds.xml` file, if it was downloaded. 1. The HighFidelity installer. Note that this is always named `HighFidelity-Beta-latest-dev` so as not to store too many installers over time. 1. A log file describing the runs. This file is appended to after each run. -# Evaluate +## Evaluate ![](./Evaluate.PNG) The Evaluate tab provides a single function - evaluating the results of a test run. @@ -171,11 +200,11 @@ The Evaluate tab provides a single function - evaluating the results of a test r A checkbox (defaulting to checked) runs the evaluation in interactive mode. In this mode - every failure is shown to the user, who can then decide whether to pass the test, fail it or abort the whole evaluation. If any tests have failed, then a zipped folder will be created in the snapshots folder, with a description of each failed step in each test. -### Usage +#### Usage Before starting the evaluation, make sure the GitHub user and branch are set correctly. The user should not normally be changed, but the branch may need to be set to the appropriate RC. After setting the check-box as required and pressing Evaluate - the user will be asked for the snapshots folder. -### Details +#### Details Evaluation proceeds in a number of steps: 1. A folder is created to store any failures @@ -191,7 +220,7 @@ Evaluation proceeds in a number of steps: 1. At the end of the test, the folder is zipped and the original folder is deleted. If there are no errors then the zipped folder will be empty. -# Web Interface +## Web Interface ![](./WebInterface.PNG) This tab has two functions: updating the TestRail cases, runs and results, and creating web page reports that are stored on AWS. @@ -206,8 +235,8 @@ Any access to TestRail will require the TestRail account (default is High Fideli - The Project ID defaults to 14 - Interface. - The Suite ID defaults to 1147 - Rendering. - The TestRail page provides 3 functions for writing to TestRail. -## Create Test Cases -### Usage +### Create Test Cases +#### Usage This function can either create an XML file that can then be imported into TestRail through TestRail itself, or automatically create the appropriate TestRail Sections. The user will be first asked for the tests root folder and a folder to store temporary files (this is the output folder). @@ -219,7 +248,7 @@ If Python is selected, the user will then be prompted for TestRail data. After After selecting the appropriate Release, press OK. The Python script will be created in the output folder, and the user will be prompted to run it. A busy window will appear until the process is complete. -### Details +#### Details A number of Python scripts are created: - `testrail.py` is the TestRail interface code. - `stack.py` is a simple stack class @@ -227,7 +256,7 @@ A number of Python scripts are created: - `addTestCases` is the script that writes to TestRail. In addition - a file containing all the releases will be created - `releases.txt` -## Create Run +### Create Run A Run is created from previously created Test Cases. The user will first be prompted for a temporary folder (for the Python scripts). @@ -237,7 +266,7 @@ After entering TestRail data and pressing `Accept` - the Sections combo will be After selecting the appropriate Section, press OK. The Python script will be created in the output folder, and the user will be prompted to run it. A busy window will appear until the process is complete. -### Details +#### Details A number of Python scripts are created: - `testrail.py` is the TestRail interface code. - `stack.py` is a simple stack class @@ -245,7 +274,7 @@ A number of Python scripts are created: - `addRun` is the script that writes to TestRail. In addition - a file containing all the releases will be created - `sections.txt` -## Update Run Results +### Update Run Results This function updates a Run with the results of an automated test. The user will first be prompted to enter the zipped results folder and a folder to store temporary files (this is the output folder). @@ -255,13 +284,13 @@ After entering TestRail data and pressing `Accept` - the Run combo will be popul After selecting the appropriate Run, press OK. The Python script will be created in the output folder, and the user will be prompted to run it. A busy window will appear until the process is complete. -### Details +#### Details A number of Python scripts are created: - `testrail.py` is the TestRail interface code. - `getRuns.py` reads the release names from TestRail - `addRun` is the script that writes to TestRail. In addition - a file containing all the releases will be created - `runs.txt`. -## Create Web Page +### Create Web Page This function requests a zipped results folder and converts it to a web page. The page is created in a user-selecetd working folder. If the `Update AWS` checkbox is checked then the page will also be copied to AWS, and the appropriate URL will be displayed in the window below the button. diff --git a/tools/nitpick/src/Downloader.cpp b/tools/nitpick/src/Downloader.cpp index de768398b0..3256e79601 100644 --- a/tools/nitpick/src/Downloader.cpp +++ b/tools/nitpick/src/Downloader.cpp @@ -12,12 +12,12 @@ #include Downloader::Downloader(QUrl fileURL, QObject *parent) : QObject(parent) { + _networkAccessManager.get(QNetworkRequest(fileURL)); + connect( &_networkAccessManager, SIGNAL (finished(QNetworkReply*)), this, SLOT (fileDownloaded(QNetworkReply*)) ); - - _networkAccessManager.get(QNetworkRequest(fileURL)); } void Downloader::fileDownloaded(QNetworkReply* reply) { diff --git a/tools/nitpick/src/Test.cpp b/tools/nitpick/src/Test.cpp index 47458d00ee..e17978d9d0 100644 --- a/tools/nitpick/src/Test.cpp +++ b/tools/nitpick/src/Test.cpp @@ -620,7 +620,7 @@ void Test::createTestAutoScript() { } if (createTestAutoScript(_testDirectory)) { - QMessageBox::information(0, "Success", "'nitpick.js` script has been created"); + QMessageBox::information(0, "Success", "'testAuto.js` script has been created"); } } @@ -677,7 +677,7 @@ bool Test::createTestAutoScript(const QString& directory) { stream << "if (typeof PATH_TO_THE_REPO_PATH_UTILS_FILE === 'undefined') PATH_TO_THE_REPO_PATH_UTILS_FILE = 'https://raw.githubusercontent.com/highfidelity/hifi_tests/master/tests/utils/branchUtils.js';\n"; stream << "Script.include(PATH_TO_THE_REPO_PATH_UTILS_FILE);\n"; - stream << "var nitpick = createAutoTester(Script.resolvePath('.'));\n\n"; + stream << "var nitpick = createNitpick(Script.resolvePath('.'));\n\n"; stream << "nitpick.enableAuto();\n\n"; stream << "Script.include('./test.js?raw=true');\n"; @@ -748,9 +748,9 @@ void Test::createRecursiveScript(const QString& topLevelDirectory, bool interact QTextStream textStream(&allTestsFilename); - textStream << "// This is an automatically generated file, created by auto-tester" << endl; + textStream << "// This is an automatically generated file, created by nitpick" << endl; - // Include 'autoTest.js' + // Include 'nitpick.js' QString branch = nitpick->getSelectedBranch(); QString user = nitpick->getSelectedUser(); @@ -758,7 +758,7 @@ void Test::createRecursiveScript(const QString& topLevelDirectory, bool interact "/tests/utils/branchUtils.js\";" << endl; textStream << "Script.include(PATH_TO_THE_REPO_PATH_UTILS_FILE);" << endl; - textStream << "var nitpick = createAutoTester(Script.resolvePath(\".\"));" << endl << endl; + textStream << "var nitpick = createNitpick(Script.resolvePath(\".\"));" << endl << endl; textStream << "var testsRootPath = nitpick.getTestsRootPath();" << endl << endl; diff --git a/tools/nitpick/src/TestRunner.cpp b/tools/nitpick/src/TestRunner.cpp index c7823ba751..12bdf87495 100644 --- a/tools/nitpick/src/TestRunner.cpp +++ b/tools/nitpick/src/TestRunner.cpp @@ -332,23 +332,23 @@ void TestRunner::verifyInstallationSucceeded() { } void TestRunner::saveExistingHighFidelityAppDataFolder() { -#ifdef Q_OS_WIN QString dataDirectory{ "NOT FOUND" }; - +#ifdef Q_OS_WIN dataDirectory = qgetenv("USERPROFILE") + "\\AppData\\Roaming"; - +#elif defined Q_OS_MAC + dataDirectory = QDir::homePath() + "/Library/Application Support"; +#endif if (_runLatest->isChecked()) { - _appDataFolder = dataDirectory + "\\High Fidelity"; + _appDataFolder = dataDirectory + "/High Fidelity"; } else { // We are running a PR build - _appDataFolder = dataDirectory + "\\High Fidelity - " + getPRNumberFromURL(_url->text()); + _appDataFolder = dataDirectory + "/High Fidelity - " + getPRNumberFromURL(_url->text()); } _savedAppDataFolder = dataDirectory + "/" + UNIQUE_FOLDER_NAME; - if (_savedAppDataFolder.exists()) { + if (QDir(_savedAppDataFolder).exists()) { _savedAppDataFolder.removeRecursively(); } - if (_appDataFolder.exists()) { // The original folder is saved in a unique name _appDataFolder.rename(_appDataFolder.path(), _savedAppDataFolder.path()); @@ -356,9 +356,6 @@ void TestRunner::saveExistingHighFidelityAppDataFolder() { // Copy an "empty" AppData folder (i.e. no entities) copyFolder(QDir::currentPath() + "/AppDataHighFidelity", _appDataFolder.path()); -#elif defined Q_OS_MAC - // TODO: find Mac equivalent of AppData -#endif } void TestRunner::createSnapshotFolder() { @@ -469,12 +466,7 @@ void TestRunner::runInterfaceWithTestScript() { // Move to an empty area url = "file:///~serverless/tutorial.json"; } else { -#ifdef Q_OS_WIN url = "hifi://localhost"; -#elif defined Q_OS_MAC - // TODO: Find out Mac equivalent of AppData, then this won't be needed - url = "hifi://localhost/9999,9999,9999"; -#endif } QString testScript = @@ -535,8 +527,6 @@ void TestRunner::runInterfaceWithTestScript() { } void TestRunner::interfaceExecutionComplete() { - killProcesses(); - QFileInfo testCompleted(QDir::toNativeSeparators(_snapshotFolder) +"/tests_completed.txt"); if (!testCompleted.exists()) { QMessageBox::critical(0, "Tests not completed", "Interface seems to have crashed before completion of the test scripts\nExisting images will be evaluated"); @@ -544,6 +534,8 @@ void TestRunner::interfaceExecutionComplete() { evaluateResults(); + killProcesses(); + // The High Fidelity AppData folder will be restored after evaluation has completed } @@ -589,15 +581,11 @@ void TestRunner::addBuildNumberToResults(QString zippedFolderName) { } void TestRunner::restoreHighFidelityAppDataFolder() { -#ifdef Q_OS_WIN _appDataFolder.removeRecursively(); if (_savedAppDataFolder != QDir()) { _appDataFolder.rename(_savedAppDataFolder.path(), _appDataFolder.path()); } -#elif defined Q_OS_MAC - // TODO: find Mac equivalent of AppData -#endif } // Copies a folder recursively diff --git a/tools/nitpick/src/ui/Nitpick.cpp b/tools/nitpick/src/ui/Nitpick.cpp index a4aef8fad5..201d6e562d 100644 --- a/tools/nitpick/src/ui/Nitpick.cpp +++ b/tools/nitpick/src/ui/Nitpick.cpp @@ -36,7 +36,7 @@ Nitpick::Nitpick(QWidget* parent) : QMainWindow(parent) { _ui.statusLabel->setText(""); _ui.plainTextEdit->setReadOnly(true); - setWindowTitle("Nitpick - v1.0"); + setWindowTitle("Nitpick - v1.1"); // Coming soon to a nitpick near you... //// _helpWindow.textBrowser->setText() diff --git a/tools/skeleton-dump/src/SkeletonDumpApp.cpp b/tools/skeleton-dump/src/SkeletonDumpApp.cpp index 10b13aef36..42a1c78090 100644 --- a/tools/skeleton-dump/src/SkeletonDumpApp.cpp +++ b/tools/skeleton-dump/src/SkeletonDumpApp.cpp @@ -12,7 +12,7 @@ #include "SkeletonDumpApp.h" #include #include -#include +#include #include SkeletonDumpApp::SkeletonDumpApp(int argc, char* argv[]) : QCoreApplication(argc, argv) { @@ -54,7 +54,7 @@ SkeletonDumpApp::SkeletonDumpApp(int argc, char* argv[]) : QCoreApplication(argc return; } QByteArray blob = file.readAll(); - std::unique_ptr geometry(readFBX(blob, QVariantHash())); + HFMModel::Pointer geometry = FBXSerializer().read(blob, QVariantHash()); std::unique_ptr skeleton(new AnimSkeleton(*geometry)); skeleton->dump(verbose); } diff --git a/tools/vhacd-util/src/VHACDUtil.cpp b/tools/vhacd-util/src/VHACDUtil.cpp index 8de9c39da9..9401da4314 100644 --- a/tools/vhacd-util/src/VHACDUtil.cpp +++ b/tools/vhacd-util/src/VHACDUtil.cpp @@ -15,9 +15,11 @@ #include #include +#include +#include -// FBXReader jumbles the order of the meshes by reading them back out of a hashtable. This will put +// FBXSerializer jumbles the order of the meshes by reading them back out of a hashtable. This will put // them back in the order in which they appeared in the file. bool HFMModelLessThan(const HFMMesh& e1, const HFMMesh& e2) { return e1.meshIndex < e2.meshIndex; @@ -43,10 +45,9 @@ bool vhacd::VHACDUtil::loadFBX(const QString filename, HFMModel& result) { QByteArray fbxContents = fbx.readAll(); HFMModel::Pointer hfmModel; if (filename.toLower().endsWith(".obj")) { - bool combineParts = false; - hfmModel = OBJReader().readOBJ(fbxContents, QVariantHash(), combineParts); + hfmModel = OBJSerializer().read(fbxContents, QVariantHash(), filename); } else if (filename.toLower().endsWith(".fbx")) { - hfmModel.reset(readFBX(fbxContents, QVariantHash(), filename)); + hfmModel = FBXSerializer().read(fbxContents, QVariantHash(), filename); } else { qWarning() << "file has unknown extension" << filename; return false; diff --git a/tools/vhacd-util/src/VHACDUtil.h b/tools/vhacd-util/src/VHACDUtil.h index dd8f606756..0fb70e8af7 100644 --- a/tools/vhacd-util/src/VHACDUtil.h +++ b/tools/vhacd-util/src/VHACDUtil.h @@ -18,10 +18,10 @@ #include #include //c++11 feature #include -#include -#include #include +#include + namespace vhacd { class VHACDUtil { public: diff --git a/tools/vhacd-util/src/VHACDUtilApp.h b/tools/vhacd-util/src/VHACDUtilApp.h index 7dadad20b3..1cbb29bb88 100644 --- a/tools/vhacd-util/src/VHACDUtilApp.h +++ b/tools/vhacd-util/src/VHACDUtilApp.h @@ -15,7 +15,7 @@ #include -#include +#include const int VHACD_RETURN_CODE_FAILURE_TO_READ = 1; const int VHACD_RETURN_CODE_FAILURE_TO_WRITE = 2;