diff --git a/android/app/build.gradle b/android/app/build.gradle
index d3463411b8..24c067b176 100644
--- a/android/app/build.gradle
+++ b/android/app/build.gradle
@@ -133,6 +133,10 @@ dependencies {
implementation 'com.android.support.constraint:constraint-layout:1.0.2'
implementation 'com.android.support:design:26.1.0'
+ compile 'com.android.support:support-v4:26.1.0'
+ compile 'com.android.support:appcompat-v7:26.1.0'
+ compile 'com.android.support:support-vector-drawable:26.1.0'
+
implementation 'com.android.support:appcompat-v7:26.1.0'
compile 'com.android.support:recyclerview-v7:26.1.0'
compile 'com.android.support:cardview-v7:26.1.0'
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..c858092f87 100644
--- a/android/app/src/main/cpp/native.cpp
+++ b/android/app/src/main/cpp/native.cpp
@@ -156,7 +156,7 @@ JNIEXPORT void Java_io_highfidelity_hifiinterface_InterfaceActivity_nativeOnCrea
JavaVM* jvm;
env->GetJavaVM(&jvm);
- QObject::connect(&AndroidHelper::instance(), &AndroidHelper::androidActivityRequested, [jvm](const QString& a, const bool backToScene, QList args) {
+ QObject::connect(&AndroidHelper::instance(), &AndroidHelper::androidActivityRequested, [jvm](const QString& a, const bool backToScene, QMap args) {
JNIEnv* myNewEnv;
JavaVMAttachArgs jvmArgs;
jvmArgs.version = JNI_VERSION_1_6; // choose your JNI version
@@ -182,9 +182,11 @@ JNIEXPORT void Java_io_highfidelity_hifiinterface_InterfaceActivity_nativeOnCrea
jmethodID mapClassConstructor = myNewEnv->GetMethodID(hashMapClass, "", "()V");
jobject hashmap = myNewEnv->NewObject(hashMapClass, mapClassConstructor);
jmethodID mapClassPut = myNewEnv->GetMethodID(hashMapClass, "put", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;");
- for (const QString& arg: args) {
- QAndroidJniObject jArg = QAndroidJniObject::fromString(arg);
- myNewEnv->CallObjectMethod(hashmap, mapClassPut, QAndroidJniObject::fromString("url").object(), jArg.object());
+ QMap::iterator i;
+ for (i = args.begin(); i != args.end(); ++i) {
+ QAndroidJniObject jKey = QAndroidJniObject::fromString(i.key());
+ QAndroidJniObject jValue = QAndroidJniObject::fromString(i.value());
+ myNewEnv->CallObjectMethod(hashmap, mapClassPut, jKey.object(), jValue.object());
}
__interfaceActivity.callMethod("openAndroidActivity", "(Ljava/lang/String;ZLjava/util/HashMap;)V", string.object(), jBackToScene, hashmap);
if (attachedHere) {
@@ -255,6 +257,16 @@ JNIEXPORT jstring JNICALL Java_io_highfidelity_hifiinterface_fragment_HomeFragme
return env->NewStringUTF(lastLocation.toString().toLatin1().data());
}
+JNIEXPORT void JNICALL
+Java_io_highfidelity_hifiinterface_fragment_LoginFragment_nativeCancelLogin(JNIEnv *env, jobject instance) {
+
+ auto accountManager = DependencyManager::get();
+
+ QObject::disconnect(accountManager.data(), &AccountManager::loginComplete, nullptr, nullptr);
+ QObject::disconnect(accountManager.data(), &AccountManager::loginFailed, nullptr, nullptr);
+
+}
+
JNIEXPORT void JNICALL
Java_io_highfidelity_hifiinterface_fragment_LoginFragment_nativeLogin(JNIEnv *env, jobject instance,
jstring username_, jstring password_,
@@ -273,17 +285,23 @@ Java_io_highfidelity_hifiinterface_fragment_LoginFragment_nativeLogin(JNIEnv *en
QObject::connect(accountManager.data(), &AccountManager::loginComplete, [](const QUrl& authURL) {
jboolean jSuccess = (jboolean) true;
- __loginCompletedListener.callMethod("handleLoginCompleted", "(Z)V", jSuccess);
+ if (__loginCompletedListener.isValid()) {
+ __loginCompletedListener.callMethod("handleLoginCompleted", "(Z)V", jSuccess);
+ }
});
QObject::connect(accountManager.data(), &AccountManager::loginFailed, []() {
jboolean jSuccess = (jboolean) false;
- __loginCompletedListener.callMethod("handleLoginCompleted", "(Z)V", jSuccess);
+ if (__loginCompletedListener.isValid()) {
+ __loginCompletedListener.callMethod("handleLoginCompleted", "(Z)V", jSuccess);
+ }
});
QObject::connect(accountManager.data(), &AccountManager::usernameChanged, [](const QString& username) {
QAndroidJniObject string = QAndroidJniObject::fromString(username);
- __usernameChangedListener.callMethod("handleUsernameChanged", "(Ljava/lang/String;)V", string.object());
+ if (__usernameChangedListener.isValid()) {
+ __usernameChangedListener.callMethod("handleUsernameChanged", "(Ljava/lang/String;)V", string.object());
+ }
});
QMetaObject::invokeMethod(accountManager.data(), "requestAccessToken",
@@ -355,5 +373,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..3d43e20c63 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;
@@ -38,8 +39,10 @@ import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
+import java.util.Map;
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 +58,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 +155,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 +167,7 @@ public class InterfaceActivity extends QtActivity implements WebViewFragment.OnW
} else {
nativeEnterBackground();
}
+ unregisterReceiver(headsetStateReceiver);
//gvrApi.pauseTracking();
}
@@ -183,6 +190,7 @@ public class InterfaceActivity extends QtActivity implements WebViewFragment.OnW
nativeEnterForeground();
surfacesWorkaround();
keepInterfaceRunning = false;
+ registerReceiver(headsetStateReceiver, new IntentFilter(Intent.ACTION_HEADSET_PLUG));
//gvrApi.resumeTracking();
}
@@ -296,14 +304,22 @@ public class InterfaceActivity extends QtActivity implements WebViewFragment.OnW
switch (activityName) {
case "Home":
case "Privacy Policy":
- case "Login": {
nativeBeforeEnterBackground();
Intent intent = new Intent(this, MainActivity.class);
intent.putExtra(MainActivity.EXTRA_FRAGMENT, activityName);
intent.putExtra(MainActivity.EXTRA_BACK_TO_SCENE, backToScene);
startActivity(intent);
break;
- }
+ case "Login":
+ nativeBeforeEnterBackground();
+ Intent loginIntent = new Intent(this, MainActivity.class);
+ loginIntent.putExtra(MainActivity.EXTRA_FRAGMENT, activityName);
+ loginIntent.putExtra(MainActivity.EXTRA_BACK_TO_SCENE, backToScene);
+ if (args != null && args.containsKey(DOMAIN_URL)) {
+ loginIntent.putExtra(DOMAIN_URL, (String) args.get(DOMAIN_URL));
+ }
+ startActivity(loginIntent);
+ break;
case "WebView":
runOnUiThread(() -> {
webSlidingDrawer.setVisibility(View.VISIBLE);
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..ff91409b9e 100644
--- a/android/app/src/main/java/io/highfidelity/hifiinterface/MainActivity.java
+++ b/android/app/src/main/java/io/highfidelity/hifiinterface/MainActivity.java
@@ -29,10 +29,14 @@ import android.widget.TextView;
import com.squareup.picasso.Callback;
import com.squareup.picasso.Picasso;
+import java.util.HashMap;
+import java.util.Map;
+
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,
@@ -44,6 +48,7 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
public static final String DEFAULT_FRAGMENT = "Home";
public static final String EXTRA_FRAGMENT = "fragment";
public static final String EXTRA_BACK_TO_SCENE = "backToScene";
+ public static final String EXTRA_BACK_TO_URL = "url";
private String TAG = "HighFidelity";
@@ -61,6 +66,7 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
private MenuItem mPeopleMenuItem;
private boolean backToScene;
+ private String backToUrl;
@Override
protected void onCreate(Bundle savedInstanceState) {
@@ -80,6 +86,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);
@@ -102,8 +110,17 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
loadFragment(DEFAULT_FRAGMENT);
}
- if (getIntent().hasExtra(EXTRA_BACK_TO_SCENE)) {
- backToScene = getIntent().getBooleanExtra(EXTRA_BACK_TO_SCENE, false);
+ backToScene = getIntent().getBooleanExtra(EXTRA_BACK_TO_SCENE, false);
+ backToUrl = getIntent().getStringExtra(EXTRA_BACK_TO_URL);
+ }
+ }
+
+ 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);
+ }
}
}
}
@@ -151,6 +168,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 +265,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;
}
@@ -278,7 +305,7 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
}
private void goToLastLocation() {
- goToDomain("");
+ goToDomain(backToUrl != null? backToUrl : "");
}
private void goToDomain(String domainUrl) {
diff --git a/android/app/src/main/java/io/highfidelity/hifiinterface/fragment/LoginFragment.java b/android/app/src/main/java/io/highfidelity/hifiinterface/fragment/LoginFragment.java
index f29c237ed7..92cdec19a1 100644
--- a/android/app/src/main/java/io/highfidelity/hifiinterface/fragment/LoginFragment.java
+++ b/android/app/src/main/java/io/highfidelity/hifiinterface/fragment/LoginFragment.java
@@ -4,12 +4,10 @@ import android.app.Activity;
import android.app.Fragment;
import android.app.ProgressDialog;
import android.content.Context;
+import android.content.DialogInterface;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
-import android.text.Editable;
-import android.text.TextWatcher;
-import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
@@ -19,8 +17,13 @@ import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
+import org.qtproject.qt5.android.QtNative;
+
import io.highfidelity.hifiinterface.R;
+import static org.qtproject.qt5.android.QtActivityDelegate.ApplicationActive;
+import static org.qtproject.qt5.android.QtActivityDelegate.ApplicationInactive;
+
public class LoginFragment extends Fragment {
private EditText mUsername;
@@ -32,6 +35,7 @@ public class LoginFragment extends Fragment {
private ProgressDialog mDialog;
public native void nativeLogin(String username, String password, Activity usernameChangedListener);
+ public native void nativeCancelLogin();
private LoginFragment.OnLoginInteractionListener mListener;
@@ -55,44 +59,6 @@ public class LoginFragment extends Fragment {
mLoginButton = rootView.findViewById(R.id.loginButton);
mForgotPassword = rootView.findViewById(R.id.forgotPassword);
- mUsername.addTextChangedListener(new TextWatcher() {
- boolean ignoreNextChange = false;
- boolean hadBlankSpace = false;
- @Override
- public void beforeTextChanged(CharSequence charSequence, int start, int count, int after) {
- hadBlankSpace = charSequence.length() > 0 && charSequence.charAt(charSequence.length()-1) == ' ';
- }
-
- @Override
- public void onTextChanged(CharSequence charSequence, int start, int count, int after) {
-
- }
-
- @Override
- public void afterTextChanged(Editable editable) {
- if (!ignoreNextChange) {
- ignoreNextChange = true;
- boolean spaceFound = false;
- for (int i = 0; i < editable.length(); i++) {
- if (editable.charAt(i) == ' ') {
- spaceFound=true;
- editable.delete(i, i + 1);
- i--;
- }
- }
-
- if (hadBlankSpace && !spaceFound && editable.length() > 0) {
- editable.delete(editable.length()-1, editable.length());
- }
-
- editable.append(' ');
- ignoreNextChange = false;
- }
-
- }
- });
-
-
mLoginButton.setOnClickListener(view -> login());
mForgotPassword.setOnClickListener(view -> forgotPassword());
@@ -125,10 +91,19 @@ public class LoginFragment extends Fragment {
mListener = null;
}
+ @Override
+ public void onResume() {
+ super.onResume();
+ // This hack intends to keep Qt threads running even after the app comes from background
+ QtNative.setApplicationState(ApplicationActive);
+ }
+
@Override
public void onStop() {
super.onStop();
cancelActivityIndicator();
+ // Leave the Qt app paused
+ QtNative.setApplicationState(ApplicationInactive);
hideKeyboard();
}
@@ -164,7 +139,15 @@ public class LoginFragment extends Fragment {
mDialog = new ProgressDialog(getContext());
}
mDialog.setMessage(getString(R.string.logging_in));
- mDialog.setCancelable(false);
+ mDialog.setCancelable(true);
+ mDialog.setOnCancelListener(new DialogInterface.OnCancelListener() {
+ @Override
+ public void onCancel(DialogInterface dialogInterface) {
+ nativeCancelLogin();
+ cancelActivityIndicator();
+ mLoginButton.setEnabled(true);
+ }
+ });
mDialog.show();
}
@@ -184,7 +167,6 @@ public class LoginFragment extends Fragment {
}
public void handleLoginCompleted(boolean success) {
- Log.d("[LOGIN]", "handleLoginCompleted " + success);
getActivity().runOnUiThread(() -> {
mLoginButton.setEnabled(true);
cancelActivityIndicator();
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/drawable/ic_eye_noshow.xml b/android/app/src/main/res/drawable/ic_eye_noshow.xml
new file mode 100644
index 0000000000..1d5304afac
--- /dev/null
+++ b/android/app/src/main/res/drawable/ic_eye_noshow.xml
@@ -0,0 +1,27 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/android/app/src/main/res/drawable/ic_eye_show.xml b/android/app/src/main/res/drawable/ic_eye_show.xml
new file mode 100644
index 0000000000..273ecc8339
--- /dev/null
+++ b/android/app/src/main/res/drawable/ic_eye_show.xml
@@ -0,0 +1,15 @@
+
+
+
+
+
+
diff --git a/android/app/src/main/res/drawable/selector_show_password.xml b/android/app/src/main/res/drawable/selector_show_password.xml
new file mode 100644
index 0000000000..a44092aceb
--- /dev/null
+++ b/android/app/src/main/res/drawable/selector_show_password.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/android/app/src/main/res/layout/fragment_login.xml b/android/app/src/main/res/layout/fragment_login.xml
index c50e6c1380..46ed783898 100644
--- a/android/app/src/main/res/layout/fragment_login.xml
+++ b/android/app/src/main/res/layout/fragment_login.xml
@@ -41,38 +41,51 @@
android:paddingTop="14dp"
android:ems="10"
android:fontFamily="@font/raleway"
- android:textSize="14sp"
+ android:textSize="17sp"
android:inputType="textEmailAddress"
android:textStyle="italic"
android:textColor="@color/editTextColor"
android:textColorHint="@color/editTextColor"
- android:gravity="right|center_vertical"
+ android:gravity="left|center_vertical"
app:layout_constraintTop_toBottomOf="@id/header"
android:layout_marginTop="70dp"
android:hint="@string/username_or_email" />
-
+
+ android:inputType="textPassword" />
+
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/colors.xml b/android/app/src/main/res/values/colors.xml
index e4bbb60544..216b3491d8 100644
--- a/android/app/src/main/res/values/colors.xml
+++ b/android/app/src/main/res/values/colors.xml
@@ -6,6 +6,7 @@
#54D7FD
#E3E3E3
#575757
+ #3D3D3D
#1EB5EC
#00B4EF
#333333
diff --git a/android/app/src/main/res/values/strings.xml b/android/app/src/main/res/values/strings.xml
index b158aba59d..9023744cf4 100644
--- a/android/app/src/main/res/values/strings.xml
+++ b/android/app/src/main/res/values/strings.xml
@@ -10,8 +10,8 @@
POPULAR
BOOKMARKS
Type a domain url
- Username or email\u00A0
- Password\u00A0
+ Username or email
+ Password
Login
Logout
Forgot password?\u00A0
@@ -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/domain-server/resources/web/js/base-settings.js b/domain-server/resources/web/js/base-settings.js
index 7a860098d2..fd404aff20 100644
--- a/domain-server/resources/web/js/base-settings.js
+++ b/domain-server/resources/web/js/base-settings.js
@@ -1110,7 +1110,36 @@ function moveTableRow(row, move_up) {
}
// we need to fire a change event on one of the remaining inputs so that the sidebar badge is updated
- badgeForDifferences($(table))
+ badgeForDifferences($(table));
+
+ // figure out which group this row is in
+ var panelParentID = row.closest('.panel').attr('id');
+
+ // get the short name for the setting from the table
+ var tableShortName = row.closest('table').data('short-name');
+
+ var changed = tableHasChanged(panelParentID, tableShortName);
+ $(table).find('.' + Settings.DATA_ROW_CLASS).each(function(){
+ var hiddenInput = $(this).find('td.' + Settings.DATA_COL_CLASS + ' input');
+ if (changed) {
+ hiddenInput.attr('data-changed', true);
+ } else {
+ hiddenInput.removeAttr('data-changed');
+ }
+ });
+
+}
+
+function tableHasChanged(panelParentID, tableShortName) {
+ // get a JSON representation of that section
+ var panelSettingJSON = form2js(panelParentID, ".", false, cleanupFormValues, true)[panelParentID][tableShortName]
+ if (Settings.initialValues[panelParentID]) {
+ var initialPanelSettingJSON = Settings.initialValues[panelParentID][tableShortName]
+ } else {
+ var initialPanelSettingJSON = {};
+ }
+
+ return !_.isEqual(panelSettingJSON, initialPanelSettingJSON);
}
function updateDataChangedForSiblingRows(row, forceTrue) {
@@ -1123,16 +1152,8 @@ function updateDataChangedForSiblingRows(row, forceTrue) {
// get the short name for the setting from the table
var tableShortName = row.closest('table').data('short-name')
- // get a JSON representation of that section
- var panelSettingJSON = form2js(panelParentID, ".", false, cleanupFormValues, true)[panelParentID][tableShortName]
- if (Settings.initialValues[panelParentID]) {
- var initialPanelSettingJSON = Settings.initialValues[panelParentID][tableShortName]
- } else {
- var initialPanelSettingJSON = {};
- }
-
// if they are equal, we don't need data-changed
- isTrue = !_.isEqual(panelSettingJSON, initialPanelSettingJSON)
+ isTrue = tableHasChanged(panelParentID, tableShortName);
} else {
isTrue = true
}
@@ -1140,9 +1161,9 @@ function updateDataChangedForSiblingRows(row, forceTrue) {
row.siblings('.' + Settings.DATA_ROW_CLASS).each(function(){
var hiddenInput = $(this).find('td.' + Settings.DATA_COL_CLASS + ' input')
if (isTrue) {
- hiddenInput.attr('data-changed', isTrue)
+ hiddenInput.attr('data-changed', isTrue);
} else {
- hiddenInput.removeAttr('data-changed')
+ hiddenInput.removeAttr('data-changed');
}
})
}
diff --git a/domain-server/src/DomainServer.cpp b/domain-server/src/DomainServer.cpp
index 57c4692794..8136bf3b53 100644
--- a/domain-server/src/DomainServer.cpp
+++ b/domain-server/src/DomainServer.cpp
@@ -2906,7 +2906,7 @@ void DomainServer::updateReplicationNodes(ReplicationServerDirection direction)
// collect them in a vector to separately remove them with handleKillNode (since eachNode has a read lock and
// we cannot recursively take the write lock required by handleKillNode)
std::vector nodesToKill;
- nodeList->eachNode([this, direction, replicationNodesInSettings, replicationDirection, &nodesToKill](const SharedNodePointer& otherNode) {
+ nodeList->eachNode([direction, replicationNodesInSettings, replicationDirection, &nodesToKill](const SharedNodePointer& otherNode) {
if ((direction == Upstream && NodeType::isUpstream(otherNode->getType()))
|| (direction == Downstream && NodeType::isDownstream(otherNode->getType()))) {
bool nodeInSettings = find(replicationNodesInSettings.cbegin(), replicationNodesInSettings.cend(),
diff --git a/interface/resources/icons/tablet-icons/goto-a-msg.svg b/interface/resources/icons/tablet-icons/goto-a-msg.svg
new file mode 100644
index 0000000000..f1f611adb9
--- /dev/null
+++ b/interface/resources/icons/tablet-icons/goto-a-msg.svg
@@ -0,0 +1,57 @@
+
+
+
+
\ No newline at end of file
diff --git a/interface/resources/icons/tablet-icons/goto-msg.svg b/interface/resources/icons/tablet-icons/goto-i-msg.svg
similarity index 100%
rename from interface/resources/icons/tablet-icons/goto-msg.svg
rename to interface/resources/icons/tablet-icons/goto-i-msg.svg
diff --git a/interface/resources/icons/tablet-icons/people-a-msg.svg b/interface/resources/icons/tablet-icons/people-a-msg.svg
new file mode 100644
index 0000000000..862ce936ce
--- /dev/null
+++ b/interface/resources/icons/tablet-icons/people-a-msg.svg
@@ -0,0 +1,83 @@
+
+
+
+
\ No newline at end of file
diff --git a/interface/resources/icons/tablet-icons/people-i-msg.svg b/interface/resources/icons/tablet-icons/people-i-msg.svg
new file mode 100644
index 0000000000..635a01be4b
--- /dev/null
+++ b/interface/resources/icons/tablet-icons/people-i-msg.svg
@@ -0,0 +1,24 @@
+
+
+
diff --git a/interface/resources/icons/tablet-icons/wallet-a-msg.svg b/interface/resources/icons/tablet-icons/wallet-a-msg.svg
new file mode 100644
index 0000000000..d51c3e99a2
--- /dev/null
+++ b/interface/resources/icons/tablet-icons/wallet-a-msg.svg
@@ -0,0 +1,6 @@
+
\ No newline at end of file
diff --git a/interface/resources/icons/tablet-icons/wallet-i-msg.svg b/interface/resources/icons/tablet-icons/wallet-i-msg.svg
new file mode 100644
index 0000000000..676f97a966
--- /dev/null
+++ b/interface/resources/icons/tablet-icons/wallet-i-msg.svg
@@ -0,0 +1,16 @@
+
+
+
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/resources/qml/LoginDialog/LinkAccountBody.qml b/interface/resources/qml/LoginDialog/LinkAccountBody.qml
index 57293cb5e3..48cf124127 100644
--- a/interface/resources/qml/LoginDialog/LinkAccountBody.qml
+++ b/interface/resources/qml/LoginDialog/LinkAccountBody.qml
@@ -23,6 +23,7 @@ Item {
property bool failAfterSignUp: false
function login() {
+ flavorText.visible = false
mainTextContainer.visible = false
toggleLoading(true)
loginDialog.login(usernameField.text, passwordField.text)
@@ -43,7 +44,7 @@ Item {
function resize() {
var targetWidth = Math.max(titleWidth, form.contentWidth);
- var targetHeight = hifi.dimensions.contentSpacing.y + mainTextContainer.height +
+ var targetHeight = hifi.dimensions.contentSpacing.y + flavorText.height + mainTextContainer.height +
4 * hifi.dimensions.contentSpacing.y + form.height;
if (additionalInformation.visible) {
@@ -106,14 +107,15 @@ Item {
ShortcutText {
id: mainTextContainer
anchors {
- top: parent.top
+ top: flavorText.bottom
left: parent.left
margins: 0
- topMargin: hifi.dimensions.contentSpacing.y
+ topMargin: 1.5 * hifi.dimensions.contentSpacing.y
}
visible: false
text: qsTr("Username or password incorrect.")
+ height: flavorText.height - 20
wrapMode: Text.WordWrap
color: hifi.colors.redAccent
lineHeight: 1
@@ -128,7 +130,7 @@ Item {
anchors {
top: mainTextContainer.bottom
- topMargin: 2 * hifi.dimensions.contentSpacing.y
+ topMargin: 1.5 * hifi.dimensions.contentSpacing.y
}
spacing: 2 * hifi.dimensions.contentSpacing.y
@@ -139,6 +141,7 @@ Item {
focus: true
placeholderText: "Username or Email"
activeFocusOnPress: true
+ onHeightChanged: d.resize(); onWidthChanged: d.resize();
ShortcutText {
z: 10
@@ -172,7 +175,7 @@ Item {
width: parent.width
placeholderText: "Password"
activeFocusOnPress: true
- echoMode: TextInput.Password
+ echoMode: passwordFieldMouseArea.showPassword ? TextInput.Normal : TextInput.Password
onHeightChanged: d.resize(); onWidthChanged: d.resize();
ShortcutText {
@@ -212,29 +215,28 @@ Item {
Image {
id: showPasswordImage
- y: (passwordField.height - (passwordField.height * 16 / 23)) / 2
- width: passwordField.width - (passwordField.width - (((passwordField.height) * 31/23)))
+ width: passwordField.height * 16 / 23
height: passwordField.height * 16 / 23
anchors {
right: parent.right
- rightMargin: 3
+ rightMargin: 8
+ top: parent.top
+ topMargin: passwordFieldMouseArea.showPassword ? 6 : 8
+ bottom: parent.bottom
+ bottomMargin: passwordFieldMouseArea.showPassword ? 5 : 8
+ }
+ source: passwordFieldMouseArea.showPassword ? "../../images/eyeClosed.svg" : "../../images/eyeOpen.svg"
+ MouseArea {
+ id: passwordFieldMouseArea
+ anchors.fill: parent
+ acceptedButtons: Qt.LeftButton
+ property bool showPassword: false
+ onClicked: {
+ showPassword = !showPassword;
+ }
}
- source: "../../images/eyeOpen.svg"
}
- MouseArea {
- id: passwordFieldMouseArea
- anchors.fill: parent
- acceptedButtons: Qt.LeftButton
- property bool showPassword: false
- onClicked: {
- showPassword = !showPassword;
- passwordField.echoMode = showPassword ? TextInput.Normal : TextInput.Password;
- showPasswordImage.source = showPassword ? "../../images/eyeClosed.svg" : "../../images/eyeOpen.svg";
- showPasswordImage.height = showPassword ? passwordField.height : passwordField.height * 16 / 23;
- showPasswordImage.y = showPassword ? 0 : (passwordField.height - showPasswordImage.height) / 2;
- }
- }
}
Keys.onReturnPressed: linkAccountBody.login()
@@ -284,7 +286,7 @@ Item {
anchors.verticalCenter: parent.verticalCenter
width: 200
- text: qsTr(loginDialog.isSteamRunning() ? "Link Account" : "Login")
+ text: qsTr(loginDialog.isSteamRunning() ? "Link Account" : "Log in")
color: hifi.buttons.blue
onClicked: linkAccountBody.login()
@@ -336,6 +338,7 @@ Item {
if (failAfterSignUp) {
mainTextContainer.text = "Account created successfully."
+ flavorText.visible = true
mainTextContainer.visible = true
}
@@ -374,6 +377,7 @@ Item {
UserActivityLogger.logAction("encourageLoginDialog", data);
Settings.setValue("loginDialogPoppedUp", false);
}
+ flavorText.visible = true
mainTextContainer.visible = true
toggleLoading(false)
}
diff --git a/interface/resources/qml/hifi/Pal.qml b/interface/resources/qml/hifi/Pal.qml
index 35a0078d32..e8fc41da63 100644
--- a/interface/resources/qml/hifi/Pal.qml
+++ b/interface/resources/qml/hifi/Pal.qml
@@ -271,6 +271,8 @@ Rectangle {
connectionsUserModel.getFirstPage();
}
activeTab = "connectionsTab";
+ connectionsOnlineDot.visible = false;
+ pal.sendToScript({method: 'hideNotificationDot'});
connectionsHelpText.color = hifi.colors.blueAccent;
}
}
@@ -298,6 +300,16 @@ Rectangle {
}
}
}
+ Rectangle {
+ id: connectionsOnlineDot;
+ visible: false;
+ width: 10;
+ height: width;
+ radius: width;
+ color: "#EF3B4E"
+ anchors.left: parent.left;
+ anchors.verticalCenter: parent.verticalCenter;
+ }
// "CONNECTIONS" text
RalewaySemiBold {
id: connectionsTabSelectorText;
@@ -305,7 +317,11 @@ Rectangle {
// Text size
size: hifi.fontSizes.tabularData;
// Anchors
- anchors.fill: parent;
+ anchors.left: connectionsOnlineDot.visible ? connectionsOnlineDot.right : parent.left;
+ anchors.leftMargin: connectionsOnlineDot.visible ? 4 : 0;
+ anchors.top: parent.top;
+ anchors.bottom: parent.bottom;
+ anchors.right: parent.right;
// Style
font.capitalization: Font.AllUppercase;
color: activeTab === "connectionsTab" ? hifi.colors.blueAccent : hifi.colors.baseGray;
@@ -326,7 +342,7 @@ Rectangle {
anchors.left: connectionsTabSelectorTextContainer.left;
anchors.top: connectionsTabSelectorTextContainer.top;
anchors.topMargin: 1;
- anchors.leftMargin: connectionsTabSelectorTextMetrics.width + 42;
+ anchors.leftMargin: connectionsTabSelectorTextMetrics.width + 42 + connectionsOnlineDot.width + connectionsTabSelectorText.anchors.leftMargin;
RalewayRegular {
id: connectionsHelpText;
text: "[?]";
@@ -1267,6 +1283,9 @@ Rectangle {
case 'http.response':
http.handleHttpResponse(message);
break;
+ case 'changeConnectionsDotStatus':
+ connectionsOnlineDot.visible = message.shouldShowDot;
+ break;
default:
console.log('Unrecognized message:', JSON.stringify(message));
}
diff --git a/interface/resources/qml/hifi/avatarapp/AdjustWearables.qml b/interface/resources/qml/hifi/avatarapp/AdjustWearables.qml
index 5bf867a331..7413cf93ab 100644
--- a/interface/resources/qml/hifi/avatarapp/AdjustWearables.qml
+++ b/interface/resources/qml/hifi/avatarapp/AdjustWearables.qml
@@ -314,7 +314,7 @@ Rectangle {
}
};
- wearableUpdated(getCurrentWearable().id, jointIndex, properties);
+ wearableUpdated(getCurrentWearable().id, wearablesCombobox.currentIndex, properties);
}
onCurrentIndexChanged: {
diff --git a/interface/resources/qml/hifi/avatarapp/TransparencyMask.qml b/interface/resources/qml/hifi/avatarapp/TransparencyMask.qml
index 6c50a6093a..db9b4f06ae 100644
--- a/interface/resources/qml/hifi/avatarapp/TransparencyMask.qml
+++ b/interface/resources/qml/hifi/avatarapp/TransparencyMask.qml
@@ -24,6 +24,7 @@ Item {
fragmentShader: {
"
+#version 150 core
varying highp vec2 qt_TexCoord0;
uniform lowp sampler2D source;
uniform lowp sampler2D mask;
diff --git a/interface/resources/qml/hifi/commerce/checkout/Checkout.qml b/interface/resources/qml/hifi/commerce/checkout/Checkout.qml
index 4d47479589..b13f23f17d 100644
--- a/interface/resources/qml/hifi/commerce/checkout/Checkout.qml
+++ b/interface/resources/qml/hifi/commerce/checkout/Checkout.qml
@@ -552,6 +552,10 @@ Rectangle {
// Alignment
horizontalAlignment: Text.AlignLeft;
verticalAlignment: Text.AlignVCenter;
+ onLinkActivated: {
+ // Only case is to go to the bank.
+ sendToScript({method: 'gotoBank'});
+ }
}
}
@@ -1107,25 +1111,32 @@ Rectangle {
}
function handleBuyAgainLogic() {
- // If you can buy this item again...
- if (canBuyAgain()) {
- // If you can't afford another copy of the item...
- if (root.balanceAfterPurchase < 0) {
- // If you already own the item...
- if (root.alreadyOwned) {
- buyText.text = "Your Wallet does not have sufficient funds to purchase this item again.";
- // Else if you don't already own the item...
- } else {
- buyText.text = "Your Wallet does not have sufficient funds to purchase this item.";
- }
- buyTextContainer.color = "#FFC3CD";
- buyTextContainer.border.color = "#F3808F";
- buyGlyph.text = hifi.glyphs.alert;
- buyGlyph.size = 54;
- // If you CAN afford another copy of the item...
+ // General rules, implemented in various scattered places in this file:
+ // 1. If you already own the item, a viewInMyPurchasesButton is visible,
+ // and the buyButton is visible (and says "Buy it again") ONLY if it is a type you canBuyAgain.
+ // 2. Separately,
+ // a. If you don't have enough money to buy, the buyText becomes visible and tells you, and the buyButton is disabled.
+ // b. Otherwise, if the item is a content set and you don't have rez permission, the buyText becomes visible and tells you so.
+
+ // If you can't afford another copy of the item...
+ if (root.balanceAfterPurchase < 0) {
+ // If you already own the item...
+ if (!root.alreadyOwned) {
+ buyText.text = "Your Wallet does not have sufficient funds to purchase this item.";
+ // Else if you don't already own the item...
+ } else if (canBuyAgain()) {
+ buyText.text = "Your Wallet does not have sufficient funds to purchase this item again.";
} else {
- handleContentSets();
+ buyText.text = "While you do not have sufficient funds to buy this, you already have this item."
}
+ buyText.text += " Visit Bank of High Fidelity to get more HFC."
+ buyTextContainer.color = "#FFC3CD";
+ buyTextContainer.border.color = "#F3808F";
+ buyGlyph.text = hifi.glyphs.alert;
+ buyGlyph.size = 54;
+ // If you CAN afford another copy of the item...
+ } else {
+ handleContentSets();
}
}
diff --git a/interface/resources/qml/hifi/commerce/marketplaceItemTester/MarketplaceItemTester.qml b/interface/resources/qml/hifi/commerce/marketplaceItemTester/MarketplaceItemTester.qml
new file mode 100644
index 0000000000..c3d87ca2f5
--- /dev/null
+++ b/interface/resources/qml/hifi/commerce/marketplaceItemTester/MarketplaceItemTester.qml
@@ -0,0 +1,290 @@
+//
+// marketplaceItemTester
+// qml/hifi/commerce/marketplaceItemTester
+//
+// Load items not in the marketplace for testing purposes
+//
+// Created by Zach Fox on 2018-09-05
+// 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
+//
+
+import QtQuick 2.5
+import QtQuick.Controls 1.4
+import QtQuick.Controls.Styles 1.4
+import QtQuick.Dialogs 1.0
+import QtQuick.Layouts 1.1
+import Hifi 1.0 as Hifi
+import "../../../styles-uit" as HifiStylesUit
+import "../../../controls-uit" as HifiControlsUit
+
+
+
+Rectangle {
+ id: root
+
+ property string installedApps
+ property var nextResourceObjectId: 0
+ signal sendToScript(var message)
+
+ HifiStylesUit.HifiConstants { id: hifi }
+ ListModel { id: resourceListModel }
+
+ color: hifi.colors.white
+
+ AnimatedImage {
+ id: spinner;
+ source: "spinner.gif"
+ width: 74;
+ height: width;
+ anchors.verticalCenter: parent.verticalCenter;
+ anchors.horizontalCenter: parent.horizontalCenter;
+ }
+
+ function fromScript(message) {
+ switch (message.method) {
+ case "newResourceObjectInTest":
+ var resourceObject = message.resourceObject;
+ resourceListModel.append(resourceObject);
+ spinner.visible = false;
+ break;
+ case "nextObjectIdInTest":
+ nextResourceObjectId = message.id;
+ spinner.visible = false;
+ break;
+ }
+ }
+
+ function buildResourceObj(resource) {
+ resource = resource.trim();
+ var assetType = (resource.match(/\.app\.json$/) ? "application" :
+ resource.match(/\.fst$/) ? "avatar" :
+ resource.match(/\.json\.gz$/) ? "content set" :
+ resource.match(/\.json$/) ? "entity or wearable" :
+ "unknown");
+ return { "id": nextResourceObjectId++,
+ "resource": resource,
+ "assetType": assetType };
+ }
+
+ function installResourceObj(resourceObj) {
+ if ("application" === resourceObj.assetType) {
+ Commerce.installApp(resourceObj.resource);
+ }
+ }
+
+ function addAllInstalledAppsToList() {
+ var i, apps = Commerce.getInstalledApps().split(","), len = apps.length;
+ for(i = 0; i < len - 1; ++i) {
+ if (i in apps) {
+ resourceListModel.append(buildResourceObj(apps[i]));
+ }
+ }
+ }
+
+ function toUrl(resource) {
+ var httpPattern = /^http/i;
+ return httpPattern.test(resource) ? resource : "file:///" + resource;
+ }
+
+ function rezEntity(resource, entityType) {
+ sendToScript({
+ method: 'tester_rezClicked',
+ itemHref: toUrl(resource),
+ itemType: entityType});
+ }
+
+ ListView {
+ anchors.fill: parent
+ anchors.leftMargin: 12
+ anchors.bottomMargin: 40
+ anchors.rightMargin: 12
+ model: resourceListModel
+ spacing: 5
+ interactive: false
+
+ delegate: RowLayout {
+ anchors.left: parent.left
+ width: parent.width
+ spacing: 5
+
+ property var actions: {
+ "forward": function(resource, assetType){
+ switch(assetType) {
+ case "application":
+ Commerce.openApp(resource);
+ break;
+ case "avatar":
+ MyAvatar.useFullAvatarURL(resource);
+ break;
+ case "content set":
+ urlHandler.handleUrl("hifi://localhost/0,0,0");
+ Commerce.replaceContentSet(toUrl(resource), "");
+ break;
+ case "entity":
+ case "wearable":
+ rezEntity(resource, assetType);
+ break;
+ default:
+ print("Marketplace item tester unsupported assetType " + assetType);
+ }
+ },
+ "trash": function(resource, assetType){
+ if ("application" === assetType) {
+ Commerce.uninstallApp(resource);
+ }
+ sendToScript({
+ method: "tester_deleteResourceObject",
+ objectId: resourceListModel.get(index).id});
+ resourceListModel.remove(index);
+ }
+ }
+
+ Column {
+ Layout.preferredWidth: root.width * .6
+ spacing: 5
+ Text {
+ text: {
+ var match = resource.match(/\/([^/]*)$/);
+ return match ? match[1] : resource;
+ }
+ font.pointSize: 12
+ horizontalAlignment: Text.AlignBottom
+ }
+ Text {
+ text: resource
+ font.pointSize: 8
+ width: root.width * .6
+ horizontalAlignment: Text.AlignBottom
+ wrapMode: Text.WrapAnywhere
+ }
+ }
+
+ ComboBox {
+ id: comboBox
+
+ Layout.preferredWidth: root.width * .2
+
+ model: [
+ "application",
+ "avatar",
+ "content set",
+ "entity",
+ "wearable",
+ "unknown"
+ ]
+
+ currentIndex: (("entity or wearable" === assetType) ?
+ model.indexOf("unknown") : model.indexOf(assetType))
+
+ Component.onCompleted: {
+ onCurrentIndexChanged.connect(function() {
+ assetType = model[currentIndex];
+ sendToScript({
+ method: "tester_updateResourceObjectAssetType",
+ objectId: resourceListModel.get(index)["id"],
+ assetType: assetType });
+ });
+ }
+ }
+
+ Repeater {
+ model: [ "forward", "trash" ]
+
+ HifiStylesUit.HiFiGlyphs {
+ property var glyphs: {
+ "application": hifi.glyphs.install,
+ "avatar": hifi.glyphs.avatar,
+ "content set": hifi.glyphs.globe,
+ "entity": hifi.glyphs.wand,
+ "trash": hifi.glyphs.trash,
+ "unknown": hifi.glyphs.circleSlash,
+ "wearable": hifi.glyphs.hat,
+ }
+ text: (("trash" === modelData) ?
+ glyphs.trash :
+ glyphs[comboBox.model[comboBox.currentIndex]])
+ size: ("trash" === modelData) ? 22 : 30
+ color: hifi.colors.black
+ horizontalAlignment: Text.AlignHCenter
+ MouseArea {
+ anchors.fill: parent
+ onClicked: {
+ actions[modelData](resource, comboBox.currentText);
+ }
+ }
+ }
+ }
+ }
+
+ headerPositioning: ListView.OverlayHeader
+ header: HifiStylesUit.RalewayRegular {
+ id: rootHeader
+ text: "Marketplace Item Tester"
+ height: 80
+ width: paintedWidth
+ size: 22
+ color: hifi.colors.black
+ anchors.left: parent.left
+ anchors.leftMargin: 12
+ }
+
+ footerPositioning: ListView.OverlayFooter
+ footer: Row {
+ id: rootActions
+ spacing: 20
+ anchors.horizontalCenter: parent.horizontalCenter
+
+ property string currentAction
+ property var actions: {
+ "Load File": function(){
+ rootActions.currentAction = "load file";
+ Window.browseChanged.connect(onResourceSelected);
+ Window.browseAsync("Please select a file (*.app.json *.json *.fst *.json.gz)", "", "Assets (*.app.json *.json *.fst *.json.gz)");
+ },
+ "Load URL": function(){
+ rootActions.currentAction = "load url";
+ Window.promptTextChanged.connect(onResourceSelected);
+ Window.promptAsync("Please enter a URL", "");
+ }
+ }
+
+ function onResourceSelected(resource) {
+ // It is possible that we received the present signal
+ // from something other than our browserAsync window.
+ // Alas, there is nothing we can do about that so charge
+ // ahead as though we are sure the present signal is one
+ // we expect.
+ switch(currentAction) {
+ case "load file":
+ Window.browseChanged.disconnect(onResourceSelected);
+ break
+ case "load url":
+ Window.promptTextChanged.disconnect(onResourceSelected);
+ break;
+ }
+ if (resource) {
+ var resourceObj = buildResourceObj(resource);
+ installResourceObj(resourceObj);
+ sendToScript({
+ method: 'tester_newResourceObject',
+ resourceObject: resourceObj });
+ }
+ }
+
+ Repeater {
+ model: [ "Load File", "Load URL" ]
+ HifiControlsUit.Button {
+ color: hifi.buttons.blue
+ fontSize: 20
+ text: modelData
+ width: root.width / 3
+ height: 40
+ onClicked: actions[text]()
+ }
+ }
+ }
+ }
+}
diff --git a/interface/resources/qml/hifi/commerce/marketplaceItemTester/spinner.gif b/interface/resources/qml/hifi/commerce/marketplaceItemTester/spinner.gif
new file mode 100644
index 0000000000..00f75ae62f
Binary files /dev/null and b/interface/resources/qml/hifi/commerce/marketplaceItemTester/spinner.gif differ
diff --git a/interface/resources/qml/hifi/commerce/purchases/PurchasedItem.qml b/interface/resources/qml/hifi/commerce/purchases/PurchasedItem.qml
index 032d9b0199..eeb9ac3c54 100644
--- a/interface/resources/qml/hifi/commerce/purchases/PurchasedItem.qml
+++ b/interface/resources/qml/hifi/commerce/purchases/PurchasedItem.qml
@@ -59,7 +59,7 @@ Item {
Connections {
target: Commerce;
-
+
onContentSetChanged: {
if (contentSetHref === root.itemHref) {
showConfirmation = true;
@@ -135,7 +135,7 @@ Item {
anchors.topMargin: 8;
width: 30;
height: width;
-
+
HiFiGlyphs {
id: closeContextMenuGlyph;
text: hifi.glyphs.close;
@@ -376,7 +376,7 @@ Item {
}
}
}
-
+
transform: Rotation {
id: rotation;
origin.x: flipable.width/2;
@@ -509,7 +509,7 @@ Item {
}
verticalAlignment: Text.AlignTop;
}
-
+
HiFiGlyphs {
id: statusIcon;
text: {
@@ -588,7 +588,7 @@ Item {
border.width: 1;
border.color: "#E2334D";
}
-
+
HiFiGlyphs {
id: contextMenuGlyph;
text: hifi.glyphs.verticalEllipsis;
@@ -615,7 +615,7 @@ Item {
}
}
}
-
+
Rectangle {
id: rezzedNotifContainer;
z: 998;
@@ -663,13 +663,13 @@ Item {
Tablet.playSound(TabletEnums.ButtonHover);
}
}
-
+
onFocusChanged: {
if (focus) {
Tablet.playSound(TabletEnums.ButtonHover);
}
}
-
+
onClicked: {
Tablet.playSound(TabletEnums.ButtonClick);
if (root.itemType === "contentSet") {
@@ -775,7 +775,7 @@ Item {
// Style
color: hifi.colors.redAccent;
horizontalAlignment: Text.AlignRight;
-
+
MouseArea {
anchors.fill: parent;
hoverEnabled: true;
diff --git a/interface/resources/qml/hifi/commerce/purchases/Purchases.qml b/interface/resources/qml/hifi/commerce/purchases/Purchases.qml
index 3b8e2c0f4d..2435678e77 100644
--- a/interface/resources/qml/hifi/commerce/purchases/Purchases.qml
+++ b/interface/resources/qml/hifi/commerce/purchases/Purchases.qml
@@ -93,7 +93,7 @@ Rectangle {
console.log("Failed to get Available Updates", result.data.message);
} else {
sendToScript({method: 'purchases_availableUpdatesReceived', numUpdates: result.data.updates.length });
- root.numUpdatesAvailable = result.data.updates.length;
+ root.numUpdatesAvailable = result.total_entries;
}
}
diff --git a/interface/resources/qml/hifi/commerce/wallet/Wallet.qml b/interface/resources/qml/hifi/commerce/wallet/Wallet.qml
index 65d98af234..588b80c435 100644
--- a/interface/resources/qml/hifi/commerce/wallet/Wallet.qml
+++ b/interface/resources/qml/hifi/commerce/wallet/Wallet.qml
@@ -408,9 +408,7 @@ Rectangle {
Connections {
onSendSignalToWallet: {
- if (msg.method === 'walletReset' || msg.method === 'passphraseReset') {
- sendToScript(msg);
- } else if (msg.method === 'walletSecurity_changeSecurityImage') {
+ if (msg.method === 'walletSecurity_changeSecurityImage') {
securityImageChange.initModel();
root.activeView = "securityImageChange";
}
@@ -831,6 +829,7 @@ Rectangle {
Commerce.getWalletAuthenticatedStatus(); // before writing security image, ensures that salt/account password is set.
Commerce.chooseSecurityImage(securityImagePath);
Commerce.generateKeyPair();
+ followReferrer({ referrer: walletSetup.referrer });
}
function addLeadingZero(n) {
@@ -838,7 +837,7 @@ Rectangle {
}
function followReferrer(msg) {
- if (msg.referrer === '' || msg.referrer === 'marketplace cta') {
+ if (msg.referrer === '') {
root.activeView = "initialize";
Commerce.getWalletStatus();
} else if (msg.referrer === 'purchases') {
diff --git a/interface/resources/qml/hifi/commerce/wallet/WalletHome.qml b/interface/resources/qml/hifi/commerce/wallet/WalletHome.qml
index 50208793fe..627da1d43f 100644
--- a/interface/resources/qml/hifi/commerce/wallet/WalletHome.qml
+++ b/interface/resources/qml/hifi/commerce/wallet/WalletHome.qml
@@ -45,14 +45,6 @@ Item {
onHistoryResult : {
transactionHistoryModel.handlePage(null, result);
}
-
- onAvailableUpdatesResult: {
- if (result.status !== 'success') {
- console.log("Failed to get Available Updates", result.data.message);
- } else {
- sendToScript({method: 'wallet_availableUpdatesReceived', numUpdates: result.data.updates.length });
- }
- }
}
Connections {
diff --git a/interface/resources/qml/hifi/commerce/wallet/WalletSetup.qml b/interface/resources/qml/hifi/commerce/wallet/WalletSetup.qml
index eeecff9ad0..dc6ce45a74 100644
--- a/interface/resources/qml/hifi/commerce/wallet/WalletSetup.qml
+++ b/interface/resources/qml/hifi/commerce/wallet/WalletSetup.qml
@@ -28,7 +28,7 @@ Item {
property string activeView: "step_1";
property string lastPage;
property bool hasShownSecurityImageTip: false;
- property string referrer;
+ property string referrer: '';
property string keyFilePath;
property date startingTimestamp;
property string setupAttemptID;
diff --git a/interface/src/AndroidHelper.cpp b/interface/src/AndroidHelper.cpp
index 419382f2cb..c3019229ca 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,12 +19,13 @@
#define qApp (static_cast(QCoreApplication::instance()))
AndroidHelper::AndroidHelper() {
+ qRegisterMetaType("QAudio::Mode");
}
AndroidHelper::~AndroidHelper() {
}
-void AndroidHelper::requestActivity(const QString &activityName, const bool backToScene, QList args) {
+void AndroidHelper::requestActivity(const QString &activityName, const bool backToScene, QMap args) {
emit androidActivityRequested(activityName, backToScene, args);
}
@@ -47,8 +49,10 @@ void AndroidHelper::performHapticFeedback(int duration) {
emit hapticFeedbackRequested(duration);
}
-void AndroidHelper::showLoginDialog() {
- emit androidActivityRequested("Login", true);
+void AndroidHelper::showLoginDialog(QUrl url) {
+ QMap args;
+ args["url"] = url.toString();
+ emit androidActivityRequested("Login", true, args);
}
void AndroidHelper::processURL(const QString &url) {
@@ -56,3 +60,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..f93187e44f 100644
--- a/interface/src/AndroidHelper.h
+++ b/interface/src/AndroidHelper.h
@@ -13,6 +13,8 @@
#define hifi_Android_Helper_h
#include
+#include
+#include
class AndroidHelper : public QObject {
Q_OBJECT
@@ -21,7 +23,7 @@ public:
static AndroidHelper instance;
return instance;
}
- void requestActivity(const QString &activityName, const bool backToScene, QList args = QList());
+ void requestActivity(const QString &activityName, const bool backToScene, QMap args = QMap());
void notifyLoadComplete();
void notifyEnterForeground();
void notifyBeforeEnterBackground();
@@ -29,15 +31,16 @@ public:
void performHapticFeedback(int duration);
void processURL(const QString &url);
+ void notifyHeadsetOn(bool pluggedIn);
AndroidHelper(AndroidHelper const&) = delete;
void operator=(AndroidHelper const&) = delete;
public slots:
- void showLoginDialog();
+ void showLoginDialog(QUrl url);
signals:
- void androidActivityRequested(const QString &activityName, const bool backToScene, QList args = QList());
+ void androidActivityRequested(const QString &activityName, const bool backToScene, QMap args = QMap());
void qtAppLoadComplete();
void enterForeground();
void beforeEnterBackground();
diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp
index 46cebc1661..2cbe996e3c 100644
--- a/interface/src/Application.cpp
+++ b/interface/src/Application.cpp
@@ -269,7 +269,7 @@ class RenderEventHandler : public QObject {
public:
RenderEventHandler() {
// Transfer to a new thread
- moveToNewNamedThread(this, "RenderThread", [this](QThread* renderThread) {
+ moveToNewNamedThread(this, "RenderThread", [](QThread* renderThread) {
hifi::qt::addBlockingForbiddenThread("Render", renderThread);
qApp->_lastTimeRendered.start();
}, std::bind(&RenderEventHandler::initialize, this), QThread::HighestPriority);
@@ -963,7 +963,7 @@ Q_GUI_EXPORT void qt_gl_set_global_share_context(QOpenGLContext *context);
Setting::Handle sessionRunTime{ "sessionRunTime", 0 };
-const float DEFAULT_HMD_TABLET_SCALE_PERCENT = 70.0f;
+const float DEFAULT_HMD_TABLET_SCALE_PERCENT = 60.0f;
const float DEFAULT_DESKTOP_TABLET_SCALE_PERCENT = 75.0f;
const bool DEFAULT_DESKTOP_TABLET_BECOMES_TOOLBAR = true;
const bool DEFAULT_HMD_TABLET_BECOMES_TOOLBAR = false;
@@ -976,7 +976,6 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
_window(new MainWindow(desktop())),
_sessionRunTimer(startupTimer),
_previousSessionCrashed(setupEssentials(argc, argv, runningMarkerExisted)),
- _undoStackScriptingInterface(&_undoStack),
_entitySimulation(new PhysicalEntitySimulation()),
_physicsEngine(new PhysicsEngine(Vectors::ZERO)),
_entityClipboard(new EntityTree()),
@@ -996,7 +995,6 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
_enableProcessOctreeThread(true),
_lastNackTime(usecTimestampNow()),
_lastSendDownstreamAudioStats(usecTimestampNow()),
- _aboutToQuit(false),
_notifiedPacketVersionMismatchThisDomain(false),
_maxOctreePPS(maxOctreePacketsPerSecond.get()),
_lastFaceTrackerUpdate(0),
@@ -1236,7 +1234,8 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
auto dialogsManager = DependencyManager::get();
#if defined(Q_OS_ANDROID)
connect(accountManager.data(), &AccountManager::authRequired, this, []() {
- AndroidHelper::instance().showLoginDialog();
+ auto addressManager = DependencyManager::get();
+ AndroidHelper::instance().showLoginDialog(addressManager->currentAddress());
});
#else
connect(accountManager.data(), &AccountManager::authRequired, dialogsManager.data(), &DialogsManager::showLoginDialog);
@@ -1691,21 +1690,21 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
return DependencyManager::get()->navigationFocused() ? 1 : 0;
});
_applicationStateDevice->setInputVariant(STATE_PLATFORM_WINDOWS, []() -> float {
-#if defined(Q_OS_WIN)
+#if defined(Q_OS_WIN)
return 1;
#else
return 0;
#endif
});
_applicationStateDevice->setInputVariant(STATE_PLATFORM_MAC, []() -> float {
-#if defined(Q_OS_MAC)
+#if defined(Q_OS_MAC)
return 1;
#else
return 0;
#endif
});
_applicationStateDevice->setInputVariant(STATE_PLATFORM_ANDROID, []() -> float {
-#if defined(Q_OS_ANDROID)
+#if defined(Q_OS_ANDROID)
return 1;
#else
return 0;
@@ -1755,14 +1754,22 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
// we can unlock the desktop repositioning code, since all the positions will be
// relative to the desktop size for this plugin
auto offscreenUi = DependencyManager::get();
- offscreenUi->getDesktop()->setProperty("repositionLocked", false);
+ connect(offscreenUi.data(), &OffscreenUi::desktopReady, []() {
+ auto offscreenUi = DependencyManager::get();
+ auto desktop = offscreenUi->getDesktop();
+ if (desktop) {
+ desktop->setProperty("repositionLocked", false);
+ }
+ });
// 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
@@ -2307,7 +2314,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
QTimer* checkLoginTimer = new QTimer(this);
checkLoginTimer->setInterval(CHECK_LOGIN_TIMER);
checkLoginTimer->setSingleShot(true);
- connect(checkLoginTimer, &QTimer::timeout, this, [this]() {
+ connect(checkLoginTimer, &QTimer::timeout, this, []() {
auto accountManager = DependencyManager::get();
auto dialogsManager = DependencyManager::get();
if (!accountManager->isLoggedIn()) {
@@ -2881,9 +2888,10 @@ void Application::initializeUi() {
QUrl{ "hifi/commerce/common/CommerceLightbox.qml" },
QUrl{ "hifi/commerce/common/EmulatedMarketplaceHeader.qml" },
QUrl{ "hifi/commerce/common/FirstUseTutorial.qml" },
- QUrl{ "hifi/commerce/common/SortableListModel.qml" },
QUrl{ "hifi/commerce/common/sendAsset/SendAsset.qml" },
+ QUrl{ "hifi/commerce/common/SortableListModel.qml" },
QUrl{ "hifi/commerce/inspectionCertificate/InspectionCertificate.qml" },
+ QUrl{ "hifi/commerce/marketplaceItemTester/MarketplaceItemTester.qml"},
QUrl{ "hifi/commerce/purchases/PurchasedItem.qml" },
QUrl{ "hifi/commerce/purchases/Purchases.qml" },
QUrl{ "hifi/commerce/wallet/Help.qml" },
@@ -3086,7 +3094,6 @@ void Application::onDesktopRootContextCreated(QQmlContext* surfaceContext) {
surfaceContext->setContextProperty("DialogsManager", _dialogsManagerScriptingInterface);
surfaceContext->setContextProperty("FaceTracker", DependencyManager::get().data());
surfaceContext->setContextProperty("AvatarManager", DependencyManager::get().data());
- surfaceContext->setContextProperty("UndoStack", &_undoStackScriptingInterface);
surfaceContext->setContextProperty("LODManager", DependencyManager::get().data());
surfaceContext->setContextProperty("HMD", DependencyManager::get().data());
surfaceContext->setContextProperty("Scene", DependencyManager::get().data());
@@ -3427,7 +3434,12 @@ void Application::handleSandboxStatus(QNetworkReply* reply) {
int urlIndex = arguments().indexOf(HIFI_URL_COMMAND_LINE_KEY);
QString addressLookupString;
if (urlIndex != -1) {
- addressLookupString = arguments().value(urlIndex + 1);
+ QUrl url(arguments().value(urlIndex + 1));
+ if (url.scheme() == URL_SCHEME_HIFIAPP) {
+ Setting::Handle("startUpApp").set(url.path());
+ } else {
+ addressLookupString = url.toString();
+ }
}
static const QString SENT_TO_PREVIOUS_LOCATION = "previous_location";
@@ -3498,13 +3510,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);
+ }
}
}
@@ -4664,8 +4677,14 @@ void Application::idle() {
checkChangeCursor();
- Stats::getInstance()->updateStats();
- AnimStats::getInstance()->updateStats();
+ auto stats = Stats::getInstance();
+ if (stats) {
+ stats->updateStats();
+ }
+ auto animStats = AnimStats::getInstance();
+ if (animStats) {
+ animStats->updateStats();
+ }
// Normally we check PipelineWarnings, but since idle will often take more than 10ms we only show these idle timing
// details if we're in ExtraDebugging mode. However, the ::update() and its subcomponents will show their timing
@@ -6746,8 +6765,6 @@ void Application::registerScriptEngineWithApplicationServices(ScriptEnginePointe
scriptEngine->registerGlobalObject("AvatarManager", DependencyManager::get().data());
- scriptEngine->registerGlobalObject("UndoStack", &_undoStackScriptingInterface);
-
scriptEngine->registerGlobalObject("LODManager", DependencyManager::get().data());
scriptEngine->registerGlobalObject("Paths", DependencyManager::get().data());
@@ -7674,6 +7691,9 @@ void Application::openUrl(const QUrl& url) const {
if (!url.isEmpty()) {
if (url.scheme() == URL_SCHEME_HIFI) {
DependencyManager::get()->handleLookupString(url.toString());
+ } else if (url.scheme() == URL_SCHEME_HIFIAPP) {
+ QmlCommerce commerce;
+ commerce.openSystemApp(url.path());
} else {
// address manager did not handle - ask QDesktopServices to handle
QDesktopServices::openUrl(url);
diff --git a/interface/src/Application.h b/interface/src/Application.h
index 3bebc60480..f2e3b3953f 100644
--- a/interface/src/Application.h
+++ b/interface/src/Application.h
@@ -23,7 +23,6 @@
#include
#include
-#include
#include
#include
@@ -70,7 +69,6 @@
#include "ui/OctreeStatsDialog.h"
#include "ui/OverlayConductor.h"
#include "ui/overlays/Overlays.h"
-#include "UndoStackScriptingInterface.h"
#include "workload/GameWorkload.h"
@@ -189,7 +187,6 @@ public:
const OctreePacketProcessor& getOctreePacketProcessor() const { return _octreeProcessor; }
QSharedPointer getEntities() const { return DependencyManager::get(); }
- QUndoStack* getUndoStack() { return &_undoStack; }
MainWindow* getWindow() const { return _window; }
EntityTreePointer getEntityClipboard() const { return _entityClipboard; }
EntityEditPacketSender* getEntityEditPacketSender() { return &_entityEditSender; }
@@ -432,7 +429,7 @@ public slots:
void setIsServerlessMode(bool serverlessDomain);
void loadServerlessDomain(QUrl domainURL, bool errorDomain = false);
- void setIsInterstitialMode(bool interstialMode);
+ void setIsInterstitialMode(bool interstitialMode);
void updateVerboseLogging();
@@ -560,6 +557,8 @@ private:
MainWindow* _window;
QElapsedTimer& _sessionRunTimer;
+ bool _aboutToQuit { false };
+
bool _previousSessionCrashed;
DisplayPluginPointer _displayPlugin;
@@ -569,9 +568,6 @@ private:
bool _activatingDisplayPlugin { false };
- QUndoStack _undoStack;
- UndoStackScriptingInterface _undoStackScriptingInterface;
-
uint32_t _renderFrameCount { 0 };
// Frame Rate Measurement
@@ -651,8 +647,6 @@ private:
quint64 _lastNackTime;
quint64 _lastSendDownstreamAudioStats;
- bool _aboutToQuit;
-
bool _notifiedPacketVersionMismatchThisDomain;
ConditionalGuard _settingsGuard;
diff --git a/interface/src/Application_render.cpp b/interface/src/Application_render.cpp
index 6648fa2eb7..a87caeb9a8 100644
--- a/interface/src/Application_render.cpp
+++ b/interface/src/Application_render.cpp
@@ -157,7 +157,10 @@ void Application::paintGL() {
renderArgs._context->enableStereo(false);
{
- Stats::getInstance()->setRenderDetails(renderArgs._details);
+ auto stats = Stats::getInstance();
+ if (stats) {
+ stats->setRenderDetails(renderArgs._details);
+ }
}
uint64_t lastPaintDuration = usecTimestampNow() - lastPaintBegin;
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/Menu.cpp b/interface/src/Menu.cpp
index 7a310e675f..eef14c873e 100644
--- a/interface/src/Menu.cpp
+++ b/interface/src/Menu.cpp
@@ -90,19 +90,6 @@ Menu::Menu() {
// Edit menu ----------------------------------
MenuWrapper* editMenu = addMenu("Edit");
- // Edit > Undo
- QUndoStack* undoStack = qApp->getUndoStack();
- QAction* undoAction = undoStack->createUndoAction(editMenu);
- undoAction->setShortcut(Qt::CTRL | Qt::Key_Z);
- addActionToQMenuAndActionHash(editMenu, undoAction);
-
- // Edit > Redo
- QAction* redoAction = undoStack->createRedoAction(editMenu);
- redoAction->setShortcut(Qt::CTRL | Qt::SHIFT | Qt::Key_Z);
- addActionToQMenuAndActionHash(editMenu, redoAction);
-
- editMenu->addSeparator();
-
// Edit > Cut
auto cutAction = addActionToQMenuAndActionHash(editMenu, "Cut", QKeySequence::Cut);
connect(cutAction, &QAction::triggered, [] {
diff --git a/interface/src/avatar/AvatarActionHold.cpp b/interface/src/avatar/AvatarActionHold.cpp
index dbc82fd70e..230f8aa64b 100644
--- a/interface/src/avatar/AvatarActionHold.cpp
+++ b/interface/src/avatar/AvatarActionHold.cpp
@@ -48,6 +48,10 @@ AvatarActionHold::~AvatarActionHold() {
myAvatar->removeHoldAction(this);
}
}
+ auto ownerEntity = _ownerEntity.lock();
+ if (ownerEntity) {
+ ownerEntity->setTransitingWithAvatar(false);
+ }
#if WANT_DEBUG
qDebug() << "AvatarActionHold::~AvatarActionHold" << (void*)this;
@@ -131,6 +135,15 @@ bool AvatarActionHold::getTarget(float deltaTimeStep, glm::quat& rotation, glm::
glm::vec3 palmPosition;
glm::quat palmRotation;
+ bool isTransitingWithAvatar = holdingAvatar->getTransit()->isTransiting();
+ if (isTransitingWithAvatar != _isTransitingWithAvatar) {
+ _isTransitingWithAvatar = isTransitingWithAvatar;
+ auto ownerEntity = _ownerEntity.lock();
+ if (ownerEntity) {
+ ownerEntity->setTransitingWithAvatar(_isTransitingWithAvatar);
+ }
+ }
+
if (holdingAvatar->isMyAvatar()) {
std::shared_ptr myAvatar = avatarManager->getMyAvatar();
@@ -404,11 +417,14 @@ bool AvatarActionHold::updateArguments(QVariantMap arguments) {
_kinematicSetVelocity = kinematicSetVelocity;
_ignoreIK = ignoreIK;
_active = true;
+
+ auto myAvatar = DependencyManager::get()->getMyAvatar();
auto ownerEntity = _ownerEntity.lock();
if (ownerEntity) {
ownerEntity->setDynamicDataDirty(true);
- ownerEntity->setDynamicDataNeedsTransmit(true);
+ ownerEntity->setDynamicDataNeedsTransmit(true);
+ ownerEntity->setTransitingWithAvatar(myAvatar->getTransit()->isTransiting());
}
});
}
diff --git a/interface/src/avatar/AvatarActionHold.h b/interface/src/avatar/AvatarActionHold.h
index 6acc71b45c..ddc5808d67 100644
--- a/interface/src/avatar/AvatarActionHold.h
+++ b/interface/src/avatar/AvatarActionHold.h
@@ -59,6 +59,8 @@ private:
bool _kinematicSetVelocity { false };
bool _previousSet { false };
bool _ignoreIK { false };
+ bool _isTransitingWithAvatar { false };
+
glm::vec3 _previousPositionalTarget;
glm::quat _previousRotationalTarget;
diff --git a/interface/src/avatar/AvatarManager.cpp b/interface/src/avatar/AvatarManager.cpp
index 1faf17ea9a..9b5aa4e415 100644
--- a/interface/src/avatar/AvatarManager.cpp
+++ b/interface/src/avatar/AvatarManager.cpp
@@ -78,6 +78,15 @@ AvatarManager::AvatarManager(QObject* parent) :
removeAvatar(nodeID, KillAvatarReason::AvatarIgnored);
}
});
+
+ const float AVATAR_TRANSIT_TRIGGER_DISTANCE = 1.0f;
+ const int AVATAR_TRANSIT_FRAME_COUNT = 11; // Based on testing
+ const int AVATAR_TRANSIT_FRAMES_PER_METER = 1; // Based on testing
+
+ _transitConfig._totalFrames = AVATAR_TRANSIT_FRAME_COUNT;
+ _transitConfig._triggerDistance = AVATAR_TRANSIT_TRIGGER_DISTANCE;
+ _transitConfig._framesPerMeter = AVATAR_TRANSIT_FRAMES_PER_METER;
+ _transitConfig._isDistanceBased = true;
}
AvatarSharedPointer AvatarManager::addAvatar(const QUuid& sessionUUID, const QWeakPointer& mixerWeakPointer) {
@@ -129,6 +138,10 @@ void AvatarManager::updateMyAvatar(float deltaTime) {
bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings);
PerformanceWarning warn(showWarnings, "AvatarManager::updateMyAvatar()");
+ AvatarTransit::Status status = _myAvatar->updateTransit(deltaTime, _myAvatar->getNextPosition(), _transitConfig);
+ bool sendFirstTransitPackage = (status == AvatarTransit::Status::START_TRANSIT);
+ bool blockTransitData = (status == AvatarTransit::Status::TRANSITING);
+
_myAvatar->update(deltaTime);
render::Transaction transaction;
_myAvatar->updateRenderItem(transaction);
@@ -137,9 +150,13 @@ void AvatarManager::updateMyAvatar(float deltaTime) {
quint64 now = usecTimestampNow();
quint64 dt = now - _lastSendAvatarDataTime;
- if (dt > MIN_TIME_BETWEEN_MY_AVATAR_DATA_SENDS && !_myAvatarDataPacketsPaused) {
+
+ if (sendFirstTransitPackage || (dt > MIN_TIME_BETWEEN_MY_AVATAR_DATA_SENDS && !_myAvatarDataPacketsPaused && !blockTransitData)) {
// send head/hand data to the avatar mixer and voxel server
PerformanceTimer perfTimer("send");
+ if (sendFirstTransitPackage) {
+ _myAvatar->overrideNextPackagePositionData(_myAvatar->getTransit()->getEndPosition());
+ }
_myAvatar->sendAvatarDataPacket();
_lastSendAvatarDataTime = now;
_myAvatarSendRate.increment();
@@ -234,11 +251,13 @@ void AvatarManager::updateOtherAvatars(float deltaTime) {
const SortableAvatar& sortData = *it;
const auto avatar = std::static_pointer_cast(sortData.getAvatar());
- // TODO: to help us scale to more avatars it would be nice to not have to poll orb state here
- // if the geometry is loaded then turn off the orb
+ // TODO: to help us scale to more avatars it would be nice to not have to poll this stuff every update
if (avatar->getSkeletonModel()->isLoaded()) {
// remove the orb if it is there
avatar->removeOrb();
+ if (avatar->needsPhysicsUpdate()) {
+ _avatarsToChangeInPhysics.insert(avatar);
+ }
} else {
avatar->updateOrbPosition();
}
@@ -256,6 +275,7 @@ void AvatarManager::updateOtherAvatars(float deltaTime) {
if (inView && avatar->hasNewJointData()) {
numAvatarsUpdated++;
}
+ avatar->_transit.update(deltaTime, avatar->_globalPosition, _transitConfig);
avatar->simulate(deltaTime, inView);
avatar->updateRenderItem(renderTransaction);
avatar->updateSpaceProxy(workloadTransaction);
@@ -456,31 +476,37 @@ void AvatarManager::handleRemovedAvatar(const AvatarSharedPointer& removedAvatar
}
void AvatarManager::clearOtherAvatars() {
- // Remove other avatars from the world but don't actually remove them from _avatarHash
- // each will either be removed on timeout or will re-added to the world on receipt of update.
- const render::ScenePointer& scene = qApp->getMain3DScene();
- render::Transaction transaction;
-
- QReadLocker locker(&_hashLock);
- AvatarHash::iterator avatarIterator = _avatarHash.begin();
- while (avatarIterator != _avatarHash.end()) {
- auto avatar = std::static_pointer_cast(avatarIterator.value());
- if (avatar != _myAvatar) {
- handleRemovedAvatar(avatar);
- avatarIterator = _avatarHash.erase(avatarIterator);
- } else {
- ++avatarIterator;
- }
- }
- assert(scene);
- scene->enqueueTransaction(transaction);
_myAvatar->clearLookAtTargetAvatar();
+
+ // setup a vector of removed avatars outside the scope of the hash lock
+ std::vector removedAvatars;
+
+ {
+ QWriteLocker locker(&_hashLock);
+
+ removedAvatars.reserve(_avatarHash.size());
+
+ auto avatarIterator = _avatarHash.begin();
+ while (avatarIterator != _avatarHash.end()) {
+ auto avatar = std::static_pointer_cast(avatarIterator.value());
+ if (avatar != _myAvatar) {
+ removedAvatars.push_back(avatar);
+ avatarIterator = _avatarHash.erase(avatarIterator);
+ } else {
+ ++avatarIterator;
+ }
+ }
+ }
+
+ for (auto& av : removedAvatars) {
+ handleRemovedAvatar(av);
+ }
}
void AvatarManager::deleteAllAvatars() {
assert(_avatarsToChangeInPhysics.empty());
- QReadLocker locker(&_hashLock);
+ QWriteLocker locker(&_hashLock);
AvatarHash::iterator avatarIterator = _avatarHash.begin();
while (avatarIterator != _avatarHash.end()) {
auto avatar = std::static_pointer_cast(avatarIterator.value());
@@ -803,7 +829,7 @@ void AvatarManager::setAvatarSortCoefficient(const QString& name, const QScriptV
}
}
- QVariantMap AvatarManager::getPalData(const QList specificAvatarIdentifiers) {
+QVariantMap AvatarManager::getPalData(const QList specificAvatarIdentifiers) {
QJsonArray palData;
auto avatarMap = getHashCopy();
diff --git a/interface/src/avatar/AvatarManager.h b/interface/src/avatar/AvatarManager.h
index 306ba6f39b..3ed156f673 100644
--- a/interface/src/avatar/AvatarManager.h
+++ b/interface/src/avatar/AvatarManager.h
@@ -31,6 +31,7 @@
#include "MyAvatar.h"
#include "OtherAvatar.h"
+
using SortedAvatar = std::pair>;
/**jsdoc
@@ -204,7 +205,12 @@ private:
void simulateAvatarFades(float deltaTime);
AvatarSharedPointer newSharedAvatar() override;
- void handleRemovedAvatar(const AvatarSharedPointer& removedAvatar, KillAvatarReason removalReason = KillAvatarReason::NoReason) override;
+
+ // called only from the AvatarHashMap thread - cannot be called while this thread holds the
+ // hash lock, since handleRemovedAvatar needs a write lock on the entity tree and the entity tree
+ // frequently grabs a read lock on the hash to get a given avatar by ID
+ void handleRemovedAvatar(const AvatarSharedPointer& removedAvatar,
+ KillAvatarReason removalReason = KillAvatarReason::NoReason) override;
QVector _avatarsToFade;
@@ -227,6 +233,8 @@ private:
mutable std::mutex _spaceLock;
workload::SpacePointer _space;
std::vector _spaceProxiesToDelete;
+
+ AvatarTransit::TransitConfig _transitConfig;
};
#endif // hifi_AvatarManager_h
diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp
index c47cfdb383..497ea351a0 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),
@@ -114,11 +116,27 @@ MyAvatar::MyAvatar(QThread* thread) :
_bodySensorMatrix(),
_goToPending(false),
_goToSafe(true),
+ _goToFeetAjustment(false),
_goToPosition(),
_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));
@@ -481,7 +499,7 @@ void MyAvatar::update(float deltaTime) {
setCurrentStandingHeight(computeStandingHeightMode(getControllerPoseInAvatarFrame(controller::Action::HEAD)));
setAverageHeadRotation(computeAverageHeadRotation(getControllerPoseInAvatarFrame(controller::Action::HEAD)));
- if (_drawAverageFacingEnabled) {
+ if (_drawAverageFacingEnabled) {
auto sensorHeadPose = getControllerPoseInSensorFrame(controller::Action::HEAD);
glm::vec3 worldHeadPos = transformPoint(getSensorToWorldMatrix(), sensorHeadPose.getTranslation());
glm::vec3 worldFacingAverage = transformVectorFast(getSensorToWorldMatrix(), glm::vec3(_headControllerFacingMovingAverage.x, 0.0f, _headControllerFacingMovingAverage.y));
@@ -509,6 +527,12 @@ void MyAvatar::update(float deltaTime) {
_physicsSafetyPending = getCollisionsEnabled();
_characterController.recomputeFlying(); // In case we've gone to into the sky.
}
+ if (_goToFeetAjustment && _skeletonModelLoaded) {
+ auto feetAjustment = getWorldPosition() - getWorldFeetPosition();
+ _goToPosition = getWorldPosition() + feetAjustment;
+ setWorldPosition(_goToPosition);
+ _goToFeetAjustment = false;
+ }
if (_physicsSafetyPending && qApp->isPhysicsEnabled() && _characterController.isEnabledAndReady()) {
// When needed and ready, arrange to check and fix.
_physicsSafetyPending = false;
@@ -615,9 +639,8 @@ void MyAvatar::updateChildCauterization(SpatiallyNestablePointer object, bool ca
void MyAvatar::simulate(float deltaTime) {
PerformanceTimer perfTimer("simulate");
-
animateScaleChanges(deltaTime);
-
+
setFlyingEnabled(getFlyingEnabled());
if (_cauterizationNeedsUpdate) {
@@ -905,6 +928,7 @@ void MyAvatar::updateSensorToWorldMatrix() {
updateJointFromController(controller::Action::RIGHT_HAND, _controllerRightHandMatrixCache);
if (hasSensorToWorldScaleChanged) {
+ setTransitScale(sensorToWorldScale);
emit sensorToWorldScaleChanged(sensorToWorldScale);
}
@@ -1135,88 +1159,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 +1330,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 +1428,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();
@@ -1748,6 +1735,7 @@ void MyAvatar::setSkeletonModelURL(const QUrl& skeletonModelURL) {
_headBoneSet.clear();
_cauterizationNeedsUpdate = true;
+ _skeletonModelLoaded = false;
std::shared_ptr skeletonConnection = std::make_shared();
*skeletonConnection = QObject::connect(_skeletonModel.get(), &SkeletonModel::skeletonLoaded, [this, skeletonModelChangeCount, skeletonConnection]() {
@@ -1765,6 +1753,7 @@ void MyAvatar::setSkeletonModelURL(const QUrl& skeletonModelURL) {
_skeletonModel->setCauterizeBoneSet(_headBoneSet);
_fstAnimGraphOverrideUrl = _skeletonModel->getGeometry()->getAnimGraphOverrideUrl();
initAnimGraph();
+ _skeletonModelLoaded = true;
}
QObject::disconnect(*skeletonConnection);
});
@@ -2899,10 +2888,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 +2900,6 @@ void MyAvatar::restrictScaleFromDomainSettings(const QJsonObject& domainSettings
setModelScale(_targetScale);
rebuildCollisionShape();
- settings.endGroup();
_haveReceivedHeightLimitsFromDomain = true;
}
@@ -2925,10 +2910,7 @@ void MyAvatar::leaveDomain() {
}
void MyAvatar::saveAvatarScale() {
- Settings settings;
- settings.beginGroup("Avatar");
- settings.setValue("scale", _targetScale);
- settings.endGroup();
+ _scaleSetting.set(_targetScale);
}
void MyAvatar::clearScaleRestriction() {
@@ -2972,46 +2954,10 @@ void MyAvatar::goToLocation(const QVariant& propertiesVar) {
}
void MyAvatar::goToFeetLocation(const glm::vec3& newPosition,
- bool hasOrientation, const glm::quat& newOrientation,
- bool shouldFaceLocation) {
-
- qCDebug(interfaceapp).nospace() << "MyAvatar goToFeetLocation - moving to " << newPosition.x << ", "
- << newPosition.y << ", " << newPosition.z;
-
- ShapeInfo shapeInfo;
- computeShapeInfo(shapeInfo);
- glm::vec3 halfExtents = shapeInfo.getHalfExtents();
- glm::vec3 localFeetPos = shapeInfo.getOffset() - glm::vec3(0.0f, halfExtents.y + halfExtents.x, 0.0f);
- glm::mat4 localFeet = createMatFromQuatAndPos(Quaternions::IDENTITY, localFeetPos);
-
- glm::mat4 worldFeet = createMatFromQuatAndPos(Quaternions::IDENTITY, newPosition);
-
- glm::mat4 avatarMat = worldFeet * glm::inverse(localFeet);
-
- glm::vec3 adjustedPosition = extractTranslation(avatarMat);
-
- _goToPending = true;
- _goToPosition = adjustedPosition;
- _goToOrientation = getWorldOrientation();
- if (hasOrientation) {
- qCDebug(interfaceapp).nospace() << "MyAvatar goToFeetLocation - new orientation is "
- << newOrientation.x << ", " << newOrientation.y << ", " << newOrientation.z << ", " << newOrientation.w;
-
- // orient the user to face the target
- glm::quat quatOrientation = cancelOutRollAndPitch(newOrientation);
-
- if (shouldFaceLocation) {
- quatOrientation = newOrientation * glm::angleAxis(PI, Vectors::UP);
-
- // move the user a couple units away
- const float DISTANCE_TO_USER = 2.0f;
- _goToPosition = adjustedPosition - quatOrientation * IDENTITY_FORWARD * DISTANCE_TO_USER;
- }
-
- _goToOrientation = quatOrientation;
- }
-
- emit transformChanged();
+ bool hasOrientation, const glm::quat& newOrientation,
+ bool shouldFaceLocation) {
+ _goToFeetAjustment = true;
+ goToLocation(newPosition, hasOrientation, newOrientation, shouldFaceLocation);
}
void MyAvatar::goToLocation(const glm::vec3& newPosition,
diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h
index 139f1f6ea2..c861ee48a4 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();
@@ -1114,6 +1115,8 @@ public:
virtual QVariantList getAttachmentsVariant() const override;
virtual void setAttachmentsVariant(const QVariantList& variant) override;
+ glm::vec3 getNextPosition() { return _goToPending ? _goToPosition : getWorldPosition(); };
+
public slots:
/**jsdoc
@@ -1731,6 +1734,7 @@ private:
bool _goToPending { false };
bool _physicsSafetyPending { false };
bool _goToSafe { true };
+ bool _goToFeetAjustment { false };
glm::vec3 _goToPosition;
glm::quat _goToOrientation;
@@ -1806,6 +1810,24 @@ private:
bool _haveReceivedHeightLimitsFromDomain { false };
int _disableHandTouchCount { 0 };
+ bool _skeletonModelLoaded { false };
+
+ 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/avatar/OtherAvatar.cpp b/interface/src/avatar/OtherAvatar.cpp
index 29fa98fd1d..625998eb95 100644
--- a/interface/src/avatar/OtherAvatar.cpp
+++ b/interface/src/avatar/OtherAvatar.cpp
@@ -119,6 +119,11 @@ bool OtherAvatar::shouldBeInPhysicsSimulation() const {
return (_workloadRegion < workload::Region::R3 && !isDead());
}
+bool OtherAvatar::needsPhysicsUpdate() const {
+ constexpr uint32_t FLAGS_OF_INTEREST = Simulation::DIRTY_SHAPE | Simulation::DIRTY_MASS | Simulation::DIRTY_POSITION;
+ return (_motionState && (bool)(_motionState->getIncomingDirtyFlags() & FLAGS_OF_INTEREST));
+}
+
void OtherAvatar::rebuildCollisionShape() {
if (_motionState) {
_motionState->addDirtyFlags(Simulation::DIRTY_SHAPE | Simulation::DIRTY_MASS);
diff --git a/interface/src/avatar/OtherAvatar.h b/interface/src/avatar/OtherAvatar.h
index 94b98f2747..5b72815757 100644
--- a/interface/src/avatar/OtherAvatar.h
+++ b/interface/src/avatar/OtherAvatar.h
@@ -43,6 +43,7 @@ public:
void setWorkloadRegion(uint8_t region);
bool shouldBeInPhysicsSimulation() const;
+ bool needsPhysicsUpdate() const;
friend AvatarManager;
diff --git a/interface/src/commerce/QmlCommerce.cpp b/interface/src/commerce/QmlCommerce.cpp
index 06da18148f..aa39fdc1b9 100644
--- a/interface/src/commerce/QmlCommerce.cpp
+++ b/interface/src/commerce/QmlCommerce.cpp
@@ -47,6 +47,54 @@ QmlCommerce::QmlCommerce() {
_appsPath = PathUtils::getAppDataPath() + "Apps/";
}
+
+
+
+void QmlCommerce::openSystemApp(const QString& appName) {
+ static QMap systemApps {
+ {"GOTO", "hifi/tablet/TabletAddressDialog.qml"},
+ {"PEOPLE", "hifi/Pal.qml"},
+ {"WALLET", "hifi/commerce/wallet/Wallet.qml"},
+ {"MARKET", "/marketplace.html"}
+ };
+
+ static QMap systemInject{
+ {"MARKET", "/scripts/system/html/js/marketplacesInject.js"}
+ };
+
+
+ auto tablet = dynamic_cast(
+ DependencyManager::get()->getTablet("com.highfidelity.interface.tablet.system"));
+
+ QMap::const_iterator appPathIter = systemApps.find(appName);
+ if (appPathIter != systemApps.end()) {
+ if (appPathIter->contains(".qml", Qt::CaseInsensitive)) {
+ tablet->loadQMLSource(*appPathIter);
+ }
+ else if (appPathIter->contains(".html", Qt::CaseInsensitive)) {
+ QMap::const_iterator injectIter = systemInject.find(appName);
+ if (appPathIter == systemInject.end()) {
+ tablet->gotoWebScreen(NetworkingConstants::METAVERSE_SERVER_URL().toString() + *appPathIter);
+ }
+ else {
+ QString inject = "file:///" + qApp->applicationDirPath() + *injectIter;
+ tablet->gotoWebScreen(NetworkingConstants::METAVERSE_SERVER_URL().toString() + *appPathIter, inject);
+ }
+ }
+ else {
+ qCDebug(commerce) << "Attempted to open unknown type of URL!";
+ return;
+ }
+ }
+ else {
+ qCDebug(commerce) << "Attempted to open unknown APP!";
+ return;
+ }
+
+ DependencyManager::get()->openTablet();
+}
+
+
void QmlCommerce::getWalletStatus() {
auto wallet = DependencyManager::get();
wallet->getWalletStatus();
@@ -199,12 +247,18 @@ void QmlCommerce::transferAssetToUsername(const QString& username,
}
void QmlCommerce::replaceContentSet(const QString& itemHref, const QString& certificateID) {
- auto ledger = DependencyManager::get();
- ledger->updateLocation(certificateID, DependencyManager::get()->getPlaceName(), true);
+ if (!certificateID.isEmpty()) {
+ auto ledger = DependencyManager::get();
+ ledger->updateLocation(
+ certificateID,
+ DependencyManager::get()->getPlaceName(),
+ true);
+ }
qApp->replaceDomainContent(itemHref);
- QJsonObject messageProperties = { { "status", "SuccessfulRequestToReplaceContent" }, { "content_set_url", itemHref } };
+ QJsonObject messageProperties = {
+ { "status", "SuccessfulRequestToReplaceContent" },
+ { "content_set_url", itemHref } };
UserActivityLogger::getInstance().logAction("replace_domain_content", messageProperties);
-
emit contentSetChanged(itemHref);
}
@@ -228,6 +282,7 @@ QString QmlCommerce::getInstalledApps(const QString& justInstalledAppID) {
// Thus, we protect against deleting the .app.json from the user's disk (below)
// by skipping that check for the app we just installed.
if ((justInstalledAppID != "") && ((justInstalledAppID + ".app.json") == appFileName)) {
+ installedAppsFromMarketplace += appFileName + ",";
continue;
}
@@ -353,7 +408,7 @@ bool QmlCommerce::openApp(const QString& itemHref) {
// Read from the file to know what .html or .qml document to open
QFile appFile(_appsPath + "/" + appHref.fileName());
if (!appFile.open(QIODevice::ReadOnly)) {
- qCDebug(commerce) << "Couldn't open local .app.json file.";
+ qCDebug(commerce) << "Couldn't open local .app.json file:" << appFile;
return false;
}
QJsonDocument appFileJsonDocument = QJsonDocument::fromJson(appFile.readAll());
diff --git a/interface/src/commerce/QmlCommerce.h b/interface/src/commerce/QmlCommerce.h
index 79d8e82e71..bee30e1b62 100644
--- a/interface/src/commerce/QmlCommerce.h
+++ b/interface/src/commerce/QmlCommerce.h
@@ -24,6 +24,7 @@ class QmlCommerce : public QObject {
public:
QmlCommerce();
+ void openSystemApp(const QString& appPath);
signals:
void walletStatusResult(uint walletStatus);
diff --git a/interface/src/main.cpp b/interface/src/main.cpp
index 3e3c9da148..d9396ae4d1 100644
--- a/interface/src/main.cpp
+++ b/interface/src/main.cpp
@@ -176,7 +176,7 @@ int main(int argc, const char* argv[]) {
if (socket.waitForConnected(LOCAL_SERVER_TIMEOUT_MS)) {
if (parser.isSet(urlOption)) {
QUrl url = QUrl(parser.value(urlOption));
- if (url.isValid() && url.scheme() == URL_SCHEME_HIFI) {
+ if (url.isValid() && (url.scheme() == URL_SCHEME_HIFI || url.scheme() == URL_SCHEME_HIFIAPP)) {
qDebug() << "Writing URL to local socket";
socket.write(url.toString().toUtf8());
if (!socket.waitForBytesWritten(5000)) {
diff --git a/interface/src/raypick/LaserPointer.cpp b/interface/src/raypick/LaserPointer.cpp
index 5fbe3a90b5..3c66923b4e 100644
--- a/interface/src/raypick/LaserPointer.cpp
+++ b/interface/src/raypick/LaserPointer.cpp
@@ -35,6 +35,14 @@ void LaserPointer::editRenderStatePath(const std::string& state, const QVariant&
}
}
+PickResultPointer LaserPointer::getPickResultCopy(const PickResultPointer& pickResult) const {
+ auto rayPickResult = std::dynamic_pointer_cast(pickResult);
+ if (!rayPickResult) {
+ return std::make_shared();
+ }
+ return std::make_shared(*rayPickResult.get());
+}
+
QVariantMap LaserPointer::toVariantMap() const {
QVariantMap qVariantMap;
diff --git a/interface/src/raypick/LaserPointer.h b/interface/src/raypick/LaserPointer.h
index c0ac3259d9..b391f60f85 100644
--- a/interface/src/raypick/LaserPointer.h
+++ b/interface/src/raypick/LaserPointer.h
@@ -47,6 +47,8 @@ public:
static std::shared_ptr buildRenderState(const QVariantMap& propMap);
protected:
+ PickResultPointer getPickResultCopy(const PickResultPointer& pickResult) const override;
+
void editRenderStatePath(const std::string& state, const QVariant& pathProps) override;
glm::vec3 getPickOrigin(const PickResultPointer& pickResult) const override;
diff --git a/interface/src/raypick/ParabolaPointer.cpp b/interface/src/raypick/ParabolaPointer.cpp
index 888b3ddbe8..33fa8738d9 100644
--- a/interface/src/raypick/ParabolaPointer.cpp
+++ b/interface/src/raypick/ParabolaPointer.cpp
@@ -30,6 +30,14 @@ ParabolaPointer::ParabolaPointer(const QVariant& rayProps, const RenderStateMap&
{
}
+PickResultPointer ParabolaPointer::getPickResultCopy(const PickResultPointer& pickResult) const {
+ auto parabolaPickResult = std::dynamic_pointer_cast(pickResult);
+ if (!parabolaPickResult) {
+ return std::make_shared();
+ }
+ return std::make_shared(*parabolaPickResult.get());
+}
+
void ParabolaPointer::editRenderStatePath(const std::string& state, const QVariant& pathProps) {
auto renderState = std::static_pointer_cast(_renderStates[state]);
if (renderState) {
@@ -382,9 +390,8 @@ void ParabolaPointer::RenderState::ParabolaRenderItem::updateBounds() {
const gpu::PipelinePointer ParabolaPointer::RenderState::ParabolaRenderItem::getParabolaPipeline() {
if (!_parabolaPipeline || !_transparentParabolaPipeline) {
- gpu::ShaderPointer program = gpu::Shader::createProgram(shader::render_utils::program::parabola);
-
{
+ gpu::ShaderPointer program = gpu::Shader::createProgram(shader::render_utils::program::parabola);
auto state = std::make_shared();
state->setDepthTest(true, true, gpu::LESS_EQUAL);
state->setBlendFunction(false,
@@ -396,6 +403,7 @@ const gpu::PipelinePointer ParabolaPointer::RenderState::ParabolaRenderItem::get
}
{
+ gpu::ShaderPointer program = gpu::Shader::createProgram(shader::render_utils::program::parabola_translucent);
auto state = std::make_shared();
state->setDepthTest(true, true, gpu::LESS_EQUAL);
state->setBlendFunction(true,
diff --git a/interface/src/raypick/ParabolaPointer.h b/interface/src/raypick/ParabolaPointer.h
index 526abe3b0d..8fb864c07b 100644
--- a/interface/src/raypick/ParabolaPointer.h
+++ b/interface/src/raypick/ParabolaPointer.h
@@ -102,6 +102,8 @@ public:
static std::shared_ptr buildRenderState(const QVariantMap& propMap);
protected:
+ virtual PickResultPointer getPickResultCopy(const PickResultPointer& pickResult) const override;
+
void editRenderStatePath(const std::string& state, const QVariant& pathProps) override;
glm::vec3 getPickOrigin(const PickResultPointer& pickResult) const override;
diff --git a/interface/src/raypick/PathPointer.h b/interface/src/raypick/PathPointer.h
index b3638d1f7d..6d5abdeec0 100644
--- a/interface/src/raypick/PathPointer.h
+++ b/interface/src/raypick/PathPointer.h
@@ -27,6 +27,7 @@ class StartEndRenderState {
public:
StartEndRenderState() {}
StartEndRenderState(const OverlayID& startID, const OverlayID& endID);
+ virtual ~StartEndRenderState() {}
const OverlayID& getStartID() const { return _startID; }
const OverlayID& getEndID() const { return _endID; }
diff --git a/interface/src/raypick/StylusPointer.cpp b/interface/src/raypick/StylusPointer.cpp
index 06e3e52d21..b648e125bf 100644
--- a/interface/src/raypick/StylusPointer.cpp
+++ b/interface/src/raypick/StylusPointer.cpp
@@ -147,6 +147,14 @@ bool StylusPointer::shouldTrigger(const PickResultPointer& pickResult) {
return false;
}
+PickResultPointer StylusPointer::getPickResultCopy(const PickResultPointer& pickResult) const {
+ auto stylusPickResult = std::dynamic_pointer_cast(pickResult);
+ if (!stylusPickResult) {
+ return std::make_shared();
+ }
+ return std::make_shared(*stylusPickResult.get());
+}
+
Pointer::PickedObject StylusPointer::getHoveredObject(const PickResultPointer& pickResult) {
auto stylusPickResult = std::static_pointer_cast(pickResult);
if (!stylusPickResult) {
diff --git a/interface/src/raypick/StylusPointer.h b/interface/src/raypick/StylusPointer.h
index 4095acb529..ff60fd78e5 100644
--- a/interface/src/raypick/StylusPointer.h
+++ b/interface/src/raypick/StylusPointer.h
@@ -42,6 +42,7 @@ protected:
Buttons getPressedButtons(const PickResultPointer& pickResult) override;
bool shouldHover(const PickResultPointer& pickResult) override;
bool shouldTrigger(const PickResultPointer& pickResult) override;
+ virtual PickResultPointer getPickResultCopy(const PickResultPointer& pickResult) const override;
PointerEvent buildPointerEvent(const PickedObject& target, const PickResultPointer& pickResult, const std::string& button = "", bool hover = true) override;
diff --git a/interface/src/scripting/HMDScriptingInterface.h b/interface/src/scripting/HMDScriptingInterface.h
index a8fec839eb..78744b320b 100644
--- a/interface/src/scripting/HMDScriptingInterface.h
+++ b/interface/src/scripting/HMDScriptingInterface.h
@@ -57,18 +57,24 @@ class QScriptEngine;
* @property {Uuid} tabletScreenID - The UUID of the tablet's screen overlay.
* @property {Uuid} homeButtonID - The UUID of the tablet's "home" button overlay.
* @property {Uuid} homeButtonHighlightID - The UUID of the tablet's "home" button highlight overlay.
+ * @property {Uuid} miniTabletID - The UUID of the mini tablet's body model overlay. null
if not in HMD mode.
+ * @property {Uuid} miniTabletScreenID - The UUID of the mini tablet's screen overlay. null
if not in HMD mode.
+ * @property {number} miniTabletHand - The hand that the mini tablet is displayed on: 0
for left hand,
+ * 1
for right hand, -1
if not in HMD mode.
*/
class HMDScriptingInterface : public AbstractHMDScriptingInterface, public Dependency {
Q_OBJECT
Q_PROPERTY(glm::vec3 position READ getPosition)
Q_PROPERTY(glm::quat orientation READ getOrientation)
- Q_PROPERTY(bool mounted READ isMounted NOTIFY mountedChanged)
Q_PROPERTY(bool showTablet READ getShouldShowTablet)
Q_PROPERTY(bool tabletContextualMode READ getTabletContextualMode)
Q_PROPERTY(QUuid tabletID READ getCurrentTabletFrameID WRITE setCurrentTabletFrameID)
Q_PROPERTY(QUuid homeButtonID READ getCurrentHomeButtonID WRITE setCurrentHomeButtonID)
Q_PROPERTY(QUuid tabletScreenID READ getCurrentTabletScreenID WRITE setCurrentTabletScreenID)
Q_PROPERTY(QUuid homeButtonHighlightID READ getCurrentHomeButtonHighlightID WRITE setCurrentHomeButtonHighlightID)
+ Q_PROPERTY(QUuid miniTabletID READ getCurrentMiniTabletID WRITE setCurrentMiniTabletID)
+ Q_PROPERTY(QUuid miniTabletScreenID READ getCurrentMiniTabletScreenID WRITE setCurrentMiniTabletScreenID)
+ Q_PROPERTY(int miniTabletHand READ getCurrentMiniTabletHand WRITE setCurrentMiniTabletHand)
public:
@@ -350,7 +356,7 @@ public:
static QScriptValue getHUDLookAtPosition2D(QScriptContext* context, QScriptEngine* engine);
static QScriptValue getHUDLookAtPosition3D(QScriptContext* context, QScriptEngine* engine);
- bool isMounted() const;
+ bool isMounted() const override;
void toggleShouldShowTablet();
void setShouldShowTablet(bool value);
@@ -369,6 +375,15 @@ public:
void setCurrentTabletScreenID(QUuid tabletID) { _tabletScreenID = tabletID; }
QUuid getCurrentTabletScreenID() const { return _tabletScreenID; }
+ void setCurrentMiniTabletID(QUuid miniTabletID) { _miniTabletID = miniTabletID; }
+ QUuid getCurrentMiniTabletID() const { return _miniTabletID; }
+
+ void setCurrentMiniTabletScreenID(QUuid miniTabletScreenID) { _miniTabletScreenID = miniTabletScreenID; }
+ QUuid getCurrentMiniTabletScreenID() const { return _miniTabletScreenID; }
+
+ void setCurrentMiniTabletHand(int miniTabletHand) { _miniTabletHand = miniTabletHand; }
+ int getCurrentMiniTabletHand() const { return _miniTabletHand; }
+
private:
bool _showTablet { false };
bool _tabletContextualMode { false };
@@ -377,6 +392,9 @@ private:
QUuid _homeButtonID;
QUuid _tabletEntityID;
QUuid _homeButtonHighlightID;
+ QUuid _miniTabletID;
+ QUuid _miniTabletScreenID;
+ int _miniTabletHand { -1 };
// Get the position of the HMD
glm::vec3 getPosition() const;
diff --git a/interface/src/scripting/WindowScriptingInterface.cpp b/interface/src/scripting/WindowScriptingInterface.cpp
index e3ae65aee1..2e679e0947 100644
--- a/interface/src/scripting/WindowScriptingInterface.cpp
+++ b/interface/src/scripting/WindowScriptingInterface.cpp
@@ -134,7 +134,8 @@ void WindowScriptingInterface::openUrl(const QUrl& url) {
DependencyManager::get()->handleLookupString(url.toString());
} else {
#if defined(Q_OS_ANDROID)
- QList args = { url.toString() };
+ QMap args;
+ args["url"] = url.toString();
AndroidHelper::instance().requestActivity("WebView", true, args);
#else
// address manager did not handle - ask QDesktopServices to handle
@@ -180,6 +181,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 3827406729..ddd7159f23 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();
@@ -758,6 +759,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/interface/src/ui/OverlayConductor.cpp b/interface/src/ui/OverlayConductor.cpp
index e27001567f..da4fdaba44 100644
--- a/interface/src/ui/OverlayConductor.cpp
+++ b/interface/src/ui/OverlayConductor.cpp
@@ -75,7 +75,14 @@ void OverlayConductor::centerUI() {
void OverlayConductor::update(float dt) {
auto offscreenUi = DependencyManager::get();
- bool currentVisible = !offscreenUi->getDesktop()->property("pinned").toBool();
+ if (!offscreenUi) {
+ return;
+ }
+ auto desktop = offscreenUi->getDesktop();
+ if (!desktop) {
+ return;
+ }
+ bool currentVisible = !desktop->property("pinned").toBool();
auto myAvatar = DependencyManager::get()->getMyAvatar();
// centerUI when hmd mode is first enabled and mounted
diff --git a/interface/src/ui/overlays/Circle3DOverlay.cpp b/interface/src/ui/overlays/Circle3DOverlay.cpp
index 2e06229276..1d418d966e 100644
--- a/interface/src/ui/overlays/Circle3DOverlay.cpp
+++ b/interface/src/ui/overlays/Circle3DOverlay.cpp
@@ -74,7 +74,7 @@ void Circle3DOverlay::render(RenderArgs* args) {
const float FULL_CIRCLE = 360.0f;
const float SLICES = 180.0f; // The amount of segment to create the circle
- const float SLICE_ANGLE = FULL_CIRCLE / SLICES;
+ const float SLICE_ANGLE_RADIANS = glm::radians(FULL_CIRCLE / SLICES);
const float MAX_COLOR = 255.0f;
auto geometryCache = DependencyManager::get();
@@ -111,28 +111,38 @@ void Circle3DOverlay::render(RenderArgs* args) {
vec4 innerEndColor = vec4(toGlm(_innerEndColor), _innerEndAlpha) * pulseModifier;
vec4 outerEndColor = vec4(toGlm(_outerEndColor), _outerEndAlpha) * pulseModifier;
+ const auto startAtRadians = glm::radians(_startAt);
+ const auto endAtRadians = glm::radians(_endAt);
+
+ const auto totalRange = _endAt - _startAt;
if (_innerRadius <= 0) {
_solidPrimitive = gpu::TRIANGLE_FAN;
points << vec2();
colors << innerStartColor;
- for (float angle = _startAt; angle <= _endAt; angle += SLICE_ANGLE) {
- float range = (angle - _startAt) / (_endAt - _startAt);
- float angleRadians = glm::radians(angle);
+ for (float angleRadians = startAtRadians; angleRadians < endAtRadians; angleRadians += SLICE_ANGLE_RADIANS) {
+ float range = (angleRadians - startAtRadians) / totalRange;
points << glm::vec2(cosf(angleRadians) * _outerRadius, sinf(angleRadians) * _outerRadius);
colors << glm::mix(outerStartColor, outerEndColor, range);
}
+ points << glm::vec2(cosf(endAtRadians) * _outerRadius, sinf(endAtRadians) * _outerRadius);
+ colors << outerEndColor;
+
} else {
_solidPrimitive = gpu::TRIANGLE_STRIP;
- for (float angle = _startAt; angle <= _endAt; angle += SLICE_ANGLE) {
- float range = (angle - _startAt) / (_endAt - _startAt);
+ for (float angleRadians = startAtRadians; angleRadians < endAtRadians; angleRadians += SLICE_ANGLE_RADIANS) {
+ float range = (angleRadians - startAtRadians) / totalRange;
- float angleRadians = glm::radians(angle);
points << glm::vec2(cosf(angleRadians) * _innerRadius, sinf(angleRadians) * _innerRadius);
colors << glm::mix(innerStartColor, innerEndColor, range);
points << glm::vec2(cosf(angleRadians) * _outerRadius, sinf(angleRadians) * _outerRadius);
colors << glm::mix(outerStartColor, outerEndColor, range);
}
+ points << glm::vec2(cosf(endAtRadians) * _innerRadius, sinf(endAtRadians) * _innerRadius);
+ colors << innerEndColor;
+
+ points << glm::vec2(cosf(endAtRadians) * _outerRadius, sinf(endAtRadians) * _outerRadius);
+ colors << outerEndColor;
}
geometryCache->updateVertices(_quadVerticesID, points, colors);
}
@@ -147,29 +157,28 @@ void Circle3DOverlay::render(RenderArgs* args) {
if (geometryChanged) {
QVector points;
- float angle = _startAt;
- float angleInRadians = glm::radians(angle);
- glm::vec2 firstPoint(cosf(angleInRadians) * _outerRadius, sinf(angleInRadians) * _outerRadius);
+ const auto startAtRadians = glm::radians(_startAt);
+ const auto endAtRadians = glm::radians(_endAt);
+
+ float angleRadians = startAtRadians;
+ glm::vec2 firstPoint(cosf(angleRadians) * _outerRadius, sinf(angleRadians) * _outerRadius);
points << firstPoint;
- while (angle < _endAt) {
- angle += SLICE_ANGLE;
- angleInRadians = glm::radians(angle);
- glm::vec2 thisPoint(cosf(angleInRadians) * _outerRadius, sinf(angleInRadians) * _outerRadius);
+ while (angleRadians < endAtRadians) {
+ angleRadians += SLICE_ANGLE_RADIANS;
+ glm::vec2 thisPoint(cosf(angleRadians) * _outerRadius, sinf(angleRadians) * _outerRadius);
points << thisPoint;
if (getIsDashedLine()) {
- angle += SLICE_ANGLE / 2.0f; // short gap
- angleInRadians = glm::radians(angle);
- glm::vec2 dashStartPoint(cosf(angleInRadians) * _outerRadius, sinf(angleInRadians) * _outerRadius);
+ angleRadians += SLICE_ANGLE_RADIANS / 2.0f; // short gap
+ glm::vec2 dashStartPoint(cosf(angleRadians) * _outerRadius, sinf(angleRadians) * _outerRadius);
points << dashStartPoint;
}
}
// get the last slice portion....
- angle = _endAt;
- angleInRadians = glm::radians(angle);
- glm::vec2 lastPoint(cosf(angleInRadians) * _outerRadius, sinf(angleInRadians) * _outerRadius);
+ angleRadians = endAtRadians;
+ glm::vec2 lastPoint(cosf(angleRadians) * _outerRadius, sinf(angleRadians) * _outerRadius);
points << lastPoint;
geometryCache->updateVertices(_lineVerticesID, points, vec4(toGlm(getColor()), getAlpha()));
}
diff --git a/interface/src/ui/overlays/ContextOverlayInterface.cpp b/interface/src/ui/overlays/ContextOverlayInterface.cpp
index ba9a1f9fc9..5de8bb1a2a 100644
--- a/interface/src/ui/overlays/ContextOverlayInterface.cpp
+++ b/interface/src/ui/overlays/ContextOverlayInterface.cpp
@@ -252,12 +252,6 @@ bool ContextOverlayInterface::destroyContextOverlay(const EntityItemID& entityIt
void ContextOverlayInterface::contextOverlays_mousePressOnOverlay(const OverlayID& overlayID, const PointerEvent& event) {
if (overlayID == _contextOverlayID && event.getButton() == PointerEvent::PrimaryButton) {
qCDebug(context_overlay) << "Clicked Context Overlay. Entity ID:" << _currentEntityWithContextOverlay << "Overlay ID:" << overlayID;
- Setting::Handle _settingSwitch{ "commerce", true };
- if (_settingSwitch.get()) {
- openInspectionCertificate();
- } else {
- openMarketplace();
- }
emit contextOverlayClicked(_currentEntityWithContextOverlay);
_contextOverlayJustClicked = true;
}
@@ -390,34 +384,6 @@ void ContextOverlayInterface::requestOwnershipVerification(const QUuid& entityID
}
}
-static const QString INSPECTION_CERTIFICATE_QML_PATH = "hifi/commerce/inspectionCertificate/InspectionCertificate.qml";
-void ContextOverlayInterface::openInspectionCertificate() {
- // lets open the tablet to the inspection certificate QML
- if (!_currentEntityWithContextOverlay.isNull() && _entityMarketplaceID.length() > 0) {
- setLastInspectedEntity(_currentEntityWithContextOverlay);
- auto tablet = dynamic_cast(_tabletScriptingInterface->getTablet("com.highfidelity.interface.tablet.system"));
- tablet->loadQMLSource(INSPECTION_CERTIFICATE_QML_PATH);
- _hmdScriptingInterface->openTablet();
- }
-}
-
-static const QString MARKETPLACE_BASE_URL = NetworkingConstants::METAVERSE_SERVER_URL().toString() + "/marketplace/items/";
-
-void ContextOverlayInterface::openMarketplace() {
- // lets open the tablet and go to the current item in
- // the marketplace (if the current entity has a
- // marketplaceID)
- if (!_currentEntityWithContextOverlay.isNull() && _entityMarketplaceID.length() > 0) {
- auto tablet = dynamic_cast(_tabletScriptingInterface->getTablet("com.highfidelity.interface.tablet.system"));
- // construct the url to the marketplace item
- QString url = MARKETPLACE_BASE_URL + _entityMarketplaceID;
- QString MARKETPLACES_INJECT_SCRIPT_PATH = "file:///" + qApp->applicationDirPath() + "/scripts/system/html/js/marketplacesInject.js";
- tablet->gotoWebScreen(url, MARKETPLACES_INJECT_SCRIPT_PATH);
- _hmdScriptingInterface->openTablet();
- _isInMarketplaceInspectionMode = true;
- }
-}
-
void ContextOverlayInterface::enableEntityHighlight(const EntityItemID& entityItemID) {
_selectionScriptingInterface->addToSelectedItemsList("contextOverlayHighlightList", "entity", entityItemID);
}
diff --git a/interface/src/ui/overlays/ContextOverlayInterface.h b/interface/src/ui/overlays/ContextOverlayInterface.h
index 808c3a4ee3..48b14e1a91 100644
--- a/interface/src/ui/overlays/ContextOverlayInterface.h
+++ b/interface/src/ui/overlays/ContextOverlayInterface.h
@@ -94,8 +94,6 @@ private:
bool _isInMarketplaceInspectionMode { false };
- void openInspectionCertificate();
- void openMarketplace();
void enableEntityHighlight(const EntityItemID& entityItemID);
void disableEntityHighlight(const EntityItemID& entityItemID);
diff --git a/interface/src/ui/overlays/Text3DOverlay.cpp b/interface/src/ui/overlays/Text3DOverlay.cpp
index fc4b8b9010..40e49ccefd 100644
--- a/interface/src/ui/overlays/Text3DOverlay.cpp
+++ b/interface/src/ui/overlays/Text3DOverlay.cpp
@@ -114,7 +114,6 @@ void Text3DOverlay::render(RenderArgs* args) {
float scaleFactor = (maxHeight / FIXED_FONT_SCALING_RATIO) * _lineHeight;
- glm::vec2 clipMinimum(0.0f, 0.0f);
glm::vec2 clipDimensions((dimensions.x - (_leftMargin + _rightMargin)) / scaleFactor,
(dimensions.y - (_topMargin + _bottomMargin)) / scaleFactor);
@@ -296,4 +295,4 @@ QSizeF Text3DOverlay::textSize(const QString& text) const {
float pointToWorldScale = (maxHeight / FIXED_FONT_SCALING_RATIO) * _lineHeight;
return QSizeF(extents.x, extents.y) * pointToWorldScale;
-}
\ No newline at end of file
+}
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/AudioHRTF.h b/libraries/audio/src/AudioHRTF.h
index 8993842d6e..65b28bc5f8 100644
--- a/libraries/audio/src/AudioHRTF.h
+++ b/libraries/audio/src/AudioHRTF.h
@@ -13,6 +13,7 @@
#define hifi_AudioHRTF_h
#include
+#include
static const int HRTF_AZIMUTHS = 72; // 360 / 5-degree steps
static const int HRTF_TAPS = 64; // minimum-phase FIR coefficients
@@ -56,6 +57,27 @@ public:
void setGainAdjustment(float gain) { _gainAdjust = HRTF_GAIN * gain; };
float getGainAdjustment() { return _gainAdjust; }
+ // clear internal state, but retain settings
+ void reset() {
+ // FIR history
+ memset(_firState, 0, sizeof(_firState));
+
+ // integer delay history
+ memset(_delayState, 0, sizeof(_delayState));
+
+ // biquad history
+ memset(_bqState, 0, sizeof(_bqState));
+
+ // parameter history
+ _azimuthState = 0.0f;
+ _distanceState = 0.0f;
+ _gainState = 0.0f;
+
+ // _gainAdjust is retained
+
+ _silentState = true;
+ }
+
private:
AudioHRTF(const AudioHRTF&) = delete;
AudioHRTF& operator=(const AudioHRTF&) = delete;
@@ -88,7 +110,7 @@ private:
// global and local gain adjustment
float _gainAdjust = HRTF_GAIN;
- bool _silentState = false;
+ bool _silentState = true;
};
#endif // AudioHRTF_h
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/avatars-renderer/src/avatars-renderer/Avatar.cpp b/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp
index 914a3b7c6e..b4b213dc87 100644
--- a/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp
+++ b/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp
@@ -113,6 +113,80 @@ void Avatar::setShowNamesAboveHeads(bool show) {
showNamesAboveHeads = show;
}
+AvatarTransit::Status AvatarTransit::update(float deltaTime, const glm::vec3& avatarPosition, const AvatarTransit::TransitConfig& config) {
+ glm::vec3 currentPosition = _isTransiting ? _currentPosition : avatarPosition;
+ float oneFrameDistance = glm::length(currentPosition - _lastPosition);
+ const float MAX_TRANSIT_DISTANCE = 30.0f;
+ float scaledMaxTransitDistance = MAX_TRANSIT_DISTANCE * _scale;
+ if (oneFrameDistance > config._triggerDistance && oneFrameDistance < scaledMaxTransitDistance && !_isTransiting) {
+ start(deltaTime, _lastPosition, currentPosition, config);
+ }
+ _lastPosition = currentPosition;
+ _status = updatePosition(deltaTime);
+ return _status;
+}
+
+void AvatarTransit::start(float deltaTime, const glm::vec3& startPosition, const glm::vec3& endPosition, const AvatarTransit::TransitConfig& config) {
+ _startPosition = startPosition;
+ _endPosition = endPosition;
+
+ _transitLine = endPosition - startPosition;
+ _totalDistance = glm::length(_transitLine);
+ _easeType = config._easeType;
+ const float REFERENCE_FRAMES_PER_SECOND = 30.0f;
+
+ int transitFrames = (!config._isDistanceBased) ? config._totalFrames : config._framesPerMeter * _totalDistance;
+ _totalTime = (float)transitFrames / REFERENCE_FRAMES_PER_SECOND;
+ _currentTime = 0.0f;
+ _isTransiting = true;
+}
+
+float AvatarTransit::getEaseValue(AvatarTransit::EaseType type, float value) {
+ switch (type) {
+ case EaseType::NONE:
+ return value;
+ break;
+ case EaseType::EASE_IN:
+ return value * value;
+ break;
+ case EaseType::EASE_OUT:
+ return value * (2.0f - value);
+ break;
+ case EaseType::EASE_IN_OUT:
+ return (value < 0.5f) ? 2.0f * value * value : -1.0f + (4.0f - 2.0f * value) * value;
+ break;
+ }
+ return value;
+}
+
+AvatarTransit::Status AvatarTransit::updatePosition(float deltaTime) {
+ Status status = Status::IDLE;
+ if (_isTransiting) {
+ float nextTime = _currentTime + deltaTime;
+ glm::vec3 newPosition;
+ if (nextTime >= _totalTime) {
+ _currentPosition = _endPosition;
+ _isTransiting = false;
+ status = Status::END_TRANSIT;
+ } else {
+ if (_currentTime == 0) {
+ status = Status::START_TRANSIT;
+ } else {
+ status = Status::TRANSITING;
+ }
+ float percentageIntoTransit = nextTime / _totalTime;
+ _currentPosition = _startPosition + getEaseValue(_easeType, percentageIntoTransit) * _transitLine;
+ }
+ _currentTime = nextTime;
+ }
+ return status;
+}
+
+bool AvatarTransit::getNextPosition(glm::vec3& nextPosition) {
+ nextPosition = _currentPosition;
+ return _isTransiting;
+}
+
Avatar::Avatar(QThread* thread) :
_voiceSphereID(GeometryCache::UNKNOWN_ID)
{
@@ -449,7 +523,18 @@ void Avatar::relayJointDataToChildren() {
void Avatar::simulate(float deltaTime, bool inView) {
PROFILE_RANGE(simulation, "simulate");
-
+
+ if (_transit.isTransiting()) {
+ glm::vec3 nextPosition;
+ if (_transit.getNextPosition(nextPosition)) {
+ _globalPosition = nextPosition;
+ _globalPositionChanged = usecTimestampNow();
+ if (!hasParent()) {
+ setLocalPosition(nextPosition);
+ }
+ }
+ }
+
_simulationRate.increment();
if (inView) {
_simulationInViewRate.increment();
@@ -460,7 +545,7 @@ void Avatar::simulate(float deltaTime, bool inView) {
PROFILE_RANGE(simulation, "updateJoints");
if (inView) {
Head* head = getHead();
- if (_hasNewJointData) {
+ if (_hasNewJointData || _transit.isTransiting()) {
_skeletonModel->getRig().copyJointsFromJointData(_jointData);
glm::mat4 rootTransform = glm::scale(_skeletonModel->getScale()) * glm::translate(_skeletonModel->getOffset());
_skeletonModel->getRig().computeExternalPoses(rootTransform);
@@ -1881,6 +1966,22 @@ float Avatar::getUnscaledEyeHeightFromSkeleton() const {
}
}
+AvatarTransit::Status Avatar::updateTransit(float deltaTime, const glm::vec3& avatarPosition, const AvatarTransit::TransitConfig& config) {
+ std::lock_guard lock(_transitLock);
+ return _transit.update(deltaTime, avatarPosition, config);
+}
+
+void Avatar::setTransitScale(float scale) {
+ std::lock_guard lock(_transitLock);
+ return _transit.setScale(scale);
+}
+
+void Avatar::overrideNextPackagePositionData(const glm::vec3& position) {
+ std::lock_guard lock(_transitLock);
+ _overrideGlobalPosition = true;
+ _globalPositionOverride = position;
+}
+
void Avatar::addMaterial(graphics::MaterialLayer material, const std::string& parentMaterialName) {
std::lock_guard lock(_materialsLock);
_materials[parentMaterialName].push(material);
diff --git a/libraries/avatars-renderer/src/avatars-renderer/Avatar.h b/libraries/avatars-renderer/src/avatars-renderer/Avatar.h
index 4f1c010d84..fe5d310812 100644
--- a/libraries/avatars-renderer/src/avatars-renderer/Avatar.h
+++ b/libraries/avatars-renderer/src/avatars-renderer/Avatar.h
@@ -50,6 +50,62 @@ enum ScreenTintLayer {
class Texture;
+class AvatarTransit {
+public:
+ enum Status {
+ IDLE = 0,
+ START_TRANSIT,
+ TRANSITING,
+ END_TRANSIT
+ };
+
+ enum EaseType {
+ NONE = 0,
+ EASE_IN,
+ EASE_OUT,
+ EASE_IN_OUT
+ };
+
+ struct TransitConfig {
+ TransitConfig() {};
+ int _totalFrames { 0 };
+ int _framesPerMeter { 0 };
+ bool _isDistanceBased { false };
+ float _triggerDistance { 0 };
+ EaseType _easeType { EaseType::EASE_OUT };
+ };
+
+ AvatarTransit() {};
+ Status update(float deltaTime, const glm::vec3& avatarPosition, const TransitConfig& config);
+ Status getStatus() { return _status; }
+ bool isTransiting() { return _isTransiting; }
+ glm::vec3 getCurrentPosition() { return _currentPosition; }
+ bool getNextPosition(glm::vec3& nextPosition);
+ glm::vec3 getEndPosition() { return _endPosition; }
+ float getTransitTime() { return _totalTime; }
+ void setScale(float scale) { _scale = scale; }
+
+private:
+ Status updatePosition(float deltaTime);
+ void start(float deltaTime, const glm::vec3& startPosition, const glm::vec3& endPosition, const TransitConfig& config);
+ float getEaseValue(AvatarTransit::EaseType type, float value);
+ bool _isTransiting { false };
+
+ glm::vec3 _startPosition;
+ glm::vec3 _endPosition;
+ glm::vec3 _currentPosition;
+
+ glm::vec3 _lastPosition;
+
+ glm::vec3 _transitLine;
+ float _totalDistance { 0.0f };
+ float _totalTime { 0.0f };
+ float _currentTime { 0.0f };
+ EaseType _easeType { EaseType::EASE_OUT };
+ Status _status { Status::IDLE };
+ float _scale { 1.0f };
+};
+
class Avatar : public AvatarData, public scriptable::ModelProvider {
Q_OBJECT
@@ -370,6 +426,13 @@ public:
virtual scriptable::ScriptableModelBase getScriptableModel() override;
+ std::shared_ptr getTransit() { return std::make_shared(_transit); };
+
+ AvatarTransit::Status updateTransit(float deltaTime, const glm::vec3& avatarPosition, const AvatarTransit::TransitConfig& config);
+ void setTransitScale(float scale);
+
+ void overrideNextPackagePositionData(const glm::vec3& position);
+
signals:
void targetScaleChanged(float targetScale);
@@ -505,6 +568,7 @@ protected:
RateCounter<> _skeletonModelSimulationRate;
RateCounter<> _jointDataSimulationRate;
+
protected:
class AvatarEntityDataHash {
public:
@@ -528,6 +592,9 @@ protected:
bool _reconstructSoftEntitiesJointMap { false };
float _modelScale { 1.0f };
+ AvatarTransit _transit;
+ std::mutex _transitLock;
+
static int _jointConesID;
int _voiceSphereID;
diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp
index 834754e228..2168dff1f6 100644
--- a/libraries/avatars/src/AvatarData.cpp
+++ b/libraries/avatars/src/AvatarData.cpp
@@ -369,7 +369,12 @@ QByteArray AvatarData::toByteArray(AvatarDataDetail dataDetail, quint64 lastSent
if (hasAvatarGlobalPosition) {
auto startSection = destinationBuffer;
- AVATAR_MEMCPY(_globalPosition);
+ if (_overrideGlobalPosition) {
+ AVATAR_MEMCPY(_globalPositionOverride);
+ } else {
+ AVATAR_MEMCPY(_globalPosition);
+ }
+
int numBytes = destinationBuffer - startSection;
@@ -2088,6 +2093,10 @@ void AvatarData::sendAvatarDataPacket(bool sendAll) {
}
}
+ if (_overrideGlobalPosition) {
+ _overrideGlobalPosition = false;
+ }
+
doneEncoding(cullSmallData);
static AvatarDataSequenceNumber sequenceNumber = 0;
@@ -2829,8 +2838,10 @@ void RayToAvatarIntersectionResultFromScriptValue(const QScriptValue& object, Ra
value.extraInfo = object.property("extraInfo").toVariant().toMap();
}
+// these coefficients can be changed via JS for experimental tuning
+// use AvatatManager.setAvatarSortCoefficient("name", value) by a user with domain kick-rights
float AvatarData::_avatarSortCoefficientSize { 8.0f };
-float AvatarData::_avatarSortCoefficientCenter { 4.0f };
+float AvatarData::_avatarSortCoefficientCenter { 0.25f };
float AvatarData::_avatarSortCoefficientAge { 1.0f };
QScriptValue AvatarEntityMapToScriptValue(QScriptEngine* engine, const AvatarEntityMap& value) {
diff --git a/libraries/avatars/src/AvatarData.h b/libraries/avatars/src/AvatarData.h
index 39f0ea34f6..a890482e9a 100644
--- a/libraries/avatars/src/AvatarData.h
+++ b/libraries/avatars/src/AvatarData.h
@@ -1372,7 +1372,8 @@ protected:
// where Entities are located. This is currently only used by the mixer to decide how often to send
// updates about one avatar to another.
glm::vec3 _globalPosition { 0, 0, 0 };
-
+ glm::vec3 _globalPositionOverride { 0, 0, 0 };
+ bool _overrideGlobalPosition { false };
quint64 _globalPositionChanged { 0 };
quint64 _avatarBoundingBoxChanged { 0 };
diff --git a/libraries/avatars/src/AvatarHashMap.cpp b/libraries/avatars/src/AvatarHashMap.cpp
index d205a915f8..c8ea68dae4 100644
--- a/libraries/avatars/src/AvatarHashMap.cpp
+++ b/libraries/avatars/src/AvatarHashMap.cpp
@@ -66,6 +66,22 @@ void AvatarReplicas::removeReplicas(const QUuid& parentID) {
}
}
+std::vector AvatarReplicas::takeReplicas(const QUuid& parentID) {
+ std::vector replicas;
+
+ auto it = _replicasMap.find(parentID);
+
+ if (it != _replicasMap.end()) {
+ // take a copy of the replica shared pointers for this parent
+ replicas.swap(it->second);
+
+ // erase the replicas for this parent from our map
+ _replicasMap.erase(it);
+ }
+
+ return replicas;
+}
+
void AvatarReplicas::processAvatarIdentity(const QUuid& parentID, const QByteArray& identityData, bool& identityChanged, bool& displayNameChanged) {
if (_replicasMap.find(parentID) != _replicasMap.end()) {
auto &replicas = _replicasMap[parentID];
@@ -250,6 +266,7 @@ AvatarSharedPointer AvatarHashMap::parseAvatarData(QSharedPointerparseDataFromBuffer(byteArray);
message->seek(positionBeforeRead + bytesRead);
@@ -300,7 +317,6 @@ void AvatarHashMap::processAvatarIdentityPacket(QSharedPointer
// In this case, the "sendingNode" is the Avatar Mixer.
avatar->processAvatarIdentity(message->getMessage(), identityChanged, displayNameChanged);
_replicas.processAvatarIdentity(identityUUID, message->getMessage(), identityChanged, displayNameChanged);
-
}
}
@@ -313,6 +329,7 @@ void AvatarHashMap::processBulkAvatarTraits(QSharedPointer mess
// grab the avatar so we can ask it to process trait data
bool isNewAvatar;
auto avatar = newOrExistingAvatar(avatarID, sendingNode, isNewAvatar);
+
// read the first trait type for this avatar
AvatarTraits::TraitType traitType;
message->readPrimitive(&traitType);
@@ -386,24 +403,31 @@ void AvatarHashMap::processKillAvatar(QSharedPointer message, S
}
void AvatarHashMap::removeAvatar(const QUuid& sessionUUID, KillAvatarReason removalReason) {
- QWriteLocker locker(&_hashLock);
+ std::vector removedAvatars;
- auto replicaIDs = _replicas.getReplicaIDs(sessionUUID);
- _replicas.removeReplicas(sessionUUID);
- for (auto id : replicaIDs) {
- auto removedReplica = _avatarHash.take(id);
- if (removedReplica) {
- handleRemovedAvatar(removedReplica, removalReason);
+ {
+ QWriteLocker locker(&_hashLock);
+
+ auto replicas = _replicas.takeReplicas(sessionUUID);
+
+ for (auto& replica : replicas) {
+ auto removedReplica = _avatarHash.take(replica->getID());
+ if (removedReplica) {
+ removedAvatars.push_back(removedReplica);
+ }
+ }
+
+ _pendingAvatars.remove(sessionUUID);
+ auto removedAvatar = _avatarHash.take(sessionUUID);
+
+ if (removedAvatar) {
+ removedAvatars.push_back(removedAvatar);
}
}
- _pendingAvatars.remove(sessionUUID);
- auto removedAvatar = _avatarHash.take(sessionUUID);
-
- if (removedAvatar) {
+ for (auto& removedAvatar: removedAvatars) {
handleRemovedAvatar(removedAvatar, removalReason);
}
-
}
void AvatarHashMap::handleRemovedAvatar(const AvatarSharedPointer& removedAvatar, KillAvatarReason removalReason) {
@@ -421,11 +445,18 @@ void AvatarHashMap::sessionUUIDChanged(const QUuid& sessionUUID, const QUuid& ol
}
void AvatarHashMap::clearOtherAvatars() {
- QWriteLocker locker(&_hashLock);
+ QList removedAvatars;
- for (auto& av : _avatarHash) {
- handleRemovedAvatar(av);
+ {
+ QWriteLocker locker(&_hashLock);
+
+ // grab a copy of the current avatars so we can call handleRemoveAvatar for them
+ removedAvatars = _avatarHash.values();
+
+ _avatarHash.clear();
}
- _avatarHash.clear();
+ for (auto& av : removedAvatars) {
+ handleRemovedAvatar(av);
+ }
}
diff --git a/libraries/avatars/src/AvatarHashMap.h b/libraries/avatars/src/AvatarHashMap.h
index 70d7f8c04d..c2cb448e52 100644
--- a/libraries/avatars/src/AvatarHashMap.h
+++ b/libraries/avatars/src/AvatarHashMap.h
@@ -49,6 +49,7 @@ public:
void parseDataFromBuffer(const QUuid& parentID, const QByteArray& buffer);
void processAvatarIdentity(const QUuid& parentID, const QByteArray& identityData, bool& identityChanged, bool& displayNameChanged);
void removeReplicas(const QUuid& parentID);
+ std::vector takeReplicas(const QUuid& parentID);
void processTrait(const QUuid& parentID, AvatarTraits::TraitType traitType, QByteArray traitBinaryData);
void processDeletedTraitInstance(const QUuid& parentID, AvatarTraits::TraitType traitType, AvatarTraits::TraitInstanceID instanceID);
void processTraitInstance(const QUuid& parentID, AvatarTraits::TraitType traitType,
@@ -179,7 +180,7 @@ protected:
bool& isNew);
virtual AvatarSharedPointer findAvatar(const QUuid& sessionUUID) const; // uses a QReadLocker on the hashLock
virtual void removeAvatar(const QUuid& sessionUUID, KillAvatarReason removalReason = KillAvatarReason::NoReason);
-
+
virtual void handleRemovedAvatar(const AvatarSharedPointer& removedAvatar, KillAvatarReason removalReason = KillAvatarReason::NoReason);
AvatarHash _avatarHash;
diff --git a/libraries/controllers/src/controllers/InputDevice.h b/libraries/controllers/src/controllers/InputDevice.h
index 1e626e6a3c..6c5cc3a065 100644
--- a/libraries/controllers/src/controllers/InputDevice.h
+++ b/libraries/controllers/src/controllers/InputDevice.h
@@ -98,6 +98,7 @@ enum Hand {
class InputDevice {
public:
InputDevice(const QString& name) : _name(name) {}
+ virtual ~InputDevice() {}
using Pointer = std::shared_ptr;
diff --git a/libraries/controllers/src/controllers/impl/conditionals/AndConditional.h b/libraries/controllers/src/controllers/impl/conditionals/AndConditional.h
index 2299843a24..7d8f08ca1c 100644
--- a/libraries/controllers/src/controllers/impl/conditionals/AndConditional.h
+++ b/libraries/controllers/src/controllers/impl/conditionals/AndConditional.h
@@ -24,6 +24,8 @@ public:
AndConditional(Conditional::Pointer& first, Conditional::Pointer& second)
: _children({ first, second }) {}
+ virtual ~AndConditional() {}
+
virtual bool satisfied() override;
private:
diff --git a/libraries/controllers/src/controllers/impl/conditionals/EndpointConditional.h b/libraries/controllers/src/controllers/impl/conditionals/EndpointConditional.h
index 0ba1347087..a6bd7d468d 100644
--- a/libraries/controllers/src/controllers/impl/conditionals/EndpointConditional.h
+++ b/libraries/controllers/src/controllers/impl/conditionals/EndpointConditional.h
@@ -18,6 +18,7 @@ namespace controller {
class EndpointConditional : public Conditional {
public:
EndpointConditional(Endpoint::Pointer endpoint) : _endpoint(endpoint) {}
+ virtual ~EndpointConditional() {}
virtual bool satisfied() override { return _endpoint && _endpoint->peek() != 0.0f; }
private:
Endpoint::Pointer _endpoint;
diff --git a/libraries/controllers/src/controllers/impl/conditionals/NotConditional.h b/libraries/controllers/src/controllers/impl/conditionals/NotConditional.h
index 6b19cf9505..3fcd5f49fc 100644
--- a/libraries/controllers/src/controllers/impl/conditionals/NotConditional.h
+++ b/libraries/controllers/src/controllers/impl/conditionals/NotConditional.h
@@ -19,6 +19,7 @@ namespace controller {
using Pointer = std::shared_ptr;
NotConditional(Conditional::Pointer operand) : _operand(operand) { }
+ virtual ~NotConditional() {}
virtual bool satisfied() override;
diff --git a/libraries/controllers/src/controllers/impl/filters/ClampFilter.h b/libraries/controllers/src/controllers/impl/filters/ClampFilter.h
index b06a43515f..6eca00fbe2 100644
--- a/libraries/controllers/src/controllers/impl/filters/ClampFilter.h
+++ b/libraries/controllers/src/controllers/impl/filters/ClampFilter.h
@@ -18,6 +18,7 @@ class ClampFilter : public Filter {
REGISTER_FILTER_CLASS(ClampFilter);
public:
ClampFilter(float min = 0.0, float max = 1.0) : _min(min), _max(max) {};
+ virtual ~ClampFilter() {}
virtual float apply(float value) const override {
return glm::clamp(value, _min, _max);
}
diff --git a/libraries/controllers/src/controllers/impl/filters/ConstrainToIntegerFilter.h b/libraries/controllers/src/controllers/impl/filters/ConstrainToIntegerFilter.h
index c9a25fde72..bc90121ab0 100644
--- a/libraries/controllers/src/controllers/impl/filters/ConstrainToIntegerFilter.h
+++ b/libraries/controllers/src/controllers/impl/filters/ConstrainToIntegerFilter.h
@@ -18,6 +18,7 @@ class ConstrainToIntegerFilter : public Filter {
REGISTER_FILTER_CLASS(ConstrainToIntegerFilter);
public:
ConstrainToIntegerFilter() {};
+ virtual ~ConstrainToIntegerFilter() {}
virtual float apply(float value) const override {
return glm::sign(value);
diff --git a/libraries/controllers/src/controllers/impl/filters/ConstrainToPositiveIntegerFilter.h b/libraries/controllers/src/controllers/impl/filters/ConstrainToPositiveIntegerFilter.h
index e3f4ee8929..accebef851 100644
--- a/libraries/controllers/src/controllers/impl/filters/ConstrainToPositiveIntegerFilter.h
+++ b/libraries/controllers/src/controllers/impl/filters/ConstrainToPositiveIntegerFilter.h
@@ -18,6 +18,7 @@ class ConstrainToPositiveIntegerFilter : public Filter {
REGISTER_FILTER_CLASS(ConstrainToPositiveIntegerFilter);
public:
ConstrainToPositiveIntegerFilter() {};
+ virtual ~ConstrainToPositiveIntegerFilter() {};
virtual float apply(float value) const override {
return (value <= 0.0f) ? 0.0f : 1.0f;
diff --git a/libraries/controllers/src/controllers/impl/filters/DeadZoneFilter.h b/libraries/controllers/src/controllers/impl/filters/DeadZoneFilter.h
index d898647126..96c60198e2 100644
--- a/libraries/controllers/src/controllers/impl/filters/DeadZoneFilter.h
+++ b/libraries/controllers/src/controllers/impl/filters/DeadZoneFilter.h
@@ -18,6 +18,7 @@ class DeadZoneFilter : public Filter {
REGISTER_FILTER_CLASS(DeadZoneFilter);
public:
DeadZoneFilter(float min = 0.0) : _min(min) {};
+ virtual ~DeadZoneFilter() {}
virtual float apply(float value) const override;
diff --git a/libraries/controllers/src/controllers/impl/filters/ExponentialSmoothingFilter.h b/libraries/controllers/src/controllers/impl/filters/ExponentialSmoothingFilter.h
index 134f57243e..5b29b6681a 100644
--- a/libraries/controllers/src/controllers/impl/filters/ExponentialSmoothingFilter.h
+++ b/libraries/controllers/src/controllers/impl/filters/ExponentialSmoothingFilter.h
@@ -20,6 +20,7 @@ namespace controller {
ExponentialSmoothingFilter() {}
ExponentialSmoothingFilter(float rotationConstant, float translationConstant) :
_translationConstant(translationConstant), _rotationConstant(rotationConstant) {}
+ virtual ~ExponentialSmoothingFilter() {}
float apply(float value) const override { return value; }
Pose apply(Pose value) const override;
diff --git a/libraries/controllers/src/controllers/impl/filters/HysteresisFilter.h b/libraries/controllers/src/controllers/impl/filters/HysteresisFilter.h
index 4eb563754f..4a607d0d5f 100644
--- a/libraries/controllers/src/controllers/impl/filters/HysteresisFilter.h
+++ b/libraries/controllers/src/controllers/impl/filters/HysteresisFilter.h
@@ -18,6 +18,7 @@ class HysteresisFilter : public Filter {
REGISTER_FILTER_CLASS(HysteresisFilter);
public:
HysteresisFilter(float min = 0.25, float max = 0.75);
+ virtual ~HysteresisFilter() {}
virtual float apply(float value) const override;
virtual Pose apply(Pose value) const override { return value; }
diff --git a/libraries/controllers/src/controllers/impl/filters/InvertFilter.h b/libraries/controllers/src/controllers/impl/filters/InvertFilter.h
index 8acc9d56d6..03b6e9fcb0 100644
--- a/libraries/controllers/src/controllers/impl/filters/InvertFilter.h
+++ b/libraries/controllers/src/controllers/impl/filters/InvertFilter.h
@@ -19,6 +19,7 @@ class InvertFilter : public ScaleFilter {
public:
using ScaleFilter::parseParameters;
InvertFilter() : ScaleFilter(-1.0f) {}
+ virtual ~InvertFilter() {}
virtual bool parseParameters(const QJsonArray& parameters) { return true; }
diff --git a/libraries/controllers/src/controllers/impl/filters/LowVelocityFilter.h b/libraries/controllers/src/controllers/impl/filters/LowVelocityFilter.h
index b1c6be1f58..fa75473edf 100644
--- a/libraries/controllers/src/controllers/impl/filters/LowVelocityFilter.h
+++ b/libraries/controllers/src/controllers/impl/filters/LowVelocityFilter.h
@@ -20,6 +20,7 @@ namespace controller {
LowVelocityFilter() {}
LowVelocityFilter(float rotationConstant, float translationConstant) :
_translationConstant(translationConstant), _rotationConstant(rotationConstant) {}
+ virtual ~LowVelocityFilter() {}
float apply(float value) const override { return value; }
Pose apply(Pose newPose) const override;
diff --git a/libraries/controllers/src/controllers/impl/filters/NotFilter.h b/libraries/controllers/src/controllers/impl/filters/NotFilter.h
index ceb7d29de3..fa52b8e212 100644
--- a/libraries/controllers/src/controllers/impl/filters/NotFilter.h
+++ b/libraries/controllers/src/controllers/impl/filters/NotFilter.h
@@ -10,6 +10,7 @@ class NotFilter : public Filter {
REGISTER_FILTER_CLASS(NotFilter);
public:
NotFilter();
+ virtual ~NotFilter() {}
virtual float apply(float value) const override;
virtual Pose apply(Pose value) const override { return value; }
diff --git a/libraries/controllers/src/controllers/impl/filters/PostTransformFilter.h b/libraries/controllers/src/controllers/impl/filters/PostTransformFilter.h
index 656a146ff2..1cb9c0a1bd 100644
--- a/libraries/controllers/src/controllers/impl/filters/PostTransformFilter.h
+++ b/libraries/controllers/src/controllers/impl/filters/PostTransformFilter.h
@@ -21,6 +21,7 @@ class PostTransformFilter : public Filter {
public:
PostTransformFilter() { }
PostTransformFilter(glm::mat4 transform) : _transform(transform) {}
+ virtual ~PostTransformFilter() {}
virtual float apply(float value) const override { return value; }
virtual Pose apply(Pose value) const override { return value.postTransform(_transform); }
virtual bool parseParameters(const QJsonValue& parameters) override { return parseMat4Parameter(parameters, _transform); }
diff --git a/libraries/controllers/src/controllers/impl/filters/PulseFilter.h b/libraries/controllers/src/controllers/impl/filters/PulseFilter.h
index a8c7cbf9e6..37cfe34b86 100644
--- a/libraries/controllers/src/controllers/impl/filters/PulseFilter.h
+++ b/libraries/controllers/src/controllers/impl/filters/PulseFilter.h
@@ -20,6 +20,7 @@ class PulseFilter : public Filter {
public:
PulseFilter() {}
PulseFilter(float interval) : _interval(interval) {}
+ virtual ~PulseFilter() {}
virtual float apply(float value) const override;
diff --git a/libraries/controllers/src/controllers/impl/filters/RotateFilter.h b/libraries/controllers/src/controllers/impl/filters/RotateFilter.h
index ee2e081393..aecf4f7b7c 100644
--- a/libraries/controllers/src/controllers/impl/filters/RotateFilter.h
+++ b/libraries/controllers/src/controllers/impl/filters/RotateFilter.h
@@ -21,6 +21,7 @@ class RotateFilter : public Filter {
public:
RotateFilter() { }
RotateFilter(glm::quat rotation) : _rotation(rotation) {}
+ virtual ~RotateFilter() {}
virtual float apply(float value) const override { return value; }
diff --git a/libraries/controllers/src/controllers/impl/filters/ScaleFilter.h b/libraries/controllers/src/controllers/impl/filters/ScaleFilter.h
index 7b03e2ce48..84f7cb7e47 100644
--- a/libraries/controllers/src/controllers/impl/filters/ScaleFilter.h
+++ b/libraries/controllers/src/controllers/impl/filters/ScaleFilter.h
@@ -21,6 +21,7 @@ class ScaleFilter : public Filter {
public:
ScaleFilter() {}
ScaleFilter(float scale) : _scale(scale) {}
+ virtual ~ScaleFilter() {}
virtual float apply(float value) const override {
return value * _scale;
diff --git a/libraries/controllers/src/controllers/impl/filters/TransformFilter.h b/libraries/controllers/src/controllers/impl/filters/TransformFilter.h
index 263b70c9b4..ccfa9c6c25 100644
--- a/libraries/controllers/src/controllers/impl/filters/TransformFilter.h
+++ b/libraries/controllers/src/controllers/impl/filters/TransformFilter.h
@@ -21,6 +21,7 @@ class TransformFilter : public Filter {
public:
TransformFilter() { }
TransformFilter(glm::mat4 transform) : _transform(transform) {}
+ virtual ~TransformFilter() {}
virtual float apply(float value) const override { return value; }
virtual Pose apply(Pose value) const override { return value.transform(_transform); }
diff --git a/libraries/controllers/src/controllers/impl/filters/TranslateFilter.h b/libraries/controllers/src/controllers/impl/filters/TranslateFilter.h
index eda2912a8a..a66e1eb4a4 100644
--- a/libraries/controllers/src/controllers/impl/filters/TranslateFilter.h
+++ b/libraries/controllers/src/controllers/impl/filters/TranslateFilter.h
@@ -21,6 +21,7 @@ class TranslateFilter : public Filter {
public:
TranslateFilter() { }
TranslateFilter(glm::vec3 translate) : _translate(translate) {}
+ virtual ~TranslateFilter() {}
virtual float apply(float value) const override { return value; }
virtual Pose apply(Pose value) const override { return value.transform(glm::translate(_translate)); }
diff --git a/libraries/display-plugins/src/display-plugins/AbstractHMDScriptingInterface.h b/libraries/display-plugins/src/display-plugins/AbstractHMDScriptingInterface.h
index 7fe58618bc..4234a8731b 100644
--- a/libraries/display-plugins/src/display-plugins/AbstractHMDScriptingInterface.h
+++ b/libraries/display-plugins/src/display-plugins/AbstractHMDScriptingInterface.h
@@ -20,6 +20,7 @@ class AbstractHMDScriptingInterface : public QObject {
Q_PROPERTY(float eyeHeight READ getEyeHeight)
Q_PROPERTY(float playerHeight READ getPlayerHeight)
Q_PROPERTY(float ipdScale READ getIPDScale WRITE setIPDScale NOTIFY IPDScaleChanged)
+ Q_PROPERTY(bool mounted READ isMounted NOTIFY mountedChanged)
public:
AbstractHMDScriptingInterface();
@@ -29,6 +30,7 @@ public:
float getIPDScale() const;
void setIPDScale(float ipdScale);
bool isHMDMode() const;
+ virtual bool isMounted() const = 0;
signals:
/**jsdoc
diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.cpp b/libraries/entities-renderer/src/EntityTreeRenderer.cpp
index 3d782f69a7..dbbf8af4b9 100644
--- a/libraries/entities-renderer/src/EntityTreeRenderer.cpp
+++ b/libraries/entities-renderer/src/EntityTreeRenderer.cpp
@@ -187,6 +187,13 @@ void EntityTreeRenderer::resetEntitiesScriptEngine() {
connect(entityScriptingInterface.data(), &EntityScriptingInterface::hoverLeaveEntity, _entitiesScriptEngine.data(), [&](const EntityItemID& entityID, const PointerEvent& event) {
_entitiesScriptEngine->callEntityScriptMethod(entityID, "hoverLeaveEntity", event);
});
+
+ connect(_entitiesScriptEngine.data(), &ScriptEngine::entityScriptPreloadFinished, [&](const EntityItemID& entityID) {
+ EntityItemPointer entity = getTree()->findEntityByID(entityID);
+ if (entity) {
+ entity->setScriptHasFinishedPreload(true);
+ }
+ });
}
void EntityTreeRenderer::clear() {
@@ -512,7 +519,11 @@ bool EntityTreeRenderer::findBestZoneAndMaybeContainingEntities(QVectorisScriptPreloadFinished())) {
// now check to see if the point contains our entity, this can be expensive if
// the entity has a collision hull
if (entity->contains(_avatarPosition)) {
@@ -972,6 +983,7 @@ void EntityTreeRenderer::checkAndCallPreload(const EntityItemID& entityID, bool
entity->scriptHasUnloaded();
}
if (shouldLoad) {
+ entity->setScriptHasFinishedPreload(false);
_entitiesScriptEngine->loadEntityScript(entityID, resolveScriptURL(scriptUrl), reload);
entity->scriptHasPreloaded();
}
diff --git a/libraries/entities-renderer/src/RenderableEntityItem.cpp b/libraries/entities-renderer/src/RenderableEntityItem.cpp
index a183101fff..aa335bb7d5 100644
--- a/libraries/entities-renderer/src/RenderableEntityItem.cpp
+++ b/libraries/entities-renderer/src/RenderableEntityItem.cpp
@@ -305,7 +305,7 @@ void EntityRenderer::updateInScene(const ScenePointer& scene, Transaction& trans
}
doRenderUpdateSynchronous(scene, transaction, _entity);
- transaction.updateItem(_renderItemID, [this](EntityRenderer& self) {
+ transaction.updateItem(_renderItemID, [this](PayloadProxyInterface& self) {
if (!isValidRenderItem()) {
return;
}
diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp
index 3a01650a04..afa03b5ddc 100644
--- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp
+++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp
@@ -250,8 +250,8 @@ void RenderableModelEntityItem::updateModelBounds() {
}
-EntityItemProperties RenderableModelEntityItem::getProperties(EntityPropertyFlags desiredProperties) const {
- EntityItemProperties properties = ModelEntityItem::getProperties(desiredProperties); // get the properties from our base class
+EntityItemProperties RenderableModelEntityItem::getProperties(const EntityPropertyFlags& desiredProperties, bool allowEmptyDesiredProperties) const {
+ EntityItemProperties properties = ModelEntityItem::getProperties(desiredProperties, allowEmptyDesiredProperties); // get the properties from our base class
if (_originalTexturesRead) {
properties.setTextureNames(_originalTextures);
}
diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.h b/libraries/entities-renderer/src/RenderableModelEntityItem.h
index 75f35fae9c..fa49624f7e 100644
--- a/libraries/entities-renderer/src/RenderableModelEntityItem.h
+++ b/libraries/entities-renderer/src/RenderableModelEntityItem.h
@@ -62,7 +62,7 @@ public:
virtual void setUnscaledDimensions(const glm::vec3& value) override;
- virtual EntityItemProperties getProperties(EntityPropertyFlags desiredProperties = EntityPropertyFlags()) const override;
+ virtual EntityItemProperties getProperties(const EntityPropertyFlags& desiredProperties, bool allowEmptyDesiredProperties) const override;
void doInitialModelSimulation();
void updateModelBounds();
diff --git a/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp b/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp
index 18c4921836..1a263fba79 100644
--- a/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp
+++ b/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp
@@ -187,12 +187,10 @@ ParticleEffectEntityRenderer::CpuParticle ParticleEffectEntityRenderer::createPa
particle.basePosition = baseTransform.getTranslation();
// Position, velocity, and acceleration
+ glm::vec3 emitDirection;
if (polarStart == 0.0f && polarFinish == 0.0f && emitDimensions.z == 0.0f) {
// Emit along z-axis from position
-
- particle.velocity = (emitSpeed + randFloatInRange(-1.0f, 1.0f) * speedSpread) * (emitOrientation * Vectors::UNIT_Z);
- particle.acceleration = emitAcceleration + randFloatInRange(-1.0f, 1.0f) * accelerationSpread;
-
+ emitDirection = Vectors::UNIT_Z;
} else {
// Emit around point or from ellipsoid
// - Distribute directions evenly around point
@@ -210,7 +208,6 @@ ParticleEffectEntityRenderer::CpuParticle ParticleEffectEntityRenderer::createPa
azimuth = azimuthStart + (TWO_PI + azimuthFinish - azimuthStart) * randFloat();
}
- glm::vec3 emitDirection;
if (emitDimensions == Vectors::ZERO) {
// Point
emitDirection = glm::quat(glm::vec3(PI_OVER_TWO - elevation, 0.0f, azimuth)) * Vectors::UNIT_Z;
@@ -235,10 +232,10 @@ ParticleEffectEntityRenderer::CpuParticle ParticleEffectEntityRenderer::createPa
));
particle.relativePosition += emitOrientation * emitPosition;
}
-
- particle.velocity = (emitSpeed + randFloatInRange(-1.0f, 1.0f) * speedSpread) * (emitOrientation * emitDirection);
- particle.acceleration = emitAcceleration + randFloatInRange(-1.0f, 1.0f) * accelerationSpread;
}
+ particle.velocity = (emitSpeed + randFloatInRange(-1.0f, 1.0f) * speedSpread) * (emitOrientation * emitDirection);
+ particle.acceleration = emitAcceleration +
+ glm::vec3(randFloatInRange(-1.0f, 1.0f), randFloatInRange(-1.0f, 1.0f), randFloatInRange(-1.0f, 1.0f)) * accelerationSpread;
return particle;
}
diff --git a/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp b/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp
index 71e3a0ff27..5003e36e86 100644
--- a/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp
+++ b/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp
@@ -97,10 +97,10 @@ void ShapeEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& sce
withWriteLock([&] {
auto entity = getEntity();
_position = entity->getWorldPosition();
- _dimensions = entity->getScaledDimensions();
+ _dimensions = entity->getUnscaledDimensions(); // get unscaled to avoid scaling twice
_orientation = entity->getWorldOrientation();
updateModelTransformAndBound();
- _renderTransform = getModelTransform();
+ _renderTransform = getModelTransform(); // contains parent scale, if this entity scales with its parent
if (_shape == entity::Sphere) {
_renderTransform.postScale(SPHERE_ENTITY_SCALE);
}
diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp
index 8e382fabd4..184bb054ea 100644
--- a/libraries/entities/src/EntityItem.cpp
+++ b/libraries/entities/src/EntityItem.cpp
@@ -1251,9 +1251,10 @@ quint64 EntityItem::getExpiry() const {
return getCreated() + (quint64)(getLifetime() * (float)USECS_PER_SECOND);
}
-EntityItemProperties EntityItem::getProperties(EntityPropertyFlags desiredProperties) const {
+EntityItemProperties EntityItem::getProperties(const EntityPropertyFlags& desiredProperties, bool allowEmptyDesiredProperties) const {
EncodeBitstreamParams params; // unknown
- EntityPropertyFlags propertyFlags = desiredProperties.isEmpty() ? getEntityProperties(params) : desiredProperties;
+ const EntityPropertyFlags propertyFlags = !allowEmptyDesiredProperties && desiredProperties.isEmpty() ?
+ getEntityProperties(params) : desiredProperties;
EntityItemProperties properties(propertyFlags);
properties._id = getID();
properties._idSet = true;
@@ -3197,3 +3198,26 @@ void EntityItem::setCloneIDs(const QVector& cloneIDs) {
_cloneIDs = cloneIDs;
});
}
+
+bool EntityItem::shouldPreloadScript() const {
+ return !_script.isEmpty() && ((_loadedScript != _script) || (_loadedScriptTimestamp != _scriptTimestamp));
+}
+
+void EntityItem::scriptHasPreloaded() {
+ _loadedScript = _script;
+ _loadedScriptTimestamp = _scriptTimestamp;
+}
+
+void EntityItem::scriptHasUnloaded() {
+ _loadedScript = "";
+ _loadedScriptTimestamp = 0;
+ _scriptPreloadFinished = false;
+}
+
+void EntityItem::setScriptHasFinishedPreload(bool value) {
+ _scriptPreloadFinished = value;
+}
+
+bool EntityItem::isScriptPreloadFinished() {
+ return _scriptPreloadFinished;
+}
diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h
index 490f9b9e6b..0e5cae66b6 100644
--- a/libraries/entities/src/EntityItem.h
+++ b/libraries/entities/src/EntityItem.h
@@ -88,7 +88,7 @@ public:
EntityItemID getEntityItemID() const { return EntityItemID(_id); }
// methods for getting/setting all properties of an entity
- virtual EntityItemProperties getProperties(EntityPropertyFlags desiredProperties = EntityPropertyFlags()) const;
+ virtual EntityItemProperties getProperties(const EntityPropertyFlags& desiredProperties = EntityPropertyFlags(), bool allowEmptyDesiredProperties = false) const;
/// returns true if something changed
// This function calls setSubClass properties and detects if any property changes value.
@@ -441,6 +441,8 @@ public:
void setDynamicDataNeedsTransmit(bool value) const { _dynamicDataNeedsTransmit = value; }
bool dynamicDataNeedsTransmit() const { return _dynamicDataNeedsTransmit; }
+ void setTransitingWithAvatar(bool value) { _transitingWithAvatar = value; }
+ bool getTransitingWithAvatar() { return _transitingWithAvatar; }
bool shouldSuppressLocationEdits() const;
@@ -470,10 +472,11 @@ public:
/// We only want to preload if:
/// there is some script, and either the script value or the scriptTimestamp
/// value have changed since our last preload
- bool shouldPreloadScript() const { return !_script.isEmpty() &&
- ((_loadedScript != _script) || (_loadedScriptTimestamp != _scriptTimestamp)); }
- void scriptHasPreloaded() { _loadedScript = _script; _loadedScriptTimestamp = _scriptTimestamp; }
- void scriptHasUnloaded() { _loadedScript = ""; _loadedScriptTimestamp = 0; }
+ bool shouldPreloadScript() const;
+ void scriptHasPreloaded();
+ void scriptHasUnloaded();
+ void setScriptHasFinishedPreload(bool value);
+ bool isScriptPreloadFinished();
bool getClientOnly() const { return _clientOnly; }
virtual void setClientOnly(bool clientOnly) { _clientOnly = clientOnly; }
@@ -584,6 +587,7 @@ protected:
QString _script { ENTITY_ITEM_DEFAULT_SCRIPT }; /// the value of the script property
QString _loadedScript; /// the value of _script when the last preload signal was sent
quint64 _scriptTimestamp { ENTITY_ITEM_DEFAULT_SCRIPT_TIMESTAMP }; /// the script loaded property used for forced reload
+ bool _scriptPreloadFinished { false };
QString _serverScripts;
/// keep track of time when _serverScripts property was last changed
@@ -666,6 +670,7 @@ protected:
QUuid _sourceUUID; /// the server node UUID we came from
bool _clientOnly { false };
+ bool _transitingWithAvatar{ false };
QUuid _owningAvatarID;
// physics related changes from the network to suppress any duplicates and make
diff --git a/libraries/entities/src/EntityItemProperties.cpp b/libraries/entities/src/EntityItemProperties.cpp
index dc29d4bb2a..7e404afa3f 100644
--- a/libraries/entities/src/EntityItemProperties.cpp
+++ b/libraries/entities/src/EntityItemProperties.cpp
@@ -1216,7 +1216,9 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const {
* });
*/
-QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool skipDefaults, bool allowUnknownCreateTime, bool strictSemantics) const {
+QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool skipDefaults, bool allowUnknownCreateTime,
+ bool strictSemantics, EntityPsuedoPropertyFlags psueudoPropertyFlags) const {
+
// If strictSemantics is true and skipDefaults is false, then all and only those properties are copied for which the property flag
// is included in _desiredProperties, or is one of the specially enumerated ALWAYS properties below.
// (There may be exceptions, but if so, they are bugs.)
@@ -1224,26 +1226,39 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool
QScriptValue properties = engine->newObject();
EntityItemProperties defaultEntityProperties;
+ const bool psuedoPropertyFlagsActive = psueudoPropertyFlags.test(EntityPsuedoPropertyFlag::FlagsActive);
+ // Fix to skip the default return all mechanism, when psuedoPropertyFlagsActive
+ const bool psuedoPropertyFlagsButDesiredEmpty = psuedoPropertyFlagsActive && _desiredProperties.isEmpty();
+
if (_created == UNKNOWN_CREATED_TIME && !allowUnknownCreateTime) {
// No entity properties can have been set so return without setting any default, zero property values.
return properties;
}
- if (_idSet) {
+ if (_idSet && (!psuedoPropertyFlagsActive || psueudoPropertyFlags.test(EntityPsuedoPropertyFlag::ID))) {
COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER_ALWAYS(id, _id.toString());
}
-
- COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER_ALWAYS(type, EntityTypes::getEntityTypeName(_type));
- auto created = QDateTime::fromMSecsSinceEpoch(getCreated() / 1000.0f, Qt::UTC); // usec per msec
- created.setTimeSpec(Qt::OffsetFromUTC);
- COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER_ALWAYS(created, created.toString(Qt::ISODate));
-
- if ((!skipDefaults || _lifetime != defaultEntityProperties._lifetime) && !strictSemantics) {
- COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER_NO_SKIP(age, getAge()); // gettable, but not settable
- COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER_NO_SKIP(ageAsText, formatSecondsElapsed(getAge())); // gettable, but not settable
+ if (!psuedoPropertyFlagsActive || psueudoPropertyFlags.test(EntityPsuedoPropertyFlag::Type)) {
+ COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER_ALWAYS(type, EntityTypes::getEntityTypeName(_type));
+ }
+ if (!psuedoPropertyFlagsActive || psueudoPropertyFlags.test(EntityPsuedoPropertyFlag::Created)) {
+ auto created = QDateTime::fromMSecsSinceEpoch(getCreated() / 1000.0f, Qt::UTC); // usec per msec
+ created.setTimeSpec(Qt::OffsetFromUTC);
+ COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER_ALWAYS(created, created.toString(Qt::ISODate));
}
- properties.setProperty("lastEdited", convertScriptValue(engine, _lastEdited));
+ if ((!skipDefaults || _lifetime != defaultEntityProperties._lifetime) && !strictSemantics) {
+ if (!psuedoPropertyFlagsActive || psueudoPropertyFlags.test(EntityPsuedoPropertyFlag::Age)) {
+ COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER_NO_SKIP(age, getAge()); // gettable, but not settable
+ }
+ if (!psuedoPropertyFlagsActive || psueudoPropertyFlags.test(EntityPsuedoPropertyFlag::AgeAsText)) {
+ COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER_NO_SKIP(ageAsText, formatSecondsElapsed(getAge())); // gettable, but not settable
+ }
+ }
+
+ if (!psuedoPropertyFlagsActive || psueudoPropertyFlags.test(EntityPsuedoPropertyFlag::LastEdited)) {
+ properties.setProperty("lastEdited", convertScriptValue(engine, _lastEdited));
+ }
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_LAST_EDITED_BY, lastEditedBy);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_POSITION, position);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_DIMENSIONS, dimensions);
@@ -1340,7 +1355,9 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool
// Models only
if (_type == EntityTypes::Model) {
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_MODEL_URL, modelURL);
- _animation.copyToScriptValue(_desiredProperties, properties, engine, skipDefaults, defaultEntityProperties);
+ if (!psuedoPropertyFlagsButDesiredEmpty) {
+ _animation.copyToScriptValue(_desiredProperties, properties, engine, skipDefaults, defaultEntityProperties);
+ }
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_JOINT_ROTATIONS_SET, jointRotationsSet);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_JOINT_ROTATIONS, jointRotations);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_JOINT_TRANSLATIONS_SET, jointTranslationsSet);
@@ -1393,21 +1410,24 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool
// Zones only
if (_type == EntityTypes::Zone) {
- _keyLight.copyToScriptValue(_desiredProperties, properties, engine, skipDefaults, defaultEntityProperties);
- _ambientLight.copyToScriptValue(_desiredProperties, properties, engine, skipDefaults, defaultEntityProperties);
-
- _skybox.copyToScriptValue(_desiredProperties, properties, engine, skipDefaults, defaultEntityProperties);
+ if (!psuedoPropertyFlagsButDesiredEmpty) {
+ _keyLight.copyToScriptValue(_desiredProperties, properties, engine, skipDefaults, defaultEntityProperties);
+ _ambientLight.copyToScriptValue(_desiredProperties, properties, engine, skipDefaults, defaultEntityProperties);
+ _skybox.copyToScriptValue(_desiredProperties, properties, engine, skipDefaults, defaultEntityProperties);
+ }
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_FLYING_ALLOWED, flyingAllowed);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_GHOSTING_ALLOWED, ghostingAllowed);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_FILTER_URL, filterURL);
COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(PROP_HAZE_MODE, hazeMode, getHazeModeAsString());
- _haze.copyToScriptValue(_desiredProperties, properties, engine, skipDefaults, defaultEntityProperties);
-
+ if (!psuedoPropertyFlagsButDesiredEmpty) {
+ _haze.copyToScriptValue(_desiredProperties, properties, engine, skipDefaults, defaultEntityProperties);
+ }
COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(PROP_BLOOM_MODE, bloomMode, getBloomModeAsString());
- _bloom.copyToScriptValue(_desiredProperties, properties, engine, skipDefaults, defaultEntityProperties);
-
+ if (!psuedoPropertyFlagsButDesiredEmpty) {
+ _bloom.copyToScriptValue(_desiredProperties, properties, engine, skipDefaults, defaultEntityProperties);
+ }
COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(PROP_KEY_LIGHT_MODE, keyLightMode, getKeyLightModeAsString());
COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(PROP_AMBIENT_LIGHT_MODE, ambientLightMode, getAmbientLightModeAsString());
COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(PROP_SKYBOX_MODE, skyboxMode, getSkyboxModeAsString());
@@ -1468,7 +1488,9 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool
* @property {Vec3} center - The center of the AA box.
* @property {Vec3} dimensions - The dimensions of the AA box.
*/
- if (!skipDefaults && !strictSemantics) {
+ if (!skipDefaults && !strictSemantics &&
+ (!psuedoPropertyFlagsActive || psueudoPropertyFlags.test(EntityPsuedoPropertyFlag::BoundingBox))) {
+
AABox aaBox = getAABox();
QScriptValue boundingBox = engine->newObject();
QScriptValue bottomRightNear = vec3toScriptValue(engine, aaBox.getCorner());
@@ -1483,7 +1505,7 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool
}
QString textureNamesStr = QJsonDocument::fromVariant(_textureNames).toJson();
- if (!skipDefaults && !strictSemantics) {
+ if (!skipDefaults && !strictSemantics && (!psuedoPropertyFlagsActive || psueudoPropertyFlags.test(EntityPsuedoPropertyFlag::OriginalTextures))) {
COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER_NO_SKIP(originalTextures, textureNamesStr); // gettable, but not settable
}
@@ -1509,7 +1531,9 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_CLONE_ORIGIN_ID, cloneOriginID);
// Rendering info
- if (!skipDefaults && !strictSemantics) {
+ if (!skipDefaults && !strictSemantics &&
+ (!psuedoPropertyFlagsActive || psueudoPropertyFlags.test(EntityPsuedoPropertyFlag::RenderInfo))) {
+
QScriptValue renderInfo = engine->newObject();
/**jsdoc
@@ -1535,8 +1559,12 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool
}
// FIXME: These properties should already have been set above.
- properties.setProperty("clientOnly", convertScriptValue(engine, getClientOnly()));
- properties.setProperty("owningAvatarID", convertScriptValue(engine, getOwningAvatarID()));
+ if (!psuedoPropertyFlagsActive || psueudoPropertyFlags.test(EntityPsuedoPropertyFlag::ClientOnly)) {
+ properties.setProperty("clientOnly", convertScriptValue(engine, getClientOnly()));
+ }
+ if (!psuedoPropertyFlagsActive || psueudoPropertyFlags.test(EntityPsuedoPropertyFlag::OwningAvatarID)) {
+ properties.setProperty("owningAvatarID", convertScriptValue(engine, getOwningAvatarID()));
+ }
// FIXME - I don't think these properties are supported any more
//COPY_PROPERTY_TO_QSCRIPTVALUE(localRenderAlpha);
diff --git a/libraries/entities/src/EntityItemProperties.h b/libraries/entities/src/EntityItemProperties.h
index 50305345de..338ec5e071 100644
--- a/libraries/entities/src/EntityItemProperties.h
+++ b/libraries/entities/src/EntityItemProperties.h
@@ -35,6 +35,7 @@
#include "EntityItemPropertiesMacros.h"
#include "EntityTypes.h"
#include "EntityPropertyFlags.h"
+#include "EntityPsuedoPropertyFlags.h"
#include "LightEntityItem.h"
#include "LineEntityItem.h"
#include "ParticleEffectEntityItem.h"
@@ -86,7 +87,8 @@ public:
EntityTypes::EntityType getType() const { return _type; }
void setType(EntityTypes::EntityType type) { _type = type; }
- virtual QScriptValue copyToScriptValue(QScriptEngine* engine, bool skipDefaults, bool allowUnknownCreateTime = false, bool strictSemantics = false) const;
+ virtual QScriptValue copyToScriptValue(QScriptEngine* engine, bool skipDefaults, bool allowUnknownCreateTime = false,
+ bool strictSemantics = false, EntityPsuedoPropertyFlags psueudoPropertyFlags = EntityPsuedoPropertyFlags()) const;
virtual void copyFromScriptValue(const QScriptValue& object, bool honorReadOnly);
static QScriptValue entityPropertyFlagsToScriptValue(QScriptEngine* engine, const EntityPropertyFlags& flags);
diff --git a/libraries/entities/src/EntityItemPropertiesMacros.h b/libraries/entities/src/EntityItemPropertiesMacros.h
index 213460ec50..ff4fb39354 100644
--- a/libraries/entities/src/EntityItemPropertiesMacros.h
+++ b/libraries/entities/src/EntityItemPropertiesMacros.h
@@ -155,7 +155,7 @@ inline QScriptValue convertScriptValue(QScriptEngine* e, const AACube& v) { retu
}
#define COPY_PROPERTY_TO_QSCRIPTVALUE(p,P) \
- if ((_desiredProperties.isEmpty() || _desiredProperties.getHasProperty(p)) && \
+ if (((!psuedoPropertyFlagsButDesiredEmpty && _desiredProperties.isEmpty()) || _desiredProperties.getHasProperty(p)) && \
(!skipDefaults || defaultEntityProperties._##P != _##P)) { \
QScriptValue V = convertScriptValue(engine, _##P); \
properties.setProperty(#P, V); \
@@ -165,7 +165,7 @@ inline QScriptValue convertScriptValue(QScriptEngine* e, const AACube& v) { retu
properties.setProperty(#P, G);
#define COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(p, P, G) \
- if ((_desiredProperties.isEmpty() || _desiredProperties.getHasProperty(p)) && \
+ if (((!psuedoPropertyFlagsButDesiredEmpty && _desiredProperties.isEmpty()) || _desiredProperties.getHasProperty(p)) && \
(!skipDefaults || defaultEntityProperties._##P != _##P)) { \
QScriptValue V = convertScriptValue(engine, G); \
properties.setProperty(#P, V); \
@@ -173,7 +173,7 @@ inline QScriptValue convertScriptValue(QScriptEngine* e, const AACube& v) { retu
// same as COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER but uses #X instead of #P in the setProperty() step
#define COPY_PROXY_PROPERTY_TO_QSCRIPTVALUE_GETTER(p, P, X, G) \
- if ((_desiredProperties.isEmpty() || _desiredProperties.getHasProperty(p)) && \
+ if (((!psuedoPropertyFlagsButDesiredEmpty && _desiredProperties.isEmpty()) || _desiredProperties.getHasProperty(p)) && \
(!skipDefaults || defaultEntityProperties._##P != _##P)) { \
QScriptValue V = convertScriptValue(engine, G); \
properties.setProperty(#X, V); \
diff --git a/libraries/entities/src/EntityPsuedoPropertyFlags.h b/libraries/entities/src/EntityPsuedoPropertyFlags.h
new file mode 100644
index 0000000000..0b051a4c74
--- /dev/null
+++ b/libraries/entities/src/EntityPsuedoPropertyFlags.h
@@ -0,0 +1,41 @@
+//
+// EntityPsuedoPropertyFlags.h
+// libraries/entities/src
+//
+// Created by Thijs Wenker on 9/18/18.
+// 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
+//
+
+#pragma once
+
+#ifndef hifi_EntityPsuedoPropertyFlag_h
+#define hifi_EntityPsuedoPropertyFlag_h
+
+#include
+#include
+
+namespace EntityPsuedoPropertyFlag {
+ enum {
+ None = 0,
+ FlagsActive,
+ ID,
+ Type,
+ Created,
+ Age,
+ AgeAsText,
+ LastEdited,
+ BoundingBox,
+ OriginalTextures,
+ RenderInfo,
+ ClientOnly,
+ OwningAvatarID,
+
+ NumFlags
+ };
+}
+typedef std::bitset EntityPsuedoPropertyFlags;
+
+#endif // hifi_EntityPsuedoPropertyFlag_h
diff --git a/libraries/entities/src/EntityScriptingInterface.cpp b/libraries/entities/src/EntityScriptingInterface.cpp
index d9924cb9fd..22eb57e051 100644
--- a/libraries/entities/src/EntityScriptingInterface.cpp
+++ b/libraries/entities/src/EntityScriptingInterface.cpp
@@ -42,7 +42,7 @@ const QString GRABBABLE_USER_DATA = "{\"grabbableKey\":{\"grabbable\":true}}";
const QString NOT_GRABBABLE_USER_DATA = "{\"grabbableKey\":{\"grabbable\":false}}";
EntityScriptingInterface::EntityScriptingInterface(bool bidOnSimulationOwnership) :
- _entityTree(NULL),
+ _entityTree(nullptr),
_bidOnSimulationOwnership(bidOnSimulationOwnership)
{
auto nodeList = DependencyManager::get();
@@ -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()) {
@@ -352,19 +350,19 @@ QUuid EntityScriptingInterface::cloneEntity(QUuid entityIDToClone) {
}
}
-EntityItemProperties EntityScriptingInterface::getEntityProperties(QUuid identity) {
- EntityPropertyFlags noSpecificProperties;
- return getEntityProperties(identity, noSpecificProperties);
+EntityItemProperties EntityScriptingInterface::getEntityProperties(QUuid entityID) {
+ const EntityPropertyFlags noSpecificProperties;
+ return getEntityProperties(entityID, noSpecificProperties);
}
-EntityItemProperties EntityScriptingInterface::getEntityProperties(QUuid identity, EntityPropertyFlags desiredProperties) {
+EntityItemProperties EntityScriptingInterface::getEntityProperties(QUuid entityID, EntityPropertyFlags desiredProperties) {
PROFILE_RANGE(script_entities, __FUNCTION__);
bool scalesWithParent { false };
EntityItemProperties results;
if (_entityTree) {
_entityTree->withReadLock([&] {
- EntityItemPointer entity = _entityTree->findEntityByEntityItemID(EntityItemID(identity));
+ EntityItemPointer entity = _entityTree->findEntityByEntityItemID(EntityItemID(entityID));
if (entity) {
scalesWithParent = entity->getScalesWithParent();
if (desiredProperties.getHasProperty(PROP_POSITION) ||
@@ -399,6 +397,134 @@ EntityItemProperties EntityScriptingInterface::getEntityProperties(QUuid identit
return convertPropertiesToScriptSemantics(results, scalesWithParent);
}
+
+struct EntityPropertiesResult {
+ EntityPropertiesResult(const EntityItemProperties& properties, bool scalesWithParent) :
+ properties(properties),
+ scalesWithParent(scalesWithParent) {
+ }
+ EntityPropertiesResult() = default;
+ EntityItemProperties properties;
+ bool scalesWithParent{ false };
+};
+
+// Static method to make sure that we have the right script engine.
+// Using sender() or QtScriptable::engine() does not work for classes used by multiple threads (script-engines)
+QScriptValue EntityScriptingInterface::getMultipleEntityProperties(QScriptContext* context, QScriptEngine* engine) {
+ const int ARGUMENT_ENTITY_IDS = 0;
+ const int ARGUMENT_EXTENDED_DESIRED_PROPERTIES = 1;
+
+ auto entityScriptingInterface = DependencyManager::get();
+ const auto entityIDs = qScriptValueToValue>(context->argument(ARGUMENT_ENTITY_IDS));
+ return entityScriptingInterface->getMultipleEntityPropertiesInternal(engine, entityIDs, context->argument(ARGUMENT_EXTENDED_DESIRED_PROPERTIES));
+}
+
+QScriptValue EntityScriptingInterface::getMultipleEntityPropertiesInternal(QScriptEngine* engine, QVector entityIDs, const QScriptValue& extendedDesiredProperties) {
+ PROFILE_RANGE(script_entities, __FUNCTION__);
+
+ EntityPsuedoPropertyFlags psuedoPropertyFlags;
+ const auto readExtendedPropertyStringValue = [&](QScriptValue extendedProperty) {
+ const auto extendedPropertyString = extendedProperty.toString();
+ if (extendedPropertyString == "id") {
+ psuedoPropertyFlags.set(EntityPsuedoPropertyFlag::ID);
+ } else if (extendedPropertyString == "type") {
+ psuedoPropertyFlags.set(EntityPsuedoPropertyFlag::Type);
+ } else if (extendedPropertyString == "created") {
+ psuedoPropertyFlags.set(EntityPsuedoPropertyFlag::Created);
+ } else if (extendedPropertyString == "age") {
+ psuedoPropertyFlags.set(EntityPsuedoPropertyFlag::Age);
+ } else if (extendedPropertyString == "ageAsText") {
+ psuedoPropertyFlags.set(EntityPsuedoPropertyFlag::AgeAsText);
+ } else if (extendedPropertyString == "lastEdited") {
+ psuedoPropertyFlags.set(EntityPsuedoPropertyFlag::LastEdited);
+ } else if (extendedPropertyString == "boundingBox") {
+ psuedoPropertyFlags.set(EntityPsuedoPropertyFlag::BoundingBox);
+ } else if (extendedPropertyString == "originalTextures") {
+ psuedoPropertyFlags.set(EntityPsuedoPropertyFlag::OriginalTextures);
+ } else if (extendedPropertyString == "renderInfo") {
+ psuedoPropertyFlags.set(EntityPsuedoPropertyFlag::RenderInfo);
+ } else if (extendedPropertyString == "clientOnly") {
+ psuedoPropertyFlags.set(EntityPsuedoPropertyFlag::ClientOnly);
+ } else if (extendedPropertyString == "owningAvatarID") {
+ psuedoPropertyFlags.set(EntityPsuedoPropertyFlag::OwningAvatarID);
+ }
+ };
+
+ if (extendedDesiredProperties.isString()) {
+ readExtendedPropertyStringValue(extendedDesiredProperties);
+ psuedoPropertyFlags.set(EntityPsuedoPropertyFlag::FlagsActive);
+ } else if (extendedDesiredProperties.isArray()) {
+ const quint32 length = extendedDesiredProperties.property("length").toInt32();
+ for (quint32 i = 0; i < length; i++) {
+ readExtendedPropertyStringValue(extendedDesiredProperties.property(i));
+ }
+ psuedoPropertyFlags.set(EntityPsuedoPropertyFlag::FlagsActive);
+ }
+
+ EntityPropertyFlags desiredProperties = qScriptValueToValue(extendedDesiredProperties);
+ bool needsScriptSemantics = desiredProperties.getHasProperty(PROP_POSITION) ||
+ desiredProperties.getHasProperty(PROP_ROTATION) ||
+ desiredProperties.getHasProperty(PROP_LOCAL_POSITION) ||
+ desiredProperties.getHasProperty(PROP_LOCAL_ROTATION) ||
+ desiredProperties.getHasProperty(PROP_LOCAL_VELOCITY) ||
+ desiredProperties.getHasProperty(PROP_LOCAL_ANGULAR_VELOCITY) ||
+ desiredProperties.getHasProperty(PROP_LOCAL_DIMENSIONS);
+ if (needsScriptSemantics) {
+ // if we are explicitly getting position or rotation, we need parent information to make sense of them.
+ desiredProperties.setHasProperty(PROP_PARENT_ID);
+ desiredProperties.setHasProperty(PROP_PARENT_JOINT_INDEX);
+ }
+ QVector resultProperties;
+ if (_entityTree) {
+ PROFILE_RANGE(script_entities, "EntityScriptingInterface::getMultipleEntityProperties>Obtaining Properties");
+ int i = 0;
+ const int lockAmount = 500;
+ int size = entityIDs.size();
+ while (i < size) {
+ _entityTree->withReadLock([&] {
+ for (int j = 0; j < lockAmount && i < size; ++i, ++j) {
+ const auto& entityID = entityIDs.at(i);
+ const EntityItemPointer entity = _entityTree->findEntityByEntityItemID(EntityItemID(entityID));
+ if (entity) {
+ if (psuedoPropertyFlags.none() && desiredProperties.isEmpty()) {
+ // these are left out of EntityItem::getEntityProperties so that localPosition and localRotation
+ // don't end up in json saves, etc. We still want them here, though.
+ EncodeBitstreamParams params; // unknown
+ desiredProperties = entity->getEntityProperties(params);
+ desiredProperties.setHasProperty(PROP_LOCAL_POSITION);
+ desiredProperties.setHasProperty(PROP_LOCAL_ROTATION);
+ desiredProperties.setHasProperty(PROP_LOCAL_VELOCITY);
+ desiredProperties.setHasProperty(PROP_LOCAL_ANGULAR_VELOCITY);
+ desiredProperties.setHasProperty(PROP_LOCAL_DIMENSIONS);
+ psuedoPropertyFlags.set();
+ needsScriptSemantics = true;
+ }
+
+ auto properties = entity->getProperties(desiredProperties, true);
+ EntityPropertiesResult result(properties, entity->getScalesWithParent());
+ resultProperties.append(result);
+ }
+ }
+ });
+ }
+ }
+ QScriptValue finalResult = engine->newArray(resultProperties.size());
+ quint32 i = 0;
+ if (needsScriptSemantics) {
+ PROFILE_RANGE(script_entities, "EntityScriptingInterface::getMultipleEntityProperties>Script Semantics");
+ foreach(const auto& result, resultProperties) {
+ finalResult.setProperty(i++, convertPropertiesToScriptSemantics(result.properties, result.scalesWithParent)
+ .copyToScriptValue(engine, false, false, false, psuedoPropertyFlags));
+ }
+ } else {
+ PROFILE_RANGE(script_entities, "EntityScriptingInterface::getMultipleEntityProperties>Skip Script Semantics");
+ foreach(const auto& result, resultProperties) {
+ finalResult.setProperty(i++, result.properties.copyToScriptValue(engine, false, false, false, psuedoPropertyFlags));
+ }
+ }
+ return finalResult;
+}
+
QUuid EntityScriptingInterface::editEntity(QUuid id, const EntityItemProperties& scriptSideProperties) {
PROFILE_RANGE(script_entities, __FUNCTION__);
diff --git a/libraries/entities/src/EntityScriptingInterface.h b/libraries/entities/src/EntityScriptingInterface.h
index 3e0f040fd6..df7b0df9a1 100644
--- a/libraries/entities/src/EntityScriptingInterface.h
+++ b/libraries/entities/src/EntityScriptingInterface.h
@@ -149,6 +149,21 @@ public:
const QVector& entityIdsToInclude, const QVector& entityIdsToDiscard,
bool visibleOnly, bool collidableOnly);
+ /**jsdoc
+ * Get the properties of multiple entities.
+ * @function Entities.getMultipleEntityProperties
+ * @param {Uuid[]} entityIDs - The IDs of the entities to get the properties of.
+ * @param {string[]|string} [desiredProperties=[]] - Either string with property name or array of the names of the properties
+ * to get. If the array is empty, all properties are returned.
+ * @returns {Entities.EntityProperties[]} The properties of the entity if the entity can be found, otherwise an empty object.
+ * @example Retrieve the names of the nearby entities
+ * var SEARCH_RADIUS = 50; // meters
+ * var entityIds = Entities.findEntities(MyAvatar.position, SEARCH_RADIUS);
+ * var propertySets = Entities.getMultipleEntityProperties(entityIds, "name");
+ * print("Nearby entity names: " + JSON.stringify(propertySets));
+ */
+ static QScriptValue getMultipleEntityProperties(QScriptContext* context, QScriptEngine* engine);
+ QScriptValue getMultipleEntityPropertiesInternal(QScriptEngine* engine, QVector entityIDs, const QScriptValue& extendedDesiredProperties);
public slots:
/**jsdoc
@@ -270,7 +285,7 @@ public slots:
* print("Entity color: " + JSON.stringify(properties.color));
*/
Q_INVOKABLE EntityItemProperties getEntityProperties(QUuid entityID);
- Q_INVOKABLE EntityItemProperties getEntityProperties(QUuid identity, EntityPropertyFlags desiredProperties);
+ Q_INVOKABLE EntityItemProperties getEntityProperties(QUuid entityID, EntityPropertyFlags desiredProperties);
/**jsdoc
* Update an entity with specified properties.
diff --git a/libraries/entities/src/EntityTreeElement.cpp b/libraries/entities/src/EntityTreeElement.cpp
index efe5dafccf..5b71010f75 100644
--- a/libraries/entities/src/EntityTreeElement.cpp
+++ b/libraries/entities/src/EntityTreeElement.cpp
@@ -145,7 +145,7 @@ EntityItemID EntityTreeElement::findRayIntersection(const glm::vec3& origin, con
bool visibleOnly, bool collidableOnly, QVariantMap& extraInfo, bool precisionPicking) {
EntityItemID result;
- BoxFace localFace;
+ BoxFace localFace { UNKNOWN_FACE };
glm::vec3 localSurfaceNormal;
if (!canPickIntersect()) {
@@ -213,7 +213,7 @@ EntityItemID EntityTreeElement::findDetailedRayIntersection(const glm::vec3& ori
// we can use the AABox's ray intersection by mapping our origin and direction into the entity frame
// and testing intersection there.
float localDistance;
- BoxFace localFace;
+ BoxFace localFace { UNKNOWN_FACE };
glm::vec3 localSurfaceNormal;
if (entityFrameBox.findRayIntersection(entityFrameOrigin, entityFrameDirection, 1.0f / entityFrameDirection, localDistance,
localFace, localSurfaceNormal)) {
diff --git a/libraries/entities/src/EntityTypes.h b/libraries/entities/src/EntityTypes.h
index 1f3434d254..954bdf8f17 100644
--- a/libraries/entities/src/EntityTypes.h
+++ b/libraries/entities/src/EntityTypes.h
@@ -13,7 +13,6 @@
#define hifi_EntityTypes_h
#include
-#include
#include
#include
diff --git a/libraries/entities/src/LightEntityItem.cpp b/libraries/entities/src/LightEntityItem.cpp
index 1db67fc0b6..57a83a4173 100644
--- a/libraries/entities/src/LightEntityItem.cpp
+++ b/libraries/entities/src/LightEntityItem.cpp
@@ -69,8 +69,8 @@ void LightEntityItem::dimensionsChanged() {
}
-EntityItemProperties LightEntityItem::getProperties(EntityPropertyFlags desiredProperties) const {
- EntityItemProperties properties = EntityItem::getProperties(desiredProperties); // get the properties from our base class
+EntityItemProperties LightEntityItem::getProperties(const EntityPropertyFlags& desiredProperties, bool allowEmptyDesiredProperties) const {
+ EntityItemProperties properties = EntityItem::getProperties(desiredProperties, allowEmptyDesiredProperties); // get the properties from our base class
COPY_ENTITY_PROPERTY_TO_PROPERTIES(isSpotlight, getIsSpotlight);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(color, getXColor);
diff --git a/libraries/entities/src/LightEntityItem.h b/libraries/entities/src/LightEntityItem.h
index 518cb18de2..f56b5ce624 100644
--- a/libraries/entities/src/LightEntityItem.h
+++ b/libraries/entities/src/LightEntityItem.h
@@ -35,7 +35,7 @@ public:
virtual bool setSubClassProperties(const EntityItemProperties& properties) override;
// methods for getting/setting all properties of an entity
- virtual EntityItemProperties getProperties(EntityPropertyFlags desiredProperties = EntityPropertyFlags()) const override;
+ virtual EntityItemProperties getProperties(const EntityPropertyFlags& desiredProperties, bool allowEmptyDesiredProperties) const override;
virtual EntityPropertyFlags getEntityProperties(EncodeBitstreamParams& params) const override;
diff --git a/libraries/entities/src/LineEntityItem.cpp b/libraries/entities/src/LineEntityItem.cpp
index 92a1c25970..1b20922b7d 100644
--- a/libraries/entities/src/LineEntityItem.cpp
+++ b/libraries/entities/src/LineEntityItem.cpp
@@ -37,9 +37,9 @@ LineEntityItem::LineEntityItem(const EntityItemID& entityItemID) :
_type = EntityTypes::Line;
}
-EntityItemProperties LineEntityItem::getProperties(EntityPropertyFlags desiredProperties) const {
+EntityItemProperties LineEntityItem::getProperties(const EntityPropertyFlags& desiredProperties, bool allowEmptyDesiredProperties) const {
- EntityItemProperties properties = EntityItem::getProperties(desiredProperties); // get the properties from our base class
+ EntityItemProperties properties = EntityItem::getProperties(desiredProperties, allowEmptyDesiredProperties); // get the properties from our base class
properties._color = getXColor();
diff --git a/libraries/entities/src/LineEntityItem.h b/libraries/entities/src/LineEntityItem.h
index 7c21b5c9d2..06f7830e06 100644
--- a/libraries/entities/src/LineEntityItem.h
+++ b/libraries/entities/src/LineEntityItem.h
@@ -23,7 +23,7 @@ class LineEntityItem : public EntityItem {
ALLOW_INSTANTIATION // This class can be instantiated
// methods for getting/setting all properties of an entity
- virtual EntityItemProperties getProperties(EntityPropertyFlags desiredProperties = EntityPropertyFlags()) const override;
+ virtual EntityItemProperties getProperties(const EntityPropertyFlags& desiredProperties, bool allowEmptyDesiredProperties) const override;
virtual bool setProperties(const EntityItemProperties& properties) override;
virtual EntityPropertyFlags getEntityProperties(EncodeBitstreamParams& params) const override;
diff --git a/libraries/entities/src/MaterialEntityItem.cpp b/libraries/entities/src/MaterialEntityItem.cpp
index 489ba5772c..06afda4283 100644
--- a/libraries/entities/src/MaterialEntityItem.cpp
+++ b/libraries/entities/src/MaterialEntityItem.cpp
@@ -31,8 +31,8 @@ MaterialEntityItem::~MaterialEntityItem() {
removeMaterial();
}
-EntityItemProperties MaterialEntityItem::getProperties(EntityPropertyFlags desiredProperties) const {
- EntityItemProperties properties = EntityItem::getProperties(desiredProperties); // get the properties from our base class
+EntityItemProperties MaterialEntityItem::getProperties(const EntityPropertyFlags& desiredProperties, bool allowEmptyDesiredProperties) const {
+ EntityItemProperties properties = EntityItem::getProperties(desiredProperties, allowEmptyDesiredProperties); // get the properties from our base class
COPY_ENTITY_PROPERTY_TO_PROPERTIES(materialURL, getMaterialURL);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(materialMappingMode, getMaterialMappingMode);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(priority, getPriority);
diff --git a/libraries/entities/src/MaterialEntityItem.h b/libraries/entities/src/MaterialEntityItem.h
index 30743850dd..7177aaf718 100644
--- a/libraries/entities/src/MaterialEntityItem.h
+++ b/libraries/entities/src/MaterialEntityItem.h
@@ -29,7 +29,7 @@ public:
bool needsToCallUpdate() const override { return true; }
// methods for getting/setting all properties of an entity
- virtual EntityItemProperties getProperties(EntityPropertyFlags desiredProperties = EntityPropertyFlags()) const override;
+ virtual EntityItemProperties getProperties(const EntityPropertyFlags& desiredProperties, bool allowEmptyDesiredProperties) const override;
virtual bool setProperties(const EntityItemProperties& properties) override;
virtual EntityPropertyFlags getEntityProperties(EncodeBitstreamParams& params) const override;
diff --git a/libraries/entities/src/ModelEntityItem.cpp b/libraries/entities/src/ModelEntityItem.cpp
index f006692415..e3fca680f3 100644
--- a/libraries/entities/src/ModelEntityItem.cpp
+++ b/libraries/entities/src/ModelEntityItem.cpp
@@ -54,8 +54,8 @@ void ModelEntityItem::setTextures(const QString& textures) {
_textures = textures;
}
-EntityItemProperties ModelEntityItem::getProperties(EntityPropertyFlags desiredProperties) const {
- EntityItemProperties properties = EntityItem::getProperties(desiredProperties); // get the properties from our base class
+EntityItemProperties ModelEntityItem::getProperties(const EntityPropertyFlags& desiredProperties, bool allowEmptyDesiredProperties) const {
+ EntityItemProperties properties = EntityItem::getProperties(desiredProperties, allowEmptyDesiredProperties); // get the properties from our base class
COPY_ENTITY_PROPERTY_TO_PROPERTIES(color, getXColor);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(modelURL, getModelURL);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(compoundShapeURL, getCompoundShapeURL);
diff --git a/libraries/entities/src/ModelEntityItem.h b/libraries/entities/src/ModelEntityItem.h
index ef758b9dde..8d34664a09 100644
--- a/libraries/entities/src/ModelEntityItem.h
+++ b/libraries/entities/src/ModelEntityItem.h
@@ -27,7 +27,7 @@ public:
ALLOW_INSTANTIATION // This class can be instantiated
// methods for getting/setting all properties of an entity
- virtual EntityItemProperties getProperties(EntityPropertyFlags desiredProperties = EntityPropertyFlags()) const override;
+ virtual EntityItemProperties getProperties(const EntityPropertyFlags& desiredProperties, bool allowEmptyDesiredProperties) const override;
virtual bool setProperties(const EntityItemProperties& properties) override;
virtual EntityPropertyFlags getEntityProperties(EncodeBitstreamParams& params) const override;
diff --git a/libraries/entities/src/ParticleEffectEntityItem.cpp b/libraries/entities/src/ParticleEffectEntityItem.cpp
index 238f41b05f..975acf153a 100644
--- a/libraries/entities/src/ParticleEffectEntityItem.cpp
+++ b/libraries/entities/src/ParticleEffectEntityItem.cpp
@@ -408,8 +408,8 @@ void ParticleEffectEntityItem::computeAndUpdateDimensions() {
}
-EntityItemProperties ParticleEffectEntityItem::getProperties(EntityPropertyFlags desiredProperties) const {
- EntityItemProperties properties = EntityItem::getProperties(desiredProperties); // get the properties from our base class
+EntityItemProperties ParticleEffectEntityItem::getProperties(const EntityPropertyFlags& desiredProperties, bool allowEmptyDesiredProperties) const {
+ EntityItemProperties properties = EntityItem::getProperties(desiredProperties, allowEmptyDesiredProperties); // get the properties from our base class
COPY_ENTITY_PROPERTY_TO_PROPERTIES(color, getXColor);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(alpha, getAlpha);
diff --git a/libraries/entities/src/ParticleEffectEntityItem.h b/libraries/entities/src/ParticleEffectEntityItem.h
index 02284768ce..a8e133942e 100644
--- a/libraries/entities/src/ParticleEffectEntityItem.h
+++ b/libraries/entities/src/ParticleEffectEntityItem.h
@@ -210,7 +210,7 @@ public:
ParticleEffectEntityItem(const EntityItemID& entityItemID);
// methods for getting/setting all properties of this entity
- virtual EntityItemProperties getProperties(EntityPropertyFlags desiredProperties = EntityPropertyFlags()) const override;
+ virtual EntityItemProperties getProperties(const EntityPropertyFlags& desiredProperties, bool allowEmptyDesiredProperties) const override;
virtual bool setProperties(const EntityItemProperties& properties) override;
virtual EntityPropertyFlags getEntityProperties(EncodeBitstreamParams& params) const override;
diff --git a/libraries/entities/src/PolyLineEntityItem.cpp b/libraries/entities/src/PolyLineEntityItem.cpp
index 5b3167b9ba..2d0689b56a 100644
--- a/libraries/entities/src/PolyLineEntityItem.cpp
+++ b/libraries/entities/src/PolyLineEntityItem.cpp
@@ -36,9 +36,9 @@ PolyLineEntityItem::PolyLineEntityItem(const EntityItemID& entityItemID) : Entit
_type = EntityTypes::PolyLine;
}
-EntityItemProperties PolyLineEntityItem::getProperties(EntityPropertyFlags desiredProperties) const {
+EntityItemProperties PolyLineEntityItem::getProperties(const EntityPropertyFlags& desiredProperties, bool allowEmptyDesiredProperties) const {
QWriteLocker lock(&_quadReadWriteLock);
- EntityItemProperties properties = EntityItem::getProperties(desiredProperties); // get the properties from our base class
+ EntityItemProperties properties = EntityItem::getProperties(desiredProperties, allowEmptyDesiredProperties); // get the properties from our base class
properties._color = getXColor();
diff --git a/libraries/entities/src/PolyLineEntityItem.h b/libraries/entities/src/PolyLineEntityItem.h
index 52ec8e8c2d..94b46ac5e2 100644
--- a/libraries/entities/src/PolyLineEntityItem.h
+++ b/libraries/entities/src/PolyLineEntityItem.h
@@ -23,7 +23,7 @@ class PolyLineEntityItem : public EntityItem {
ALLOW_INSTANTIATION // This class can be instantiated
// methods for getting/setting all properties of an entity
- virtual EntityItemProperties getProperties(EntityPropertyFlags desiredProperties = EntityPropertyFlags()) const override;
+ virtual EntityItemProperties getProperties(const EntityPropertyFlags& desiredProperties, bool allowEmptyDesiredProperties) const override;
virtual bool setProperties(const EntityItemProperties& properties) override;
virtual EntityPropertyFlags getEntityProperties(EncodeBitstreamParams& params) const override;
diff --git a/libraries/entities/src/PolyVoxEntityItem.cpp b/libraries/entities/src/PolyVoxEntityItem.cpp
index ed3372818a..484a6110c3 100644
--- a/libraries/entities/src/PolyVoxEntityItem.cpp
+++ b/libraries/entities/src/PolyVoxEntityItem.cpp
@@ -113,8 +113,8 @@ glm::vec3 PolyVoxEntityItem::getVoxelVolumeSize() const {
}
-EntityItemProperties PolyVoxEntityItem::getProperties(EntityPropertyFlags desiredProperties) const {
- EntityItemProperties properties = EntityItem::getProperties(desiredProperties); // get the properties from our base class
+EntityItemProperties PolyVoxEntityItem::getProperties(const EntityPropertyFlags& desiredProperties, bool allowEmptyDesiredProperties) const {
+ EntityItemProperties properties = EntityItem::getProperties(desiredProperties, allowEmptyDesiredProperties); // get the properties from our base class
COPY_ENTITY_PROPERTY_TO_PROPERTIES(voxelVolumeSize, getVoxelVolumeSize);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(voxelData, getVoxelData);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(voxelSurfaceStyle, getVoxelSurfaceStyle);
diff --git a/libraries/entities/src/PolyVoxEntityItem.h b/libraries/entities/src/PolyVoxEntityItem.h
index d2ca4db124..ba238ab24f 100644
--- a/libraries/entities/src/PolyVoxEntityItem.h
+++ b/libraries/entities/src/PolyVoxEntityItem.h
@@ -23,7 +23,7 @@ class PolyVoxEntityItem : public EntityItem {
ALLOW_INSTANTIATION // This class can be instantiated
// methods for getting/setting all properties of an entity
- virtual EntityItemProperties getProperties(EntityPropertyFlags desiredProperties = EntityPropertyFlags()) const override;
+ virtual EntityItemProperties getProperties(const EntityPropertyFlags& desiredProperties, bool allowEmptyDesiredProperties) const override;
virtual bool setProperties(const EntityItemProperties& properties) override;
virtual EntityPropertyFlags getEntityProperties(EncodeBitstreamParams& params) const override;
diff --git a/libraries/entities/src/ShapeEntityItem.cpp b/libraries/entities/src/ShapeEntityItem.cpp
index 773a7059dc..a5e4e25e67 100644
--- a/libraries/entities/src/ShapeEntityItem.cpp
+++ b/libraries/entities/src/ShapeEntityItem.cpp
@@ -115,8 +115,8 @@ ShapeEntityItem::ShapeEntityItem(const EntityItemID& entityItemID) : EntityItem(
_material = std::make_shared();
}
-EntityItemProperties ShapeEntityItem::getProperties(EntityPropertyFlags desiredProperties) const {
- EntityItemProperties properties = EntityItem::getProperties(desiredProperties); // get the properties from our base class
+EntityItemProperties ShapeEntityItem::getProperties(const EntityPropertyFlags& desiredProperties, bool allowEmptyDesiredProperties) const {
+ EntityItemProperties properties = EntityItem::getProperties(desiredProperties, allowEmptyDesiredProperties); // get the properties from our base class
properties.setShape(entity::stringFromShape(getShape()));
COPY_ENTITY_PROPERTY_TO_PROPERTIES(color, getXColor);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(alpha, getAlpha);
diff --git a/libraries/entities/src/ShapeEntityItem.h b/libraries/entities/src/ShapeEntityItem.h
index ded5df15fe..d0326a3794 100644
--- a/libraries/entities/src/ShapeEntityItem.h
+++ b/libraries/entities/src/ShapeEntityItem.h
@@ -52,7 +52,7 @@ public:
//ALLOW_INSTANTIATION
// methods for getting/setting all properties of an entity
- EntityItemProperties getProperties(EntityPropertyFlags desiredProperties = EntityPropertyFlags()) const override;
+ EntityItemProperties getProperties(const EntityPropertyFlags& desiredProperties, bool allowEmptyDesiredProperties) const override;
bool setProperties(const EntityItemProperties& properties) override;
EntityPropertyFlags getEntityProperties(EncodeBitstreamParams& params) const override;
diff --git a/libraries/entities/src/TextEntityItem.cpp b/libraries/entities/src/TextEntityItem.cpp
index f130995bb5..da843256a0 100644
--- a/libraries/entities/src/TextEntityItem.cpp
+++ b/libraries/entities/src/TextEntityItem.cpp
@@ -46,8 +46,8 @@ void TextEntityItem::setUnscaledDimensions(const glm::vec3& value) {
EntityItem::setUnscaledDimensions(glm::vec3(value.x, value.y, TEXT_ENTITY_ITEM_FIXED_DEPTH));
}
-EntityItemProperties TextEntityItem::getProperties(EntityPropertyFlags desiredProperties) const {
- EntityItemProperties properties = EntityItem::getProperties(desiredProperties); // get the properties from our base class
+EntityItemProperties TextEntityItem::getProperties(const EntityPropertyFlags& desiredProperties, bool allowEmptyDesiredProperties) const {
+ EntityItemProperties properties = EntityItem::getProperties(desiredProperties, allowEmptyDesiredProperties); // get the properties from our base class
COPY_ENTITY_PROPERTY_TO_PROPERTIES(text, getText);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(lineHeight, getLineHeight);
diff --git a/libraries/entities/src/TextEntityItem.h b/libraries/entities/src/TextEntityItem.h
index 4ce5ef3297..cbddf87fda 100644
--- a/libraries/entities/src/TextEntityItem.h
+++ b/libraries/entities/src/TextEntityItem.h
@@ -27,7 +27,7 @@ public:
virtual ShapeType getShapeType() const override { return SHAPE_TYPE_BOX; }
// methods for getting/setting all properties of an entity
- virtual EntityItemProperties getProperties(EntityPropertyFlags desiredProperties = EntityPropertyFlags()) const override;
+ virtual EntityItemProperties getProperties(const EntityPropertyFlags& desiredProperties, bool allowEmptyDesiredProperties) const override;
virtual bool setProperties(const EntityItemProperties& properties) override;
virtual EntityPropertyFlags getEntityProperties(EncodeBitstreamParams& params) const override;
diff --git a/libraries/entities/src/WebEntityItem.cpp b/libraries/entities/src/WebEntityItem.cpp
index 0070eb538c..d20d36cd71 100644
--- a/libraries/entities/src/WebEntityItem.cpp
+++ b/libraries/entities/src/WebEntityItem.cpp
@@ -41,8 +41,8 @@ void WebEntityItem::setUnscaledDimensions(const glm::vec3& value) {
EntityItem::setUnscaledDimensions(glm::vec3(value.x, value.y, WEB_ENTITY_ITEM_FIXED_DEPTH));
}
-EntityItemProperties WebEntityItem::getProperties(EntityPropertyFlags desiredProperties) const {
- EntityItemProperties properties = EntityItem::getProperties(desiredProperties); // get the properties from our base class
+EntityItemProperties WebEntityItem::getProperties(const EntityPropertyFlags& desiredProperties, bool allowEmptyDesiredProperties) const {
+ EntityItemProperties properties = EntityItem::getProperties(desiredProperties, allowEmptyDesiredProperties); // get the properties from our base class
COPY_ENTITY_PROPERTY_TO_PROPERTIES(sourceUrl, getSourceUrl);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(dpi, getDPI);
return properties;
diff --git a/libraries/entities/src/WebEntityItem.h b/libraries/entities/src/WebEntityItem.h
index 2fa2033445..10d06e6f4a 100644
--- a/libraries/entities/src/WebEntityItem.h
+++ b/libraries/entities/src/WebEntityItem.h
@@ -26,7 +26,7 @@ public:
virtual ShapeType getShapeType() const override { return SHAPE_TYPE_BOX; }
// methods for getting/setting all properties of an entity
- virtual EntityItemProperties getProperties(EntityPropertyFlags desiredProperties = EntityPropertyFlags()) const override;
+ virtual EntityItemProperties getProperties(const EntityPropertyFlags& desiredProperties, bool allowEmptyDesiredProperties) const override;
virtual bool setProperties(const EntityItemProperties& properties) override;
virtual EntityPropertyFlags getEntityProperties(EncodeBitstreamParams& params) const override;
diff --git a/libraries/entities/src/ZoneEntityItem.cpp b/libraries/entities/src/ZoneEntityItem.cpp
index c0ae61fdba..1b8675caac 100644
--- a/libraries/entities/src/ZoneEntityItem.cpp
+++ b/libraries/entities/src/ZoneEntityItem.cpp
@@ -45,8 +45,8 @@ ZoneEntityItem::ZoneEntityItem(const EntityItemID& entityItemID) : EntityItem(en
_visuallyReady = false;
}
-EntityItemProperties ZoneEntityItem::getProperties(EntityPropertyFlags desiredProperties) const {
- EntityItemProperties properties = EntityItem::getProperties(desiredProperties); // get the properties from our base class
+EntityItemProperties ZoneEntityItem::getProperties(const EntityPropertyFlags& desiredProperties, bool allowEmptyDesiredProperties) const {
+ EntityItemProperties properties = EntityItem::getProperties(desiredProperties, allowEmptyDesiredProperties); // get the properties from our base class
// Contain QString properties, must be synchronized
withReadLock([&] {
diff --git a/libraries/entities/src/ZoneEntityItem.h b/libraries/entities/src/ZoneEntityItem.h
index e2ebf16f11..c2f4542aa6 100644
--- a/libraries/entities/src/ZoneEntityItem.h
+++ b/libraries/entities/src/ZoneEntityItem.h
@@ -30,7 +30,7 @@ public:
ALLOW_INSTANTIATION // This class can be instantiated
// methods for getting/setting all properties of an entity
- virtual EntityItemProperties getProperties(EntityPropertyFlags desiredProperties = EntityPropertyFlags()) const override;
+ virtual EntityItemProperties getProperties(const EntityPropertyFlags& desiredProperties, bool allowEmptyDesiredProperties) const override;
virtual bool setProperties(const EntityItemProperties& properties) override;
virtual bool setSubClassProperties(const EntityItemProperties& properties) override;
diff --git a/libraries/fbx/src/FBXReader.cpp b/libraries/fbx/src/FBXReader.cpp
index d0efed3df4..dd766f002c 100644
--- a/libraries/fbx/src/FBXReader.cpp
+++ b/libraries/fbx/src/FBXReader.cpp
@@ -1923,7 +1923,6 @@ FBXGeometry* FBXReader::extractFBXGeometry(const QVariantHash& mapping, const QS
};
// now that all joints have been scanned compute a k-Dop bounding volume of mesh
- glm::vec3 defaultCapsuleAxis(0.0f, 1.0f, 0.0f);
for (int i = 0; i < geometry.joints.size(); ++i) {
FBXJoint& joint = geometry.joints[i];
diff --git a/libraries/gpu-gl-common/src/gpu/gl/GLTexture.h b/libraries/gpu-gl-common/src/gpu/gl/GLTexture.h
index a6a38fbcd6..e9a55ad8e2 100644
--- a/libraries/gpu-gl-common/src/gpu/gl/GLTexture.h
+++ b/libraries/gpu-gl-common/src/gpu/gl/GLTexture.h
@@ -25,6 +25,7 @@ struct GLFilterMode {
class GLTextureTransferEngine {
public:
+ virtual ~GLTextureTransferEngine() {}
using Pointer = std::shared_ptr;
/// Called once per frame to perform any require memory management or transfer work
virtual void manageMemory() = 0;
diff --git a/libraries/gpu-gl/src/gpu/gl41/GL41BackendShader.cpp b/libraries/gpu-gl/src/gpu/gl41/GL41BackendShader.cpp
index 8a67ff9619..46f91fdc15 100644
--- a/libraries/gpu-gl/src/gpu/gl41/GL41BackendShader.cpp
+++ b/libraries/gpu-gl/src/gpu/gl41/GL41BackendShader.cpp
@@ -57,7 +57,7 @@ void GL41Backend::postLinkProgram(ShaderObject& programObject, const Shader& pro
const auto resourceBufferUniforms = ::gl::Uniform::loadByName(glprogram, program.getResourceBuffers().getNames());
for (const auto& resourceBuffer : resourceBufferUniforms) {
const auto& targetBinding = expectedResourceBuffers.at(resourceBuffer.name);
- glProgramUniform1i(glprogram, resourceBuffer.binding, targetBinding);
+ glProgramUniform1i(glprogram, resourceBuffer.binding, targetBinding + GL41Backend::RESOURCE_BUFFER_SLOT0_TEX_UNIT);
}
}
diff --git a/libraries/gpu-gl/src/gpu/gl41/GL41BackendTexture.cpp b/libraries/gpu-gl/src/gpu/gl41/GL41BackendTexture.cpp
index 97b1a96a1d..d1b5969793 100644
--- a/libraries/gpu-gl/src/gpu/gl41/GL41BackendTexture.cpp
+++ b/libraries/gpu-gl/src/gpu/gl41/GL41BackendTexture.cpp
@@ -295,7 +295,6 @@ GL41VariableAllocationTexture::GL41VariableAllocationTexture(const std::weak_ptr
_maxAllocatedMip = _populatedMip = mipLevels;
_minAllocatedMip = texture.minAvailableMipLevel();
- uvec3 mipDimensions;
for (uint16_t mip = _minAllocatedMip; mip < mipLevels; ++mip) {
if (glm::all(glm::lessThanEqual(texture.evalMipDimensions(mip), INITIAL_MIP_TRANSFER_DIMENSIONS))) {
_maxAllocatedMip = _populatedMip = mip;
diff --git a/libraries/gpu-gl/src/gpu/gl45/GL45BackendVariableTexture.cpp b/libraries/gpu-gl/src/gpu/gl45/GL45BackendVariableTexture.cpp
index 4689163a47..f53eff637d 100644
--- a/libraries/gpu-gl/src/gpu/gl45/GL45BackendVariableTexture.cpp
+++ b/libraries/gpu-gl/src/gpu/gl45/GL45BackendVariableTexture.cpp
@@ -85,7 +85,6 @@ GL45ResourceTexture::GL45ResourceTexture(const std::weak_ptr& backend
_maxAllocatedMip = _populatedMip = mipLevels;
_minAllocatedMip = texture.minAvailableMipLevel();
- uvec3 mipDimensions;
for (uint16_t mip = _minAllocatedMip; mip < mipLevels; ++mip) {
if (glm::all(glm::lessThanEqual(texture.evalMipDimensions(mip), INITIAL_MIP_TRANSFER_DIMENSIONS))) {
_maxAllocatedMip = _populatedMip = mip;
diff --git a/libraries/gpu/src/gpu/State.h b/libraries/gpu/src/gpu/State.h
index 385edec277..9bcd69dcdb 100755
--- a/libraries/gpu/src/gpu/State.h
+++ b/libraries/gpu/src/gpu/State.h
@@ -118,10 +118,12 @@ public:
uint8 _function = LESS;
uint8 _writeMask = true;
uint8 _enabled = false;
- uint8 _spare = 0;
+ uint8 _spare = 0; // _spare is here to to affect alignment
public:
DepthTest(bool enabled = false, bool writeMask = true, ComparisonFunction func = LESS) :
- _function(func), _writeMask(writeMask), _enabled(enabled) {}
+ _function(func), _writeMask(writeMask), _enabled(enabled) {
+ (void)_spare; // to avoid unusued variable warning
+ }
bool isEnabled() const { return _enabled != 0; }
ComparisonFunction getFunction() const { return ComparisonFunction(_function); }
diff --git a/libraries/graphics-scripting/src/graphics-scripting/GraphicsScriptingInterface.cpp b/libraries/graphics-scripting/src/graphics-scripting/GraphicsScriptingInterface.cpp
index 6fd0017ae2..f2afc1e7d4 100644
--- a/libraries/graphics-scripting/src/graphics-scripting/GraphicsScriptingInterface.cpp
+++ b/libraries/graphics-scripting/src/graphics-scripting/GraphicsScriptingInterface.cpp
@@ -445,5 +445,3 @@ void GraphicsScriptingInterface::registerMetaTypes(QScriptEngine* engine) {
Q_UNUSED(metaTypeIds);
}
-
-#include "GraphicsScriptingInterface.moc"
diff --git a/libraries/graphics-scripting/src/graphics-scripting/ScriptableMesh.cpp b/libraries/graphics-scripting/src/graphics-scripting/ScriptableMesh.cpp
index 585a719638..72d2adb48f 100644
--- a/libraries/graphics-scripting/src/graphics-scripting/ScriptableMesh.cpp
+++ b/libraries/graphics-scripting/src/graphics-scripting/ScriptableMesh.cpp
@@ -401,6 +401,3 @@ scriptable::ScriptableMesh::~ScriptableMesh() {
#endif
strongMesh.reset();
}
-
-#include "ScriptableMesh.moc"
-
diff --git a/libraries/graphics-scripting/src/graphics-scripting/ScriptableModel.cpp b/libraries/graphics-scripting/src/graphics-scripting/ScriptableModel.cpp
index 7aaa182163..51085561c3 100644
--- a/libraries/graphics-scripting/src/graphics-scripting/ScriptableModel.cpp
+++ b/libraries/graphics-scripting/src/graphics-scripting/ScriptableModel.cpp
@@ -240,5 +240,3 @@ glm::uint32 scriptable::ScriptableModel::forEachVertexAttribute(QScriptValue cal
return result;
}
#endif
-
-#include "ScriptableModel.moc"
diff --git a/libraries/input-plugins/src/input-plugins/KeyboardMouseDevice.h b/libraries/input-plugins/src/input-plugins/KeyboardMouseDevice.h
index b94acb8b71..ce2bea0853 100644
--- a/libraries/input-plugins/src/input-plugins/KeyboardMouseDevice.h
+++ b/libraries/input-plugins/src/input-plugins/KeyboardMouseDevice.h
@@ -96,6 +96,7 @@ protected:
class InputDevice : public controller::InputDevice {
public:
InputDevice() : controller::InputDevice("Keyboard") {}
+ virtual ~InputDevice() {}
private:
// Device functions
virtual controller::Input::NamedVector getAvailableInputs() const override;
diff --git a/libraries/model-networking/src/model-networking/ModelCache.h b/libraries/model-networking/src/model-networking/ModelCache.h
index eea6c93786..dfe26788f2 100644
--- a/libraries/model-networking/src/model-networking/ModelCache.h
+++ b/libraries/model-networking/src/model-networking/ModelCache.h
@@ -36,6 +36,7 @@ public:
Geometry() = default;
Geometry(const Geometry& geometry);
+ virtual ~Geometry() {}
// Immutable over lifetime
using GeometryMeshes = std::vector>;
diff --git a/libraries/networking/src/AccountManager.cpp b/libraries/networking/src/AccountManager.cpp
index 5b3196a2bf..d99c0020da 100644
--- a/libraries/networking/src/AccountManager.cpp
+++ b/libraries/networking/src/AccountManager.cpp
@@ -538,7 +538,6 @@ void AccountManager::requestAccessToken(const QString& login, const QString& pas
QNetworkReply* requestReply = networkAccessManager.post(request, postData);
connect(requestReply, &QNetworkReply::finished, this, &AccountManager::requestAccessTokenFinished);
- connect(requestReply, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(requestAccessTokenError(QNetworkReply::NetworkError)));
}
void AccountManager::requestAccessTokenWithSteam(QByteArray authSessionTicket) {
@@ -633,12 +632,6 @@ void AccountManager::requestAccessTokenFinished() {
}
}
-void AccountManager::requestAccessTokenError(QNetworkReply::NetworkError error) {
- // TODO: error handling
- qCDebug(networking) << "AccountManager: failed to fetch access token - " << error;
- emit loginFailed();
-}
-
void AccountManager::refreshAccessTokenFinished() {
QNetworkReply* requestReply = reinterpret_cast(sender());
diff --git a/libraries/networking/src/AccountManager.h b/libraries/networking/src/AccountManager.h
index b122115dd0..f3b81cf1c9 100644
--- a/libraries/networking/src/AccountManager.h
+++ b/libraries/networking/src/AccountManager.h
@@ -106,7 +106,6 @@ public slots:
void requestAccessTokenFinished();
void refreshAccessTokenFinished();
void requestProfileFinished();
- void requestAccessTokenError(QNetworkReply::NetworkError error);
void refreshAccessTokenError(QNetworkReply::NetworkError error);
void requestProfileError(QNetworkReply::NetworkError error);
void logout();
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/networking/src/MessagesClient.cpp b/libraries/networking/src/MessagesClient.cpp
index 2302c22a48..d6f9d041ea 100644
--- a/libraries/networking/src/MessagesClient.cpp
+++ b/libraries/networking/src/MessagesClient.cpp
@@ -116,32 +116,33 @@ void MessagesClient::handleMessagesPacket(QSharedPointer receiv
void MessagesClient::sendMessage(QString channel, QString message, bool localOnly) {
auto nodeList = DependencyManager::get();
+ QUuid senderID = nodeList->getSessionUUID();
if (localOnly) {
- QUuid senderID = nodeList->getSessionUUID();
emit messageReceived(channel, message, senderID, true);
} else {
SharedNodePointer messagesMixer = nodeList->soloNodeOfType(NodeType::MessagesMixer);
-
if (messagesMixer) {
- QUuid senderID = nodeList->getSessionUUID();
auto packetList = encodeMessagesPacket(channel, message, senderID);
nodeList->sendPacketList(std::move(packetList), *messagesMixer);
+ } else {
+ emit messageReceived(channel, message, senderID, true);
}
}
}
void MessagesClient::sendData(QString channel, QByteArray data, bool localOnly) {
auto nodeList = DependencyManager::get();
+ QUuid senderID = nodeList->getSessionUUID();
if (localOnly) {
- QUuid senderID = nodeList->getSessionUUID();
emit dataReceived(channel, data, senderID, true);
} else {
SharedNodePointer messagesMixer = nodeList->soloNodeOfType(NodeType::MessagesMixer);
-
if (messagesMixer) {
QUuid senderID = nodeList->getSessionUUID();
auto packetList = encodeMessagesDataPacket(channel, data, senderID);
nodeList->sendPacketList(std::move(packetList), *messagesMixer);
+ } else {
+ emit dataReceived(channel, data, senderID, true);
}
}
}
diff --git a/libraries/networking/src/NetworkingConstants.h b/libraries/networking/src/NetworkingConstants.h
index 31ff6da873..839e269fd4 100644
--- a/libraries/networking/src/NetworkingConstants.h
+++ b/libraries/networking/src/NetworkingConstants.h
@@ -32,6 +32,7 @@ namespace NetworkingConstants {
const QString URL_SCHEME_ABOUT = "about";
const QString URL_SCHEME_HIFI = "hifi";
+const QString URL_SCHEME_HIFIAPP = "hifiapp";
const QString URL_SCHEME_QRC = "qrc";
const QString URL_SCHEME_FILE = "file";
const QString URL_SCHEME_HTTP = "http";
diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp
index 5478221607..8162bf4e18 100644
--- a/libraries/physics/src/EntityMotionState.cpp
+++ b/libraries/physics/src/EntityMotionState.cpp
@@ -432,6 +432,9 @@ bool EntityMotionState::shouldSendUpdate(uint32_t simulationStep) {
// this case is prevented by setting _ownershipState to UNOWNABLE in EntityMotionState::ctor
assert(!(_entity->getClientOnly() && _entity->getOwningAvatarID() != Physics::getSessionUUID()));
+ if (_entity->getTransitingWithAvatar()) {
+ return false;
+ }
if (_entity->dynamicDataNeedsTransmit()) {
return true;
}
diff --git a/libraries/plugins/src/plugins/InputPlugin.h b/libraries/plugins/src/plugins/InputPlugin.h
index 23fbb6cac6..344f07d64c 100644
--- a/libraries/plugins/src/plugins/InputPlugin.h
+++ b/libraries/plugins/src/plugins/InputPlugin.h
@@ -19,6 +19,7 @@ namespace controller {
class InputPlugin : public Plugin {
public:
+ virtual ~InputPlugin() {}
virtual void pluginFocusOutEvent() = 0;
virtual void pluginUpdate(float deltaTime, const controller::InputCalibrationData& inputCalibrationData) = 0;
diff --git a/libraries/pointers/src/Pick.h b/libraries/pointers/src/Pick.h
index 099a791407..1703f6598f 100644
--- a/libraries/pointers/src/Pick.h
+++ b/libraries/pointers/src/Pick.h
@@ -109,6 +109,7 @@ class PickResult {
public:
PickResult() {}
PickResult(const QVariantMap& pickVariant) : pickVariant(pickVariant) {}
+ virtual ~PickResult() {}
virtual QVariantMap toVariantMap() const {
return pickVariant;
@@ -233,6 +234,7 @@ template
class Pick : public PickQuery {
public:
Pick(const PickFilter& filter, const float maxDistance, const bool enabled) : PickQuery(filter, maxDistance, enabled) {}
+ virtual ~Pick() {}
virtual T getMathematicalPick() const = 0;
virtual PickResultPointer getDefaultResult(const QVariantMap& pickVariant) const = 0;
diff --git a/libraries/pointers/src/Pointer.cpp b/libraries/pointers/src/Pointer.cpp
index 031baece5f..26460cbdd7 100644
--- a/libraries/pointers/src/Pointer.cpp
+++ b/libraries/pointers/src/Pointer.cpp
@@ -68,7 +68,8 @@ void Pointer::update(unsigned int pointerID) {
// This only needs to be a read lock because update won't change any of the properties that can be modified from scripts
withReadLock([&] {
auto pickResult = getPrevPickResult();
- auto visualPickResult = getVisualPickResult(pickResult);
+ // Pointer needs its own PickResult object so it doesn't modify the cached pick result
+ auto visualPickResult = getVisualPickResult(getPickResultCopy(pickResult));
updateVisuals(visualPickResult);
generatePointerEvents(pointerID, visualPickResult);
});
diff --git a/libraries/pointers/src/Pointer.h b/libraries/pointers/src/Pointer.h
index 4264a60079..173163374f 100644
--- a/libraries/pointers/src/Pointer.h
+++ b/libraries/pointers/src/Pointer.h
@@ -91,6 +91,7 @@ protected:
virtual bool shouldHover(const PickResultPointer& pickResult) { return true; }
virtual bool shouldTrigger(const PickResultPointer& pickResult) { return true; }
+ virtual PickResultPointer getPickResultCopy(const PickResultPointer& pickResult) const = 0;
virtual PickResultPointer getVisualPickResult(const PickResultPointer& pickResult) { return pickResult; };
static const float POINTER_MOVE_DELAY;
diff --git a/libraries/qml/src/qml/impl/SharedObject.cpp b/libraries/qml/src/qml/impl/SharedObject.cpp
index 3b8d0bb743..259defdb48 100644
--- a/libraries/qml/src/qml/impl/SharedObject.cpp
+++ b/libraries/qml/src/qml/impl/SharedObject.cpp
@@ -19,6 +19,7 @@
#include
#include
#include
+#include
#include "../OffscreenSurface.h"
#include "../Logging.h"
@@ -67,6 +68,7 @@ SharedObject::SharedObject() {
// so we wait until after its ctor to move object/context to this thread.
QQuickWindow::setDefaultAlphaBuffer(true);
_quickWindow = new QQuickWindow(_renderControl);
+ _quickWindow->setFormat(getDefaultOpenGLSurfaceFormat());
_quickWindow->setColor(QColor(255, 255, 255, 0));
_quickWindow->setClearBeforeRendering(true);
diff --git a/libraries/render-utils/src/CauterizedModel.cpp b/libraries/render-utils/src/CauterizedModel.cpp
index ffb652f923..d52b7854ea 100644
--- a/libraries/render-utils/src/CauterizedModel.cpp
+++ b/libraries/render-utils/src/CauterizedModel.cpp
@@ -226,8 +226,9 @@ void CauterizedModel::updateRenderItems() {
bool invalidatePayloadShapeKey = self->shouldInvalidatePayloadShapeKey(meshIndex);
bool useDualQuaternionSkinning = self->getUseDualQuaternionSkinning();
- transaction.updateItem(itemID, [modelTransform, meshState, useDualQuaternionSkinning, cauterizedMeshState, invalidatePayloadShapeKey,
- isWireframe, renderItemKeyGlobalFlags, enableCauterization](CauterizedMeshPartPayload& data) {
+ transaction.updateItem(itemID, [modelTransform, meshState, useDualQuaternionSkinning, cauterizedMeshState, invalidatePayloadShapeKey,
+ isWireframe, renderItemKeyGlobalFlags, enableCauterization](ModelMeshPartPayload& mmppData) {
+ CauterizedMeshPartPayload& data = static_cast(mmppData);
if (useDualQuaternionSkinning) {
data.updateClusterBuffer(meshState.clusterDualQuaternions,
cauterizedMeshState.clusterDualQuaternions);
diff --git a/libraries/render-utils/src/Highlight.slh b/libraries/render-utils/src/Highlight.slh
index fe77c38fd5..b26337676f 100644
--- a/libraries/render-utils/src/Highlight.slh
+++ b/libraries/render-utils/src/Highlight.slh
@@ -15,7 +15,7 @@
<@include Highlight_shared.slh@>
-layout(binding=RENDER_UTILS_BUFFER_HIGHLIGHT_PARAMS) uniform highlightParamsBuffer {
+layout(std140, binding=RENDER_UTILS_BUFFER_HIGHLIGHT_PARAMS) uniform highlightParamsBuffer {
HighlightParameters params;
};
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/Highlight_aabox.slv b/libraries/render-utils/src/Highlight_aabox.slv
index 5130d5e7ff..2ecebdea51 100644
--- a/libraries/render-utils/src/Highlight_aabox.slv
+++ b/libraries/render-utils/src/Highlight_aabox.slv
@@ -45,7 +45,7 @@ struct HighlightParameters {
vec2 outlineWidth;
};
-layout(binding=0) uniform parametersBuffer {
+layout(std140, binding=0) uniform parametersBuffer {
HighlightParameters _parameters;
};
diff --git a/libraries/render-utils/src/MeshPartPayload.h b/libraries/render-utils/src/MeshPartPayload.h
index 5c7177e890..0cbe082cb5 100644
--- a/libraries/render-utils/src/MeshPartPayload.h
+++ b/libraries/render-utils/src/MeshPartPayload.h
@@ -28,6 +28,7 @@ class MeshPartPayload {
public:
MeshPartPayload() {}
MeshPartPayload(const std::shared_ptr& mesh, int partIndex, graphics::MaterialPointer material);
+ virtual ~MeshPartPayload() {}
typedef render::Payload Payload;
typedef Payload::DataPointer Pointer;
diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp
index b9ed43c339..be78a69b4c 100644
--- a/libraries/render-utils/src/Model.cpp
+++ b/libraries/render-utils/src/Model.cpp
@@ -1281,92 +1281,6 @@ QStringList Model::getJointNames() const {
return isActive() ? getFBXGeometry().getJointNames() : QStringList();
}
-class Blender : public QRunnable {
-public:
-
- Blender(ModelPointer model, int blendNumber, const Geometry::WeakPointer& geometry, const QVector& blendshapeCoefficients);
-
- virtual void run() override;
-
-private:
-
- ModelPointer _model;
- int _blendNumber;
- Geometry::WeakPointer _geometry;
- QVector _blendshapeCoefficients;
-};
-
-Blender::Blender(ModelPointer model, int blendNumber, const Geometry::WeakPointer& geometry, const QVector& blendshapeCoefficients) :
- _model(model),
- _blendNumber(blendNumber),
- _geometry(geometry),
- _blendshapeCoefficients(blendshapeCoefficients) {
-}
-
-void Blender::run() {
- QVector vertices;
- QVector normalsAndTangents;
- if (_model && _model->isLoaded()) {
- DETAILED_PROFILE_RANGE_EX(simulation_animation, __FUNCTION__, 0xFFFF0000, 0, { { "url", _model->getURL().toString() } });
- int offset = 0;
- int normalsAndTangentsOffset = 0;
- auto meshes = _model->getFBXGeometry().meshes;
- int meshIndex = 0;
- foreach (const FBXMesh& mesh, meshes) {
- auto modelMeshNormalsAndTangents = _model->_normalsAndTangents.find(meshIndex++);
- if (mesh.blendshapes.isEmpty() || modelMeshNormalsAndTangents == _model->_normalsAndTangents.end()) {
- continue;
- }
-
- vertices += mesh.vertices;
- normalsAndTangents += modelMeshNormalsAndTangents->second;
- glm::vec3* meshVertices = vertices.data() + offset;
- NormalType* meshNormalsAndTangents = normalsAndTangents.data() + normalsAndTangentsOffset;
- offset += mesh.vertices.size();
- normalsAndTangentsOffset += modelMeshNormalsAndTangents->second.size();
- const float NORMAL_COEFFICIENT_SCALE = 0.01f;
- for (int i = 0, n = qMin(_blendshapeCoefficients.size(), mesh.blendshapes.size()); i < n; i++) {
- float vertexCoefficient = _blendshapeCoefficients.at(i);
- const float EPSILON = 0.0001f;
- if (vertexCoefficient < EPSILON) {
- continue;
- }
- float normalCoefficient = vertexCoefficient * NORMAL_COEFFICIENT_SCALE;
- const FBXBlendshape& blendshape = mesh.blendshapes.at(i);
- tbb::parallel_for(tbb::blocked_range(0, blendshape.indices.size()), [&](const tbb::blocked_range& range) {
- for (auto j = range.begin(); j < range.end(); j++) {
- int index = blendshape.indices.at(j);
- meshVertices[index] += blendshape.vertices.at(j) * vertexCoefficient;
-
- glm::vec3 normal = mesh.normals.at(index) + blendshape.normals.at(j) * normalCoefficient;
- glm::vec3 tangent;
- if (index < mesh.tangents.size()) {
- tangent = mesh.tangents.at(index);
- if ((int)j < blendshape.tangents.size()) {
- tangent += blendshape.tangents.at(j) * normalCoefficient;
- }
- }
-#if FBX_PACK_NORMALS
- glm::uint32 finalNormal;
- glm::uint32 finalTangent;
- buffer_helpers::packNormalAndTangent(normal, tangent, finalNormal, finalTangent);
-#else
- const auto& finalNormal = normal;
- const auto& finalTangent = tangent;
-#endif
- meshNormalsAndTangents[2 * index] = finalNormal;
- meshNormalsAndTangents[2 * index + 1] = finalTangent;
- }
- });
- }
- }
- }
- // post the result to the ModelBlender, which will dispatch to the model if still alive
- QMetaObject::invokeMethod(DependencyManager::get().data(), "setBlendedVertices",
- Q_ARG(ModelPointer, _model), Q_ARG(int, _blendNumber), Q_ARG(QVector, vertices),
- Q_ARG(QVector, normalsAndTangents));
-}
-
void Model::setScaleToFit(bool scaleToFit, const glm::vec3& dimensions, bool forceRescale) {
if (forceRescale || _scaleToFit != scaleToFit || _scaleToFitDimensions != dimensions) {
_scaleToFit = scaleToFit;
@@ -1531,45 +1445,6 @@ void Model::updateClusterMatrices() {
}
}
-bool Model::maybeStartBlender() {
- if (isLoaded()) {
- const FBXGeometry& fbxGeometry = getFBXGeometry();
- if (fbxGeometry.hasBlendedMeshes()) {
- QThreadPool::globalInstance()->start(new Blender(getThisPointer(), ++_blendNumber, _renderGeometry, _blendshapeCoefficients));
- return true;
- }
- }
- return false;
-}
-
-void Model::setBlendedVertices(int blendNumber, const QVector& vertices, const QVector