diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml
index 7255e1f295..b216819ed0 100644
--- a/android/app/src/main/AndroidManifest.xml
+++ b/android/app/src/main/AndroidManifest.xml
@@ -9,6 +9,7 @@
+
@@ -75,6 +76,15 @@
android:enabled="true"
android:exported="false"
android:process=":breakpad_uploader"/>
+
+
+
+
+
+
diff --git a/android/app/src/main/cpp/native.cpp b/android/app/src/main/cpp/native.cpp
index ce5af01f29..6b44b2dc7a 100644
--- a/android/app/src/main/cpp/native.cpp
+++ b/android/app/src/main/cpp/native.cpp
@@ -355,5 +355,51 @@ JNIEXPORT void Java_io_highfidelity_hifiinterface_WebViewActivity_nativeProcessU
AndroidHelper::instance().processURL(QString::fromUtf8(nativeString));
}
+JNIEXPORT void JNICALL
+Java_io_highfidelity_hifiinterface_fragment_SettingsFragment_updateHifiSetting(JNIEnv *env,
+ jobject instance,
+ jstring group_,
+ jstring key_,
+ jboolean value_) {
+ const char *c_group = env->GetStringUTFChars(group_, 0);
+ const char *c_key = env->GetStringUTFChars(key_, 0);
+
+ const QString group = QString::fromUtf8(c_group);
+ const QString key = QString::fromUtf8(c_key);
+
+ env->ReleaseStringUTFChars(group_, c_group);
+ env->ReleaseStringUTFChars(key_, c_key);
+
+ bool value = value_;
+
+ Setting::Handle setting { QStringList() << group << key , !value };
+ setting.set(value);
+}
+
+JNIEXPORT jboolean JNICALL
+Java_io_highfidelity_hifiinterface_fragment_SettingsFragment_getHifiSettingBoolean(JNIEnv *env,
+ jobject instance,
+ jstring group_,
+ jstring key_,
+ jboolean defaultValue) {
+ const char *c_group = env->GetStringUTFChars(group_, 0);
+ const char *c_key = env->GetStringUTFChars(key_, 0);
+
+ const QString group = QString::fromUtf8(c_group);
+ const QString key = QString::fromUtf8(c_key);
+
+ env->ReleaseStringUTFChars(group_, c_group);
+ env->ReleaseStringUTFChars(key_, c_key);
+
+ Setting::Handle setting { QStringList() << group << key , defaultValue};
+ return setting.get();
+}
+
+JNIEXPORT void JNICALL
+Java_io_highfidelity_hifiinterface_receiver_HeadsetStateReceiver_notifyHeadsetOn(JNIEnv *env,
+ jobject instance,
+ jboolean pluggedIn) {
+ AndroidHelper::instance().notifyHeadsetOn(pluggedIn);
+}
}
diff --git a/android/app/src/main/java/io/highfidelity/hifiinterface/InterfaceActivity.java b/android/app/src/main/java/io/highfidelity/hifiinterface/InterfaceActivity.java
index f161783d6a..08e66a2f42 100644
--- a/android/app/src/main/java/io/highfidelity/hifiinterface/InterfaceActivity.java
+++ b/android/app/src/main/java/io/highfidelity/hifiinterface/InterfaceActivity.java
@@ -13,6 +13,7 @@ package io.highfidelity.hifiinterface;
import android.content.Context;
import android.content.Intent;
+import android.content.IntentFilter;
import android.content.pm.ActivityInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
@@ -40,6 +41,7 @@ import java.util.HashMap;
import java.util.List;
import io.highfidelity.hifiinterface.fragment.WebViewFragment;
+import io.highfidelity.hifiinterface.receiver.HeadsetStateReceiver;
/*import com.google.vr.cardboard.DisplaySynchronizer;
import com.google.vr.cardboard.DisplayUtils;
@@ -55,6 +57,7 @@ public class InterfaceActivity extends QtActivity implements WebViewFragment.OnW
private static final int NORMAL_DPI = 160;
private Vibrator mVibrator;
+ private HeadsetStateReceiver headsetStateReceiver;
//public static native void handleHifiURL(String hifiURLString);
private native long nativeOnCreate(InterfaceActivity instance, AssetManager assetManager);
@@ -151,6 +154,8 @@ public class InterfaceActivity extends QtActivity implements WebViewFragment.OnW
layoutParams.resolveLayoutDirection(View.LAYOUT_DIRECTION_RTL);
qtLayout.addView(webSlidingDrawer, layoutParams);
webSlidingDrawer.setVisibility(View.GONE);
+
+ headsetStateReceiver = new HeadsetStateReceiver();
}
@Override
@@ -161,6 +166,7 @@ public class InterfaceActivity extends QtActivity implements WebViewFragment.OnW
} else {
nativeEnterBackground();
}
+ unregisterReceiver(headsetStateReceiver);
//gvrApi.pauseTracking();
}
@@ -183,6 +189,7 @@ public class InterfaceActivity extends QtActivity implements WebViewFragment.OnW
nativeEnterForeground();
surfacesWorkaround();
keepInterfaceRunning = false;
+ registerReceiver(headsetStateReceiver, new IntentFilter(Intent.ACTION_HEADSET_PLUG));
//gvrApi.resumeTracking();
}
diff --git a/android/app/src/main/java/io/highfidelity/hifiinterface/MainActivity.java b/android/app/src/main/java/io/highfidelity/hifiinterface/MainActivity.java
index db6f0fca24..4c6d05a3e8 100644
--- a/android/app/src/main/java/io/highfidelity/hifiinterface/MainActivity.java
+++ b/android/app/src/main/java/io/highfidelity/hifiinterface/MainActivity.java
@@ -33,6 +33,7 @@ import io.highfidelity.hifiinterface.fragment.FriendsFragment;
import io.highfidelity.hifiinterface.fragment.HomeFragment;
import io.highfidelity.hifiinterface.fragment.LoginFragment;
import io.highfidelity.hifiinterface.fragment.PolicyFragment;
+import io.highfidelity.hifiinterface.fragment.SettingsFragment;
import io.highfidelity.hifiinterface.task.DownloadProfileImageTask;
public class MainActivity extends AppCompatActivity implements NavigationView.OnNavigationItemSelectedListener,
@@ -80,6 +81,8 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
mPeopleMenuItem = mNavigationView.getMenu().findItem(R.id.action_people);
+ updateDebugMenu(mNavigationView.getMenu());
+
Toolbar toolbar = findViewById(R.id.toolbar);
toolbar.setTitleTextAppearance(this, R.style.HomeActionBarTitleStyle);
setSupportActionBar(toolbar);
@@ -108,6 +111,16 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
}
}
+ private void updateDebugMenu(Menu menu) {
+ if (BuildConfig.DEBUG) {
+ for (int i=0; i < menu.size(); i++) {
+ if (menu.getItem(i).getItemId() == R.id.action_debug_settings) {
+ menu.getItem(i).setVisible(true);
+ }
+ }
+ }
+ }
+
private void loadFragment(String fragment) {
switch (fragment) {
case "Login":
@@ -151,6 +164,13 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
loadFragment(fragment, getString(R.string.people), getString(R.string.tagFragmentPeople), true);
}
+ private void loadSettingsFragment() {
+ SettingsFragment fragment = SettingsFragment.newInstance();
+
+ loadFragment(fragment, getString(R.string.settings), getString(R.string.tagSettings), true);
+ }
+
+
private void loadFragment(Fragment fragment, String title, String tag, boolean addToBackStack) {
FragmentManager fragmentManager = getFragmentManager();
@@ -241,6 +261,9 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
case R.id.action_people:
loadPeopleFragment();
return true;
+ case R.id.action_debug_settings:
+ loadSettingsFragment();
+ return true;
}
return false;
}
diff --git a/android/app/src/main/java/io/highfidelity/hifiinterface/fragment/SettingsFragment.java b/android/app/src/main/java/io/highfidelity/hifiinterface/fragment/SettingsFragment.java
new file mode 100644
index 0000000000..cc23665e72
--- /dev/null
+++ b/android/app/src/main/java/io/highfidelity/hifiinterface/fragment/SettingsFragment.java
@@ -0,0 +1,63 @@
+package io.highfidelity.hifiinterface.fragment;
+
+import android.content.SharedPreferences;
+import android.media.audiofx.AcousticEchoCanceler;
+import android.os.Bundle;
+import android.preference.Preference;
+import android.preference.PreferenceFragment;
+import android.support.annotation.Nullable;
+
+import io.highfidelity.hifiinterface.R;
+
+public class SettingsFragment extends PreferenceFragment implements SharedPreferences.OnSharedPreferenceChangeListener {
+
+ public native void updateHifiSetting(String group, String key, boolean value);
+ public native boolean getHifiSettingBoolean(String group, String key, boolean defaultValue);
+
+ private final String HIFI_SETTINGS_ANDROID_GROUP = "Android";
+ private final String HIFI_SETTINGS_AEC_KEY = "aec";
+ private final String PREFERENCE_KEY_AEC = "aec";
+
+ @Override
+ public void onCreate(@Nullable Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ addPreferencesFromResource(R.xml.settings);
+
+ if (!AcousticEchoCanceler.isAvailable()) {
+ getPreferenceScreen().getPreferenceManager().findPreference("aec").setEnabled(false);
+ }
+
+ getPreferenceScreen().getSharedPreferences().edit().putBoolean(PREFERENCE_KEY_AEC,
+ getHifiSettingBoolean(HIFI_SETTINGS_ANDROID_GROUP, HIFI_SETTINGS_AEC_KEY, false));
+ }
+
+ public static SettingsFragment newInstance() {
+ SettingsFragment fragment = new SettingsFragment();
+ return fragment;
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+ getPreferenceScreen().getSharedPreferences().registerOnSharedPreferenceChangeListener(this);
+ }
+
+ @Override
+ public void onPause() {
+ super.onPause();
+ getPreferenceScreen().getSharedPreferences().unregisterOnSharedPreferenceChangeListener(this);
+
+ }
+
+ @Override
+ public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
+ Preference pref = findPreference(key);
+ switch (key) {
+ case "aec":
+ updateHifiSetting(HIFI_SETTINGS_ANDROID_GROUP, HIFI_SETTINGS_AEC_KEY, sharedPreferences.getBoolean(key, false));
+ break;
+ default:
+ break;
+ }
+ }
+}
diff --git a/android/app/src/main/java/io/highfidelity/hifiinterface/receiver/HeadsetStateReceiver.java b/android/app/src/main/java/io/highfidelity/hifiinterface/receiver/HeadsetStateReceiver.java
new file mode 100644
index 0000000000..5645912d73
--- /dev/null
+++ b/android/app/src/main/java/io/highfidelity/hifiinterface/receiver/HeadsetStateReceiver.java
@@ -0,0 +1,18 @@
+package io.highfidelity.hifiinterface.receiver;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.media.AudioManager;
+import android.util.Log;
+
+public class HeadsetStateReceiver extends BroadcastReceiver {
+
+ private native void notifyHeadsetOn(boolean pluggedIn);
+
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ AudioManager audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
+ notifyHeadsetOn(audioManager.isWiredHeadsetOn());
+ }
+}
diff --git a/android/app/src/main/res/menu/menu_navigation.xml b/android/app/src/main/res/menu/menu_navigation.xml
index 3cce64f9f5..142af5d146 100644
--- a/android/app/src/main/res/menu/menu_navigation.xml
+++ b/android/app/src/main/res/menu/menu_navigation.xml
@@ -9,4 +9,9 @@
android:id="@+id/action_people"
android:title="@string/people"
/>
+
diff --git a/android/app/src/main/res/values/strings.xml b/android/app/src/main/res/values/strings.xml
index b158aba59d..abde15f484 100644
--- a/android/app/src/main/res/values/strings.xml
+++ b/android/app/src/main/res/values/strings.xml
@@ -29,4 +29,9 @@
tagFragmentLogin
tagFragmentPolicy
tagFragmentPeople
+ tagSettings
+ Settings
+ AEC
+ Acoustic Echo Cancellation
+ Developer
diff --git a/android/app/src/main/res/xml/settings.xml b/android/app/src/main/res/xml/settings.xml
new file mode 100644
index 0000000000..5ec47b1aff
--- /dev/null
+++ b/android/app/src/main/res/xml/settings.xml
@@ -0,0 +1,11 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/android/build.gradle b/android/build.gradle
index a6de0d469c..aa7aa399b2 100644
--- a/android/build.gradle
+++ b/android/build.gradle
@@ -72,17 +72,17 @@ def jniFolder = new File(appDir, 'src/main/jniLibs/arm64-v8a')
def baseUrl = 'https://hifi-public.s3.amazonaws.com/dependencies/android/'
def breakpadDumpSymsDir = new File("${appDir}/build/tmp/breakpadDumpSyms")
-def qtFile='qt-5.11.1_linux_armv8-libcpp_openssl.tgz'
-def qtChecksum='f312c47cd8b8dbca824c32af4eec5e66'
-def qtVersionId='nyCGcb91S4QbYeJhUkawO5x1lrLdSNB_'
+def qtFile='qt-5.11.1_linux_armv8-libcpp_openssl_patched.tgz'
+def qtChecksum='aa449d4bfa963f3bc9a9dfe558ba29df'
+def qtVersionId='3S97HBM5G5Xw9EfE52sikmgdN3t6C2MN'
if (Os.isFamily(Os.FAMILY_MAC)) {
- qtFile = 'qt-5.11.1_osx_armv8-libcpp_openssl.tgz'
- qtChecksum='a0c8b394aec5b0fcd46714ca3a53278a'
- qtVersionId='QNa.lwNJaPc0eGuIL.xZ8ebeTuLL7rh8'
+ qtFile = 'qt-5.11.1_osx_armv8-libcpp_openssl_patched.tgz'
+ qtChecksum='c83cc477c08a892e00c71764dca051a0'
+ qtVersionId='OxBD7iKINv1HbyOXmAmDrBb8AF3N.Kup'
} else if (Os.isFamily(Os.FAMILY_WINDOWS)) {
- qtFile = 'qt-5.11.1_win_armv8-libcpp_openssl.tgz'
- qtChecksum='d80aed4233ce9e222aae8376e7a94bf9'
- qtVersionId='iDVXu0i3WEXRFIxQCtzcJ2XuKrE8RIqB'
+ qtFile = 'qt-5.11.1_win_armv8-libcpp_openssl_patched.tgz'
+ qtChecksum='0582191cc55431aa4f660848a542883e'
+ qtVersionId='JfWM0P_Mz5Qp0LwpzhrsRwN3fqlLSFeT'
}
def packages = [
diff --git a/interface/resources/qml/AnimStats.qml b/interface/resources/qml/AnimStats.qml
index 35ed3799a6..b1900cf0a7 100644
--- a/interface/resources/qml/AnimStats.qml
+++ b/interface/resources/qml/AnimStats.qml
@@ -48,35 +48,11 @@ Item {
spacing: 4; x: 4; y: 4;
StatText {
- text: "State Machines:---------------------------------------------------------------------------"
+ text: root.positionText
}
- ListView {
- width: firstCol.width
- height: root.animStateMachines.length * 15
- visible: root.animStateMchines.length > 0;
- model: root.animStateMachines
- delegate: StatText {
- text: {
- return modelData;
- }
- }
- }
- }
- }
-
- Rectangle {
- width: secondCol.width + 8
- height: secondCol.height + 8
- color: root.bgColor;
-
- Column {
- id: secondCol
- spacing: 4; x: 4; y: 4;
-
StatText {
text: "Anim Vars:--------------------------------------------------------------------------------"
}
-
ListView {
width: secondCol.width
height: root.animVars.length * 15
@@ -104,6 +80,36 @@ Item {
}
}
+ Rectangle {
+ width: secondCol.width + 8
+ height: secondCol.height + 8
+ color: root.bgColor;
+
+ Column {
+ id: secondCol
+ spacing: 4; x: 4; y: 4;
+
+ StatText {
+ text: root.rotationText
+ }
+ StatText {
+ text: "State Machines:---------------------------------------------------------------------------"
+ }
+ ListView {
+ width: firstCol.width
+ height: root.animStateMachines.length * 15
+ visible: root.animStateMachines.length > 0;
+ model: root.animStateMachines
+ delegate: StatText {
+ text: {
+ return modelData;
+ }
+ }
+ }
+
+ }
+ }
+
Rectangle {
width: thirdCol.width + 8
height: thirdCol.height + 8
@@ -113,10 +119,12 @@ Item {
id: thirdCol
spacing: 4; x: 4; y: 4;
+ StatText {
+ text: root.velocityText
+ }
StatText {
text: "Alpha Values:--------------------------------------------------------------------------"
}
-
ListView {
width: thirdCol.width
height: root.animAlphaValues.length * 15
diff --git a/interface/src/AndroidHelper.cpp b/interface/src/AndroidHelper.cpp
index 419382f2cb..400085a62a 100644
--- a/interface/src/AndroidHelper.cpp
+++ b/interface/src/AndroidHelper.cpp
@@ -10,6 +10,7 @@
//
#include "AndroidHelper.h"
#include
+#include
#include "Application.h"
#if defined(qApp)
@@ -18,6 +19,7 @@
#define qApp (static_cast(QCoreApplication::instance()))
AndroidHelper::AndroidHelper() {
+ qRegisterMetaType("QAudio::Mode");
}
AndroidHelper::~AndroidHelper() {
@@ -56,3 +58,12 @@ void AndroidHelper::processURL(const QString &url) {
qApp->acceptURL(url);
}
}
+
+void AndroidHelper::notifyHeadsetOn(bool pluggedIn) {
+#if defined (Q_OS_ANDROID)
+ auto audioClient = DependencyManager::get();
+ if (audioClient) {
+ QMetaObject::invokeMethod(audioClient.data(), "setHeadsetPluggedIn", Q_ARG(bool, pluggedIn));
+ }
+#endif
+}
diff --git a/interface/src/AndroidHelper.h b/interface/src/AndroidHelper.h
index 03d92f91d9..11b84e4025 100644
--- a/interface/src/AndroidHelper.h
+++ b/interface/src/AndroidHelper.h
@@ -29,6 +29,7 @@ public:
void performHapticFeedback(int duration);
void processURL(const QString &url);
+ void notifyHeadsetOn(bool pluggedIn);
AndroidHelper(AndroidHelper const&) = delete;
void operator=(AndroidHelper const&) = delete;
diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp
index ac21af6d44..e0d2ab2586 100644
--- a/interface/src/Application.cpp
+++ b/interface/src/Application.cpp
@@ -1760,10 +1760,12 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
// Make sure we don't time out during slow operations at startup
updateHeartbeat();
-
QTimer* settingsTimer = new QTimer();
moveToNewNamedThread(settingsTimer, "Settings Thread", [this, settingsTimer]{
- connect(qApp, &Application::beforeAboutToQuit, [this, settingsTimer]{
+ // This needs to run on the settings thread, so we need to pass the `settingsTimer` as the
+ // receiver object, otherwise it will run on the application thread and trigger a warning
+ // about trying to kill the timer on the main thread.
+ connect(qApp, &Application::beforeAboutToQuit, settingsTimer, [this, settingsTimer]{
// Disconnect the signal from the save settings
QObject::disconnect(settingsTimer, &QTimer::timeout, this, &Application::saveSettings);
// Stop the settings timer
@@ -3499,13 +3501,14 @@ bool Application::isServerlessMode() const {
}
void Application::setIsInterstitialMode(bool interstitialMode) {
- Settings settings;
- bool enableInterstitial = settings.value("enableIntersitialMode", false).toBool();
- if (_interstitialMode != interstitialMode && enableInterstitial) {
- _interstitialMode = interstitialMode;
+ bool enableInterstitial = DependencyManager::get()->getDomainHandler().getInterstitialModeEnabled();
+ if (enableInterstitial) {
+ if (_interstitialMode != interstitialMode) {
+ _interstitialMode = interstitialMode;
- DependencyManager::get()->setAudioPaused(_interstitialMode);
- DependencyManager::get()->setMyAvatarDataPacketsPaused(_interstitialMode);
+ DependencyManager::get()->setAudioPaused(_interstitialMode);
+ DependencyManager::get()->setMyAvatarDataPacketsPaused(_interstitialMode);
+ }
}
}
diff --git a/interface/src/Application.h b/interface/src/Application.h
index b4df36704a..d9fff89915 100644
--- a/interface/src/Application.h
+++ b/interface/src/Application.h
@@ -434,7 +434,7 @@ public slots:
void setIsServerlessMode(bool serverlessDomain);
void loadServerlessDomain(QUrl domainURL, bool errorDomain = false);
- void setIsInterstitialMode(bool interstialMode);
+ void setIsInterstitialMode(bool interstitialMode);
void updateVerboseLogging();
diff --git a/interface/src/ConnectionMonitor.cpp b/interface/src/ConnectionMonitor.cpp
index 3c85cfb339..e86061b090 100644
--- a/interface/src/ConnectionMonitor.cpp
+++ b/interface/src/ConnectionMonitor.cpp
@@ -41,9 +41,15 @@ void ConnectionMonitor::init() {
}
connect(&_timer, &QTimer::timeout, this, [this]() {
- qDebug() << "ConnectionMonitor: Redirecting to 404 error domain";
// set in a timeout error
- emit setRedirectErrorState(REDIRECT_HIFI_ADDRESS, 5);
+ bool enableInterstitial = DependencyManager::get()->getDomainHandler().getInterstitialModeEnabled();
+ if (enableInterstitial) {
+ qDebug() << "ConnectionMonitor: Redirecting to 404 error domain";
+ emit setRedirectErrorState(REDIRECT_HIFI_ADDRESS, "", 5);
+ } else {
+ qDebug() << "ConnectionMonitor: Showing connection failure window";
+ DependencyManager::get()->setDomainConnectionFailureVisibility(true);
+ }
});
}
@@ -53,4 +59,8 @@ void ConnectionMonitor::startTimer() {
void ConnectionMonitor::stopTimer() {
_timer.stop();
+ bool enableInterstitial = DependencyManager::get()->getDomainHandler().getInterstitialModeEnabled();
+ if (!enableInterstitial) {
+ DependencyManager::get()->setDomainConnectionFailureVisibility(false);
+ }
}
diff --git a/interface/src/ConnectionMonitor.h b/interface/src/ConnectionMonitor.h
index 5e75e2618b..2fda6ef7cd 100644
--- a/interface/src/ConnectionMonitor.h
+++ b/interface/src/ConnectionMonitor.h
@@ -24,7 +24,7 @@ public:
void init();
signals:
- void setRedirectErrorState(QUrl errorURL, int reasonCode);
+ void setRedirectErrorState(QUrl errorURL, QString reasonMessage = "", int reasonCode = -1, const QString& extraInfo = "");
private slots:
void startTimer();
@@ -34,4 +34,4 @@ private:
QTimer _timer;
};
-#endif // hifi_ConnectionMonitor_h
\ No newline at end of file
+#endif // hifi_ConnectionMonitor_h
diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp
index c47cfdb383..df7ec93b6a 100755
--- a/interface/src/avatar/MyAvatar.cpp
+++ b/interface/src/avatar/MyAvatar.cpp
@@ -91,6 +91,8 @@ const float MIN_SCALE_CHANGED_DELTA = 0.001f;
const int MODE_READINGS_RING_BUFFER_SIZE = 500;
const float CENTIMETERS_PER_METER = 100.0f;
+const QString AVATAR_SETTINGS_GROUP_NAME { "Avatar" };
+
MyAvatar::MyAvatar(QThread* thread) :
Avatar(thread),
_yawSpeed(YAW_SPEED_DEFAULT),
@@ -118,7 +120,22 @@ MyAvatar::MyAvatar(QThread* thread) :
_goToOrientation(),
_prevShouldDrawHead(true),
_audioListenerMode(FROM_HEAD),
- _hmdAtRestDetector(glm::vec3(0), glm::quat())
+ _hmdAtRestDetector(glm::vec3(0), glm::quat()),
+ _dominantHandSetting(QStringList() << AVATAR_SETTINGS_GROUP_NAME << "dominantHand", DOMINANT_RIGHT_HAND),
+ _headPitchSetting(QStringList() << AVATAR_SETTINGS_GROUP_NAME << "", 0.0f),
+ _scaleSetting(QStringList() << AVATAR_SETTINGS_GROUP_NAME << "scale", _targetScale),
+ _yawSpeedSetting(QStringList() << AVATAR_SETTINGS_GROUP_NAME << "yawSpeed", _yawSpeed),
+ _pitchSpeedSetting(QStringList() << AVATAR_SETTINGS_GROUP_NAME << "pitchSpeed", _pitchSpeed),
+ _fullAvatarURLSetting(QStringList() << AVATAR_SETTINGS_GROUP_NAME << "fullAvatarURL",
+ AvatarData::defaultFullAvatarModelUrl()),
+ _fullAvatarModelNameSetting(QStringList() << AVATAR_SETTINGS_GROUP_NAME << "fullAvatarModelName", _fullAvatarModelName),
+ _animGraphURLSetting(QStringList() << AVATAR_SETTINGS_GROUP_NAME << "animGraphURL", QUrl("")),
+ _displayNameSetting(QStringList() << AVATAR_SETTINGS_GROUP_NAME << "displayName", ""),
+ _collisionSoundURLSetting(QStringList() << AVATAR_SETTINGS_GROUP_NAME << "collisionSoundURL", QUrl(_collisionSoundURL)),
+ _useSnapTurnSetting(QStringList() << AVATAR_SETTINGS_GROUP_NAME << "useSnapTurn", _useSnapTurn),
+ _userHeightSetting(QStringList() << AVATAR_SETTINGS_GROUP_NAME << "userHeight", DEFAULT_AVATAR_HEIGHT),
+ _flyingHMDSetting(QStringList() << AVATAR_SETTINGS_GROUP_NAME << "flyingHMD", _flyingPrefHMD),
+ _avatarEntityCountSetting(QStringList() << AVATAR_SETTINGS_GROUP_NAME << "avatarEntityData" << "size", _flyingPrefHMD)
{
_clientTraitsHandler = std::unique_ptr(new ClientTraitsHandler(this));
@@ -1135,88 +1152,80 @@ void MyAvatar::restoreRoleAnimation(const QString& role) {
}
void MyAvatar::saveAvatarUrl() {
- Settings settings;
- settings.beginGroup("Avatar");
- if (qApp->getSaveAvatarOverrideUrl() || !qApp->getAvatarOverrideUrl().isValid() ) {
- settings.setValue("fullAvatarURL",
- _fullAvatarURLFromPreferences == AvatarData::defaultFullAvatarModelUrl() ?
- "" :
- _fullAvatarURLFromPreferences.toString());
+ if (qApp->getSaveAvatarOverrideUrl() || !qApp->getAvatarOverrideUrl().isValid()) {
+ _fullAvatarURLSetting.set(_fullAvatarURLFromPreferences == AvatarData::defaultFullAvatarModelUrl() ?
+ "" :
+ _fullAvatarURLFromPreferences.toString());
+ }
+}
+
+void MyAvatar::resizeAvatarEntitySettingHandles(unsigned int avatarEntityIndex) {
+ // The original Settings interface saved avatar-entity array data like this:
+ // Avatar/avatarEntityData/size: 5
+ // Avatar/avatarEntityData/1/id: ...
+ // Avatar/avatarEntityData/1/properties: ...
+ // ...
+ // Avatar/avatarEntityData/5/id: ...
+ // Avatar/avatarEntityData/5/properties: ...
+ //
+ // Create Setting::Handles to mimic this.
+
+ while (_avatarEntityIDSettings.size() <= avatarEntityIndex) {
+ Setting::Handle idHandle(QStringList() << AVATAR_SETTINGS_GROUP_NAME << "avatarEntityData"
+ << QString::number(avatarEntityIndex + 1) << "id", QUuid());
+ _avatarEntityIDSettings.push_back(idHandle);
+ Setting::Handle dataHandle(QStringList() << AVATAR_SETTINGS_GROUP_NAME << "avatarEntityData"
+ << QString::number(avatarEntityIndex + 1) << "properties", QByteArray());
+ _avatarEntityDataSettings.push_back(dataHandle);
}
- settings.endGroup();
}
void MyAvatar::saveData() {
- Settings settings;
- settings.beginGroup("Avatar");
-
- settings.setValue("dominantHand", _dominantHand);
- settings.setValue("headPitch", getHead()->getBasePitch());
-
- settings.setValue("scale", _targetScale);
-
- settings.setValue("yawSpeed", _yawSpeed);
- settings.setValue("pitchSpeed", _pitchSpeed);
+ _dominantHandSetting.set(_dominantHand);
+ _headPitchSetting.set(getHead()->getBasePitch());
+ _scaleSetting.set(_targetScale);
+ _yawSpeedSetting.set(_yawSpeed);
+ _pitchSpeedSetting.set(_pitchSpeed);
// only save the fullAvatarURL if it has not been overwritten on command line
// (so the overrideURL is not valid), or it was overridden _and_ we specified
// --replaceAvatarURL (so _saveAvatarOverrideUrl is true)
if (qApp->getSaveAvatarOverrideUrl() || !qApp->getAvatarOverrideUrl().isValid() ) {
- settings.setValue("fullAvatarURL",
- _fullAvatarURLFromPreferences == AvatarData::defaultFullAvatarModelUrl() ?
- "" :
- _fullAvatarURLFromPreferences.toString());
+ _fullAvatarURLSetting.set(_fullAvatarURLFromPreferences == AvatarData::defaultFullAvatarModelUrl() ?
+ "" :
+ _fullAvatarURLFromPreferences.toString());
}
- settings.setValue("fullAvatarModelName", _fullAvatarModelName);
-
+ _fullAvatarModelNameSetting.set(_fullAvatarModelName);
QUrl animGraphUrl = _prefOverrideAnimGraphUrl.get();
- settings.setValue("animGraphURL", animGraphUrl);
+ _animGraphURLSetting.set(animGraphUrl);
+ _displayNameSetting.set(_displayName);
+ _collisionSoundURLSetting.set(_collisionSoundURL);
+ _useSnapTurnSetting.set(_useSnapTurn);
+ _userHeightSetting.set(getUserHeight());
+ _flyingHMDSetting.set(getFlyingHMDPref());
- settings.beginWriteArray("attachmentData");
- for (int i = 0; i < _attachmentData.size(); i++) {
- settings.setArrayIndex(i);
- const AttachmentData& attachment = _attachmentData.at(i);
- settings.setValue("modelURL", attachment.modelURL);
- settings.setValue("jointName", attachment.jointName);
- settings.setValue("translation_x", attachment.translation.x);
- settings.setValue("translation_y", attachment.translation.y);
- settings.setValue("translation_z", attachment.translation.z);
- glm::vec3 eulers = safeEulerAngles(attachment.rotation);
- settings.setValue("rotation_x", eulers.x);
- settings.setValue("rotation_y", eulers.y);
- settings.setValue("rotation_z", eulers.z);
- settings.setValue("scale", attachment.scale);
- settings.setValue("isSoft", attachment.isSoft);
- }
- settings.endArray();
-
- settings.remove("avatarEntityData");
- settings.beginWriteArray("avatarEntityData");
- int avatarEntityIndex = 0;
auto hmdInterface = DependencyManager::get();
_avatarEntitiesLock.withReadLock([&] {
- for (auto entityID : _avatarEntityData.keys()) {
- if (hmdInterface->getCurrentTabletFrameID() == entityID) {
- // don't persist the tablet between domains / sessions
- continue;
- }
+ QList avatarEntityIDs = _avatarEntityData.keys();
+ unsigned int avatarEntityCount = avatarEntityIDs.size();
+ unsigned int previousAvatarEntityCount = _avatarEntityCountSetting.get(0);
+ resizeAvatarEntitySettingHandles(std::max(avatarEntityCount, previousAvatarEntityCount));
+ _avatarEntityCountSetting.set(avatarEntityCount);
- settings.setArrayIndex(avatarEntityIndex);
- settings.setValue("id", entityID);
- settings.setValue("properties", _avatarEntityData.value(entityID));
+ unsigned int avatarEntityIndex = 0;
+ for (auto entityID : avatarEntityIDs) {
+ _avatarEntityIDSettings[avatarEntityIndex].set(entityID);
+ _avatarEntityDataSettings[avatarEntityIndex].set(_avatarEntityData.value(entityID));
avatarEntityIndex++;
}
+
+ // clean up any left-over (due to the list shrinking) slots
+ for (; avatarEntityIndex < previousAvatarEntityCount; avatarEntityIndex++) {
+ _avatarEntityIDSettings[avatarEntityIndex].remove();
+ _avatarEntityDataSettings[avatarEntityIndex].remove();
+ }
});
- settings.endArray();
-
- settings.setValue("displayName", _displayName);
- settings.setValue("collisionSoundURL", _collisionSoundURL);
- settings.setValue("useSnapTurn", _useSnapTurn);
- settings.setValue("userHeight", getUserHeight());
- settings.setValue("flyingHMD", getFlyingHMDPref());
-
- settings.endGroup();
}
float loadSetting(Settings& settings, const QString& name, float defaultValue) {
@@ -1314,66 +1323,36 @@ void MyAvatar::setEnableInverseKinematics(bool isEnabled) {
}
void MyAvatar::loadData() {
- Settings settings;
- settings.beginGroup("Avatar");
+ getHead()->setBasePitch(_headPitchSetting.get());
- getHead()->setBasePitch(loadSetting(settings, "headPitch", 0.0f));
+ _yawSpeed = _yawSpeedSetting.get(_yawSpeed);
+ _pitchSpeed = _pitchSpeedSetting.get(_pitchSpeed);
- _yawSpeed = loadSetting(settings, "yawSpeed", _yawSpeed);
- _pitchSpeed = loadSetting(settings, "pitchSpeed", _pitchSpeed);
-
- _prefOverrideAnimGraphUrl.set(QUrl(settings.value("animGraphURL", "").toString()));
- _fullAvatarURLFromPreferences = settings.value("fullAvatarURL", AvatarData::defaultFullAvatarModelUrl()).toUrl();
- _fullAvatarModelName = settings.value("fullAvatarModelName", DEFAULT_FULL_AVATAR_MODEL_NAME).toString();
+ _prefOverrideAnimGraphUrl.set(_prefOverrideAnimGraphUrl.get().toString());
+ _fullAvatarURLFromPreferences = _fullAvatarURLSetting.get(QUrl(AvatarData::defaultFullAvatarModelUrl()));
+ _fullAvatarModelName = _fullAvatarModelNameSetting.get(DEFAULT_FULL_AVATAR_MODEL_NAME).toString();
useFullAvatarURL(_fullAvatarURLFromPreferences, _fullAvatarModelName);
- int attachmentCount = settings.beginReadArray("attachmentData");
- for (int i = 0; i < attachmentCount; i++) {
- settings.setArrayIndex(i);
- AttachmentData attachment;
- attachment.modelURL = settings.value("modelURL").toUrl();
- attachment.jointName = settings.value("jointName").toString();
- attachment.translation.x = loadSetting(settings, "translation_x", 0.0f);
- attachment.translation.y = loadSetting(settings, "translation_y", 0.0f);
- attachment.translation.z = loadSetting(settings, "translation_z", 0.0f);
- glm::vec3 eulers;
- eulers.x = loadSetting(settings, "rotation_x", 0.0f);
- eulers.y = loadSetting(settings, "rotation_y", 0.0f);
- eulers.z = loadSetting(settings, "rotation_z", 0.0f);
- attachment.rotation = glm::quat(eulers);
- attachment.scale = loadSetting(settings, "scale", 1.0f);
- attachment.isSoft = settings.value("isSoft").toBool();
- // old attachments are stored and loaded/converted later when rig is ready
- _oldAttachmentData.append(attachment);
- }
- settings.endArray();
-
- int avatarEntityCount = settings.beginReadArray("avatarEntityData");
+ int avatarEntityCount = _avatarEntityCountSetting.get(0);
for (int i = 0; i < avatarEntityCount; i++) {
- settings.setArrayIndex(i);
- QUuid entityID = settings.value("id").toUuid();
+ resizeAvatarEntitySettingHandles(i);
// QUuid entityID = QUuid::createUuid(); // generate a new ID
- QByteArray properties = settings.value("properties").toByteArray();
+ QUuid entityID = _avatarEntityIDSettings[i].get(QUuid());
+ QByteArray properties = _avatarEntityDataSettings[i].get();
updateAvatarEntity(entityID, properties);
}
- settings.endArray();
- if (avatarEntityCount == 0) {
- // HACK: manually remove empty 'avatarEntityData' else legacy data may persist in settings file
- settings.remove("avatarEntityData");
- }
// Flying preferences must be loaded before calling setFlyingEnabled()
Setting::Handle firstRunVal { Settings::firstRun, true };
- setFlyingHMDPref(firstRunVal.get() ? false : settings.value("flyingHMD").toBool());
+ setFlyingHMDPref(firstRunVal.get() ? false : _flyingHMDSetting.get());
setFlyingEnabled(getFlyingEnabled());
- setDisplayName(settings.value("displayName").toString());
- setCollisionSoundURL(settings.value("collisionSoundURL", DEFAULT_AVATAR_COLLISION_SOUND_URL).toString());
- setSnapTurn(settings.value("useSnapTurn", _useSnapTurn).toBool());
- setDominantHand(settings.value("dominantHand", _dominantHand).toString().toLower());
- setUserHeight(settings.value("userHeight", DEFAULT_AVATAR_HEIGHT).toDouble());
- settings.endGroup();
+ setDisplayName(_displayNameSetting.get());
+ setCollisionSoundURL(_collisionSoundURLSetting.get(QUrl(DEFAULT_AVATAR_COLLISION_SOUND_URL)).toString());
+ setSnapTurn(_useSnapTurnSetting.get());
+ setDominantHand(_dominantHandSetting.get(DOMINANT_RIGHT_HAND).toLower());
+ setUserHeight(_userHeightSetting.get(DEFAULT_AVATAR_HEIGHT));
setEnableMeshVisible(Menu::getInstance()->isOptionChecked(MenuOption::MeshVisible));
_follow.setToggleHipsFollowing (Menu::getInstance()->isOptionChecked(MenuOption::ToggleHipsFollowing));
@@ -1442,6 +1421,7 @@ AttachmentData MyAvatar::loadAttachmentData(const QUrl& modelURL, const QString&
return attachment;
}
+
int MyAvatar::parseDataFromBuffer(const QByteArray& buffer) {
qCDebug(interfaceapp) << "Error: ignoring update packet for MyAvatar"
<< " packetLength = " << buffer.size();
@@ -2899,10 +2879,7 @@ void MyAvatar::restrictScaleFromDomainSettings(const QJsonObject& domainSettings
}
// Set avatar current scale
- Settings settings;
- settings.beginGroup("Avatar");
- _targetScale = loadSetting(settings, "scale", 1.0f);
-
+ _targetScale = _scaleSetting.get();
// clamp the desired _targetScale by the domain limits NOW, don't try to gracefully animate. Because
// this might cause our avatar to become embedded in the terrain.
_targetScale = getDomainLimitedScale();
@@ -2914,7 +2891,6 @@ void MyAvatar::restrictScaleFromDomainSettings(const QJsonObject& domainSettings
setModelScale(_targetScale);
rebuildCollisionShape();
- settings.endGroup();
_haveReceivedHeightLimitsFromDomain = true;
}
@@ -2925,10 +2901,7 @@ void MyAvatar::leaveDomain() {
}
void MyAvatar::saveAvatarScale() {
- Settings settings;
- settings.beginGroup("Avatar");
- settings.setValue("scale", _targetScale);
- settings.endGroup();
+ _scaleSetting.set(_targetScale);
}
void MyAvatar::clearScaleRestriction() {
diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h
index 139f1f6ea2..1dc0b3cd40 100644
--- a/interface/src/avatar/MyAvatar.h
+++ b/interface/src/avatar/MyAvatar.h
@@ -550,6 +550,7 @@ public:
float getHMDRollControlRate() const { return _hmdRollControlRate; }
// get/set avatar data
+ void resizeAvatarEntitySettingHandles(unsigned int avatarEntityIndex);
void saveData();
void loadData();
@@ -1806,6 +1807,23 @@ private:
bool _haveReceivedHeightLimitsFromDomain { false };
int _disableHandTouchCount { 0 };
+
+ Setting::Handle _dominantHandSetting;
+ Setting::Handle _headPitchSetting;
+ Setting::Handle _scaleSetting;
+ Setting::Handle _yawSpeedSetting;
+ Setting::Handle _pitchSpeedSetting;
+ Setting::Handle _fullAvatarURLSetting;
+ Setting::Handle _fullAvatarModelNameSetting;
+ Setting::Handle _animGraphURLSetting;
+ Setting::Handle _displayNameSetting;
+ Setting::Handle _collisionSoundURLSetting;
+ Setting::Handle _useSnapTurnSetting;
+ Setting::Handle _userHeightSetting;
+ Setting::Handle _flyingHMDSetting;
+ Setting::Handle _avatarEntityCountSetting;
+ std::vector> _avatarEntityIDSettings;
+ std::vector> _avatarEntityDataSettings;
};
QScriptValue audioListenModeToScriptValue(QScriptEngine* engine, const AudioListenerMode& audioListenerMode);
diff --git a/interface/src/scripting/WindowScriptingInterface.cpp b/interface/src/scripting/WindowScriptingInterface.cpp
index 543dfe4933..9785c0b69f 100644
--- a/interface/src/scripting/WindowScriptingInterface.cpp
+++ b/interface/src/scripting/WindowScriptingInterface.cpp
@@ -180,6 +180,14 @@ void WindowScriptingInterface::setPreviousBrowseAssetLocation(const QString& loc
Setting::Handle(LAST_BROWSE_ASSETS_LOCATION_SETTING).set(location);
}
+bool WindowScriptingInterface::getInterstitialModeEnabled() const {
+ return DependencyManager::get()->getDomainHandler().getInterstitialModeEnabled();
+}
+
+void WindowScriptingInterface::setInterstitialModeEnabled(bool enableInterstitialMode) {
+ DependencyManager::get()->getDomainHandler().setInterstitialModeEnabled(enableInterstitialMode);
+}
+
bool WindowScriptingInterface::isPointOnDesktopWindow(QVariant point) {
auto offscreenUi = DependencyManager::get();
return offscreenUi->isPointOnDesktopWindow(point);
diff --git a/interface/src/scripting/WindowScriptingInterface.h b/interface/src/scripting/WindowScriptingInterface.h
index bf93e73ea9..264aa29743 100644
--- a/interface/src/scripting/WindowScriptingInterface.h
+++ b/interface/src/scripting/WindowScriptingInterface.h
@@ -49,6 +49,7 @@ class WindowScriptingInterface : public QObject, public Dependency {
Q_PROPERTY(int innerHeight READ getInnerHeight)
Q_PROPERTY(int x READ getX)
Q_PROPERTY(int y READ getY)
+ Q_PROPERTY(bool interstitialModeEnabled READ getInterstitialModeEnabled WRITE setInterstitialModeEnabled)
public:
WindowScriptingInterface();
@@ -760,6 +761,9 @@ private:
QString getPreviousBrowseAssetLocation() const;
void setPreviousBrowseAssetLocation(const QString& location);
+ bool getInterstitialModeEnabled() const;
+ void setInterstitialModeEnabled(bool enableInterstitialMode);
+
void ensureReticleVisible() const;
int createMessageBox(QString title, QString text, int buttons, int defaultButton);
diff --git a/interface/src/ui/AnimStats.cpp b/interface/src/ui/AnimStats.cpp
index 7b4778e365..e3579fa2dc 100644
--- a/interface/src/ui/AnimStats.cpp
+++ b/interface/src/ui/AnimStats.cpp
@@ -42,6 +42,29 @@ void AnimStats::updateStats(bool force) {
auto myAvatar = avatarManager->getMyAvatar();
auto debugAlphaMap = myAvatar->getSkeletonModel()->getRig().getDebugAlphaMap();
+ glm::vec3 position = myAvatar->getWorldPosition();
+ glm::quat rotation = myAvatar->getWorldOrientation();
+ glm::vec3 velocity = myAvatar->getWorldVelocity();
+
+ _positionText = QString("Position: (%1, %2, %3)").
+ arg(QString::number(position.x, 'f', 2)).
+ arg(QString::number(position.y, 'f', 2)).
+ arg(QString::number(position.z, 'f', 2));
+ emit positionTextChanged();
+
+ glm::vec3 eulerRotation = safeEulerAngles(rotation);
+ _rotationText = QString("Heading: %1").
+ arg(QString::number(glm::degrees(eulerRotation.y), 'f', 2));
+ emit rotationTextChanged();
+
+ // transform velocity into rig coordinate frame. z forward.
+ glm::vec3 localVelocity = Quaternions::Y_180 * glm::inverse(rotation) * velocity;
+ _velocityText = QString("Local Vel: (%1, %2, %3)").
+ arg(QString::number(localVelocity.x, 'f', 2)).
+ arg(QString::number(localVelocity.y, 'f', 2)).
+ arg(QString::number(localVelocity.z, 'f', 2));
+ emit velocityTextChanged();
+
// update animation debug alpha values
QStringList newAnimAlphaValues;
qint64 now = usecTimestampNow();
diff --git a/interface/src/ui/AnimStats.h b/interface/src/ui/AnimStats.h
index 1a6795b498..7b6aaf7b54 100644
--- a/interface/src/ui/AnimStats.h
+++ b/interface/src/ui/AnimStats.h
@@ -19,6 +19,9 @@ class AnimStats : public QQuickItem {
Q_PROPERTY(QStringList animAlphaValues READ animAlphaValues NOTIFY animAlphaValuesChanged)
Q_PROPERTY(QStringList animVars READ animVars NOTIFY animVarsChanged)
Q_PROPERTY(QStringList animStateMachines READ animStateMachines NOTIFY animStateMachinesChanged)
+ Q_PROPERTY(QString positionText READ positionText NOTIFY positionTextChanged)
+ Q_PROPERTY(QString rotationText READ rotationText NOTIFY rotationTextChanged)
+ Q_PROPERTY(QString velocityText READ velocityText NOTIFY velocityTextChanged)
public:
static AnimStats* getInstance();
@@ -27,9 +30,13 @@ public:
void updateStats(bool force = false);
- QStringList animAlphaValues() { return _animAlphaValues; }
- QStringList animVars() { return _animVarsList; }
- QStringList animStateMachines() { return _animStateMachines; }
+ QStringList animAlphaValues() const { return _animAlphaValues; }
+ QStringList animVars() const { return _animVarsList; }
+ QStringList animStateMachines() const { return _animStateMachines; }
+
+ QString positionText() const { return _positionText; }
+ QString rotationText() const { return _rotationText; }
+ QString velocityText() const { return _velocityText; }
public slots:
void forceUpdateStats() { updateStats(true); }
@@ -39,6 +46,9 @@ signals:
void animAlphaValuesChanged();
void animVarsChanged();
void animStateMachinesChanged();
+ void positionTextChanged();
+ void rotationTextChanged();
+ void velocityTextChanged();
private:
QStringList _animAlphaValues;
@@ -50,6 +60,10 @@ private:
std::map _animVarChangedTimers; // last time animVar value has changed.
QStringList _animStateMachines;
+
+ QString _positionText;
+ QString _rotationText;
+ QString _velocityText;
};
#endif // hifi_AnimStats_h
diff --git a/libraries/animation/src/AnimStateMachine.cpp b/libraries/animation/src/AnimStateMachine.cpp
index 7f46cd614a..fb13b8e71c 100644
--- a/libraries/animation/src/AnimStateMachine.cpp
+++ b/libraries/animation/src/AnimStateMachine.cpp
@@ -88,6 +88,10 @@ const AnimPoseVec& AnimStateMachine::evaluate(const AnimVariantMap& animVars, co
processOutputJoints(triggersOut);
context.addStateMachineInfo(_id, _currentState->getID(), _previousState->getID(), _duringInterp, _alpha);
+ if (_duringInterp) {
+ // hack: add previoius state to debug alpha map, with parens around it's name.
+ context.setDebugAlpha(QString("(%1)").arg(_previousState->getID()), 1.0f - _alpha, AnimNodeType::Clip);
+ }
return _poses;
}
diff --git a/libraries/animation/src/AnimVariant.cpp b/libraries/animation/src/AnimVariant.cpp
index 509462984a..21fe234f7b 100644
--- a/libraries/animation/src/AnimVariant.cpp
+++ b/libraries/animation/src/AnimVariant.cpp
@@ -140,14 +140,19 @@ std::map AnimVariantMap::toDebugMap() const {
result[pair.first] = QString::number(pair.second.getFloat(), 'f', 3);
break;
case AnimVariant::Type::Vec3: {
+ // To prevent filling up debug stats, don't show vec3 values
+ /*
glm::vec3 value = pair.second.getVec3();
result[pair.first] = QString("(%1, %2, %3)").
arg(QString::number(value.x, 'f', 3)).
arg(QString::number(value.y, 'f', 3)).
arg(QString::number(value.z, 'f', 3));
+ */
break;
}
case AnimVariant::Type::Quat: {
+ // To prevent filling up the anim stats, don't show quat values
+ /*
glm::quat value = pair.second.getQuat();
result[pair.first] = QString("(%1, %2, %3, %4)").
arg(QString::number(value.x, 'f', 3)).
@@ -155,10 +160,14 @@ std::map AnimVariantMap::toDebugMap() const {
arg(QString::number(value.z, 'f', 3)).
arg(QString::number(value.w, 'f', 3));
break;
+ */
}
case AnimVariant::Type::String:
+ // To prevent filling up anim stats, don't show string values
+ /*
result[pair.first] = pair.second.getString();
break;
+ */
default:
assert(("invalid AnimVariant::Type", false));
}
diff --git a/libraries/audio-client/src/AudioClient.cpp b/libraries/audio-client/src/AudioClient.cpp
index 3a33eccc8a..d00bc29054 100644
--- a/libraries/audio-client/src/AudioClient.cpp
+++ b/libraries/audio-client/src/AudioClient.cpp
@@ -53,7 +53,6 @@
#include "AudioHelpers.h"
#if defined(Q_OS_ANDROID)
-#define VOICE_RECOGNITION "voicerecognition"
#include
#endif
@@ -101,6 +100,13 @@ QList getAvailableDevices(QAudio::Mode mode) {
// now called from a background thread, to keep blocking operations off the audio thread
void AudioClient::checkDevices() {
+ // Make sure we're not shutting down
+ Lock timerMutex(_checkDevicesMutex);
+ // If we HAVE shut down after we were queued, but prior to execution, early exit
+ if (nullptr == _checkDevicesTimer) {
+ return;
+ }
+
auto inputDevices = getAvailableDevices(QAudio::AudioInput);
auto outputDevices = getAvailableDevices(QAudio::AudioOutput);
@@ -210,6 +216,7 @@ AudioClient::AudioClient() :
_positionGetter(DEFAULT_POSITION_GETTER),
#if defined(Q_OS_ANDROID)
_checkInputTimer(this),
+ _isHeadsetPluggedIn(false),
#endif
_orientationGetter(DEFAULT_ORIENTATION_GETTER) {
// avoid putting a lock in the device callback
@@ -278,9 +285,6 @@ void AudioClient::customDeleter() {
_shouldRestartInputSetup = false;
#endif
stop();
- _checkDevicesTimer->stop();
- _checkPeakValuesTimer->stop();
-
deleteLater();
}
@@ -461,9 +465,14 @@ QAudioDeviceInfo defaultAudioDeviceForMode(QAudio::Mode mode) {
#if defined (Q_OS_ANDROID)
if (mode == QAudio::AudioInput) {
+ Setting::Handle enableAEC(SETTING_AEC_KEY, false);
+ bool aecEnabled = enableAEC.get();
+ auto audioClient = DependencyManager::get();
+ bool headsetOn = audioClient? audioClient->isHeadsetPluggedIn() : false;
auto inputDevices = QAudioDeviceInfo::availableDevices(QAudio::AudioInput);
for (auto inputDevice : inputDevices) {
- if (inputDevice.deviceName() == VOICE_RECOGNITION) {
+ if (((headsetOn || !aecEnabled) && inputDevice.deviceName() == VOICE_RECOGNITION) ||
+ ((!headsetOn && aecEnabled) && inputDevice.deviceName() == VOICE_COMMUNICATION)) {
return inputDevice;
}
}
@@ -648,12 +657,26 @@ void AudioClient::start() {
}
void AudioClient::stop() {
-
qCDebug(audioclient) << "AudioClient::stop(), requesting switchInputToAudioDevice() to shut down";
switchInputToAudioDevice(QAudioDeviceInfo(), true);
qCDebug(audioclient) << "AudioClient::stop(), requesting switchOutputToAudioDevice() to shut down";
switchOutputToAudioDevice(QAudioDeviceInfo(), true);
+
+ // Stop triggering the checks
+ QObject::disconnect(_checkPeakValuesTimer, &QTimer::timeout, nullptr, nullptr);
+ QObject::disconnect(_checkDevicesTimer, &QTimer::timeout, nullptr, nullptr);
+
+ // Destruction of the pointers will occur when the parent object (this) is destroyed)
+ {
+ Lock lock(_checkDevicesMutex);
+ _checkDevicesTimer = nullptr;
+ }
+ {
+ Lock lock(_checkPeakValuesMutex);
+ _checkPeakValuesTimer = nullptr;
+ }
+
#if defined(Q_OS_ANDROID)
_checkInputTimer.stop();
disconnect(&_checkInputTimer, &QTimer::timeout, 0, 0);
@@ -1640,6 +1663,29 @@ void AudioClient::checkInputTimeout() {
#endif
}
+void AudioClient::setHeadsetPluggedIn(bool pluggedIn) {
+#if defined(Q_OS_ANDROID)
+ if (pluggedIn == !_isHeadsetPluggedIn && !_inputDeviceInfo.isNull()) {
+ QAndroidJniObject brand = QAndroidJniObject::getStaticObjectField("android/os/Build", "BRAND");
+ // some samsung phones needs more time to shutdown the previous input device
+ if (brand.toString().contains("samsung", Qt::CaseInsensitive)) {
+ switchInputToAudioDevice(QAudioDeviceInfo(), true);
+ QThread::msleep(200);
+ }
+
+ Setting::Handle enableAEC(SETTING_AEC_KEY, false);
+ bool aecEnabled = enableAEC.get();
+
+ if ((pluggedIn || !aecEnabled) && _inputDeviceInfo.deviceName() != VOICE_RECOGNITION) {
+ switchAudioDevice(QAudio::AudioInput, VOICE_RECOGNITION);
+ } else if (!pluggedIn && aecEnabled && _inputDeviceInfo.deviceName() != VOICE_COMMUNICATION) {
+ switchAudioDevice(QAudio::AudioInput, VOICE_COMMUNICATION);
+ }
+ }
+ _isHeadsetPluggedIn = pluggedIn;
+#endif
+}
+
void AudioClient::outputNotify() {
int recentUnfulfilled = _audioOutputIODevice.getRecentUnfulfilledReads();
if (recentUnfulfilled > 0) {
diff --git a/libraries/audio-client/src/AudioClient.h b/libraries/audio-client/src/AudioClient.h
index 4640d7c045..5e7f1fb8a0 100644
--- a/libraries/audio-client/src/AudioClient.h
+++ b/libraries/audio-client/src/AudioClient.h
@@ -64,6 +64,13 @@
#pragma warning( pop )
#endif
+#if defined (Q_OS_ANDROID)
+#define VOICE_RECOGNITION "voicerecognition"
+#define VOICE_COMMUNICATION "voicecommunication"
+
+#define SETTING_AEC_KEY "Android/aec"
+#endif
+
class QAudioInput;
class QAudioOutput;
class QIODevice;
@@ -169,6 +176,10 @@ public:
static QString getWinDeviceName(wchar_t* guid);
#endif
+#if defined(Q_OS_ANDROID)
+ bool isHeadsetPluggedIn() { return _isHeadsetPluggedIn; }
+#endif
+
public slots:
void start();
void stop();
@@ -217,6 +228,9 @@ public slots:
bool switchAudioDevice(QAudio::Mode mode, const QAudioDeviceInfo& deviceInfo = QAudioDeviceInfo());
bool switchAudioDevice(QAudio::Mode mode, const QString& deviceName);
+ // Qt opensles plugin is not able to detect when the headset is plugged in
+ void setHeadsetPluggedIn(bool pluggedIn);
+
float getInputVolume() const { return (_audioInput) ? (float)_audioInput->volume() : 0.0f; }
void setInputVolume(float volume, bool emitSignal = true);
void setReverb(bool reverb);
@@ -278,6 +292,7 @@ private:
#ifdef Q_OS_ANDROID
QTimer _checkInputTimer;
long _inputReadsSinceLastCheck = 0l;
+ bool _isHeadsetPluggedIn;
#endif
class Gate {
@@ -432,7 +447,9 @@ private:
bool _shouldRestartInputSetup { true }; // Should we restart the input device because of an unintended stop?
#endif
+ Mutex _checkDevicesMutex;
QTimer* _checkDevicesTimer { nullptr };
+ Mutex _checkPeakValuesMutex;
QTimer* _checkPeakValuesTimer { nullptr };
bool _isRecording { false };
diff --git a/libraries/audio-client/src/AudioPeakValues.cpp b/libraries/audio-client/src/AudioPeakValues.cpp
index 0b8921a117..a50567da7f 100644
--- a/libraries/audio-client/src/AudioPeakValues.cpp
+++ b/libraries/audio-client/src/AudioPeakValues.cpp
@@ -40,6 +40,12 @@ void release(IAudioClient* audioClient) {
}
void AudioClient::checkPeakValues() {
+ // Guard against running during shutdown
+ Lock timerMutex(_checkPeakValuesMutex);
+ if (nullptr == _checkPeakValuesTimer) {
+ return;
+ }
+
// prepare the windows environment
CoInitialize(NULL);
diff --git a/libraries/audio/src/Sound.cpp b/libraries/audio/src/Sound.cpp
index 67f9952771..da284f19a3 100644
--- a/libraries/audio/src/Sound.cpp
+++ b/libraries/audio/src/Sound.cpp
@@ -43,8 +43,11 @@ void soundSharedPointerFromScriptValue(const QScriptValue& object, SharedSoundPo
}
}
-SoundScriptingInterface::SoundScriptingInterface(SharedSoundPointer sound) : _sound(sound) {
- QObject::connect(sound.data(), &Sound::ready, this, &SoundScriptingInterface::ready);
+SoundScriptingInterface::SoundScriptingInterface(const SharedSoundPointer& sound) : _sound(sound) {
+ // During shutdown we can sometimes get an empty sound pointer back
+ if (_sound) {
+ QObject::connect(_sound.data(), &Sound::ready, this, &SoundScriptingInterface::ready);
+ }
}
Sound::Sound(const QUrl& url, bool isStereo, bool isAmbisonic) :
diff --git a/libraries/audio/src/Sound.h b/libraries/audio/src/Sound.h
index 348600e4ae..a0544870d0 100644
--- a/libraries/audio/src/Sound.h
+++ b/libraries/audio/src/Sound.h
@@ -105,11 +105,11 @@ class SoundScriptingInterface : public QObject {
Q_PROPERTY(float duration READ getDuration)
public:
- SoundScriptingInterface(SharedSoundPointer sound);
- SharedSoundPointer getSound() { return _sound; }
+ SoundScriptingInterface(const SharedSoundPointer& sound);
+ const SharedSoundPointer& getSound() { return _sound; }
- bool isReady() const { return _sound->isReady(); }
- float getDuration() { return _sound->getDuration(); }
+ bool isReady() const { return _sound ? _sound->isReady() : false; }
+ float getDuration() { return _sound ? _sound->getDuration() : 0.0f; }
/**jsdoc
* Triggered when the sound has been downloaded and is ready to be played.
diff --git a/libraries/entities/src/EntityScriptingInterface.cpp b/libraries/entities/src/EntityScriptingInterface.cpp
index d9924cb9fd..8f0fde5c9a 100644
--- a/libraries/entities/src/EntityScriptingInterface.cpp
+++ b/libraries/entities/src/EntityScriptingInterface.cpp
@@ -132,8 +132,8 @@ EntityItemProperties convertPropertiesToScriptSemantics(const EntityItemProperti
EntityItemProperties scriptSideProperties = entitySideProperties;
scriptSideProperties.setLocalPosition(entitySideProperties.getPosition());
scriptSideProperties.setLocalRotation(entitySideProperties.getRotation());
- scriptSideProperties.setLocalVelocity(entitySideProperties.getLocalVelocity());
- scriptSideProperties.setLocalAngularVelocity(entitySideProperties.getLocalAngularVelocity());
+ scriptSideProperties.setLocalVelocity(entitySideProperties.getVelocity());
+ scriptSideProperties.setLocalAngularVelocity(entitySideProperties.getAngularVelocity());
scriptSideProperties.setLocalDimensions(entitySideProperties.getDimensions());
bool success;
@@ -181,8 +181,6 @@ EntityItemProperties convertPropertiesFromScriptSemantics(const EntityItemProper
EntityItemProperties entitySideProperties = scriptSideProperties;
bool success;
- // TODO -- handle velocity and angularVelocity
-
if (scriptSideProperties.localPositionChanged()) {
entitySideProperties.setPosition(scriptSideProperties.getLocalPosition());
} else if (scriptSideProperties.positionChanged()) {
diff --git a/libraries/networking/src/AddressManager.h b/libraries/networking/src/AddressManager.h
index c7cdf8f4ea..17041a5fd7 100644
--- a/libraries/networking/src/AddressManager.h
+++ b/libraries/networking/src/AddressManager.h
@@ -140,8 +140,7 @@ public:
*
* @typedef {number} location.LookupTrigger
*/
- enum LookupTrigger
- {
+ enum LookupTrigger {
UserInput,
Back,
Forward,
@@ -207,9 +206,8 @@ public slots:
// functions and signals that should be exposed are moved to a scripting interface class.
//
// we currently expect this to be called from NodeList once handleLookupString has been called with a path
- bool goToViewpointForPath(const QString& viewpointString, const QString& pathString) {
- return handleViewpoint(viewpointString, false, DomainPathResponse, false, pathString);
- }
+ bool goToViewpointForPath(const QString& viewpointString, const QString& pathString)
+ { return handleViewpoint(viewpointString, false, DomainPathResponse, false, pathString); }
/**jsdoc
* Go back to the previous location in your navigation history, if there is one.
@@ -231,8 +229,7 @@ public slots:
* location history is correctly maintained.
*/
void goToLocalSandbox(QString path = "", LookupTrigger trigger = LookupTrigger::StartupFromSettings) {
- handleUrl(SANDBOX_HIFI_ADDRESS + path, trigger);
- }
+ handleUrl(SANDBOX_HIFI_ADDRESS + path, trigger); }
/**jsdoc
* Go to the default "welcome" metaverse address.
@@ -364,8 +361,7 @@ signals:
* location.locationChangeRequired.connect(onLocationChangeRequired);
*/
void locationChangeRequired(const glm::vec3& newPosition,
- bool hasOrientationChange,
- const glm::quat& newOrientation,
+ bool hasOrientationChange, const glm::quat& newOrientation,
bool shouldFaceLocation);
/**jsdoc
@@ -448,11 +444,8 @@ private:
bool handleNetworkAddress(const QString& lookupString, LookupTrigger trigger, bool& hostChanged);
void handlePath(const QString& path, LookupTrigger trigger, bool wasPathOnly = false);
- bool handleViewpoint(const QString& viewpointString,
- bool shouldFace,
- LookupTrigger trigger,
- bool definitelyPathOnly = false,
- const QString& pathString = QString());
+ bool handleViewpoint(const QString& viewpointString, bool shouldFace, LookupTrigger trigger,
+ bool definitelyPathOnly = false, const QString& pathString = QString());
bool handleUsername(const QString& lookupString);
bool handleDomainID(const QString& host);
diff --git a/libraries/networking/src/DomainHandler.cpp b/libraries/networking/src/DomainHandler.cpp
index f34a93de96..df34a1fb59 100644
--- a/libraries/networking/src/DomainHandler.cpp
+++ b/libraries/networking/src/DomainHandler.cpp
@@ -15,6 +15,10 @@
#include
+#include
+
+#include
+
#include
#include
@@ -134,6 +138,18 @@ void DomainHandler::hardReset() {
_pendingPath.clear();
}
+bool DomainHandler::getInterstitialModeEnabled() const {
+ return _interstitialModeSettingLock.resultWithReadLock([&] {
+ return _enableInterstitialMode.get();
+ });
+}
+
+void DomainHandler::setInterstitialModeEnabled(bool enableInterstitialMode) {
+ _interstitialModeSettingLock.withWriteLock([&] {
+ _enableInterstitialMode.set(enableInterstitialMode);
+ });
+}
+
void DomainHandler::setErrorDomainURL(const QUrl& url) {
_errorDomainURL = url;
return;
@@ -340,11 +356,15 @@ void DomainHandler::loadedErrorDomain(std::map namedPaths) {
DependencyManager::get()->goToViewpointForPath(viewpoint, QString());
}
-void DomainHandler::setRedirectErrorState(QUrl errorUrl, int reasonCode) {
- _errorDomainURL = errorUrl;
+void DomainHandler::setRedirectErrorState(QUrl errorUrl, QString reasonMessage, int reasonCode, const QString& extraInfo) {
_lastDomainConnectionError = reasonCode;
- _isInErrorState = true;
- emit redirectToErrorDomainURL(_errorDomainURL);
+ if (getInterstitialModeEnabled()) {
+ _errorDomainURL = errorUrl;
+ _isInErrorState = true;
+ emit redirectToErrorDomainURL(_errorDomainURL);
+ } else {
+ emit domainConnectionRefused(reasonMessage, reasonCode, extraInfo);
+ }
}
void DomainHandler::requestDomainSettings() {
@@ -485,13 +505,9 @@ void DomainHandler::processDomainServerConnectionDeniedPacket(QSharedPointer
#include
+#include
+#include
+
#include "HifiSockAddr.h"
#include "NetworkPeer.h"
#include "NLPacket.h"
@@ -83,6 +86,8 @@ public:
bool isConnected() const { return _isConnected; }
void setIsConnected(bool isConnected);
bool isServerless() const { return _domainURL.scheme() != URL_SCHEME_HIFI; }
+ bool getInterstitialModeEnabled() const;
+ void setInterstitialModeEnabled(bool enableInterstitialMode);
void connectedToServerless(std::map namedPaths);
@@ -171,7 +176,7 @@ public slots:
void processDomainServerConnectionDeniedPacket(QSharedPointer message);
// sets domain handler in error state.
- void setRedirectErrorState(QUrl errorUrl, int reasonCode);
+ void setRedirectErrorState(QUrl errorUrl, QString reasonMessage = "", int reason = -1, const QString& extraInfo = "");
bool isInErrorState() { return _isInErrorState; }
@@ -224,6 +229,8 @@ private:
QJsonObject _settingsObject;
QString _pendingPath;
QTimer _settingsTimer;
+ mutable ReadWriteLockable _interstitialModeSettingLock;
+ Setting::Handle _enableInterstitialMode{ "enableInterstitialMode", false };
QSet _domainConnectionRefusals;
bool _hasCheckedForAccessToken { false };
diff --git a/libraries/render-utils/src/HighlightEffect.cpp b/libraries/render-utils/src/HighlightEffect.cpp
index 11326b1120..bcac31dd5a 100644
--- a/libraries/render-utils/src/HighlightEffect.cpp
+++ b/libraries/render-utils/src/HighlightEffect.cpp
@@ -37,6 +37,8 @@ namespace gr {
#define OUTLINE_STENCIL_MASK 1
+extern void initZPassPipelines(ShapePlumber& plumber, gpu::StatePointer state);
+
HighlightRessources::HighlightRessources() {
}
@@ -180,6 +182,7 @@ void DrawHighlightMask::run(const render::RenderContextPointer& renderContext, c
auto maskPipeline = _shapePlumber->pickPipeline(args, defaultKeyBuilder);
auto maskSkinnedPipeline = _shapePlumber->pickPipeline(args, defaultKeyBuilder.withSkinned());
+ auto maskSkinnedDQPipeline = _shapePlumber->pickPipeline(args, defaultKeyBuilder.withSkinned().withDualQuatSkinned());
// Setup camera, projection and viewport for all items
batch.setViewportTransform(args->_viewport);
@@ -187,14 +190,17 @@ void DrawHighlightMask::run(const render::RenderContextPointer& renderContext, c
batch.setProjectionJitter(jitter.x, jitter.y);
batch.setViewTransform(viewMat);
- std::vector skinnedShapeKeys{};
+ std::vector skinnedShapeKeys;
+ std::vector skinnedDQShapeKeys;
// Iterate through all inShapes and render the unskinned
args->_shapePipeline = maskPipeline;
batch.setPipeline(maskPipeline->pipeline);
for (const auto& items : inShapes) {
itemBounds.insert(itemBounds.end(), items.second.begin(), items.second.end());
- if (items.first.isSkinned()) {
+ if (items.first.isSkinned() && items.first.isDualQuatSkinned()) {
+ skinnedDQShapeKeys.push_back(items.first);
+ } else if (items.first.isSkinned()) {
skinnedShapeKeys.push_back(items.first);
} else {
renderItems(renderContext, items.second);
@@ -202,10 +208,21 @@ void DrawHighlightMask::run(const render::RenderContextPointer& renderContext, c
}
// Reiterate to render the skinned
- args->_shapePipeline = maskSkinnedPipeline;
- batch.setPipeline(maskSkinnedPipeline->pipeline);
- for (const auto& key : skinnedShapeKeys) {
- renderItems(renderContext, inShapes.at(key));
+ if (skinnedShapeKeys.size() > 0) {
+ args->_shapePipeline = maskSkinnedPipeline;
+ batch.setPipeline(maskSkinnedPipeline->pipeline);
+ for (const auto& key : skinnedShapeKeys) {
+ renderItems(renderContext, inShapes.at(key));
+ }
+ }
+
+ // Reiterate to render the DQ skinned
+ if (skinnedDQShapeKeys.size() > 0) {
+ args->_shapePipeline = maskSkinnedDQPipeline;
+ batch.setPipeline(maskSkinnedDQPipeline->pipeline);
+ for (const auto& key : skinnedDQShapeKeys) {
+ renderItems(renderContext, inShapes.at(key));
+ }
}
args->_shapePipeline = nullptr;
@@ -488,7 +505,7 @@ void DrawHighlightTask::build(JobModel& task, const render::Varying& inputs, ren
state->setDepthTest(true, true, gpu::LESS_EQUAL);
state->setColorWriteMask(false, false, false, false);
- initMaskPipelines(*shapePlumber, state);
+ initZPassPipelines(*shapePlumber, state);
}
auto sharedParameters = std::make_shared();
@@ -548,16 +565,4 @@ const render::Varying DrawHighlightTask::addSelectItemJobs(JobModel& task, const
const auto selectedMetasAndOpaques = task.addJob("OpaqueSelection", selectMetaAndOpaqueInput);
const auto selectItemInput = SelectItems::Inputs(transparents, selectedMetasAndOpaques, selectionName).asVarying();
return task.addJob("TransparentSelection", selectItemInput);
-}
-
-void DrawHighlightTask::initMaskPipelines(render::ShapePlumber& shapePlumber, gpu::StatePointer state) {
- gpu::ShaderPointer modelProgram = gpu::Shader::createProgram(shader::render_utils::program::model_shadow);
- shapePlumber.addPipeline(
- ShapeKey::Filter::Builder().withoutSkinned(),
- modelProgram, state);
-
- gpu::ShaderPointer skinProgram = gpu::Shader::createProgram(shader::render_utils::program::skin_model_shadow);
- shapePlumber.addPipeline(
- ShapeKey::Filter::Builder().withSkinned(),
- skinProgram, state);
-}
+}
\ No newline at end of file
diff --git a/libraries/render-utils/src/HighlightEffect.h b/libraries/render-utils/src/HighlightEffect.h
index 64a97a549e..32668c1ab6 100644
--- a/libraries/render-utils/src/HighlightEffect.h
+++ b/libraries/render-utils/src/HighlightEffect.h
@@ -208,8 +208,6 @@ public:
void build(JobModel& task, const render::Varying& inputs, render::Varying& outputs);
private:
-
- static void initMaskPipelines(render::ShapePlumber& plumber, gpu::StatePointer state);
static const render::Varying addSelectItemJobs(JobModel& task, const render::Varying& selectionName, const RenderFetchCullSortTask::BucketList& items);
};
diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp
index b9ed43c339..ab6507b29c 100644
--- a/libraries/render-utils/src/Model.cpp
+++ b/libraries/render-utils/src/Model.cpp
@@ -1553,14 +1553,13 @@ void Model::setBlendedVertices(int blendNumber, const QVector& vertic
for (int i = 0; i < fbxGeometry.meshes.size(); i++) {
const FBXMesh& mesh = fbxGeometry.meshes.at(i);
auto meshNormalsAndTangents = _normalsAndTangents.find(i);
- if (mesh.blendshapes.isEmpty() || meshNormalsAndTangents == _normalsAndTangents.end()) {
+ const auto& buffer = _blendedVertexBuffers.find(i);
+ if (mesh.blendshapes.isEmpty() || meshNormalsAndTangents == _normalsAndTangents.end() || buffer == _blendedVertexBuffers.end()) {
continue;
}
const auto vertexCount = mesh.vertices.size();
const auto verticesSize = vertexCount * sizeof(glm::vec3);
- const auto& buffer = _blendedVertexBuffers.find(i);
- assert(buffer != _blendedVertexBuffers.end());
buffer->second->resize(mesh.vertices.size() * sizeof(glm::vec3) + meshNormalsAndTangents->second.size() * sizeof(NormalType));
buffer->second->setSubData(0, verticesSize, (gpu::Byte*) vertices.constData() + index * sizeof(glm::vec3));
buffer->second->setSubData(verticesSize, meshNormalsAndTangents->second.size() * sizeof(NormalType), (const gpu::Byte*) normalsAndTangents.data() + normalAndTangentIndex * sizeof(NormalType));
diff --git a/libraries/shared/src/SettingManager.cpp b/libraries/shared/src/SettingManager.cpp
index 2e0850255a..e5920b785e 100644
--- a/libraries/shared/src/SettingManager.cpp
+++ b/libraries/shared/src/SettingManager.cpp
@@ -52,7 +52,7 @@ namespace Setting {
if (_pendingChanges.contains(key) && _pendingChanges[key] != UNSET_VALUE) {
loadedValue = _pendingChanges[key];
} else {
- loadedValue = value(key);
+ loadedValue = _qSettings.value(key);
}
if (loadedValue.isValid()) {
handle->setVariant(loadedValue);
@@ -92,32 +92,115 @@ namespace Setting {
}
void Manager::saveAll() {
- bool forceSync = false;
withWriteLock([&] {
+ bool forceSync = false;
for (auto key : _pendingChanges.keys()) {
auto newValue = _pendingChanges[key];
- auto savedValue = value(key, UNSET_VALUE);
+ auto savedValue = _qSettings.value(key, UNSET_VALUE);
if (newValue == savedValue) {
continue;
}
+ forceSync = true;
if (newValue == UNSET_VALUE || !newValue.isValid()) {
- forceSync = true;
- remove(key);
+ _qSettings.remove(key);
} else {
- forceSync = true;
- setValue(key, newValue);
+ _qSettings.setValue(key, newValue);
}
}
_pendingChanges.clear();
- });
- if (forceSync) {
- sync();
- }
+ if (forceSync) {
+ _qSettings.sync();
+ }
+ });
// Restart timer
if (_saveTimer) {
_saveTimer->start();
}
}
+
+ QString Manager::fileName() const {
+ return resultWithReadLock([&] {
+ return _qSettings.fileName();
+ });
+ }
+
+ void Manager::remove(const QString &key) {
+ withWriteLock([&] {
+ _qSettings.remove(key);
+ });
+ }
+
+ QStringList Manager::childGroups() const {
+ return resultWithReadLock([&] {
+ return _qSettings.childGroups();
+ });
+ }
+
+ QStringList Manager::childKeys() const {
+ return resultWithReadLock([&] {
+ return _qSettings.childKeys();
+ });
+ }
+
+ QStringList Manager::allKeys() const {
+ return resultWithReadLock([&] {
+ return _qSettings.allKeys();
+ });
+ }
+
+ bool Manager::contains(const QString &key) const {
+ return resultWithReadLock([&] {
+ return _qSettings.contains(key);
+ });
+ }
+
+ int Manager::beginReadArray(const QString &prefix) {
+ return resultWithReadLock([&] {
+ return _qSettings.beginReadArray(prefix);
+ });
+ }
+
+ void Manager::beginGroup(const QString &prefix) {
+ withWriteLock([&] {
+ _qSettings.beginGroup(prefix);
+ });
+ }
+
+ void Manager::beginWriteArray(const QString &prefix, int size) {
+ withWriteLock([&] {
+ _qSettings.beginWriteArray(prefix, size);
+ });
+ }
+
+ void Manager::endArray() {
+ withWriteLock([&] {
+ _qSettings.endArray();
+ });
+ }
+
+ void Manager::endGroup() {
+ withWriteLock([&] {
+ _qSettings.endGroup();
+ });
+ }
+
+ void Manager::setArrayIndex(int i) {
+ withWriteLock([&] {
+ _qSettings.setArrayIndex(i);
+ });
+ }
+
+ void Manager::setValue(const QString &key, const QVariant &value) {
+ withWriteLock([&] {
+ _qSettings.setValue(key, value);
+ });
+ }
+
+ QVariant Manager::value(const QString &key, const QVariant &defaultValue) const {
+ return resultWithReadLock([&] {
+ return _qSettings.value(key, defaultValue);
+ });
+ }
}
diff --git a/libraries/shared/src/SettingManager.h b/libraries/shared/src/SettingManager.h
index 6696a1ecf4..49f3bece4b 100644
--- a/libraries/shared/src/SettingManager.h
+++ b/libraries/shared/src/SettingManager.h
@@ -23,12 +23,28 @@
namespace Setting {
class Interface;
- class Manager : public QSettings, public ReadWriteLockable, public Dependency {
+ class Manager : public QObject, public ReadWriteLockable, public Dependency {
Q_OBJECT
public:
void customDeleter() override;
+ // thread-safe proxies into QSettings
+ QString fileName() const;
+ void remove(const QString &key);
+ QStringList childGroups() const;
+ QStringList childKeys() const;
+ QStringList allKeys() const;
+ bool contains(const QString &key) const;
+ int beginReadArray(const QString &prefix);
+ void beginGroup(const QString &prefix);
+ void beginWriteArray(const QString &prefix, int size = -1);
+ void endArray();
+ void endGroup();
+ void setArrayIndex(int i);
+ void setValue(const QString &key, const QVariant &value);
+ QVariant value(const QString &key, const QVariant &defaultValue = QVariant()) const;
+
protected:
~Manager();
void registerHandle(Interface* handle);
@@ -52,6 +68,9 @@ namespace Setting {
friend class Interface;
friend void cleanupSettingsSaveThread();
friend void setupSettingsSaveThread();
+
+
+ QSettings _qSettings;
};
}
diff --git a/scripts/system/edit.js b/scripts/system/edit.js
index 88ae2852be..b1f01e1ea9 100644
--- a/scripts/system/edit.js
+++ b/scripts/system/edit.js
@@ -2134,9 +2134,7 @@ var PropertiesTool = function (opts) {
var onWebEventReceived = function(data) {
try {
data = JSON.parse(data);
- }
- catch(e) {
- print('Edit.js received web event that was not valid json.');
+ } catch(e) {
return;
}
var i, properties, dY, diff, newPosition;
diff --git a/scripts/system/html/js/entityList.js b/scripts/system/html/js/entityList.js
index 23de49b613..7cc5937536 100644
--- a/scripts/system/html/js/entityList.js
+++ b/scripts/system/html/js/entityList.js
@@ -164,7 +164,10 @@ function loaded() {
selectedEntities.forEach(function(entityID) {
if (selection.indexOf(entityID) === -1) {
- entitiesByID[entityID].el.className = '';
+ let entity = entitiesByID[entityID];
+ if (entity !== undefined) {
+ entity.el.className = '';
+ }
}
});
@@ -388,15 +391,18 @@ function loaded() {
let notFound = false;
selectedEntities.forEach(function(id) {
- entitiesByID[id].el.className = '';
+ let entity = entitiesByID[id];
+ if (entity !== undefined) {
+ entity.el.className = '';
+ }
});
selectedEntities = [];
for (let i = 0; i < selectedIDs.length; i++) {
let id = selectedIDs[i];
selectedEntities.push(id);
- if (id in entitiesByID) {
- let entity = entitiesByID[id];
+ let entity = entitiesByID[id];
+ if (entity !== undefined) {
entity.el.className = 'selected';
} else {
notFound = true;
diff --git a/scripts/system/libraries/entitySelectionTool.js b/scripts/system/libraries/entitySelectionTool.js
index 5bca58b1ac..1fc0f0611c 100644
--- a/scripts/system/libraries/entitySelectionTool.js
+++ b/scripts/system/libraries/entitySelectionTool.js
@@ -29,17 +29,6 @@ Script.include([
SelectionManager = (function() {
var that = {};
- /**
- * @description Removes known to be broken properties from a properties object
- * @param properties
- * @return properties
- */
- var fixRemoveBrokenProperties = function (properties) {
- // Reason: Entity property is always set to 0,0,0 which causes it to override angularVelocity (see MS17131)
- delete properties.localAngularVelocity;
- return properties;
- }
-
// FUNCTION: SUBSCRIBE TO UPDATE MESSAGES
function subscribeToUpdateMessages() {
Messages.subscribe("entityToolUpdates");
@@ -130,7 +119,7 @@ SelectionManager = (function() {
that.savedProperties = {};
for (var i = 0; i < that.selections.length; i++) {
var entityID = that.selections[i];
- that.savedProperties[entityID] = fixRemoveBrokenProperties(Entities.getEntityProperties(entityID));
+ that.savedProperties[entityID] = Entities.getEntityProperties(entityID);
}
};
@@ -258,7 +247,7 @@ SelectionManager = (function() {
var originalEntityID = entitiesToDuplicate[i];
var properties = that.savedProperties[originalEntityID];
if (properties === undefined) {
- properties = fixRemoveBrokenProperties(Entities.getEntityProperties(originalEntityID));
+ properties = Entities.getEntityProperties(originalEntityID);
}
if (!properties.locked && (!properties.clientOnly || properties.owningAvatarID === MyAvatar.sessionUUID)) {
if (nonDynamicEntityIsBeingGrabbedByAvatar(properties)) {
diff --git a/scripts/system/libraries/gridTool.js b/scripts/system/libraries/gridTool.js
index 3a114f23c7..6f62742e8f 100644
--- a/scripts/system/libraries/gridTool.js
+++ b/scripts/system/libraries/gridTool.js
@@ -267,7 +267,6 @@ GridTool = function(opts) {
try {
data = JSON.parse(data);
} catch (e) {
- print("gridTool.js: Error parsing JSON: " + e.name + " data " + data);
return;
}