diff --git a/android/app/build.gradle b/android/app/build.gradle index 97267258e2..7a6f34b58b 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -98,6 +98,13 @@ android { dependencies { implementation 'com.google.vr:sdk-audio:1.80.0' implementation 'com.google.vr:sdk-base:1.80.0' + + + implementation 'com.android.support.constraint:constraint-layout:1.0.2' + implementation 'com.android.support:design:26.1.0' + implementation 'com.android.support:appcompat-v7:26.1.0' + compile 'com.android.support:recyclerview-v7:26.1.0' + implementation fileTree(include: ['*.jar'], dir: 'libs') } diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index b3a8c87649..ed9caee58b 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -38,6 +38,17 @@ --> + + + + + + diff --git a/android/app/src/main/assets/hifi_domains.json b/android/app/src/main/assets/hifi_domains.json new file mode 100644 index 0000000000..a63ef7b6aa --- /dev/null +++ b/android/app/src/main/assets/hifi_domains.json @@ -0,0 +1,24 @@ +{ + "hifi_domains" : [ + { + "name": "Your last location", + "url": "", + "thumbnail": "" + }, + { + "name": "dev-mobile-master", + "url": "hifi://dev-mobile-master", + "thumbnail": "" + }, + { + "name": "dev-mobile", + "url": "hifi://dev-mobile", + "thumbnail": "" + }, + { + "name": "dev-welcome", + "url": "hifi://dev-welcome", + "thumbnail": "" + } + ] +} \ No newline at end of file diff --git a/android/app/src/main/cpp/native.cpp b/android/app/src/main/cpp/native.cpp index 13daf4c471..facf6bd4bd 100644 --- a/android/app/src/main/cpp/native.cpp +++ b/android/app/src/main/cpp/native.cpp @@ -17,6 +17,12 @@ #include #include +#include + +#include +#include "AndroidHelper.h" + +QAndroidJniObject __activity; void tempMessageHandler(QtMsgType type, const QMessageLogContext& context, const QString& message) { if (!message.isEmpty()) { @@ -138,9 +144,26 @@ extern "C" { JNIEXPORT void Java_io_highfidelity_hifiinterface_InterfaceActivity_nativeOnCreate(JNIEnv* env, jobject obj, jobject instance, jobject asset_mgr) { qDebug() << "nativeOnCreate On thread " << QThread::currentThreadId(); g_assetManager = AAssetManager_fromJava(env, asset_mgr); + __activity = QAndroidJniObject(instance); auto oldMessageHandler = qInstallMessageHandler(tempMessageHandler); unpackAndroidAssets(); qInstallMessageHandler(oldMessageHandler); + + QObject::connect(&AndroidHelper::instance(), &AndroidHelper::androidActivityRequested, [](const QString& a) { + QAndroidJniObject string = QAndroidJniObject::fromString(a); + __activity.callMethod("openAndroidActivity", "(Ljava/lang/String;)V", string.object()); + }); +} + +JNIEXPORT void Java_io_highfidelity_hifiinterface_InterfaceActivity_nativeOnDestroy(JNIEnv* env, jobject obj) { + QObject::disconnect(&AndroidHelper::instance(), &AndroidHelper::androidActivityRequested, + nullptr, nullptr); + +} + +JNIEXPORT void Java_io_highfidelity_hifiinterface_InterfaceActivity_nativeGotoUrl(JNIEnv* env, jobject obj, jstring url) { + QAndroidJniObject jniUrl("java/lang/String", "(Ljava/lang/String;)V", url); + DependencyManager::get()->handleLookupString(jniUrl.toString()); } JNIEXPORT void Java_io_highfidelity_hifiinterface_InterfaceActivity_nativeOnPause(JNIEnv* env, jobject obj) { @@ -155,6 +178,30 @@ JNIEXPORT void Java_io_highfidelity_hifiinterface_InterfaceActivity_nativeOnExit qDebug() << "nativeOnCreate On thread " << QThread::currentThreadId(); } +JNIEXPORT void Java_io_highfidelity_hifiinterface_InterfaceActivity_nativeGoBackFromAndroidActivity(JNIEnv *env, jobject instance) { + AndroidHelper::instance().goBackFromAndroidActivity(); } +// HifiUtils +JNIEXPORT jstring JNICALL Java_io_highfidelity_hifiinterface_HifiUtils_getCurrentAddress(JNIEnv *env, jobject instance) { + QSharedPointer addressManager = DependencyManager::get(); + if (!addressManager) { + return env->NewString(nullptr, 0); + } + QString str; + if (!addressManager->getPlaceName().isEmpty()) { + str = addressManager->getPlaceName(); + } else if (!addressManager->getHost().isEmpty()) { + str = addressManager->getHost(); + } + + QRegExp pathRegEx("(\\/[^\\/]+)"); + if (!addressManager->currentPath().isEmpty() && addressManager->currentPath().contains(pathRegEx) && pathRegEx.matchedLength() > 0) { + str += pathRegEx.cap(0); + } + + return env->NewStringUTF(str.toLatin1().data()); +} + +} diff --git a/android/app/src/main/java/io/highfidelity/hifiinterface/GotoActivity.java b/android/app/src/main/java/io/highfidelity/hifiinterface/GotoActivity.java new file mode 100644 index 0000000000..995e64c2a5 --- /dev/null +++ b/android/app/src/main/java/io/highfidelity/hifiinterface/GotoActivity.java @@ -0,0 +1,94 @@ +package io.highfidelity.hifiinterface; + +import android.content.Intent; +import android.os.Bundle; +import android.support.v7.app.ActionBar; +import android.support.v7.app.AppCompatActivity; +import android.support.v7.widget.AppCompatButton; +import android.support.v7.widget.Toolbar; +import android.view.KeyEvent; +import android.view.MenuItem; +import android.view.View; +import android.view.inputmethod.EditorInfo; +import android.widget.EditText; + +import java.net.URI; +import java.net.URISyntaxException; + +public class GotoActivity extends AppCompatActivity { + + public static final String PARAM_DOMAIN_URL = "domain_url"; + + private EditText mUrlEditText; + private AppCompatButton mGoBtn; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_goto); + + Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); + toolbar.setTitleTextAppearance(this, R.style.HomeActionBarTitleStyle); + setSupportActionBar(toolbar); + + ActionBar actionbar = getSupportActionBar(); + actionbar.setDisplayHomeAsUpEnabled(true); + + mUrlEditText = (EditText) findViewById(R.id.url_text); + mUrlEditText.setOnKeyListener(new View.OnKeyListener() { + @Override + public boolean onKey(View view, int i, KeyEvent keyEvent) { + if (i == KeyEvent.KEYCODE_ENTER) { + actionGo(); + return true; + } + return false; + } + }); + + mUrlEditText.setText(HifiUtils.getInstance().getCurrentAddress()); + + mGoBtn = (AppCompatButton) findViewById(R.id.go_btn); + + mGoBtn.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + actionGo(); + } + }); + } + + private void actionGo() { + String urlString = mUrlEditText.getText().toString(); + if (!urlString.trim().isEmpty()) { + URI uri; + try { + uri = new URI(urlString); + } catch (URISyntaxException e) { + return; + } + if (uri.getScheme() == null || uri.getScheme().isEmpty()) { + urlString = "hifi://" + urlString; + } + + Intent intent = new Intent(); + intent.putExtra(GotoActivity.PARAM_DOMAIN_URL, urlString); + setResult(RESULT_OK, intent); + finish(); + } + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + // Handle action bar item clicks here. The action bar will + // automatically handle clicks on the Home/Up button, so long + // as you specify a parent activity in AndroidManifest.xml. + int id = item.getItemId(); + switch (id) { + case android.R.id.home: + finish(); + return true; + } + return super.onOptionsItemSelected(item); + } +} diff --git a/android/app/src/main/java/io/highfidelity/hifiinterface/HifiUtils.java b/android/app/src/main/java/io/highfidelity/hifiinterface/HifiUtils.java new file mode 100644 index 0000000000..15d716548f --- /dev/null +++ b/android/app/src/main/java/io/highfidelity/hifiinterface/HifiUtils.java @@ -0,0 +1,23 @@ +package io.highfidelity.hifiinterface; + +/** + * Created by Gabriel Calero & Cristian Duarte on 4/13/18. + */ + +public class HifiUtils { + + private static HifiUtils instance; + + private HifiUtils() { + } + + public static HifiUtils getInstance() { + if (instance == null) { + instance = new HifiUtils(); + } + return instance; + } + + public native String getCurrentAddress(); + +} diff --git a/android/app/src/main/java/io/highfidelity/hifiinterface/HomeActivity.java b/android/app/src/main/java/io/highfidelity/hifiinterface/HomeActivity.java new file mode 100644 index 0000000000..611c8f50cc --- /dev/null +++ b/android/app/src/main/java/io/highfidelity/hifiinterface/HomeActivity.java @@ -0,0 +1,220 @@ +package io.highfidelity.hifiinterface; + +import android.app.ProgressDialog; +import android.content.Intent; +import android.graphics.Color; +import android.os.AsyncTask; +import android.os.Bundle; +import android.support.annotation.NonNull; +import android.support.design.widget.NavigationView; +import android.support.v4.view.GravityCompat; +import android.support.v4.widget.DrawerLayout; +import android.support.v7.app.ActionBar; +import android.support.v7.app.AppCompatActivity; +import android.support.v7.widget.GridLayoutManager; +import android.support.v7.widget.RecyclerView; +import android.support.v7.widget.Toolbar; +import android.view.Menu; +import android.view.MenuItem; +import android.view.View; +import android.widget.SearchView; +import android.widget.TabHost; +import android.widget.TabWidget; +import android.widget.TextView; + +import io.highfidelity.hifiinterface.QtPreloader.QtPreloader; +import io.highfidelity.hifiinterface.view.DomainAdapter; + +public class HomeActivity extends AppCompatActivity implements NavigationView.OnNavigationItemSelectedListener { + + /** + * Set this intent extra param to NOT start a new InterfaceActivity after a domain is selected" + */ + public static final String PARAM_NOT_START_INTERFACE_ACTIVITY = "not_start_interface_activity"; + + public static final int ENTER_DOMAIN_URL = 1; + + private DomainAdapter domainAdapter; + private DrawerLayout mDrawerLayout; + private ProgressDialog mDialog; + private NavigationView mNavigationView; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_home); + Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); + toolbar.setTitleTextAppearance(this, R.style.HomeActionBarTitleStyle); + setSupportActionBar(toolbar); + + ActionBar actionbar = getSupportActionBar(); + actionbar.setDisplayHomeAsUpEnabled(true); + actionbar.setHomeAsUpIndicator(R.drawable.ic_menu); + + mDrawerLayout = findViewById(R.id.drawer_layout); + + mNavigationView = (NavigationView) findViewById(R.id.nav_view); + mNavigationView.setNavigationItemSelectedListener(this); + + TabHost tabs = (TabHost)findViewById(R.id.tabhost); + tabs.setup(); + + TabHost.TabSpec spec=tabs.newTabSpec("featured"); + spec.setContent(R.id.featured); + spec.setIndicator(getString(R.string.featured)); + tabs.addTab(spec); + + spec = tabs.newTabSpec("popular"); + spec.setContent(R.id.popular); + spec.setIndicator(getString(R.string.popular)); + tabs.addTab(spec); + + spec = tabs.newTabSpec("bookmarks"); + spec.setContent(R.id.bookmarks); + spec.setIndicator(getString(R.string.bookmarks)); + tabs.addTab(spec); + + tabs.setCurrentTab(0); + + TabWidget tabwidget=tabs.getTabWidget(); + for(int i=0; i libraryList = new ArrayList<>(); + String localPrefix = m_context.getApplicationInfo().dataDir + "/"; + String pluginsPrefix = localPrefix + "qt-reserved-files/"; + cleanOldCacheIfNecessary(localPrefix, pluginsPrefix); + extractBundledPluginsAndImports(pluginsPrefix); + + for (String lib : m_qtLibs) { + libraryList.add(localPrefix + "lib/lib" + lib + ".so"); + } + + if (m_contextInfo.metaData.containsKey("android.app.load_local_libs")) { + String[] extraLibs = m_contextInfo.metaData.getString("android.app.load_local_libs").split(":"); + for (String lib : extraLibs) { + if (lib.length() > 0) { + if (lib.startsWith("lib/")) { + libraryList.add(localPrefix + lib); + } else { + libraryList.add(pluginsPrefix + lib); + } + } + } + } + + Bundle loaderParams = new Bundle(); + loaderParams.putString(DEX_PATH_KEY, new String()); + + loaderParams.putStringArrayList(NATIVE_LIBRARIES_KEY, libraryList); + + loaderParams.putString(ENVIRONMENT_VARIABLES_KEY, ENVIRONMENT_VARIABLES + + "\tQML2_IMPORT_PATH=" + pluginsPrefix + "/qml" + + "\tQML_IMPORT_PATH=" + pluginsPrefix + "/imports" + + "\tQT_PLUGIN_PATH=" + pluginsPrefix + "/plugins"); + + + // add all bundled Qt libs to loader params + ArrayList libs = new ArrayList<>(); + + String libName = m_contextInfo.metaData.getString("android.app.lib_name"); + loaderParams.putString(MAIN_LIBRARY_KEY, libName); //main library contains main() function + loaderParams.putStringArrayList(BUNDLED_LIBRARIES_KEY, libs); + + // load and start QtLoader class + DexClassLoader classLoader = new DexClassLoader(loaderParams.getString(DEX_PATH_KEY), // .jar/.apk files + m_context.getDir("outdex", Context.MODE_PRIVATE).getAbsolutePath(), // directory where optimized DEX files should be written. + loaderParams.containsKey(LIB_PATH_KEY) ? loaderParams.getString(LIB_PATH_KEY) : null, // libs folder (if exists) + m_context.getClassLoader()); // parent loader + + Class loaderClass = classLoader.loadClass(loaderClassName()); // load QtLoader class + Object qtLoader = loaderClass.newInstance(); // create an instance + Method prepareAppMethod = qtLoader.getClass().getMethod("loadApplication", + contextClassName(), + ClassLoader.class, + Bundle.class); + prepareAppMethod.invoke(qtLoader, m_context, classLoader, loaderParams); + + // now load the application library so it's accessible from this class loader + if (libName != null) { + System.loadLibrary(libName); + } + } catch (Exception e) { + Log.e(QtApplication.QtTAG, "Error pre-loading HiFi Qt app", e); + } + } + + protected String loaderClassName() { + return "org.qtproject.qt5.android.QtActivityDelegate"; + } + + protected Class contextClassName() { + return android.app.Activity.class; + } + + + private void deleteRecursively(File directory) { + File[] files = directory.listFiles(); + if (files != null) { + for (File file : files) { + if (file.isDirectory()) { + deleteRecursively(file); + } else { + file.delete(); + } + } + + directory.delete(); + } + } + + private void cleanOldCacheIfNecessary(String oldLocalPrefix, String localPrefix) { + File newCache = new File(localPrefix); + if (!newCache.exists()) { + { + File oldPluginsCache = new File(oldLocalPrefix + "plugins/"); + if (oldPluginsCache.exists() && oldPluginsCache.isDirectory()) { + deleteRecursively(oldPluginsCache); + } + } + + { + File oldImportsCache = new File(oldLocalPrefix + "imports/"); + if (oldImportsCache.exists() && oldImportsCache.isDirectory()) { + deleteRecursively(oldImportsCache); + } + } + + { + File oldQmlCache = new File(oldLocalPrefix + "qml/"); + if (oldQmlCache.exists() && oldQmlCache.isDirectory()) { + deleteRecursively(oldQmlCache); + } + } + } + } + + static private void copyFile(InputStream inputStream, OutputStream outputStream) + throws IOException { + byte[] buffer = new byte[BUFFER_SIZE]; + + int count; + while ((count = inputStream.read(buffer)) > 0) { + outputStream.write(buffer, 0, count); + } + } + + private void copyAsset(String source, String destination) + throws IOException { + // Already exists, we don't have to do anything + File destinationFile = new File(destination); + if (destinationFile.exists()) { + return; + } + + File parentDirectory = destinationFile.getParentFile(); + if (!parentDirectory.exists()) { + parentDirectory.mkdirs(); + } + + destinationFile.createNewFile(); + + AssetManager assetsManager = m_context.getAssets(); + InputStream inputStream = assetsManager.open(source); + OutputStream outputStream = new FileOutputStream(destinationFile); + copyFile(inputStream, outputStream); + + inputStream.close(); + outputStream.close(); + } + + private static void createBundledBinary(String source, String destination) + throws IOException { + // Already exists, we don't have to do anything + File destinationFile = new File(destination); + if (destinationFile.exists()) { + return; + } + + File parentDirectory = destinationFile.getParentFile(); + if (!parentDirectory.exists()) { + parentDirectory.mkdirs(); + } + + destinationFile.createNewFile(); + + InputStream inputStream = new FileInputStream(source); + OutputStream outputStream = new FileOutputStream(destinationFile); + copyFile(inputStream, outputStream); + + inputStream.close(); + outputStream.close(); + } + + private boolean cleanCacheIfNecessary(String pluginsPrefix, long packageVersion) { + File versionFile = new File(pluginsPrefix + "cache.version"); + + long cacheVersion = 0; + if (versionFile.exists() && versionFile.canRead()) { + try { + DataInputStream inputStream = new DataInputStream(new FileInputStream(versionFile)); + cacheVersion = inputStream.readLong(); + inputStream.close(); + } catch (Exception e) { + e.printStackTrace(); + } + } + + if (cacheVersion != packageVersion) { + deleteRecursively(new File(pluginsPrefix)); + return true; + } else { + return false; + } + } + + private void extractBundledPluginsAndImports(String pluginsPrefix) throws IOException { + String libsDir = m_context.getApplicationInfo().nativeLibraryDir + "/"; + long packageVersion = -1; + try { + PackageInfo packageInfo = m_context.getPackageManager().getPackageInfo(m_context.getPackageName(), 0); + packageVersion = packageInfo.lastUpdateTime; + } catch (Exception e) { + e.printStackTrace(); + } + + + if (!cleanCacheIfNecessary(pluginsPrefix, packageVersion)) { + return; + } + + { + File versionFile = new File(pluginsPrefix + "cache.version"); + + File parentDirectory = versionFile.getParentFile(); + if (!parentDirectory.exists()) { + parentDirectory.mkdirs(); + } + + versionFile.createNewFile(); + + DataOutputStream outputStream = new DataOutputStream(new FileOutputStream(versionFile)); + outputStream.writeLong(packageVersion); + outputStream.close(); + } + + { + String key = BUNDLED_IN_LIB_RESOURCE_ID_KEY; + if (m_contextInfo.metaData.containsKey(key)) { + String[] list = m_context.getResources().getStringArray(m_contextInfo.metaData.getInt(key)); + + for (String bundledImportBinary : list) { + String[] split = bundledImportBinary.split(":"); + String sourceFileName = libsDir + split[0]; + String destinationFileName = pluginsPrefix + split[1]; + createBundledBinary(sourceFileName, destinationFileName); + } + } + } + + { + String key = BUNDLED_IN_ASSETS_RESOURCE_ID_KEY; + if (m_contextInfo.metaData.containsKey(key)) { + String[] list = m_context.getResources().getStringArray(m_contextInfo.metaData.getInt(key)); + + for (String fileName : list) { + String[] split = fileName.split(":"); + String sourceFileName = split[0]; + String destinationFileName = pluginsPrefix + split[1]; + copyAsset(sourceFileName, destinationFileName); + } + } + + } + } +} diff --git a/android/app/src/main/java/io/highfidelity/hifiinterface/view/DomainAdapter.java b/android/app/src/main/java/io/highfidelity/hifiinterface/view/DomainAdapter.java new file mode 100644 index 0000000000..1129ec586f --- /dev/null +++ b/android/app/src/main/java/io/highfidelity/hifiinterface/view/DomainAdapter.java @@ -0,0 +1,131 @@ +package io.highfidelity.hifiinterface.view; + +import android.content.Context; +import android.support.v7.widget.RecyclerView; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageView; +import android.widget.TextView; + +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; + +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.List; + +import io.highfidelity.hifiinterface.R; + +/** + * Created by Gabriel Calero & Cristian Duarte on 3/20/18. + */ +public class DomainAdapter extends RecyclerView.Adapter { + + private static final java.lang.String DOMAINS_FILE = "hifi_domains.json"; + private static final String TAG = "HiFi Interface"; + private Context mContext; + private LayoutInflater mInflater; + private ItemClickListener mClickListener; + + public class Domain { + public String name; + public String url; + public String thumbnail; + Domain(String name, String url, String thumbnail) { + this.name = name; + this.thumbnail = thumbnail; + this.url = url; + } + } + + // references to our domains + private Domain[] mDomains = {}; + + public DomainAdapter(Context c) { + mContext = c; + this.mInflater = LayoutInflater.from(mContext); + loadDomains(); + } + + private void loadDomains() { + try { + JSONObject json = new JSONObject(loadJSONFromAsset()); + JSONArray hifiDomains = json.getJSONArray("hifi_domains"); + List domains = new ArrayList<>(); + for (int i = 0; i < hifiDomains.length(); i++) { + JSONObject jDomain = hifiDomains.getJSONObject(i); + + String domainName = jDomain.getString("name"); + String domainUrl = jDomain.getString("url"); + String domainThumb = jDomain.getString("thumbnail"); + + domains.add(new Domain(domainName, domainUrl, domainThumb)); + } + mDomains = domains.toArray(mDomains); + } catch (IOException e) { + Log.e(TAG, "Error loading domains from local file", e); + } catch (JSONException e) { + Log.e(TAG, "Error loading domains from local file", e); + } + } + + public String loadJSONFromAsset() throws IOException { + String json = null; + InputStream is = mContext.getAssets().open(DOMAINS_FILE); + int size = is.available(); + byte[] buffer = new byte[size]; + is.read(buffer); + is.close(); + json = new String(buffer, "UTF-8"); + return json; + } + + @Override + public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { + View view = mInflater.inflate(R.layout.domain_view, parent, false); + return new ViewHolder(view); + } + + @Override + public void onBindViewHolder(ViewHolder holder, int position) { + // TODO + //holder.thumbnail.setImageResource(mDomains[position].thumbnail); + holder.mDomainName.setText(mDomains[position].name); + } + + @Override + public int getItemCount() { + return mDomains.length; + } + + public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener { + TextView mDomainName; + ImageView mThumbnail; + + ViewHolder(View itemView) { + super(itemView); + mThumbnail = (ImageView) itemView.findViewById(R.id.domainThumbnail); + mDomainName = (TextView) itemView.findViewById(R.id.domainName); + itemView.setOnClickListener(this); + } + + @Override + public void onClick(View view) { + int position = getAdapterPosition(); + if (mClickListener != null) mClickListener.onItemClick(view, position, mDomains[position]); + } + } + + // allows clicks events to be caught + public void setClickListener(ItemClickListener itemClickListener) { + this.mClickListener = itemClickListener; + } + // parent activity will implement this method to respond to click events + public interface ItemClickListener { + void onItemClick(View view, int position, Domain domain); + } +} diff --git a/android/app/src/main/res/drawable/domain_bg.xml b/android/app/src/main/res/drawable/domain_bg.xml new file mode 100644 index 0000000000..d30d6413e1 --- /dev/null +++ b/android/app/src/main/res/drawable/domain_bg.xml @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file diff --git a/android/app/src/main/res/drawable/ic_bookmark.xml b/android/app/src/main/res/drawable/ic_bookmark.xml new file mode 100644 index 0000000000..ddf03e340b --- /dev/null +++ b/android/app/src/main/res/drawable/ic_bookmark.xml @@ -0,0 +1,4 @@ + + + diff --git a/android/app/src/main/res/drawable/ic_menu.xml b/android/app/src/main/res/drawable/ic_menu.xml new file mode 100644 index 0000000000..cf37e2a393 --- /dev/null +++ b/android/app/src/main/res/drawable/ic_menu.xml @@ -0,0 +1,9 @@ + + + diff --git a/android/app/src/main/res/drawable/ic_person.xml b/android/app/src/main/res/drawable/ic_person.xml new file mode 100644 index 0000000000..cf57059c77 --- /dev/null +++ b/android/app/src/main/res/drawable/ic_person.xml @@ -0,0 +1,5 @@ + + + + diff --git a/android/app/src/main/res/drawable/ic_share.xml b/android/app/src/main/res/drawable/ic_share.xml new file mode 100644 index 0000000000..91b01694da --- /dev/null +++ b/android/app/src/main/res/drawable/ic_share.xml @@ -0,0 +1,4 @@ + + + diff --git a/android/app/src/main/res/drawable/search_bg.xml b/android/app/src/main/res/drawable/search_bg.xml new file mode 100644 index 0000000000..fd1a9ea42e --- /dev/null +++ b/android/app/src/main/res/drawable/search_bg.xml @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/android/app/src/main/res/font/raleway.ttf b/android/app/src/main/res/font/raleway.ttf new file mode 100644 index 0000000000..e570a2d5c3 Binary files /dev/null and b/android/app/src/main/res/font/raleway.ttf differ diff --git a/android/app/src/main/res/font/raleway_bold.xml b/android/app/src/main/res/font/raleway_bold.xml new file mode 100644 index 0000000000..136472c0b3 --- /dev/null +++ b/android/app/src/main/res/font/raleway_bold.xml @@ -0,0 +1,7 @@ + + + diff --git a/android/app/src/main/res/font/raleway_light_italic.xml b/android/app/src/main/res/font/raleway_light_italic.xml new file mode 100644 index 0000000000..4acab05089 --- /dev/null +++ b/android/app/src/main/res/font/raleway_light_italic.xml @@ -0,0 +1,7 @@ + + + diff --git a/android/app/src/main/res/font/raleway_medium.xml b/android/app/src/main/res/font/raleway_medium.xml new file mode 100644 index 0000000000..3894c95b10 --- /dev/null +++ b/android/app/src/main/res/font/raleway_medium.xml @@ -0,0 +1,7 @@ + + + diff --git a/android/app/src/main/res/font/raleway_semibold.xml b/android/app/src/main/res/font/raleway_semibold.xml new file mode 100644 index 0000000000..39cde5a30b --- /dev/null +++ b/android/app/src/main/res/font/raleway_semibold.xml @@ -0,0 +1,7 @@ + + + diff --git a/android/app/src/main/res/layout/activity_goto.xml b/android/app/src/main/res/layout/activity_goto.xml new file mode 100644 index 0000000000..06e1383da5 --- /dev/null +++ b/android/app/src/main/res/layout/activity_goto.xml @@ -0,0 +1,39 @@ + + + + + + + + + diff --git a/android/app/src/main/res/layout/activity_home.xml b/android/app/src/main/res/layout/activity_home.xml new file mode 100644 index 0000000000..144ca84a0f --- /dev/null +++ b/android/app/src/main/res/layout/activity_home.xml @@ -0,0 +1,38 @@ + + + + + + + + + + + + + + + + + diff --git a/android/app/src/main/res/layout/content_home.xml b/android/app/src/main/res/layout/content_home.xml new file mode 100644 index 0000000000..f25d9d8f7b --- /dev/null +++ b/android/app/src/main/res/layout/content_home.xml @@ -0,0 +1,76 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/android/app/src/main/res/layout/domain_view.xml b/android/app/src/main/res/layout/domain_view.xml new file mode 100644 index 0000000000..d0ed2d3a44 --- /dev/null +++ b/android/app/src/main/res/layout/domain_view.xml @@ -0,0 +1,74 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/android/app/src/main/res/menu/menu_home.xml b/android/app/src/main/res/menu/menu_home.xml new file mode 100644 index 0000000000..c27233a6c3 --- /dev/null +++ b/android/app/src/main/res/menu/menu_home.xml @@ -0,0 +1,15 @@ + + + + diff --git a/android/app/src/main/res/values/colors.xml b/android/app/src/main/res/values/colors.xml index 344907f039..0325881f1b 100644 --- a/android/app/src/main/res/values/colors.xml +++ b/android/app/src/main/res/values/colors.xml @@ -1,4 +1,13 @@ #ffffff + #272727 + #000000 + #54D7FD + #1EB5EC + #333333 + #4F4F4F + #33999999 + #212121 + #9e9e9e diff --git a/android/app/src/main/res/values/dimens.xml b/android/app/src/main/res/values/dimens.xml index a9ec657aa9..440adcf6b9 100644 --- a/android/app/src/main/res/values/dimens.xml +++ b/android/app/src/main/res/values/dimens.xml @@ -9,4 +9,6 @@ 14dp 12dp + 12dp + 8dp \ No newline at end of file diff --git a/android/app/src/main/res/values/font_certs.xml b/android/app/src/main/res/values/font_certs.xml new file mode 100644 index 0000000000..d2226ac01c --- /dev/null +++ b/android/app/src/main/res/values/font_certs.xml @@ -0,0 +1,17 @@ + + + + @array/com_google_android_gms_fonts_certs_dev + @array/com_google_android_gms_fonts_certs_prod + + + + MIIEqDCCA5CgAwIBAgIJANWFuGx90071MA0GCSqGSIb3DQEBBAUAMIGUMQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzEQMA4GA1UEChMHQW5kcm9pZDEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UEAxMHQW5kcm9pZDEiMCAGCSqGSIb3DQEJARYTYW5kcm9pZEBhbmRyb2lkLmNvbTAeFw0wODA0MTUyMzM2NTZaFw0zNTA5MDEyMzM2NTZaMIGUMQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzEQMA4GA1UEChMHQW5kcm9pZDEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UEAxMHQW5kcm9pZDEiMCAGCSqGSIb3DQEJARYTYW5kcm9pZEBhbmRyb2lkLmNvbTCCASAwDQYJKoZIhvcNAQEBBQADggENADCCAQgCggEBANbOLggKv+IxTdGNs8/TGFy0PTP6DHThvbbR24kT9ixcOd9W+EaBPWW+wPPKQmsHxajtWjmQwWfna8mZuSeJS48LIgAZlKkpFeVyxW0qMBujb8X8ETrWy550NaFtI6t9+u7hZeTfHwqNvacKhp1RbE6dBRGWynwMVX8XW8N1+UjFaq6GCJukT4qmpN2afb8sCjUigq0GuMwYXrFVee74bQgLHWGJwPmvmLHC69EH6kWr22ijx4OKXlSIx2xT1AsSHee70w5iDBiK4aph27yH3TxkXy9V89TDdexAcKk/cVHYNnDBapcavl7y0RiQ4biu8ymM8Ga/nmzhRKya6G0cGw8CAQOjgfwwgfkwHQYDVR0OBBYEFI0cxb6VTEM8YYY6FbBMvAPyT+CyMIHJBgNVHSMEgcEwgb6AFI0cxb6VTEM8YYY6FbBMvAPyT+CyoYGapIGXMIGUMQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzEQMA4GA1UEChMHQW5kcm9pZDEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UEAxMHQW5kcm9pZDEiMCAGCSqGSIb3DQEJARYTYW5kcm9pZEBhbmRyb2lkLmNvbYIJANWFuGx90071MAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEEBQADggEBABnTDPEF+3iSP0wNfdIjIz1AlnrPzgAIHVvXxunW7SBrDhEglQZBbKJEk5kT0mtKoOD1JMrSu1xuTKEBahWRbqHsXclaXjoBADb0kkjVEJu/Lh5hgYZnOjvlba8Ld7HCKePCVePoTJBdI4fvugnL8TsgK05aIskyY0hKI9L8KfqfGTl1lzOv2KoWD0KWwtAWPoGChZxmQ+nBli+gwYMzM1vAkP+aayLe0a1EQimlOalO762r0GXO0ks+UeXde2Z4e+8S/pf7pITEI/tP+MxJTALw9QUWEv9lKTk+jkbqxbsh8nfBUapfKqYn0eidpwq2AzVp3juYl7//fKnaPhJD9gs= + + + + + MIIEQzCCAyugAwIBAgIJAMLgh0ZkSjCNMA0GCSqGSIb3DQEBBAUAMHQxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQHEw1Nb3VudGFpbiBWaWV3MRQwEgYDVQQKEwtHb29nbGUgSW5jLjEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UEAxMHQW5kcm9pZDAeFw0wODA4MjEyMzEzMzRaFw0zNjAxMDcyMzEzMzRaMHQxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQHEw1Nb3VudGFpbiBWaWV3MRQwEgYDVQQKEwtHb29nbGUgSW5jLjEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UEAxMHQW5kcm9pZDCCASAwDQYJKoZIhvcNAQEBBQADggENADCCAQgCggEBAKtWLgDYO6IIrgqWbxJOKdoR8qtW0I9Y4sypEwPpt1TTcvZApxsdyxMJZ2JORland2qSGT2y5b+3JKkedxiLDmpHpDsz2WCbdxgxRczfey5YZnTJ4VZbH0xqWVW/8lGmPav5xVwnIiJS6HXk+BVKZF+JcWjAsb/GEuq/eFdpuzSqeYTcfi6idkyugwfYwXFU1+5fZKUaRKYCwkkFQVfcAs1fXA5V+++FGfvjJ/CxURaSxaBvGdGDhfXE28LWuT9ozCl5xw4Yq5OGazvV24mZVSoOO0yZ31j7kYvtwYK6NeADwbSxDdJEqO4k//0zOHKrUiGYXtqw/A0LFFtqoZKFjnkCAQOjgdkwgdYwHQYDVR0OBBYEFMd9jMIhF1Ylmn/Tgt9r45jk14alMIGmBgNVHSMEgZ4wgZuAFMd9jMIhF1Ylmn/Tgt9r45jk14aloXikdjB0MQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzEUMBIGA1UEChMLR29vZ2xlIEluYy4xEDAOBgNVBAsTB0FuZHJvaWQxEDAOBgNVBAMTB0FuZHJvaWSCCQDC4IdGZEowjTAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBBAUAA4IBAQBt0lLO74UwLDYKqs6Tm8/yzKkEu116FmH4rkaymUIE0P9KaMftGlMexFlaYjzmB2OxZyl6euNXEsQH8gjwyxCUKRJNexBiGcCEyj6z+a1fuHHvkiaai+KL8W1EyNmgjmyy8AW7P+LLlkR+ho5zEHatRbM/YAnqGcFh5iZBqpknHf1SKMXFh4dd239FJ1jWYfbMDMy3NS5CTMQ2XFI1MvcyUTdZPErjQfTbQe3aDQsQcafEQPD+nqActifKZ0Np0IS9L9kR/wbNvyz6ENwPiTrjV2KRkEjH78ZMcUQXg0L3BYHJ3lc69Vs5Ddf9uUGGMYldX3WfMBEmh/9iFBDAaTCK + + + diff --git a/android/app/src/main/res/values/preloaded_fonts.xml b/android/app/src/main/res/values/preloaded_fonts.xml new file mode 100644 index 0000000000..6f9d0e424e --- /dev/null +++ b/android/app/src/main/res/values/preloaded_fonts.xml @@ -0,0 +1,9 @@ + + + + @font/raleway_bold + @font/raleway_light_italic + @font/raleway_medium + @font/raleway_semibold + + diff --git a/android/app/src/main/res/values/strings.xml b/android/app/src/main/res/values/strings.xml index b8080fae0f..6ce0670dd8 100644 --- a/android/app/src/main/res/values/strings.xml +++ b/android/app/src/main/res/values/strings.xml @@ -1,8 +1,17 @@ Interface + Home + Go To Open in browser Share link Shared a link Share link + FEATURED + POPULAR + BOOKMARKS + Settings + Go To + Type a domain url + Go diff --git a/android/app/src/main/res/values/styles.xml b/android/app/src/main/res/values/styles.xml index 23fe67f029..55c9b2af11 100644 --- a/android/app/src/main/res/values/styles.xml +++ b/android/app/src/main/res/values/styles.xml @@ -1,14 +1,41 @@ - - - + + + + + + + @@ -21,5 +48,11 @@ @dimen/text_size_subtitle_material_toolbar + diff --git a/assignment-client/src/Agent.cpp b/assignment-client/src/Agent.cpp index 1df901dd98..42924a8487 100644 --- a/assignment-client/src/Agent.cpp +++ b/assignment-client/src/Agent.cpp @@ -548,16 +548,21 @@ void Agent::setIsAvatar(bool isAvatar) { if (_isAvatar && !_avatarIdentityTimer) { // set up the avatar timers _avatarIdentityTimer = new QTimer(this); + _avatarQueryTimer = new QTimer(this); // connect our slot connect(_avatarIdentityTimer, &QTimer::timeout, this, &Agent::sendAvatarIdentityPacket); + connect(_avatarQueryTimer, &QTimer::timeout, this, &Agent::queryAvatars); + + static const int AVATAR_IDENTITY_PACKET_SEND_INTERVAL_MSECS = 1000; + static const int AVATAR_VIEW_PACKET_SEND_INTERVAL_MSECS = 1000; // start the timers _avatarIdentityTimer->start(AVATAR_IDENTITY_PACKET_SEND_INTERVAL_MSECS); // FIXME - we shouldn't really need to constantly send identity packets + _avatarQueryTimer->start(AVATAR_VIEW_PACKET_SEND_INTERVAL_MSECS); // tell the avatarAudioTimer to start ticking QMetaObject::invokeMethod(&_avatarAudioTimer, "start"); - } if (!_isAvatar) { @@ -567,6 +572,10 @@ void Agent::setIsAvatar(bool isAvatar) { delete _avatarIdentityTimer; _avatarIdentityTimer = nullptr; + _avatarQueryTimer->stop(); + delete _avatarQueryTimer; + _avatarQueryTimer = nullptr; + // The avatar mixer never times out a connection (e.g., based on identity or data packets) // but rather keeps avatars in its list as long as "connected". As a result, clients timeout // when we stop sending identity, but then get woken up again by the mixer itself, which sends @@ -585,6 +594,7 @@ void Agent::setIsAvatar(bool isAvatar) { nodeList->sendPacket(std::move(packet), *node); }); } + QMetaObject::invokeMethod(&_avatarAudioTimer, "stop"); } } @@ -597,6 +607,31 @@ void Agent::sendAvatarIdentityPacket() { } } +void Agent::queryAvatars() { + auto scriptedAvatar = DependencyManager::get(); + + ViewFrustum view; + view.setPosition(scriptedAvatar->getWorldPosition()); + view.setOrientation(scriptedAvatar->getHeadOrientation()); + view.calculate(); + ConicalViewFrustum conicalView { view }; + + auto avatarPacket = NLPacket::create(PacketType::AvatarQuery); + auto destinationBuffer = reinterpret_cast(avatarPacket->getPayload()); + auto bufferStart = destinationBuffer; + + uint8_t numFrustums = 1; + memcpy(destinationBuffer, &numFrustums, sizeof(numFrustums)); + destinationBuffer += sizeof(numFrustums); + + destinationBuffer += conicalView.serialize(destinationBuffer); + + avatarPacket->setPayloadSize(destinationBuffer - bufferStart); + + DependencyManager::get()->broadcastToNodes(std::move(avatarPacket), + { NodeType::AvatarMixer }); +} + void Agent::processAgentAvatar() { if (!_scriptEngine->isFinished() && _isAvatar) { auto scriptedAvatar = DependencyManager::get(); diff --git a/assignment-client/src/Agent.h b/assignment-client/src/Agent.h index 1229f06276..0cdc9e0029 100644 --- a/assignment-client/src/Agent.h +++ b/assignment-client/src/Agent.h @@ -97,6 +97,7 @@ private: void setAvatarSound(SharedSoundPointer avatarSound) { _avatarSound = avatarSound; } void sendAvatarIdentityPacket(); + void queryAvatars(); QString _scriptContents; QTimer* _scriptRequestTimeout { nullptr }; @@ -106,6 +107,7 @@ private: int _numAvatarSoundSentBytes = 0; bool _isAvatar = false; QTimer* _avatarIdentityTimer = nullptr; + QTimer* _avatarQueryTimer = nullptr; QHash _outgoingScriptAudioSequenceNumbers; AudioGate _audioGate; diff --git a/assignment-client/src/AssignmentClient.cpp b/assignment-client/src/AssignmentClient.cpp index efced972a0..41e42aa0a1 100644 --- a/assignment-client/src/AssignmentClient.cpp +++ b/assignment-client/src/AssignmentClient.cpp @@ -9,6 +9,8 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include "AssignmentClient.h" + #include #include @@ -32,16 +34,14 @@ #include #include #include - -#include "AssignmentFactory.h" -#include "AssignmentDynamicFactory.h" - -#include "AssignmentClient.h" -#include "AssignmentClientLogging.h" -#include "avatars/ScriptableAvatar.h" #include #include +#include "AssignmentClientLogging.h" +#include "AssignmentDynamicFactory.h" +#include "AssignmentFactory.h" +#include "avatars/ScriptableAvatar.h" + const QString ASSIGNMENT_CLIENT_TARGET_NAME = "assignment-client"; const long long ASSIGNMENT_REQUEST_INTERVAL_MSECS = 1 * 1000; diff --git a/assignment-client/src/AssignmentClientMonitor.cpp b/assignment-client/src/AssignmentClientMonitor.cpp index 1868ccfafe..2847d4ebf1 100644 --- a/assignment-client/src/AssignmentClientMonitor.cpp +++ b/assignment-client/src/AssignmentClientMonitor.cpp @@ -9,6 +9,8 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include "AssignmentClientMonitor.h" + #include #include @@ -19,7 +21,6 @@ #include #include -#include "AssignmentClientMonitor.h" #include "AssignmentClientApp.h" #include "AssignmentClientChildData.h" #include "SharedUtil.h" diff --git a/assignment-client/src/AssignmentDynamic.cpp b/assignment-client/src/AssignmentDynamic.cpp index 7adbd55c39..447097ac74 100644 --- a/assignment-client/src/AssignmentDynamic.cpp +++ b/assignment-client/src/AssignmentDynamic.cpp @@ -9,10 +9,10 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -#include "EntitySimulation.h" - #include "AssignmentDynamic.h" +#include "EntitySimulation.h" + AssignmentDynamic::AssignmentDynamic(EntityDynamicType type, const QUuid& id, EntityItemPointer ownerEntity) : EntityDynamicInterface(type, id), _data(QByteArray()), diff --git a/assignment-client/src/AssignmentFactory.cpp b/assignment-client/src/AssignmentFactory.cpp index 38eb72649f..405039d833 100644 --- a/assignment-client/src/AssignmentFactory.cpp +++ b/assignment-client/src/AssignmentFactory.cpp @@ -9,11 +9,12 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include "AssignmentFactory.h" + #include #include "Agent.h" #include "assets/AssetServer.h" -#include "AssignmentFactory.h" #include "audio/AudioMixer.h" #include "avatars/AvatarMixer.h" #include "entities/EntityServer.h" diff --git a/assignment-client/src/assets/AssetServer.h b/assignment-client/src/assets/AssetServer.h index f83545c25c..96a220d64d 100644 --- a/assignment-client/src/assets/AssetServer.h +++ b/assignment-client/src/assets/AssetServer.h @@ -36,10 +36,11 @@ enum class BakedAssetType : int { Undefined }; -// ATTENTION! If you change the current version for an asset type, you will also -// need to update the function currentBakeVersionForAssetType() inside of AssetServer.cpp. +// ATTENTION! Do not remove baking versions, and do not reorder them. If you add +// a new value, it will immediately become the "current" version. enum class ModelBakeVersion : BakeVersion { Initial = INITIAL_BAKE_VERSION, + MetaTextureJson, COUNT }; @@ -47,6 +48,7 @@ enum class ModelBakeVersion : BakeVersion { // ATTENTION! See above. enum class TextureBakeVersion : BakeVersion { Initial = INITIAL_BAKE_VERSION, + MetaTextureJson, COUNT }; diff --git a/assignment-client/src/audio/AudioMixerSlavePool.cpp b/assignment-client/src/audio/AudioMixerSlavePool.cpp index e28c96e259..dfe7ef56aa 100644 --- a/assignment-client/src/audio/AudioMixerSlavePool.cpp +++ b/assignment-client/src/audio/AudioMixerSlavePool.cpp @@ -9,11 +9,11 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include "AudioMixerSlavePool.h" + #include #include -#include "AudioMixerSlavePool.h" - void AudioMixerSlaveThread::run() { while (true) { wait(); diff --git a/assignment-client/src/audio/AvatarAudioStream.cpp b/assignment-client/src/audio/AvatarAudioStream.cpp index 42495b4dd0..22ea8c0617 100644 --- a/assignment-client/src/audio/AvatarAudioStream.cpp +++ b/assignment-client/src/audio/AvatarAudioStream.cpp @@ -9,10 +9,11 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include "AvatarAudioStream.h" + #include #include "AudioLogging.h" -#include "AvatarAudioStream.h" AvatarAudioStream::AvatarAudioStream(bool isStereo, int numStaticJitterFrames) : PositionalAudioStream(PositionalAudioStream::Microphone, isStereo, numStaticJitterFrames) {} diff --git a/assignment-client/src/avatars/AvatarMixer.cpp b/assignment-client/src/avatars/AvatarMixer.cpp index 29340f6474..9b5c4d4f30 100644 --- a/assignment-client/src/avatars/AvatarMixer.cpp +++ b/assignment-client/src/avatars/AvatarMixer.cpp @@ -9,6 +9,8 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include "AvatarMixer.h" + #include #include #include @@ -31,8 +33,6 @@ #include #include -#include "AvatarMixer.h" - const QString AVATAR_MIXER_LOGGING_NAME = "avatar-mixer"; // FIXME - what we'd actually like to do is send to users at ~50% of their present rate down to 30hz. Assume 90 for now. @@ -47,7 +47,7 @@ AvatarMixer::AvatarMixer(ReceivedMessage& message) : auto& packetReceiver = DependencyManager::get()->getPacketReceiver(); packetReceiver.registerListener(PacketType::AvatarData, this, "queueIncomingPacket"); packetReceiver.registerListener(PacketType::AdjustAvatarSorting, this, "handleAdjustAvatarSorting"); - packetReceiver.registerListener(PacketType::ViewFrustum, this, "handleViewFrustumPacket"); + packetReceiver.registerListener(PacketType::AvatarQuery, this, "handleAvatarQueryPacket"); packetReceiver.registerListener(PacketType::AvatarIdentity, this, "handleAvatarIdentityPacket"); packetReceiver.registerListener(PacketType::KillAvatar, this, "handleKillAvatarPacket"); packetReceiver.registerListener(PacketType::NodeIgnoreRequest, this, "handleNodeIgnoreRequestPacket"); @@ -517,15 +517,13 @@ void AvatarMixer::handleAdjustAvatarSorting(QSharedPointer mess } -void AvatarMixer::handleViewFrustumPacket(QSharedPointer message, SharedNodePointer senderNode) { +void AvatarMixer::handleAvatarQueryPacket(QSharedPointer message, SharedNodePointer senderNode) { auto start = usecTimestampNow(); getOrCreateClientData(senderNode); - if (senderNode->getLinkedData()) { - AvatarMixerClientData* nodeData = dynamic_cast(senderNode->getLinkedData()); - if (nodeData != nullptr) { - nodeData->readViewFrustumPacket(message->getMessage()); - } + AvatarMixerClientData* nodeData = dynamic_cast(senderNode->getLinkedData()); + if (nodeData) { + nodeData->readViewFrustumPacket(message->getMessage()); } auto end = usecTimestampNow(); @@ -685,7 +683,7 @@ void AvatarMixer::sendStatsPacket() { incomingPacketStats["handleNodeIgnoreRequestPacket"] = TIGHT_LOOP_STAT_UINT64(_handleNodeIgnoreRequestPacketElapsedTime); incomingPacketStats["handleRadiusIgnoreRequestPacket"] = TIGHT_LOOP_STAT_UINT64(_handleRadiusIgnoreRequestPacketElapsedTime); incomingPacketStats["handleRequestsDomainListDataPacket"] = TIGHT_LOOP_STAT_UINT64(_handleRequestsDomainListDataPacketElapsedTime); - incomingPacketStats["handleViewFrustumPacket"] = TIGHT_LOOP_STAT_UINT64(_handleViewFrustumPacketElapsedTime); + incomingPacketStats["handleAvatarQueryPacket"] = TIGHT_LOOP_STAT_UINT64(_handleViewFrustumPacketElapsedTime); singleCoreTasks["incoming_packets"] = incomingPacketStats; singleCoreTasks["sendStats"] = (float)_sendStatsElapsedTime; diff --git a/assignment-client/src/avatars/AvatarMixer.h b/assignment-client/src/avatars/AvatarMixer.h index 1fbfd7338b..9ef5903eec 100644 --- a/assignment-client/src/avatars/AvatarMixer.h +++ b/assignment-client/src/avatars/AvatarMixer.h @@ -46,7 +46,7 @@ public slots: private slots: void queueIncomingPacket(QSharedPointer message, SharedNodePointer node); void handleAdjustAvatarSorting(QSharedPointer message, SharedNodePointer senderNode); - void handleViewFrustumPacket(QSharedPointer message, SharedNodePointer senderNode); + void handleAvatarQueryPacket(QSharedPointer message, SharedNodePointer senderNode); void handleAvatarIdentityPacket(QSharedPointer message, SharedNodePointer senderNode); void handleKillAvatarPacket(QSharedPointer message, SharedNodePointer senderNode); void handleNodeIgnoreRequestPacket(QSharedPointer message, SharedNodePointer senderNode); diff --git a/assignment-client/src/avatars/AvatarMixerClientData.cpp b/assignment-client/src/avatars/AvatarMixerClientData.cpp index 268aba62d6..e185fe9167 100644 --- a/assignment-client/src/avatars/AvatarMixerClientData.cpp +++ b/assignment-client/src/avatars/AvatarMixerClientData.cpp @@ -9,18 +9,16 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include "AvatarMixerClientData.h" + #include #include #include -#include "AvatarMixerClientData.h" - AvatarMixerClientData::AvatarMixerClientData(const QUuid& nodeID) : NodeData(nodeID) { - _currentViewFrustum.invalidate(); - // in case somebody calls getSessionUUID on the AvatarData instance, make sure it has the right ID _avatar->setID(nodeID); } @@ -129,11 +127,27 @@ void AvatarMixerClientData::removeFromRadiusIgnoringSet(SharedNodePointer self, } void AvatarMixerClientData::readViewFrustumPacket(const QByteArray& message) { - _currentViewFrustum.fromByteArray(message); + _currentViewFrustums.clear(); + + auto sourceBuffer = reinterpret_cast(message.constData()); + + uint8_t numFrustums = 0; + memcpy(&numFrustums, sourceBuffer, sizeof(numFrustums)); + sourceBuffer += sizeof(numFrustums); + + for (uint8_t i = 0; i < numFrustums; ++i) { + ConicalViewFrustum frustum; + sourceBuffer += frustum.deserialize(sourceBuffer); + + _currentViewFrustums.push_back(frustum); + } } bool AvatarMixerClientData::otherAvatarInView(const AABox& otherAvatarBox) { - return _currentViewFrustum.boxIntersectsKeyhole(otherAvatarBox); + return std::any_of(std::begin(_currentViewFrustums), std::end(_currentViewFrustums), + [&](const ConicalViewFrustum& viewFrustum) { + return viewFrustum.intersects(otherAvatarBox); + }); } void AvatarMixerClientData::loadJSONStats(QJsonObject& jsonObject) const { diff --git a/assignment-client/src/avatars/AvatarMixerClientData.h b/assignment-client/src/avatars/AvatarMixerClientData.h index 6963f4df0d..e038e81505 100644 --- a/assignment-client/src/avatars/AvatarMixerClientData.h +++ b/assignment-client/src/avatars/AvatarMixerClientData.h @@ -28,7 +28,7 @@ #include #include #include -#include +#include const QString OUTBOUND_AVATAR_DATA_STATS_KEY = "outbound_av_data_kbps"; const QString INBOUND_AVATAR_DATA_STATS_KEY = "inbound_av_data_kbps"; @@ -110,7 +110,7 @@ public: bool getRequestsDomainListData() { return _requestsDomainListData; } void setRequestsDomainListData(bool requesting) { _requestsDomainListData = requesting; } - ViewFrustum getViewFrustum() const { return _currentViewFrustum; } + const ConicalViewFrustums& getViewFrustums() const { return _currentViewFrustums; } uint64_t getLastOtherAvatarEncodeTime(QUuid otherAvatar) const; void setLastOtherAvatarEncodeTime(const QUuid& otherAvatar, uint64_t time); @@ -150,7 +150,7 @@ private: SimpleMovingAverage _avgOtherAvatarDataRate; std::unordered_set _radiusIgnoredOthers; - ViewFrustum _currentViewFrustum; + ConicalViewFrustums _currentViewFrustums; int _recentOtherAvatarsInView { 0 }; int _recentOtherAvatarsOutOfView { 0 }; diff --git a/assignment-client/src/avatars/AvatarMixerSlave.cpp b/assignment-client/src/avatars/AvatarMixerSlave.cpp index 6f19b73cc5..984884adb2 100644 --- a/assignment-client/src/avatars/AvatarMixerSlave.cpp +++ b/assignment-client/src/avatars/AvatarMixerSlave.cpp @@ -9,6 +9,8 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include "AvatarMixerSlave.h" + #include #include @@ -28,10 +30,8 @@ #include #include - #include "AvatarMixer.h" #include "AvatarMixerClientData.h" -#include "AvatarMixerSlave.h" void AvatarMixerSlave::configure(ConstIter begin, ConstIter end) { _begin = begin; @@ -222,8 +222,8 @@ void AvatarMixerSlave::broadcastAvatarDataToAgent(const SharedNodePointer& node) }; // prepare to sort - ViewFrustum cameraView = nodeData->getViewFrustum(); - PrioritySortUtil::PriorityQueue sortedAvatars(cameraView, + const auto& cameraViews = nodeData->getViewFrustums(); + PrioritySortUtil::PriorityQueue sortedAvatars(cameraViews, AvatarData::_avatarSortCoefficientSize, AvatarData::_avatarSortCoefficientCenter, AvatarData::_avatarSortCoefficientAge); diff --git a/assignment-client/src/avatars/AvatarMixerSlave.h b/assignment-client/src/avatars/AvatarMixerSlave.h index bdddd5ceab..7be119c4b2 100644 --- a/assignment-client/src/avatars/AvatarMixerSlave.h +++ b/assignment-client/src/avatars/AvatarMixerSlave.h @@ -12,6 +12,8 @@ #ifndef hifi_AvatarMixerSlave_h #define hifi_AvatarMixerSlave_h +#include + class AvatarMixerClientData; class AvatarMixerSlaveStats { diff --git a/assignment-client/src/avatars/AvatarMixerSlavePool.cpp b/assignment-client/src/avatars/AvatarMixerSlavePool.cpp index 25b88686b7..962bba21d2 100644 --- a/assignment-client/src/avatars/AvatarMixerSlavePool.cpp +++ b/assignment-client/src/avatars/AvatarMixerSlavePool.cpp @@ -9,11 +9,11 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include "AvatarMixerSlavePool.h" + #include #include -#include "AvatarMixerSlavePool.h" - void AvatarMixerSlaveThread::run() { while (true) { wait(); diff --git a/assignment-client/src/avatars/ScriptableAvatar.cpp b/assignment-client/src/avatars/ScriptableAvatar.cpp index 1f3f770867..e7210db83a 100644 --- a/assignment-client/src/avatars/ScriptableAvatar.cpp +++ b/assignment-client/src/avatars/ScriptableAvatar.cpp @@ -9,6 +9,8 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include "ScriptableAvatar.h" + #include #include #include @@ -16,7 +18,6 @@ #include #include #include -#include "ScriptableAvatar.h" QByteArray ScriptableAvatar::toByteArrayStateful(AvatarDataDetail dataDetail, bool dropFaceTracking) { diff --git a/assignment-client/src/entities/EntityPriorityQueue.cpp b/assignment-client/src/entities/EntityPriorityQueue.cpp deleted file mode 100644 index 999a05f2e2..0000000000 --- a/assignment-client/src/entities/EntityPriorityQueue.cpp +++ /dev/null @@ -1,53 +0,0 @@ -// -// EntityPriorityQueue.cpp -// assignment-client/src/entities -// -// Created by Andrew Meadows 2017.08.08 -// Copyright 2017 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -#include "EntityPriorityQueue.h" - -const float PrioritizedEntity::DO_NOT_SEND = -1.0e-6f; -const float PrioritizedEntity::FORCE_REMOVE = -1.0e-5f; -const float PrioritizedEntity::WHEN_IN_DOUBT_PRIORITY = 1.0f; - -void ConicalView::set(const ViewFrustum& viewFrustum) { - // The ConicalView has two parts: a central sphere (same as ViewFrustum) and a circular cone that bounds the frustum part. - // Why? Because approximate intersection tests are much faster to compute for a cone than for a frustum. - _position = viewFrustum.getPosition(); - _direction = viewFrustum.getDirection(); - - // We cache the sin and cos of the half angle of the cone that bounds the frustum. - // (the math here is left as an exercise for the reader) - float A = viewFrustum.getAspectRatio(); - float t = tanf(0.5f * viewFrustum.getFieldOfView()); - _cosAngle = 1.0f / sqrtf(1.0f + (A * A + 1.0f) * (t * t)); - _sinAngle = sqrtf(1.0f - _cosAngle * _cosAngle); - - _radius = viewFrustum.getCenterRadius(); -} - -float ConicalView::computePriority(const AACube& cube) const { - glm::vec3 p = cube.calcCenter() - _position; // position of bounding sphere in view-frame - float d = glm::length(p); // distance to center of bounding sphere - float r = 0.5f * cube.getScale(); // radius of bounding sphere - if (d < _radius + r) { - return r; - } - // We check the angle between the center of the cube and the _direction of the view. - // If it is less than the sum of the half-angle from center of cone to outer edge plus - // the half apparent angle of the bounding sphere then it is in view. - // - // The math here is left as an exercise for the reader with the following hints: - // (1) We actually check the dot product of the cube's local position rather than the angle and - // (2) we take advantage of this trig identity: cos(A+B) = cos(A)*cos(B) - sin(A)*sin(B) - if (glm::dot(p, _direction) > sqrtf(d * d - r * r) * _cosAngle - r * _sinAngle) { - const float AVOID_DIVIDE_BY_ZERO = 0.001f; - return r / (d + AVOID_DIVIDE_BY_ZERO); - } - return PrioritizedEntity::DO_NOT_SEND; -} diff --git a/assignment-client/src/entities/EntityPriorityQueue.h b/assignment-client/src/entities/EntityPriorityQueue.h deleted file mode 100644 index e308d9b549..0000000000 --- a/assignment-client/src/entities/EntityPriorityQueue.h +++ /dev/null @@ -1,66 +0,0 @@ -// -// EntityPriorityQueue.h -// assignment-client/src/entities -// -// Created by Andrew Meadows 2017.08.08 -// Copyright 2017 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -#ifndef hifi_EntityPriorityQueue_h -#define hifi_EntityPriorityQueue_h - -#include - -#include -#include - -const float SQRT_TWO_OVER_TWO = 0.7071067811865f; -const float DEFAULT_VIEW_RADIUS = 10.0f; - -// ConicalView is an approximation of a ViewFrustum for fast calculation of sort priority. -class ConicalView { -public: - ConicalView() {} - ConicalView(const ViewFrustum& viewFrustum) { set(viewFrustum); } - void set(const ViewFrustum& viewFrustum); - float computePriority(const AACube& cube) const; -private: - glm::vec3 _position { 0.0f, 0.0f, 0.0f }; - glm::vec3 _direction { 0.0f, 0.0f, 1.0f }; - float _sinAngle { SQRT_TWO_OVER_TWO }; - float _cosAngle { SQRT_TWO_OVER_TWO }; - float _radius { DEFAULT_VIEW_RADIUS }; -}; - -// PrioritizedEntity is a placeholder in a sorted queue. -class PrioritizedEntity { -public: - static const float DO_NOT_SEND; - static const float FORCE_REMOVE; - static const float WHEN_IN_DOUBT_PRIORITY; - - PrioritizedEntity(EntityItemPointer entity, float priority, bool forceRemove = false) : _weakEntity(entity), _rawEntityPointer(entity.get()), _priority(priority), _forceRemove(forceRemove) {} - EntityItemPointer getEntity() const { return _weakEntity.lock(); } - EntityItem* getRawEntityPointer() const { return _rawEntityPointer; } - float getPriority() const { return _priority; } - bool shouldForceRemove() const { return _forceRemove; } - - class Compare { - public: - bool operator() (const PrioritizedEntity& A, const PrioritizedEntity& B) { return A._priority < B._priority; } - }; - friend class Compare; - -private: - EntityItemWeakPointer _weakEntity; - EntityItem* _rawEntityPointer; - float _priority; - bool _forceRemove; -}; - -using EntityPriorityQueue = std::priority_queue< PrioritizedEntity, std::vector, PrioritizedEntity::Compare >; - -#endif // hifi_EntityPriorityQueue_h diff --git a/assignment-client/src/entities/EntityServer.cpp b/assignment-client/src/entities/EntityServer.cpp index 70fad03d67..c108dad6cf 100644 --- a/assignment-client/src/entities/EntityServer.cpp +++ b/assignment-client/src/entities/EntityServer.cpp @@ -9,21 +9,23 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include "EntityServer.h" + #include #include +#include +#include + #include #include #include #include #include #include -#include -#include #include #include "AssignmentParentFinder.h" #include "EntityNodeData.h" -#include "EntityServer.h" #include "EntityServerConsts.h" #include "EntityTreeSendThread.h" diff --git a/assignment-client/src/entities/EntityTreeSendThread.cpp b/assignment-client/src/entities/EntityTreeSendThread.cpp index 4aa52922c0..f008ef9925 100644 --- a/assignment-client/src/entities/EntityTreeSendThread.cpp +++ b/assignment-client/src/entities/EntityTreeSendThread.cpp @@ -103,48 +103,41 @@ void EntityTreeSendThread::preDistributionProcessing() { void EntityTreeSendThread::traverseTreeAndSendContents(SharedNodePointer node, OctreeQueryNode* nodeData, bool viewFrustumChanged, bool isFullScene) { if (viewFrustumChanged || _traversal.finished()) { - ViewFrustum viewFrustum; - nodeData->copyCurrentViewFrustum(viewFrustum); EntityTreeElementPointer root = std::dynamic_pointer_cast(_myServer->getOctree()->getRoot()); + + + DiffTraversal::View newView; + newView.viewFrustums = nodeData->getCurrentViews(); + int32_t lodLevelOffset = nodeData->getBoundaryLevelAdjust() + (viewFrustumChanged ? LOW_RES_MOVING_ADJUST : NO_BOUNDARY_ADJUST); - startNewTraversal(viewFrustum, root, lodLevelOffset, nodeData->getUsesFrustum()); + newView.lodScaleFactor = powf(2.0f, lodLevelOffset); + + startNewTraversal(newView, root); // When the viewFrustum changed the sort order may be incorrect, so we re-sort // and also use the opportunity to cull anything no longer in view if (viewFrustumChanged && !_sendQueue.empty()) { EntityPriorityQueue prevSendQueue; - _sendQueue.swap(prevSendQueue); - _entitiesInQueue.clear(); + std::swap(_sendQueue, prevSendQueue); + assert(_sendQueue.empty()); + // Re-add elements from previous traversal if they still need to be sent - float lodScaleFactor = _traversal.getCurrentLODScaleFactor(); - glm::vec3 viewPosition = _traversal.getCurrentView().getPosition(); while (!prevSendQueue.empty()) { EntityItemPointer entity = prevSendQueue.top().getEntity(); bool forceRemove = prevSendQueue.top().shouldForceRemove(); prevSendQueue.pop(); if (entity) { - if (!forceRemove) { - bool success = false; - AACube cube = entity->getQueryAACube(success); - if (success) { - if (_traversal.getCurrentView().cubeIntersectsKeyhole(cube)) { - float priority = _conicalView.computePriority(cube); - if (priority != PrioritizedEntity::DO_NOT_SEND) { - float distance = glm::distance(cube.calcCenter(), viewPosition) + MIN_VISIBLE_DISTANCE; - float angularDiameter = cube.getScale() / distance; - if (angularDiameter > MIN_ENTITY_ANGULAR_DIAMETER * lodScaleFactor) { - _sendQueue.push(PrioritizedEntity(entity, priority)); - _entitiesInQueue.insert(entity.get()); - } - } - } - } else { - _sendQueue.push(PrioritizedEntity(entity, PrioritizedEntity::WHEN_IN_DOUBT_PRIORITY)); - _entitiesInQueue.insert(entity.get()); - } + float priority = PrioritizedEntity::DO_NOT_SEND; + + if (forceRemove) { + priority = PrioritizedEntity::FORCE_REMOVE; } else { - _sendQueue.push(PrioritizedEntity(entity, PrioritizedEntity::FORCE_REMOVE, true)); - _entitiesInQueue.insert(entity.get()); + const auto& view = _traversal.getCurrentView(); + priority = view.computePriority(entity); + } + + if (priority != PrioritizedEntity::DO_NOT_SEND) { + _sendQueue.emplace(entity, priority, forceRemove); } } } @@ -215,10 +208,9 @@ bool EntityTreeSendThread::addDescendantsToExtraFlaggedEntities(const QUuid& fil return hasNewChild || hasNewDescendants; } -void EntityTreeSendThread::startNewTraversal(const ViewFrustum& view, EntityTreeElementPointer root, int32_t lodLevelOffset, - bool usesViewFrustum) { +void EntityTreeSendThread::startNewTraversal(const DiffTraversal::View& view, EntityTreeElementPointer root) { - DiffTraversal::Type type = _traversal.prepareNewTraversal(view, root, lodLevelOffset, usesViewFrustum); + DiffTraversal::Type type = _traversal.prepareNewTraversal(view, root); // there are three types of traversal: // // (1) FirstTime = at login --> find everything in view @@ -226,171 +218,80 @@ void EntityTreeSendThread::startNewTraversal(const ViewFrustum& view, EntityTree // (3) Differential = view has changed --> find what has changed or in new view but not old // // The "scanCallback" we provide to the traversal depends on the type: - // - // The _conicalView is updated here as a cached view approximation used by the lambdas for efficient - // computation of entity sorting priorities. - // - _conicalView.set(_traversal.getCurrentView()); switch (type) { case DiffTraversal::First: // When we get to a First traversal, clear the _knownState _knownState.clear(); - if (usesViewFrustum) { - float lodScaleFactor = _traversal.getCurrentLODScaleFactor(); - glm::vec3 viewPosition = _traversal.getCurrentView().getPosition(); - _traversal.setScanCallback([=](DiffTraversal::VisibleElement& next) { - next.element->forEachEntity([=](EntityItemPointer entity) { - // Bail early if we've already checked this entity this frame - if (_entitiesInQueue.find(entity.get()) != _entitiesInQueue.end()) { - return; - } - bool success = false; - AACube cube = entity->getQueryAACube(success); - if (success) { - if (_traversal.getCurrentView().cubeIntersectsKeyhole(cube)) { - // Check the size of the entity, it's possible that a "too small to see" entity is included in a - // larger octree cell because of its position (for example if it crosses the boundary of a cell it - // pops to the next higher cell. So we want to check to see that the entity is large enough to be seen - // before we consider including it. - float distance = glm::distance(cube.calcCenter(), viewPosition) + MIN_VISIBLE_DISTANCE; - float angularDiameter = cube.getScale() / distance; - if (angularDiameter > MIN_ENTITY_ANGULAR_DIAMETER * lodScaleFactor) { - float priority = _conicalView.computePriority(cube); - _sendQueue.push(PrioritizedEntity(entity, priority)); - _entitiesInQueue.insert(entity.get()); - } - } - } else { - _sendQueue.push(PrioritizedEntity(entity, PrioritizedEntity::WHEN_IN_DOUBT_PRIORITY)); - _entitiesInQueue.insert(entity.get()); - } - }); - }); - } else { - _traversal.setScanCallback([this](DiffTraversal::VisibleElement& next) { - next.element->forEachEntity([this](EntityItemPointer entity) { - // Bail early if we've already checked this entity this frame - if (_entitiesInQueue.find(entity.get()) != _entitiesInQueue.end()) { - return; - } - _sendQueue.push(PrioritizedEntity(entity, PrioritizedEntity::WHEN_IN_DOUBT_PRIORITY)); - _entitiesInQueue.insert(entity.get()); - }); - }); - } - break; - case DiffTraversal::Repeat: - if (usesViewFrustum) { - float lodScaleFactor = _traversal.getCurrentLODScaleFactor(); - glm::vec3 viewPosition = _traversal.getCurrentView().getPosition(); - _traversal.setScanCallback([=](DiffTraversal::VisibleElement& next) { - uint64_t startOfCompletedTraversal = _traversal.getStartOfCompletedTraversal(); - if (next.element->getLastChangedContent() > startOfCompletedTraversal) { - next.element->forEachEntity([=](EntityItemPointer entity) { - // Bail early if we've already checked this entity this frame - if (_entitiesInQueue.find(entity.get()) != _entitiesInQueue.end()) { - return; - } - auto knownTimestamp = _knownState.find(entity.get()); - if (knownTimestamp == _knownState.end()) { - bool success = false; - AACube cube = entity->getQueryAACube(success); - if (success) { - if (next.intersection == ViewFrustum::INSIDE || _traversal.getCurrentView().cubeIntersectsKeyhole(cube)) { - // See the DiffTraversal::First case for an explanation of the "entity is too small" check - float distance = glm::distance(cube.calcCenter(), viewPosition) + MIN_VISIBLE_DISTANCE; - float angularDiameter = cube.getScale() / distance; - if (angularDiameter > MIN_ENTITY_ANGULAR_DIAMETER * lodScaleFactor) { - float priority = _conicalView.computePriority(cube); - _sendQueue.push(PrioritizedEntity(entity, priority)); - _entitiesInQueue.insert(entity.get()); - } - } - } else { - _sendQueue.push(PrioritizedEntity(entity, PrioritizedEntity::WHEN_IN_DOUBT_PRIORITY)); - _entitiesInQueue.insert(entity.get()); - } - } else if (entity->getLastEdited() > knownTimestamp->second - || entity->getLastChangedOnServer() > knownTimestamp->second) { - // it is known and it changed --> put it on the queue with any priority - // TODO: sort these correctly - _sendQueue.push(PrioritizedEntity(entity, PrioritizedEntity::WHEN_IN_DOUBT_PRIORITY)); - _entitiesInQueue.insert(entity.get()); - } - }); - } - }); - } else { - _traversal.setScanCallback([this](DiffTraversal::VisibleElement& next) { - uint64_t startOfCompletedTraversal = _traversal.getStartOfCompletedTraversal(); - if (next.element->getLastChangedContent() > startOfCompletedTraversal) { - next.element->forEachEntity([this](EntityItemPointer entity) { - // Bail early if we've already checked this entity this frame - if (_entitiesInQueue.find(entity.get()) != _entitiesInQueue.end()) { - return; - } - auto knownTimestamp = _knownState.find(entity.get()); - if (knownTimestamp == _knownState.end() - || entity->getLastEdited() > knownTimestamp->second - || entity->getLastChangedOnServer() > knownTimestamp->second) { - _sendQueue.push(PrioritizedEntity(entity, PrioritizedEntity::WHEN_IN_DOUBT_PRIORITY)); - _entitiesInQueue.insert(entity.get()); - } - }); - } - }); - } - break; - case DiffTraversal::Differential: - assert(usesViewFrustum); - float lodScaleFactor = _traversal.getCurrentLODScaleFactor(); - glm::vec3 viewPosition = _traversal.getCurrentView().getPosition(); - float completedLODScaleFactor = _traversal.getCompletedLODScaleFactor(); - glm::vec3 completedViewPosition = _traversal.getCompletedView().getPosition(); - _traversal.setScanCallback([=] (DiffTraversal::VisibleElement& next) { - next.element->forEachEntity([=](EntityItemPointer entity) { + _traversal.setScanCallback([this](DiffTraversal::VisibleElement& next) { + next.element->forEachEntity([&](EntityItemPointer entity) { // Bail early if we've already checked this entity this frame - if (_entitiesInQueue.find(entity.get()) != _entitiesInQueue.end()) { + if (_sendQueue.contains(entity.get())) { return; } + const auto& view = _traversal.getCurrentView(); + float priority = view.computePriority(entity); + + if (priority != PrioritizedEntity::DO_NOT_SEND) { + _sendQueue.emplace(entity, priority); + } + }); + }); + break; + case DiffTraversal::Repeat: + _traversal.setScanCallback([this](DiffTraversal::VisibleElement& next) { + uint64_t startOfCompletedTraversal = _traversal.getStartOfCompletedTraversal(); + if (next.element->getLastChangedContent() > startOfCompletedTraversal) { + next.element->forEachEntity([&](EntityItemPointer entity) { + // Bail early if we've already checked this entity this frame + if (_sendQueue.contains(entity.get())) { + return; + } + float priority = PrioritizedEntity::DO_NOT_SEND; + + auto knownTimestamp = _knownState.find(entity.get()); + if (knownTimestamp == _knownState.end()) { + const auto& view = _traversal.getCurrentView(); + priority = view.computePriority(entity); + + } else if (entity->getLastEdited() > knownTimestamp->second || + entity->getLastChangedOnServer() > knownTimestamp->second) { + // it is known and it changed --> put it on the queue with any priority + // TODO: sort these correctly + priority = PrioritizedEntity::WHEN_IN_DOUBT_PRIORITY; + } + + if (priority != PrioritizedEntity::DO_NOT_SEND) { + _sendQueue.emplace(entity, priority); + } + }); + } + }); + break; + case DiffTraversal::Differential: + assert(view.usesViewFrustums()); + _traversal.setScanCallback([this] (DiffTraversal::VisibleElement& next) { + next.element->forEachEntity([&](EntityItemPointer entity) { + // Bail early if we've already checked this entity this frame + if (_sendQueue.contains(entity.get())) { + return; + } + float priority = PrioritizedEntity::DO_NOT_SEND; + auto knownTimestamp = _knownState.find(entity.get()); if (knownTimestamp == _knownState.end()) { - bool success = false; - AACube cube = entity->getQueryAACube(success); - if (success) { - if (_traversal.getCurrentView().cubeIntersectsKeyhole(cube)) { - // See the DiffTraversal::First case for an explanation of the "entity is too small" check - float distance = glm::distance(cube.calcCenter(), viewPosition) + MIN_VISIBLE_DISTANCE; - float angularDiameter = cube.getScale() / distance; - if (angularDiameter > MIN_ENTITY_ANGULAR_DIAMETER * lodScaleFactor) { - if (!_traversal.getCompletedView().cubeIntersectsKeyhole(cube)) { - float priority = _conicalView.computePriority(cube); - _sendQueue.push(PrioritizedEntity(entity, priority)); - _entitiesInQueue.insert(entity.get()); - } else { - // If this entity was skipped last time because it was too small, we still need to send it - distance = glm::distance(cube.calcCenter(), completedViewPosition) + MIN_VISIBLE_DISTANCE; - angularDiameter = cube.getScale() / distance; - if (angularDiameter <= MIN_ENTITY_ANGULAR_DIAMETER * completedLODScaleFactor) { - // this object was skipped in last completed traversal - float priority = _conicalView.computePriority(cube); - _sendQueue.push(PrioritizedEntity(entity, priority)); - _entitiesInQueue.insert(entity.get()); - } - } - } - } - } else { - _sendQueue.push(PrioritizedEntity(entity, PrioritizedEntity::WHEN_IN_DOUBT_PRIORITY)); - _entitiesInQueue.insert(entity.get()); - } - } else if (entity->getLastEdited() > knownTimestamp->second - || entity->getLastChangedOnServer() > knownTimestamp->second) { + const auto& view = _traversal.getCurrentView(); + priority = view.computePriority(entity); + + } else if (entity->getLastEdited() > knownTimestamp->second || + entity->getLastChangedOnServer() > knownTimestamp->second) { // it is known and it changed --> put it on the queue with any priority // TODO: sort these correctly - _sendQueue.push(PrioritizedEntity(entity, PrioritizedEntity::WHEN_IN_DOUBT_PRIORITY)); - _entitiesInQueue.insert(entity.get()); + priority = PrioritizedEntity::WHEN_IN_DOUBT_PRIORITY; + } + + if (priority != PrioritizedEntity::DO_NOT_SEND) { + _sendQueue.emplace(entity, priority); } }); }); @@ -479,11 +380,10 @@ bool EntityTreeSendThread::traverseTreeAndBuildNextPacketPayload(EncodeBitstream } } _sendQueue.pop(); - _entitiesInQueue.erase(entity.get()); } nodeData->stats.encodeStopped(); if (_sendQueue.empty()) { - assert(_entitiesInQueue.empty()); + assert(_sendQueue.empty()); params.stopReason = EncodeBitstreamParams::FINISHED; _extraEncodeData->entities.clear(); } @@ -501,18 +401,15 @@ bool EntityTreeSendThread::traverseTreeAndBuildNextPacketPayload(EncodeBitstream void EntityTreeSendThread::editingEntityPointer(const EntityItemPointer& entity) { if (entity) { - if (_entitiesInQueue.find(entity.get()) == _entitiesInQueue.end() && _knownState.find(entity.get()) != _knownState.end()) { - bool success = false; - AACube cube = entity->getQueryAACube(success); - if (success) { - // We can force a removal from _knownState if the current view is used and entity is out of view - if (_traversal.doesCurrentUseViewFrustum() && !_traversal.getCurrentView().cubeIntersectsKeyhole(cube)) { - _sendQueue.push(PrioritizedEntity(entity, PrioritizedEntity::FORCE_REMOVE, true)); - _entitiesInQueue.insert(entity.get()); - } - } else { - _sendQueue.push(PrioritizedEntity(entity, PrioritizedEntity::WHEN_IN_DOUBT_PRIORITY, true)); - _entitiesInQueue.insert(entity.get()); + if (!_sendQueue.contains(entity.get()) && _knownState.find(entity.get()) != _knownState.end()) { + const auto& view = _traversal.getCurrentView(); + float priority = view.computePriority(entity); + + // We can force a removal from _knownState if the current view is used and entity is out of view + if (priority == PrioritizedEntity::DO_NOT_SEND) { + _sendQueue.emplace(entity, PrioritizedEntity::FORCE_REMOVE, true); + } else if (priority == PrioritizedEntity::WHEN_IN_DOUBT_PRIORITY) { + _sendQueue.emplace(entity, PrioritizedEntity::WHEN_IN_DOUBT_PRIORITY, true); } } } diff --git a/assignment-client/src/entities/EntityTreeSendThread.h b/assignment-client/src/entities/EntityTreeSendThread.h index 1e2bd15429..1305d7bfc7 100644 --- a/assignment-client/src/entities/EntityTreeSendThread.h +++ b/assignment-client/src/entities/EntityTreeSendThread.h @@ -17,8 +17,9 @@ #include "../octree/OctreeSendThread.h" #include +#include +#include -#include "EntityPriorityQueue.h" class EntityNodeData; class EntityItem; @@ -41,8 +42,7 @@ private: bool addAncestorsToExtraFlaggedEntities(const QUuid& filteredEntityID, EntityItem& entityItem, EntityNodeData& nodeData); bool addDescendantsToExtraFlaggedEntities(const QUuid& filteredEntityID, EntityItem& entityItem, EntityNodeData& nodeData); - void startNewTraversal(const ViewFrustum& viewFrustum, EntityTreeElementPointer root, int32_t lodLevelOffset, - bool usesViewFrustum); + void startNewTraversal(const DiffTraversal::View& viewFrustum, EntityTreeElementPointer root); bool traverseTreeAndBuildNextPacketPayload(EncodeBitstreamParams& params, const QJsonObject& jsonFilters) override; void preDistributionProcessing() override; @@ -51,9 +51,7 @@ private: DiffTraversal _traversal; EntityPriorityQueue _sendQueue; - std::unordered_set _entitiesInQueue; std::unordered_map _knownState; - ConicalView _conicalView; // cached optimized view for fast priority calculations // packet construction stuff EntityTreeElementExtraEncodeDataPointer _extraEncodeData { new EntityTreeElementExtraEncodeData() }; diff --git a/assignment-client/src/messages/MessagesMixer.cpp b/assignment-client/src/messages/MessagesMixer.cpp index 4bf708cf34..c11c8f40a0 100644 --- a/assignment-client/src/messages/MessagesMixer.cpp +++ b/assignment-client/src/messages/MessagesMixer.cpp @@ -9,6 +9,8 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include "MessagesMixer.h" + #include #include #include @@ -16,7 +18,6 @@ #include #include #include -#include "MessagesMixer.h" const QString MESSAGES_MIXER_LOGGING_NAME = "messages-mixer"; diff --git a/assignment-client/src/octree/OctreeHeadlessViewer.cpp b/assignment-client/src/octree/OctreeHeadlessViewer.cpp index d3b20fb623..039dbdab78 100644 --- a/assignment-client/src/octree/OctreeHeadlessViewer.cpp +++ b/assignment-client/src/octree/OctreeHeadlessViewer.cpp @@ -14,32 +14,21 @@ #include #include - -OctreeHeadlessViewer::OctreeHeadlessViewer() { - _viewFrustum.setProjection(glm::perspective(glm::radians(DEFAULT_FIELD_OF_VIEW_DEGREES), DEFAULT_ASPECT_RATIO, DEFAULT_NEAR_CLIP, DEFAULT_FAR_CLIP)); -} - void OctreeHeadlessViewer::queryOctree() { char serverType = getMyNodeType(); PacketType packetType = getMyQueryMessageType(); - _octreeQuery.setCameraPosition(_viewFrustum.getPosition()); - _octreeQuery.setCameraOrientation(_viewFrustum.getOrientation()); - _octreeQuery.setCameraFov(_viewFrustum.getFieldOfView()); - _octreeQuery.setCameraAspectRatio(_viewFrustum.getAspectRatio()); - _octreeQuery.setCameraNearClip(_viewFrustum.getNearClip()); - _octreeQuery.setCameraFarClip(_viewFrustum.getFarClip()); - _octreeQuery.setCameraEyeOffsetPosition(glm::vec3()); - _octreeQuery.setCameraCenterRadius(_viewFrustum.getCenterRadius()); - _octreeQuery.setOctreeSizeScale(_voxelSizeScale); - _octreeQuery.setBoundaryLevelAdjust(_boundaryLevelAdjust); + if (_hasViewFrustum) { + ConicalViewFrustums views { _viewFrustum }; + _octreeQuery.setConicalViews(views); + } else { + _octreeQuery.clearConicalViews(); + } auto nodeList = DependencyManager::get(); auto node = nodeList->soloNodeOfType(serverType); if (node && node->getActiveSocket()) { - _octreeQuery.setMaxQueryPacketsPerSecond(getMaxPacketsPerSecond()); - auto queryPacket = NLPacket::create(packetType); // encode the query data diff --git a/assignment-client/src/octree/OctreeHeadlessViewer.h b/assignment-client/src/octree/OctreeHeadlessViewer.h index feb8211c39..dea91ce66f 100644 --- a/assignment-client/src/octree/OctreeHeadlessViewer.h +++ b/assignment-client/src/octree/OctreeHeadlessViewer.h @@ -20,9 +20,6 @@ class OctreeHeadlessViewer : public OctreeProcessor { Q_OBJECT public: - OctreeHeadlessViewer(); - virtual ~OctreeHeadlessViewer() {}; - OctreeQuery& getOctreeQuery() { return _octreeQuery; } static int parseOctreeStats(QSharedPointer message, SharedNodePointer sourceNode); @@ -32,34 +29,32 @@ public slots: void queryOctree(); // setters for camera attributes - void setPosition(const glm::vec3& position) { _viewFrustum.setPosition(position); } - void setOrientation(const glm::quat& orientation) { _viewFrustum.setOrientation(orientation); } - void setCenterRadius(float radius) { _viewFrustum.setCenterRadius(radius); } - void setKeyholeRadius(float radius) { _viewFrustum.setCenterRadius(radius); } // TODO: remove this legacy support + void setPosition(const glm::vec3& position) { _hasViewFrustum = true; _viewFrustum.setPosition(position); } + void setOrientation(const glm::quat& orientation) { _hasViewFrustum = true; _viewFrustum.setOrientation(orientation); } + void setCenterRadius(float radius) { _hasViewFrustum = true; _viewFrustum.setCenterRadius(radius); } + void setKeyholeRadius(float radius) { _hasViewFrustum = true; _viewFrustum.setCenterRadius(radius); } // TODO: remove this legacy support // setters for LOD and PPS - void setVoxelSizeScale(float sizeScale) { _voxelSizeScale = sizeScale; } - void setBoundaryLevelAdjust(int boundaryLevelAdjust) { _boundaryLevelAdjust = boundaryLevelAdjust; } - void setMaxPacketsPerSecond(int maxPacketsPerSecond) { _maxPacketsPerSecond = maxPacketsPerSecond; } + void setVoxelSizeScale(float sizeScale) { _octreeQuery.setOctreeSizeScale(sizeScale) ; } + void setBoundaryLevelAdjust(int boundaryLevelAdjust) { _octreeQuery.setBoundaryLevelAdjust(boundaryLevelAdjust); } + void setMaxPacketsPerSecond(int maxPacketsPerSecond) { _octreeQuery.setMaxQueryPacketsPerSecond(maxPacketsPerSecond); } // getters for camera attributes const glm::vec3& getPosition() const { return _viewFrustum.getPosition(); } const glm::quat& getOrientation() const { return _viewFrustum.getOrientation(); } // getters for LOD and PPS - float getVoxelSizeScale() const { return _voxelSizeScale; } - int getBoundaryLevelAdjust() const { return _boundaryLevelAdjust; } - int getMaxPacketsPerSecond() const { return _maxPacketsPerSecond; } + float getVoxelSizeScale() const { return _octreeQuery.getOctreeSizeScale(); } + int getBoundaryLevelAdjust() const { return _octreeQuery.getBoundaryLevelAdjust(); } + int getMaxPacketsPerSecond() const { return _octreeQuery.getMaxQueryPacketsPerSecond(); } unsigned getOctreeElementsCount() const { return _tree->getOctreeElementsCount(); } private: OctreeQuery _octreeQuery; + bool _hasViewFrustum { false }; ViewFrustum _viewFrustum; - float _voxelSizeScale { DEFAULT_OCTREE_SIZE_SCALE }; - int _boundaryLevelAdjust { 0 }; - int _maxPacketsPerSecond { DEFAULT_MAX_OCTREE_PPS }; }; #endif // hifi_OctreeHeadlessViewer_h diff --git a/assignment-client/src/octree/OctreeInboundPacketProcessor.cpp b/assignment-client/src/octree/OctreeInboundPacketProcessor.cpp index bce6e7fe44..ef532bb33f 100644 --- a/assignment-client/src/octree/OctreeInboundPacketProcessor.cpp +++ b/assignment-client/src/octree/OctreeInboundPacketProcessor.cpp @@ -9,6 +9,8 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include "OctreeInboundPacketProcessor.h" + #include #include @@ -17,7 +19,6 @@ #include "OctreeServer.h" #include "OctreeServerConsts.h" -#include "OctreeInboundPacketProcessor.h" static QUuid DEFAULT_NODE_ID_REF; const quint64 TOO_LONG_SINCE_LAST_NACK = 1 * USECS_PER_SECOND; diff --git a/assignment-client/src/octree/OctreeSendThread.cpp b/assignment-client/src/octree/OctreeSendThread.cpp index de49bd461c..e9aa44b970 100644 --- a/assignment-client/src/octree/OctreeSendThread.cpp +++ b/assignment-client/src/octree/OctreeSendThread.cpp @@ -9,6 +9,8 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include "OctreeSendThread.h" + #include #include @@ -17,7 +19,6 @@ #include #include -#include "OctreeSendThread.h" #include "OctreeServer.h" #include "OctreeServerConsts.h" #include "OctreeLogging.h" @@ -330,8 +331,9 @@ int OctreeSendThread::packetDistributor(SharedNodePointer node, OctreeQueryNode* } else { // we aren't forcing a full scene, check if something else suggests we should isFullScene = nodeData->haveJSONParametersChanged() || - (nodeData->getUsesFrustum() - && ((!viewFrustumChanged && nodeData->getViewFrustumJustStoppedChanging()) || nodeData->hasLodChanged())); + (nodeData->hasConicalViews() && + (nodeData->getViewFrustumJustStoppedChanging() || + nodeData->hasLodChanged())); } if (nodeData->isPacketWaiting()) { @@ -445,7 +447,6 @@ void OctreeSendThread::traverseTreeAndSendContents(SharedNodePointer node, Octre params.trackSend = [this](const QUuid& dataID, quint64 dataEdited) { _myServer->trackSend(dataID, dataEdited, _nodeUuid); }; - nodeData->copyCurrentViewFrustum(params.viewFrustum); bool somethingToSend = true; // assume we have something bool hadSomething = hasSomethingToSend(nodeData); diff --git a/assignment-client/src/scripts/EntityScriptServer.cpp b/assignment-client/src/scripts/EntityScriptServer.cpp index d242b393bf..eea8e8b470 100644 --- a/assignment-client/src/scripts/EntityScriptServer.cpp +++ b/assignment-client/src/scripts/EntityScriptServer.cpp @@ -294,7 +294,6 @@ void EntityScriptServer::run() { queryJSONParameters[EntityJSONQueryProperties::FLAGS_PROPERTY] = queryFlags; // setup the JSON parameters so that OctreeQuery does not use a frustum and uses our JSON filter - _entityViewer.getOctreeQuery().setUsesFrustum(false); _entityViewer.getOctreeQuery().setJSONParameters(queryJSONParameters); entityScriptingInterface->setEntityTree(_entityViewer.getTree()); diff --git a/domain-server/resources/web/wizard/index.shtml b/domain-server/resources/web/wizard/index.shtml index 5a3286296d..3bc7503b44 100644 --- a/domain-server/resources/web/wizard/index.shtml +++ b/domain-server/resources/web/wizard/index.shtml @@ -26,7 +26,7 @@ Place names are similar to web addresses. Users who want to visit your domain can enter its Place Name in High Fidelity's Interface. You can choose a Place Name for your domain.
- People can also use your domain's IP address (shown below) to visit your High Fidelity domain. + Your domain may also be reachable by IP address.
@@ -35,10 +35,10 @@ diff --git a/domain-server/src/DomainServerNodeData.cpp b/domain-server/src/DomainServerNodeData.cpp index 974d4a59c3..486b51f9eb 100644 --- a/domain-server/src/DomainServerNodeData.cpp +++ b/domain-server/src/DomainServerNodeData.cpp @@ -9,6 +9,8 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include "DomainServerNodeData.h" + #include #include #include @@ -17,8 +19,6 @@ #include -#include "DomainServerNodeData.h" - DomainServerNodeData::StringPairHash DomainServerNodeData::_overrideHash; DomainServerNodeData::DomainServerNodeData() { diff --git a/domain-server/src/DomainServerNodeData.h b/domain-server/src/DomainServerNodeData.h index db41c77cf2..6b8e9a1718 100644 --- a/domain-server/src/DomainServerNodeData.h +++ b/domain-server/src/DomainServerNodeData.h @@ -15,6 +15,7 @@ #include #include #include +#include #include #include diff --git a/domain-server/src/DomainServerWebSessionData.cpp b/domain-server/src/DomainServerWebSessionData.cpp index 3744af77f3..90eea17bec 100644 --- a/domain-server/src/DomainServerWebSessionData.cpp +++ b/domain-server/src/DomainServerWebSessionData.cpp @@ -9,13 +9,13 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include "DomainServerWebSessionData.h" + #include #include #include #include -#include "DomainServerWebSessionData.h" - DomainServerWebSessionData::DomainServerWebSessionData() : _username(), _roles() diff --git a/gvr-interface/src/Client.cpp b/gvr-interface/src/Client.cpp index 65238ad784..8f064c7fd5 100644 --- a/gvr-interface/src/Client.cpp +++ b/gvr-interface/src/Client.cpp @@ -9,14 +9,14 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include "Client.h" + #include #include #include #include #include -#include "Client.h" - Client::Client(QObject* parent) : QObject(parent) { @@ -70,4 +70,4 @@ void Client::processDatagrams() { processVerifiedPacket(senderSockAddr, incomingPacket); } } -} \ No newline at end of file +} diff --git a/gvr-interface/src/GVRInterface.cpp b/gvr-interface/src/GVRInterface.cpp index 3d58396322..f9a29d4ac4 100644 --- a/gvr-interface/src/GVRInterface.cpp +++ b/gvr-interface/src/GVRInterface.cpp @@ -9,6 +9,8 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include "GVRInterface.h" + #ifdef ANDROID #include @@ -32,8 +34,6 @@ #include "GVRMainWindow.h" #include "RenderingClient.h" -#include "GVRInterface.h" - static QString launchURLString = QString(); #ifdef ANDROID diff --git a/gvr-interface/src/GVRMainWindow.cpp b/gvr-interface/src/GVRMainWindow.cpp index 7a36aba66e..5495354233 100644 --- a/gvr-interface/src/GVRMainWindow.cpp +++ b/gvr-interface/src/GVRMainWindow.cpp @@ -9,6 +9,8 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include "GVRMainWindow.h" + #include #include #include @@ -37,8 +39,6 @@ const float LIBOVR_LONG_PRESS_DURATION = 0.75f; #include "LoginDialog.h" #include "RenderingClient.h" -#include "GVRMainWindow.h" - GVRMainWindow::GVRMainWindow(QWidget* parent) : diff --git a/gvr-interface/src/LoginDialog.cpp b/gvr-interface/src/LoginDialog.cpp index 95b7451bcb..d4efd425bd 100644 --- a/gvr-interface/src/LoginDialog.cpp +++ b/gvr-interface/src/LoginDialog.cpp @@ -9,14 +9,14 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include "LoginDialog.h" + #include #include #include #include #include -#include "LoginDialog.h" - LoginDialog::LoginDialog(QWidget* parent) : QDialog(parent) { @@ -66,4 +66,4 @@ void LoginDialog::setupGUI() { void LoginDialog::loginButtonClicked() { emit credentialsEntered(_usernameLineEdit->text(), _passwordLineEdit->text()); close(); -} \ No newline at end of file +} diff --git a/gvr-interface/src/RenderingClient.cpp b/gvr-interface/src/RenderingClient.cpp index f04be5cb7f..4c691a48e6 100644 --- a/gvr-interface/src/RenderingClient.cpp +++ b/gvr-interface/src/RenderingClient.cpp @@ -9,6 +9,8 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include "RenderingClient.h" + #include #include @@ -17,8 +19,6 @@ #include #include -#include "RenderingClient.h" - RenderingClient* RenderingClient::_instance = NULL; RenderingClient::RenderingClient(QObject *parent, const QString& launchURLString) : diff --git a/interface/resources/icons/+android/avatar-a.svg b/interface/resources/icons/+android/avatar-a.svg deleted file mode 100755 index 165b39943e..0000000000 --- a/interface/resources/icons/+android/avatar-a.svg +++ /dev/null @@ -1,38 +0,0 @@ - - - - - - - - - - - diff --git a/interface/resources/icons/+android/avatar-i.svg b/interface/resources/icons/+android/avatar-i.svg deleted file mode 100755 index c1557487ea..0000000000 --- a/interface/resources/icons/+android/avatar-i.svg +++ /dev/null @@ -1,38 +0,0 @@ - - - - - - - - - - - diff --git a/interface/resources/icons/+android/backward.svg b/interface/resources/icons/+android/backward.svg old mode 100644 new mode 100755 index ae0893fc66..6b4c560768 --- a/interface/resources/icons/+android/backward.svg +++ b/interface/resources/icons/+android/backward.svg @@ -1,70 +1,13 @@ - - - -image/svg+xml \ No newline at end of file + + + + + + + + diff --git a/interface/resources/icons/+android/goto-a.svg b/interface/resources/icons/+android/goto-a.svg deleted file mode 100755 index 5fb3e52e4c..0000000000 --- a/interface/resources/icons/+android/goto-a.svg +++ /dev/null @@ -1,28 +0,0 @@ - - - - - - - - - - - - - diff --git a/interface/resources/icons/+android/goto-i.svg b/interface/resources/icons/+android/goto-i.svg deleted file mode 100644 index 7613beb9e7..0000000000 --- a/interface/resources/icons/+android/goto-i.svg +++ /dev/null @@ -1,28 +0,0 @@ - - - - - - - - - - - - - diff --git a/interface/resources/icons/+android/home.svg b/interface/resources/icons/+android/home.svg deleted file mode 100644 index 414c179e79..0000000000 --- a/interface/resources/icons/+android/home.svg +++ /dev/null @@ -1,82 +0,0 @@ - - - -image/svg+xml \ No newline at end of file diff --git a/interface/resources/icons/+android/login-a.svg b/interface/resources/icons/+android/login-a.svg deleted file mode 100755 index 8a7f097ed7..0000000000 --- a/interface/resources/icons/+android/login-a.svg +++ /dev/null @@ -1,990 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/interface/resources/icons/+android/login-i.svg b/interface/resources/icons/+android/login-i.svg deleted file mode 100755 index 6f011e1d13..0000000000 --- a/interface/resources/icons/+android/login-i.svg +++ /dev/null @@ -1,990 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/interface/resources/icons/+android/mic-unmute-a.svg b/interface/resources/icons/+android/mic-unmute-a.svg old mode 100644 new mode 100755 index bb28dc0f2b..8717636a34 --- a/interface/resources/icons/+android/mic-unmute-a.svg +++ b/interface/resources/icons/+android/mic-unmute-a.svg @@ -1,70 +1,22 @@ - - - -image/svg+xml \ No newline at end of file + + + + + + + + + + + + + + diff --git a/interface/resources/icons/+android/myview-a.svg b/interface/resources/icons/+android/myview-a.svg index 307b559c95..e2c183caf2 100755 --- a/interface/resources/icons/+android/myview-a.svg +++ b/interface/resources/icons/+android/myview-a.svg @@ -1,56 +1,19 @@ - - - -image/svg+xmlAsset 3 \ No newline at end of file + + + + + + + + + + + diff --git a/interface/resources/icons/+android/radar-a.svg b/interface/resources/icons/+android/radar-a.svg deleted file mode 100755 index e4b157f827..0000000000 --- a/interface/resources/icons/+android/radar-a.svg +++ /dev/null @@ -1 +0,0 @@ -Asset 1 \ No newline at end of file diff --git a/interface/resources/icons/+android/radar-hover.svg b/interface/resources/icons/+android/radar-hover.svg deleted file mode 100755 index e4b157f827..0000000000 --- a/interface/resources/icons/+android/radar-hover.svg +++ /dev/null @@ -1 +0,0 @@ -Asset 1 \ No newline at end of file diff --git a/interface/resources/icons/+android/radar-i.svg b/interface/resources/icons/+android/radar-i.svg deleted file mode 100755 index 3994a775d3..0000000000 --- a/interface/resources/icons/+android/radar-i.svg +++ /dev/null @@ -1 +0,0 @@ -Asset 1 \ No newline at end of file diff --git a/interface/resources/images/fly.png b/interface/resources/images/fly.png index 0edfcab21b..b8b96645f8 100644 Binary files a/interface/resources/images/fly.png and b/interface/resources/images/fly.png differ diff --git a/interface/resources/qml/+android/AddressBarDialog.qml b/interface/resources/qml/+android/AddressBarDialog.qml deleted file mode 100644 index 4477d512fc..0000000000 --- a/interface/resources/qml/+android/AddressBarDialog.qml +++ /dev/null @@ -1,232 +0,0 @@ -// -// AddressBarDialog.qml -// -// Created by Austin Davis on 2015/04/14 -// Copyright 2015 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -import Hifi 1.0 -import QtQuick 2.4 -import "../controls" -import "../styles" -import "../hifi" as QmlHifi -import "../hifi/toolbars" -import "../styles-uit" as HifiStyles -import "../controls-uit" as HifiControls - -Item { - QmlHifi.HifiConstants { id: android } - - width: parent ? parent.width - android.dimen.windowLessWidth : 0 - height: parent ? parent.height - android.dimen.windowLessHeight : 0 - z: android.dimen.windowZ - anchors { horizontalCenter: parent.horizontalCenter; bottom: parent.bottom } - - id: bar - property bool isCursorVisible: false // Override default cursor visibility. - property bool shown: true - - onShownChanged: { - bar.visible = shown; - sendToScript({method: 'shownChanged', params: { shown: shown }}); - if (shown) { - addressLine.text=""; - updateLocationText(addressLine.text.length > 0); - } - } - - function hide() { - shown = false; - sendToScript ({ type: "hide" }); - } - - Component.onCompleted: { - updateLocationText(addressLine.text.length > 0); - } - - HifiConstants { id: hifi } - HifiStyles.HifiConstants { id: hifiStyleConstants } - - signal sendToScript(var message); - - AddressBarDialog { - id: addressBarDialog - } - - - Rectangle { - id: background - gradient: Gradient { - GradientStop { position: 0.0; color: android.color.gradientTop } - GradientStop { position: 1.0; color: android.color.gradientBottom } - } - anchors { - fill: parent - } - - MouseArea { - anchors.fill: parent - } - - QmlHifi.WindowHeader { - id: header - iconSource: "../../../icons/goto-i.svg" - titleText: "GO TO" - } - - HifiStyles.RalewayRegular { - id: notice - text: "YOUR LOCATION" - font.pixelSize: (hifi.fonts.pixelSize * 2.15) * (android.dimen.atLeast1440p ? 1 : .75); - color: "#2CD7FF" - anchors { - bottom: addressBackground.top - bottomMargin: android.dimen.atLeast1440p ? 45 : 34 - left: addressBackground.left - leftMargin: android.dimen.atLeast1440p ? 60 : 45 - } - - } - - property int inputAreaHeight: android.dimen.atLeast1440p ? 210 : 156 - property int inputAreaStep: (height - inputAreaHeight) / 2 - - ToolbarButton { - id: homeButton - y: android.dimen.atLeast1440p ? 280 : 210 - imageURL: "../../icons/home.svg" - onClicked: { - addressBarDialog.loadHome(); - bar.shown = false; - } - anchors { - leftMargin: android.dimen.atLeast1440p ? 75 : 56 - left: parent.left - } - size: android.dimen.atLeast1440p ? 150 : 150//112 - } - - ToolbarButton { - id: backArrow; - imageURL: "../../icons/backward.svg"; - onClicked: addressBarDialog.loadBack(); - anchors { - left: homeButton.right - leftMargin: android.dimen.atLeast1440p ? 70 : 52 - verticalCenter: homeButton.verticalCenter - } - size: android.dimen.atLeast1440p ? 150 : 150 - } - ToolbarButton { - id: forwardArrow; - imageURL: "../../icons/forward.svg"; - onClicked: addressBarDialog.loadForward(); - anchors { - left: backArrow.right - leftMargin: android.dimen.atLeast1440p ? 60 : 45 - verticalCenter: homeButton.verticalCenter - } - size: android.dimen.atLeast1440p ? 150 : 150 - } - - HifiStyles.FiraSansRegular { - id: location; - font.pixelSize: addressLine.font.pixelSize; - color: "lightgray"; - clip: true; - anchors.fill: addressLine; - visible: addressLine.text.length === 0 - z: 1 - } - - Rectangle { - id: addressBackground - x: android.dimen.atLeast1440p ? 780 : 585 - y: android.dimen.atLeast1440p ? 280 : 235 // tweaking by hand - width: android.dimen.atLeast1440p ? 1270 : 952 - height: android.dimen.atLeast1440p ? 150 : 112 - color: "#FFFFFF" - } - - TextInput { - id: addressLine - focus: true - x: android.dimen.atLeast1440p ? 870 : 652 - y: android.dimen.atLeast1440p ? 300 : 245 // tweaking by hand - width: android.dimen.atLeast1440p ? 1200 : 900 - height: android.dimen.atLeast1440p ? 120 : 90 - inputMethodHints: Qt.ImhNoPredictiveText - //helperText: "Hint is here" - font.pixelSize: hifi.fonts.pixelSize * 3.75 - onTextChanged: { - //filterChoicesByText(); - updateLocationText(addressLine.text.length > 0); - if (!isCursorVisible && text.length > 0) { - isCursorVisible = true; - cursorVisible = true; - } - } - - onActiveFocusChanged: { - //cursorVisible = isCursorVisible && focus; - } - } - - - - function toggleOrGo() { - if (addressLine.text !== "") { - addressBarDialog.loadAddress(addressLine.text); - } - bar.shown = false; - } - - Keys.onPressed: { - switch (event.key) { - case Qt.Key_Escape: - case Qt.Key_Back: - clearAddressLineTimer.start(); - event.accepted = true - bar.shown = false; - break - case Qt.Key_Enter: - case Qt.Key_Return: - toggleOrGo(); - clearAddressLineTimer.start(); - event.accepted = true - break - } - } - - } - - Timer { - // Delay clearing address line so as to avoid flicker of "not connected" being displayed after entering an address. - id: clearAddressLineTimer - running: false - interval: 100 // ms - repeat: false - onTriggered: { - addressLine.text = ""; - isCursorVisible = false; - } - } - - function updateLocationText(enteringAddress) { - if (enteringAddress) { - notice.text = "Go to a place, @user, path or network address"; - notice.color = "#ffffff"; // hifiStyleConstants.colors.baseGrayHighlight; - location.visible = false; - } else { - notice.text = AddressManager.isConnected ? "YOUR LOCATION:" : "NOT CONNECTED"; - notice.color = AddressManager.isConnected ? hifiStyleConstants.colors.blueHighlight : hifiStyleConstants.colors.redHighlight; - // Display hostname, which includes ip address, localhost, and other non-placenames. - location.text = (AddressManager.placename || AddressManager.hostname || '') + (AddressManager.pathname ? AddressManager.pathname.match(/\/[^\/]+/)[0] : ''); - location.visible = true; - } - } - -} diff --git a/interface/resources/qml/+android/LoginDialog.qml b/interface/resources/qml/+android/LoginDialog.qml deleted file mode 100644 index 567cca9bcf..0000000000 --- a/interface/resources/qml/+android/LoginDialog.qml +++ /dev/null @@ -1,95 +0,0 @@ -// -// LoginDialog.qml -// -// Created by David Rowe on 3 Jun 2015 -// Copyright 2015 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -import Hifi 1.0 -import QtQuick 2.4 - -import "controls-uit" -import "styles-uit" -import "windows" - -import "LoginDialog" - -ModalWindow { - id: root - HifiConstants { id: hifi } - - objectName: "LoginDialog" - implicitWidth: 1560 - implicitHeight: 450 - y:0 - destroyOnCloseButton: true - destroyOnHidden: true - visible: true - - property string iconText: "" - property int iconSize: 105 - - property string title: "" - property int titleWidth: 0 - - keyboardOverride: true // Disable ModalWindow's keyboard. - - function tryDestroy() { - Controller.setVPadHidden(false); - root.destroy(); - } - - LoginDialog { - id: loginDialog - - Loader { - id: bodyLoader - source: loginDialog.isSteamRunning() ? "LoginDialog/+android/SignInBody.qml" : "LoginDialog/+android/LinkAccountBody.qml" - } - } - - Component.onCompleted: { - this.anchors.centerIn = undefined; - this.y = 150; - this.x = (parent.width - this.width) / 2; - Controller.setVPadHidden(true); - } - - Keys.onPressed: { - if (!visible) { - return - } - - if (event.modifiers === Qt.ControlModifier) - switch (event.key) { - case Qt.Key_A: - event.accepted = true - detailedText.selectAll() - break - case Qt.Key_C: - event.accepted = true - detailedText.copy() - break - case Qt.Key_Period: - if (Qt.platform.os === "osx") { - event.accepted = true - content.reject() - } - break - } else switch (event.key) { - case Qt.Key_Escape: - case Qt.Key_Back: - event.accepted = true - destroy() - break - - case Qt.Key_Enter: - case Qt.Key_Return: - event.accepted = true - break - } - } -} diff --git a/interface/resources/qml/LoginDialog/SignInBody.qml b/interface/resources/qml/LoginDialog/SignInBody.qml index c4b6c2aee1..9cb1add704 100644 --- a/interface/resources/qml/LoginDialog/SignInBody.qml +++ b/interface/resources/qml/LoginDialog/SignInBody.qml @@ -84,11 +84,9 @@ Item { height: undefined // invalidate so that the image's size sets the height focus: true - style: OriginalStyles.ButtonStyle { - background: Image { - id: buttonImage - source: "../../images/steam-sign-in.png" - } + background: Image { + id: buttonImage + source: "../../images/steam-sign-in.png" } onClicked: signInBody.login() } diff --git a/interface/resources/qml/hifi/+android/ActionBar.qml b/interface/resources/qml/hifi/+android/ActionBar.qml new file mode 100644 index 0000000000..d487901d6f --- /dev/null +++ b/interface/resources/qml/hifi/+android/ActionBar.qml @@ -0,0 +1,71 @@ +import QtQuick 2.5 +import QtQuick.Controls 1.4 +import QtQuick.Controls.Styles 1.4 +import QtQuick.Layouts 1.3 +import Qt.labs.settings 1.0 +import "../../styles-uit" +import "../../controls-uit" as HifiControlsUit +import "../../controls" as HifiControls +import ".." + +Item { + id: actionBar + x:0 + y:0 + width: 300 + height: 300 + z: -1 + + signal sendToScript(var message); + signal windowClosed(); + + property bool shown: true + + onShownChanged: { + actionBar.visible = shown; + } + + Rectangle { + anchors.fill : parent + color: "transparent" + Flow { + id: flowMain + spacing: 10 + flow: Flow.TopToBottom + layoutDirection: Flow.TopToBottom + anchors.fill: parent + anchors.margins: 4 + } + } + + Component.onCompleted: { + // put on bottom + x = 7; + y = 7; + width = 300; + height = 300; + } + + function addButton(properties) { + var component = Qt.createComponent("button.qml"); + if (component.status == Component.Ready) { + var button = component.createObject(flowMain); + // copy all properites to button + var keys = Object.keys(properties).forEach(function (key) { + button[key] = properties[key]; + }); + return button; + } else if( component.status == Component.Error) { + console.log("Load button errors " + component.errorString()); + } + } + + function urlHelper(src) { + if (src.match(/\bhttp/)) { + return src; + } else { + return "../../../" + src; + } + } + +} diff --git a/interface/resources/qml/hifi/+android/AudioBar.qml b/interface/resources/qml/hifi/+android/AudioBar.qml index f524595ef5..6cc17fccf7 100644 --- a/interface/resources/qml/hifi/+android/AudioBar.qml +++ b/interface/resources/qml/hifi/+android/AudioBar.qml @@ -38,13 +38,26 @@ Item { } } - Component.onCompleted: { - // put on bottom - x = 0; - y = 0; + function relocateAndResize(newWindowWidth, newWindowHeight) { + x = newWindowWidth-328; + y = 19; width = 300; height = 300; } + + function onWindowGeometryChanged(rect) { + relocateAndResize(rect.width, rect.height); + } + + Component.onCompleted: { + relocateAndResize(parent.width, parent.height); + Window.geometryChanged.connect(onWindowGeometryChanged); // In devices with bars appearing at startup we should listen for this + } + + Component.onDestruction: { + Window.geometryChanged.disconnect(onWindowGeometryChanged); + } + function addButton(properties) { var component = Qt.createComponent("button.qml"); diff --git a/interface/resources/qml/hifi/+android/avatarSelection.qml b/interface/resources/qml/hifi/+android/avatarSelection.qml deleted file mode 100644 index afa5634575..0000000000 --- a/interface/resources/qml/hifi/+android/avatarSelection.qml +++ /dev/null @@ -1,179 +0,0 @@ -// -// avatarSelection.qml -// interface/resources/qml/android -// -// Created by Gabriel Calero & Cristian Duarte on 21 Sep 2017 -// Copyright 2017 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// -import QtQuick 2.5 -import QtQuick.Layouts 1.3 -import Hifi 1.0 - -import "../../styles" -import "." -import ".." -import ".." as QmlHifi -import "../../styles-uit" as HifiStyles - - -Item { - - id: top - - HifiConstants { id: android } - width: parent ? parent.width - android.dimen.windowLessWidth : 0 - height: parent ? parent.height - android.dimen.windowLessHeight : 0 - z: android.dimen.windowZ - anchors { horizontalCenter: parent.horizontalCenter; bottom: parent.bottom } - - signal sendToScript(var message); - - property bool shown: true - - onShownChanged: { - top.visible = shown; - } - - - HifiConstants { id: hifi } - HifiStyles.HifiConstants { id: hifiStyleConstants } - - property int cardWidth: 250 *3; - property int cardHeight: 240 *3; - property int gap: 14 *3; - - property var avatarsArray: []; - property var extraOptionsArray: []; - - function hide() { - shown = false; - sendToScript ({ method: "hide" }); - } - - Rectangle { - - width: parent ? parent.width : 0 - height: parent ? parent.height : 0 - - MouseArea { - anchors.fill: parent - } - - gradient: Gradient { - GradientStop { position: 0.0; color: android.color.gradientTop } - GradientStop { position: 1.0; color: android.color.gradientBottom } - } - - QmlHifi.WindowHeader { - id: header - iconSource: "../../../../icons/avatar-i.svg" - titleText: "AVATAR" - } - - ListModel { id: avatars } - - ListView { - id: scroll - height: 250*3 - property int stackedCardShadowHeight: 10*3; - spacing: gap; - clip: true; - anchors { - left: parent.left - right: parent.right - top: header.bottom - topMargin: gap - leftMargin: gap - rightMargin: gap - } - model: avatars; - orientation: ListView.Horizontal; - delegate: QmlHifi.AvatarOption { - type: model.type; - thumbnailUrl: model.thumbnailUrl; - avatarUrl: model.avatarUrl; - avatarName: model.avatarName; - avatarSelected: model.avatarSelected; - methodName: model.methodName; - actionText: model.actionText; - } - highlightMoveDuration: -1; - highlightMoveVelocity: -1; - } - - } - - function escapeRegExp(str) { - return str.replace(/([.*+?^=!:${}()|\[\]\/\\])/g, "\\$1"); - } - function replaceAll(str, find, replace) { - return str.replace(new RegExp(escapeRegExp(find), 'g'), replace); - } - - function refreshSelected(selectedAvatarUrl) { - // URL as ID? - avatarsArray.forEach(function (avatarData) { - avatarData.avatarSelected = (selectedAvatarUrl == avatarData.avatarUrl); - console.log('[avatarSelection] avatar : ', avatarData.avatarName, ' is selected? ' , avatarData.avatarSelected); - }); - } - - function addAvatar(name, thumbnailUrl, avatarUrl) { - avatarsArray.push({ - type: "avatar", - thumbnailUrl: thumbnailUrl, - avatarUrl: avatarUrl, - avatarName: name, - avatarSelected: false, - methodName: "", - actionText: "" - }); - } - - function showAvatars() { - avatars.clear(); - avatarsArray.forEach(function (avatarData) { - avatars.append(avatarData); - console.log('[avatarSelection] adding avatar to model: ', JSON.stringify(avatarData)); - }); - extraOptionsArray.forEach(function (extraData) { - avatars.append(extraData); - console.log('[avatarSelection] adding extra option to model: ', JSON.stringify(extraData)); - }); - } - - function addExtraOption(showName, thumbnailUrl, methodNameWhenClicked, actionText) { - extraOptionsArray.push({ - type: "extra", - thumbnailUrl: thumbnailUrl, - avatarUrl: "", - avatarName: showName, - avatarSelected: false, - methodName: methodNameWhenClicked, - actionText: actionText - }); - } - - function fromScript(message) { - //console.log("[CHAT] fromScript " + JSON.stringify(message)); - switch (message.type) { - case "addAvatar": - addAvatar(message.name, message.thumbnailUrl, message.avatarUrl); - break; - case "addExtraOption": - //(showName, thumbnailUrl, methodNameWhenClicked, actionText) - addExtraOption(message.showName, message.thumbnailUrl, message.methodNameWhenClicked, message.actionText); - break; - case "refreshSelected": - refreshSelected(message.selectedAvatarUrl); - break; - case "showAvatars": - showAvatars(); - break; - default: - } - } -} \ No newline at end of file diff --git a/interface/resources/qml/hifi/+android/bottomHudOptions.qml b/interface/resources/qml/hifi/+android/bottomHudOptions.qml index 860298149f..22beccf531 100644 --- a/interface/resources/qml/hifi/+android/bottomHudOptions.qml +++ b/interface/resources/qml/hifi/+android/bottomHudOptions.qml @@ -47,17 +47,14 @@ Item { spacing: 0 flow: Flow.LeftToRight layoutDirection: Flow.LeftToRight - anchors.fill: parent + anchors.horizontalCenter: parent.horizontalCenter anchors.margins: 12 Rectangle { id: hideButton - height: android.dimen.headerHideWidth - width: android.dimen.headerHideHeight + height: android.dimen.headerHideHeight + width: android.dimen.headerHideWidth color: "#00000000" - anchors { - horizontalCenter: parent.horizontalCenter - } Image { id: hideIcon source: "../../../icons/show-up.svg" diff --git a/interface/resources/qml/hifi/+android/bottombar.qml b/interface/resources/qml/hifi/+android/bottombar.qml deleted file mode 100644 index 66117d0389..0000000000 --- a/interface/resources/qml/hifi/+android/bottombar.qml +++ /dev/null @@ -1,151 +0,0 @@ -// -// bottomHudOptions.qml -// interface/resources/qml/android -// -// Created by Gabriel Calero & Cristian Duarte on 19 Jan 2018 -// 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 Hifi 1.0 -import QtQuick 2.5 -import QtQuick.Controls 1.4 -import QtQuick.Controls.Styles 1.4 -import QtQuick.Layouts 1.3 -import Qt.labs.settings 1.0 -import "../../styles" as Styles -import "../../styles-uit" -import "../../controls-uit" as HifiControlsUit -import "../../controls" as HifiControls -import ".." -import "." - -Item { - id: bar - x:0 - height: 255 - - property bool shown: true - - signal sendToScript(var message); - - onShownChanged: { - bar.visible = shown; - } - - function hide() { - //shown = false; - sendToScript({ method: "hide" }); - } - - Styles.HifiConstants { id: hifi } - HifiConstants { id: android } - MouseArea { - anchors.fill: parent - } - - Rectangle { - id: background - anchors.fill : parent - color: "#FF000000" - border.color: "#FFFFFF" - anchors.bottomMargin: -1 - anchors.leftMargin: -1 - anchors.rightMargin: -1 - Flow { - id: flowMain - spacing: 10 - anchors.fill: parent - anchors.topMargin: 12 - anchors.bottomMargin: 12 - anchors.rightMargin: 12 - anchors.leftMargin: 72 - } - - - Rectangle { - id: hideButton - height: android.dimen.headerHideWidth - width: android.dimen.headerHideHeight - color: "#00000000" - anchors { - right: parent.right - rightMargin: android.dimen.headerHideRightMargin - top: parent.top - topMargin: android.dimen.headerHideTopMargin - } - - Image { - id: hideIcon - source: "../../../icons/hide.svg" - width: android.dimen.headerHideIconWidth - height: android.dimen.headerHideIconHeight - anchors { - horizontalCenter: parent.horizontalCenter - top: parent.top - } - } - FiraSansRegular { - anchors { - top: hideIcon.bottom - horizontalCenter: hideIcon.horizontalCenter - topMargin: 12 - } - text: "HIDE" - color: "#FFFFFF" - font.pixelSize: hifi.fonts.pixelSize * 2.5; - } - - MouseArea { - anchors.fill: parent - onClicked: { - hide(); - } - } - } - } - - function relocateAndResize(newWindowWidth, newWindowHeight) { - width = newWindowWidth; - y = newWindowHeight - height; - } - - function onWindowGeometryChanged(rect) { - relocateAndResize(rect.width, rect.height); - } - - Component.onCompleted: { - // put on bottom - relocateAndResize(Window.innerWidth, Window.innerHeight); - Window.geometryChanged.connect(onWindowGeometryChanged); // In devices with bars appearing at startup we should listen for this - } - - Component.onDestruction: { - Window.geometryChanged.disconnect(onWindowGeometryChanged); - } - - function addButton(properties) { - var component = Qt.createComponent("button.qml"); - if (component.status == Component.Ready) { - var button = component.createObject(flowMain); - // copy all properites to button - var keys = Object.keys(properties).forEach(function (key) { - button[key] = properties[key]; - }); - return button; - } else if( component.status == Component.Error) { - console.log("Load button errors " + component.errorString()); - } - } - - function urlHelper(src) { - if (src.match(/\bhttp/)) { - return src; - } else { - return "../../../" + src; - } - } - -} diff --git a/interface/resources/qml/hifi/+android/button.qml b/interface/resources/qml/hifi/+android/button.qml index 3e9ce39351..a4c65b3c6f 100644 --- a/interface/resources/qml/hifi/+android/button.qml +++ b/interface/resources/qml/hifi/+android/button.qml @@ -32,6 +32,9 @@ Item { property string hoverTextColor: "#ffffff" property string activeTextColor: "#ffffff" property string activeHoverTextColor: "#ffffff" + property string fontFamily: "FiraSans" + property bool fontBold: false + property int bottomMargin: 30 property bool isEntered: false @@ -92,8 +95,8 @@ Item { id: text color: "#ffffff" text: button.text - font.family: "FiraSans" - //font.bold: true + font.family: button.fontFamily + font.bold: button.fontBold font.pixelSize: textSize anchors.bottom: parent.bottom anchors.bottomMargin: bottomMargin @@ -143,15 +146,12 @@ Item { PropertyChanges { target: buttonBg - //color: "#cfcfcf" - //opacity: 1 color: button.hoverBgColor opacity: button.hoverBgOpacity } PropertyChanges { target: text - //color: "#ffffff" color: button.hoverTextColor text: button.hoverText } @@ -166,15 +166,12 @@ Item { PropertyChanges { target: buttonBg - //color: "#1fc6a6" - //opacity: 1 color: button.activeBgColor opacity: button.activeBgOpacity } PropertyChanges { target: text - //color: "#333333" color: button.activeTextColor text: button.activeText } @@ -189,15 +186,12 @@ Item { PropertyChanges { target: buttonBg - //color: "#ff0000" - //opacity: 1 color: button.activeHoverBgColor opacity: button.activeHoverBgOpacity } PropertyChanges { target: text - //color: "#333333" color: button.activeHoverTextColor text: button.activeHoverText } @@ -212,15 +206,12 @@ Item { PropertyChanges { target: buttonBg - //color: "#9A9A9A" - //opacity: 0.1 color: button.bgColor opacity: button.bgOpacity } PropertyChanges { target: text - //color: "#ffffff" color: button.textColor text: button.text } diff --git a/interface/resources/qml/hifi/+android/modesbar.qml b/interface/resources/qml/hifi/+android/modesbar.qml index fe71314ece..994bf1efe4 100644 --- a/interface/resources/qml/hifi/+android/modesbar.qml +++ b/interface/resources/qml/hifi/+android/modesbar.qml @@ -10,24 +10,25 @@ import ".." Item { id: modesbar - y:60 - Rectangle { - anchors.fill : parent - color: "transparent" - Flow { - id: flowMain - spacing: 0 - flow: Flow.TopToBottom - layoutDirection: Flow.TopToBottom - anchors.fill: parent - anchors.margins: 4 - } - } + y:5 + + function relocateAndResize(newWindowWidth, newWindowHeight) { + width = 300; + height = 300; + x = newWindowWidth - 565; + } + + function onWindowGeometryChanged(rect) { + relocateAndResize(rect.width, rect.height); + } Component.onCompleted: { - width = 300 + 30; // That 30 is extra regardless the qty of items shown - height = 300 + 30; - x=Window.innerWidth - width; + relocateAndResize(parent.width, parent.height); + Window.geometryChanged.connect(onWindowGeometryChanged); // In devices with bars appearing at startup we should listen for this + } + + Component.onDestruction: { + Window.geometryChanged.disconnect(onWindowGeometryChanged); } function addButton(properties) { @@ -35,7 +36,7 @@ Item { console.log("load button"); if (component.status == Component.Ready) { console.log("load button 2"); - var button = component.createObject(flowMain); + var button = component.createObject(modesbar); // copy all properites to button var keys = Object.keys(properties).forEach(function (key) { button[key] = properties[key]; @@ -59,14 +60,12 @@ Item { function fromScript(message) { switch (message.type) { - case "allButtonsShown": - modesbar.height = flowMain.children.length * 300 + 30; // That 30 is extra regardless the qty of items shown - break; - case "inactiveButtonsHidden": - modesbar.height = 300 + 30; - break; + case "switch": + // message.params.to + // still not needed + break; default: - break; + break; } } diff --git a/interface/resources/qml/hifi/commerce/checkout/Checkout.qml b/interface/resources/qml/hifi/commerce/checkout/Checkout.qml index 1cfbcf9075..f25282c738 100644 --- a/interface/resources/qml/hifi/commerce/checkout/Checkout.qml +++ b/interface/resources/qml/hifi/commerce/checkout/Checkout.qml @@ -787,7 +787,7 @@ Rectangle { } lightboxPopup.button2text = "CONFIRM"; lightboxPopup.button2method = function() { - Commerce.replaceContentSet(root.itemHref); + Commerce.replaceContentSet(root.itemHref, root.certificateId); lightboxPopup.visible = false; rezzedNotifContainer.visible = true; rezzedNotifContainerTimer.start(); diff --git a/interface/resources/qml/hifi/commerce/purchases/Purchases.qml b/interface/resources/qml/hifi/commerce/purchases/Purchases.qml index 6b48f8d51d..d79b8d09fa 100644 --- a/interface/resources/qml/hifi/commerce/purchases/Purchases.qml +++ b/interface/resources/qml/hifi/commerce/purchases/Purchases.qml @@ -729,7 +729,7 @@ Rectangle { } lightboxPopup.button2text = "CONFIRM"; lightboxPopup.button2method = function() { - MyAvatar.skeletonModelURL = ''; + MyAvatar.useFullAvatarURL(''); root.activeView = "giftAsset"; lightboxPopup.visible = false; }; diff --git a/interface/resources/qml/hifi/commerce/wallet/PassphraseModal.qml b/interface/resources/qml/hifi/commerce/wallet/PassphraseModal.qml index 1cada9789b..c4abd40d2a 100644 --- a/interface/resources/qml/hifi/commerce/wallet/PassphraseModal.qml +++ b/interface/resources/qml/hifi/commerce/wallet/PassphraseModal.qml @@ -47,6 +47,13 @@ Item { onWalletAuthenticatedStatusResult: { submitPassphraseInputButton.enabled = true; + + // It's not possible to auth with a blank passphrase, + // so bail early if we get this signal without anything in the passphrase field + if (passphraseField.text === "") { + return; + } + if (!isAuthenticated) { errorText.text = "Authentication failed - please try again."; passphraseField.error = true; @@ -211,6 +218,10 @@ Item { error = false; focus = true; forceActiveFocus(); + } else { + showPassphrase.checked = false; + passphraseField.text = ""; + error = false; } } diff --git a/interface/src/AndroidHelper.cpp b/interface/src/AndroidHelper.cpp new file mode 100644 index 0000000000..b04a6ff2c4 --- /dev/null +++ b/interface/src/AndroidHelper.cpp @@ -0,0 +1,20 @@ +// +// AndroidHelper.cpp +// interface/src +// +// Created by Gabriel Calero & Cristian Duarte on 3/30/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 +// +#include "AndroidHelper.h" +#include + +void AndroidHelper::requestActivity(const QString &activityName) { + emit androidActivityRequested(activityName); +} + +void AndroidHelper::goBackFromAndroidActivity() { + emit backFromAndroidActivity(); +} \ No newline at end of file diff --git a/interface/src/AndroidHelper.h b/interface/src/AndroidHelper.h new file mode 100644 index 0000000000..34f32b461b --- /dev/null +++ b/interface/src/AndroidHelper.h @@ -0,0 +1,37 @@ +// +// AndroidHelper.h +// interface/src +// +// Created by Gabriel Calero & Cristian Duarte on 3/30/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 +// + +#ifndef hifi_Android_Helper_h +#define hifi_Android_Helper_h + +#include + +class AndroidHelper : public QObject { + Q_OBJECT +public: + static AndroidHelper& instance() { + static AndroidHelper instance; + return instance; + } + void requestActivity(const QString &activityName); + void goBackFromAndroidActivity(); + + AndroidHelper(AndroidHelper const&) = delete; + void operator=(AndroidHelper const&) = delete; +signals: + void androidActivityRequested(const QString &activityName); + void backFromAndroidActivity(); + +private: + AndroidHelper() {} +}; + +#endif \ No newline at end of file diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index cd4562da54..ec28dcb3dd 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -252,6 +252,7 @@ extern "C" { #if defined(Q_OS_ANDROID) #include +#include "AndroidHelper.h" #endif enum ApplicationEvent { @@ -742,6 +743,11 @@ extern DisplayPluginList getDisplayPlugins(); extern InputPluginList getInputPlugins(); extern void saveInputPluginSettings(const InputPluginList& plugins); +// Parameters used for running tests from teh command line +const QString TEST_SCRIPT_COMMAND { "--testScript" }; +const QString TEST_QUIT_WHEN_FINISHED_OPTION { "quitWhenFinished" }; +const QString TEST_SNAPSHOT_LOCATION_COMMAND { "--testSnapshotLocation" }; + bool setupEssentials(int& argc, char** argv, bool runningMarkerExisted) { const char** constArgv = const_cast(argv); @@ -776,7 +782,22 @@ bool setupEssentials(int& argc, char** argv, bool runningMarkerExisted) { static const auto SUPPRESS_SETTINGS_RESET = "--suppress-settings-reset"; bool suppressPrompt = cmdOptionExists(argc, const_cast(argv), SUPPRESS_SETTINGS_RESET); - bool previousSessionCrashed = CrashHandler::checkForResetSettings(runningMarkerExisted, suppressPrompt); + + // Ignore any previous crashes if running from command line with a test script. + bool inTestMode { false }; + for (int i = 0; i < argc; ++i) { + QString parameter(argv[i]); + if (parameter == TEST_SCRIPT_COMMAND) { + inTestMode = true; + break; + } + } + + bool previousSessionCrashed { false }; + if (!inTestMode) { + previousSessionCrashed = CrashHandler::checkForResetSettings(runningMarkerExisted, suppressPrompt); + } + // get dir to use for cache static const auto CACHE_SWITCH = "--cache"; QString cacheDir = getCmdOption(argc, const_cast(argv), CACHE_SWITCH); @@ -966,7 +987,6 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo _entitySimulation(new PhysicalEntitySimulation()), _physicsEngine(new PhysicsEngine(Vectors::ZERO)), _entityClipboard(new EntityTree()), - _lastQueriedTime(usecTimestampNow()), _previousScriptLocation("LastScriptLocation", DESKTOP_LOCATION), _fieldOfView("fieldOfView", DEFAULT_FIELD_OF_VIEW_DEGREES), _hmdTabletScale("hmdTabletScale", DEFAULT_HMD_TABLET_SCALE_PERCENT), @@ -996,13 +1016,30 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo setProperty(hifi::properties::STEAM, (steamClient && steamClient->isRunning())); setProperty(hifi::properties::CRASHED, _previousSessionCrashed); { - const QString TEST_SCRIPT = "--testScript"; const QStringList args = arguments(); + for (int i = 0; i < args.size() - 1; ++i) { - if (args.at(i) == TEST_SCRIPT) { + if (args.at(i) == TEST_SCRIPT_COMMAND && (i + 1) < args.size()) { QString testScriptPath = args.at(i + 1); - if (QFileInfo(testScriptPath).exists()) { + + // If the URL scheme is http(s) or ftp, then use as is, else - treat it as a local file + // This is done so as not break previous command line scripts + if (testScriptPath.left(URL_SCHEME_HTTP.length()) == URL_SCHEME_HTTP || testScriptPath.left(URL_SCHEME_FTP.length()) == URL_SCHEME_FTP) { + setProperty(hifi::properties::TEST, QUrl::fromUserInput(testScriptPath)); + } else if (QFileInfo(testScriptPath).exists()) { setProperty(hifi::properties::TEST, QUrl::fromLocalFile(testScriptPath)); + } + + // quite when finished parameter must directly follow the test script + if ((i + 2) < args.size() && args.at(i + 2) == TEST_QUIT_WHEN_FINISHED_OPTION) { + quitWhenFinished = true; + } + } else if (args.at(i) == TEST_SNAPSHOT_LOCATION_COMMAND) { + // Set test snapshot location only if it is a writeable directory + QString pathname(args.at(i + 1)); + QFileInfo fileInfo(pathname); + if (fileInfo.isDir() && fileInfo.isWritable()) { + testSnapshotLocation = pathname; } } } @@ -1258,6 +1295,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo connect(scriptEngines, &ScriptEngines::scriptsReloading, scriptEngines, [this] { getEntities()->reloadEntityScripts(); + loadAvatarScripts(getMyAvatar()->getScriptUrls()); }, Qt::QueuedConnection); connect(scriptEngines, &ScriptEngines::scriptLoadError, @@ -1323,6 +1361,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo // Create the main thread context, the GPU backend, and the display plugins initializeGL(); + DependencyManager::get()->setGPUContext(_gpuContext); qCDebug(interfaceapp, "Initialized Display."); // Create the rendering engine. This can be slow on some machines due to lots of // GPU pipeline creation. @@ -2126,14 +2165,24 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo return entityServerNode && !isPhysicsEnabled(); }); - _snapshotSound = DependencyManager::get()->getSound(PathUtils::resourcesUrl("sounds/snap.wav")); + _snapshotSound = DependencyManager::get()->getSound(PathUtils::resourcesUrl("sounds/snapshot/snap.wav")); QVariant testProperty = property(hifi::properties::TEST); qDebug() << testProperty; if (testProperty.isValid()) { auto scriptEngines = DependencyManager::get(); const auto testScript = property(hifi::properties::TEST).toUrl(); - scriptEngines->loadScript(testScript, false); + + // Set last parameter to exit interface when the test script finishes, if so requested + scriptEngines->loadScript(testScript, false, false, false, false, quitWhenFinished); + + // This is done so we don't get a "connection time-out" message when we haven't passed in a URL. + if (arguments().contains("--url")) { + auto reply = SandboxUtils::getStatus(); + connect(reply, &QNetworkReply::finished, this, [=] { + handleSandboxStatus(reply); + }); + } } else { PROFILE_RANGE(render, "GetSandboxStatus"); auto reply = SandboxUtils::getStatus(); @@ -2731,6 +2780,9 @@ void Application::initializeUi() { offscreenUi->resume(); connect(_window, &MainWindow::windowGeometryChanged, [this](const QRect& r){ resizeGL(); + if (_touchscreenVirtualPadDevice) { + _touchscreenVirtualPadDevice->resize(); + } }); // This will set up the input plugins UI @@ -3166,11 +3218,13 @@ void Application::handleSandboxStatus(QNetworkReply* reply) { // If this is a first run we short-circuit the address passed in if (firstRun.get()) { -#if !defined(Q_OS_ANDROID) - showHelp(); -#endif +#if defined(Q_OS_ANDROID) + qCDebug(interfaceapp) << "First run... going to" << qPrintable(addressLookupString.isEmpty() ? QString("default location") : addressLookupString); + DependencyManager::get()->loadSettings(addressLookupString); +#else DependencyManager::get()->goToEntry(); sentTo = SENT_TO_ENTRY; +#endif firstRun.set(false); } else { @@ -3626,7 +3680,7 @@ void Application::keyPressEvent(QKeyEvent* event) { } else { showCursor(Cursor::Icon::DEFAULT); } - } else { + } else if (!event->isAutoRepeat()){ resetSensors(true); } break; @@ -3740,6 +3794,12 @@ void Application::keyPressEvent(QKeyEvent* event) { void Application::keyReleaseEvent(QKeyEvent* event) { _keysPressed.remove(event->key()); +#if defined(Q_OS_ANDROID) + if (event->key() == Qt::Key_Back) { + event->accept(); + openAndroidActivity("Home"); + } +#endif _controllerScriptingInterface->emitKeyReleaseEvent(event); // send events to any registered scripts // if one of our scripts have asked to capture this event, then stop processing it @@ -4807,6 +4867,31 @@ void Application::init() { }, Qt::QueuedConnection); } +void Application::loadAvatarScripts(const QVector& urls) { + auto scriptEngines = DependencyManager::get(); + auto runningScripts = scriptEngines->getRunningScripts(); + for (auto url : urls) { + int index = runningScripts.indexOf(url); + if (index < 0) { + auto scriptEnginePointer = scriptEngines->loadScript(url, false); + if (scriptEnginePointer) { + scriptEnginePointer->setType(ScriptEngine::Type::AVATAR); + } + } + } +} + +void Application::unloadAvatarScripts() { + auto scriptEngines = DependencyManager::get(); + auto urls = scriptEngines->getRunningScripts(); + for (auto url : urls) { + auto scriptEngine = scriptEngines->getScriptEngine(url); + if (scriptEngine->getType() == ScriptEngine::Type::AVATAR) { + scriptEngines->stopScript(url, false); + } + } +} + void Application::updateLOD(float deltaTime) const { PerformanceTimer perfTimer("LOD"); // adjust it unless we were asked to disable this feature, or if we're currently in throttleRendering mode @@ -5045,7 +5130,7 @@ void Application::reloadResourceCaches() { resetPhysicsReadyInformation(); // Query the octree to refresh everything in view - _lastQueriedTime = 0; + _queryExpiry = SteadyClock::now(); _octreeQuery.incrementConnectionID(); queryOctree(NodeType::EntityServer, PacketType::EntityQuery); @@ -5179,6 +5264,78 @@ void Application::updateDialogs(float deltaTime) const { } } +void Application::updateSecondaryCameraViewFrustum() { + // TODO: Fix this by modeling the way the secondary camera works on how the main camera works + // ie. Use a camera object stored in the game logic and informs the Engine on where the secondary + // camera should be. + + // Code based on SecondaryCameraJob + auto renderConfig = _renderEngine->getConfiguration(); + assert(renderConfig); + auto camera = dynamic_cast(renderConfig->getConfig("SecondaryCamera")); + + if (!camera || !camera->isEnabled()) { + return; + } + + ViewFrustum secondaryViewFrustum; + if (camera->mirrorProjection && !camera->attachedEntityId.isNull()) { + auto entityScriptingInterface = DependencyManager::get(); + auto entityProperties = entityScriptingInterface->getEntityProperties(camera->attachedEntityId); + glm::vec3 mirrorPropertiesPosition = entityProperties.getPosition(); + glm::quat mirrorPropertiesRotation = entityProperties.getRotation(); + glm::vec3 mirrorPropertiesDimensions = entityProperties.getDimensions(); + glm::vec3 halfMirrorPropertiesDimensions = 0.5f * mirrorPropertiesDimensions; + + // setup mirror from world as inverse of world from mirror transformation using inverted x and z for mirrored image + // TODO: we are assuming here that UP is world y-axis + glm::mat4 worldFromMirrorRotation = glm::mat4_cast(mirrorPropertiesRotation) * glm::scale(vec3(-1.0f, 1.0f, -1.0f)); + glm::mat4 worldFromMirrorTranslation = glm::translate(mirrorPropertiesPosition); + glm::mat4 worldFromMirror = worldFromMirrorTranslation * worldFromMirrorRotation; + glm::mat4 mirrorFromWorld = glm::inverse(worldFromMirror); + + // get mirror camera position by reflecting main camera position's z coordinate in mirror space + glm::vec3 mainCameraPositionWorld = getCamera().getPosition(); + glm::vec3 mainCameraPositionMirror = vec3(mirrorFromWorld * vec4(mainCameraPositionWorld, 1.0f)); + glm::vec3 mirrorCameraPositionMirror = vec3(mainCameraPositionMirror.x, mainCameraPositionMirror.y, + -mainCameraPositionMirror.z); + glm::vec3 mirrorCameraPositionWorld = vec3(worldFromMirror * vec4(mirrorCameraPositionMirror, 1.0f)); + + // set frustum position to be mirrored camera and set orientation to mirror's adjusted rotation + glm::quat mirrorCameraOrientation = glm::quat_cast(worldFromMirrorRotation); + secondaryViewFrustum.setPosition(mirrorCameraPositionWorld); + secondaryViewFrustum.setOrientation(mirrorCameraOrientation); + + // build frustum using mirror space translation of mirrored camera + float nearClip = mirrorCameraPositionMirror.z + mirrorPropertiesDimensions.z * 2.0f; + glm::vec3 upperRight = halfMirrorPropertiesDimensions - mirrorCameraPositionMirror; + glm::vec3 bottomLeft = -halfMirrorPropertiesDimensions - mirrorCameraPositionMirror; + glm::mat4 frustum = glm::frustum(bottomLeft.x, upperRight.x, bottomLeft.y, upperRight.y, nearClip, camera->farClipPlaneDistance); + secondaryViewFrustum.setProjection(frustum); + } else { + if (!camera->attachedEntityId.isNull()) { + auto entityScriptingInterface = DependencyManager::get(); + auto entityProperties = entityScriptingInterface->getEntityProperties(camera->attachedEntityId); + secondaryViewFrustum.setPosition(entityProperties.getPosition()); + secondaryViewFrustum.setOrientation(entityProperties.getRotation()); + } else { + secondaryViewFrustum.setPosition(camera->position); + secondaryViewFrustum.setOrientation(camera->orientation); + } + + float aspectRatio = (float)camera->textureWidth / (float)camera->textureHeight; + secondaryViewFrustum.setProjection(camera->vFoV, + aspectRatio, + camera->nearClipPlaneDistance, + camera->farClipPlaneDistance); + } + // Without calculating the bound planes, the secondary camera will use the same culling frustum as the main camera, + // which is not what we want here. + secondaryViewFrustum.calculate(); + + _conicalViews.push_back(secondaryViewFrustum); +} + static bool domainLoadingInProgress = false; void Application::update(float deltaTime) { @@ -5532,6 +5689,13 @@ void Application::update(float deltaTime) { { QMutexLocker viewLocker(&_viewMutex); _myCamera.loadViewFrustum(_viewFrustum); + + _conicalViews.clear(); + _conicalViews.push_back(_viewFrustum); + // TODO: Fix this by modeling the way the secondary camera works on how the main camera works + // ie. Use a camera object stored in the game logic and informs the Engine on where the secondary + // camera should be. + updateSecondaryCameraViewFrustum(); } quint64 now = usecTimestampNow(); @@ -5541,18 +5705,31 @@ void Application::update(float deltaTime) { PROFILE_RANGE_EX(app, "QueryOctree", 0xffff0000, (uint64_t)getActiveDisplayPlugin()->presentCount()); PerformanceTimer perfTimer("queryOctree"); QMutexLocker viewLocker(&_viewMutex); - quint64 sinceLastQuery = now - _lastQueriedTime; - const quint64 TOO_LONG_SINCE_LAST_QUERY = 3 * USECS_PER_SECOND; - bool queryIsDue = sinceLastQuery > TOO_LONG_SINCE_LAST_QUERY; - bool viewIsDifferentEnough = !_lastQueriedViewFrustum.isVerySimilar(_viewFrustum); + + bool viewIsDifferentEnough = false; + if (_conicalViews.size() == _lastQueriedViews.size()) { + for (size_t i = 0; i < _conicalViews.size(); ++i) { + if (!_conicalViews[i].isVerySimilar(_lastQueriedViews[i])) { + viewIsDifferentEnough = true; + break; + } + } + } else { + viewIsDifferentEnough = true; + } + + // if it's been a while since our last query or the view has significantly changed then send a query, otherwise suppress it - if (queryIsDue || viewIsDifferentEnough) { - _lastQueriedTime = now; + static const std::chrono::seconds MIN_PERIOD_BETWEEN_QUERIES { 3 }; + auto now = SteadyClock::now(); + if (now > _queryExpiry || viewIsDifferentEnough) { if (DependencyManager::get()->shouldRenderEntities()) { queryOctree(NodeType::EntityServer, PacketType::EntityQuery); } - sendAvatarViewFrustum(); - _lastQueriedViewFrustum = _viewFrustum; + queryAvatars(); + + _lastQueriedViews = _conicalViews; + _queryExpiry = now + MIN_PERIOD_BETWEEN_QUERIES; } } @@ -5724,10 +5901,20 @@ void Application::update(float deltaTime) { } } -void Application::sendAvatarViewFrustum() { - QByteArray viewFrustumByteArray = _viewFrustum.toByteArray(); - auto avatarPacket = NLPacket::create(PacketType::ViewFrustum, viewFrustumByteArray.size()); - avatarPacket->write(viewFrustumByteArray); +void Application::queryAvatars() { + auto avatarPacket = NLPacket::create(PacketType::AvatarQuery); + auto destinationBuffer = reinterpret_cast(avatarPacket->getPayload()); + unsigned char* bufferStart = destinationBuffer; + + uint8_t numFrustums = (uint8_t)_conicalViews.size(); + memcpy(destinationBuffer, &numFrustums, sizeof(numFrustums)); + destinationBuffer += sizeof(numFrustums); + + for (const auto& view : _conicalViews) { + destinationBuffer += view.serialize(destinationBuffer); + } + + avatarPacket->setPayloadSize(destinationBuffer - bufferStart); DependencyManager::get()->broadcastToNodes(std::move(avatarPacket), NodeSet() << NodeType::AvatarMixer); } @@ -5789,16 +5976,8 @@ void Application::queryOctree(NodeType_t serverType, PacketType packetType) { return; // bail early if settings are not loaded } - ViewFrustum viewFrustum; - copyViewFrustum(viewFrustum); - _octreeQuery.setCameraPosition(viewFrustum.getPosition()); - _octreeQuery.setCameraOrientation(viewFrustum.getOrientation()); - _octreeQuery.setCameraFov(viewFrustum.getFieldOfView()); - _octreeQuery.setCameraAspectRatio(viewFrustum.getAspectRatio()); - _octreeQuery.setCameraNearClip(viewFrustum.getNearClip()); - _octreeQuery.setCameraFarClip(viewFrustum.getFarClip()); - _octreeQuery.setCameraEyeOffsetPosition(glm::vec3()); - _octreeQuery.setCameraCenterRadius(viewFrustum.getCenterRadius()); + _octreeQuery.setConicalViews(_conicalViews); + auto lodManager = DependencyManager::get(); _octreeQuery.setOctreeSizeScale(lodManager->getOctreeSizeScale()); _octreeQuery.setBoundaryLevelAdjust(lodManager->getBoundaryLevelAdjust()); @@ -6007,7 +6186,7 @@ void Application::nodeActivated(SharedNodePointer node) { // If we get a new EntityServer activated, reset lastQueried time // so we will do a proper query during update if (node->getType() == NodeType::EntityServer) { - _lastQueriedTime = 0; + _queryExpiry = SteadyClock::now(); _octreeQuery.incrementConnectionID(); } @@ -6016,6 +6195,8 @@ void Application::nodeActivated(SharedNodePointer node) { } if (node->getType() == NodeType::AvatarMixer) { + _queryExpiry = SteadyClock::now(); + // new avatar mixer, send off our identity packet on next update loop // Reset skeletonModelUrl if the last server modified our choice. // Override the avatar url (but not model name) here too. @@ -7331,7 +7512,7 @@ void Application::loadAvatarBrowser() const { void Application::takeSnapshot(bool notify, bool includeAnimated, float aspectRatio, const QString& filename) { postLambdaEvent([notify, includeAnimated, aspectRatio, filename, this] { // Get a screenshot and save it - QString path = Snapshot::saveSnapshot(getActiveDisplayPlugin()->getScreenshot(aspectRatio), filename); + QString path = Snapshot::saveSnapshot(getActiveDisplayPlugin()->getScreenshot(aspectRatio), filename, testSnapshotLocation); // If we're not doing an animated snapshot as well... if (!includeAnimated) { // Tell the dependency manager that the capture of the still snapshot has taken place. @@ -7345,7 +7526,7 @@ void Application::takeSnapshot(bool notify, bool includeAnimated, float aspectRa void Application::takeSecondaryCameraSnapshot(const QString& filename) { postLambdaEvent([filename, this] { - QString snapshotPath = Snapshot::saveSnapshot(getActiveDisplayPlugin()->getSecondaryCameraScreenshot(), filename); + QString snapshotPath = Snapshot::saveSnapshot(getActiveDisplayPlugin()->getSecondaryCameraScreenshot(), filename, testSnapshotLocation); emit DependencyManager::get()->stillSnapshotTaken(snapshotPath, true); }); } @@ -7828,6 +8009,26 @@ void Application::switchDisplayMode() { _previousHMDWornStatus = currentHMDWornStatus; } +void Application::setShowBulletWireframe(bool value) { + _physicsEngine->setShowBulletWireframe(value); +} + +void Application::setShowBulletAABBs(bool value) { + _physicsEngine->setShowBulletAABBs(value); +} + +void Application::setShowBulletContactPoints(bool value) { + _physicsEngine->setShowBulletContactPoints(value); +} + +void Application::setShowBulletConstraints(bool value) { + _physicsEngine->setShowBulletConstraints(value); +} + +void Application::setShowBulletConstraintLimits(bool value) { + _physicsEngine->setShowBulletConstraintLimits(value); +} + void Application::startHMDStandBySession() { _autoSwitchDisplayModeSupportedHMDPlugin->startStandBySession(); } @@ -8009,4 +8210,29 @@ void Application::saveNextPhysicsStats(QString filename) { _physicsEngine->saveNextPhysicsStats(filename); } +void Application::openAndroidActivity(const QString& activityName) { +#if defined(Q_OS_ANDROID) + AndroidHelper::instance().requestActivity(activityName); +#endif +} + +#if defined(Q_OS_ANDROID) +void Application::enterBackground() { + QMetaObject::invokeMethod(DependencyManager::get().data(), + "stop", Qt::BlockingQueuedConnection); + //GC: commenting it out until we fix it + //getActiveDisplayPlugin()->deactivate(); +} +void Application::enterForeground() { + QMetaObject::invokeMethod(DependencyManager::get().data(), + "start", Qt::BlockingQueuedConnection); + //GC: commenting it out until we fix it + /*if (!getActiveDisplayPlugin() || !getActiveDisplayPlugin()->activate()) { + qWarning() << "Could not re-activate display plugin"; + }*/ + +} +#endif + +#include "Application_jni.cpp" #include "Application.moc" diff --git a/interface/src/Application.h b/interface/src/Application.h index 6d611bc8e2..aa6469c592 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -47,6 +47,7 @@ #include #include #include +#include #include #include @@ -110,7 +111,8 @@ class Application : public QApplication, public AbstractViewStateInterface, public AbstractScriptingServicesInterface, public AbstractUriHandler, - public PluginContainer { + public PluginContainer +{ Q_OBJECT // TODO? Get rid of those @@ -149,6 +151,8 @@ public: void initializeRenderEngine(); void initializeUi(); + void updateSecondaryCameraViewFrustum(); + void updateCamera(RenderArgs& renderArgs, float deltaTime); void paintGL(); void resizeGL(); @@ -178,6 +182,9 @@ public: // which might be different from the viewFrustum, i.e. shadowmap // passes, mirror window passes, etc void copyDisplayViewFrustum(ViewFrustum& viewOut) const; + + const ConicalViewFrustums& getConicalViews() const override { return _conicalViews; } + const OctreePacketProcessor& getOctreePacketProcessor() const { return _octreeProcessor; } QSharedPointer getEntities() const { return DependencyManager::get(); } QUndoStack* getUndoStack() { return &_undoStack; } @@ -243,6 +250,7 @@ public: bool isAboutToQuit() const { return _aboutToQuit; } bool isPhysicsEnabled() const { return _physicsEnabled; } + PhysicsEnginePointer getPhysicsEngine() { return _physicsEngine; } // the isHMDMode is true whenever we use the interface from an HMD and not a standard flat display // rendering of several elements depend on that @@ -290,6 +298,14 @@ public: void replaceDomainContent(const QString& url); + void loadAvatarScripts(const QVector& urls); + void unloadAvatarScripts(); + +#if defined(Q_OS_ANDROID) + void enterBackground(); + void enterForeground(); +#endif + signals: void svoImportRequested(const QString& url); @@ -400,6 +416,8 @@ public slots: Q_INVOKABLE bool askBeforeSetAvatarUrl(const QString& avatarUrl) { return askToSetAvatarUrl(avatarUrl); } void updateVerboseLogging(); + Q_INVOKABLE void openAndroidActivity(const QString& activityName); + private slots: void onDesktopRootItemCreated(QQuickItem* qmlContext); @@ -453,6 +471,12 @@ private slots: void handleSandboxStatus(QNetworkReply* reply); void switchDisplayMode(); + void setShowBulletWireframe(bool value); + void setShowBulletAABBs(bool value); + void setShowBulletContactPoints(bool value); + void setShowBulletConstraints(bool value); + void setShowBulletConstraintLimits(bool value); + private: void init(); bool handleKeyEventForFocusedEntityOrOverlay(QEvent* event); @@ -469,9 +493,9 @@ private: void updateDialogs(float deltaTime) const; void queryOctree(NodeType_t serverType, PacketType packetType); + void queryAvatars(); int sendNackPackets(); - void sendAvatarViewFrustum(); std::shared_ptr getMyAvatar() const; @@ -552,9 +576,14 @@ private: mutable QMutex _viewMutex { QMutex::Recursive }; ViewFrustum _viewFrustum; // current state of view frustum, perspective, orientation, etc. - ViewFrustum _lastQueriedViewFrustum; /// last view frustum used to query octree servers (voxels) ViewFrustum _displayViewFrustum; - quint64 _lastQueriedTime; + + ConicalViewFrustums _conicalViews; + ConicalViewFrustums _lastQueriedViews; // last views used to query servers + + using SteadyClock = std::chrono::steady_clock; + using TimePoint = SteadyClock::time_point; + TimePoint _queryExpiry; OctreeQuery _octreeQuery { true }; // NodeData derived class for querying octee cells from octree servers @@ -721,5 +750,8 @@ private: std::atomic _pendingIdleEvent { true }; std::atomic _pendingRenderEvent { true }; + + QString testSnapshotLocation; + bool quitWhenFinished { false }; }; #endif // hifi_Application_h diff --git a/interface/src/Application_jni.cpp b/interface/src/Application_jni.cpp new file mode 100644 index 0000000000..5e9f1ac29e --- /dev/null +++ b/interface/src/Application_jni.cpp @@ -0,0 +1,24 @@ +#if defined(Q_OS_ANDROID) + +#include +#include "AndroidHelper.h" + +extern "C" { + +JNIEXPORT void +Java_io_highfidelity_hifiinterface_InterfaceActivity_nativeEnterBackground(JNIEnv *env, jobject obj) { + if (qApp) { + qApp->enterBackground(); + } +} + +JNIEXPORT void +Java_io_highfidelity_hifiinterface_InterfaceActivity_nativeEnterForeground(JNIEnv *env, jobject obj) { + if (qApp) { + qApp->enterForeground(); + } +} + + +} +#endif \ No newline at end of file diff --git a/interface/src/AvatarBookmarks.cpp b/interface/src/AvatarBookmarks.cpp index 7845158a80..8e15de673f 100644 --- a/interface/src/AvatarBookmarks.cpp +++ b/interface/src/AvatarBookmarks.cpp @@ -9,6 +9,8 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include "AvatarBookmarks.h" + #include #include #include @@ -27,7 +29,6 @@ #include "MainWindow.h" #include "Menu.h" -#include "AvatarBookmarks.h" #include "InterfaceLogging.h" #include "QVariantGLM.h" diff --git a/interface/src/AvatarBookmarks.h b/interface/src/AvatarBookmarks.h index 177e6e493e..7b47ea8af7 100644 --- a/interface/src/AvatarBookmarks.h +++ b/interface/src/AvatarBookmarks.h @@ -18,6 +18,10 @@ /**jsdoc * This API helps manage adding and deleting avatar bookmarks. * @namespace AvatarBookmarks + * + * @hifi-interface + * @hifi-client-entity + * */ class AvatarBookmarks: public Bookmarks, public Dependency { diff --git a/interface/src/Bookmarks.cpp b/interface/src/Bookmarks.cpp index f48b5e1f5b..6e99b81e50 100644 --- a/interface/src/Bookmarks.cpp +++ b/interface/src/Bookmarks.cpp @@ -9,6 +9,8 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include "Bookmarks.h" + #include #include #include @@ -22,8 +24,6 @@ #include "Menu.h" #include "InterfaceLogging.h" -#include "Bookmarks.h" - Bookmarks::Bookmarks() : _isMenuSorted(false) { diff --git a/interface/src/Crashpad.cpp b/interface/src/Crashpad.cpp index e39cd42d81..45f1d0778f 100644 --- a/interface/src/Crashpad.cpp +++ b/interface/src/Crashpad.cpp @@ -11,6 +11,8 @@ #include "Crashpad.h" +#include + #include #if HAS_CRASHPAD @@ -20,7 +22,7 @@ #include #include -#include +#include #include #include @@ -28,28 +30,27 @@ #include #include +#include + using namespace crashpad; static const std::string BACKTRACE_URL { CMAKE_BACKTRACE_URL }; static const std::string BACKTRACE_TOKEN { CMAKE_BACKTRACE_TOKEN }; -static std::wstring gIPCPipe; - extern QString qAppFileName(); +CrashpadClient* client { nullptr }; std::mutex annotationMutex; crashpad::SimpleStringDictionary* crashpadAnnotations { nullptr }; -#include - LONG WINAPI vectoredExceptionHandler(PEXCEPTION_POINTERS pExceptionInfo) { + if (!client) { + return EXCEPTION_CONTINUE_SEARCH; + } + if (pExceptionInfo->ExceptionRecord->ExceptionCode == STATUS_HEAP_CORRUPTION || pExceptionInfo->ExceptionRecord->ExceptionCode == STATUS_STACK_BUFFER_OVERRUN) { - CrashpadClient client; - if (gIPCPipe.length()) { - client.SetHandlerIPCPipe(gIPCPipe); - } - client.DumpAndCrash(pExceptionInfo); + client->DumpAndCrash(pExceptionInfo); } return EXCEPTION_CONTINUE_SEARCH; @@ -60,7 +61,8 @@ bool startCrashHandler() { return false; } - CrashpadClient client; + assert(!client); + client = new CrashpadClient(); std::vector arguments; std::map annotations; @@ -96,12 +98,9 @@ bool startCrashHandler() { // Enable automated uploads. database->GetSettings()->SetUploadsEnabled(true); - bool result = client.StartHandler(handler, db, db, BACKTRACE_URL, annotations, arguments, true, true); - gIPCPipe = client.GetHandlerIPCPipe(); - AddVectoredExceptionHandler(0, vectoredExceptionHandler); - return result; + return client->StartHandler(handler, db, db, BACKTRACE_URL, annotations, arguments, true, true); } void setCrashAnnotation(std::string name, std::string value) { diff --git a/interface/src/DiscoverabilityManager.cpp b/interface/src/DiscoverabilityManager.cpp index b3c059de7f..684539145e 100644 --- a/interface/src/DiscoverabilityManager.cpp +++ b/interface/src/DiscoverabilityManager.cpp @@ -9,7 +9,10 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include "DiscoverabilityManager.h" + #include +#include #include #include @@ -21,11 +24,8 @@ #include #include "Crashpad.h" -#include "DiscoverabilityManager.h" #include "Menu.h" -#include - const Discoverability::Mode DEFAULT_DISCOVERABILITY_MODE = Discoverability::Connections; DiscoverabilityManager::DiscoverabilityManager() : diff --git a/interface/src/DiscoverabilityManager.h b/interface/src/DiscoverabilityManager.h index 96190b25d9..0c62ad5663 100644 --- a/interface/src/DiscoverabilityManager.h +++ b/interface/src/DiscoverabilityManager.h @@ -12,9 +12,13 @@ #ifndef hifi_DiscoverabilityManager_h #define hifi_DiscoverabilityManager_h +#include + #include #include +class QNetworkReply; + namespace Discoverability { enum Mode { None, diff --git a/interface/src/GLCanvas.cpp b/interface/src/GLCanvas.cpp index ec96f7c5d4..0d087c9b48 100644 --- a/interface/src/GLCanvas.cpp +++ b/interface/src/GLCanvas.cpp @@ -9,10 +9,10 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -// FIXME ordering of headers -#include "Application.h" #include "GLCanvas.h" +#include "Application.h" + bool GLCanvas::event(QEvent* event) { if (QEvent::Paint == event->type() && qApp->isAboutToQuit()) { return true; diff --git a/interface/src/InterfaceDynamicFactory.cpp b/interface/src/InterfaceDynamicFactory.cpp index b7861b56c8..e0d912b252 100644 --- a/interface/src/InterfaceDynamicFactory.cpp +++ b/interface/src/InterfaceDynamicFactory.cpp @@ -9,7 +9,7 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // - +#include "InterfaceDynamicFactory.h" #include #include @@ -22,9 +22,6 @@ #include #include -#include "InterfaceDynamicFactory.h" - - EntityDynamicPointer interfaceDynamicFactory(EntityDynamicType type, const QUuid& id, EntityItemPointer ownerEntity) { switch (type) { case DYNAMIC_TYPE_NONE: diff --git a/interface/src/InterfaceParentFinder.cpp b/interface/src/InterfaceParentFinder.cpp index 14088bc716..b9be58f04b 100644 --- a/interface/src/InterfaceParentFinder.cpp +++ b/interface/src/InterfaceParentFinder.cpp @@ -9,13 +9,13 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include "InterfaceParentFinder.h" + #include +#include +#include #include #include -#include -#include - -#include "InterfaceParentFinder.h" SpatiallyNestableWeakPointer InterfaceParentFinder::find(QUuid parentID, bool& success, SpatialParentTree* entityTree) const { SpatiallyNestableWeakPointer parent; diff --git a/interface/src/LODManager.cpp b/interface/src/LODManager.cpp index d7d73e962a..d06ba14bcf 100644 --- a/interface/src/LODManager.cpp +++ b/interface/src/LODManager.cpp @@ -9,6 +9,8 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include "LODManager.h" + #include #include #include @@ -17,8 +19,6 @@ #include "ui/DialogsManager.h" #include "InterfaceLogging.h" -#include "LODManager.h" - Setting::Handle desktopLODDecreaseFPS("desktopLODDecreaseFPS", DEFAULT_DESKTOP_LOD_DOWN_FPS); Setting::Handle hmdLODDecreaseFPS("hmdLODDecreaseFPS", DEFAULT_HMD_LOD_DOWN_FPS); diff --git a/interface/src/LODManager.h b/interface/src/LODManager.h index 96d92e91e9..8f88da63a8 100644 --- a/interface/src/LODManager.h +++ b/interface/src/LODManager.h @@ -37,6 +37,10 @@ class AABox; /**jsdoc * The LOD class manages your Level of Detail functions within Interface. * @namespace LODManager + * + * @hifi-interface + * @hifi-client-entity + * * @property {number} presentTime Read-only. * @property {number} engineRunTime Read-only. * @property {number} gpuTime Read-only. diff --git a/interface/src/LocationBookmarks.cpp b/interface/src/LocationBookmarks.cpp index 285f533a7f..8415c84282 100644 --- a/interface/src/LocationBookmarks.cpp +++ b/interface/src/LocationBookmarks.cpp @@ -9,21 +9,16 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include "LocationBookmarks.h" + #include -#include -#include #include #include -#include #include -#include "MainWindow.h" #include "Menu.h" -#include "LocationBookmarks.h" -#include - const QString LocationBookmarks::HOME_BOOKMARK = "Home"; LocationBookmarks::LocationBookmarks() { diff --git a/interface/src/LocationBookmarks.h b/interface/src/LocationBookmarks.h index 9a800ba35e..39abea9ba4 100644 --- a/interface/src/LocationBookmarks.h +++ b/interface/src/LocationBookmarks.h @@ -13,6 +13,7 @@ #define hifi_LocationBookmarks_h #include + #include "Bookmarks.h" class LocationBookmarks : public Bookmarks, public Dependency { diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 50ff65ad1a..bf0fc05350 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -9,6 +9,8 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include "Menu.h" + #include #include #include @@ -52,8 +54,6 @@ #include "SpeechRecognizer.h" #endif -#include "Menu.h" - extern bool DEV_DECIMATE_TEXTURES; Menu* Menu::getInstance() { @@ -735,6 +735,12 @@ Menu::Menu() { } addCheckableActionToQMenuAndActionHash(physicsOptionsMenu, MenuOption::PhysicsShowHulls, 0, false, qApp->getEntities().data(), SIGNAL(setRenderDebugHulls())); + addCheckableActionToQMenuAndActionHash(physicsOptionsMenu, MenuOption::PhysicsShowBulletWireframe, 0, false, qApp, SLOT(setShowBulletWireframe(bool))); + addCheckableActionToQMenuAndActionHash(physicsOptionsMenu, MenuOption::PhysicsShowBulletAABBs, 0, false, qApp, SLOT(setShowBulletAABBs(bool))); + addCheckableActionToQMenuAndActionHash(physicsOptionsMenu, MenuOption::PhysicsShowBulletContactPoints, 0, false, qApp, SLOT(setShowBulletContactPoints(bool))); + addCheckableActionToQMenuAndActionHash(physicsOptionsMenu, MenuOption::PhysicsShowBulletConstraints, 0, false, qApp, SLOT(setShowBulletConstraints(bool))); + addCheckableActionToQMenuAndActionHash(physicsOptionsMenu, MenuOption::PhysicsShowBulletConstraintLimits, 0, false, qApp, SLOT(setShowBulletConstraintLimits(bool))); + // Developer > Ask to Reset Settings addCheckableActionToQMenuAndActionHash(developerMenu, MenuOption::AskToResetSettings, 0, false); diff --git a/interface/src/Menu.h b/interface/src/Menu.h index c8c8ee42df..20375a71b2 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -143,6 +143,11 @@ namespace MenuOption { const QString PhysicsShowHulls = "Draw Collision Shapes"; const QString PhysicsShowOwned = "Highlight Simulation Ownership"; const QString VerboseLogging = "Verbose Logging"; + const QString PhysicsShowBulletWireframe = "Show Bullet Collision"; + const QString PhysicsShowBulletAABBs = "Show Bullet Bounding Boxes"; + const QString PhysicsShowBulletContactPoints = "Show Bullet Contact Points"; + const QString PhysicsShowBulletConstraints = "Show Bullet Constraints"; + const QString PhysicsShowBulletConstraintLimits = "Show Bullet Constraint Limits"; const QString PipelineWarnings = "Log Render Pipeline Warnings"; const QString Preferences = "General..."; const QString Quit = "Quit"; diff --git a/interface/src/ModelPackager.cpp b/interface/src/ModelPackager.cpp index 5f4c7526e0..3a5d92eb8c 100644 --- a/interface/src/ModelPackager.cpp +++ b/interface/src/ModelPackager.cpp @@ -9,6 +9,8 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include "ModelPackager.h" + #include #include #include @@ -21,8 +23,6 @@ #include "ModelPropertiesDialog.h" #include "InterfaceLogging.h" -#include "ModelPackager.h" - static const int MAX_TEXTURE_SIZE = 1024; void copyDirectoryContent(QDir& from, QDir& to) { @@ -156,9 +156,11 @@ bool ModelPackager::zipModel() { QByteArray nameField = _mapping.value(NAME_FIELD).toByteArray(); tempDir.mkpath(nameField + "/textures"); + tempDir.mkpath(nameField + "/scripts"); QDir fbxDir(tempDir.path() + "/" + nameField); QDir texDir(fbxDir.path() + "/textures"); - + QDir scriptDir(fbxDir.path() + "/scripts"); + // Copy textures listTextures(); if (!_textures.empty()) { @@ -166,6 +168,23 @@ bool ModelPackager::zipModel() { _texDir = _modelFile.path() + "/" + texdirField; copyTextures(_texDir, texDir); } + + // Copy scripts + QByteArray scriptField = _mapping.value(SCRIPT_FIELD).toByteArray(); + _mapping.remove(SCRIPT_FIELD); + if (scriptField.size() > 1) { + tempDir.mkpath(nameField + "/scripts"); + _scriptDir = _modelFile.path() + "/" + scriptField; + QDir wdir = QDir(_scriptDir); + _mapping.remove(SCRIPT_FIELD); + wdir.setSorting(QDir::Name | QDir::Reversed); + auto list = wdir.entryList(QDir::NoDotAndDotDot | QDir::AllEntries); + for (auto script : list) { + auto sc = tempDir.relativeFilePath(scriptDir.path()) + "/" + QUrl(script).fileName(); + _mapping.insertMulti(SCRIPT_FIELD, sc); + } + copyDirectoryContent(wdir, scriptDir); + } // Copy LODs QVariantHash lodField = _mapping.value(LOD_FIELD).toHash(); @@ -189,7 +208,10 @@ bool ModelPackager::zipModel() { // Correct FST _mapping[FILENAME_FIELD] = tempDir.relativeFilePath(newPath); _mapping[TEXDIR_FIELD] = tempDir.relativeFilePath(texDir.path()); - + + for (auto multi : _mapping.values(SCRIPT_FIELD)) { + multi.fromValue(tempDir.relativeFilePath(scriptDir.path()) + multi.toString()); + } // Copy FST QFile fst(tempDir.path() + "/" + nameField + ".fst"); if (fst.open(QIODevice::WriteOnly)) { @@ -237,7 +259,9 @@ void ModelPackager::populateBasicMapping(QVariantHash& mapping, QString filename if (!mapping.contains(TEXDIR_FIELD)) { mapping.insert(TEXDIR_FIELD, "."); } - + if (!mapping.contains(SCRIPT_FIELD)) { + mapping.insert(SCRIPT_FIELD, "."); + } // mixamo/autodesk defaults if (!mapping.contains(SCALE_FIELD)) { mapping.insert(SCALE_FIELD, 1.0); diff --git a/interface/src/ModelPackager.h b/interface/src/ModelPackager.h index 10942833f9..76295e5a85 100644 --- a/interface/src/ModelPackager.h +++ b/interface/src/ModelPackager.h @@ -12,11 +12,15 @@ #ifndef hifi_ModelPackager_h #define hifi_ModelPackager_h +#include + #include #include #include "ui/ModelsBrowser.h" +class FBXGeometry; + class ModelPackager : public QObject { public: static bool package(); @@ -37,10 +41,12 @@ private: QFileInfo _fbxInfo; FSTReader::ModelType _modelType; QString _texDir; + QString _scriptDir; QVariantHash _mapping; std::unique_ptr _geometry; QStringList _textures; + QStringList _scripts; }; diff --git a/interface/src/ModelPropertiesDialog.cpp b/interface/src/ModelPropertiesDialog.cpp index ae352974ae..8984f89d07 100644 --- a/interface/src/ModelPropertiesDialog.cpp +++ b/interface/src/ModelPropertiesDialog.cpp @@ -9,6 +9,8 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include "ModelPropertiesDialog.h" + #include #include #include @@ -23,8 +25,6 @@ #include #include -#include "ModelPropertiesDialog.h" - ModelPropertiesDialog::ModelPropertiesDialog(FSTReader::ModelType modelType, const QVariantHash& originalMapping, const QString& basePath, const FBXGeometry& geometry) : @@ -43,6 +43,9 @@ _geometry(geometry) form->addRow("Texture Directory:", _textureDirectory = new QPushButton()); connect(_textureDirectory, SIGNAL(clicked(bool)), SLOT(chooseTextureDirectory())); + form->addRow("Script Directory:", _scriptDirectory = new QPushButton()); + connect(_scriptDirectory, SIGNAL(clicked(bool)), SLOT(chooseScriptDirectory())); + form->addRow("Scale:", _scale = new QDoubleSpinBox()); _scale->setMaximum(FLT_MAX); _scale->setSingleStep(0.01); @@ -100,6 +103,7 @@ QVariantHash ModelPropertiesDialog::getMapping() const { mapping.insert(TYPE_FIELD, getType()); mapping.insert(NAME_FIELD, _name->text()); mapping.insert(TEXDIR_FIELD, _textureDirectory->text()); + mapping.insert(SCRIPT_FIELD, _scriptDirectory->text()); mapping.insert(SCALE_FIELD, QString::number(_scale->value())); // update the joint indices @@ -157,6 +161,7 @@ void ModelPropertiesDialog::reset() { _name->setText(_originalMapping.value(NAME_FIELD).toString()); _textureDirectory->setText(_originalMapping.value(TEXDIR_FIELD).toString()); _scale->setValue(_originalMapping.value(SCALE_FIELD).toDouble()); + _scriptDirectory->setText(_originalMapping.value(SCRIPT_FIELD).toString()); QVariantHash jointHash = _originalMapping.value(JOINT_FIELD).toHash(); @@ -207,6 +212,20 @@ void ModelPropertiesDialog::chooseTextureDirectory() { _textureDirectory->setText(directory.length() == _basePath.length() ? "." : directory.mid(_basePath.length() + 1)); } +void ModelPropertiesDialog::chooseScriptDirectory() { + QString directory = QFileDialog::getExistingDirectory(this, "Choose Script Directory", + _basePath + "/" + _scriptDirectory->text()); + if (directory.isEmpty()) { + return; + } + if (!directory.startsWith(_basePath)) { + OffscreenUi::asyncWarning(NULL, "Invalid script directory", "Script directory must be child of base path."); + return; + } + _scriptDirectory->setText(directory.length() == _basePath.length() ? "." : directory.mid(_basePath.length() + 1)); +} + + void ModelPropertiesDialog::updatePivotJoint() { _pivotJoint->setEnabled(!_pivotAboutCenter->isChecked()); } diff --git a/interface/src/ModelPropertiesDialog.h b/interface/src/ModelPropertiesDialog.h index 11abc5ab54..e3c2d8ed6a 100644 --- a/interface/src/ModelPropertiesDialog.h +++ b/interface/src/ModelPropertiesDialog.h @@ -37,6 +37,7 @@ public: private slots: void reset(); void chooseTextureDirectory(); + void chooseScriptDirectory(); void updatePivotJoint(); void createNewFreeJoint(const QString& joint = QString()); @@ -52,6 +53,7 @@ private: FBXGeometry _geometry; QLineEdit* _name = nullptr; QPushButton* _textureDirectory = nullptr; + QPushButton* _scriptDirectory = nullptr; QDoubleSpinBox* _scale = nullptr; QDoubleSpinBox* _translationX = nullptr; QDoubleSpinBox* _translationY = nullptr; diff --git a/interface/src/ModelSelector.cpp b/interface/src/ModelSelector.cpp index 2f85849fbe..7d91359a11 100644 --- a/interface/src/ModelSelector.cpp +++ b/interface/src/ModelSelector.cpp @@ -9,6 +9,8 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include "ModelSelector.h" + #include #include #include @@ -16,8 +18,6 @@ #include #include -#include "ModelSelector.h" - static const QString AVATAR_HEAD_AND_BODY_STRING = "Avatar Body with Head"; static const QString AVATAR_ATTACHEMENT_STRING = "Avatar Attachment"; static const QString ENTITY_MODEL_STRING = "Entity Model"; @@ -82,4 +82,4 @@ void ModelSelector::browse() { _browseButton->setText(fileInfo.fileName()); lastModelBrowseLocation.set(fileInfo.path()); } -} \ No newline at end of file +} diff --git a/interface/src/SecondaryCamera.cpp b/interface/src/SecondaryCamera.cpp index a4bf0bcefe..acde535d2b 100644 --- a/interface/src/SecondaryCamera.cpp +++ b/interface/src/SecondaryCamera.cpp @@ -9,13 +9,16 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -#include "Application.h" #include "SecondaryCamera.h" -#include -#include -#include + #include +#include +#include +#include + +#include "Application.h" + using RenderArgsPointer = std::shared_ptr; void MainRenderTask::build(JobModel& task, const render::Varying& inputs, render::Varying& outputs, render::CullFunctor cullFunctor, bool isDeferred) { @@ -213,4 +216,4 @@ void SecondaryCameraRenderTask::build(JobModel& task, const render::Varying& inp task.addJob("RenderDeferredTask", items); } task.addJob("EndSecondaryCamera", cachedArg); -} \ No newline at end of file +} diff --git a/interface/src/SecondaryCamera.h b/interface/src/SecondaryCamera.h index 026b72d865..3d9e52617c 100644 --- a/interface/src/SecondaryCamera.h +++ b/interface/src/SecondaryCamera.h @@ -17,6 +17,8 @@ #include #include #include +#include +#include class MainRenderTask { public: diff --git a/interface/src/SpeechRecognizer.cpp b/interface/src/SpeechRecognizer.cpp index f5d0cb9e24..4815d20a83 100644 --- a/interface/src/SpeechRecognizer.cpp +++ b/interface/src/SpeechRecognizer.cpp @@ -9,11 +9,12 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include "SpeechRecognizer.h" + #include #include #include "InterfaceLogging.h" -#include "SpeechRecognizer.h" #if defined(Q_OS_WIN) diff --git a/interface/src/SpeechRecognizer.h b/interface/src/SpeechRecognizer.h index d5f9031cfc..b22ab73837 100644 --- a/interface/src/SpeechRecognizer.h +++ b/interface/src/SpeechRecognizer.h @@ -24,6 +24,9 @@ /**jsdoc * @namespace SpeechRecognizer + * + * @hifi-interface + * @hifi-client-entity */ class SpeechRecognizer : public QObject, public Dependency { Q_OBJECT diff --git a/interface/src/SpeechRecognizer.mm b/interface/src/SpeechRecognizer.mm index 038bcce3e4..6b9da6f3e8 100644 --- a/interface/src/SpeechRecognizer.mm +++ b/interface/src/SpeechRecognizer.mm @@ -16,10 +16,10 @@ #import #import -#include - #include "SpeechRecognizer.h" +#include + @interface SpeechRecognizerDelegate : NSObject { SpeechRecognizer* _listener; } diff --git a/interface/src/UIUtil.cpp b/interface/src/UIUtil.cpp index 7b50975c92..a27bd6c5db 100644 --- a/interface/src/UIUtil.cpp +++ b/interface/src/UIUtil.cpp @@ -9,11 +9,11 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include "UIUtil.h" + #include #include -#include "UIUtil.h" - int UIUtil::getWindowTitleBarHeight(const QWidget* window) { QStyleOptionTitleBar options; options.titleBarState = 1; diff --git a/interface/src/audio/AudioScope.cpp b/interface/src/audio/AudioScope.cpp index 1a2e867d51..1750c00d37 100644 --- a/interface/src/audio/AudioScope.cpp +++ b/interface/src/audio/AudioScope.cpp @@ -9,6 +9,8 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include "AudioScope.h" + #include #include @@ -19,8 +21,6 @@ #include #include -#include "AudioScope.h" - static const unsigned int DEFAULT_FRAMES_PER_SCOPE = 5; static const unsigned int MULTIPLIER_SCOPE_HEIGHT = 20; static const unsigned int SCOPE_HEIGHT = 2 * 15 * MULTIPLIER_SCOPE_HEIGHT; diff --git a/interface/src/audio/AudioScope.h b/interface/src/audio/AudioScope.h index ff8bfda6dd..41cee8d17d 100644 --- a/interface/src/audio/AudioScope.h +++ b/interface/src/audio/AudioScope.h @@ -28,6 +28,10 @@ class AudioScope : public QObject, public Dependency { /**jsdoc * The AudioScope API helps control the Audio Scope features in Interface * @namespace AudioScope + * + * @hifi-interface + * @hifi-client-entity + * * @property {number} scopeInput Read-only. * @property {number} scopeOutputLeft Read-only. * @property {number} scopeOutputRight Read-only. diff --git a/interface/src/avatar/AvatarManager.cpp b/interface/src/avatar/AvatarManager.cpp index b71c060465..094b3bb67b 100644 --- a/interface/src/avatar/AvatarManager.cpp +++ b/interface/src/avatar/AvatarManager.cpp @@ -9,6 +9,8 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include "AvatarManager.h" + #include #include @@ -35,9 +37,9 @@ #include #include #include +#include #include "Application.h" -#include "AvatarManager.h" #include "InterfaceLogging.h" #include "Menu.h" #include "MyAvatar.h" @@ -155,9 +157,9 @@ void AvatarManager::updateOtherAvatars(float deltaTime) { AvatarSharedPointer _avatar; }; - ViewFrustum cameraView; - qApp->copyDisplayViewFrustum(cameraView); - PrioritySortUtil::PriorityQueue sortedAvatars(cameraView, + + const auto& views = qApp->getConicalViews(); + PrioritySortUtil::PriorityQueue sortedAvatars(views, AvatarData::_avatarSortCoefficientSize, AvatarData::_avatarSortCoefficientCenter, AvatarData::_avatarSortCoefficientAge); diff --git a/interface/src/avatar/AvatarManager.h b/interface/src/avatar/AvatarManager.h index d2655914d2..7f5aa00466 100644 --- a/interface/src/avatar/AvatarManager.h +++ b/interface/src/avatar/AvatarManager.h @@ -30,6 +30,9 @@ /**jsdoc * The AvatarManager API has properties and methods which manage Avatars within the same domain. * @namespace AvatarManager + * + * @hifi-interface + * @hifi-client-entity */ class AvatarManager : public AvatarHashMap { diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 249a765d92..15b220c63b 100755 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -121,6 +121,19 @@ MyAvatar::MyAvatar(QThread* thread) : _skeletonModel = std::make_shared(this, nullptr); connect(_skeletonModel.get(), &Model::setURLFinished, this, &Avatar::setModelURLFinished); + connect(_skeletonModel.get(), &Model::setURLFinished, this, [this](bool success) { + if (success) { + qApp->unloadAvatarScripts(); + _shouldLoadScripts = true; + } + }); + connect(_skeletonModel.get(), &Model::rigReady, this, [this]() { + if (_shouldLoadScripts) { + auto geometry = getSkeletonModel()->getFBXGeometry(); + qApp->loadAvatarScripts(geometry.scripts); + _shouldLoadScripts = false; + } + }); connect(_skeletonModel.get(), &Model::rigReady, this, &Avatar::rigReady); connect(_skeletonModel.get(), &Model::rigReset, this, &Avatar::rigReset); @@ -1473,6 +1486,15 @@ void MyAvatar::setSkeletonModelURL(const QUrl& skeletonModelURL) { std::shared_ptr skeletonConnection = std::make_shared(); *skeletonConnection = QObject::connect(_skeletonModel.get(), &SkeletonModel::skeletonLoaded, [this, skeletonModelChangeCount, skeletonConnection]() { if (skeletonModelChangeCount == _skeletonModelChangeCount) { + + if (_fullAvatarModelName.isEmpty()) { + // Store the FST file name into preferences + const auto& mapping = _skeletonModel->getGeometry()->getMapping(); + if (mapping.value("name").isValid()) { + _fullAvatarModelName = mapping.value("name").toString(); + } + } + initHeadBones(); _skeletonModel->setCauterizeBoneSet(_headBoneSet); _fstAnimGraphOverrideUrl = _skeletonModel->getGeometry()->getAnimGraphOverrideUrl(); @@ -1535,12 +1557,7 @@ void MyAvatar::useFullAvatarURL(const QUrl& fullAvatarURL, const QString& modelN if (_fullAvatarURLFromPreferences != fullAvatarURL) { _fullAvatarURLFromPreferences = fullAvatarURL; - if (modelName.isEmpty()) { - QVariantHash fullAvatarFST = FSTReader::downloadMapping(_fullAvatarURLFromPreferences.toString()); - _fullAvatarModelName = fullAvatarFST["name"].toString(); - } else { - _fullAvatarModelName = modelName; - } + _fullAvatarModelName = modelName; } const QString& urlString = fullAvatarURL.toString(); @@ -1548,8 +1565,8 @@ void MyAvatar::useFullAvatarURL(const QUrl& fullAvatarURL, const QString& modelN setSkeletonModelURL(fullAvatarURL); UserActivityLogger::getInstance().changedModel("skeleton", urlString); } + markIdentityDataChanged(); - } void MyAvatar::setAttachmentData(const QVector& attachmentData) { @@ -2037,12 +2054,14 @@ void MyAvatar::preDisplaySide(RenderArgs* renderArgs) { _attachmentData[i].jointName.compare("RightEye", Qt::CaseInsensitive) == 0 || _attachmentData[i].jointName.compare("HeadTop_End", Qt::CaseInsensitive) == 0 || _attachmentData[i].jointName.compare("Face", Qt::CaseInsensitive) == 0) { + uint8_t modelRenderTagBits = shouldDrawHead ? render::ItemKey::TAG_BITS_0 : render::ItemKey::TAG_BITS_NONE; + modelRenderTagBits |= render::ItemKey::TAG_BITS_1; + _attachmentModels[i]->setVisibleInScene(true, qApp->getMain3DScene(), + modelRenderTagBits, false); - _attachmentModels[i]->setVisibleInScene(shouldDrawHead, qApp->getMain3DScene(), - render::ItemKey::TAG_BITS_NONE, true); - - _attachmentModels[i]->setCanCastShadow(shouldDrawHead, qApp->getMain3DScene(), - render::ItemKey::TAG_BITS_NONE, true); + uint8_t castShadowRenderTagBits = render::ItemKey::TAG_BITS_0 | render::ItemKey::TAG_BITS_1; + _attachmentModels[i]->setCanCastShadow(true, qApp->getMain3DScene(), + castShadowRenderTagBits, false); } } } @@ -2839,6 +2858,11 @@ void MyAvatar::setWalkSpeed(float value) { _walkSpeed.set(value); } +QVector MyAvatar::getScriptUrls() { + QVector scripts = _skeletonModel->isLoaded() ? _skeletonModel->getFBXGeometry().scripts : QVector(); + return scripts; +} + glm::vec3 MyAvatar::getPositionForAudio() { glm::vec3 result; switch (_audioListenerMode) { diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index 74f7a3c89f..ac3d3cd2f4 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -985,6 +985,8 @@ public: void setWalkSpeed(float value); float getWalkSpeed() const; + QVector getScriptUrls(); + public slots: /**jsdoc @@ -1322,7 +1324,6 @@ signals: private slots: void leaveDomain(); - protected: virtual void beParentOfChild(SpatiallyNestablePointer newChild) const override; virtual void forgetChild(SpatiallyNestablePointer newChild) const override; @@ -1564,6 +1565,9 @@ private: // max unscaled forward movement speed ThreadSafeValueCache _walkSpeed { DEFAULT_AVATAR_MAX_WALKING_SPEED }; float _walkSpeedScalar { AVATAR_WALK_SPEED_SCALAR }; + + // load avatar scripts once when rig is ready + bool _shouldLoadScripts { false }; }; QScriptValue audioListenModeToScriptValue(QScriptEngine* engine, const AudioListenerMode& audioListenerMode); diff --git a/interface/src/commerce/Ledger.cpp b/interface/src/commerce/Ledger.cpp index fde8c49933..f791ea25bc 100644 --- a/interface/src/commerce/Ledger.cpp +++ b/interface/src/commerce/Ledger.cpp @@ -9,16 +9,19 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include "Ledger.h" + #include #include #include #include -#include "Wallet.h" -#include "Ledger.h" -#include "CommerceLogging.h" + #include #include +#include "Wallet.h" +#include "CommerceLogging.h" + // inventory answers {status: 'success', data: {assets: [{id: "guid", title: "name", preview: "url"}....]}} // balance answers {status: 'success', data: {balance: integer}} // buy and receive_at answer {status: 'success'} diff --git a/interface/src/commerce/QmlCommerce.cpp b/interface/src/commerce/QmlCommerce.cpp index 568556cb22..722f29ba2f 100644 --- a/interface/src/commerce/QmlCommerce.cpp +++ b/interface/src/commerce/QmlCommerce.cpp @@ -301,7 +301,7 @@ bool QmlCommerce::uninstallApp(const QString& itemHref) { // Read from the file to know what .js script to stop QFile appFile(_appsPath + "/" + appHref.fileName()); if (!appFile.open(QIODevice::ReadOnly)) { - qCDebug(commerce) << "Couldn't open local .app.json file for deletion."; + qCDebug(commerce) << "Couldn't open local .app.json file for deletion. Cannot continue with app uninstallation. App filename is:" << appHref.fileName(); return false; } QJsonDocument appFileJsonDocument = QJsonDocument::fromJson(appFile.readAll()); @@ -309,15 +309,13 @@ bool QmlCommerce::uninstallApp(const QString& itemHref) { QString scriptUrl = appFileJsonObject["scriptURL"].toString(); if (!DependencyManager::get()->stopScript(scriptUrl.trimmed(), false)) { - qCDebug(commerce) << "Couldn't stop script."; - return false; + qCWarning(commerce) << "Couldn't stop script during app uninstall. Continuing anyway. ScriptURL is:" << scriptUrl.trimmed(); } // Delete the .app.json from the filesystem // remove() closes the file first. if (!appFile.remove()) { - qCDebug(commerce) << "Couldn't delete local .app.json file."; - return false; + qCWarning(commerce) << "Couldn't delete local .app.json file during app uninstall. Continuing anyway. App filename is:" << appHref.fileName(); } emit appUninstalled(itemHref); diff --git a/interface/src/commerce/Wallet.cpp b/interface/src/commerce/Wallet.cpp index 35e6ca1c92..982adb4b5e 100644 --- a/interface/src/commerce/Wallet.cpp +++ b/interface/src/commerce/Wallet.cpp @@ -9,22 +9,7 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -#include "CommerceLogging.h" -#include "Ledger.h" #include "Wallet.h" -#include "Application.h" -#include "ui/SecurityImageProvider.h" -#include "scripting/HMDScriptingInterface.h" -#include - -#include -#include -#include - -#include -#include -#include -#include #include #include @@ -33,7 +18,6 @@ #include #include #include - // I know, right? But per https://www.openssl.org/docs/faq.html // this avoids OPENSSL_Uplink(00007FF847238000,08): no OPENSSL_Applink // at runtime. @@ -41,6 +25,22 @@ #include #endif +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "Application.h" +#include "CommerceLogging.h" +#include "Ledger.h" +#include "ui/SecurityImageProvider.h" +#include "scripting/HMDScriptingInterface.h" + static const char* KEY_FILE = "hifikey"; static const char* INSTRUCTIONS_FILE = "backup_instructions.html"; static const char* IMAGE_HEADER = "-----BEGIN SECURITY IMAGE-----\n"; diff --git a/interface/src/devices/DdeFaceTracker.h b/interface/src/devices/DdeFaceTracker.h index d4af0bbd37..4fe36b582e 100644 --- a/interface/src/devices/DdeFaceTracker.h +++ b/interface/src/devices/DdeFaceTracker.h @@ -29,6 +29,9 @@ /**jsdoc * The FaceTracker API helps manage facial tracking hardware. * @namespace FaceTracker + * + * @hifi-interface + * @hifi-client-entity */ class DdeFaceTracker : public FaceTracker, public Dependency { diff --git a/interface/src/java/io/highfidelity/interface/InterfaceActivity.java b/interface/src/java/io/highfidelity/interface/InterfaceActivity.java index c7cbdd3dff..ae10c320f8 100644 --- a/interface/src/java/io/highfidelity/interface/InterfaceActivity.java +++ b/interface/src/java/io/highfidelity/interface/InterfaceActivity.java @@ -15,7 +15,6 @@ import android.content.Intent; import android.net.Uri; import android.os.Bundle; import android.view.WindowManager; -import android.util.Log; import org.qtproject.qt5.android.bindings.QtActivity; public class InterfaceActivity extends QtActivity { diff --git a/interface/src/networking/CloseEventSender.cpp b/interface/src/networking/CloseEventSender.cpp index fe939afe05..16549d5510 100644 --- a/interface/src/networking/CloseEventSender.cpp +++ b/interface/src/networking/CloseEventSender.cpp @@ -9,6 +9,8 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include "CloseEventSender.h" + #include #include #include @@ -22,8 +24,6 @@ #include #include -#include "CloseEventSender.h" - QNetworkRequest createNetworkRequest() { QNetworkRequest request; diff --git a/interface/src/octree/OctreePacketProcessor.cpp b/interface/src/octree/OctreePacketProcessor.cpp index 0c2883a9a4..7d38e29710 100644 --- a/interface/src/octree/OctreePacketProcessor.cpp +++ b/interface/src/octree/OctreePacketProcessor.cpp @@ -9,11 +9,12 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include "OctreePacketProcessor.h" + #include #include "Application.h" #include "Menu.h" -#include "OctreePacketProcessor.h" #include "SceneScriptingInterface.h" OctreePacketProcessor::OctreePacketProcessor() { diff --git a/interface/src/raypick/PickScriptingInterface.h b/interface/src/raypick/PickScriptingInterface.h index f2cd9287a5..2568dd8457 100644 --- a/interface/src/raypick/PickScriptingInterface.h +++ b/interface/src/raypick/PickScriptingInterface.h @@ -18,6 +18,10 @@ * The Picks API lets you create and manage objects for repeatedly calculating intersections in different ways. * * @namespace Picks + * + * @hifi-interface + * @hifi-client-entity + * * @property PICK_NOTHING {number} A filter flag. Don't intersect with anything. * @property PICK_ENTITIES {number} A filter flag. Include entities when intersecting. * @property PICK_OVERLAYS {number} A filter flag. Include overlays when intersecting. diff --git a/interface/src/raypick/PointerScriptingInterface.h b/interface/src/raypick/PointerScriptingInterface.h index 1cc7b56503..e7acfd4037 100644 --- a/interface/src/raypick/PointerScriptingInterface.h +++ b/interface/src/raypick/PointerScriptingInterface.h @@ -19,6 +19,9 @@ * Pointers can also be configured to automatically generate PointerEvents. * * @namespace Pointers + * + * @hifi-interface + * @hifi-client-entity */ class PointerScriptingInterface : public QObject, public Dependency { diff --git a/interface/src/scripting/AccountServicesScriptingInterface.cpp b/interface/src/scripting/AccountServicesScriptingInterface.cpp index fc293098bb..3939fce91d 100644 --- a/interface/src/scripting/AccountServicesScriptingInterface.cpp +++ b/interface/src/scripting/AccountServicesScriptingInterface.cpp @@ -9,13 +9,13 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include "AccountServicesScriptingInterface.h" + #include "AccountManager.h" #include "Application.h" #include "DiscoverabilityManager.h" #include "ResourceCache.h" -#include "AccountServicesScriptingInterface.h" - AccountServicesScriptingInterface::AccountServicesScriptingInterface() { auto accountManager = DependencyManager::get(); connect(accountManager.data(), &AccountManager::usernameChanged, this, &AccountServicesScriptingInterface::onUsernameChanged); diff --git a/interface/src/scripting/AccountServicesScriptingInterface.h b/interface/src/scripting/AccountServicesScriptingInterface.h index d38a84d8fa..fb3c329def 100644 --- a/interface/src/scripting/AccountServicesScriptingInterface.h +++ b/interface/src/scripting/AccountServicesScriptingInterface.h @@ -18,6 +18,8 @@ #include #include #include + +#include #include class DownloadInfoResult { @@ -38,6 +40,9 @@ class AccountServicesScriptingInterface : public QObject { /**jsdoc * The AccountServices API contains helper functions related to user connectivity * + * @hifi-interface + * @hifi-client-entity + * * @namespace AccountServices * @property {string} username Read-only. * @property {boolean} loggedIn Read-only. diff --git a/interface/src/scripting/Audio.h b/interface/src/scripting/Audio.h index c77d1522b5..f0a4328c2f 100644 --- a/interface/src/scripting/Audio.h +++ b/interface/src/scripting/Audio.h @@ -27,8 +27,14 @@ class Audio : public AudioScriptingInterface, protected ReadWriteLockable { /**jsdoc * The Audio API features tools to help control audio contexts and settings. - * + * * @namespace Audio + * + * @hifi-interface + * @hifi-client-entity + * @hifi-server-entity + * @hifi-assignment-client + * * @property {boolean} muted * @property {boolean} noiseReduction * @property {number} inputVolume diff --git a/interface/src/scripting/AudioDevices.cpp b/interface/src/scripting/AudioDevices.cpp index a3c80bf1b6..f08a0bf382 100644 --- a/interface/src/scripting/AudioDevices.cpp +++ b/interface/src/scripting/AudioDevices.cpp @@ -9,18 +9,17 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include "AudioDevices.h" + #include #include #include #include -#include "AudioDevices.h" - #include "Application.h" #include "AudioClient.h" #include "Audio.h" - #include "UserActivityLogger.h" using namespace scripting; diff --git a/interface/src/scripting/ClipboardScriptingInterface.h b/interface/src/scripting/ClipboardScriptingInterface.h index cce300e831..32b8c64a7d 100644 --- a/interface/src/scripting/ClipboardScriptingInterface.h +++ b/interface/src/scripting/ClipboardScriptingInterface.h @@ -21,6 +21,9 @@ * The Clipboard API enables you to export and import entities to and from JSON files. * * @namespace Clipboard + * + * @hifi-interface + * @hifi-client-entity */ class ClipboardScriptingInterface : public QObject { Q_OBJECT diff --git a/interface/src/scripting/ControllerScriptingInterface.h b/interface/src/scripting/ControllerScriptingInterface.h index 4fceda3b04..e16383e234 100644 --- a/interface/src/scripting/ControllerScriptingInterface.h +++ b/interface/src/scripting/ControllerScriptingInterface.h @@ -200,7 +200,10 @@ class ScriptEngine; * * @namespace Controller * - * @property {Controller.Actions} Actions - Predefined actions on Interface and the user's avatar. These can be used as end + * @hifi-interface + * @hifi-client-entity + * + * @property {Controller.Actions} Actions - Predefined actions on Interface and the user's avatar. These can be used as end * points in a {@link RouteObject} mapping. A synonym for Controller.Hardware.Actions. * Read-only.
* Default mappings are provided from the Controller.Hardware.Keyboard and Controller.Standard to diff --git a/interface/src/scripting/GooglePolyScriptingInterface.cpp b/interface/src/scripting/GooglePolyScriptingInterface.cpp index 8ed5d59d07..fde2676986 100644 --- a/interface/src/scripting/GooglePolyScriptingInterface.cpp +++ b/interface/src/scripting/GooglePolyScriptingInterface.cpp @@ -9,6 +9,8 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include "GooglePolyScriptingInterface.h" + #include #include #include @@ -20,9 +22,7 @@ #include #include #include -#include -#include "GooglePolyScriptingInterface.h" #include "ScriptEngineLogging.h" const QString LIST_POLY_URL = "https://poly.googleapis.com/v1/assets?"; diff --git a/interface/src/scripting/GooglePolyScriptingInterface.h b/interface/src/scripting/GooglePolyScriptingInterface.h index 5c37b394fa..fb5aed9759 100644 --- a/interface/src/scripting/GooglePolyScriptingInterface.h +++ b/interface/src/scripting/GooglePolyScriptingInterface.h @@ -18,6 +18,9 @@ /**jsdoc * The GooglePoly API allows you to interact with Google Poly models direct from inside High Fidelity. * @namespace GooglePoly + * + * @hifi-interface + * @hifi-client-entity */ class GooglePolyScriptingInterface : public QObject, public Dependency { diff --git a/interface/src/scripting/HMDScriptingInterface.h b/interface/src/scripting/HMDScriptingInterface.h index 9b2482e73a..d2a272851f 100644 --- a/interface/src/scripting/HMDScriptingInterface.h +++ b/interface/src/scripting/HMDScriptingInterface.h @@ -28,7 +28,11 @@ class QScriptEngine; * The HMD API provides access to the HMD used in VR display mode. * * @namespace HMD - * @property {Vec3} position - The position of the HMD if currently in VR display mode, otherwise + * + * @hifi-interface + * @hifi-client-entity + * + * @property {Vec3} position - The position of the HMD if currently in VR display mode, otherwise * {@link Vec3(0)|Vec3.ZERO}. Read-only. * @property {Quat} orientation - The orientation of the HMD if currently in VR display mode, otherwise * {@link Quat(0)|Quat.IDENTITY}. Read-only. diff --git a/interface/src/scripting/LimitlessVoiceRecognitionScriptingInterface.cpp b/interface/src/scripting/LimitlessVoiceRecognitionScriptingInterface.cpp index ebb5ca9280..2692608106 100644 --- a/interface/src/scripting/LimitlessVoiceRecognitionScriptingInterface.cpp +++ b/interface/src/scripting/LimitlessVoiceRecognitionScriptingInterface.cpp @@ -9,13 +9,14 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include "LimitlessVoiceRecognitionScriptingInterface.h" + #include #include -#include -#include -#include "LimitlessVoiceRecognitionScriptingInterface.h" +#include "InterfaceLogging.h" +#include "ui/AvatarInputs.h" const float LimitlessVoiceRecognitionScriptingInterface::_audioLevelThreshold = 0.33f; const int LimitlessVoiceRecognitionScriptingInterface::_voiceTimeoutDuration = 2000; diff --git a/interface/src/scripting/MenuScriptingInterface.h b/interface/src/scripting/MenuScriptingInterface.h index 649c444eaf..81cf775de8 100644 --- a/interface/src/scripting/MenuScriptingInterface.h +++ b/interface/src/scripting/MenuScriptingInterface.h @@ -32,6 +32,9 @@ class MenuItemProperties; * If a menu item doesn't belong to a group it is always displayed. * * @namespace Menu + * + * @hifi-interface + * @hifi-client-entity */ /** diff --git a/interface/src/scripting/SelectionScriptingInterface.h b/interface/src/scripting/SelectionScriptingInterface.h index 71ff41248a..8b5c12e3dc 100644 --- a/interface/src/scripting/SelectionScriptingInterface.h +++ b/interface/src/scripting/SelectionScriptingInterface.h @@ -86,6 +86,9 @@ protected: * The Selection API provides a means of grouping together avatars, entities, and overlays in named lists. * @namespace Selection * + * @hifi-interface + * @hifi-client-entity + * * @example Outline an entity when it is grabbed by a controller. * // Create a box and copy the following text into the entity's "Script URL" field. * (function () { @@ -131,7 +134,7 @@ public: /**jsdoc * Get the names of all the selection lists. * @function Selection.getListNames - * @return {list[]} An array of names of all the selection lists. + * @returns {list[]} An array of names of all the selection lists. */ Q_INVOKABLE QStringList getListNames() const; @@ -181,7 +184,7 @@ public: * Get the list of avatars, entities, and overlays stored in a selection list. * @function Selection.getList * @param {string} listName - The name of the selection list. - * @return {Selection.SelectedItemsList} The content of a selection list. If the list name doesn't exist, the function + * @returns {Selection.SelectedItemsList} The content of a selection list. If the list name doesn't exist, the function * returns an empty object with no properties. */ Q_INVOKABLE QVariantMap getSelectedItemsList(const QString& listName) const; @@ -189,7 +192,7 @@ public: /**jsdoc * Get the names of the highlighted selection lists. * @function Selection.getHighlightedListNames - * @return {string[]} An array of names of the selection list currently highlight enabled. + * @returns {string[]} An array of names of the selection list currently highlight enabled. */ Q_INVOKABLE QStringList getHighlightedListNames() const; diff --git a/interface/src/scripting/SettingsScriptingInterface.h b/interface/src/scripting/SettingsScriptingInterface.h index 9e0271601b..32d868bb24 100644 --- a/interface/src/scripting/SettingsScriptingInterface.h +++ b/interface/src/scripting/SettingsScriptingInterface.h @@ -18,6 +18,9 @@ /**jsdoc * The Settings API provides a facility to store and retrieve values that persist between Interface runs. * @namespace Settings + * + * @hifi-interface + * @hifi-client-entity */ class SettingsScriptingInterface : public QObject { diff --git a/interface/src/scripting/WindowScriptingInterface.h b/interface/src/scripting/WindowScriptingInterface.h index 0b766d2097..348882e0f8 100644 --- a/interface/src/scripting/WindowScriptingInterface.h +++ b/interface/src/scripting/WindowScriptingInterface.h @@ -28,7 +28,11 @@ * physics. * * @namespace Window - * @property {number} innerWidth - The width of the drawable area of the Interface window (i.e., without borders or other + * + * @hifi-interface + * @hifi-client-entity + * + * @property {number} innerWidth - The width of the drawable area of the Interface window (i.e., without borders or other * chrome), in pixels. Read-only. * @property {number} innerHeight - The height of the drawable area of the Interface window (i.e., without borders or other * chrome), in pixels. Read-only. diff --git a/interface/src/ui/AvatarInputs.cpp b/interface/src/ui/AvatarInputs.cpp index 3053cb8855..0aa352de23 100644 --- a/interface/src/ui/AvatarInputs.cpp +++ b/interface/src/ui/AvatarInputs.cpp @@ -18,7 +18,7 @@ static AvatarInputs* INSTANCE{ nullptr }; -Setting::Handle showAudioToolsSetting { QStringList { "AvatarInputs", "showAudioTools" }, false }; +Setting::Handle showAudioToolsSetting { QStringList { "AvatarInputs", "showAudioTools" }, true }; AvatarInputs* AvatarInputs::getInstance() { if (!INSTANCE) { diff --git a/interface/src/ui/AvatarInputs.h b/interface/src/ui/AvatarInputs.h index a9d1509770..e67d35e59f 100644 --- a/interface/src/ui/AvatarInputs.h +++ b/interface/src/ui/AvatarInputs.h @@ -26,6 +26,10 @@ class AvatarInputs : public QObject { /**jsdoc * API to help manage your Avatar's input * @namespace AvatarInputs + * + * @hifi-interface + * @hifi-client-entity + * * @property {boolean} cameraEnabled Read-only. * @property {boolean} cameraMuted Read-only. * @property {boolean} isHMD Read-only. diff --git a/interface/src/ui/DomainConnectionDialog.cpp b/interface/src/ui/DomainConnectionDialog.cpp index c0471dc5e1..57a8d41257 100644 --- a/interface/src/ui/DomainConnectionDialog.cpp +++ b/interface/src/ui/DomainConnectionDialog.cpp @@ -9,6 +9,8 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include "DomainConnectionDialog.h" + #include #include #include @@ -17,8 +19,6 @@ #include #include -#include "DomainConnectionDialog.h" - DomainConnectionDialog::DomainConnectionDialog(QWidget* parent) : QDialog(parent, Qt::Window | Qt::WindowCloseButtonHint) { diff --git a/interface/src/ui/HMDToolsDialog.cpp b/interface/src/ui/HMDToolsDialog.cpp index 55c321723e..63794da60f 100644 --- a/interface/src/ui/HMDToolsDialog.cpp +++ b/interface/src/ui/HMDToolsDialog.cpp @@ -9,6 +9,8 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include "HMDToolsDialog.h" + #include #include #include @@ -25,8 +27,7 @@ #include "Application.h" #include "MainWindow.h" #include "Menu.h" -#include "ui/DialogsManager.h" -#include "ui/HMDToolsDialog.h" +#include "DialogsManager.h" static const int WIDTH = 350; static const int HEIGHT = 100; diff --git a/interface/src/ui/LodToolsDialog.cpp b/interface/src/ui/LodToolsDialog.cpp index 34b68a123e..71e5293f30 100644 --- a/interface/src/ui/LodToolsDialog.cpp +++ b/interface/src/ui/LodToolsDialog.cpp @@ -9,6 +9,8 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include "LodToolsDialog.h" + #include #include #include @@ -23,7 +25,6 @@ #include #include "Menu.h" -#include "ui/LodToolsDialog.h" LodToolsDialog::LodToolsDialog(QWidget* parent) : diff --git a/interface/src/ui/ModelsBrowser.cpp b/interface/src/ui/ModelsBrowser.cpp index 44089119c6..4709cc0a9c 100644 --- a/interface/src/ui/ModelsBrowser.cpp +++ b/interface/src/ui/ModelsBrowser.cpp @@ -9,6 +9,8 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include "ModelsBrowser.h" + #include #include #include @@ -27,8 +29,6 @@ #include #include -#include "ModelsBrowser.h" - const char* MODEL_TYPE_NAMES[] = { "entities", "heads", "skeletons", "skeletons", "attachments" }; static const QString S3_URL = "http://s3.amazonaws.com/hifi-public"; diff --git a/interface/src/ui/OctreeStatsDialog.cpp b/interface/src/ui/OctreeStatsDialog.cpp index ec5d800042..ea0f05f47f 100644 --- a/interface/src/ui/OctreeStatsDialog.cpp +++ b/interface/src/ui/OctreeStatsDialog.cpp @@ -9,20 +9,19 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include "OctreeStatsDialog.h" + #include #include #include - #include #include #include #include "Application.h" - #include "../octree/OctreePacketProcessor.h" -#include "ui/OctreeStatsDialog.h" OctreeStatsDialog::OctreeStatsDialog(QWidget* parent, NodeToOctreeSceneStats* model) : QDialog(parent, Qt::Window | Qt::WindowCloseButtonHint | Qt::WindowStaysOnTopHint), diff --git a/interface/src/ui/OctreeStatsDialog.h b/interface/src/ui/OctreeStatsDialog.h index 81bf5f251f..c05c8eadba 100644 --- a/interface/src/ui/OctreeStatsDialog.h +++ b/interface/src/ui/OctreeStatsDialog.h @@ -19,7 +19,6 @@ #include #define MAX_STATS 100 -#define DEFAULT_COLOR 0 class OctreeStatsDialog : public QDialog { Q_OBJECT @@ -42,7 +41,7 @@ protected: // Emits a 'closed' signal when this dialog is closed. void closeEvent(QCloseEvent*) override; - int AddStatItem(const char* caption, unsigned colorRGBA = DEFAULT_COLOR); + int AddStatItem(const char* caption, unsigned colorRGBA = 0); void RemoveStatItem(int item); void showAllOctreeServers(); diff --git a/interface/src/ui/OctreeStatsProvider.cpp b/interface/src/ui/OctreeStatsProvider.cpp index a393660c17..8917056be4 100644 --- a/interface/src/ui/OctreeStatsProvider.cpp +++ b/interface/src/ui/OctreeStatsProvider.cpp @@ -9,10 +9,10 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -#include "Application.h" +#include "OctreeStatsProvider.h" -#include "../octree/OctreePacketProcessor.h" -#include "ui/OctreeStatsProvider.h" +#include "Application.h" +#include "octree/OctreePacketProcessor.h" OctreeStatsProvider::OctreeStatsProvider(QObject* parent, NodeToOctreeSceneStats* model) : QObject(parent), diff --git a/interface/src/ui/OverlayConductor.cpp b/interface/src/ui/OverlayConductor.cpp index ed8fa53fe2..e7e3c91d13 100644 --- a/interface/src/ui/OverlayConductor.cpp +++ b/interface/src/ui/OverlayConductor.cpp @@ -8,13 +8,14 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include "OverlayConductor.h" + #include #include #include "Application.h" #include "avatar/AvatarManager.h" #include "InterfaceLogging.h" -#include "OverlayConductor.h" OverlayConductor::OverlayConductor() { diff --git a/interface/src/ui/OverlayConductor.h b/interface/src/ui/OverlayConductor.h index 1bdfe2ed79..cdd596a7bc 100644 --- a/interface/src/ui/OverlayConductor.h +++ b/interface/src/ui/OverlayConductor.h @@ -11,6 +11,8 @@ #ifndef hifi_OverlayConductor_h #define hifi_OverlayConductor_h +#include + class OverlayConductor { public: OverlayConductor(); @@ -34,12 +36,12 @@ private: bool _hmdMode { false }; // used by updateAvatarHasDriveInput - quint64 _desiredDrivingTimer { 0 }; + uint64_t _desiredDrivingTimer { 0 }; bool _desiredDriving { false }; bool _currentDriving { false }; // used by updateAvatarIsAtRest - quint64 _desiredAtRestTimer { 0 }; + uint64_t _desiredAtRestTimer { 0 }; bool _desiredAtRest { true }; bool _currentAtRest { true }; }; diff --git a/interface/src/ui/Snapshot.cpp b/interface/src/ui/Snapshot.cpp index 69103a40b5..39fef1d742 100644 --- a/interface/src/ui/Snapshot.cpp +++ b/interface/src/ui/Snapshot.cpp @@ -9,6 +9,8 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include "Snapshot.h" + #include #include #include @@ -31,7 +33,6 @@ #include #include "Application.h" -#include "Snapshot.h" #include "SnapshotUploader.h" // filename format: hifi-snap-by-%username%-on-%date%_%time%_@-%location%.jpg @@ -73,9 +74,9 @@ SnapshotMetaData* Snapshot::parseSnapshotData(QString snapshotPath) { return data; } -QString Snapshot::saveSnapshot(QImage image, const QString& filename) { +QString Snapshot::saveSnapshot(QImage image, const QString& filename, const QString& pathname) { - QFile* snapshotFile = savedFileForSnapshot(image, false, filename); + QFile* snapshotFile = savedFileForSnapshot(image, false, filename, pathname); // we don't need the snapshot file, so close it, grab its filename and delete it snapshotFile->close(); @@ -92,7 +93,7 @@ QTemporaryFile* Snapshot::saveTempSnapshot(QImage image) { return static_cast(savedFileForSnapshot(image, true)); } -QFile* Snapshot::savedFileForSnapshot(QImage & shot, bool isTemporary, const QString& userSelectedFilename) { +QFile* Snapshot::savedFileForSnapshot(QImage & shot, bool isTemporary, const QString& userSelectedFilename, const QString& userSelectedPathname) { // adding URL to snapshot QUrl currentURL = DependencyManager::get()->currentPublicAddress(); @@ -117,7 +118,13 @@ QFile* Snapshot::savedFileForSnapshot(QImage & shot, bool isTemporary, const QSt const int IMAGE_QUALITY = 100; if (!isTemporary) { - QString snapshotFullPath = snapshotsLocation.get(); + // If user has requested specific path then use it, else use the application value + QString snapshotFullPath; + if (!userSelectedPathname.isNull()) { + snapshotFullPath = userSelectedPathname; + } else { + snapshotFullPath = snapshotsLocation.get(); + } if (snapshotFullPath.isEmpty()) { snapshotFullPath = OffscreenUi::getExistingDirectory(nullptr, "Choose Snapshots Directory", QStandardPaths::writableLocation(QStandardPaths::DesktopLocation)); diff --git a/interface/src/ui/Snapshot.h b/interface/src/ui/Snapshot.h index 62d3ed3db8..606313f3c3 100644 --- a/interface/src/ui/Snapshot.h +++ b/interface/src/ui/Snapshot.h @@ -16,6 +16,7 @@ #include #include +#include #include #include @@ -37,7 +38,7 @@ class Snapshot : public QObject, public Dependency { Q_OBJECT SINGLETON_DEPENDENCY public: - static QString saveSnapshot(QImage image, const QString& filename); + static QString saveSnapshot(QImage image, const QString& filename, const QString& pathname = QString()); static QTemporaryFile* saveTempSnapshot(QImage image); static SnapshotMetaData* parseSnapshotData(QString snapshotPath); @@ -51,7 +52,10 @@ public slots: Q_INVOKABLE QString getSnapshotsLocation(); Q_INVOKABLE void setSnapshotsLocation(const QString& location); private: - static QFile* savedFileForSnapshot(QImage & image, bool isTemporary, const QString& userSelectedFilename = QString()); + static QFile* savedFileForSnapshot(QImage& image, + bool isTemporary, + const QString& userSelectedFilename = QString(), + const QString& userSelectedPathname = QString()); }; #endif // hifi_Snapshot_h diff --git a/interface/src/ui/SnapshotAnimated.cpp b/interface/src/ui/SnapshotAnimated.cpp index 3c00be8358..7866e742d9 100644 --- a/interface/src/ui/SnapshotAnimated.cpp +++ b/interface/src/ui/SnapshotAnimated.cpp @@ -9,6 +9,8 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include "SnapshotAnimated.h" + #include #include #include @@ -16,7 +18,6 @@ #include #include -#include "SnapshotAnimated.h" QTimer* SnapshotAnimated::snapshotAnimatedTimer = NULL; qint64 SnapshotAnimated::snapshotAnimatedTimestamp = 0; diff --git a/interface/src/ui/SnapshotUploader.cpp b/interface/src/ui/SnapshotUploader.cpp index 37505db629..67902c1a35 100644 --- a/interface/src/ui/SnapshotUploader.cpp +++ b/interface/src/ui/SnapshotUploader.cpp @@ -9,11 +9,14 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include "SnapshotUploader.h" + #include #include + #include + #include "scripting/WindowScriptingInterface.h" -#include "SnapshotUploader.h" SnapshotUploader::SnapshotUploader(QUrl inWorldLocation, QString pathname) : _inWorldLocation(inWorldLocation), diff --git a/interface/src/ui/StandAloneJSConsole.cpp b/interface/src/ui/StandAloneJSConsole.cpp index 72b6ecc547..49cf22a9eb 100644 --- a/interface/src/ui/StandAloneJSConsole.cpp +++ b/interface/src/ui/StandAloneJSConsole.cpp @@ -9,6 +9,8 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include "StandAloneJSConsole.h" + #include #include #include @@ -16,8 +18,6 @@ #include #include -#include "StandAloneJSConsole.h" - void StandAloneJSConsole::toggleConsole() { QMainWindow* mainWindow = qApp->getWindow(); if (!_jsConsole) { diff --git a/interface/src/ui/TestingDialog.cpp b/interface/src/ui/TestingDialog.cpp index 6f499f2a8d..6143f20ee6 100644 --- a/interface/src/ui/TestingDialog.cpp +++ b/interface/src/ui/TestingDialog.cpp @@ -9,10 +9,10 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -#include "ScriptEngines.h" +#include "TestingDialog.h" -#include "ui/TestingDialog.h" #include "Application.h" +#include "ScriptEngines.h" TestingDialog::TestingDialog(QWidget* parent) : QDialog(parent, Qt::Window | Qt::WindowCloseButtonHint | Qt::WindowStaysOnTopHint), diff --git a/interface/src/ui/overlays/ContextOverlayInterface.h b/interface/src/ui/overlays/ContextOverlayInterface.h index b80a3a70fb..808c3a4ee3 100644 --- a/interface/src/ui/overlays/ContextOverlayInterface.h +++ b/interface/src/ui/overlays/ContextOverlayInterface.h @@ -31,9 +31,6 @@ #include "EntityTree.h" #include "ContextOverlayLogging.h" -/**jsdoc -* @namespace ContextOverlay -*/ class ContextOverlayInterface : public QObject, public Dependency { Q_OBJECT diff --git a/interface/src/ui/overlays/ModelOverlay.cpp b/interface/src/ui/overlays/ModelOverlay.cpp index 7edc03490c..27e3bd0e2d 100644 --- a/interface/src/ui/overlays/ModelOverlay.cpp +++ b/interface/src/ui/overlays/ModelOverlay.cpp @@ -9,10 +9,11 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include "ModelOverlay.h" + #include #include -#include "ModelOverlay.h" #include #include "Application.h" diff --git a/interface/src/ui/overlays/Overlays.h b/interface/src/ui/overlays/Overlays.h index c2f6e3e693..cf1151b46a 100644 --- a/interface/src/ui/overlays/Overlays.h +++ b/interface/src/ui/overlays/Overlays.h @@ -76,6 +76,10 @@ void RayToOverlayIntersectionResultFromScriptValue(const QScriptValue& object, R * The Overlays API provides facilities to create and interact with overlays. Overlays are 2D and 3D objects visible only to * yourself and that aren't persisted to the domain. They are used for UI. * @namespace Overlays + * + * @hifi-interface + * @hifi-client-entity + * * @property {Uuid} keyboardFocusOverlay - Get or set the {@link Overlays.OverlayType|web3d} overlay that has keyboard focus. * If no overlay has keyboard focus, get returns null; set to null or {@link Uuid|Uuid.NULL} to * clear keyboard focus. diff --git a/libraries/animation/src/AnimClip.cpp b/libraries/animation/src/AnimClip.cpp index 2ead4558fe..7d358e85cc 100644 --- a/libraries/animation/src/AnimClip.cpp +++ b/libraries/animation/src/AnimClip.cpp @@ -8,8 +8,9 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -#include "GLMHelpers.h" #include "AnimClip.h" + +#include "GLMHelpers.h" #include "AnimationLogging.h" #include "AnimUtil.h" diff --git a/libraries/animation/src/AnimExpression.cpp b/libraries/animation/src/AnimExpression.cpp index 9777e9c6af..ddcbd01220 100644 --- a/libraries/animation/src/AnimExpression.cpp +++ b/libraries/animation/src/AnimExpression.cpp @@ -8,10 +8,12 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -#include +#include "AnimExpression.h" + #include -#include "AnimExpression.h" +#include + #include "AnimationLogging.h" AnimExpression::AnimExpression(const QString& str) : diff --git a/libraries/animation/src/AnimNode.cpp b/libraries/animation/src/AnimNode.cpp index 80093e43db..ba8e095109 100644 --- a/libraries/animation/src/AnimNode.cpp +++ b/libraries/animation/src/AnimNode.cpp @@ -8,9 +8,10 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -#include #include "AnimNode.h" +#include + AnimNode::Pointer AnimNode::getParent() { return _parent.lock(); } diff --git a/libraries/animation/src/AnimNodeLoader.cpp b/libraries/animation/src/AnimNodeLoader.cpp index 8173845205..4169ff61a7 100644 --- a/libraries/animation/src/AnimNodeLoader.cpp +++ b/libraries/animation/src/AnimNodeLoader.cpp @@ -8,6 +8,8 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include "AnimNodeLoader.h" + #include #include #include @@ -19,7 +21,6 @@ #include "AnimBlendLinearMove.h" #include "AnimationLogging.h" #include "AnimOverlay.h" -#include "AnimNodeLoader.h" #include "AnimStateMachine.h" #include "AnimManipulator.h" #include "AnimInverseKinematics.h" diff --git a/libraries/animation/src/AnimVariant.cpp b/libraries/animation/src/AnimVariant.cpp index 832ab8678c..483a7999c9 100644 --- a/libraries/animation/src/AnimVariant.cpp +++ b/libraries/animation/src/AnimVariant.cpp @@ -1,5 +1,5 @@ // -// AnimVariantMap.cpp +// AnimVariant.cpp // library/animation // // Created by Howard Stearns on 10/15/15. @@ -9,11 +9,12 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include "AnimVariant.h" // which has AnimVariant/AnimVariantMap + #include #include #include #include -#include "AnimVariant.h" // which has AnimVariant/AnimVariantMap const AnimVariant AnimVariant::False = AnimVariant(); diff --git a/libraries/animation/src/AnimationCache.h b/libraries/animation/src/AnimationCache.h index 03b37aef2f..d8f8a13cde 100644 --- a/libraries/animation/src/AnimationCache.h +++ b/libraries/animation/src/AnimationCache.h @@ -37,51 +37,49 @@ public: * API to manage animation cache resources. * @namespace AnimationCache * + * @hifi-interface + * @hifi-client-entity + * @hifi-assignment-client + * * @property {number} numTotal - Total number of total resources. Read-only. * @property {number} numCached - Total number of cached resource. Read-only. * @property {number} sizeTotal - Size in bytes of all resources. Read-only. * @property {number} sizeCached - Size in bytes of all cached resources. Read-only. */ - // Functions are copied over from ResourceCache (see ResourceCache.h for reason). + // Functions are copied over from ResourceCache (see ResourceCache.h for reason). - /**jsdoc + /**jsdoc * Get the list of all resource URLs. * @function AnimationCache.getResourceList - * @return {string[]} + * @returns {string[]} */ - /**jsdoc + /**jsdoc * @function AnimationCache.dirty * @returns {Signal} */ - /**jsdoc + /**jsdoc * @function AnimationCache.updateTotalSize * @param {number} deltaSize */ - /**jsdoc + /**jsdoc + * Prefetches a resource. * @function AnimationCache.prefetch - * @param {string} url - * @param {object} extra - * @returns {object} + * @param {string} url - URL of the resource to prefetch. + * @param {object} [extra=null] + * @returns {Resource} */ - /**jsdoc + /**jsdoc * Asynchronously loads a resource from the specified URL and returns it. * @function AnimationCache.getResource * @param {string} url - URL of the resource to load. * @param {string} [fallback=""] - Fallback URL if load of the desired URL fails. * @param {} [extra=null] - * @return {Resource} - */ - - /**jsdoc - * Prefetches a resource. - * @function AnimationCache.prefetch - * @param {string} url - URL of the resource to prefetch. - * @return {Resource} + * @returns {Resource} */ diff --git a/libraries/animation/src/AnimationObject.cpp b/libraries/animation/src/AnimationObject.cpp index 25a5743121..7f0f35b104 100644 --- a/libraries/animation/src/AnimationObject.cpp +++ b/libraries/animation/src/AnimationObject.cpp @@ -9,10 +9,11 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include "AnimationObject.h" + #include #include "AnimationCache.h" -#include "AnimationObject.h" QStringList AnimationObject::getJointNames() const { return qscriptvalue_cast(thisObject())->getJointNames(); diff --git a/libraries/audio-client/src/AudioClient.cpp b/libraries/audio-client/src/AudioClient.cpp index f643719a2e..a5f79290cd 100644 --- a/libraries/audio-client/src/AudioClient.cpp +++ b/libraries/audio-client/src/AudioClient.cpp @@ -9,6 +9,8 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include "AudioClient.h" + #include #include #include @@ -50,8 +52,6 @@ #include "AudioLogging.h" #include "AudioHelpers.h" -#include "AudioClient.h" - const int AudioClient::MIN_BUFFER_FRAMES = 1; const int AudioClient::MAX_BUFFER_FRAMES = 20; diff --git a/libraries/audio-client/src/AudioIOStats.cpp b/libraries/audio-client/src/AudioIOStats.cpp index 3bd3f4a47d..1717ad1f9c 100644 --- a/libraries/audio-client/src/AudioIOStats.cpp +++ b/libraries/audio-client/src/AudioIOStats.cpp @@ -9,6 +9,8 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include "AudioIOStats.h" + #include #include #include @@ -16,8 +18,6 @@ #include "AudioClient.h" -#include "AudioIOStats.h" - // This is called 1x/sec (see AudioClient) and we want it to log the last 5s static const int INPUT_READS_WINDOW = 5; static const int INPUT_UNPLAYED_WINDOW = 5; diff --git a/libraries/audio-client/src/AudioIOStats.h b/libraries/audio-client/src/AudioIOStats.h index 89db4942ec..45fcf365da 100644 --- a/libraries/audio-client/src/AudioIOStats.h +++ b/libraries/audio-client/src/AudioIOStats.h @@ -41,6 +41,10 @@ class AudioStreamStatsInterface : public QObject { /**jsdoc * @class AudioStats.AudioStreamStats + * + * @hifi-interface + * @hifi-client-entity + * * @property {number} lossRate Read-only. * @property {number} lossCount Read-only. * @property {number} lossRateWindow Read-only. @@ -185,6 +189,10 @@ class AudioStatsInterface : public QObject { /**jsdoc * Audio stats from the client. * @namespace AudioStats + * + * @hifi-interface + * @hifi-client-entity + * * @property {number} pingMs Read-only. * @property {number} inputReadMsMax Read-only. * @property {number} inputUnplayedMsMax Read-only. diff --git a/libraries/audio/src/AudioDynamics.h b/libraries/audio/src/AudioDynamics.h index a43833610a..8dbc7a75cc 100644 --- a/libraries/audio/src/AudioDynamics.h +++ b/libraries/audio/src/AudioDynamics.h @@ -10,9 +10,9 @@ // Inline functions to implement audio dynamics processing // -#include #include #include +#include #ifndef MAX #define MAX(a,b) ((a) > (b) ? (a) : (b)) @@ -21,7 +21,15 @@ #define MIN(a,b) ((a) < (b) ? (a) : (b)) #endif -#ifdef _MSC_VER +#if defined(_MSC_VER) +#define FORCEINLINE __forceinline +#elif defined(__GNUC__) +#define FORCEINLINE inline __attribute__((always_inline)) +#else +#define FORCEINLINE inline +#endif + +#if defined(_MSC_VER) #include #define MUL64(a,b) __emul((a), (b)) #else @@ -42,14 +50,14 @@ #include // convert float to int using round-to-nearest -static inline int32_t floatToInt(float x) { +FORCEINLINE static int32_t floatToInt(float x) { return _mm_cvt_ss2si(_mm_load_ss(&x)); } #else // convert float to int using round-to-nearest -static inline int32_t floatToInt(float x) { +FORCEINLINE static int32_t floatToInt(float x) { x += (x < 0.0f ? -0.5f : 0.5f); // round return (int32_t)x; } @@ -60,12 +68,12 @@ static const double FIXQ31 = 2147483648.0; // convert float to Q31 static const double DB_TO_LOG2 = 0.16609640474436813; // convert dB to log2 // convert dB to amplitude -static inline double dBToGain(double dB) { +FORCEINLINE static double dBToGain(double dB) { return pow(10.0, dB / 20.0); } // convert milliseconds to first-order time constant -static inline int32_t msToTc(double ms, double sampleRate) { +FORCEINLINE static int32_t msToTc(double ms, double sampleRate) { double tc = exp(-1000.0 / (ms * sampleRate)); return (int32_t)(FIXQ31 * tc); // Q31 } @@ -144,16 +152,16 @@ static const int IEEE754_EXPN_BIAS = 127; // x < 2^(31-LOG2_HEADROOM) returns 0x7fffffff // x > 2^LOG2_HEADROOM undefined // -static inline int32_t peaklog2(float* input) { +FORCEINLINE static int32_t peaklog2(float* input) { // float as integer bits - int32_t u = *(int32_t*)input; + uint32_t u = *(uint32_t*)input; // absolute value - int32_t peak = u & IEEE754_FABS_MASK; + uint32_t peak = u & IEEE754_FABS_MASK; // split into e and x - 1.0 - int32_t e = IEEE754_EXPN_BIAS - (peak >> IEEE754_MANT_BITS) + LOG2_HEADROOM; + int e = IEEE754_EXPN_BIAS - (peak >> IEEE754_MANT_BITS) + LOG2_HEADROOM; int32_t x = (peak << IEEE754_EXPN_BITS) & 0x7fffffff; // saturate @@ -180,19 +188,19 @@ static inline int32_t peaklog2(float* input) { // x < 2^(31-LOG2_HEADROOM) returns 0x7fffffff // x > 2^LOG2_HEADROOM undefined // -static inline int32_t peaklog2(float* input0, float* input1) { +FORCEINLINE static int32_t peaklog2(float* input0, float* input1) { // float as integer bits - int32_t u0 = *(int32_t*)input0; - int32_t u1 = *(int32_t*)input1; + uint32_t u0 = *(uint32_t*)input0; + uint32_t u1 = *(uint32_t*)input1; // max absolute value u0 &= IEEE754_FABS_MASK; u1 &= IEEE754_FABS_MASK; - int32_t peak = MAX(u0, u1); + uint32_t peak = MAX(u0, u1); // split into e and x - 1.0 - int32_t e = IEEE754_EXPN_BIAS - (peak >> IEEE754_MANT_BITS) + LOG2_HEADROOM; + int e = IEEE754_EXPN_BIAS - (peak >> IEEE754_MANT_BITS) + LOG2_HEADROOM; int32_t x = (peak << IEEE754_EXPN_BITS) & 0x7fffffff; // saturate @@ -219,23 +227,23 @@ static inline int32_t peaklog2(float* input0, float* input1) { // x < 2^(31-LOG2_HEADROOM) returns 0x7fffffff // x > 2^LOG2_HEADROOM undefined // -static inline int32_t peaklog2(float* input0, float* input1, float* input2, float* input3) { +FORCEINLINE static int32_t peaklog2(float* input0, float* input1, float* input2, float* input3) { // float as integer bits - int32_t u0 = *(int32_t*)input0; - int32_t u1 = *(int32_t*)input1; - int32_t u2 = *(int32_t*)input2; - int32_t u3 = *(int32_t*)input3; + uint32_t u0 = *(uint32_t*)input0; + uint32_t u1 = *(uint32_t*)input1; + uint32_t u2 = *(uint32_t*)input2; + uint32_t u3 = *(uint32_t*)input3; // max absolute value u0 &= IEEE754_FABS_MASK; u1 &= IEEE754_FABS_MASK; u2 &= IEEE754_FABS_MASK; u3 &= IEEE754_FABS_MASK; - int32_t peak = MAX(MAX(u0, u1), MAX(u2, u3)); + uint32_t peak = MAX(MAX(u0, u1), MAX(u2, u3)); // split into e and x - 1.0 - int32_t e = IEEE754_EXPN_BIAS - (peak >> IEEE754_MANT_BITS) + LOG2_HEADROOM; + int e = IEEE754_EXPN_BIAS - (peak >> IEEE754_MANT_BITS) + LOG2_HEADROOM; int32_t x = (peak << IEEE754_EXPN_BITS) & 0x7fffffff; // saturate @@ -261,7 +269,7 @@ static inline int32_t peaklog2(float* input0, float* input1, float* input2, floa // Count Leading Zeros // Emulates the CLZ (ARM) and LZCNT (x86) instruction // -static inline int CLZ(uint32_t u) { +FORCEINLINE static int CLZ(uint32_t u) { if (u == 0) { return 32; @@ -294,7 +302,7 @@ static inline int CLZ(uint32_t u) { // Compute -log2(x) for x=[0,1] in Q31, result in Q26 // x <= 0 returns 0x7fffffff // -static inline int32_t fixlog2(int32_t x) { +FORCEINLINE static int32_t fixlog2(int32_t x) { if (x <= 0) { return 0x7fffffff; @@ -303,8 +311,7 @@ static inline int32_t fixlog2(int32_t x) { // split into e and x - 1.0 uint32_t u = (uint32_t)x; int e = CLZ(u); - u <<= e; // normalize to [0x80000000, 0xffffffff] - x = u & 0x7fffffff; // x - 1.0 + x = (u << e) & 0x7fffffff; int k = x >> (31 - LOG2_TABBITS); @@ -324,7 +331,7 @@ static inline int32_t fixlog2(int32_t x) { // Compute exp2(-x) for x=[0,32] in Q26, result in Q31 // x <= 0 returns 0x7fffffff // -static inline int32_t fixexp2(int32_t x) { +FORCEINLINE static int32_t fixexp2(int32_t x) { if (x <= 0) { return 0x7fffffff; @@ -350,12 +357,12 @@ static inline int32_t fixexp2(int32_t x) { } // fast TPDF dither in [-1.0f, 1.0f] -static inline float dither() { +FORCEINLINE static float dither() { static uint32_t rz = 0; rz = rz * 69069 + 1; int32_t r0 = rz & 0xffff; int32_t r1 = rz >> 16; - return (int32_t)(r0 - r1) * (1/65536.0f); + return (r0 - r1) * (1/65536.0f); } // diff --git a/libraries/audio/src/AudioFOA.cpp b/libraries/audio/src/AudioFOA.cpp index 718b29d1b2..16c0721047 100644 --- a/libraries/audio/src/AudioFOA.cpp +++ b/libraries/audio/src/AudioFOA.cpp @@ -9,10 +9,11 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include "AudioFOA.h" + #include #include -#include "AudioFOA.h" #include "AudioFOAData.h" #if defined(_MSC_VER) diff --git a/libraries/audio/src/AudioGate.cpp b/libraries/audio/src/AudioGate.cpp index 5ef5ee25b5..e9cdf832d2 100644 --- a/libraries/audio/src/AudioGate.cpp +++ b/libraries/audio/src/AudioGate.cpp @@ -6,12 +6,13 @@ // Copyright 2017 High Fidelity, Inc. // +#include "AudioGate.h" + #include #include #include #include "AudioDynamics.h" -#include "AudioGate.h" // log2 domain headroom bits above 0dB (int32_t) static const int LOG2_HEADROOM_Q30 = 1; diff --git a/libraries/audio/src/AudioHRTF.cpp b/libraries/audio/src/AudioHRTF.cpp index aa951210a6..c0751c6a20 100644 --- a/libraries/audio/src/AudioHRTF.cpp +++ b/libraries/audio/src/AudioHRTF.cpp @@ -9,11 +9,12 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include "AudioHRTF.h" + #include #include #include -#include "AudioHRTF.h" #include "AudioHRTFData.h" #if defined(_MSC_VER) diff --git a/libraries/audio/src/AudioLimiter.cpp b/libraries/audio/src/AudioLimiter.cpp index e20a070bd6..79bb84f7b1 100644 --- a/libraries/audio/src/AudioLimiter.cpp +++ b/libraries/audio/src/AudioLimiter.cpp @@ -6,10 +6,11 @@ // Copyright 2016 High Fidelity, Inc. // +#include "AudioLimiter.h" + #include #include "AudioDynamics.h" -#include "AudioLimiter.h" // // Limiter (common) diff --git a/libraries/audio/src/AudioReverb.cpp b/libraries/audio/src/AudioReverb.cpp index c561231376..a7c6fefd39 100644 --- a/libraries/audio/src/AudioReverb.cpp +++ b/libraries/audio/src/AudioReverb.cpp @@ -6,25 +6,18 @@ // Copyright 2015 High Fidelity, Inc. // +#include "AudioReverb.h" + #include #include #include -#include "AudioReverb.h" - #ifdef _MSC_VER - #include -inline static int MULHI(int a, int b) { - long long c = __emul(a, b); - return ((int*)&c)[1]; -} - +#define MULHI(a,b) ((int32_t)(__emul(a, b) >> 32)) #else - -#define MULHI(a,b) (int)(((long long)(a) * (b)) >> 32) - -#endif // _MSC_VER +#define MULHI(a,b) ((int32_t)(((int64_t)(a) * (int64_t)(b)) >> 32)) +#endif #ifndef MAX #define MAX(a,b) (((a) > (b)) ? (a) : (b)) @@ -1954,7 +1947,7 @@ static inline float dither() { rz = rz * 69069 + 1; int32_t r0 = rz & 0xffff; int32_t r1 = rz >> 16; - return (int32_t)(r0 - r1) * (1/65536.0f); + return (r0 - r1) * (1/65536.0f); } // convert float to int16_t with dither, interleave stereo diff --git a/libraries/audio/src/AudioRingBuffer.cpp b/libraries/audio/src/AudioRingBuffer.cpp index 518fdd3c17..d8531ec216 100644 --- a/libraries/audio/src/AudioRingBuffer.cpp +++ b/libraries/audio/src/AudioRingBuffer.cpp @@ -9,6 +9,8 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include "AudioRingBuffer.h" + #include #include #include @@ -21,8 +23,6 @@ #include "AudioLogging.h" -#include "AudioRingBuffer.h" - static const QString RING_BUFFER_OVERFLOW_DEBUG { "AudioRingBuffer::writeData has overflown the buffer. Overwriting old data." }; static const QString DROPPED_SILENT_DEBUG { "AudioRingBuffer::addSilentSamples dropping silent samples to prevent overflow." }; diff --git a/libraries/audio/src/AudioSRC.cpp b/libraries/audio/src/AudioSRC.cpp index 80cb756d04..d488eccb6a 100644 --- a/libraries/audio/src/AudioSRC.cpp +++ b/libraries/audio/src/AudioSRC.cpp @@ -9,11 +9,12 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include "AudioSRC.h" + #include #include #include -#include "AudioSRC.h" #include "AudioSRCData.h" #ifndef MAX @@ -1200,7 +1201,7 @@ static inline float dither() { rz = rz * 69069 + 1; int32_t r0 = rz & 0xffff; int32_t r1 = rz >> 16; - return (int32_t)(r0 - r1) * (1/65536.0f); + return (r0 - r1) * (1/65536.0f); } // convert float to int16_t with dither, interleave stereo diff --git a/libraries/audio/src/InboundAudioStream.cpp b/libraries/audio/src/InboundAudioStream.cpp index d60c5ba4ab..7645a674e4 100644 --- a/libraries/audio/src/InboundAudioStream.cpp +++ b/libraries/audio/src/InboundAudioStream.cpp @@ -9,13 +9,14 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include "InboundAudioStream.h" + #include #include #include #include -#include "InboundAudioStream.h" #include "AudioLogging.h" const bool InboundAudioStream::DEFAULT_DYNAMIC_JITTER_BUFFER_ENABLED = true; diff --git a/libraries/audio/src/InjectedAudioStream.cpp b/libraries/audio/src/InjectedAudioStream.cpp index a06dba5389..2f357416f2 100644 --- a/libraries/audio/src/InjectedAudioStream.cpp +++ b/libraries/audio/src/InjectedAudioStream.cpp @@ -9,6 +9,8 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include "InjectedAudioStream.h" + #include #include @@ -17,7 +19,6 @@ #include #include -#include "InjectedAudioStream.h" #include "AudioHelpers.h" InjectedAudioStream::InjectedAudioStream(const QUuid& streamIdentifier, bool isStereo, int numStaticJitterFrames) : diff --git a/libraries/audio/src/Sound.cpp b/libraries/audio/src/Sound.cpp index 672c0b69b3..cd93f7b52e 100644 --- a/libraries/audio/src/Sound.cpp +++ b/libraries/audio/src/Sound.cpp @@ -9,6 +9,8 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include "Sound.h" + #include #include @@ -29,8 +31,6 @@ #include "AudioLogging.h" #include "AudioSRC.h" -#include "Sound.h" - QScriptValue soundSharedPointerToScriptValue(QScriptEngine* engine, const SharedSoundPointer& in) { return engine->newQObject(new SoundScriptingInterface(in), QScriptEngine::ScriptOwnership); } diff --git a/libraries/audio/src/SoundCache.h b/libraries/audio/src/SoundCache.h index d8c52635e0..347f324353 100644 --- a/libraries/audio/src/SoundCache.h +++ b/libraries/audio/src/SoundCache.h @@ -29,6 +29,11 @@ public: * API to manage sound cache resources. * @namespace SoundCache * + * @hifi-interface + * @hifi-client-entity + * @hifi-server-entity + * @hifi-assignment-client + * * @property {number} numTotal - Total number of total resources. Read-only. * @property {number} numCached - Total number of cached resource. Read-only. * @property {number} sizeTotal - Size in bytes of all resources. Read-only. @@ -36,12 +41,12 @@ public: */ - // Functions are copied over from ResourceCache (see ResourceCache.h for reason). + // Functions are copied over from ResourceCache (see ResourceCache.h for reason). /**jsdoc * Get the list of all resource URLs. * @function SoundCache.getResourceList - * @return {string[]} + * @returns {string[]} */ /**jsdoc @@ -55,10 +60,11 @@ public: */ /**jsdoc + * Prefetches a resource. * @function SoundCache.prefetch - * @param {string} url - * @param {object} extra - * @returns {object} + * @param {string} url - URL of the resource to prefetch. + * @param {object} [extra=null] + * @returns {Resource} */ /**jsdoc @@ -67,14 +73,7 @@ public: * @param {string} url - URL of the resource to load. * @param {string} [fallback=""] - Fallback URL if load of the desired URL fails. * @param {} [extra=null] - * @return {Resource} - */ - - /**jsdoc - * Prefetches a resource. - * @function SoundCache.prefetch - * @param {string} url - URL of the resource to prefetch. - * @return {Resource} + * @returns {Resource} */ diff --git a/libraries/avatars/src/AvatarData.h b/libraries/avatars/src/AvatarData.h index 888c3bfb24..bbcdd3693d 100644 --- a/libraries/avatars/src/AvatarData.h +++ b/libraries/avatars/src/AvatarData.h @@ -277,8 +277,6 @@ namespace AvatarDataPacket { const float MAX_AUDIO_LOUDNESS = 1000.0f; // close enough for mouth animation -const int AVATAR_IDENTITY_PACKET_SEND_INTERVAL_MSECS = 1000; - // See also static AvatarData::defaultFullAvatarModelUrl(). const QString DEFAULT_FULL_AVATAR_MODEL_NAME = QString("Default"); diff --git a/libraries/avatars/src/AvatarHashMap.cpp b/libraries/avatars/src/AvatarHashMap.cpp index b564ad6a3b..829c98a418 100644 --- a/libraries/avatars/src/AvatarHashMap.cpp +++ b/libraries/avatars/src/AvatarHashMap.cpp @@ -9,6 +9,8 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include "AvatarHashMap.h" + #include #include @@ -17,7 +19,6 @@ #include #include "AvatarLogging.h" -#include "AvatarHashMap.h" AvatarHashMap::AvatarHashMap() { auto nodeList = DependencyManager::get(); diff --git a/libraries/baking/src/Baker.cpp b/libraries/baking/src/Baker.cpp index 2adedf08a1..78a34ac5e8 100644 --- a/libraries/baking/src/Baker.cpp +++ b/libraries/baking/src/Baker.cpp @@ -9,10 +9,10 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -#include "ModelBakingLoggingCategory.h" - #include "Baker.h" +#include "ModelBakingLoggingCategory.h" + bool Baker::shouldStop() { if (_shouldAbort) { setWasAborted(true); diff --git a/libraries/baking/src/FBXBaker.cpp b/libraries/baking/src/FBXBaker.cpp index 0407c8508c..e3839bb95a 100644 --- a/libraries/baking/src/FBXBaker.cpp +++ b/libraries/baking/src/FBXBaker.cpp @@ -9,6 +9,8 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include "FBXBaker.h" + #include // need this include so we don't get an error looking for std::isnan #include @@ -31,8 +33,6 @@ #include "ModelBakingLoggingCategory.h" #include "TextureBaker.h" -#include "FBXBaker.h" - void FBXBaker::bake() { qDebug() << "FBXBaker" << _modelURL << "bake starting"; @@ -70,13 +70,6 @@ void FBXBaker::bakeSourceCopy() { return; } - // export the FBX with re-written texture references - exportScene(); - - if (shouldStop()) { - return; - } - // check if we're already done with textures (in case we had none to re-write) checkIfTexturesFinished(); } @@ -352,27 +345,3 @@ void FBXBaker::rewriteAndBakeSceneTextures() { } } } - -void FBXBaker::exportScene() { - // save the relative path to this FBX inside our passed output folder - auto fileName = _modelURL.fileName(); - auto baseName = fileName.left(fileName.lastIndexOf('.')); - auto bakedFilename = baseName + BAKED_FBX_EXTENSION; - - _bakedModelFilePath = _bakedOutputDir + "/" + bakedFilename; - - auto fbxData = FBXWriter::encodeFBX(_rootNode); - - QFile bakedFile(_bakedModelFilePath); - - if (!bakedFile.open(QIODevice::WriteOnly)) { - handleError("Error opening " + _bakedModelFilePath + " for writing"); - return; - } - - bakedFile.write(fbxData); - - _outputFiles.push_back(_bakedModelFilePath); - - qCDebug(model_baking) << "Exported" << _modelURL << "with re-written paths to" << _bakedModelFilePath; -} diff --git a/libraries/baking/src/FBXBaker.h b/libraries/baking/src/FBXBaker.h index 2888a60f73..58a7bffa18 100644 --- a/libraries/baking/src/FBXBaker.h +++ b/libraries/baking/src/FBXBaker.h @@ -26,8 +26,6 @@ #include -static const QString BAKED_FBX_EXTENSION = ".baked.fbx"; - using TextureBakerThreadGetter = std::function; class FBXBaker : public ModelBaker { @@ -51,11 +49,11 @@ private: void loadSourceFBX(); void importScene(); + void embedTextureMetaData(); void rewriteAndBakeSceneModels(); void rewriteAndBakeSceneTextures(); void exportScene(); - FBXNode _rootNode; FBXGeometry* _geometry; QHash _textureNameMatchCount; QHash _remappedTexturePaths; diff --git a/libraries/baking/src/JSBaker.cpp b/libraries/baking/src/JSBaker.cpp index 9932ad633e..b19336f4ca 100644 --- a/libraries/baking/src/JSBaker.cpp +++ b/libraries/baking/src/JSBaker.cpp @@ -9,9 +9,10 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include "JSBaker.h" + #include -#include "JSBaker.h" #include "Baker.h" const int ASCII_CHARACTERS_UPPER_LIMIT = 126; diff --git a/libraries/baking/src/JSBaker.h b/libraries/baking/src/JSBaker.h index b5889440cb..a7c3e62174 100644 --- a/libraries/baking/src/JSBaker.h +++ b/libraries/baking/src/JSBaker.h @@ -12,6 +12,8 @@ #ifndef hifi_JSBaker_h #define hifi_JSBaker_h +#include + #include "Baker.h" #include "JSBakingLoggingCategory.h" diff --git a/libraries/baking/src/ModelBaker.cpp b/libraries/baking/src/ModelBaker.cpp index 16a0c89c7f..ac332f4ceb 100644 --- a/libraries/baking/src/ModelBaker.cpp +++ b/libraries/baking/src/ModelBaker.cpp @@ -246,9 +246,9 @@ bool ModelBaker::compressMesh(FBXMesh& mesh, bool hasDeformers, FBXNode& dracoMe QString ModelBaker::compressTexture(QString modelTextureFileName, image::TextureUsage::Type textureType) { - QFileInfo modelTextureFileInfo{ modelTextureFileName.replace("\\", "/") }; + QFileInfo modelTextureFileInfo { modelTextureFileName.replace("\\", "/") }; - if (modelTextureFileInfo.suffix() == BAKED_TEXTURE_EXT.mid(1)) { + if (modelTextureFileInfo.suffix().toLower() == BAKED_TEXTURE_KTX_EXT.mid(1)) { // re-baking a model that already references baked textures // this is an error - return from here handleError("Cannot re-bake a file that already references compressed textures"); @@ -273,31 +273,31 @@ QString ModelBaker::compressTexture(QString modelTextureFileName, image::Texture } auto urlToTexture = getTextureURL(modelTextureFileInfo, modelTextureFileName, !textureContent.isNull()); - QString bakedTextureFileName; + QString baseTextureFileName; if (_remappedTexturePaths.contains(urlToTexture)) { - bakedTextureFileName = _remappedTexturePaths[urlToTexture]; + baseTextureFileName = _remappedTexturePaths[urlToTexture]; } else { // construct the new baked texture file name and file path // ensuring that the baked texture will have a unique name // even if there was another texture with the same name at a different path - bakedTextureFileName = createBakedTextureFileName(modelTextureFileInfo); - _remappedTexturePaths[urlToTexture] = bakedTextureFileName; + baseTextureFileName = createBaseTextureFileName(modelTextureFileInfo); + _remappedTexturePaths[urlToTexture] = baseTextureFileName; } qCDebug(model_baking).noquote() << "Re-mapping" << modelTextureFileName - << "to" << bakedTextureFileName; + << "to" << baseTextureFileName; - QString bakedTextureFilePath{ - _bakedOutputDir + "/" + bakedTextureFileName + QString bakedTextureFilePath { + _bakedOutputDir + "/" + baseTextureFileName + BAKED_META_TEXTURE_SUFFIX }; - textureChild = bakedTextureFileName; + textureChild = baseTextureFileName + BAKED_META_TEXTURE_SUFFIX; if (!_bakingTextures.contains(urlToTexture)) { _outputFiles.push_back(bakedTextureFilePath); // bake this texture asynchronously - bakeTexture(urlToTexture, textureType, _bakedOutputDir, bakedTextureFileName, textureContent); + bakeTexture(urlToTexture, textureType, _bakedOutputDir, baseTextureFileName, textureContent); } } @@ -309,7 +309,7 @@ void ModelBaker::bakeTexture(const QUrl& textureURL, image::TextureUsage::Type t // start a bake for this texture and add it to our list to keep track of QSharedPointer bakingTexture{ - new TextureBaker(textureURL, textureType, outputDir, bakedFilename, textureContent), + new TextureBaker(textureURL, textureType, outputDir, "../", bakedFilename, textureContent), &TextureBaker::deleteLater }; @@ -484,30 +484,30 @@ void ModelBaker::checkIfTexturesFinished() { } else { qCDebug(model_baking) << "Finished baking, emitting finished" << _modelURL; + texturesFinished(); + setIsFinished(true); } } } -QString ModelBaker::createBakedTextureFileName(const QFileInfo& textureFileInfo) { +QString ModelBaker::createBaseTextureFileName(const QFileInfo& textureFileInfo) { // first make sure we have a unique base name for this texture // in case another texture referenced by this model has the same base name auto& nameMatches = _textureNameMatchCount[textureFileInfo.baseName()]; - QString bakedTextureFileName{ textureFileInfo.completeBaseName() }; + QString baseTextureFileName{ textureFileInfo.completeBaseName() }; if (nameMatches > 0) { // there are already nameMatches texture with this name // append - and that number to our baked texture file name so that it is unique - bakedTextureFileName += "-" + QString::number(nameMatches); + baseTextureFileName += "-" + QString::number(nameMatches); } - bakedTextureFileName += BAKED_TEXTURE_EXT; - // increment the number of name matches ++nameMatches; - return bakedTextureFileName; + return baseTextureFileName; } void ModelBaker::setWasAborted(bool wasAborted) { @@ -519,3 +519,91 @@ void ModelBaker::setWasAborted(bool wasAborted) { } } } + +void ModelBaker::texturesFinished() { + embedTextureMetaData(); + exportScene(); +} + +void ModelBaker::embedTextureMetaData() { + std::vector embeddedTextureNodes; + + for (FBXNode& rootChild : _rootNode.children) { + if (rootChild.name == "Objects") { + qlonglong maxId = 0; + for (auto &child : rootChild.children) { + if (child.properties.length() == 3) { + maxId = std::max(maxId, child.properties[0].toLongLong()); + } + } + + for (auto& object : rootChild.children) { + if (object.name == "Texture") { + QVariant relativeFilename; + for (auto& child : object.children) { + if (child.name == "RelativeFilename") { + relativeFilename = child.properties[0]; + break; + } + } + + if (relativeFilename.isNull() + || !relativeFilename.toString().endsWith(BAKED_META_TEXTURE_SUFFIX)) { + continue; + } + if (object.properties.length() < 2) { + qWarning() << "Found texture with unexpected number of properties: " << object.name; + continue; + } + + FBXNode videoNode; + videoNode.name = "Video"; + videoNode.properties.append(++maxId); + videoNode.properties.append(object.properties[1]); + videoNode.properties.append("Clip"); + + QString bakedTextureFilePath { + _bakedOutputDir + "/" + relativeFilename.toString() + }; + + QFile textureFile { bakedTextureFilePath }; + if (!textureFile.open(QIODevice::ReadOnly)) { + qWarning() << "Failed to open: " << bakedTextureFilePath; + continue; + } + + videoNode.children.append({ "RelativeFilename", { relativeFilename }, { } }); + videoNode.children.append({ "Content", { textureFile.readAll() }, { } }); + + rootChild.children.append(videoNode); + + textureFile.close(); + } + } + } + } +} + +void ModelBaker::exportScene() { + // save the relative path to this FBX inside our passed output folder + auto fileName = _modelURL.fileName(); + auto baseName = fileName.left(fileName.lastIndexOf('.')); + auto bakedFilename = baseName + BAKED_FBX_EXTENSION; + + _bakedModelFilePath = _bakedOutputDir + "/" + bakedFilename; + + auto fbxData = FBXWriter::encodeFBX(_rootNode); + + QFile bakedFile(_bakedModelFilePath); + + if (!bakedFile.open(QIODevice::WriteOnly)) { + handleError("Error opening " + _bakedModelFilePath + " for writing"); + return; + } + + bakedFile.write(fbxData); + + _outputFiles.push_back(_bakedModelFilePath); + + qCDebug(model_baking) << "Exported" << _modelURL << "with re-written paths to" << _bakedModelFilePath; +} diff --git a/libraries/baking/src/ModelBaker.h b/libraries/baking/src/ModelBaker.h index 6fd529af92..1fd77ab761 100644 --- a/libraries/baking/src/ModelBaker.h +++ b/libraries/baking/src/ModelBaker.h @@ -29,6 +29,8 @@ using TextureBakerThreadGetter = std::function; using GetMaterialIDCallback = std::function ; +static const QString BAKED_FBX_EXTENSION = ".baked.fbx"; + class ModelBaker : public Baker { Q_OBJECT @@ -49,7 +51,11 @@ public slots: protected: void checkIfTexturesFinished(); + void texturesFinished(); + void embedTextureMetaData(); + void exportScene(); + FBXNode _rootNode; QHash _textureContentMap; QUrl _modelURL; QString _bakedOutputDir; @@ -63,7 +69,7 @@ private slots: void handleAbortedTexture(); private: - QString createBakedTextureFileName(const QFileInfo & textureFileInfo); + QString createBaseTextureFileName(const QFileInfo & textureFileInfo); QUrl getTextureURL(const QFileInfo& textureFileInfo, QString relativeFileName, bool isEmbedded = false); void bakeTexture(const QUrl & textureURL, image::TextureUsage::Type textureType, const QDir & outputDir, const QString & bakedFilename, const QByteArray & textureContent); diff --git a/libraries/baking/src/OBJBaker.cpp b/libraries/baking/src/OBJBaker.cpp index 85771ff2e3..cf62bc4fa8 100644 --- a/libraries/baking/src/OBJBaker.cpp +++ b/libraries/baking/src/OBJBaker.cpp @@ -9,10 +9,11 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include "OBJBaker.h" + #include #include -#include "OBJBaker.h" #include "OBJReader.h" #include "FBXWriter.h" @@ -147,31 +148,7 @@ void OBJBaker::bakeOBJ() { auto geometry = reader.readOBJ(objData, QVariantHash(), combineParts, _modelURL); // Write OBJ Data as FBX tree nodes - FBXNode rootNode; - createFBXNodeTree(rootNode, *geometry); - - // Serialize the resultant FBX tree - auto encodedFBX = FBXWriter::encodeFBX(rootNode); - - // Export as baked FBX - auto fileName = _modelURL.fileName(); - auto baseName = fileName.left(fileName.lastIndexOf('.')); - auto bakedFilename = baseName + ".baked.fbx"; - - _bakedModelFilePath = _bakedOutputDir + "/" + bakedFilename; - - QFile bakedFile; - bakedFile.setFileName(_bakedModelFilePath); - if (!bakedFile.open(QIODevice::WriteOnly)) { - handleError("Error opening " + _bakedModelFilePath + " for writing"); - return; - } - - bakedFile.write(encodedFBX); - - // Export successful - _outputFiles.push_back(_bakedModelFilePath); - qCDebug(model_baking) << "Exported" << _modelURL << "to" << _bakedModelFilePath; + createFBXNodeTree(_rootNode, *geometry); checkIfTexturesFinished(); } @@ -203,15 +180,17 @@ void OBJBaker::createFBXNodeTree(FBXNode& rootNode, FBXGeometry& geometry) { globalSettingsNode.children = { properties70Node }; // Generating Object node - _objectNode.name = OBJECTS_NODE_NAME; + FBXNode objectNode; + objectNode.name = OBJECTS_NODE_NAME; // Generating Object node's child - Geometry node FBXNode geometryNode; geometryNode.name = GEOMETRY_NODE_NAME; + NodeID geometryID; { - _geometryID = nextNodeID(); + geometryID = nextNodeID(); geometryNode.properties = { - _geometryID, + geometryID, GEOMETRY_NODE_NAME, MESH }; @@ -226,12 +205,13 @@ void OBJBaker::createFBXNodeTree(FBXNode& rootNode, FBXGeometry& geometry) { // Generating Object node's child - Model node FBXNode modelNode; modelNode.name = MODEL_NODE_NAME; + NodeID modelID; { - _modelID = nextNodeID(); - modelNode.properties = { _modelID, MODEL_NODE_NAME, MESH }; + modelID = nextNodeID(); + modelNode.properties = { modelID, MODEL_NODE_NAME, MESH }; } - _objectNode.children = { geometryNode, modelNode }; + objectNode.children = { geometryNode, modelNode }; // Generating Objects node's child - Material node auto& meshParts = geometry.meshes[0].parts; @@ -247,7 +227,7 @@ void OBJBaker::createFBXNodeTree(FBXNode& rootNode, FBXGeometry& geometry) { setMaterialNodeProperties(materialNode, meshPart.materialID, geometry); } - _objectNode.children.append(materialNode); + objectNode.children.append(materialNode); } // Generating Texture Node @@ -257,13 +237,13 @@ void OBJBaker::createFBXNodeTree(FBXNode& rootNode, FBXGeometry& geometry) { QString material = meshParts[i].materialID; FBXMaterial currentMaterial = geometry.materials[material]; if (!currentMaterial.albedoTexture.filename.isEmpty() || !currentMaterial.specularTexture.filename.isEmpty()) { - _textureID = nextNodeID(); - _mapTextureMaterial.emplace_back(_textureID, i); + auto textureID = nextNodeID(); + _mapTextureMaterial.emplace_back(textureID, i); FBXNode textureNode; { textureNode.name = TEXTURE_NODE_NAME; - textureNode.properties = { _textureID }; + textureNode.properties = { textureID, "texture" + QString::number(textureID) }; } // Texture node child - TextureName node @@ -295,7 +275,7 @@ void OBJBaker::createFBXNodeTree(FBXNode& rootNode, FBXGeometry& geometry) { textureNode.children = { textureNameNode, relativeFilenameNode }; - _objectNode.children.append(textureNode); + objectNode.children.append(textureNode); } } @@ -306,14 +286,14 @@ void OBJBaker::createFBXNodeTree(FBXNode& rootNode, FBXGeometry& geometry) { // connect Geometry to Model FBXNode cNode; cNode.name = C_NODE_NAME; - cNode.properties = { CONNECTIONS_NODE_PROPERTY, _geometryID, _modelID }; + cNode.properties = { CONNECTIONS_NODE_PROPERTY, geometryID, modelID }; connectionsNode.children = { cNode }; // connect all materials to model for (auto& materialID : _materialIDs) { FBXNode cNode; cNode.name = C_NODE_NAME; - cNode.properties = { CONNECTIONS_NODE_PROPERTY, materialID, _modelID }; + cNode.properties = { CONNECTIONS_NODE_PROPERTY, materialID, modelID }; connectionsNode.children.append(cNode); } @@ -341,7 +321,7 @@ void OBJBaker::createFBXNodeTree(FBXNode& rootNode, FBXGeometry& geometry) { } // Make all generated nodes children of rootNode - rootNode.children = { globalSettingsNode, _objectNode, connectionsNode }; + rootNode.children = { globalSettingsNode, objectNode, connectionsNode }; } // Set properties for material nodes diff --git a/libraries/baking/src/OBJBaker.h b/libraries/baking/src/OBJBaker.h index e888c7b1d8..8e49692d35 100644 --- a/libraries/baking/src/OBJBaker.h +++ b/libraries/baking/src/OBJBaker.h @@ -43,12 +43,9 @@ private: void setMaterialNodeProperties(FBXNode& materialNode, QString material, FBXGeometry& geometry); NodeID nextNodeID() { return _nodeID++; } + NodeID _nodeID { 0 }; - NodeID _geometryID; - NodeID _modelID; std::vector _materialIDs; - NodeID _textureID; std::vector> _mapTextureMaterial; - FBXNode _objectNode; }; #endif // hifi_OBJBaker_h diff --git a/libraries/baking/src/TextureBaker.cpp b/libraries/baking/src/TextureBaker.cpp index b6edd07965..b6957a2712 100644 --- a/libraries/baking/src/TextureBaker.cpp +++ b/libraries/baking/src/TextureBaker.cpp @@ -9,6 +9,8 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include "TextureBaker.h" + #include #include #include @@ -18,26 +20,28 @@ #include #include #include +#include #include "ModelBakingLoggingCategory.h" -#include "TextureBaker.h" - -const QString BAKED_TEXTURE_EXT = ".ktx"; +const QString BAKED_TEXTURE_KTX_EXT = ".ktx"; +const QString BAKED_TEXTURE_BCN_SUFFIX = "_bcn.ktx"; +const QString BAKED_META_TEXTURE_SUFFIX = ".texmeta.json"; TextureBaker::TextureBaker(const QUrl& textureURL, image::TextureUsage::Type textureType, - const QDir& outputDirectory, const QString& bakedFilename, - const QByteArray& textureContent) : + const QDir& outputDirectory, const QString& metaTexturePathPrefix, + const QString& baseFilename, const QByteArray& textureContent) : _textureURL(textureURL), _originalTexture(textureContent), _textureType(textureType), + _baseFilename(baseFilename), _outputDirectory(outputDirectory), - _bakedTextureFileName(bakedFilename) + _metaTexturePathPrefix(metaTexturePathPrefix) { - if (bakedFilename.isEmpty()) { + if (baseFilename.isEmpty()) { // figure out the baked texture filename auto originalFilename = textureURL.fileName(); - _bakedTextureFileName = originalFilename.left(originalFilename.lastIndexOf('.')) + BAKED_TEXTURE_EXT; + _baseFilename = originalFilename.left(originalFilename.lastIndexOf('.')); } } @@ -118,6 +122,19 @@ void TextureBaker::processTexture() { auto hashData = QCryptographicHash::hash(_originalTexture, QCryptographicHash::Md5); std::string hash = hashData.toHex().toStdString(); + TextureMeta meta; + + { + auto filePath = _outputDirectory.absoluteFilePath(_textureURL.fileName()); + QFile file { filePath }; + if (!file.open(QIODevice::WriteOnly) || file.write(_originalTexture) == -1) { + handleError("Could not write original texture for " + _textureURL.toString()); + return; + } + _outputFiles.push_back(filePath); + meta.original = _metaTexturePathPrefix +_textureURL.fileName(); + } + // IMPORTANT: _originalTexture is empty past this point auto processedTexture = image::processImage(std::move(_originalTexture), _textureURL.toString().toStdString(), ABSOLUTE_MAX_TEXTURE_NUM_PIXELS, _textureType, _abortProcessing); @@ -140,17 +157,38 @@ void TextureBaker::processTexture() { return; } - const char* data = reinterpret_cast(memKTX->_storage->data()); - const size_t length = memKTX->_storage->size(); + const char* name = khronos::gl::texture::toString(memKTX->_header.getGLInternaFormat()); + if (name == nullptr) { + handleError("Could not determine internal format for compressed KTX: " + _textureURL.toString()); + return; + } // attempt to write the baked texture to the destination file path - auto filePath = _outputDirectory.absoluteFilePath(_bakedTextureFileName); - QFile bakedTextureFile { filePath }; + { + const char* data = reinterpret_cast(memKTX->_storage->data()); + const size_t length = memKTX->_storage->size(); - if (!bakedTextureFile.open(QIODevice::WriteOnly) || bakedTextureFile.write(data, length) == -1) { - handleError("Could not write baked texture for " + _textureURL.toString()); - } else { + auto fileName = _baseFilename + BAKED_TEXTURE_BCN_SUFFIX; + auto filePath = _outputDirectory.absoluteFilePath(fileName); + QFile bakedTextureFile { filePath }; + if (!bakedTextureFile.open(QIODevice::WriteOnly) || bakedTextureFile.write(data, length) == -1) { + handleError("Could not write baked texture for " + _textureURL.toString()); + return; + } _outputFiles.push_back(filePath); + meta.availableTextureTypes[memKTX->_header.getGLInternaFormat()] = _metaTexturePathPrefix + fileName; + } + + + { + auto data = meta.serialize(); + _metaTextureFileName = _outputDirectory.absoluteFilePath(_baseFilename + BAKED_META_TEXTURE_SUFFIX); + QFile file { _metaTextureFileName }; + if (!file.open(QIODevice::WriteOnly) || file.write(data) == -1) { + handleError("Could not write meta texture for " + _textureURL.toString()); + } else { + _outputFiles.push_back(_metaTextureFileName); + } } qCDebug(model_baking) << "Baked texture" << _textureURL; diff --git a/libraries/baking/src/TextureBaker.h b/libraries/baking/src/TextureBaker.h index 90ecfe52f7..54839c001a 100644 --- a/libraries/baking/src/TextureBaker.h +++ b/libraries/baking/src/TextureBaker.h @@ -15,28 +15,29 @@ #include #include #include +#include #include #include #include "Baker.h" -extern const QString BAKED_TEXTURE_EXT; +extern const QString BAKED_TEXTURE_KTX_EXT; +extern const QString BAKED_META_TEXTURE_SUFFIX; class TextureBaker : public Baker { Q_OBJECT public: TextureBaker(const QUrl& textureURL, image::TextureUsage::Type textureType, - const QDir& outputDirectory, const QString& bakedFilename = QString(), - const QByteArray& textureContent = QByteArray()); + const QDir& outputDirectory, const QString& metaTexturePathPrefix = "", + const QString& baseFilename = QString(), const QByteArray& textureContent = QByteArray()); const QByteArray& getOriginalTexture() const { return _originalTexture; } QUrl getTextureURL() const { return _textureURL; } - QString getDestinationFilePath() const { return _outputDirectory.absoluteFilePath(_bakedTextureFileName); } - QString getBakedTextureFileName() const { return _bakedTextureFileName; } + QString getMetaTextureFileName() const { return _metaTextureFileName; } virtual void setWasAborted(bool wasAborted) override; @@ -58,8 +59,10 @@ private: QByteArray _originalTexture; image::TextureUsage::Type _textureType; + QString _baseFilename; QDir _outputDirectory; - QString _bakedTextureFileName; + QString _metaTextureFileName; + QString _metaTexturePathPrefix; std::atomic _abortProcessing { false }; }; diff --git a/libraries/controllers/src/controllers/DeviceProxy.cpp b/libraries/controllers/src/controllers/DeviceProxy.cpp deleted file mode 100644 index f03354c52d..0000000000 --- a/libraries/controllers/src/controllers/DeviceProxy.cpp +++ /dev/null @@ -1,17 +0,0 @@ -// -// Created by Bradley Austin Davis on 2015/10/18 -// (based on UserInputMapper inner class created by Sam Gateau on 4/27/15) -// Copyright 2015 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -// NOTE: we don't need to include this header unless/until we add additional symbols. -// By removing this header we prevent these warnings on windows: -// -// warning LNK4221: This object file does not define any previously undefined public symbols, -// so it will not be used by any link operation that consumes this library -// -//#include "DeviceProxy.h" - diff --git a/libraries/controllers/src/controllers/Pose.cpp b/libraries/controllers/src/controllers/Pose.cpp index 6f0296c09d..967838ef84 100644 --- a/libraries/controllers/src/controllers/Pose.cpp +++ b/libraries/controllers/src/controllers/Pose.cpp @@ -6,13 +6,13 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include "Pose.h" + #include #include #include -#include "Pose.h" - namespace controller { Pose::Pose(const vec3& translation, const quat& rotation, diff --git a/libraries/controllers/src/controllers/impl/Mapping.cpp b/libraries/controllers/src/controllers/impl/Mapping.cpp deleted file mode 100644 index dd8e1c1d48..0000000000 --- a/libraries/controllers/src/controllers/impl/Mapping.cpp +++ /dev/null @@ -1,15 +0,0 @@ -// -// Created by Bradley Austin Davis 2015/10/09 -// Copyright 2015 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -// NOTE: we don't need to include this header unless/until we add additional symbols. -// By removing this header we prevent these warnings on windows: -// -// warning LNK4221: This object file does not define any previously undefined public symbols, -// so it will not be used by any link operation that consumes this library -// -//#include "Mapping.h" diff --git a/libraries/controllers/src/controllers/impl/MappingBuilderProxy.h b/libraries/controllers/src/controllers/impl/MappingBuilderProxy.h index 3c3858e2ba..5bc7357dd7 100644 --- a/libraries/controllers/src/controllers/impl/MappingBuilderProxy.h +++ b/libraries/controllers/src/controllers/impl/MappingBuilderProxy.h @@ -54,6 +54,9 @@ class UserInputMapper; * * * @class MappingObject + * + * @hifi-interface + * @hifi-client-entity */ /**jsdoc diff --git a/libraries/controllers/src/controllers/impl/Route.cpp b/libraries/controllers/src/controllers/impl/Route.cpp deleted file mode 100644 index c74f809195..0000000000 --- a/libraries/controllers/src/controllers/impl/Route.cpp +++ /dev/null @@ -1,15 +0,0 @@ -// -// Created by Bradley Austin Davis 2015/10/09 -// Copyright 2015 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -// NOTE: we don't need to include this header unless/until we add additional symbols. -// By removing this header we prevent these warnings on windows: -// -// warning LNK4221: This object file does not define any previously undefined public symbols, -// so it will not be used by any link operation that consumes this library -// -//#include "Route.h" diff --git a/libraries/controllers/src/controllers/impl/RouteBuilderProxy.h b/libraries/controllers/src/controllers/impl/RouteBuilderProxy.h index d33f3e3383..804709ebfa 100644 --- a/libraries/controllers/src/controllers/impl/RouteBuilderProxy.h +++ b/libraries/controllers/src/controllers/impl/RouteBuilderProxy.h @@ -36,6 +36,9 @@ class ScriptingInterface; * types.

* * @class RouteObject + * + * @hifi-interface + * @hifi-client-entity */ // TODO migrate functionality to a RouteBuilder class and make the proxy defer to that diff --git a/libraries/controllers/src/controllers/impl/conditionals/EndpointConditional.cpp b/libraries/controllers/src/controllers/impl/conditionals/EndpointConditional.cpp deleted file mode 100644 index f833eedb60..0000000000 --- a/libraries/controllers/src/controllers/impl/conditionals/EndpointConditional.cpp +++ /dev/null @@ -1,15 +0,0 @@ -// -// Created by Bradley Austin Davis 2015/10/23 -// Copyright 2015 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -// NOTE: we don't need to include this header unless/until we add additional symbols. -// By removing this header we prevent these warnings on windows: -// -// warning LNK4221: This object file does not define any previously undefined public symbols, -// so it will not be used by any link operation that consumes this library -// -//#include "EndpointConditional.h" \ No newline at end of file diff --git a/libraries/controllers/src/controllers/impl/endpoints/ArrayEndpoint.cpp b/libraries/controllers/src/controllers/impl/endpoints/ArrayEndpoint.cpp deleted file mode 100644 index 5dea1de34e..0000000000 --- a/libraries/controllers/src/controllers/impl/endpoints/ArrayEndpoint.cpp +++ /dev/null @@ -1,15 +0,0 @@ -// -// Created by Bradley Austin Davis 2015/10/23 -// Copyright 2015 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -// NOTE: we don't need to include this header unless/until we add additional symbols. -// By removing this header we prevent these warnings on windows: -// -// warning LNK4221: This object file does not define any previously undefined public symbols, -// so it will not be used by any link operation that consumes this library -// -//#include "ArrayEndpoint.h" \ No newline at end of file diff --git a/libraries/controllers/src/controllers/impl/endpoints/StandardEndpoint.cpp b/libraries/controllers/src/controllers/impl/endpoints/StandardEndpoint.cpp deleted file mode 100644 index 89bbe5d777..0000000000 --- a/libraries/controllers/src/controllers/impl/endpoints/StandardEndpoint.cpp +++ /dev/null @@ -1,15 +0,0 @@ -// -// Created by Bradley Austin Davis 2015/10/23 -// Copyright 2015 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -// NOTE: we don't need to include this header unless/until we add additional symbols. -// By removing this header we prevent these warnings on windows: -// -// warning LNK4221: This object file does not define any previously undefined public symbols, -// so it will not be used by any link operation that consumes this library -// -//#include "StandardEndpoint.h" \ No newline at end of file diff --git a/libraries/controllers/src/controllers/impl/filters/ConstrainToIntegerFilter.cpp b/libraries/controllers/src/controllers/impl/filters/ConstrainToIntegerFilter.cpp deleted file mode 100644 index 8bd3d2db89..0000000000 --- a/libraries/controllers/src/controllers/impl/filters/ConstrainToIntegerFilter.cpp +++ /dev/null @@ -1,15 +0,0 @@ -// -// Created by Bradley Austin Davis 2015/10/25 -// Copyright 2015 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -// NOTE: we don't need to include this header unless/until we add additional symbols. -// By removing this header we prevent these warnings on windows: -// -// warning LNK4221: This object file does not define any previously undefined public symbols, -// so it will not be used by any link operation that consumes this library -// -//#include "ConstrainToIntegerFilter.h" diff --git a/libraries/controllers/src/controllers/impl/filters/ConstrainToPositiveIntegerFilter.cpp b/libraries/controllers/src/controllers/impl/filters/ConstrainToPositiveIntegerFilter.cpp deleted file mode 100644 index f1abc8cecd..0000000000 --- a/libraries/controllers/src/controllers/impl/filters/ConstrainToPositiveIntegerFilter.cpp +++ /dev/null @@ -1,15 +0,0 @@ -// -// Created by Bradley Austin Davis 2015/10/25 -// Copyright 2015 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -// NOTE: we don't need to include this header unless/until we add additional symbols. -// By removing this header we prevent these warnings on windows: -// -// warning LNK4221: This object file does not define any previously undefined public symbols, -// so it will not be used by any link operation that consumes this library -// -//#include "ConstrainToPositiveIntegerFilter.h" diff --git a/libraries/controllers/src/controllers/impl/filters/InvertFilter.cpp b/libraries/controllers/src/controllers/impl/filters/InvertFilter.cpp deleted file mode 100644 index 5407c6dd1d..0000000000 --- a/libraries/controllers/src/controllers/impl/filters/InvertFilter.cpp +++ /dev/null @@ -1,15 +0,0 @@ -// -// Created by Bradley Austin Davis 2015/10/25 -// Copyright 2015 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -// NOTE: we don't need to include this header unless/until we add additional symbols. -// By removing this header we prevent these warnings on windows: -// -// warning LNK4221: This object file does not define any previously undefined public symbols, -// so it will not be used by any link operation that consumes this library -// -//#include "InvertFilter.h" diff --git a/libraries/display-plugins/src/display-plugins/Basic2DWindowOpenGLDisplayPlugin.cpp b/libraries/display-plugins/src/display-plugins/Basic2DWindowOpenGLDisplayPlugin.cpp index f33af1b580..59cd637ca0 100644 --- a/libraries/display-plugins/src/display-plugins/Basic2DWindowOpenGLDisplayPlugin.cpp +++ b/libraries/display-plugins/src/display-plugins/Basic2DWindowOpenGLDisplayPlugin.cpp @@ -147,20 +147,21 @@ void Basic2DWindowOpenGLDisplayPlugin::compositeExtra() { batch.setViewportTransform(ivec4(uvec2(0), getRecommendedRenderSize())); batch.draw(gpu::TRIANGLE_STRIP, 4); }); - - // render stick head - auto jumpTransform = DependencyManager::get()->getPoint2DTransform(virtualPadManager.getJumpButtonPosition(), - _virtualPadJumpBtnPixelSize, _virtualPadJumpBtnPixelSize); - render([&](gpu::Batch& batch) { - batch.enableStereo(false); - batch.setProjectionTransform(mat4()); - batch.setPipeline(_cursorPipeline); - batch.setResourceTexture(0, _virtualPadJumpBtnTexture); - batch.resetViewTransform(); - batch.setModelTransform(jumpTransform); - batch.setViewportTransform(ivec4(uvec2(0), getRecommendedRenderSize())); - batch.draw(gpu::TRIANGLE_STRIP, 4); - }); + if (!virtualPadManager.getLeftVirtualPad()->isBeingTouched()) { + // render stick head + auto jumpTransform = DependencyManager::get()->getPoint2DTransform(virtualPadManager.getJumpButtonPosition(), + _virtualPadJumpBtnPixelSize, _virtualPadJumpBtnPixelSize); + render([&](gpu::Batch& batch) { + batch.enableStereo(false); + batch.setProjectionTransform(mat4()); + batch.setPipeline(_cursorPipeline); + batch.setResourceTexture(0, _virtualPadJumpBtnTexture); + batch.resetViewTransform(); + batch.setModelTransform(jumpTransform); + batch.setViewportTransform(ivec4(uvec2(0), getRecommendedRenderSize())); + batch.draw(gpu::TRIANGLE_STRIP, 4); + }); + } } #endif Parent::compositeExtra(); diff --git a/libraries/display-plugins/src/display-plugins/CompositorHelper.h b/libraries/display-plugins/src/display-plugins/CompositorHelper.h index bc6ed63363..fb712c26fa 100644 --- a/libraries/display-plugins/src/display-plugins/CompositorHelper.h +++ b/libraries/display-plugins/src/display-plugins/CompositorHelper.h @@ -174,6 +174,10 @@ private: /**jsdoc * @namespace Reticle + * + * @hifi-interface + * @hifi-client-entity + * * @property {boolean} allowMouseCapture * @property {number} depth * @property {Vec2} maximumPosition diff --git a/libraries/embedded-webserver/src/HTTPConnection.cpp b/libraries/embedded-webserver/src/HTTPConnection.cpp index 280b44cec0..12da599575 100644 --- a/libraries/embedded-webserver/src/HTTPConnection.cpp +++ b/libraries/embedded-webserver/src/HTTPConnection.cpp @@ -9,15 +9,15 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include "HTTPConnection.h" #include #include #include +#include -#include "HTTPConnection.h" #include "EmbeddedWebserverLogging.h" #include "HTTPManager.h" -#include const char* HTTPConnection::StatusCode200 = "200 OK"; const char* HTTPConnection::StatusCode301 = "301 Moved Permanently"; diff --git a/libraries/embedded-webserver/src/HTTPManager.cpp b/libraries/embedded-webserver/src/HTTPManager.cpp index bd1b545412..db6fc8e084 100644 --- a/libraries/embedded-webserver/src/HTTPManager.cpp +++ b/libraries/embedded-webserver/src/HTTPManager.cpp @@ -9,6 +9,8 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include "HTTPManager.h" + #include #include #include @@ -18,7 +20,6 @@ #include "HTTPConnection.h" #include "EmbeddedWebserverLogging.h" -#include "HTTPManager.h" const int SOCKET_ERROR_EXIT_CODE = 2; const int SOCKET_CHECK_INTERVAL_IN_MS = 30000; diff --git a/libraries/embedded-webserver/src/HTTPSConnection.cpp b/libraries/embedded-webserver/src/HTTPSConnection.cpp index 7af14ce0a7..f5473d577f 100644 --- a/libraries/embedded-webserver/src/HTTPSConnection.cpp +++ b/libraries/embedded-webserver/src/HTTPSConnection.cpp @@ -9,9 +9,10 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -#include "EmbeddedWebserverLogging.h" #include "HTTPSConnection.h" +#include "EmbeddedWebserverLogging.h" + HTTPSConnection::HTTPSConnection(QSslSocket* sslSocket, HTTPSManager* parentManager) : HTTPConnection(sslSocket, parentManager) { diff --git a/libraries/embedded-webserver/src/HTTPSManager.cpp b/libraries/embedded-webserver/src/HTTPSManager.cpp index ee61f15457..8ba44f98ac 100644 --- a/libraries/embedded-webserver/src/HTTPSManager.cpp +++ b/libraries/embedded-webserver/src/HTTPSManager.cpp @@ -9,12 +9,12 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include "HTTPSManager.h" + #include #include "HTTPSConnection.h" -#include "HTTPSManager.h" - HTTPSManager::HTTPSManager(QHostAddress listenAddress, quint16 port, const QSslCertificate& certificate, const QSslKey& privateKey, const QString& documentRoot, HTTPSRequestHandler* requestHandler, QObject* parent) : HTTPManager(listenAddress, port, documentRoot, requestHandler, parent), diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.cpp b/libraries/entities-renderer/src/EntityTreeRenderer.cpp index ba81922979..600d1c32a8 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.cpp +++ b/libraries/entities-renderer/src/EntityTreeRenderer.cpp @@ -296,7 +296,7 @@ void EntityTreeRenderer::addPendingEntities(const render::ScenePointer& scene, r } } -void EntityTreeRenderer::updateChangedEntities(const render::ScenePointer& scene, const ViewFrustum& view, render::Transaction& transaction) { +void EntityTreeRenderer::updateChangedEntities(const render::ScenePointer& scene, render::Transaction& transaction) { PROFILE_RANGE_EX(simulation_physics, "ChangeInScene", 0xffff00ff, (uint64_t)_changedEntities.size()); PerformanceTimer pt("change"); std::unordered_set changedEntities; @@ -357,7 +357,9 @@ void EntityTreeRenderer::updateChangedEntities(const render::ScenePointer& scene // prioritize and sort the renderables uint64_t sortStart = usecTimestampNow(); - PrioritySortUtil::PriorityQueue sortedRenderables(view); + + const auto& views = _viewState->getConicalViews(); + PrioritySortUtil::PriorityQueue sortedRenderables(views); { PROFILE_RANGE_EX(simulation_physics, "SortRenderables", 0xffff00ff, (uint64_t)_renderablesToUpdate.size()); std::unordered_map::iterator itr = _renderablesToUpdate.begin(); @@ -415,9 +417,8 @@ void EntityTreeRenderer::update(bool simulate) { if (scene) { render::Transaction transaction; addPendingEntities(scene, transaction); - ViewFrustum view; - _viewState->copyCurrentViewFrustum(view); - updateChangedEntities(scene, view, transaction); + + updateChangedEntities(scene, transaction); scene->enqueueTransaction(transaction); } } diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.h b/libraries/entities-renderer/src/EntityTreeRenderer.h index f5cedfdd01..882ec2fd5b 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.h +++ b/libraries/entities-renderer/src/EntityTreeRenderer.h @@ -148,7 +148,7 @@ protected: private: void addPendingEntities(const render::ScenePointer& scene, render::Transaction& transaction); - void updateChangedEntities(const render::ScenePointer& scene, const ViewFrustum& view, render::Transaction& transaction); + void updateChangedEntities(const render::ScenePointer& scene, render::Transaction& transaction); EntityRendererPointer renderableForEntity(const EntityItemPointer& entity) const { return renderableForEntityId(entity->getID()); } render::ItemID renderableIdForEntity(const EntityItemPointer& entity) const { return renderableIdForEntityId(entity->getID()); } diff --git a/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp b/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp index b3a4a1a1ab..ee77646920 100644 --- a/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp @@ -23,8 +23,8 @@ using namespace render::entities; static uint8_t CUSTOM_PIPELINE_NUMBER = 0; static gpu::Stream::FormatPointer _vertexFormat; static std::weak_ptr _texturedPipeline; -// FIXME: This is interfering with the uniform buffers in DeferredLightingEffect.cpp, so use 11 to avoid collisions -static int32_t PARTICLE_UNIFORM_SLOT { 11 }; +// FIXME: This is interfering with the uniform buffers in DeferredLightingEffect.cpp, so use 12 to avoid collisions +static int32_t PARTICLE_UNIFORM_SLOT { 12 }; static ShapePipelinePointer shapePipelineFactory(const ShapePlumber& plumber, const ShapeKey& key, gpu::Batch& batch) { auto texturedPipeline = _texturedPipeline.lock(); diff --git a/libraries/entities-renderer/src/RenderablePolyLineEntityItem.cpp b/libraries/entities-renderer/src/RenderablePolyLineEntityItem.cpp index 394ab08dfb..d571eac35c 100644 --- a/libraries/entities-renderer/src/RenderablePolyLineEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderablePolyLineEntityItem.cpp @@ -34,8 +34,8 @@ using namespace render::entities; static uint8_t CUSTOM_PIPELINE_NUMBER { 0 }; static const int32_t PAINTSTROKE_TEXTURE_SLOT { 0 }; -// FIXME: This is interfering with the uniform buffers in DeferredLightingEffect.cpp, so use 11 to avoid collisions -static const int32_t PAINTSTROKE_UNIFORM_SLOT { 11 }; +// FIXME: This is interfering with the uniform buffers in DeferredLightingEffect.cpp, so use 12 to avoid collisions +static const int32_t PAINTSTROKE_UNIFORM_SLOT { 12 }; static gpu::Stream::FormatPointer polylineFormat; static gpu::PipelinePointer polylinePipeline; #ifdef POLYLINE_ENTITY_USE_FADE_EFFECT diff --git a/libraries/entities/src/DeleteEntityOperator.cpp b/libraries/entities/src/DeleteEntityOperator.cpp index 347d40ea49..d369e08ecf 100644 --- a/libraries/entities/src/DeleteEntityOperator.cpp +++ b/libraries/entities/src/DeleteEntityOperator.cpp @@ -9,12 +9,12 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include "DeleteEntityOperator.h" + #include "EntityItem.h" #include "EntityTree.h" #include "EntityTreeElement.h" - #include "EntitiesLogging.h" -#include "DeleteEntityOperator.h" DeleteEntityOperator::DeleteEntityOperator(EntityTreePointer tree, const EntityItemID& searchEntityID) : _tree(tree), diff --git a/libraries/entities/src/DeleteEntityOperator.h b/libraries/entities/src/DeleteEntityOperator.h index 135949a53d..3b3ee2a868 100644 --- a/libraries/entities/src/DeleteEntityOperator.h +++ b/libraries/entities/src/DeleteEntityOperator.h @@ -12,6 +12,12 @@ #ifndef hifi_DeleteEntityOperator_h #define hifi_DeleteEntityOperator_h +#include + +#include + +#include "EntityItem.h" + class EntityToDeleteDetails { public: EntityItemPointer entity; diff --git a/libraries/entities/src/DiffTraversal.cpp b/libraries/entities/src/DiffTraversal.cpp index 764c420197..36d1f41267 100644 --- a/libraries/entities/src/DiffTraversal.cpp +++ b/libraries/entities/src/DiffTraversal.cpp @@ -13,6 +13,7 @@ #include +#include "EntityPriorityQueue.h" DiffTraversal::Waypoint::Waypoint(EntityTreeElementPointer& element) : _nextIndex(0) { assert(element); @@ -36,20 +37,9 @@ void DiffTraversal::Waypoint::getNextVisibleElementFirstTime(DiffTraversal::Visi while (_nextIndex < NUMBER_OF_CHILDREN) { EntityTreeElementPointer nextElement = element->getChildAtIndex(_nextIndex); ++_nextIndex; - if (nextElement) { - if (!view.usesViewFrustum) { - // No LOD truncation if we aren't using the view frustum - next.element = nextElement; - return; - } else if (view.viewFrustum.cubeIntersectsKeyhole(nextElement->getAACube())) { - // check for LOD truncation - float distance = glm::distance(view.viewFrustum.getPosition(), nextElement->getAACube().calcCenter()) + MIN_VISIBLE_DISTANCE; - float angularDiameter = nextElement->getAACube().getScale() / distance; - if (angularDiameter > MIN_ELEMENT_ANGULAR_DIAMETER * view.lodScaleFactor) { - next.element = nextElement; - return; - } - } + if (nextElement && view.shouldTraverseElement(*nextElement)) { + next.element = nextElement; + return; } } } @@ -65,7 +55,6 @@ void DiffTraversal::Waypoint::getNextVisibleElementRepeat( EntityTreeElementPointer element = _weakElement.lock(); if (element->getLastChangedContent() > lastTime) { next.element = element; - next.intersection = ViewFrustum::INTERSECT; return; } } @@ -75,31 +64,17 @@ void DiffTraversal::Waypoint::getNextVisibleElementRepeat( while (_nextIndex < NUMBER_OF_CHILDREN) { EntityTreeElementPointer nextElement = element->getChildAtIndex(_nextIndex); ++_nextIndex; - if (nextElement && nextElement->getLastChanged() > lastTime) { - if (!view.usesViewFrustum) { - // No LOD truncation if we aren't using the view frustum - next.element = nextElement; - next.intersection = ViewFrustum::INSIDE; - return; - } else { - // check for LOD truncation - float distance = glm::distance(view.viewFrustum.getPosition(), nextElement->getAACube().calcCenter()) + MIN_VISIBLE_DISTANCE; - float angularDiameter = nextElement->getAACube().getScale() / distance; - if (angularDiameter > MIN_ELEMENT_ANGULAR_DIAMETER * view.lodScaleFactor) { - ViewFrustum::intersection intersection = view.viewFrustum.calculateCubeKeyholeIntersection(nextElement->getAACube()); - if (intersection != ViewFrustum::OUTSIDE) { - next.element = nextElement; - next.intersection = intersection; - return; - } - } - } + if (nextElement && + nextElement->getLastChanged() > lastTime && + view.shouldTraverseElement(*nextElement)) { + + next.element = nextElement; + return; } } } } next.element.reset(); - next.intersection = ViewFrustum::OUTSIDE; } void DiffTraversal::Waypoint::getNextVisibleElementDifferential(DiffTraversal::VisibleElement& next, @@ -109,7 +84,6 @@ void DiffTraversal::Waypoint::getNextVisibleElementDifferential(DiffTraversal::V ++_nextIndex; EntityTreeElementPointer element = _weakElement.lock(); next.element = element; - next.intersection = ViewFrustum::INTERSECT; return; } else if (_nextIndex < NUMBER_OF_CHILDREN) { EntityTreeElementPointer element = _weakElement.lock(); @@ -117,24 +91,101 @@ void DiffTraversal::Waypoint::getNextVisibleElementDifferential(DiffTraversal::V while (_nextIndex < NUMBER_OF_CHILDREN) { EntityTreeElementPointer nextElement = element->getChildAtIndex(_nextIndex); ++_nextIndex; - if (nextElement) { - AACube cube = nextElement->getAACube(); - // check for LOD truncation - float distance = glm::distance(view.viewFrustum.getPosition(), cube.calcCenter()) + MIN_VISIBLE_DISTANCE; - float angularDiameter = cube.getScale() / distance; - if (angularDiameter > MIN_ELEMENT_ANGULAR_DIAMETER * view.lodScaleFactor) { - if (view.viewFrustum.calculateCubeKeyholeIntersection(cube) != ViewFrustum::OUTSIDE) { - next.element = nextElement; - next.intersection = ViewFrustum::OUTSIDE; - return; - } - } + if (nextElement && view.shouldTraverseElement(*nextElement)) { + next.element = nextElement; + return; } } } } next.element.reset(); - next.intersection = ViewFrustum::OUTSIDE; +} + +bool DiffTraversal::View::usesViewFrustums() const { + return !viewFrustums.empty(); +} + +bool DiffTraversal::View::isVerySimilar(const View& view) const { + auto size = view.viewFrustums.size(); + + if (view.lodScaleFactor != lodScaleFactor || + viewFrustums.size() != size) { + return false; + } + + for (size_t i = 0; i < size; ++i) { + if (!viewFrustums[i].isVerySimilar(view.viewFrustums[i])) { + return false; + } + } + return true; +} + +float DiffTraversal::View::computePriority(const EntityItemPointer& entity) const { + if (!entity) { + return PrioritizedEntity::DO_NOT_SEND; + } + + if (!usesViewFrustums()) { + return PrioritizedEntity::WHEN_IN_DOUBT_PRIORITY; + } + + bool success = false; + auto cube = entity->getQueryAACube(success); + if (!success) { + return PrioritizedEntity::WHEN_IN_DOUBT_PRIORITY; + } + + auto center = cube.calcCenter(); // center of bounding sphere + auto radius = 0.5f * SQRT_THREE * cube.getScale(); // radius of bounding sphere + + auto priority = PrioritizedEntity::DO_NOT_SEND; + + for (const auto& frustum : viewFrustums) { + auto position = center - frustum.getPosition(); // position of bounding sphere in view-frame + float distance = glm::length(position); // distance to center of bounding sphere + + // Check the size of the entity, it's possible that a "too small to see" entity is included in a + // larger octree cell because of its position (for example if it crosses the boundary of a cell it + // pops to the next higher cell. So we want to check to see that the entity is large enough to be seen + // before we consider including it. + float angularSize = frustum.getAngularSize(distance, radius); + if (angularSize > lodScaleFactor * MIN_ENTITY_ANGULAR_DIAMETER && + frustum.intersects(position, distance, radius)) { + + // use the angular size as priority + // we compute the max priority for all frustums + priority = std::max(priority, angularSize); + } + } + + return priority; +} + +bool DiffTraversal::View::shouldTraverseElement(const EntityTreeElement& element) const { + if (!usesViewFrustums()) { + return true; + } + + const auto& cube = element.getAACube(); + + auto center = cube.calcCenter(); // center of bounding sphere + auto radius = 0.5f * SQRT_THREE * cube.getScale(); // radius of bounding sphere + + + return any_of(begin(viewFrustums), end(viewFrustums), [&](const ConicalViewFrustum& frustum) { + auto position = center - frustum.getPosition(); // position of bounding sphere in view-frame + float distance = glm::length(position); // distance to center of bounding sphere + + // Check the size of the entity, it's possible that a "too small to see" entity is included in a + // larger octree cell because of its position (for example if it crosses the boundary of a cell it + // pops to the next higher cell. So we want to check to see that the entity is large enough to be seen + // before we consider including it. + float angularSize = frustum.getAngularSize(distance, radius); + + return angularSize > lodScaleFactor * MIN_ELEMENT_ANGULAR_DIAMETER && + frustum.intersects(position, distance, radius); + }); } DiffTraversal::DiffTraversal() { @@ -142,8 +193,7 @@ DiffTraversal::DiffTraversal() { _path.reserve(MIN_PATH_DEPTH); } -DiffTraversal::Type DiffTraversal::prepareNewTraversal(const ViewFrustum& viewFrustum, EntityTreeElementPointer root, - int32_t lodLevelOffset, bool usesViewFrustum) { +DiffTraversal::Type DiffTraversal::prepareNewTraversal(const DiffTraversal::View& view, EntityTreeElementPointer root) { assert(root); // there are three types of traversal: // @@ -159,29 +209,25 @@ DiffTraversal::Type DiffTraversal::prepareNewTraversal(const ViewFrustum& viewFr // // external code should update the _scanElementCallback after calling prepareNewTraversal // - _currentView.usesViewFrustum = usesViewFrustum; - float lodScaleFactor = powf(2.0f, lodLevelOffset); Type type; // If usesViewFrustum changes, treat it as a First traversal - if (_completedView.startTime == 0 || _currentView.usesViewFrustum != _completedView.usesViewFrustum) { + if (_completedView.startTime == 0 || _currentView.usesViewFrustums() != _completedView.usesViewFrustums()) { type = Type::First; - _currentView.viewFrustum = viewFrustum; - _currentView.lodScaleFactor = lodScaleFactor; + _currentView.viewFrustums = view.viewFrustums; + _currentView.lodScaleFactor = view.lodScaleFactor; _getNextVisibleElementCallback = [this](DiffTraversal::VisibleElement& next) { _path.back().getNextVisibleElementFirstTime(next, _currentView); }; - } else if (!_currentView.usesViewFrustum || - (_completedView.viewFrustum.isVerySimilar(viewFrustum) && - lodScaleFactor == _completedView.lodScaleFactor)) { + } else if (!_currentView.usesViewFrustums() || _completedView.isVerySimilar(view)) { type = Type::Repeat; _getNextVisibleElementCallback = [this](DiffTraversal::VisibleElement& next) { _path.back().getNextVisibleElementRepeat(next, _completedView, _completedView.startTime); }; } else { type = Type::Differential; - _currentView.viewFrustum = viewFrustum; - _currentView.lodScaleFactor = lodScaleFactor; + _currentView.viewFrustums = view.viewFrustums; + _currentView.lodScaleFactor = view.lodScaleFactor; _getNextVisibleElementCallback = [this](DiffTraversal::VisibleElement& next) { _path.back().getNextVisibleElementDifferential(next, _currentView, _completedView); }; @@ -200,7 +246,6 @@ DiffTraversal::Type DiffTraversal::prepareNewTraversal(const ViewFrustum& viewFr void DiffTraversal::getNextVisibleElement(DiffTraversal::VisibleElement& next) { if (_path.empty()) { next.element.reset(); - next.intersection = ViewFrustum::OUTSIDE; return; } _getNextVisibleElementCallback(next); diff --git a/libraries/entities/src/DiffTraversal.h b/libraries/entities/src/DiffTraversal.h index 69431d8db5..d62c7b8ee1 100644 --- a/libraries/entities/src/DiffTraversal.h +++ b/libraries/entities/src/DiffTraversal.h @@ -12,7 +12,7 @@ #ifndef hifi_DiffTraversal_h #define hifi_DiffTraversal_h -#include +#include #include "EntityTreeElement.h" @@ -24,16 +24,20 @@ public: class VisibleElement { public: EntityTreeElementPointer element; - ViewFrustum::intersection intersection { ViewFrustum::OUTSIDE }; }; // View is a struct with a ViewFrustum and LOD parameters class View { public: - ViewFrustum viewFrustum; + bool usesViewFrustums() const; + bool isVerySimilar(const View& view) const; + + bool shouldTraverseElement(const EntityTreeElement& element) const; + float computePriority(const EntityItemPointer& entity) const; + + ConicalViewFrustums viewFrustums; uint64_t startTime { 0 }; float lodScaleFactor { 1.0f }; - bool usesViewFrustum { true }; }; // Waypoint is an bookmark in a "path" of waypoints during a traversal. @@ -57,15 +61,9 @@ public: DiffTraversal(); - Type prepareNewTraversal(const ViewFrustum& viewFrustum, EntityTreeElementPointer root, int32_t lodLevelOffset, - bool usesViewFrustum); + Type prepareNewTraversal(const DiffTraversal::View& view, EntityTreeElementPointer root); - const ViewFrustum& getCurrentView() const { return _currentView.viewFrustum; } - const ViewFrustum& getCompletedView() const { return _completedView.viewFrustum; } - - bool doesCurrentUseViewFrustum() const { return _currentView.usesViewFrustum; } - float getCurrentLODScaleFactor() const { return _currentView.lodScaleFactor; } - float getCompletedLODScaleFactor() const { return _completedView.lodScaleFactor; } + const View& getCurrentView() const { return _currentView; } uint64_t getStartOfCompletedTraversal() const { return _completedView.startTime; } bool finished() const { return _path.empty(); } diff --git a/libraries/entities/src/EntityDynamicInterface.cpp b/libraries/entities/src/EntityDynamicInterface.cpp index d43bdd7b51..1115559342 100644 --- a/libraries/entities/src/EntityDynamicInterface.cpp +++ b/libraries/entities/src/EntityDynamicInterface.cpp @@ -89,10 +89,9 @@ variables. These argument variables are used by the code which is run when bull */ -#include "EntityItem.h" - #include "EntityDynamicInterface.h" +#include "EntityItem.h" /**jsdoc *

An entity action may be one of the following types:

diff --git a/libraries/entities/src/EntityDynamicInterface.h b/libraries/entities/src/EntityDynamicInterface.h index 40e39eecf1..6b82e7df73 100644 --- a/libraries/entities/src/EntityDynamicInterface.h +++ b/libraries/entities/src/EntityDynamicInterface.h @@ -13,9 +13,12 @@ #define hifi_EntityDynamicInterface_h #include -#include + #include +#include +#include + class EntityItem; class EntityItemID; class EntitySimulation; diff --git a/libraries/entities/src/EntityEditFilters.cpp b/libraries/entities/src/EntityEditFilters.cpp index 676b1ce518..94df7eb465 100644 --- a/libraries/entities/src/EntityEditFilters.cpp +++ b/libraries/entities/src/EntityEditFilters.cpp @@ -9,11 +9,11 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include "EntityEditFilters.h" #include #include -#include "EntityEditFilters.h" QList EntityEditFilters::getZonesByPosition(glm::vec3& position) { QList zones; diff --git a/libraries/entities/src/EntityEditPacketSender.cpp b/libraries/entities/src/EntityEditPacketSender.cpp index 5d7bd61854..d89dd4f9d0 100644 --- a/libraries/entities/src/EntityEditPacketSender.cpp +++ b/libraries/entities/src/EntityEditPacketSender.cpp @@ -9,16 +9,20 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include "EntityEditPacketSender.h" + #include + #include + +#include #include #include #include -#include "EntityEditPacketSender.h" + #include "EntitiesLogging.h" #include "EntityItem.h" #include "EntityItemProperties.h" -#include EntityEditPacketSender::EntityEditPacketSender() { auto& packetReceiver = DependencyManager::get()->getPacketReceiver(); diff --git a/libraries/entities/src/EntityItemProperties.cpp b/libraries/entities/src/EntityItemProperties.cpp index 4638b46437..4d7c114176 100644 --- a/libraries/entities/src/EntityItemProperties.cpp +++ b/libraries/entities/src/EntityItemProperties.cpp @@ -9,24 +9,28 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -#include -#include -#include -#include +#include "EntityItemProperties.h" + #include #include #include #include -#include + +#include +#include +#include +#include #include #include + +#include #include #include #include #include + #include "EntitiesLogging.h" #include "EntityItem.h" -#include "EntityItemProperties.h" #include "ModelEntityItem.h" #include "PolyLineEntityItem.h" diff --git a/libraries/entities/src/EntityItemProperties.h b/libraries/entities/src/EntityItemProperties.h index 38e4f0c8c0..39ea2e0bdd 100644 --- a/libraries/entities/src/EntityItemProperties.h +++ b/libraries/entities/src/EntityItemProperties.h @@ -27,6 +27,7 @@ #include #include #include +#include #include "AnimationPropertyGroup.h" #include "EntityItemID.h" diff --git a/libraries/entities/src/EntityPriorityQueue.h b/libraries/entities/src/EntityPriorityQueue.h new file mode 100644 index 0000000000..339676d237 --- /dev/null +++ b/libraries/entities/src/EntityPriorityQueue.h @@ -0,0 +1,92 @@ +// +// EntityPriorityQueue.h +// assignment-client/src/entities +// +// Created by Andrew Meadows 2017.08.08 +// Copyright 2017 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef hifi_EntityPriorityQueue_h +#define hifi_EntityPriorityQueue_h + +#include +#include + +#include "EntityItem.h" + +// PrioritizedEntity is a placeholder in a sorted queue. +class PrioritizedEntity { +public: + static constexpr float DO_NOT_SEND { -1.0e6f }; + static constexpr float FORCE_REMOVE { -1.0e5f }; + static constexpr float WHEN_IN_DOUBT_PRIORITY { 1.0f }; + + PrioritizedEntity(EntityItemPointer entity, float priority, bool forceRemove = false) : _weakEntity(entity), _rawEntityPointer(entity.get()), _priority(priority), _forceRemove(forceRemove) {} + EntityItemPointer getEntity() const { return _weakEntity.lock(); } + EntityItem* getRawEntityPointer() const { return _rawEntityPointer; } + float getPriority() const { return _priority; } + bool shouldForceRemove() const { return _forceRemove; } + + class Compare { + public: + bool operator() (const PrioritizedEntity& A, const PrioritizedEntity& B) { return A._priority < B._priority; } + }; + friend class Compare; + +private: + EntityItemWeakPointer _weakEntity; + EntityItem* _rawEntityPointer; + float _priority; + bool _forceRemove; +}; + +class EntityPriorityQueue { +public: + inline bool empty() const { + assert(_queue.empty() == _entities.empty()); + return _queue.empty(); + } + + inline const PrioritizedEntity& top() const { + assert(!_queue.empty()); + return _queue.top(); + } + + inline bool contains(const EntityItem* entity) const { + return _entities.find(entity) != std::end(_entities); + } + + inline void emplace(const EntityItemPointer& entity, float priority, bool forceRemove = false) { + assert(entity && !contains(entity.get())); + _queue.emplace(entity, priority, forceRemove); + _entities.insert(entity.get()); + assert(_queue.size() == _entities.size()); + } + + inline void pop() { + assert(!empty()); + _entities.erase(_queue.top().getRawEntityPointer()); + _queue.pop(); + assert(_queue.size() == _entities.size()); + } + + inline void swap(EntityPriorityQueue& other) { + std::swap(_queue, other._queue); + std::swap(_entities, other._entities); + } + +private: + using PriorityQueue = std::priority_queue, + PrioritizedEntity::Compare>; + + PriorityQueue _queue; + // Keep dictionary of all the entities in the queue for fast contain checks. + std::unordered_set _entities; + +}; + +#endif // hifi_EntityPriorityQueue_h diff --git a/libraries/entities/src/EntityScriptingInterface.h b/libraries/entities/src/EntityScriptingInterface.h index 5e76d18515..8adb5138f2 100644 --- a/libraries/entities/src/EntityScriptingInterface.h +++ b/libraries/entities/src/EntityScriptingInterface.h @@ -94,6 +94,12 @@ void RayToEntityIntersectionResultFromScriptValue(const QScriptValue& object, Ra * Interface has displayed and so knows about. * * @namespace Entities + * + * @hifi-interface + * @hifi-client-entity + * @hifi-server-entity + * @hifi-assignment-client + * * @property {Uuid} keyboardFocusEntity - Get or set the {@link Entities.EntityType|Web} entity that has keyboard focus. * If no entity has keyboard focus, get returns null; set to null or {@link Uuid|Uuid.NULL} to * clear keyboard focus. diff --git a/libraries/entities/src/EntityTree.h b/libraries/entities/src/EntityTree.h index 3289101967..ee9fb10554 100644 --- a/libraries/entities/src/EntityTree.h +++ b/libraries/entities/src/EntityTree.h @@ -18,18 +18,13 @@ #include #include -class EntityTree; -using EntityTreePointer = std::shared_ptr; - #include "AddEntityOperator.h" #include "EntityTreeElement.h" #include "DeleteEntityOperator.h" #include "MovingEntitiesOperator.h" -class EntityEditFilters; -class Model; -using ModelPointer = std::shared_ptr; -using ModelWeakPointer = std::weak_ptr; +class EntityTree; +using EntityTreePointer = std::shared_ptr; class EntitySimulation; diff --git a/libraries/entities/src/EntityTypes.cpp b/libraries/entities/src/EntityTypes.cpp index 694542b04e..9611063f8b 100644 --- a/libraries/entities/src/EntityTypes.cpp +++ b/libraries/entities/src/EntityTypes.cpp @@ -9,6 +9,8 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include "EntityTypes.h" + #include #include @@ -16,7 +18,6 @@ #include "EntityItem.h" #include "EntityItemProperties.h" -#include "EntityTypes.h" #include "EntitiesLogging.h" #include "LightEntityItem.h" diff --git a/libraries/entities/src/EntityTypes.h b/libraries/entities/src/EntityTypes.h index 0e2fca8180..1f3434d254 100644 --- a/libraries/entities/src/EntityTypes.h +++ b/libraries/entities/src/EntityTypes.h @@ -12,6 +12,7 @@ #ifndef hifi_EntityTypes_h #define hifi_EntityTypes_h +#include #include #include diff --git a/libraries/entities/src/HazePropertyGroup.cpp b/libraries/entities/src/HazePropertyGroup.cpp index f137fca5ce..c15b28707c 100644 --- a/libraries/entities/src/HazePropertyGroup.cpp +++ b/libraries/entities/src/HazePropertyGroup.cpp @@ -9,9 +9,10 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include "HazePropertyGroup.h" + #include -#include "HazePropertyGroup.h" #include "EntityItemProperties.h" #include "EntityItemPropertiesMacros.h" diff --git a/libraries/entities/src/LightEntityItem.cpp b/libraries/entities/src/LightEntityItem.cpp index f0fbb20f98..e95af7ebf9 100644 --- a/libraries/entities/src/LightEntityItem.cpp +++ b/libraries/entities/src/LightEntityItem.cpp @@ -9,6 +9,7 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include "LightEntityItem.h" #include @@ -19,7 +20,6 @@ #include "EntityItemProperties.h" #include "EntityTree.h" #include "EntityTreeElement.h" -#include "LightEntityItem.h" const bool LightEntityItem::DEFAULT_IS_SPOTLIGHT = false; const float LightEntityItem::DEFAULT_INTENSITY = 1.0f; diff --git a/libraries/entities/src/ModelEntityItem.cpp b/libraries/entities/src/ModelEntityItem.cpp index 0f59bc673d..cf89a73214 100644 --- a/libraries/entities/src/ModelEntityItem.cpp +++ b/libraries/entities/src/ModelEntityItem.cpp @@ -9,18 +9,20 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include "ModelEntityItem.h" + #include +#include + #include #include -#include #include "EntitiesLogging.h" #include "EntityItemProperties.h" #include "EntityTree.h" #include "EntityTreeElement.h" #include "ResourceCache.h" -#include "ModelEntityItem.h" const QString ModelEntityItem::DEFAULT_MODEL_URL = QString(""); const QString ModelEntityItem::DEFAULT_COMPOUND_SHAPE_URL = QString(""); diff --git a/libraries/entities/src/MovingEntitiesOperator.cpp b/libraries/entities/src/MovingEntitiesOperator.cpp index cf043dd93e..4b908745e0 100644 --- a/libraries/entities/src/MovingEntitiesOperator.cpp +++ b/libraries/entities/src/MovingEntitiesOperator.cpp @@ -9,13 +9,13 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include "MovingEntitiesOperator.h" + #include "EntityItem.h" #include "EntityTree.h" #include "EntityTreeElement.h" #include "EntitiesLogging.h" -#include "MovingEntitiesOperator.h" - MovingEntitiesOperator::MovingEntitiesOperator() { } MovingEntitiesOperator::~MovingEntitiesOperator() { diff --git a/libraries/entities/src/MovingEntitiesOperator.h b/libraries/entities/src/MovingEntitiesOperator.h index d93efa60f2..9e98374fc3 100644 --- a/libraries/entities/src/MovingEntitiesOperator.h +++ b/libraries/entities/src/MovingEntitiesOperator.h @@ -14,8 +14,7 @@ #include -#include "EntityTypes.h" -#include "EntityTreeElement.h" +#include "EntityItem.h" class EntityToMoveDetails { public: diff --git a/libraries/entities/src/ParticleEffectEntityItem.cpp b/libraries/entities/src/ParticleEffectEntityItem.cpp index d9ef5e2178..d1fc3d2775 100644 --- a/libraries/entities/src/ParticleEffectEntityItem.cpp +++ b/libraries/entities/src/ParticleEffectEntityItem.cpp @@ -26,6 +26,7 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include "ParticleEffectEntityItem.h" #include #include @@ -38,8 +39,6 @@ #include "EntityTreeElement.h" #include "EntitiesLogging.h" #include "EntityScriptingInterface.h" -#include "ParticleEffectEntityItem.h" - using namespace particle; diff --git a/libraries/entities/src/PolyLineEntityItem.cpp b/libraries/entities/src/PolyLineEntityItem.cpp index 420c570e8d..5b3167b9ba 100644 --- a/libraries/entities/src/PolyLineEntityItem.cpp +++ b/libraries/entities/src/PolyLineEntityItem.cpp @@ -9,6 +9,7 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include "PolyLineEntityItem.h" #include @@ -19,7 +20,6 @@ #include "EntityTree.h" #include "EntityTreeElement.h" #include "OctreeConstants.h" -#include "PolyLineEntityItem.h" const float PolyLineEntityItem::DEFAULT_LINE_WIDTH = 0.1f; const int PolyLineEntityItem::MAX_POINTS_PER_LINE = 60; diff --git a/libraries/entities/src/ShapeEntityItem.cpp b/libraries/entities/src/ShapeEntityItem.cpp index 520d892682..943ae2e462 100644 --- a/libraries/entities/src/ShapeEntityItem.cpp +++ b/libraries/entities/src/ShapeEntityItem.cpp @@ -6,6 +6,7 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include "ShapeEntityItem.h" #include @@ -17,7 +18,6 @@ #include "EntityItemProperties.h" #include "EntityTree.h" #include "EntityTreeElement.h" -#include "ShapeEntityItem.h" namespace entity { diff --git a/libraries/entities/src/SkyboxPropertyGroup.cpp b/libraries/entities/src/SkyboxPropertyGroup.cpp index f8baf57856..ba40c3fa6f 100644 --- a/libraries/entities/src/SkyboxPropertyGroup.cpp +++ b/libraries/entities/src/SkyboxPropertyGroup.cpp @@ -9,9 +9,10 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include "SkyboxPropertyGroup.h" + #include -#include "SkyboxPropertyGroup.h" #include "EntityItemProperties.h" #include "EntityItemPropertiesMacros.h" diff --git a/libraries/entities/src/SkyboxPropertyGroup.h b/libraries/entities/src/SkyboxPropertyGroup.h index d7b422bf11..a94365d24d 100644 --- a/libraries/entities/src/SkyboxPropertyGroup.h +++ b/libraries/entities/src/SkyboxPropertyGroup.h @@ -18,6 +18,8 @@ #include +#include + #include "PropertyGroup.h" #include "EntityItemPropertiesMacros.h" diff --git a/libraries/entities/src/TextEntityItem.cpp b/libraries/entities/src/TextEntityItem.cpp index 97080d3ca2..56e12e66d9 100644 --- a/libraries/entities/src/TextEntityItem.cpp +++ b/libraries/entities/src/TextEntityItem.cpp @@ -9,6 +9,7 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include "TextEntityItem.h" #include @@ -21,7 +22,6 @@ #include "EntitiesLogging.h" #include "EntityTree.h" #include "EntityTreeElement.h" -#include "TextEntityItem.h" const QString TextEntityItem::DEFAULT_TEXT(""); const float TextEntityItem::DEFAULT_LINE_HEIGHT = 0.1f; diff --git a/libraries/entities/src/ZoneEntityItem.cpp b/libraries/entities/src/ZoneEntityItem.cpp index b07d0597bc..3a6095b89f 100644 --- a/libraries/entities/src/ZoneEntityItem.cpp +++ b/libraries/entities/src/ZoneEntityItem.cpp @@ -9,6 +9,7 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include "ZoneEntityItem.h" #include @@ -18,7 +19,6 @@ #include "EntityItemProperties.h" #include "EntityTree.h" #include "EntityTreeElement.h" -#include "ZoneEntityItem.h" #include "EntityEditFilters.h" bool ZoneEntityItem::_zonesArePickable = false; diff --git a/libraries/fbx/src/FBX.h b/libraries/fbx/src/FBX.h index a609d85fc8..ce3fc52c3a 100644 --- a/libraries/fbx/src/FBX.h +++ b/libraries/fbx/src/FBX.h @@ -298,6 +298,7 @@ public: bool hasSkeletonJoints; QVector meshes; + QVector scripts; QHash materials; diff --git a/libraries/fbx/src/FBXReader.cpp b/libraries/fbx/src/FBXReader.cpp index 86422ef70c..81637e82a8 100644 --- a/libraries/fbx/src/FBXReader.cpp +++ b/libraries/fbx/src/FBXReader.cpp @@ -9,6 +9,8 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include "FBXReader.h" + #include #include #include @@ -31,7 +33,6 @@ #include #include -#include "FBXReader.h" #include "ModelFormatLogging.h" // TOOL: Uncomment the following line to enable the filtering of all the unkwnon fields of a node so we can break point easily while loading a model with problems... diff --git a/libraries/fbx/src/FSTReader.cpp b/libraries/fbx/src/FSTReader.cpp index cc4a919445..75596862d2 100644 --- a/libraries/fbx/src/FSTReader.cpp +++ b/libraries/fbx/src/FSTReader.cpp @@ -9,6 +9,8 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include "FSTReader.h" + #include #include #include @@ -17,8 +19,6 @@ #include #include -#include "FSTReader.h" - QVariantHash FSTReader::parseMapping(QIODevice* device) { QVariantHash properties; @@ -84,7 +84,7 @@ void FSTReader::writeVariant(QBuffer& buffer, QVariantHash::const_iterator& it) QByteArray FSTReader::writeMapping(const QVariantHash& mapping) { static const QStringList PREFERED_ORDER = QStringList() << NAME_FIELD << TYPE_FIELD << SCALE_FIELD << FILENAME_FIELD - << TEXDIR_FIELD << JOINT_FIELD << FREE_JOINT_FIELD + << TEXDIR_FIELD << SCRIPT_FIELD << JOINT_FIELD << FREE_JOINT_FIELD << BLENDSHAPE_FIELD << JOINT_INDEX_FIELD; QBuffer buffer; buffer.open(QIODevice::WriteOnly); @@ -92,7 +92,7 @@ QByteArray FSTReader::writeMapping(const QVariantHash& mapping) { for (auto key : PREFERED_ORDER) { auto it = mapping.find(key); if (it != mapping.constEnd()) { - if (key == FREE_JOINT_FIELD) { // writeVariant does not handle strings added using insertMulti. + if (key == FREE_JOINT_FIELD || key == SCRIPT_FIELD) { // writeVariant does not handle strings added using insertMulti. for (auto multi : mapping.values(key)) { buffer.write(key.toUtf8()); buffer.write(" = "); @@ -187,6 +187,26 @@ FSTReader::ModelType FSTReader::predictModelType(const QVariantHash& mapping) { return ENTITY_MODEL; } +QVector FSTReader::getScripts(const QUrl& url, const QVariantHash& mapping) { + + auto fstMapping = mapping.isEmpty() ? downloadMapping(url.toString()) : mapping; + QVector scriptPaths; + if (!fstMapping.value(SCRIPT_FIELD).isNull()) { + auto scripts = fstMapping.values(SCRIPT_FIELD).toVector(); + for (auto &script : scripts) { + QString scriptPath = script.toString(); + if (QUrl(scriptPath).isRelative()) { + if (scriptPath.at(0) == '/') { + scriptPath = scriptPath.right(scriptPath.length() - 1); + } + scriptPath = url.resolved(QUrl(scriptPath)).toString(); + } + scriptPaths.push_back(scriptPath); + } + } + return scriptPaths; +} + QVariantHash FSTReader::downloadMapping(const QString& url) { QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance(); QNetworkRequest networkRequest = QNetworkRequest(url); diff --git a/libraries/fbx/src/FSTReader.h b/libraries/fbx/src/FSTReader.h index 981bae4feb..4a8574f0cf 100644 --- a/libraries/fbx/src/FSTReader.h +++ b/libraries/fbx/src/FSTReader.h @@ -28,6 +28,7 @@ static const QString TRANSLATION_Z_FIELD = "tz"; static const QString JOINT_FIELD = "joint"; static const QString FREE_JOINT_FIELD = "freeJoint"; static const QString BLENDSHAPE_FIELD = "bs"; +static const QString SCRIPT_FIELD = "script"; class FSTReader { public: @@ -49,6 +50,8 @@ public: /// Predicts the type of model by examining the mapping static ModelType predictModelType(const QVariantHash& mapping); + static QVector getScripts(const QUrl& fstUrl, const QVariantHash& mapping = QVariantHash()); + static QString getNameFromType(ModelType modelType); static FSTReader::ModelType getTypeFromName(const QString& name); static QVariantHash downloadMapping(const QString& url); diff --git a/libraries/fbx/src/GLTFReader.cpp b/libraries/fbx/src/GLTFReader.cpp index 0c04b3d733..f322c2319e 100644 --- a/libraries/fbx/src/GLTFReader.cpp +++ b/libraries/fbx/src/GLTFReader.cpp @@ -9,6 +9,8 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include "GLTFReader.h" + #include #include #include @@ -28,7 +30,6 @@ #include #include -#include "GLTFReader.h" #include "FBXReader.h" @@ -1377,4 +1378,4 @@ void GLTFReader::fbxDebugDump(const FBXGeometry& fbxgeo) { } qCDebug(modelformat) << "\n"; -} \ No newline at end of file +} diff --git a/libraries/gl/src/gl/OffscreenGLCanvas.cpp b/libraries/gl/src/gl/OffscreenGLCanvas.cpp index 4a2c5fd7f7..91f7954943 100644 --- a/libraries/gl/src/gl/OffscreenGLCanvas.cpp +++ b/libraries/gl/src/gl/OffscreenGLCanvas.cpp @@ -17,15 +17,18 @@ #include #include #include +#include +#include #include #include #include +#include + #include "Context.h" #include "GLHelpers.h" #include "GLLogging.h" - OffscreenGLCanvas::OffscreenGLCanvas() : _context(new QOpenGLContext), _offscreenSurface(new QOffscreenSurface) @@ -33,6 +36,8 @@ OffscreenGLCanvas::OffscreenGLCanvas() : } OffscreenGLCanvas::~OffscreenGLCanvas() { + clearThreadContext(); + // A context with logging enabled needs to be current when it's destroyed _context->makeCurrent(_offscreenSurface); delete _context; @@ -117,25 +122,51 @@ QObject* OffscreenGLCanvas::getContextObject() { } void OffscreenGLCanvas::moveToThreadWithContext(QThread* thread) { + clearThreadContext(); moveToThread(thread); _context->moveToThread(thread); } -static const char* THREAD_CONTEXT_PROPERTY = "offscreenGlCanvas"; +struct ThreadContextStorage : public Dependency { + QThreadStorage> threadContext; +}; void OffscreenGLCanvas::setThreadContext() { - QThread::currentThread()->setProperty(THREAD_CONTEXT_PROPERTY, QVariant::fromValue(this)); + if (!DependencyManager::isSet()) { + DependencyManager::set(); + } + auto threadContextStorage = DependencyManager::get(); + QPointer p(this); + threadContextStorage->threadContext.setLocalData(p); +} + +void OffscreenGLCanvas::clearThreadContext() { + if (!DependencyManager::isSet()) { + return; + } + auto threadContextStorage = DependencyManager::get(); + if (!threadContextStorage->threadContext.hasLocalData()) { + return; + } + auto& threadContext = threadContextStorage->threadContext.localData(); + if (this != threadContext.operator OffscreenGLCanvas *()) { + return; + } + threadContextStorage->threadContext.setLocalData(nullptr); } bool OffscreenGLCanvas::restoreThreadContext() { // Restore the rendering context for this thread - auto threadCanvasVariant = QThread::currentThread()->property(THREAD_CONTEXT_PROPERTY); - if (!threadCanvasVariant.isValid()) { + if (!DependencyManager::isSet()) { return false; } - auto threadCanvasObject = qvariant_cast(threadCanvasVariant); - auto threadCanvas = static_cast(threadCanvasObject); + auto threadContextStorage = DependencyManager::get(); + if (!threadContextStorage->threadContext.hasLocalData()) { + return false; + } + + auto threadCanvas = threadContextStorage->threadContext.localData(); if (!threadCanvas) { return false; } diff --git a/libraries/gl/src/gl/OffscreenGLCanvas.h b/libraries/gl/src/gl/OffscreenGLCanvas.h index ed644b98fb..a4960ae234 100644 --- a/libraries/gl/src/gl/OffscreenGLCanvas.h +++ b/libraries/gl/src/gl/OffscreenGLCanvas.h @@ -39,6 +39,8 @@ private slots: void onMessageLogged(const QOpenGLDebugMessage &debugMessage); protected: + void clearThreadContext(); + std::once_flag _reportOnce; QOpenGLContext* _context{ nullptr }; QOffscreenSurface* _offscreenSurface{ nullptr }; diff --git a/libraries/gpu-gl-common/src/gpu/gl/GLBackend.h b/libraries/gpu-gl-common/src/gpu/gl/GLBackend.h index 5bbb44f9e1..314bbee387 100644 --- a/libraries/gpu-gl-common/src/gpu/gl/GLBackend.h +++ b/libraries/gpu-gl-common/src/gpu/gl/GLBackend.h @@ -91,7 +91,7 @@ public: // this is the maximum per shader stage on the low end apple // TODO make it platform dependant at init time - static const int MAX_NUM_UNIFORM_BUFFERS = 12; + static const int MAX_NUM_UNIFORM_BUFFERS = 14; size_t getMaxNumUniformBuffers() const { return MAX_NUM_UNIFORM_BUFFERS; } // this is the maximum per shader stage on the low end apple diff --git a/libraries/gpu-gl-common/src/gpu/gl/GLBackendOutput.cpp b/libraries/gpu-gl-common/src/gpu/gl/GLBackendOutput.cpp index 2285b0e486..d1ab34da90 100644 --- a/libraries/gpu-gl-common/src/gpu/gl/GLBackendOutput.cpp +++ b/libraries/gpu-gl-common/src/gpu/gl/GLBackendOutput.cpp @@ -46,10 +46,10 @@ void GLBackend::do_setFramebuffer(const Batch& batch, size_t paramOffset) { } void GLBackend::do_setFramebufferSwapChain(const Batch& batch, size_t paramOffset) { - auto swapChain = batch._swapChains.get(batch._params[paramOffset]._uint); + auto swapChain = std::static_pointer_cast(batch._swapChains.get(batch._params[paramOffset]._uint)); if (swapChain) { auto index = batch._params[paramOffset + 1]._uint; - FramebufferPointer framebuffer = static_cast(swapChain.get())->get(index); + const auto& framebuffer = swapChain->get(index); setFramebuffer(framebuffer); } } diff --git a/libraries/gpu-gl-common/src/gpu/gl/GLBackendPipeline.cpp b/libraries/gpu-gl-common/src/gpu/gl/GLBackendPipeline.cpp index 58fcc51605..91f1d8bb8c 100644 --- a/libraries/gpu-gl-common/src/gpu/gl/GLBackendPipeline.cpp +++ b/libraries/gpu-gl-common/src/gpu/gl/GLBackendPipeline.cpp @@ -268,7 +268,7 @@ void GLBackend::do_setResourceFramebufferSwapChainTexture(const Batch& batch, si return; } - SwapChainPointer swapChain = batch._swapChains.get(batch._params[paramOffset + 0]._uint); + auto swapChain = std::static_pointer_cast(batch._swapChains.get(batch._params[paramOffset + 0]._uint)); if (!swapChain) { releaseResourceTexture(slot); @@ -276,9 +276,8 @@ void GLBackend::do_setResourceFramebufferSwapChainTexture(const Batch& batch, si } auto index = batch._params[paramOffset + 2]._uint; auto renderBufferSlot = batch._params[paramOffset + 3]._uint; - FramebufferPointer resourceFramebuffer = static_cast(swapChain.get())->get(index); - TexturePointer resourceTexture = resourceFramebuffer->getRenderBuffer(renderBufferSlot); - + auto resourceFramebuffer = swapChain->get(index); + auto resourceTexture = resourceFramebuffer->getRenderBuffer(renderBufferSlot); setResourceTexture(slot, resourceTexture); } diff --git a/libraries/gpu-gl/src/gpu/gl41/GL41Backend.h b/libraries/gpu-gl/src/gpu/gl41/GL41Backend.h index 9479321747..f3b452b1f9 100644 --- a/libraries/gpu-gl/src/gpu/gl41/GL41Backend.h +++ b/libraries/gpu-gl/src/gpu/gl41/GL41Backend.h @@ -52,6 +52,8 @@ public: static const std::string GL41_VERSION; const std::string& getVersion() const override { return GL41_VERSION; } + bool supportedTextureFormat(const gpu::Element& format) override; + class GL41Texture : public GLTexture { using Parent = GLTexture; friend class GL41Backend; @@ -173,8 +175,6 @@ protected: void makeProgramBindings(ShaderObject& shaderObject) override; int makeResourceBufferSlots(GLuint glprogram, const Shader::BindingSet& slotBindings,Shader::SlotSet& resourceBuffers) override; - static bool supportedTextureFormat(const gpu::Element& format); - }; } } diff --git a/libraries/gpu-gl/src/gpu/gl45/GL45Backend.h b/libraries/gpu-gl/src/gpu/gl45/GL45Backend.h index c23a83eaf9..616b6d1075 100644 --- a/libraries/gpu-gl/src/gpu/gl45/GL45Backend.h +++ b/libraries/gpu-gl/src/gpu/gl45/GL45Backend.h @@ -54,6 +54,8 @@ public: static const std::string GL45_VERSION; const std::string& getVersion() const override { return GL45_VERSION; } + bool supportedTextureFormat(const gpu::Element& format) override; + class GL45Texture : public GLTexture { using Parent = GLTexture; friend class GL45Backend; diff --git a/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp b/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp index 4d5ffefa67..6b3c99ccc3 100644 --- a/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp +++ b/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp @@ -32,6 +32,24 @@ using namespace gpu::gl45; #define FORCE_STRICT_TEXTURE 0 #define ENABLE_SPARSE_TEXTURE 0 +bool GL45Backend::supportedTextureFormat(const gpu::Element& format) { + switch (format.getSemantic()) { + case gpu::Semantic::COMPRESSED_ETC2_RGB: + case gpu::Semantic::COMPRESSED_ETC2_SRGB: + case gpu::Semantic::COMPRESSED_ETC2_RGB_PUNCHTHROUGH_ALPHA: + case gpu::Semantic::COMPRESSED_ETC2_SRGB_PUNCHTHROUGH_ALPHA: + case gpu::Semantic::COMPRESSED_ETC2_RGBA: + case gpu::Semantic::COMPRESSED_ETC2_SRGBA: + case gpu::Semantic::COMPRESSED_EAC_RED: + case gpu::Semantic::COMPRESSED_EAC_RED_SIGNED: + case gpu::Semantic::COMPRESSED_EAC_XY: + case gpu::Semantic::COMPRESSED_EAC_XY_SIGNED: + return false; + default: + return true; + } +} + GLTexture* GL45Backend::syncGPUObject(const TexturePointer& texturePointer) { if (!texturePointer) { return nullptr; diff --git a/libraries/gpu-gles/src/gpu/gles/GLESBackend.h b/libraries/gpu-gles/src/gpu/gles/GLESBackend.h index 38e28e630a..47a123718a 100644 --- a/libraries/gpu-gles/src/gpu/gles/GLESBackend.h +++ b/libraries/gpu-gles/src/gpu/gles/GLESBackend.h @@ -32,7 +32,6 @@ public: static const GLint RESOURCE_TRANSFER_EXTRA_TEX_UNIT { 33 }; static const GLint RESOURCE_BUFFER_TEXBUF_TEX_UNIT { 34 }; static const GLint RESOURCE_BUFFER_SLOT0_TEX_UNIT { 35 }; - static bool supportedTextureFormat(const gpu::Element& format); explicit GLESBackend(bool syncCache) : Parent(syncCache) {} GLESBackend() : Parent() {} virtual ~GLESBackend() { @@ -40,6 +39,8 @@ public: // which is pure virtual from GLBackend's dtor. resetStages(); } + + bool supportedTextureFormat(const gpu::Element& format) override; static const std::string GLES_VERSION; const std::string& getVersion() const override { return GLES_VERSION; } diff --git a/libraries/gpu/src/gpu/Batch.cpp b/libraries/gpu/src/gpu/Batch.cpp index 84a7c275f0..90115806b4 100644 --- a/libraries/gpu/src/gpu/Batch.cpp +++ b/libraries/gpu/src/gpu/Batch.cpp @@ -34,7 +34,7 @@ ProfileRangeBatch::~ProfileRangeBatch() { using namespace gpu; // FIXME make these backend / pipeline dependent. -static const int MAX_NUM_UNIFORM_BUFFERS = 12; +static const int MAX_NUM_UNIFORM_BUFFERS = 14; static const int MAX_NUM_RESOURCE_BUFFERS = 16; static const int MAX_NUM_RESOURCE_TEXTURES = 16; diff --git a/libraries/gpu/src/gpu/Context.h b/libraries/gpu/src/gpu/Context.h index eda8fee596..8c5a4d493e 100644 --- a/libraries/gpu/src/gpu/Context.h +++ b/libraries/gpu/src/gpu/Context.h @@ -64,6 +64,8 @@ public: virtual void recycle() const = 0; virtual void downloadFramebuffer(const FramebufferPointer& srcFramebuffer, const Vec4i& region, QImage& destImage) = 0; + virtual bool supportedTextureFormat(const gpu::Element& format) = 0; + // Shared header between C++ and GLSL #include "TransformCamera_shared.slh" diff --git a/libraries/gpu/src/gpu/Format.h b/libraries/gpu/src/gpu/Format.h index d4e4a89636..7a3e0a2f82 100644 --- a/libraries/gpu/src/gpu/Format.h +++ b/libraries/gpu/src/gpu/Format.h @@ -50,47 +50,50 @@ enum Type : uint8_t { }; // Array providing the size in bytes for a given scalar type static const int TYPE_SIZE[NUM_TYPES] = { - 4, - 4, - 4, - 2, - 2, - 2, - 1, - 1, + 4, // FLOAT + 4, // INT32 + 4, // UINT32 + 2, // HALF + 2, // INT16 + 2, // UINT16 + 1, // INT8 + 1, // UINT8 // normalized values - 4, - 4, - 2, - 2, - 1, - 1, - 4, + 4, // NINT32 + 4, // NUINT32 + 2, // NINT16 + 2, // NUINT16 + 1, // NINT8 + 1, // NUINT8 + 1, // NUINT2 + 1, // NINT2_10_10_10 - 1 + 1, // COMPRESSED }; + // Array answering the question Does this type is integer or not static const bool TYPE_IS_INTEGER[NUM_TYPES] = { - false, - true, - true, - false, - true, - true, - true, - true, + false, // FLOAT + true, // INT32 + true, // UINT32 + false, // HALF + true, // INT16 + true, // UINT16 + true, // INT8 + true, // UINT8 // Normalized values - false, - false, - false, - false, - false, - false, - false, + false, // NINT32 + false, // NUINT32 + false, // NINT16 + false, // NUINT16 + false, // NINT8 + false, // NUINT8 + false, // NUINT2 + false, // NINT2_10_10_10 - false, + false, // COMPRESSED }; // Dimension of an Element @@ -367,9 +370,9 @@ public: static const Element PART_DRAWCALL; protected: - uint8 _semantic; - uint8 _dimension : 4; - uint8 _type : 4; + uint16 _semantic : 7; + uint16 _dimension : 4; + uint16 _type : 5; }; diff --git a/libraries/gpu/src/gpu/ResourceSwapChain.h b/libraries/gpu/src/gpu/ResourceSwapChain.h index 7b46b35521..28c5ff2ed3 100644 --- a/libraries/gpu/src/gpu/ResourceSwapChain.h +++ b/libraries/gpu/src/gpu/ResourceSwapChain.h @@ -15,18 +15,18 @@ namespace gpu { class SwapChain { public: - SwapChain(unsigned int size = 2U) : _size{ size } {} + SwapChain(uint8_t size = 2U) : _size{ size } {} virtual ~SwapChain() {} void advance() { _frontIndex = (_frontIndex + 1) % _size; } - unsigned int getSize() const { return _size; } + uint8_t getSize() const { return _size; } protected: - unsigned int _size; - unsigned int _frontIndex{ 0U }; + const uint8_t _size; + uint8_t _frontIndex{ 0U }; }; typedef std::shared_ptr SwapChainPointer; @@ -41,16 +41,13 @@ namespace gpu { using Type = R; using TypePointer = std::shared_ptr; + using TypeConstPointer = std::shared_ptr; - ResourceSwapChain(unsigned int size = 2U) : SwapChain{ size } {} - - void reset() { - for (auto& ptr : _resources) { - ptr.reset(); + ResourceSwapChain(const std::vector& v) : SwapChain{ std::min((uint8_t)v.size(), MAX_SIZE) } { + for (size_t i = 0; i < _size; ++i) { + _resources[i] = v[i]; } } - - TypePointer& edit(unsigned int index) { return _resources[(index + _frontIndex) % _size]; } const TypePointer& get(unsigned int index) const { return _resources[(index + _frontIndex) % _size]; } private: diff --git a/libraries/gpu/src/gpu/Texture.h b/libraries/gpu/src/gpu/Texture.h index 4d82aba595..09b2bc9475 100755 --- a/libraries/gpu/src/gpu/Texture.h +++ b/libraries/gpu/src/gpu/Texture.h @@ -37,6 +37,10 @@ namespace ktx { using KeyValues = std::list; } +namespace khronos { namespace gl { namespace texture { + enum class InternalFormat: uint32_t; +}}} + namespace gpu { @@ -565,6 +569,7 @@ public: static bool evalKTXFormat(const Element& mipFormat, const Element& texelFormat, ktx::Header& header); static bool evalTextureFormat(const ktx::Header& header, Element& mipFormat, Element& texelFormat); + static bool getCompressedFormat(khronos::gl::texture::InternalFormat format, Element& elFormat); protected: const TextureUsageType _usageType; diff --git a/libraries/gpu/src/gpu/Texture_ktx.cpp b/libraries/gpu/src/gpu/Texture_ktx.cpp index 5e354c0a5c..129c125411 100644 --- a/libraries/gpu/src/gpu/Texture_ktx.cpp +++ b/libraries/gpu/src/gpu/Texture_ktx.cpp @@ -46,13 +46,14 @@ struct GPUKTXPayload { memcpy(data, &_samplerDesc, sizeof(Sampler::Desc)); data += sizeof(Sampler::Desc); - + // We can't copy the bitset in Texture::Usage in a crossplateform manner // So serialize it manually - *(uint32*)data = _usage._flags.to_ulong(); + uint32 usageData = _usage._flags.to_ulong(); + memcpy(data, &usageData, sizeof(uint32)); data += sizeof(uint32); - *(TextureUsageType*)data = _usageType; + memcpy(data, &_usageType, sizeof(TextureUsageType)); data += sizeof(TextureUsageType); return data + PADDING; @@ -77,13 +78,15 @@ struct GPUKTXPayload { memcpy(&_samplerDesc, data, sizeof(Sampler::Desc)); data += sizeof(Sampler::Desc); - + // We can't copy the bitset in Texture::Usage in a crossplateform manner // So unserialize it manually - _usage = Texture::Usage(*(const uint32*)data); + uint32 usageData; + memcpy(&usageData, data, sizeof(uint32)); + _usage = Texture::Usage(usageData); data += sizeof(uint32); - _usageType = *(const TextureUsageType*)data; + memcpy(&_usageType, data, sizeof(TextureUsageType)); return true; } @@ -619,6 +622,47 @@ bool Texture::evalKTXFormat(const Element& mipFormat, const Element& texelFormat return true; } +bool Texture::getCompressedFormat(ktx::GLInternalFormat format, Element& elFormat) { + if (format == ktx::GLInternalFormat::COMPRESSED_SRGB_S3TC_DXT1_EXT) { + elFormat = Format::COLOR_COMPRESSED_BCX_SRGB; + } else if (format == ktx::GLInternalFormat::COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT) { + elFormat = Format::COLOR_COMPRESSED_BCX_SRGBA_MASK; + } else if (format == ktx::GLInternalFormat::COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT) { + elFormat = Format::COLOR_COMPRESSED_BCX_SRGBA; + } else if (format == ktx::GLInternalFormat::COMPRESSED_RED_RGTC1) { + elFormat = Format::COLOR_COMPRESSED_BCX_RED; + } else if (format == ktx::GLInternalFormat::COMPRESSED_RG_RGTC2) { + elFormat = Format::COLOR_COMPRESSED_BCX_XY; + } else if (format == ktx::GLInternalFormat::COMPRESSED_SRGB_ALPHA_BPTC_UNORM) { + elFormat = Format::COLOR_COMPRESSED_BCX_SRGBA_HIGH; + } else if (format == ktx::GLInternalFormat::COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT) { + elFormat = Format::COLOR_COMPRESSED_BCX_HDR_RGB; + } else if (format == ktx::GLInternalFormat::COMPRESSED_RGB8_ETC2) { + elFormat = Format::COLOR_COMPRESSED_ETC2_RGB; + } else if (format == ktx::GLInternalFormat::COMPRESSED_SRGB8_ETC2) { + elFormat = Format::COLOR_COMPRESSED_ETC2_SRGB; + } else if (format == ktx::GLInternalFormat::COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2) { + elFormat = Format::COLOR_COMPRESSED_ETC2_RGB_PUNCHTHROUGH_ALPHA; + } else if (format == ktx::GLInternalFormat::COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2) { + elFormat = Format::COLOR_COMPRESSED_ETC2_SRGB_PUNCHTHROUGH_ALPHA; + } else if (format == ktx::GLInternalFormat::COMPRESSED_RGBA8_ETC2_EAC) { + elFormat = Format::COLOR_COMPRESSED_ETC2_RGBA; + } else if (format == ktx::GLInternalFormat::COMPRESSED_SRGB8_ALPHA8_ETC2_EAC) { + elFormat = Format::COLOR_COMPRESSED_ETC2_SRGBA; + } else if (format == ktx::GLInternalFormat::COMPRESSED_R11_EAC) { + elFormat = Format::COLOR_COMPRESSED_EAC_RED; + } else if (format == ktx::GLInternalFormat::COMPRESSED_SIGNED_R11_EAC) { + elFormat = Format::COLOR_COMPRESSED_EAC_RED_SIGNED; + } else if (format == ktx::GLInternalFormat::COMPRESSED_RG11_EAC) { + elFormat = Format::COLOR_COMPRESSED_EAC_XY; + } else if (format == ktx::GLInternalFormat::COMPRESSED_SIGNED_RG11_EAC) { + elFormat = Format::COLOR_COMPRESSED_EAC_XY_SIGNED; + } else { + return false; + } + return true; +} + bool Texture::evalTextureFormat(const ktx::Header& header, Element& mipFormat, Element& texelFormat) { if (header.getGLFormat() == ktx::GLFormat::BGRA && header.getGLType() == ktx::GLType::UNSIGNED_BYTE && header.getTypeSize() == 1) { if (header.getGLInternaFormat() == ktx::GLInternalFormat::RGBA8) { @@ -661,41 +705,7 @@ bool Texture::evalTextureFormat(const ktx::Header& header, Element& mipFormat, E mipFormat = Format::COLOR_RGB9E5; texelFormat = Format::COLOR_RGB9E5; } else if (header.isCompressed()) { - if (header.getGLInternaFormat() == ktx::GLInternalFormat::COMPRESSED_SRGB_S3TC_DXT1_EXT) { - texelFormat = Format::COLOR_COMPRESSED_BCX_SRGB; - } else if (header.getGLInternaFormat() == ktx::GLInternalFormat::COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT) { - texelFormat = Format::COLOR_COMPRESSED_BCX_SRGBA_MASK; - } else if (header.getGLInternaFormat() == ktx::GLInternalFormat::COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT) { - texelFormat = Format::COLOR_COMPRESSED_BCX_SRGBA; - } else if (header.getGLInternaFormat() == ktx::GLInternalFormat::COMPRESSED_RED_RGTC1) { - texelFormat = Format::COLOR_COMPRESSED_BCX_RED; - } else if (header.getGLInternaFormat() == ktx::GLInternalFormat::COMPRESSED_RG_RGTC2) { - texelFormat = Format::COLOR_COMPRESSED_BCX_XY; - } else if (header.getGLInternaFormat() == ktx::GLInternalFormat::COMPRESSED_SRGB_ALPHA_BPTC_UNORM) { - texelFormat = Format::COLOR_COMPRESSED_BCX_SRGBA_HIGH; - } else if (header.getGLInternaFormat() == ktx::GLInternalFormat::COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT) { - texelFormat = Format::COLOR_COMPRESSED_BCX_HDR_RGB; - } else if (header.getGLInternaFormat() == ktx::GLInternalFormat::COMPRESSED_RGB8_ETC2) { - texelFormat = Format::COLOR_COMPRESSED_ETC2_RGB; - } else if (header.getGLInternaFormat() == ktx::GLInternalFormat::COMPRESSED_SRGB8_ETC2) { - texelFormat = Format::COLOR_COMPRESSED_ETC2_SRGB; - } else if (header.getGLInternaFormat() == ktx::GLInternalFormat::COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2) { - texelFormat = Format::COLOR_COMPRESSED_ETC2_RGB_PUNCHTHROUGH_ALPHA; - } else if (header.getGLInternaFormat() == ktx::GLInternalFormat::COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2) { - texelFormat = Format::COLOR_COMPRESSED_ETC2_SRGB_PUNCHTHROUGH_ALPHA; - } else if (header.getGLInternaFormat() == ktx::GLInternalFormat::COMPRESSED_RGBA8_ETC2_EAC) { - texelFormat = Format::COLOR_COMPRESSED_ETC2_RGBA; - } else if (header.getGLInternaFormat() == ktx::GLInternalFormat::COMPRESSED_SRGB8_ALPHA8_ETC2_EAC) { - texelFormat = Format::COLOR_COMPRESSED_ETC2_SRGBA; - } else if (header.getGLInternaFormat() == ktx::GLInternalFormat::COMPRESSED_R11_EAC) { - texelFormat = Format::COLOR_COMPRESSED_EAC_RED; - } else if (header.getGLInternaFormat() == ktx::GLInternalFormat::COMPRESSED_SIGNED_R11_EAC) { - texelFormat = Format::COLOR_COMPRESSED_EAC_RED_SIGNED; - } else if (header.getGLInternaFormat() == ktx::GLInternalFormat::COMPRESSED_RG11_EAC) { - texelFormat = Format::COLOR_COMPRESSED_EAC_XY; - } else if (header.getGLInternaFormat() == ktx::GLInternalFormat::COMPRESSED_SIGNED_RG11_EAC) { - texelFormat = Format::COLOR_COMPRESSED_EAC_XY_SIGNED; - } else { + if (!getCompressedFormat(header.getGLInternaFormat(), texelFormat)) { return false; } mipFormat = texelFormat; @@ -703,4 +713,4 @@ bool Texture::evalTextureFormat(const ktx::Header& header, Element& mipFormat, E return false; } return true; -} \ No newline at end of file +} diff --git a/libraries/graphics-scripting/src/graphics-scripting/GraphicsScriptingInterface.h b/libraries/graphics-scripting/src/graphics-scripting/GraphicsScriptingInterface.h index 526352804b..b88c6345cf 100644 --- a/libraries/graphics-scripting/src/graphics-scripting/GraphicsScriptingInterface.h +++ b/libraries/graphics-scripting/src/graphics-scripting/GraphicsScriptingInterface.h @@ -24,6 +24,9 @@ /**jsdoc * The experimental Graphics API (experimental) lets you query and manage certain graphics-related structures (like underlying meshes and textures) from scripting. * @namespace Graphics + * + * @hifi-interface + * @hifi-client-entity */ class GraphicsScriptingInterface : public QObject, public QScriptable, public Dependency { @@ -39,7 +42,7 @@ public slots: * * @function Graphics.getModel * @param {UUID} entityID - The objectID of the model whose meshes are to be retrieved. - * @return {Graphics.Model} the resulting Model object + * @returns {Graphics.Model} the resulting Model object */ scriptable::ScriptableModelPointer getModel(QUuid uuid); @@ -54,7 +57,7 @@ public slots: * * @function Graphics.newMesh * @param {Graphics.IFSData} ifsMeshData Index-Faced Set (IFS) arrays used to create the new mesh. - * @return {Graphics.Mesh} the resulting Mesh / Mesh Part object + * @returns {Graphics.Mesh} the resulting Mesh / Mesh Part object */ /**jsdoc * @typedef {object} Graphics.IFSData diff --git a/libraries/graphics-scripting/src/graphics-scripting/ScriptableMesh.cpp b/libraries/graphics-scripting/src/graphics-scripting/ScriptableMesh.cpp index 8e6d4bec9b..585a719638 100644 --- a/libraries/graphics-scripting/src/graphics-scripting/ScriptableMesh.cpp +++ b/libraries/graphics-scripting/src/graphics-scripting/ScriptableMesh.cpp @@ -5,22 +5,24 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -#include "Forward.h" - #include "ScriptableMesh.h" -#include "ScriptableMeshPart.h" -#include "GraphicsScriptingUtil.h" -#include "OBJWriter.h" -#include #include -#include + #include #include #include + +#include #include #include #include +#include + +#include "Forward.h" +#include "ScriptableMeshPart.h" +#include "GraphicsScriptingUtil.h" +#include "OBJWriter.h" // #define SCRIPTABLE_MESH_DEBUG 1 diff --git a/libraries/graphics-scripting/src/graphics-scripting/ScriptableMeshPart.cpp b/libraries/graphics-scripting/src/graphics-scripting/ScriptableMeshPart.cpp index 4414b0ad7e..192071d3af 100644 --- a/libraries/graphics-scripting/src/graphics-scripting/ScriptableMeshPart.cpp +++ b/libraries/graphics-scripting/src/graphics-scripting/ScriptableMeshPart.cpp @@ -5,22 +5,23 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -#include "Forward.h" - #include "ScriptableMeshPart.h" -#include "GraphicsScriptingUtil.h" -#include "OBJWriter.h" -#include -#include -#include #include #include #include + +#include +#include +#include #include #include #include +#include "Forward.h" +#include "GraphicsScriptingUtil.h" +#include "OBJWriter.h" + QString scriptable::ScriptableMeshPart::toOBJ() { if (!getMeshPointer()) { diff --git a/libraries/graphics-scripting/src/graphics-scripting/ScriptableModel.cpp b/libraries/graphics-scripting/src/graphics-scripting/ScriptableModel.cpp index c65764a225..7aaa182163 100644 --- a/libraries/graphics-scripting/src/graphics-scripting/ScriptableModel.cpp +++ b/libraries/graphics-scripting/src/graphics-scripting/ScriptableModel.cpp @@ -8,14 +8,13 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -#include "GraphicsScriptingUtil.h" #include "ScriptableModel.h" -#include "ScriptableMesh.h" #include +#include "GraphicsScriptingUtil.h" +#include "ScriptableMesh.h" #include "graphics/Material.h" - #include "image/Image.h" // #define SCRIPTABLE_MESH_DEBUG 1 diff --git a/libraries/graphics/src/graphics/Haze.cpp b/libraries/graphics/src/graphics/Haze.cpp index dfe70175f4..d5a060b90b 100644 --- a/libraries/graphics/src/graphics/Haze.cpp +++ b/libraries/graphics/src/graphics/Haze.cpp @@ -9,9 +9,10 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -#include #include "Haze.h" +#include + using namespace graphics; const float Haze::INITIAL_HAZE_RANGE{ 1000.0f }; diff --git a/libraries/input-plugins/src/input-plugins/TouchscreenVirtualPadDevice.cpp b/libraries/input-plugins/src/input-plugins/TouchscreenVirtualPadDevice.cpp index 957104bd30..7ee2135325 100644 --- a/libraries/input-plugins/src/input-plugins/TouchscreenVirtualPadDevice.cpp +++ b/libraries/input-plugins/src/input-plugins/TouchscreenVirtualPadDevice.cpp @@ -43,6 +43,18 @@ void TouchscreenVirtualPadDevice::init() { _fixedPosition = true; // This should be config _viewTouchUpdateCount = 0; + resize(); + + auto& virtualPadManager = VirtualPad::Manager::instance(); + + if (_fixedPosition) { + virtualPadManager.getLeftVirtualPad()->setShown(virtualPadManager.isEnabled() && !virtualPadManager.isHidden()); // Show whenever it's enabled + } + + KeyboardMouseDevice::enableTouch(false); // Touch for view controls is managed by this plugin +} + +void TouchscreenVirtualPadDevice::resize() { QScreen* eventScreen = qApp->primaryScreen(); if (_screenDPIProvided != eventScreen->physicalDotsPerInch()) { _screenWidthCenter = eventScreen->size().width() / 2; @@ -59,12 +71,6 @@ void TouchscreenVirtualPadDevice::init() { auto& virtualPadManager = VirtualPad::Manager::instance(); setupControlsPositions(virtualPadManager, true); - - if (_fixedPosition) { - virtualPadManager.getLeftVirtualPad()->setShown(virtualPadManager.isEnabled() && !virtualPadManager.isHidden()); // Show whenever it's enabled - } - - KeyboardMouseDevice::enableTouch(false); // Touch for view controls is managed by this plugin } void TouchscreenVirtualPadDevice::setupControlsPositions(VirtualPad::Manager& virtualPadManager, bool force) { @@ -80,9 +86,10 @@ void TouchscreenVirtualPadDevice::setupControlsPositions(VirtualPad::Manager& vi virtualPadManager.getLeftVirtualPad()->setFirstTouch(_moveRefTouchPoint); // Jump button - float leftMargin = _screenDPI * VirtualPad::Manager::JUMP_BTN_LEFT_MARGIN_PIXELS / VirtualPad::Manager::DPI; + float jumpBtnPixelSize = _screenDPI * VirtualPad::Manager::JUMP_BTN_FULL_PIXELS / VirtualPad::Manager::DPI; + float rightMargin = _screenDPI * VirtualPad::Manager::JUMP_BTN_RIGHT_MARGIN_PIXELS / VirtualPad::Manager::DPI; float bottomMargin = _screenDPI * VirtualPad::Manager::JUMP_BTN_BOTTOM_MARGIN_PIXELS/ VirtualPad::Manager::DPI; - _jumpButtonPosition = glm::vec2( _jumpButtonRadius + leftMargin, eventScreen->size().height() - bottomMargin - _jumpButtonRadius - _extraBottomMargin); + _jumpButtonPosition = glm::vec2( eventScreen->size().width() - rightMargin - jumpBtnPixelSize, eventScreen->size().height() - bottomMargin - _jumpButtonRadius - _extraBottomMargin); virtualPadManager.setJumpButtonPosition(_jumpButtonPosition); } diff --git a/libraries/input-plugins/src/input-plugins/TouchscreenVirtualPadDevice.h b/libraries/input-plugins/src/input-plugins/TouchscreenVirtualPadDevice.h index 212b7633ec..e7e540b503 100644 --- a/libraries/input-plugins/src/input-plugins/TouchscreenVirtualPadDevice.h +++ b/libraries/input-plugins/src/input-plugins/TouchscreenVirtualPadDevice.h @@ -26,6 +26,7 @@ public: // Plugin functions virtual void init() override; + virtual void resize(); virtual bool isSupported() const override; virtual const QString getName() const override { return NAME; } diff --git a/libraries/ktx/src/TextureMeta.cpp b/libraries/ktx/src/TextureMeta.cpp new file mode 100644 index 0000000000..3a2abf24c4 --- /dev/null +++ b/libraries/ktx/src/TextureMeta.cpp @@ -0,0 +1,64 @@ +// +// TextureMeta.cpp +// libraries/shared/src +// +// Created by Ryan Huffman on 04/10/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 +// + +#include "TextureMeta.h" + +#include +#include +#include + +const QString TEXTURE_META_EXTENSION = ".texmeta.json"; + +bool TextureMeta::deserialize(const QByteArray& data, TextureMeta* meta) { + QJsonParseError error; + auto doc = QJsonDocument::fromJson(data, &error); + if (error.error != QJsonParseError::NoError) { + qDebug() << "Failed to parse TextureMeta:" << error.errorString(); + return false; + } + if (!doc.isObject()) { + qDebug() << "Unable to process TextureMeta: top-level value is not an Object"; + return false; + } + + auto root = doc.object(); + if (root.contains("original")) { + meta->original = root["original"].toString(); + } + if (root.contains("compressed")) { + auto compressed = root["compressed"].toObject(); + for (auto it = compressed.constBegin(); it != compressed.constEnd(); it++) { + khronos::gl::texture::InternalFormat format; + auto formatName = it.key().toLatin1(); + if (khronos::gl::texture::fromString(formatName.constData(), &format)) { + meta->availableTextureTypes[format] = it.value().toString(); + } + } + } + + return true; +} + +QByteArray TextureMeta::serialize() { + QJsonDocument doc; + QJsonObject root; + QJsonObject compressed; + + for (auto kv : availableTextureTypes) { + const char* name = khronos::gl::texture::toString(kv.first); + compressed[name] = kv.second.toString(); + } + root["original"] = original.toString(); + root["compressed"] = compressed; + doc.setObject(root); + + return doc.toJson(); +} diff --git a/libraries/ktx/src/TextureMeta.h b/libraries/ktx/src/TextureMeta.h new file mode 100644 index 0000000000..6582c29e70 --- /dev/null +++ b/libraries/ktx/src/TextureMeta.h @@ -0,0 +1,42 @@ +// +// TextureMeta.h +// libraries/shared/src +// +// Created by Ryan Huffman on 04/10/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 +// + +#ifndef hifi_TextureMeta_h +#define hifi_TextureMeta_h + +#include +#include +#include + +#include "khronos/KHR.h" + +extern const QString TEXTURE_META_EXTENSION; + +namespace std { + template<> struct hash { + using enum_type = std::underlying_type::type; + typedef std::size_t result_type; + result_type operator()(khronos::gl::texture::InternalFormat const& v) const noexcept { + return std::hash()(static_cast(v)); + } + }; +} + +struct TextureMeta { + static bool deserialize(const QByteArray& data, TextureMeta* meta); + QByteArray serialize(); + + QUrl original; + std::unordered_map availableTextureTypes; +}; + + +#endif // hifi_TextureMeta_h diff --git a/libraries/ktx/src/khronos/KHR.h b/libraries/ktx/src/khronos/KHR.h index 4ee893e4fc..617e40ce06 100644 --- a/libraries/ktx/src/khronos/KHR.h +++ b/libraries/ktx/src/khronos/KHR.h @@ -10,6 +10,8 @@ #ifndef khronos_khr_hpp #define khronos_khr_hpp +#include + namespace khronos { namespace gl { @@ -209,6 +211,63 @@ namespace khronos { COMPRESSED_SIGNED_RG11_EAC = 0x9273, }; + static std::unordered_map nameToFormat { + { "COMPRESSED_RED", InternalFormat::COMPRESSED_RED }, + { "COMPRESSED_RG", InternalFormat::COMPRESSED_RG }, + { "COMPRESSED_RGB", InternalFormat::COMPRESSED_RGB }, + { "COMPRESSED_RGBA", InternalFormat::COMPRESSED_RGBA }, + + { "COMPRESSED_SRGB", InternalFormat::COMPRESSED_SRGB }, + { "COMPRESSED_SRGB_ALPHA", InternalFormat::COMPRESSED_SRGB_ALPHA }, + + { "COMPRESSED_ETC1_RGB8_OES", InternalFormat::COMPRESSED_ETC1_RGB8_OES }, + + { "COMPRESSED_SRGB_S3TC_DXT1_EXT", InternalFormat::COMPRESSED_SRGB_S3TC_DXT1_EXT }, + { "COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT", InternalFormat::COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT }, + { "COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT", InternalFormat::COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT }, + { "COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT", InternalFormat::COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT }, + + { "COMPRESSED_RED_RGTC1", InternalFormat::COMPRESSED_RED_RGTC1 }, + { "COMPRESSED_SIGNED_RED_RGTC1", InternalFormat::COMPRESSED_SIGNED_RED_RGTC1 }, + { "COMPRESSED_RG_RGTC2", InternalFormat::COMPRESSED_RG_RGTC2 }, + { "COMPRESSED_SIGNED_RG_RGTC2", InternalFormat::COMPRESSED_SIGNED_RG_RGTC2 }, + + { "COMPRESSED_RGBA_BPTC_UNORM", InternalFormat::COMPRESSED_RGBA_BPTC_UNORM }, + { "COMPRESSED_SRGB_ALPHA_BPTC_UNORM", InternalFormat::COMPRESSED_SRGB_ALPHA_BPTC_UNORM }, + { "COMPRESSED_RGB_BPTC_SIGNED_FLOAT", InternalFormat::COMPRESSED_RGB_BPTC_SIGNED_FLOAT }, + { "COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT", InternalFormat::COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT }, + + { "COMPRESSED_RGB8_ETC2", InternalFormat::COMPRESSED_RGB8_ETC2 }, + { "COMPRESSED_SRGB8_ETC2", InternalFormat::COMPRESSED_SRGB8_ETC2 }, + { "COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2", InternalFormat::COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2 }, + { "COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2", InternalFormat::COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2 }, + { "COMPRESSED_RGBA8_ETC2_EAC", InternalFormat::COMPRESSED_RGBA8_ETC2_EAC }, + { "COMPRESSED_SRGB8_ALPHA8_ETC2_EAC", InternalFormat::COMPRESSED_SRGB8_ALPHA8_ETC2_EAC }, + + { "COMPRESSED_R11_EAC", InternalFormat::COMPRESSED_R11_EAC }, + { "COMPRESSED_SIGNED_R11_EAC", InternalFormat::COMPRESSED_SIGNED_R11_EAC }, + { "COMPRESSED_RG11_EAC", InternalFormat::COMPRESSED_RG11_EAC }, + { "COMPRESSED_SIGNED_RG11_EAC", InternalFormat::COMPRESSED_SIGNED_RG11_EAC } + }; + + inline const char* toString(InternalFormat format) { + for (auto& pair : nameToFormat) { + if (pair.second == format) { + return pair.first.data(); + } + } + return nullptr; + } + + inline bool fromString(const char* name, InternalFormat* format) { + auto it = nameToFormat.find(name); + if (it == nameToFormat.end()) { + return false; + } + *format = it->second; + return true; + } + inline uint8_t evalUncompressedBlockBitSize(InternalFormat format) { switch (format) { case InternalFormat::R8: diff --git a/libraries/model-networking/src/model-networking/ModelCache.cpp b/libraries/model-networking/src/model-networking/ModelCache.cpp index f17cdbb7e8..716d2aeab1 100644 --- a/libraries/model-networking/src/model-networking/ModelCache.cpp +++ b/libraries/model-networking/src/model-networking/ModelCache.cpp @@ -63,16 +63,18 @@ void GeometryMappingResource::downloadFinished(const QByteArray& data) { PROFILE_ASYNC_BEGIN(resource_parse_geometry, "GeometryMappingResource::downloadFinished", _url.toString(), { { "url", _url.toString() } }); - auto mapping = FSTReader::readMapping(data); + // store parsed contents of FST file + _mapping = FSTReader::readMapping(data); + + QString filename = _mapping.value("filename").toString(); - QString filename = mapping.value("filename").toString(); if (filename.isNull()) { qCDebug(modelnetworking) << "Mapping file" << _url << "has no \"filename\" field"; finishedLoading(false); } else { QUrl url = _url.resolved(filename); - QString texdir = mapping.value(TEXDIR_FIELD).toString(); + QString texdir = _mapping.value(TEXDIR_FIELD).toString(); if (!texdir.isNull()) { if (!texdir.endsWith('/')) { texdir += '/'; @@ -82,7 +84,16 @@ void GeometryMappingResource::downloadFinished(const QByteArray& data) { _textureBaseUrl = url.resolved(QUrl(".")); } - auto animGraphVariant = mapping.value("animGraphUrl"); + auto scripts = FSTReader::getScripts(_url, _mapping); + if (scripts.size() > 0) { + _mapping.remove(SCRIPT_FIELD); + for (auto &scriptPath : scripts) { + _mapping.insertMulti(SCRIPT_FIELD, scriptPath); + } + } + + auto animGraphVariant = _mapping.value("animGraphUrl"); + if (animGraphVariant.isValid()) { QUrl fstUrl(animGraphVariant.toString()); if (fstUrl.isValid()) { @@ -95,7 +106,7 @@ void GeometryMappingResource::downloadFinished(const QByteArray& data) { } auto modelCache = DependencyManager::get(); - GeometryExtra extra{ mapping, _textureBaseUrl, false }; + GeometryExtra extra{ _mapping, _textureBaseUrl, false }; // Get the raw GeometryResource _geometryResource = modelCache->getResource(url, QUrl(), &extra).staticCast(); @@ -209,6 +220,14 @@ void GeometryReader::run() { throw QString("unsupported format"); } + // Add scripts to fbxgeometry + if (!_mapping.value(SCRIPT_FIELD).isNull()) { + QVariantList scripts = _mapping.values(SCRIPT_FIELD); + for (auto &script : scripts) { + fbxGeometry->scripts.push_back(script.toString()); + } + } + // Ensure the resource has not been deleted auto resource = _resource.toStrongRef(); if (!resource) { @@ -362,6 +381,7 @@ Geometry::Geometry(const Geometry& geometry) { } _animGraphOverrideUrl = geometry._animGraphOverrideUrl; + _mapping = geometry._mapping; } void Geometry::setTextures(const QVariantMap& textureMap) { @@ -517,10 +537,11 @@ QUrl NetworkMaterial::getTextureUrl(const QUrl& baseUrl, const FBXTexture& textu // Inlined file: cache under the fbx file to avoid namespace clashes // NOTE: We cannot resolve the path because filename may be an absolute path assert(texture.filename.size() > 0); + auto baseUrlStripped = baseUrl.toDisplayString(QUrl::RemoveFragment | QUrl::RemoveQuery | QUrl::RemoveUserInfo); if (texture.filename.at(0) == '/') { - return baseUrl.toString() + texture.filename; + return baseUrlStripped + texture.filename; } else { - return baseUrl.toString() + '/' + texture.filename; + return baseUrlStripped + '/' + texture.filename; } } } diff --git a/libraries/model-networking/src/model-networking/ModelCache.h b/libraries/model-networking/src/model-networking/ModelCache.h index 9532f39ce0..7e911bc9bf 100644 --- a/libraries/model-networking/src/model-networking/ModelCache.h +++ b/libraries/model-networking/src/model-networking/ModelCache.h @@ -55,6 +55,7 @@ public: virtual bool areTexturesLoaded() const; const QUrl& getAnimGraphOverrideUrl() const { return _animGraphOverrideUrl; } + const QVariantHash& getMapping() const { return _mapping; } protected: friend class GeometryMappingResource; @@ -68,6 +69,7 @@ protected: NetworkMaterials _materials; QUrl _animGraphOverrideUrl; + QVariantHash _mapping; // parsed contents of FST file. private: mutable bool _areTexturesLoaded { false }; @@ -144,6 +146,9 @@ public: * API to manage model cache resources. * @namespace ModelCache * + * @hifi-interface + * @hifi-client-entity + * * @property {number} numTotal - Total number of total resources. Read-only. * @property {number} numCached - Total number of cached resource. Read-only. * @property {number} sizeTotal - Size in bytes of all resources. Read-only. @@ -156,7 +161,7 @@ public: /**jsdoc * Get the list of all resource URLs. * @function ModelCache.getResourceList - * @return {string[]} + * @returns {string[]} */ /**jsdoc @@ -170,10 +175,11 @@ public: */ /**jsdoc + * Prefetches a resource. * @function ModelCache.prefetch - * @param {string} url - * @param {object} extra - * @returns {object} + * @param {string} url - URL of the resource to prefetch. + * @param {object} [extra=null] + * @returns {Resource} */ /**jsdoc @@ -182,14 +188,7 @@ public: * @param {string} url - URL of the resource to load. * @param {string} [fallback=""] - Fallback URL if load of the desired URL fails. * @param {} [extra=null] - * @return {Resource} - */ - - /**jsdoc - * Prefetches a resource. - * @function ModelCache.prefetch - * @param {string} url - URL of the resource to prefetch. - * @return {Resource} + * @returns {Resource} */ diff --git a/libraries/model-networking/src/model-networking/TextureCache.cpp b/libraries/model-networking/src/model-networking/TextureCache.cpp index 04696cea1a..ed21fd35bc 100644 --- a/libraries/model-networking/src/model-networking/TextureCache.cpp +++ b/libraries/model-networking/src/model-networking/TextureCache.cpp @@ -48,6 +48,8 @@ #include #include +#include + Q_LOGGING_CATEGORY(trace_resource_parse_image, "trace.resource.parse.image") Q_LOGGING_CATEGORY(trace_resource_parse_image_raw, "trace.resource.parse.image.raw") Q_LOGGING_CATEGORY(trace_resource_parse_image_ktx, "trace.resource.parse.image.ktx") @@ -293,7 +295,6 @@ int networkTexturePointerMetaTypeId = qRegisterMetaType(url); @@ -309,17 +310,25 @@ static bool isLocalUrl(const QUrl& url) { NetworkTexture::NetworkTexture(const QUrl& url, image::TextureUsage::Type type, const QByteArray& content, int maxNumPixels) : Resource(url), _type(type), - _sourceIsKTX(url.path().endsWith(".ktx")), _maxNumPixels(maxNumPixels) { _textureSource = std::make_shared(url, (int)type); _lowestRequestedMipLevel = 0; - _shouldFailOnRedirect = !_sourceIsKTX; + auto fileNameLowercase = url.fileName().toLower(); + if (fileNameLowercase.endsWith(TEXTURE_META_EXTENSION)) { + _currentlyLoadingResourceType = ResourceType::META; + } else if (fileNameLowercase.endsWith(".ktx")) { + _currentlyLoadingResourceType = ResourceType::KTX; + } else { + _currentlyLoadingResourceType = ResourceType::ORIGINAL; + } + + _shouldFailOnRedirect = _currentlyLoadingResourceType != ResourceType::KTX; if (type == image::TextureUsage::CUBE_TEXTURE) { setLoadPriority(this, SKYBOX_LOAD_PRIORITY); - } else if (_sourceIsKTX) { + } else if (_currentlyLoadingResourceType == ResourceType::KTX) { setLoadPriority(this, HIGH_MIPS_LOAD_PRIORITY); } @@ -330,7 +339,7 @@ NetworkTexture::NetworkTexture(const QUrl& url, image::TextureUsage::Type type, // if we have content, load it after we have our self pointer if (!content.isEmpty()) { _startedLoading = true; - QMetaObject::invokeMethod(this, "loadContent", Qt::QueuedConnection, Q_ARG(const QByteArray&, content)); + QMetaObject::invokeMethod(this, "downloadFinished", Qt::QueuedConnection, Q_ARG(const QByteArray&, content)); } } @@ -393,12 +402,12 @@ NetworkTexture::~NetworkTexture() { const uint16_t NetworkTexture::NULL_MIP_LEVEL = std::numeric_limits::max(); void NetworkTexture::makeRequest() { - if (!_sourceIsKTX) { + if (_currentlyLoadingResourceType != ResourceType::KTX) { Resource::makeRequest(); return; } - if (isLocalUrl(_url)) { + if (isLocalUrl(_activeUrl)) { auto self = _self; QtConcurrent::run(QThreadPool::globalInstance(), [self] { auto resource = self.lock(); @@ -466,12 +475,12 @@ void NetworkTexture::handleLocalRequestCompleted() { } void NetworkTexture::makeLocalRequest() { - const QString scheme = _url.scheme(); + const QString scheme = _activeUrl.scheme(); QString path; if (scheme == URL_SCHEME_FILE) { - path = PathUtils::expandToLocalDataAbsolutePath(_url).toLocalFile(); + path = PathUtils::expandToLocalDataAbsolutePath(_activeUrl).toLocalFile(); } else { - path = ":" + _url.path(); + path = ":" + _activeUrl.path(); } connect(this, &Resource::finished, this, &NetworkTexture::handleLocalRequestCompleted); @@ -497,7 +506,7 @@ void NetworkTexture::makeLocalRequest() { }); if (found == ktxDescriptor->keyValues.end() || found->_value.size() != gpu::SOURCE_HASH_BYTES) { - hash = _url.toString().toLocal8Bit().toHex().toStdString(); + hash = _activeUrl.toString().toLocal8Bit().toHex().toStdString(); } else { // at this point the source hash is in binary 16-byte form // and we need it in a hexadecimal string @@ -536,11 +545,13 @@ void NetworkTexture::makeLocalRequest() { } bool NetworkTexture::handleFailedRequest(ResourceRequest::Result result) { - if (!_sourceIsKTX && result == ResourceRequest::Result::RedirectFail) { + if (_currentlyLoadingResourceType != ResourceType::KTX + && result == ResourceRequest::Result::RedirectFail) { + auto newPath = _request->getRelativePathUrl(); if (newPath.fileName().endsWith(".ktx")) { qDebug() << "Redirecting to" << newPath << "from" << _url; - _sourceIsKTX = true; + _currentlyLoadingResourceType = ResourceType::KTX; _activeUrl = newPath; _shouldFailOnRedirect = false; makeRequest(); @@ -930,11 +941,75 @@ void NetworkTexture::handleFinishedInitialLoad() { } void NetworkTexture::downloadFinished(const QByteArray& data) { - loadContent(data); + if (_currentlyLoadingResourceType == ResourceType::META) { + loadMetaContent(data); + } else if (_currentlyLoadingResourceType == ResourceType::ORIGINAL) { + loadTextureContent(data); + } else { + TextureCache::requestCompleted(_self); + Resource::handleFailedRequest(ResourceRequest::Error); + } } -void NetworkTexture::loadContent(const QByteArray& content) { - if (_sourceIsKTX) { +void NetworkTexture::loadMetaContent(const QByteArray& content) { + if (_currentlyLoadingResourceType != ResourceType::META) { + qWarning() << "Trying to load meta content when current resource type is not META"; + assert(false); + return; + } + + TextureMeta meta; + if (!TextureMeta::deserialize(content, &meta)) { + qWarning() << "Failed to read texture meta from " << _url; + return; + } + + + auto& backend = DependencyManager::get()->getGPUContext()->getBackend(); + for (auto pair : meta.availableTextureTypes) { + gpu::Element elFormat; + + if (gpu::Texture::getCompressedFormat(pair.first, elFormat)) { + if (backend->supportedTextureFormat(elFormat)) { + auto url = pair.second; + if (url.fileName().endsWith(TEXTURE_META_EXTENSION)) { + qWarning() << "Found a texture meta URL inside of the texture meta file at" << _activeUrl; + continue; + } + + _currentlyLoadingResourceType = ResourceType::KTX; + _activeUrl = _activeUrl.resolved(url); + auto textureCache = DependencyManager::get(); + auto self = _self.lock(); + if (!self) { + return; + } + QMetaObject::invokeMethod(this, "attemptRequest", Qt::QueuedConnection); + return; + } + } + } + + if (!meta.original.isEmpty()) { + _currentlyLoadingResourceType = ResourceType::ORIGINAL; + _activeUrl = _activeUrl.resolved(meta.original); + + auto textureCache = DependencyManager::get(); + auto self = _self.lock(); + if (!self) { + return; + } + QMetaObject::invokeMethod(this, "attemptRequest", Qt::QueuedConnection); + return; + } + + qWarning() << "Failed to find supported texture type in " << _activeUrl; + Resource::handleFailedRequest(ResourceRequest::NotFound); +} + +void NetworkTexture::loadTextureContent(const QByteArray& content) { + if (_currentlyLoadingResourceType != ResourceType::ORIGINAL) { + qWarning() << "Trying to load texture content when current resource type is not ORIGINAL"; assert(false); return; } diff --git a/libraries/model-networking/src/model-networking/TextureCache.h b/libraries/model-networking/src/model-networking/TextureCache.h index 3f46dc3074..898f0e3d3a 100644 --- a/libraries/model-networking/src/model-networking/TextureCache.h +++ b/libraries/model-networking/src/model-networking/TextureCache.h @@ -24,7 +24,9 @@ #include #include #include +#include +#include #include "KTXCache.h" namespace gpu { @@ -75,11 +77,13 @@ protected: virtual bool isCacheable() const override { return _loaded; } - virtual void downloadFinished(const QByteArray& data) override; + Q_INVOKABLE virtual void downloadFinished(const QByteArray& data) override; bool handleFailedRequest(ResourceRequest::Result result) override; - Q_INVOKABLE void loadContent(const QByteArray& content); + Q_INVOKABLE void loadMetaContent(const QByteArray& content); + Q_INVOKABLE void loadTextureContent(const QByteArray& content); + Q_INVOKABLE void setImage(gpu::TexturePointer texture, int originalWidth, int originalHeight); Q_INVOKABLE void startRequestForNextMipLevel(); @@ -93,6 +97,14 @@ private: image::TextureUsage::Type _type; + enum class ResourceType { + META, + ORIGINAL, + KTX + }; + + ResourceType _currentlyLoadingResourceType { ResourceType::META }; + static const uint16_t NULL_MIP_LEVEL; enum KTXResourceState { PENDING_INITIAL_LOAD = 0, @@ -103,7 +115,6 @@ private: FAILED_TO_LOAD }; - bool _sourceIsKTX { false }; KTXResourceState _ktxResourceState { PENDING_INITIAL_LOAD }; // The current mips that are currently being requested w/ _ktxMipRequest @@ -151,6 +162,9 @@ public: * API to manage texture cache resources. * @namespace TextureCache * + * @hifi-interface + * @hifi-client-entity + * * @property {number} numTotal - Total number of total resources. Read-only. * @property {number} numCached - Total number of cached resource. Read-only. * @property {number} sizeTotal - Size in bytes of all resources. Read-only. @@ -160,44 +174,38 @@ public: // Functions are copied over from ResourceCache (see ResourceCache.h for reason). - /**jsdoc - * Get the list of all resource URLs. - * @function TextureCache.getResourceList - * @return {string[]} - */ + /**jsdoc + * Get the list of all resource URLs. + * @function TextureCache.getResourceList + * @returns {string[]} + */ - /**jsdoc - * @function TextureCache.dirty - * @returns {Signal} - */ + /**jsdoc + * @function TextureCache.dirty + * @returns {Signal} + */ - /**jsdoc - * @function TextureCache.updateTotalSize - * @param {number} deltaSize - */ + /**jsdoc + * @function TextureCache.updateTotalSize + * @param {number} deltaSize + */ - /**jsdoc - * @function TextureCache.prefetch - * @param {string} url - * @param {object} extra - * @returns {object} - */ + /**jsdoc + * Prefetches a resource. + * @function TextureCache.prefetch + * @param {string} url - URL of the resource to prefetch. + * @param {object} [extra=null] + * @returns {Resource} + */ - /**jsdoc - * Asynchronously loads a resource from the specified URL and returns it. - * @function TextureCache.getResource - * @param {string} url - URL of the resource to load. - * @param {string} [fallback=""] - Fallback URL if load of the desired URL fails. - * @param {} [extra=null] - * @return {Resource} - */ - - /**jsdoc - * Prefetches a resource. - * @function TextureCache.prefetch - * @param {string} url - URL of the resource to prefetch. - * @return {Resource} - */ + /**jsdoc + * Asynchronously loads a resource from the specified URL and returns it. + * @function TextureCache.getResource + * @param {string} url - URL of the resource to load. + * @param {string} [fallback=""] - Fallback URL if load of the desired URL fails. + * @param {} [extra=null] + * @returns {Resource} + */ /// Returns the ID of the permutation/normal texture used for Perlin noise shader programs. This texture @@ -236,6 +244,9 @@ public: static const int DEFAULT_SPECTATOR_CAM_WIDTH { 2048 }; static const int DEFAULT_SPECTATOR_CAM_HEIGHT { 1024 }; + void setGPUContext(const gpu::ContextPointer& context) { _gpuContext = context; } + gpu::ContextPointer getGPUContext() const { return _gpuContext; } + signals: /**jsdoc * @function TextureCache.spectatorCameraFramebufferReset @@ -246,10 +257,11 @@ signals: protected: /**jsdoc - * @function TextureCache.prefect + * @function TextureCache.prefetch * @param {string} url * @param {number} type * @param {number} [maxNumPixels=67108864] + * @returns {Resource} */ // Overload ResourceCache::prefetch to allow specifying texture type for loads Q_INVOKABLE ScriptableResource* prefetch(const QUrl& url, int type, int maxNumPixels = ABSOLUTE_MAX_TEXTURE_NUM_PIXELS); @@ -268,6 +280,8 @@ private: static const std::string KTX_DIRNAME; static const std::string KTX_EXT; + gpu::ContextPointer _gpuContext { nullptr }; + std::shared_ptr _ktxCache { std::make_shared(KTX_DIRNAME, KTX_EXT) }; // Map from image hashes to texture weak pointers diff --git a/libraries/networking/src/AccountManager.cpp b/libraries/networking/src/AccountManager.cpp index f6264a19c4..049129b2ba 100644 --- a/libraries/networking/src/AccountManager.cpp +++ b/libraries/networking/src/AccountManager.cpp @@ -106,7 +106,11 @@ void AccountManager::logout() { } QString accountFileDir() { +#if defined(Q_OS_ANDROID) + return QStandardPaths::writableLocation(QStandardPaths::CacheLocation) + "/../files"; +#else return QStandardPaths::writableLocation(QStandardPaths::AppDataLocation); +#endif } QString accountFilePath() { diff --git a/libraries/networking/src/AddressManager.cpp b/libraries/networking/src/AddressManager.cpp index 055d94c3b3..dd6a7fffe9 100644 --- a/libraries/networking/src/AddressManager.cpp +++ b/libraries/networking/src/AddressManager.cpp @@ -9,6 +9,8 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include "AddressManager.h" + #include #include #include @@ -23,7 +25,6 @@ #include #include -#include "AddressManager.h" #include "NodeList.h" #include "NetworkLogging.h" #include "UserActivityLogger.h" @@ -114,8 +115,6 @@ QUrl AddressManager::currentFacingPublicAddress() const { void AddressManager::loadSettings(const QString& lookupString) { #if defined(USE_GLES) && defined(Q_OS_WIN) handleUrl(QUrl("hifi://127.0.0.0"), LookupTrigger::StartupFromSettings); -#elif defined(Q_OS_ANDROID) - handleUrl(QUrl("hifi://pikachu/167.11,0.745735,181.529/0,0.887027,0,-0.461717"), LookupTrigger::StartupFromSettings); #else if (lookupString.isEmpty()) { handleUrl(currentAddressHandle.get(), LookupTrigger::StartupFromSettings); diff --git a/libraries/networking/src/AddressManager.h b/libraries/networking/src/AddressManager.h index 94eff46bda..8e2553779b 100644 --- a/libraries/networking/src/AddressManager.h +++ b/libraries/networking/src/AddressManager.h @@ -33,11 +33,14 @@ const QString GET_PLACE = "/api/v1/places/%1"; * The location API provides facilities related to your current location in the metaverse. * * @namespace location + * + * @hifi-interface + * @hifi-client-entity + * @hifi-assignment-client + * * @property {Uuid} domainID - A UUID uniquely identifying the domain you're visiting. Is {@link Uuid|Uuid.NULL} if you're not * connected to the domain or are in a serverless domain. * Read-only. - * @property {Uuid} domainId - Synonym for domainId. Read-only. Deprecated: This property - * is deprecated and will soon be removed. * @property {string} hostname - The name of the domain for your current metaverse address (e.g., "AvatarIsland", * localhost, or an IP address). Is blank if you're in a serverless domain. * Read-only. @@ -68,7 +71,6 @@ class AddressManager : public QObject, public Dependency { Q_PROPERTY(QString pathname READ currentPath) Q_PROPERTY(QString placename READ getPlaceName) Q_PROPERTY(QString domainID READ getDomainID) - Q_PROPERTY(QString domainId READ getDomainID) public: using PositionGetter = std::function; using OrientationGetter = std::function; diff --git a/libraries/networking/src/Assignment.cpp b/libraries/networking/src/Assignment.cpp index 58a4446aa6..71a3cfb269 100644 --- a/libraries/networking/src/Assignment.cpp +++ b/libraries/networking/src/Assignment.cpp @@ -9,17 +9,18 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -#include "udt/PacketHeaders.h" -#include "SharedUtil.h" -#include "UUID.h" +#include "Assignment.h" #include #include -#include "Assignment.h" #include #include +#include "udt/PacketHeaders.h" +#include "SharedUtil.h" +#include "UUID.h" + Assignment::Type Assignment::typeForNodeType(NodeType_t nodeType) { switch (nodeType) { case NodeType::AudioMixer: diff --git a/libraries/networking/src/AtpReply.cpp b/libraries/networking/src/AtpReply.cpp index 6417478005..b2b7e8bee7 100644 --- a/libraries/networking/src/AtpReply.cpp +++ b/libraries/networking/src/AtpReply.cpp @@ -9,9 +9,10 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -#include "ResourceManager.h" #include "AtpReply.h" +#include "ResourceManager.h" + AtpReply::AtpReply(const QUrl& url, QObject* parent) : _resourceRequest(DependencyManager::get()->createResourceRequest(parent, url)) { setOperation(QNetworkAccessManager::GetOperation); diff --git a/libraries/networking/src/BandwidthRecorder.cpp b/libraries/networking/src/BandwidthRecorder.cpp index d43d4cf21f..5ad3494017 100644 --- a/libraries/networking/src/BandwidthRecorder.cpp +++ b/libraries/networking/src/BandwidthRecorder.cpp @@ -11,9 +11,9 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -#include #include "BandwidthRecorder.h" +#include BandwidthRecorder::Channel::Channel() { } diff --git a/libraries/networking/src/DataServerAccountInfo.cpp b/libraries/networking/src/DataServerAccountInfo.cpp index 51f93d13b0..8756a0cc4b 100644 --- a/libraries/networking/src/DataServerAccountInfo.cpp +++ b/libraries/networking/src/DataServerAccountInfo.cpp @@ -9,6 +9,8 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include "DataServerAccountInfo.h" + #include #include @@ -20,7 +22,6 @@ #include #include "NetworkLogging.h" -#include "DataServerAccountInfo.h" #ifdef __clang__ #pragma clang diagnostic ignored "-Wdeprecated-declarations" diff --git a/libraries/networking/src/HifiSockAddr.cpp b/libraries/networking/src/HifiSockAddr.cpp index e2a3e79c79..a1bfcdd275 100644 --- a/libraries/networking/src/HifiSockAddr.cpp +++ b/libraries/networking/src/HifiSockAddr.cpp @@ -9,11 +9,12 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include "HifiSockAddr.h" + #include #include #include -#include "HifiSockAddr.h" #include "NetworkLogging.h" int hifiSockAddrMetaTypeId = qRegisterMetaType(); diff --git a/libraries/networking/src/LocationScriptingInterface.cpp b/libraries/networking/src/LocationScriptingInterface.cpp index aae1da73ba..39845558a8 100644 --- a/libraries/networking/src/LocationScriptingInterface.cpp +++ b/libraries/networking/src/LocationScriptingInterface.cpp @@ -9,10 +9,10 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -#include "AddressManager.h" - #include "LocationScriptingInterface.h" +#include "AddressManager.h" + LocationScriptingInterface* LocationScriptingInterface::getInstance() { static LocationScriptingInterface sharedInstance; return &sharedInstance; diff --git a/libraries/networking/src/MessagesClient.h b/libraries/networking/src/MessagesClient.h index 6ef3777d8c..f2ccfe33f4 100644 --- a/libraries/networking/src/MessagesClient.h +++ b/libraries/networking/src/MessagesClient.h @@ -37,6 +37,11 @@ * * * @namespace Messages + * + * @hifi-interface + * @hifi-client-entity + * @hifi-server-entity + * @hifi-assignment-client */ class MessagesClient : public QObject, public Dependency { Q_OBJECT diff --git a/libraries/networking/src/NetworkAccessManager.cpp b/libraries/networking/src/NetworkAccessManager.cpp index fd356c3e94..f73243e675 100644 --- a/libraries/networking/src/NetworkAccessManager.cpp +++ b/libraries/networking/src/NetworkAccessManager.cpp @@ -9,10 +9,11 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include "NetworkAccessManager.h" + #include #include "AtpReply.h" -#include "NetworkAccessManager.h" #include QThreadStorage networkAccessManagers; diff --git a/libraries/networking/src/Node.cpp b/libraries/networking/src/Node.cpp index 73b7c44e7e..626503d8ae 100644 --- a/libraries/networking/src/Node.cpp +++ b/libraries/networking/src/Node.cpp @@ -9,6 +9,8 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include "Node.h" + #include #include @@ -21,8 +23,6 @@ #include "NodePermissions.h" #include "SharedUtil.h" -#include "Node.h" - const QString UNKNOWN_NodeType_t_NAME = "Unknown"; int NodePtrMetaTypeId = qRegisterMetaType("Node*"); diff --git a/libraries/networking/src/NodeList.h b/libraries/networking/src/NodeList.h index 9595c5da84..c5cf5e9524 100644 --- a/libraries/networking/src/NodeList.h +++ b/libraries/networking/src/NodeList.h @@ -167,7 +167,7 @@ private: HifiSockAddr _assignmentServerSocket; bool _isShuttingDown { false }; QTimer _keepAlivePingTimer; - bool _requestsDomainListData; + bool _requestsDomainListData { false }; mutable QReadWriteLock _ignoredSetLock; tbb::concurrent_unordered_set _ignoredNodeIDs; diff --git a/libraries/networking/src/OAuthAccessToken.cpp b/libraries/networking/src/OAuthAccessToken.cpp index 0c14e5e074..44db2a799e 100644 --- a/libraries/networking/src/OAuthAccessToken.cpp +++ b/libraries/networking/src/OAuthAccessToken.cpp @@ -9,10 +9,10 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -#include - #include "OAuthAccessToken.h" +#include + OAuthAccessToken::OAuthAccessToken() : token(), refreshToken(), diff --git a/libraries/networking/src/OAuthNetworkAccessManager.cpp b/libraries/networking/src/OAuthNetworkAccessManager.cpp index a30786efa4..272ff47a49 100644 --- a/libraries/networking/src/OAuthNetworkAccessManager.cpp +++ b/libraries/networking/src/OAuthNetworkAccessManager.cpp @@ -9,6 +9,8 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include "OAuthNetworkAccessManager.h" + #include #include #include @@ -18,8 +20,6 @@ #include "NetworkingConstants.h" #include "SharedUtil.h" -#include "OAuthNetworkAccessManager.h" - QThreadStorage oauthNetworkAccessManagers; OAuthNetworkAccessManager* OAuthNetworkAccessManager::getInstance() { diff --git a/libraries/networking/src/PacketSender.cpp b/libraries/networking/src/PacketSender.cpp index 02c4815f1f..6288743c46 100644 --- a/libraries/networking/src/PacketSender.cpp +++ b/libraries/networking/src/PacketSender.cpp @@ -9,12 +9,13 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include "PacketSender.h" + #include #include #include #include "NodeList.h" -#include "PacketSender.h" #include "SharedUtil.h" const quint64 PacketSender::USECS_PER_SECOND = 1000 * 1000; diff --git a/libraries/networking/src/RSAKeypairGenerator.cpp b/libraries/networking/src/RSAKeypairGenerator.cpp index a98cf74564..8ca8b81ea3 100644 --- a/libraries/networking/src/RSAKeypairGenerator.cpp +++ b/libraries/networking/src/RSAKeypairGenerator.cpp @@ -9,6 +9,8 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include "RSAKeypairGenerator.h" + #include #include #include @@ -16,8 +18,6 @@ #include #include "NetworkLogging.h" - -#include "RSAKeypairGenerator.h" #ifdef __clang__ #pragma clang diagnostic ignored "-Wdeprecated-declarations" #endif diff --git a/libraries/networking/src/ReceivedPacketProcessor.cpp b/libraries/networking/src/ReceivedPacketProcessor.cpp index c18d4ed1e8..7145744206 100644 --- a/libraries/networking/src/ReceivedPacketProcessor.cpp +++ b/libraries/networking/src/ReceivedPacketProcessor.cpp @@ -9,10 +9,11 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include "ReceivedPacketProcessor.h" + #include #include "NodeList.h" -#include "ReceivedPacketProcessor.h" #include "SharedUtil.h" ReceivedPacketProcessor::ReceivedPacketProcessor() { diff --git a/libraries/networking/src/ReceivedPacketProcessor.h b/libraries/networking/src/ReceivedPacketProcessor.h index f71abce1f1..6c590ec54d 100644 --- a/libraries/networking/src/ReceivedPacketProcessor.h +++ b/libraries/networking/src/ReceivedPacketProcessor.h @@ -14,8 +14,12 @@ #include +#include "NodeList.h" + #include "GenericThread.h" +class ReceivedMessage; + /// Generalized threaded processor for handling received inbound packets. class ReceivedPacketProcessor : public GenericThread { Q_OBJECT diff --git a/libraries/networking/src/ResourceCache.cpp b/libraries/networking/src/ResourceCache.cpp index d3583687e8..28266d0a7f 100644 --- a/libraries/networking/src/ResourceCache.cpp +++ b/libraries/networking/src/ResourceCache.cpp @@ -581,6 +581,7 @@ void Resource::refresh() { ResourceCache::requestCompleted(_self); } + _activeUrl = _url; init(); ensureLoading(); emit onRefresh(); @@ -618,7 +619,6 @@ void Resource::init(bool resetLoaded) { _loaded = false; } _attempts = 0; - _activeUrl = _url; if (_url.isEmpty()) { _startedLoading = _loaded = true; @@ -724,7 +724,7 @@ void Resource::handleReplyFinished() { auto result = _request->getResult(); if (result == ResourceRequest::Success) { auto extraInfo = _url == _activeUrl ? "" : QString(", %1").arg(_activeUrl.toDisplayString()); - qCDebug(networking).noquote() << QString("Request finished for %1%2").arg(_url.toDisplayString(), extraInfo); + qCDebug(networking).noquote() << QString("Request finished for %1%2").arg(_activeUrl.toDisplayString(), extraInfo); auto relativePathURL = _request->getRelativePathUrl(); if (!relativePathURL.isEmpty()) { diff --git a/libraries/networking/src/ResourceCache.h b/libraries/networking/src/ResourceCache.h index 609483bc56..e2df582aa3 100644 --- a/libraries/networking/src/ResourceCache.h +++ b/libraries/networking/src/ResourceCache.h @@ -89,6 +89,12 @@ class ScriptableResource : public QObject { /**jsdoc * @constructor Resource + * + * @hifi-interface + * @hifi-client-entity + * @hifi-server-entity + * @hifi-assignment-client + * * @property {string} url - URL of this resource. * @property {Resource.State} state - Current loading state. */ @@ -209,7 +215,7 @@ public: /**jsdoc * Get the list of all resource URLs. * @function ResourceCache.getResourceList - * @return {string[]} + * @returns {string[]} */ Q_INVOKABLE QVariantList getResourceList(); @@ -251,10 +257,11 @@ protected slots: void updateTotalSize(const qint64& deltaSize); /**jsdoc + * Prefetches a resource. * @function ResourceCache.prefetch - * @param {string} url - * @param {object} extra - * @returns {object} + * @param {string} url - URL of the resource to prefetch. + * @param {object} [extra=null] + * @returns {Resource} */ // Prefetches a resource to be held by the QScriptEngine. // Left as a protected member so subclasses can overload prefetch @@ -267,7 +274,7 @@ protected slots: * @param {string} url - URL of the resource to load. * @param {string} [fallback=""] - Fallback URL if load of the desired URL fails. * @param {} [extra=null] - * @return {Resource} + * @returns {Resource} */ /// Loads a resource from the specified URL and returns it. /// If the caller is on a different thread than the ResourceCache, @@ -285,12 +292,7 @@ protected: // Pointers created through this method should be owned by the caller, // which should be a QScriptEngine with ScriptableResource registered, so that // the QScriptEngine will delete the pointer when it is garbage collected. - /**jsdoc - * Prefetches a resource. - * @function ResourceCache.prefetch - * @param {string} url - URL of the resource to prefetch. - * @return {Resource} - */ + // JSDoc is provided on more general function signature. Q_INVOKABLE ScriptableResource* prefetch(const QUrl& url) { return prefetch(url, nullptr); } /// Creates a new resource. diff --git a/libraries/networking/src/ThreadedAssignment.cpp b/libraries/networking/src/ThreadedAssignment.cpp index 8b6de7da11..9a69d9b3d8 100644 --- a/libraries/networking/src/ThreadedAssignment.cpp +++ b/libraries/networking/src/ThreadedAssignment.cpp @@ -9,6 +9,8 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include "ThreadedAssignment.h" + #include #include #include @@ -17,8 +19,6 @@ #include -#include "ThreadedAssignment.h" - #include "NetworkLogging.h" ThreadedAssignment::ThreadedAssignment(ReceivedMessage& message) : diff --git a/libraries/networking/src/UserActivityLogger.cpp b/libraries/networking/src/UserActivityLogger.cpp index 0cfd1e09e7..7a92d4bad9 100644 --- a/libraries/networking/src/UserActivityLogger.cpp +++ b/libraries/networking/src/UserActivityLogger.cpp @@ -9,16 +9,17 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include "UserActivityLogger.h" + #include #include #include #include -#include "NetworkLogging.h" - -#include "UserActivityLogger.h" #include + #include "AddressManager.h" +#include "NetworkLogging.h" UserActivityLogger::UserActivityLogger() { _timer.start(); diff --git a/libraries/networking/src/WalletTransaction.cpp b/libraries/networking/src/WalletTransaction.cpp index 0c823555fd..2bb66c67d0 100644 --- a/libraries/networking/src/WalletTransaction.cpp +++ b/libraries/networking/src/WalletTransaction.cpp @@ -9,13 +9,12 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include "WalletTransaction.h" + #include #include -#include "WalletTransaction.h" - - WalletTransaction::WalletTransaction() : _uuid(), _destinationUUID(), diff --git a/libraries/networking/src/udt/ConnectionStats.cpp b/libraries/networking/src/udt/ConnectionStats.cpp index e7efe3d5af..986da062f2 100644 --- a/libraries/networking/src/udt/ConnectionStats.cpp +++ b/libraries/networking/src/udt/ConnectionStats.cpp @@ -11,6 +11,8 @@ #include "ConnectionStats.h" +#include + using namespace udt; using namespace std::chrono; @@ -112,3 +114,31 @@ void ConnectionStats::recordPacketSendPeriod(int sample) { _currentSample.packetSendPeriod = sample; _total.packetSendPeriod = (int)((_total.packetSendPeriod * EWMA_PREVIOUS_SAMPLES_WEIGHT) + (sample * EWMA_CURRENT_SAMPLE_WEIGHT)); } + +QDebug& operator<<(QDebug&& debug, const udt::ConnectionStats::Stats& stats) { + debug << "Connection stats:\n"; +#define HIFI_LOG_EVENT(x) << " " #x " events: " << stats.events[ConnectionStats::Stats::Event::x] << "\n" + debug + HIFI_LOG_EVENT(SentACK) + HIFI_LOG_EVENT(ReceivedACK) + HIFI_LOG_EVENT(ProcessedACK) + HIFI_LOG_EVENT(SentLightACK) + HIFI_LOG_EVENT(ReceivedLightACK) + HIFI_LOG_EVENT(SentACK2) + HIFI_LOG_EVENT(ReceivedACK2) + HIFI_LOG_EVENT(SentNAK) + HIFI_LOG_EVENT(ReceivedNAK) + HIFI_LOG_EVENT(SentTimeoutNAK) + HIFI_LOG_EVENT(ReceivedTimeoutNAK) + HIFI_LOG_EVENT(Retransmission) + HIFI_LOG_EVENT(Duplicate) + ; +#undef HIFI_LOG_EVENT + + debug << " Sent packets: " << stats.sentPackets; + debug << "\n Received packets: " << stats.receivedPackets; + debug << "\n Sent util bytes: " << stats.sentUtilBytes; + debug << "\n Sent bytes: " << stats.sentBytes; + debug << "\n Received bytes: " << stats.receivedBytes << "\n"; + return debug; +} diff --git a/libraries/networking/src/udt/ConnectionStats.h b/libraries/networking/src/udt/ConnectionStats.h index 84cd6b2486..7ec7b163ee 100644 --- a/libraries/networking/src/udt/ConnectionStats.h +++ b/libraries/networking/src/udt/ConnectionStats.h @@ -101,4 +101,7 @@ private: } +class QDebug; +QDebug& operator<<(QDebug&& debug, const udt::ConnectionStats::Stats& stats); + #endif // hifi_ConnectionStats_h diff --git a/libraries/networking/src/udt/PacketHeaders.cpp b/libraries/networking/src/udt/PacketHeaders.cpp index 98b0e1d892..70880833bf 100644 --- a/libraries/networking/src/udt/PacketHeaders.cpp +++ b/libraries/networking/src/udt/PacketHeaders.cpp @@ -34,7 +34,7 @@ PacketVersion versionForPacketType(PacketType packetType) { case PacketType::EntityPhysics: return static_cast(EntityVersion::MaterialData); case PacketType::EntityQuery: - return static_cast(EntityQueryPacketVersion::RemovedJurisdictions); + return static_cast(EntityQueryPacketVersion::ConicalFrustums); case PacketType::AvatarIdentity: case PacketType::AvatarData: case PacketType::BulkAvatarData: @@ -59,11 +59,10 @@ PacketVersion versionForPacketType(PacketType packetType) { return 17; case PacketType::AssetMappingOperation: case PacketType::AssetMappingOperationReply: - return static_cast(AssetServerPacketVersion::RedirectedMappings); case PacketType::AssetGetInfo: case PacketType::AssetGet: case PacketType::AssetUpload: - return static_cast(AssetServerPacketVersion::RangeRequestSupport); + return static_cast(AssetServerPacketVersion::BakingTextureMeta); case PacketType::NodeIgnoreRequest: return 18; // Introduction of node ignore request (which replaced an unused packet tpye) @@ -90,6 +89,8 @@ PacketVersion versionForPacketType(PacketType packetType) { return 18; // replace min_avatar_scale and max_avatar_scale with min_avatar_height and max_avatar_height case PacketType::Ping: return static_cast(PingVersion::IncludeConnectionID); + case PacketType::AvatarQuery: + return static_cast(AvatarQueryVersion::ConicalFrustums); default: return 20; } diff --git a/libraries/networking/src/udt/PacketHeaders.h b/libraries/networking/src/udt/PacketHeaders.h index e6b133c158..7d374f3625 100644 --- a/libraries/networking/src/udt/PacketHeaders.h +++ b/libraries/networking/src/udt/PacketHeaders.h @@ -103,7 +103,7 @@ public: RadiusIgnoreRequest, UsernameFromIDRequest, UsernameFromIDReply, - ViewFrustum, + AvatarQuery, RequestsDomainListData, PerAvatarGainSet, EntityScriptGetStatus, @@ -244,13 +244,16 @@ enum class EntityQueryPacketVersion: PacketVersion { JSONFilter = 18, JSONFilterWithFamilyTree = 19, ConnectionIdentifier = 20, - RemovedJurisdictions = 21 + RemovedJurisdictions = 21, + MultiFrustumQuery = 22, + ConicalFrustums = 23 }; enum class AssetServerPacketVersion: PacketVersion { VegasCongestionControl = 19, RangeRequestSupport, - RedirectedMappings + RedirectedMappings, + BakingTextureMeta }; enum class AvatarMixerPacketVersion : PacketVersion { @@ -327,4 +330,9 @@ enum class PingVersion : PacketVersion { IncludeConnectionID = 18 }; +enum class AvatarQueryVersion : PacketVersion { + SendMultipleFrustums = 21, + ConicalFrustums = 22 +}; + #endif // hifi_PacketHeaders_h diff --git a/libraries/octree/src/Octree.cpp b/libraries/octree/src/Octree.cpp index 2efd32f2e8..5f943fabf2 100644 --- a/libraries/octree/src/Octree.cpp +++ b/libraries/octree/src/Octree.cpp @@ -9,6 +9,8 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include "Octree.h" + #include #include #include @@ -43,7 +45,6 @@ #include #include -#include "Octree.h" #include "OctreeConstants.h" #include "OctreeLogging.h" #include "OctreeQueryNode.h" diff --git a/libraries/octree/src/Octree.h b/libraries/octree/src/Octree.h index a2ad834e18..b827ed7cd0 100644 --- a/libraries/octree/src/Octree.h +++ b/libraries/octree/src/Octree.h @@ -59,7 +59,6 @@ const int LOW_RES_MOVING_ADJUST = 1; class EncodeBitstreamParams { public: - ViewFrustum viewFrustum; bool includeExistsBits; NodeData* nodeData; diff --git a/libraries/octree/src/OctreeEditPacketSender.cpp b/libraries/octree/src/OctreeEditPacketSender.cpp index 4f10c9bf79..0156013821 100644 --- a/libraries/octree/src/OctreeEditPacketSender.cpp +++ b/libraries/octree/src/OctreeEditPacketSender.cpp @@ -9,6 +9,8 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include "OctreeEditPacketSender.h" + #include #include @@ -16,7 +18,6 @@ #include #include #include "OctreeLogging.h" -#include "OctreeEditPacketSender.h" const int OctreeEditPacketSender::DEFAULT_MAX_PENDING_MESSAGES = PacketSender::DEFAULT_PACKETS_PER_SECOND; diff --git a/libraries/octree/src/OctreeElement.cpp b/libraries/octree/src/OctreeElement.cpp index a666ba0426..b94d0d57e1 100644 --- a/libraries/octree/src/OctreeElement.cpp +++ b/libraries/octree/src/OctreeElement.cpp @@ -9,6 +9,8 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include "OctreeElement.h" + #include #include #include @@ -21,17 +23,16 @@ #include #include #include +#include #include "AACube.h" #include "Logging.h" #include "OctalCode.h" #include "Octree.h" #include "OctreeConstants.h" -#include "OctreeElement.h" #include "OctreeLogging.h" #include "OctreeUtils.h" #include "SharedUtil.h" -#include AtomicUIntStat OctreeElement::_octreeMemoryUsage { 0 }; AtomicUIntStat OctreeElement::_octcodeMemoryUsage { 0 }; diff --git a/libraries/octree/src/OctreePacketData.cpp b/libraries/octree/src/OctreePacketData.cpp index 7108f9a4e4..b938850684 100644 --- a/libraries/octree/src/OctreePacketData.cpp +++ b/libraries/octree/src/OctreePacketData.cpp @@ -9,11 +9,12 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include "OctreePacketData.h" + #include #include #include "OctreeLogging.h" -#include "OctreePacketData.h" #include "NumericalConstants.h" bool OctreePacketData::_debug = false; diff --git a/libraries/octree/src/OctreePersistThread.cpp b/libraries/octree/src/OctreePersistThread.cpp index e6c28f75e8..e6afccab47 100644 --- a/libraries/octree/src/OctreePersistThread.cpp +++ b/libraries/octree/src/OctreePersistThread.cpp @@ -9,6 +9,8 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include "OctreePersistThread.h" + #include #include @@ -30,7 +32,6 @@ #include #include "OctreeLogging.h" -#include "OctreePersistThread.h" #include "OctreeUtils.h" #include "OctreeDataUtils.h" diff --git a/libraries/octree/src/OctreeProcessor.cpp b/libraries/octree/src/OctreeProcessor.cpp index 43019c7acc..db78e985e6 100644 --- a/libraries/octree/src/OctreeProcessor.cpp +++ b/libraries/octree/src/OctreeProcessor.cpp @@ -8,16 +8,17 @@ // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include "OctreeProcessor.h" + +#include #include -#include #include #include #include #include "OctreeLogging.h" -#include "OctreeProcessor.h" OctreeProcessor::OctreeProcessor() : _tree(NULL), diff --git a/libraries/octree/src/OctreeQuery.cpp b/libraries/octree/src/OctreeQuery.cpp index 18766dd7f6..3f730d4458 100644 --- a/libraries/octree/src/OctreeQuery.cpp +++ b/libraries/octree/src/OctreeQuery.cpp @@ -9,6 +9,8 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include "OctreeQuery.h" + #include #include @@ -16,23 +18,7 @@ #include #include -#include "OctreeConstants.h" -#include "OctreeQuery.h" - -const float DEFAULT_FOV = 45.0f; // degrees -const float DEFAULT_ASPECT_RATIO = 1.0f; -const float DEFAULT_NEAR_CLIP = 0.1f; -const float DEFAULT_FAR_CLIP = 3.0f; - -OctreeQuery::OctreeQuery(bool randomizeConnectionID) : - _cameraFov(DEFAULT_FOV), - _cameraAspectRatio(DEFAULT_ASPECT_RATIO), - _cameraNearClip(DEFAULT_NEAR_CLIP), - _cameraFarClip(DEFAULT_FAR_CLIP), - _cameraCenterRadius(DEFAULT_FAR_CLIP) -{ - _maxQueryPPS = DEFAULT_MAX_OCTREE_PPS; - +OctreeQuery::OctreeQuery(bool randomizeConnectionID) { if (randomizeConnectionID) { // randomize our initial octree query connection ID using random_device // the connection ID is 16 bits so we take a generated 32 bit value from random device and chop off the top @@ -47,26 +33,14 @@ int OctreeQuery::getBroadcastData(unsigned char* destinationBuffer) { // pack the connection ID so the server can detect when we start a new connection memcpy(destinationBuffer, &_connectionID, sizeof(_connectionID)); destinationBuffer += sizeof(_connectionID); - - // back a boolean (cut to 1 byte) to designate if this query uses the sent view frustum - memcpy(destinationBuffer, &_usesFrustum, sizeof(_usesFrustum)); - destinationBuffer += sizeof(_usesFrustum); - - if (_usesFrustum) { - // TODO: DRY this up to a shared method - // that can pack any type given the number of bytes - // and return the number of bytes to push the pointer - - // camera details - memcpy(destinationBuffer, &_cameraPosition, sizeof(_cameraPosition)); - destinationBuffer += sizeof(_cameraPosition); - destinationBuffer += packOrientationQuatToBytes(destinationBuffer, _cameraOrientation); - destinationBuffer += packFloatAngleToTwoByte(destinationBuffer, _cameraFov); - destinationBuffer += packFloatRatioToTwoByte(destinationBuffer, _cameraAspectRatio); - destinationBuffer += packClipValueToTwoByte(destinationBuffer, _cameraNearClip); - destinationBuffer += packClipValueToTwoByte(destinationBuffer, _cameraFarClip); - memcpy(destinationBuffer, &_cameraEyeOffsetPosition, sizeof(_cameraEyeOffsetPosition)); - destinationBuffer += sizeof(_cameraEyeOffsetPosition); + + // Number of frustums + uint8_t numFrustums = (uint8_t)_conicalViews.size(); + memcpy(destinationBuffer, &numFrustums, sizeof(numFrustums)); + destinationBuffer += sizeof(numFrustums); + + for (const auto& view : _conicalViews) { + destinationBuffer += view.serialize(destinationBuffer); } // desired Max Octree PPS @@ -80,9 +54,6 @@ int OctreeQuery::getBroadcastData(unsigned char* destinationBuffer) { // desired boundaryLevelAdjust memcpy(destinationBuffer, &_boundaryLevelAdjust, sizeof(_boundaryLevelAdjust)); destinationBuffer += sizeof(_boundaryLevelAdjust); - - memcpy(destinationBuffer, &_cameraCenterRadius, sizeof(_cameraCenterRadius)); - destinationBuffer += sizeof(_cameraCenterRadius); // create a QByteArray that holds the binary representation of the JSON parameters QByteArray binaryParametersDocument; @@ -133,20 +104,15 @@ int OctreeQuery::parseData(ReceivedMessage& message) { } // check if this query uses a view frustum - memcpy(&_usesFrustum, sourceBuffer, sizeof(_usesFrustum)); - sourceBuffer += sizeof(_usesFrustum); - - if (_usesFrustum) { - // unpack camera details - memcpy(&_cameraPosition, sourceBuffer, sizeof(_cameraPosition)); - sourceBuffer += sizeof(_cameraPosition); - sourceBuffer += unpackOrientationQuatFromBytes(sourceBuffer, _cameraOrientation); - sourceBuffer += unpackFloatAngleFromTwoByte((uint16_t*) sourceBuffer, &_cameraFov); - sourceBuffer += unpackFloatRatioFromTwoByte(sourceBuffer,_cameraAspectRatio); - sourceBuffer += unpackClipValueFromTwoByte(sourceBuffer,_cameraNearClip); - sourceBuffer += unpackClipValueFromTwoByte(sourceBuffer,_cameraFarClip); - memcpy(&_cameraEyeOffsetPosition, sourceBuffer, sizeof(_cameraEyeOffsetPosition)); - sourceBuffer += sizeof(_cameraEyeOffsetPosition); + uint8_t numFrustums = 0; + memcpy(&numFrustums, sourceBuffer, sizeof(numFrustums)); + sourceBuffer += sizeof(numFrustums); + + _conicalViews.clear(); + for (int i = 0; i < numFrustums; ++i) { + ConicalViewFrustum view; + sourceBuffer += view.deserialize(sourceBuffer); + _conicalViews.push_back(view); } // desired Max Octree PPS @@ -161,9 +127,6 @@ int OctreeQuery::parseData(ReceivedMessage& message) { memcpy(&_boundaryLevelAdjust, sourceBuffer, sizeof(_boundaryLevelAdjust)); sourceBuffer += sizeof(_boundaryLevelAdjust); - memcpy(&_cameraCenterRadius, sourceBuffer, sizeof(_cameraCenterRadius)); - sourceBuffer += sizeof(_cameraCenterRadius); - // check if we have a packed JSON filter uint16_t binaryParametersBytes; memcpy(&binaryParametersBytes, sourceBuffer, sizeof(binaryParametersBytes)); @@ -184,8 +147,3 @@ int OctreeQuery::parseData(ReceivedMessage& message) { return sourceBuffer - startPosition; } - -glm::vec3 OctreeQuery::calculateCameraDirection() const { - glm::vec3 direction = glm::vec3(_cameraOrientation * glm::vec4(IDENTITY_FORWARD, 0.0f)); - return direction; -} diff --git a/libraries/octree/src/OctreeQuery.h b/libraries/octree/src/OctreeQuery.h index 21ce2e7fac..7dfc1cfaaf 100644 --- a/libraries/octree/src/OctreeQuery.h +++ b/libraries/octree/src/OctreeQuery.h @@ -12,16 +12,13 @@ #ifndef hifi_OctreeQuery_h #define hifi_OctreeQuery_h -#include - -#include -#include - #include #include #include +#include +#include "OctreeConstants.h" class OctreeQuery : public NodeData { Q_OBJECT @@ -30,31 +27,16 @@ public: OctreeQuery(bool randomizeConnectionID = false); virtual ~OctreeQuery() {} + OctreeQuery(const OctreeQuery&) = delete; + OctreeQuery& operator=(const OctreeQuery&) = delete; + int getBroadcastData(unsigned char* destinationBuffer); int parseData(ReceivedMessage& message) override; - // getters for camera details - const glm::vec3& getCameraPosition() const { return _cameraPosition; } - const glm::quat& getCameraOrientation() const { return _cameraOrientation; } - float getCameraFov() const { return _cameraFov; } - float getCameraAspectRatio() const { return _cameraAspectRatio; } - float getCameraNearClip() const { return _cameraNearClip; } - float getCameraFarClip() const { return _cameraFarClip; } - const glm::vec3& getCameraEyeOffsetPosition() const { return _cameraEyeOffsetPosition; } - float getCameraCenterRadius() const { return _cameraCenterRadius; } + bool hasConicalViews() const { return !_conicalViews.empty(); } + void setConicalViews(ConicalViewFrustums views) { _conicalViews = views; } + void clearConicalViews() { _conicalViews.clear(); } - glm::vec3 calculateCameraDirection() const; - - // setters for camera details - void setCameraPosition(const glm::vec3& position) { _cameraPosition = position; } - void setCameraOrientation(const glm::quat& orientation) { _cameraOrientation = orientation; } - void setCameraFov(float fov) { _cameraFov = fov; } - void setCameraAspectRatio(float aspectRatio) { _cameraAspectRatio = aspectRatio; } - void setCameraNearClip(float nearClip) { _cameraNearClip = nearClip; } - void setCameraFarClip(float farClip) { _cameraFarClip = farClip; } - void setCameraEyeOffsetPosition(const glm::vec3& eyeOffsetPosition) { _cameraEyeOffsetPosition = eyeOffsetPosition; } - void setCameraCenterRadius(float radius) { _cameraCenterRadius = radius; } - // getters/setters for JSON filter QJsonObject getJSONParameters() { QReadLocker locker { &_jsonParametersLock }; return _jsonParameters; } void setJSONParameters(const QJsonObject& jsonParameters) @@ -64,9 +46,6 @@ public: int getMaxQueryPacketsPerSecond() const { return _maxQueryPPS; } float getOctreeSizeScale() const { return _octreeElementSizeScale; } int getBoundaryLevelAdjust() const { return _boundaryLevelAdjust; } - - bool getUsesFrustum() { return _usesFrustum; } - void setUsesFrustum(bool usesFrustum) { _usesFrustum = usesFrustum; } void incrementConnectionID() { ++_connectionID; } @@ -81,33 +60,19 @@ public slots: void setBoundaryLevelAdjust(int boundaryLevelAdjust) { _boundaryLevelAdjust = boundaryLevelAdjust; } protected: - // camera details for the avatar - glm::vec3 _cameraPosition { glm::vec3(0.0f) }; - glm::quat _cameraOrientation { glm::quat() }; - float _cameraFov; - float _cameraAspectRatio; - float _cameraNearClip; - float _cameraFarClip; - float _cameraCenterRadius; - glm::vec3 _cameraEyeOffsetPosition { glm::vec3(0.0f) }; + ConicalViewFrustums _conicalViews; // octree server sending items int _maxQueryPPS = DEFAULT_MAX_OCTREE_PPS; float _octreeElementSizeScale = DEFAULT_OCTREE_SIZE_SCALE; /// used for LOD calculations int _boundaryLevelAdjust = 0; /// used for LOD calculations - - uint8_t _usesFrustum = true; + uint16_t _connectionID; // query connection ID, randomized to start, increments with each new connection to server QJsonObject _jsonParameters; QReadWriteLock _jsonParametersLock; bool _hasReceivedFirstQuery { false }; - -private: - // privatize the copy constructor and assignment operator so they cannot be called - OctreeQuery(const OctreeQuery&); - OctreeQuery& operator= (const OctreeQuery&); }; #endif // hifi_OctreeQuery_h diff --git a/libraries/octree/src/OctreeQueryNode.cpp b/libraries/octree/src/OctreeQueryNode.cpp index 16542b697e..2d1d89a11c 100644 --- a/libraries/octree/src/OctreeQueryNode.cpp +++ b/libraries/octree/src/OctreeQueryNode.cpp @@ -139,81 +139,61 @@ void OctreeQueryNode::writeToPacket(const unsigned char* buffer, unsigned int by } } -void OctreeQueryNode::copyCurrentViewFrustum(ViewFrustum& viewOut) const { - QMutexLocker viewLocker(&_viewMutex); - viewOut = _currentViewFrustum; -} - bool OctreeQueryNode::updateCurrentViewFrustum() { // if shutting down, return immediately if (_isShuttingDown) { return false; } - if (!_usesFrustum) { + if (!hasConicalViews()) { // this client does not use a view frustum so the view frustum for this query has not changed return false; - } else { - bool currentViewFrustumChanged = false; - - ViewFrustum newestViewFrustum; - // get position and orientation details from the camera - newestViewFrustum.setPosition(getCameraPosition()); - newestViewFrustum.setOrientation(getCameraOrientation()); - - newestViewFrustum.setCenterRadius(getCameraCenterRadius()); - - // Also make sure it's got the correct lens details from the camera - float originalFOV = getCameraFov(); - float wideFOV = originalFOV + VIEW_FRUSTUM_FOV_OVERSEND; - - if (0.0f != getCameraAspectRatio() && - 0.0f != getCameraNearClip() && - 0.0f != getCameraFarClip() && - getCameraNearClip() != getCameraFarClip()) { - newestViewFrustum.setProjection(glm::perspective( - glm::radians(wideFOV), // hack - getCameraAspectRatio(), - getCameraNearClip(), - getCameraFarClip())); - newestViewFrustum.calculate(); - } - - - { // if there has been a change, then recalculate - QMutexLocker viewLocker(&_viewMutex); - if (!newestViewFrustum.isVerySimilar(_currentViewFrustum)) { - _currentViewFrustum = newestViewFrustum; - currentViewFrustumChanged = true; - } - } - - // Also check for LOD changes from the client - if (_lodInitialized) { - if (_lastClientBoundaryLevelAdjust != getBoundaryLevelAdjust()) { - _lastClientBoundaryLevelAdjust = getBoundaryLevelAdjust(); - _lodChanged = true; - } - if (_lastClientOctreeSizeScale != getOctreeSizeScale()) { - _lastClientOctreeSizeScale = getOctreeSizeScale(); - _lodChanged = true; + } + + bool currentViewFrustumChanged = false; + + { // if there has been a change, then recalculate + QMutexLocker viewLocker(&_viewMutex); + + if (_conicalViews.size() == _currentConicalViews.size()) { + for (size_t i = 0; i < _conicalViews.size(); ++i) { + if (!_conicalViews[i].isVerySimilar(_currentConicalViews[i])) { + _currentConicalViews = _conicalViews; + currentViewFrustumChanged = true; + break; + } } } else { - _lodInitialized = true; - _lastClientOctreeSizeScale = getOctreeSizeScale(); - _lastClientBoundaryLevelAdjust = getBoundaryLevelAdjust(); - _lodChanged = false; + _currentConicalViews = _conicalViews; + currentViewFrustumChanged = true; } - - // When we first detect that the view stopped changing, we record this. - // but we don't change it back to false until we've completely sent this - // scene. - if (_viewFrustumChanging && !currentViewFrustumChanged) { - _viewFrustumJustStoppedChanging = true; - } - _viewFrustumChanging = currentViewFrustumChanged; - return currentViewFrustumChanged; } + + // Also check for LOD changes from the client + if (_lodInitialized) { + if (_lastClientBoundaryLevelAdjust != getBoundaryLevelAdjust()) { + _lastClientBoundaryLevelAdjust = getBoundaryLevelAdjust(); + _lodChanged = true; + } + if (_lastClientOctreeSizeScale != getOctreeSizeScale()) { + _lastClientOctreeSizeScale = getOctreeSizeScale(); + _lodChanged = true; + } + } else { + _lodInitialized = true; + _lastClientOctreeSizeScale = getOctreeSizeScale(); + _lastClientBoundaryLevelAdjust = getBoundaryLevelAdjust(); + _lodChanged = false; + } + + // When we first detect that the view stopped changing, we record this. + // but we don't change it back to false until we've completely sent this + // scene. + if (_viewFrustumChanging && !currentViewFrustumChanged) { + _viewFrustumJustStoppedChanging = true; + } + _viewFrustumChanging = currentViewFrustumChanged; + return currentViewFrustumChanged; } void OctreeQueryNode::setViewSent(bool viewSent) { diff --git a/libraries/octree/src/OctreeQueryNode.h b/libraries/octree/src/OctreeQueryNode.h index 640a7c7ddc..d984e048c1 100644 --- a/libraries/octree/src/OctreeQueryNode.h +++ b/libraries/octree/src/OctreeQueryNode.h @@ -14,14 +14,14 @@ #include -#include +#include + #include "OctreeConstants.h" #include "OctreeElementBag.h" #include "OctreePacketData.h" #include "OctreeQuery.h" #include "OctreeSceneStats.h" #include "SentPacketHistory.h" -#include class OctreeSendThread; class OctreeServer; @@ -49,7 +49,7 @@ public: OctreeElementExtraEncodeData extraEncodeData; - void copyCurrentViewFrustum(ViewFrustum& viewOut) const; + const ConicalViewFrustums& getCurrentViews() const { return _currentConicalViews; } // These are not classic setters because they are calculating and maintaining state // which is set asynchronously through the network receive @@ -87,9 +87,6 @@ public: void setShouldForceFullScene(bool shouldForceFullScene) { _shouldForceFullScene = shouldForceFullScene; } private: - OctreeQueryNode(const OctreeQueryNode &); - OctreeQueryNode& operator= (const OctreeQueryNode&); - bool _viewSent { false }; std::unique_ptr _octreePacket; bool _octreePacketWaiting; @@ -99,7 +96,7 @@ private: quint64 _firstSuppressedPacket { usecTimestampNow() }; mutable QMutex _viewMutex { QMutex::Recursive }; - ViewFrustum _currentViewFrustum; + ConicalViewFrustums _currentConicalViews; bool _viewFrustumChanging { false }; bool _viewFrustumJustStoppedChanging { true }; diff --git a/libraries/octree/src/OctreeSceneStats.cpp b/libraries/octree/src/OctreeSceneStats.cpp index b2efdfd595..d8ff6ba0ec 100644 --- a/libraries/octree/src/OctreeSceneStats.cpp +++ b/libraries/octree/src/OctreeSceneStats.cpp @@ -9,6 +9,8 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include "OctreeSceneStats.h" + #include #include #include @@ -20,8 +22,6 @@ #include "OctreePacketData.h" #include "OctreeElement.h" #include "OctreeLogging.h" -#include "OctreeSceneStats.h" - const int samples = 100; OctreeSceneStats::OctreeSceneStats() : diff --git a/libraries/octree/src/OctreeScriptingInterface.cpp b/libraries/octree/src/OctreeScriptingInterface.cpp index 618e8ac469..b1729c649e 100644 --- a/libraries/octree/src/OctreeScriptingInterface.cpp +++ b/libraries/octree/src/OctreeScriptingInterface.cpp @@ -9,10 +9,10 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -#include - #include "OctreeScriptingInterface.h" +#include + OctreeScriptingInterface::OctreeScriptingInterface(OctreeEditPacketSender* packetSender) : _packetSender(packetSender), _managedPacketSender(false), diff --git a/libraries/octree/src/OctreeUtils.cpp b/libraries/octree/src/OctreeUtils.cpp index 8980504431..8eaf22e198 100644 --- a/libraries/octree/src/OctreeUtils.cpp +++ b/libraries/octree/src/OctreeUtils.cpp @@ -16,6 +16,7 @@ #include #include +#include float calculateRenderAccuracy(const glm::vec3& position, const AABox& bounds, @@ -73,4 +74,10 @@ float getOrthographicAccuracySize(float octreeSizeScale, int boundaryLevelAdjust // Smallest visible element is 1cm const float smallestSize = 0.01f; return (smallestSize * MAX_VISIBILITY_DISTANCE_FOR_UNIT_ELEMENT) / boundaryDistanceForRenderLevel(boundaryLevelAdjust, octreeSizeScale); -} \ No newline at end of file +} + +bool isAngularSizeBigEnough(glm::vec3 position, const AACube& cube, float lodScaleFactor, float minDiameter) { + float distance = glm::distance(cube.calcCenter(), position) + MIN_VISIBLE_DISTANCE; + float angularDiameter = cube.getScale() / distance; + return angularDiameter > minDiameter * lodScaleFactor; +} diff --git a/libraries/octree/src/OctreeUtils.h b/libraries/octree/src/OctreeUtils.h index d5008376ea..dff56cad64 100644 --- a/libraries/octree/src/OctreeUtils.h +++ b/libraries/octree/src/OctreeUtils.h @@ -12,9 +12,12 @@ #ifndef hifi_OctreeUtils_h #define hifi_OctreeUtils_h +#include + #include "OctreeConstants.h" class AABox; +class AACube; class QJsonDocument; /// renderAccuracy represents a floating point "visibility" of an object based on it's view from the camera. At a simple @@ -32,8 +35,9 @@ float getOrthographicAccuracySize(float octreeSizeScale, int boundaryLevelAdjust // MIN_ELEMENT_ANGULAR_DIAMETER = angular diameter of 1x1x1m cube at 400m = sqrt(3) / 400 = 0.0043301 radians ~= 0.25 degrees const float MIN_ELEMENT_ANGULAR_DIAMETER = 0.0043301f; // radians // NOTE: the entity bounding cube is larger than the smallest possible containing octree element by sqrt(3) -const float SQRT_THREE = 1.73205080f; const float MIN_ENTITY_ANGULAR_DIAMETER = MIN_ELEMENT_ANGULAR_DIAMETER * SQRT_THREE; const float MIN_VISIBLE_DISTANCE = 0.0001f; // helps avoid divide-by-zero check +bool isAngularSizeBigEnough(glm::vec3 position, const AACube& cube, float lodScaleFactor, float minDiameter); + #endif // hifi_OctreeUtils_h diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp index 68f21eea87..a801392b66 100644 --- a/libraries/physics/src/EntityMotionState.cpp +++ b/libraries/physics/src/EntityMotionState.cpp @@ -9,6 +9,8 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include "EntityMotionState.h" + #include #include @@ -19,7 +21,6 @@ #include #include "BulletUtil.h" -#include "EntityMotionState.h" #include "PhysicsEngine.h" #include "PhysicsHelpers.h" #include "PhysicsLogging.h" diff --git a/libraries/physics/src/MeshMassProperties.cpp b/libraries/physics/src/MeshMassProperties.cpp index a6a33932aa..ad4208e6a1 100644 --- a/libraries/physics/src/MeshMassProperties.cpp +++ b/libraries/physics/src/MeshMassProperties.cpp @@ -9,11 +9,11 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include "MeshMassProperties.h" + #include #include -#include "MeshMassProperties.h" - // this method is included for unit test verification void computeBoxInertia(btScalar mass, const btVector3& diagonal, btMatrix3x3& inertia) { // formula for box inertia tensor: diff --git a/libraries/physics/src/ObjectAction.cpp b/libraries/physics/src/ObjectAction.cpp index 87732ded03..dfcf1aba33 100644 --- a/libraries/physics/src/ObjectAction.cpp +++ b/libraries/physics/src/ObjectAction.cpp @@ -9,10 +9,10 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -#include "EntitySimulation.h" - #include "ObjectAction.h" +#include "EntitySimulation.h" + #include "PhysicsLogging.h" diff --git a/libraries/physics/src/ObjectActionOffset.cpp b/libraries/physics/src/ObjectActionOffset.cpp index e90862266b..4c2ed35f8e 100644 --- a/libraries/physics/src/ObjectActionOffset.cpp +++ b/libraries/physics/src/ObjectActionOffset.cpp @@ -9,10 +9,10 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -#include "QVariantGLM.h" - #include "ObjectActionOffset.h" +#include "QVariantGLM.h" + #include "PhysicsLogging.h" diff --git a/libraries/physics/src/ObjectActionTractor.cpp b/libraries/physics/src/ObjectActionTractor.cpp index 9b2da22665..a48989be33 100644 --- a/libraries/physics/src/ObjectActionTractor.cpp +++ b/libraries/physics/src/ObjectActionTractor.cpp @@ -9,10 +9,10 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -#include "QVariantGLM.h" - #include "ObjectActionTractor.h" +#include "QVariantGLM.h" + #include "PhysicsLogging.h" const float TRACTOR_MAX_SPEED = 10.0f; diff --git a/libraries/physics/src/ObjectActionTravelOriented.cpp b/libraries/physics/src/ObjectActionTravelOriented.cpp index accade8695..c93cce2482 100644 --- a/libraries/physics/src/ObjectActionTravelOriented.cpp +++ b/libraries/physics/src/ObjectActionTravelOriented.cpp @@ -9,10 +9,11 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include "ObjectActionTravelOriented.h" + #include #include "QVariantGLM.h" -#include "ObjectActionTravelOriented.h" #include "PhysicsLogging.h" const uint16_t ObjectActionTravelOriented::actionVersion = 1; diff --git a/libraries/physics/src/ObjectConstraint.cpp b/libraries/physics/src/ObjectConstraint.cpp index 54fd4777e0..38467b1d83 100644 --- a/libraries/physics/src/ObjectConstraint.cpp +++ b/libraries/physics/src/ObjectConstraint.cpp @@ -9,10 +9,10 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -#include "EntitySimulation.h" - #include "ObjectConstraint.h" +#include "EntitySimulation.h" + #include "PhysicsLogging.h" ObjectConstraint::ObjectConstraint(EntityDynamicType type, const QUuid& id, EntityItemPointer ownerEntity) : diff --git a/libraries/physics/src/ObjectConstraintBallSocket.cpp b/libraries/physics/src/ObjectConstraintBallSocket.cpp index 4736f2c9e2..b7a186e187 100644 --- a/libraries/physics/src/ObjectConstraintBallSocket.cpp +++ b/libraries/physics/src/ObjectConstraintBallSocket.cpp @@ -9,12 +9,13 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include "ObjectConstraintBallSocket.h" + #include #include "QVariantGLM.h" #include "EntityTree.h" -#include "ObjectConstraintBallSocket.h" #include "PhysicsLogging.h" diff --git a/libraries/physics/src/ObjectConstraintConeTwist.cpp b/libraries/physics/src/ObjectConstraintConeTwist.cpp index 47228c1c16..e2b86a9e0f 100644 --- a/libraries/physics/src/ObjectConstraintConeTwist.cpp +++ b/libraries/physics/src/ObjectConstraintConeTwist.cpp @@ -9,12 +9,13 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include "ObjectConstraintConeTwist.h" + #include #include "QVariantGLM.h" #include "EntityTree.h" -#include "ObjectConstraintConeTwist.h" #include "PhysicsLogging.h" const uint16_t CONE_TWIST_VERSION_WITH_UNUSED_PAREMETERS = 1; diff --git a/libraries/physics/src/ObjectConstraintHinge.cpp b/libraries/physics/src/ObjectConstraintHinge.cpp index 4793741391..0a01f413dc 100644 --- a/libraries/physics/src/ObjectConstraintHinge.cpp +++ b/libraries/physics/src/ObjectConstraintHinge.cpp @@ -9,12 +9,13 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include "ObjectConstraintHinge.h" + #include #include "QVariantGLM.h" #include "EntityTree.h" -#include "ObjectConstraintHinge.h" #include "PhysicsLogging.h" diff --git a/libraries/physics/src/ObjectConstraintSlider.cpp b/libraries/physics/src/ObjectConstraintSlider.cpp index da5bba7f4d..4776e0e4a6 100644 --- a/libraries/physics/src/ObjectConstraintSlider.cpp +++ b/libraries/physics/src/ObjectConstraintSlider.cpp @@ -9,12 +9,13 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include "ObjectConstraintSlider.h" + #include #include "QVariantGLM.h" #include "EntityTree.h" -#include "ObjectConstraintSlider.h" #include "PhysicsLogging.h" diff --git a/libraries/physics/src/ObjectDynamic.cpp b/libraries/physics/src/ObjectDynamic.cpp index 5bbb5981d1..3341025a8f 100644 --- a/libraries/physics/src/ObjectDynamic.cpp +++ b/libraries/physics/src/ObjectDynamic.cpp @@ -9,10 +9,10 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -#include "EntitySimulation.h" - #include "ObjectDynamic.h" +#include "EntitySimulation.h" + #include "PhysicsLogging.h" diff --git a/libraries/physics/src/ObjectMotionState.cpp b/libraries/physics/src/ObjectMotionState.cpp index b11e21366e..64d2368207 100644 --- a/libraries/physics/src/ObjectMotionState.cpp +++ b/libraries/physics/src/ObjectMotionState.cpp @@ -9,10 +9,11 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include "ObjectMotionState.h" + #include #include "BulletUtil.h" -#include "ObjectMotionState.h" #include "PhysicsEngine.h" #include "PhysicsHelpers.h" #include "PhysicsLogging.h" diff --git a/libraries/physics/src/PhysicsDebugDraw.cpp b/libraries/physics/src/PhysicsDebugDraw.cpp new file mode 100644 index 0000000000..b2911219d5 --- /dev/null +++ b/libraries/physics/src/PhysicsDebugDraw.cpp @@ -0,0 +1,54 @@ +// +// PhysicsDebugDraw.cpp +// libraries/physics/src +// +// Created by Anthony Thibault 2018-4-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 +// + +#include "PhysicsDebugDraw.h" +#include "BulletUtil.h" +#include "PhysicsLogging.h" + +#include +#include + +void PhysicsDebugDraw::drawLine(const btVector3& from, const btVector3& to, const btVector3& color) { + DebugDraw::getInstance().drawRay(bulletToGLM(from), bulletToGLM(to), glm::vec4(color.getX(), color.getY(), color.getZ(), 1.0f)); +} + +void PhysicsDebugDraw::drawContactPoint(const btVector3& PointOnB, const btVector3& normalOnB, btScalar distance, + int lifeTime, const btVector3& color) { + + glm::vec3 normal, tangent, biNormal; + generateBasisVectors(bulletToGLM(normalOnB), Vectors::UNIT_X, normal, tangent, biNormal); + btVector3 u = glmToBullet(normal); + btVector3 v = glmToBullet(tangent); + btVector3 w = glmToBullet(biNormal); + + // x marks the spot, green is along the normal. + const float CONTACT_POINT_RADIUS = 0.1f; + const btVector3 GREEN(0.0f, 1.0f, 0.0f); + const btVector3 WHITE(1.0f, 1.0f, 1.0f); + drawLine(PointOnB - u * CONTACT_POINT_RADIUS, PointOnB + u * CONTACT_POINT_RADIUS, GREEN); + drawLine(PointOnB - v * CONTACT_POINT_RADIUS, PointOnB + v * CONTACT_POINT_RADIUS, WHITE); + drawLine(PointOnB - w * CONTACT_POINT_RADIUS, PointOnB + w * CONTACT_POINT_RADIUS, WHITE); +} + +void PhysicsDebugDraw::reportErrorWarning(const char* warningString) { + qCWarning(physics) << "BULLET:" << warningString; +} + +void PhysicsDebugDraw::draw3dText(const btVector3& location, const char* textString) { +} + +void PhysicsDebugDraw::setDebugMode(int debugMode) { + _debugDrawMode = debugMode; +} + +int PhysicsDebugDraw::getDebugMode() const { + return _debugDrawMode; +} diff --git a/libraries/physics/src/PhysicsDebugDraw.h b/libraries/physics/src/PhysicsDebugDraw.h new file mode 100644 index 0000000000..f653136474 --- /dev/null +++ b/libraries/physics/src/PhysicsDebugDraw.h @@ -0,0 +1,34 @@ +// +// PhysicsDebugDraw.h +// libraries/physics/src +// +// Created by Anthony Thibault 2018-4-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 +// +// http://bulletphysics.org/Bullet/BulletFull/classbtIDebugDraw.html + +#ifndef hifi_PhysicsDebugDraw_h +#define hifi_PhysicsDebugDraw_h + +#include +#include + +class PhysicsDebugDraw : public btIDebugDraw { +public: + using btIDebugDraw::drawLine; + virtual void drawLine(const btVector3& from, const btVector3& to, const btVector3& color) override; + virtual void drawContactPoint(const btVector3& PointOnB, const btVector3& normalOnB, btScalar distance, + int lifeTime, const btVector3& color) override; + virtual void reportErrorWarning(const char* warningString) override; + virtual void draw3dText(const btVector3& location, const char* textString) override; + virtual void setDebugMode(int debugMode) override; + virtual int getDebugMode() const override; + +protected: + uint32_t _debugDrawMode; +}; + +#endif // hifi_PhysicsDebugDraw_h diff --git a/libraries/physics/src/PhysicsEngine.cpp b/libraries/physics/src/PhysicsEngine.cpp index 7c2ad55405..83ffa21a55 100644 --- a/libraries/physics/src/PhysicsEngine.cpp +++ b/libraries/physics/src/PhysicsEngine.cpp @@ -9,19 +9,20 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -#include +#include "PhysicsEngine.h" #include #include #include +#include #include #include "CharacterController.h" #include "ObjectMotionState.h" -#include "PhysicsEngine.h" #include "PhysicsHelpers.h" +#include "PhysicsDebugDraw.h" #include "ThreadSafeDynamicsWorld.h" #include "PhysicsLogging.h" @@ -49,6 +50,10 @@ void PhysicsEngine::init() { _broadphaseFilter = new btDbvtBroadphase(); _constraintSolver = new btSequentialImpulseConstraintSolver; _dynamicsWorld = new ThreadSafeDynamicsWorld(_collisionDispatcher, _broadphaseFilter, _constraintSolver, _collisionConfig); + _physicsDebugDraw.reset(new PhysicsDebugDraw()); + + // hook up debug draw renderer + _dynamicsWorld->setDebugDrawer(_physicsDebugDraw.get()); _ghostPairCallback = new btGhostPairCallback(); _dynamicsWorld->getPairCache()->setInternalGhostPairCallback(_ghostPairCallback); @@ -333,6 +338,10 @@ void PhysicsEngine::stepSimulation() { _hasOutgoingChanges = true; } + + if (_physicsDebugDraw->getDebugMode()) { + _dynamicsWorld->debugDrawWorld(); + } } class CProfileOperator { @@ -785,3 +794,49 @@ void PhysicsEngine::forEachDynamic(std::function act } } } + +void PhysicsEngine::setShowBulletWireframe(bool value) { + int mode = _physicsDebugDraw->getDebugMode(); + if (value) { + _physicsDebugDraw->setDebugMode(mode | btIDebugDraw::DBG_DrawWireframe); + } else { + _physicsDebugDraw->setDebugMode(mode & ~btIDebugDraw::DBG_DrawWireframe); + } +} + +void PhysicsEngine::setShowBulletAABBs(bool value) { + int mode = _physicsDebugDraw->getDebugMode(); + if (value) { + _physicsDebugDraw->setDebugMode(mode | btIDebugDraw::DBG_DrawAabb); + } else { + _physicsDebugDraw->setDebugMode(mode & ~btIDebugDraw::DBG_DrawAabb); + } +} + +void PhysicsEngine::setShowBulletContactPoints(bool value) { + int mode = _physicsDebugDraw->getDebugMode(); + if (value) { + _physicsDebugDraw->setDebugMode(mode | btIDebugDraw::DBG_DrawContactPoints); + } else { + _physicsDebugDraw->setDebugMode(mode & ~btIDebugDraw::DBG_DrawContactPoints); + } +} + +void PhysicsEngine::setShowBulletConstraints(bool value) { + int mode = _physicsDebugDraw->getDebugMode(); + if (value) { + _physicsDebugDraw->setDebugMode(mode | btIDebugDraw::DBG_DrawConstraints); + } else { + _physicsDebugDraw->setDebugMode(mode & ~btIDebugDraw::DBG_DrawConstraints); + } +} + +void PhysicsEngine::setShowBulletConstraintLimits(bool value) { + int mode = _physicsDebugDraw->getDebugMode(); + if (value) { + _physicsDebugDraw->setDebugMode(mode | btIDebugDraw::DBG_DrawConstraintLimits); + } else { + _physicsDebugDraw->setDebugMode(mode & ~btIDebugDraw::DBG_DrawConstraintLimits); + } +} + diff --git a/libraries/physics/src/PhysicsEngine.h b/libraries/physics/src/PhysicsEngine.h index 92d2e6885a..0dfe3a7a7c 100644 --- a/libraries/physics/src/PhysicsEngine.h +++ b/libraries/physics/src/PhysicsEngine.h @@ -30,6 +30,7 @@ const float HALF_SIMULATION_EXTENT = 512.0f; // meters class CharacterController; +class PhysicsDebugDraw; // simple class for keeping track of contacts class ContactKey { @@ -96,6 +97,12 @@ public: void removeDynamic(const QUuid dynamicID); void forEachDynamic(std::function actor); + void setShowBulletWireframe(bool value); + void setShowBulletAABBs(bool value); + void setShowBulletContactPoints(bool value); + void setShowBulletConstraints(bool value); + void setShowBulletConstraintLimits(bool value); + private: QList removeDynamicsForBody(btRigidBody* body); void addObjectToDynamicsWorld(ObjectMotionState* motionState); @@ -114,6 +121,7 @@ private: btSequentialImpulseConstraintSolver* _constraintSolver = NULL; ThreadSafeDynamicsWorld* _dynamicsWorld = NULL; btGhostPairCallback* _ghostPairCallback = NULL; + std::unique_ptr _physicsDebugDraw; ContactMap _contactMap; CollisionEvents _collisionEvents; diff --git a/libraries/physics/src/ShapeFactory.cpp b/libraries/physics/src/ShapeFactory.cpp index 5abeb022aa..8057eb0e0c 100644 --- a/libraries/physics/src/ShapeFactory.cpp +++ b/libraries/physics/src/ShapeFactory.cpp @@ -9,11 +9,12 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include "ShapeFactory.h" + #include #include // for MILLIMETERS_PER_METER -#include "ShapeFactory.h" #include "BulletUtil.h" diff --git a/libraries/physics/src/ShapeManager.cpp b/libraries/physics/src/ShapeManager.cpp index 97b9e5dab1..ef7a4a1749 100644 --- a/libraries/physics/src/ShapeManager.cpp +++ b/libraries/physics/src/ShapeManager.cpp @@ -9,12 +9,13 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -#include +#include "ShapeManager.h" #include +#include + #include "ShapeFactory.h" -#include "ShapeManager.h" ShapeManager::ShapeManager() { } diff --git a/libraries/physics/src/ThreadSafeDynamicsWorld.cpp b/libraries/physics/src/ThreadSafeDynamicsWorld.cpp index 5b8c0d5843..3f24851dce 100644 --- a/libraries/physics/src/ThreadSafeDynamicsWorld.cpp +++ b/libraries/physics/src/ThreadSafeDynamicsWorld.cpp @@ -15,9 +15,10 @@ * Copied and modified from btDiscreteDynamicsWorld.cpp by AndrewMeadows on 2014.11.12. * */ +#include "ThreadSafeDynamicsWorld.h" + #include -#include "ThreadSafeDynamicsWorld.h" #include "Profile.h" ThreadSafeDynamicsWorld::ThreadSafeDynamicsWorld( diff --git a/libraries/recording/src/recording/ClipCache.cpp b/libraries/recording/src/recording/ClipCache.cpp index 0fbbf1bc8e..c63350de7f 100644 --- a/libraries/recording/src/recording/ClipCache.cpp +++ b/libraries/recording/src/recording/ClipCache.cpp @@ -6,11 +6,12 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include "ClipCache.h" + #include #include -#include "ClipCache.h" #include "impl/PointerClip.h" #include "Logging.h" diff --git a/libraries/render-utils/src/AbstractViewStateInterface.h b/libraries/render-utils/src/AbstractViewStateInterface.h index 54fdc903ca..b90e291da5 100644 --- a/libraries/render-utils/src/AbstractViewStateInterface.h +++ b/libraries/render-utils/src/AbstractViewStateInterface.h @@ -24,6 +24,8 @@ class Transform; class QThread; class ViewFrustum; class PickRay; +class ConicalViewFrustum; +using ConicalViewFrustums = std::vector; /// Interface provided by Application to other objects that need access to the current view state details class AbstractViewStateInterface { @@ -31,6 +33,8 @@ public: /// copies the current view frustum for rendering the view state virtual void copyCurrentViewFrustum(ViewFrustum& viewOut) const = 0; + virtual const ConicalViewFrustums& getConicalViews() const = 0; + virtual QThread* getMainThread() = 0; virtual PickRay computePickRay(float x, float y) const = 0; diff --git a/libraries/render-utils/src/AmbientOcclusionEffect.cpp b/libraries/render-utils/src/AmbientOcclusionEffect.cpp index c526f16b75..2ac8e77898 100644 --- a/libraries/render-utils/src/AmbientOcclusionEffect.cpp +++ b/libraries/render-utils/src/AmbientOcclusionEffect.cpp @@ -9,11 +9,11 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // - -#include +#include "AmbientOcclusionEffect.h" #include //min max and more +#include #include #include @@ -22,7 +22,6 @@ #include "RenderUtilsLogging.h" #include "DeferredLightingEffect.h" -#include "AmbientOcclusionEffect.h" #include "TextureCache.h" #include "FramebufferCache.h" #include "DependencyManager.h" @@ -543,4 +542,4 @@ void DebugAmbientOcclusion::run(const render::RenderContextPointer& renderContex }); } - \ No newline at end of file + diff --git a/libraries/render-utils/src/AnimDebugDraw.cpp b/libraries/render-utils/src/AnimDebugDraw.cpp index 7086b65f4c..eca500f36c 100644 --- a/libraries/render-utils/src/AnimDebugDraw.cpp +++ b/libraries/render-utils/src/AnimDebugDraw.cpp @@ -52,9 +52,9 @@ public: batch.setInputFormat(_vertexFormat); batch.setInputBuffer(0, _vertexBuffer, 0, sizeof(Vertex)); - batch.setIndexBuffer(gpu::UINT16, _indexBuffer, 0); + batch.setIndexBuffer(gpu::UINT32, _indexBuffer, 0); - auto numIndices = _indexBuffer->getSize() / sizeof(uint16_t); + auto numIndices = _indexBuffer->getSize() / sizeof(uint32_t); batch.drawIndexed(gpu::LINES, (int)numIndices); } @@ -135,9 +135,9 @@ AnimDebugDraw::AnimDebugDraw() : AnimDebugDrawData::Vertex { glm::vec3(1.0, 1.0f, 1.0f), toRGBA(0, 0, 255, 255) }, AnimDebugDrawData::Vertex { glm::vec3(1.0, 1.0f, 2.0f), toRGBA(0, 0, 255, 255) }, }); - static std::vector indices({ 0, 1, 2, 3, 4, 5 }); + static std::vector indices({ 0, 1, 2, 3, 4, 5 }); _animDebugDrawData->_vertexBuffer->setSubData(0, vertices); - _animDebugDrawData->_indexBuffer->setSubData(0, indices); + _animDebugDrawData->_indexBuffer->setSubData(0, indices); } AnimDebugDraw::~AnimDebugDraw() { @@ -425,9 +425,9 @@ void AnimDebugDraw::update() { data._isVisible = (numVerts > 0); - data._indexBuffer->resize(sizeof(uint16_t) * numVerts); + data._indexBuffer->resize(sizeof(uint32_t) * numVerts); for (int i = 0; i < numVerts; i++) { - data._indexBuffer->setSubData(i, (uint16_t)i);; + data._indexBuffer->setSubData(i, (uint32_t)i);; } }); scene->enqueueTransaction(transaction); diff --git a/libraries/render-utils/src/AntialiasingEffect.cpp b/libraries/render-utils/src/AntialiasingEffect.cpp index dd4bda2e37..2173aef76a 100644 --- a/libraries/render-utils/src/AntialiasingEffect.cpp +++ b/libraries/render-utils/src/AntialiasingEffect.cpp @@ -9,6 +9,7 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include "AntialiasingEffect.h" #include @@ -17,7 +18,6 @@ #include #include -#include "AntialiasingEffect.h" #include "StencilMaskPass.h" #include "TextureCache.h" #include "DependencyManager.h" @@ -189,7 +189,6 @@ const int AntialiasingPass_NextMapSlot = 4; Antialiasing::Antialiasing(bool isSharpenEnabled) : _isSharpenEnabled{ isSharpenEnabled } { - _antialiasingBuffers = std::make_shared(2U); } Antialiasing::~Antialiasing() { @@ -325,25 +324,25 @@ void Antialiasing::run(const render::RenderContextPointer& renderContext, const int width = sourceBuffer->getWidth(); int height = sourceBuffer->getHeight(); - if (_antialiasingBuffers->get(0)) { - if (_antialiasingBuffers->get(0)->getSize() != uvec2(width, height)) {// || (sourceBuffer && (_antialiasingBuffer->getRenderBuffer(1) != sourceBuffer->getRenderBuffer(0)))) { - _antialiasingBuffers->edit(0).reset(); - _antialiasingBuffers->edit(1).reset(); - _antialiasingTextures[0].reset(); - _antialiasingTextures[1].reset(); - } + if (_antialiasingBuffers && _antialiasingBuffers->get(0) && _antialiasingBuffers->get(0)->getSize() != uvec2(width, height)) { + _antialiasingBuffers.reset(); + _antialiasingTextures[0].reset(); + _antialiasingTextures[1].reset(); } - if (!_antialiasingBuffers->get(0)) { + + if (!_antialiasingBuffers) { + std::vector antiAliasingBuffers; // Link the antialiasing FBO to texture auto format = sourceBuffer->getRenderBuffer(0)->getTexelFormat(); auto defaultSampler = gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_LINEAR, gpu::Sampler::WRAP_CLAMP); for (int i = 0; i < 2; i++) { - auto& antiAliasingBuffer = _antialiasingBuffers->edit(i); - antiAliasingBuffer = gpu::FramebufferPointer(gpu::Framebuffer::create("antialiasing")); + antiAliasingBuffers.emplace_back(gpu::Framebuffer::create("antialiasing")); + const auto& antiAliasingBuffer = antiAliasingBuffers.back(); _antialiasingTextures[i] = gpu::Texture::createRenderBuffer(format, width, height, gpu::Texture::SINGLE_MIP, defaultSampler); antiAliasingBuffer->setRenderBuffer(0, _antialiasingTextures[i]); } + _antialiasingBuffers = std::make_shared(antiAliasingBuffers); } gpu::doInBatch("Antialiasing::run", args->_context, [&](gpu::Batch& batch) { diff --git a/libraries/render-utils/src/LightStage.cpp b/libraries/render-utils/src/LightStage.cpp index 854ff71e20..ceac4ae3c8 100644 --- a/libraries/render-utils/src/LightStage.cpp +++ b/libraries/render-utils/src/LightStage.cpp @@ -9,12 +9,12 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -#include "ViewFrustum.h" - #include "LightStage.h" #include +#include "ViewFrustum.h" + std::string LightStage::_stageName { "LIGHT_STAGE"}; const glm::mat4 LightStage::Shadow::_biasMatrix{ 0.5, 0.0, 0.0, 0.0, diff --git a/libraries/render-utils/src/RenderPipelines.cpp b/libraries/render-utils/src/RenderPipelines.cpp index a3abb24afe..b02266e67b 100644 --- a/libraries/render-utils/src/RenderPipelines.cpp +++ b/libraries/render-utils/src/RenderPipelines.cpp @@ -10,10 +10,13 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include "RenderPipelines.h" + #include #include #include +#include #include "StencilMaskPass.h" #include "DeferredLightingEffect.h" @@ -615,9 +618,6 @@ void initZPassPipelines(ShapePlumber& shapePlumber, gpu::StatePointer state) { skinModelShadowFadeDualQuatProgram, state); } -#include "RenderPipelines.h" -#include - // FIXME find a better way to setup the default textures void RenderPipelines::bindMaterial(const graphics::MaterialPointer& material, gpu::Batch& batch, bool enableTextures) { if (!material) { diff --git a/libraries/render-utils/src/forward_simple.slf b/libraries/render-utils/src/forward_simple.slf index 587fcbde73..1ac44750a7 100644 --- a/libraries/render-utils/src/forward_simple.slf +++ b/libraries/render-utils/src/forward_simple.slf @@ -16,11 +16,21 @@ <@include ForwardGlobalLight.slh@> <$declareEvalSkyboxGlobalColor()$> + // the interpolated normal in vec3 _normalWS; +in vec3 _normalMS; in vec4 _color; +in vec2 _texCoord0; +in vec4 _positionMS; in vec4 _positionES; +// For retro-compatibility +#define _normal _normalWS +#define _modelNormal _normalMS +#define _position _positionMS +#define _eyePosition _positionES + layout(location = 0) out vec4 _fragColor0; //PROCEDURAL_COMMON_BLOCK diff --git a/libraries/render-utils/src/forward_simple_transparent.slf b/libraries/render-utils/src/forward_simple_transparent.slf index f40ba2ed4f..8be2759571 100644 --- a/libraries/render-utils/src/forward_simple_transparent.slf +++ b/libraries/render-utils/src/forward_simple_transparent.slf @@ -18,9 +18,18 @@ // the interpolated normal in vec3 _normalWS; +in vec3 _normalMS; in vec4 _color; +in vec2 _texCoord0; +in vec4 _positionMS; in vec4 _positionES; +// For retro-compatibility +#define _normal _normalWS +#define _modelNormal _normalMS +#define _position _positionMS +#define _eyePosition _positionES + layout(location = 0) out vec4 _fragColor0; //PROCEDURAL_COMMON_BLOCK diff --git a/libraries/render-utils/src/simple.slf b/libraries/render-utils/src/simple.slf index ed77777184..7591dc1882 100644 --- a/libraries/render-utils/src/simple.slf +++ b/libraries/render-utils/src/simple.slf @@ -16,7 +16,17 @@ // the interpolated normal in vec3 _normalWS; +in vec3 _normalMS; in vec4 _color; +in vec2 _texCoord0; +in vec4 _positionMS; +in vec4 _positionES; + +// For retro-compatibility +#define _normal _normalWS +#define _modelNormal _normalMS +#define _position _positionMS +#define _eyePosition _positionES //PROCEDURAL_COMMON_BLOCK diff --git a/libraries/render-utils/src/simple_fade.slf b/libraries/render-utils/src/simple_fade.slf index 6e7aee2894..0710c3e10b 100644 --- a/libraries/render-utils/src/simple_fade.slf +++ b/libraries/render-utils/src/simple_fade.slf @@ -19,9 +19,19 @@ // the interpolated normal in vec3 _normalWS; +in vec3 _normalMS; in vec4 _color; +in vec2 _texCoord0; +in vec4 _positionMS; +in vec4 _positionES; in vec4 _positionWS; +// For retro-compatibility +#define _normal _normalWS +#define _modelNormal _normalMS +#define _position _positionMS +#define _eyePosition _positionES + //PROCEDURAL_COMMON_BLOCK #line 1001 diff --git a/libraries/render-utils/src/simple_transparent.slf b/libraries/render-utils/src/simple_transparent.slf index c9815e8a80..ee79d2c0c4 100644 --- a/libraries/render-utils/src/simple_transparent.slf +++ b/libraries/render-utils/src/simple_transparent.slf @@ -16,7 +16,17 @@ // the interpolated normal in vec3 _normalWS; +in vec3 _normalMS; in vec4 _color; +in vec2 _texCoord0; +in vec4 _positionMS; +in vec4 _positionES; + +// For retro-compatibility +#define _normal _normalWS +#define _modelNormal _normalMS +#define _position _positionMS +#define _eyePosition _positionES //PROCEDURAL_COMMON_BLOCK diff --git a/libraries/render/src/render/DrawTask.cpp b/libraries/render/src/render/DrawTask.cpp index 8aabffea46..3a7555f790 100755 --- a/libraries/render/src/render/DrawTask.cpp +++ b/libraries/render/src/render/DrawTask.cpp @@ -9,19 +9,19 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -#include - #include "DrawTask.h" -#include "Logging.h" #include #include +#include #include #include #include #include +#include "Logging.h" + #include "drawItemBounds_vert.h" #include "drawItemBounds_frag.h" diff --git a/libraries/render/src/render/ShapePipeline.cpp b/libraries/render/src/render/ShapePipeline.cpp index 35cc66315b..703acc5fa6 100644 --- a/libraries/render/src/render/ShapePipeline.cpp +++ b/libraries/render/src/render/ShapePipeline.cpp @@ -9,12 +9,13 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -#include "DependencyManager.h" -#include "Logging.h" #include "ShapePipeline.h" #include +#include "DependencyManager.h" +#include "Logging.h" + using namespace render; ShapePipeline::CustomFactoryMap ShapePipeline::_globalCustomFactoryMap; @@ -182,4 +183,4 @@ const ShapePipelinePointer ShapePlumber::pickPipeline(RenderArgs* args, const Ke } return shapePipeline; -} \ No newline at end of file +} diff --git a/libraries/script-engine/src/ArrayBufferClass.cpp b/libraries/script-engine/src/ArrayBufferClass.cpp index 4a06dee391..f64dbeffd6 100644 --- a/libraries/script-engine/src/ArrayBufferClass.cpp +++ b/libraries/script-engine/src/ArrayBufferClass.cpp @@ -9,6 +9,8 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include "ArrayBufferClass.h" + #include #include "ArrayBufferPrototype.h" @@ -16,8 +18,6 @@ #include "ScriptEngine.h" #include "TypedArrays.h" -#include "ArrayBufferClass.h" - static const QString CLASS_NAME = "ArrayBuffer"; diff --git a/libraries/script-engine/src/ArrayBufferPrototype.cpp b/libraries/script-engine/src/ArrayBufferPrototype.cpp index 9739f67381..d75482aa2e 100644 --- a/libraries/script-engine/src/ArrayBufferPrototype.cpp +++ b/libraries/script-engine/src/ArrayBufferPrototype.cpp @@ -9,13 +9,14 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include "ArrayBufferPrototype.h" + #include #include #include #include "ArrayBufferClass.h" -#include "ArrayBufferPrototype.h" static const int QCOMPRESS_HEADER_POSITION = 0; static const int QCOMPRESS_HEADER_SIZE = 4; diff --git a/libraries/script-engine/src/AssetScriptingInterface.h b/libraries/script-engine/src/AssetScriptingInterface.h index 5cb1136b74..eb9a628ae3 100644 --- a/libraries/script-engine/src/AssetScriptingInterface.h +++ b/libraries/script-engine/src/AssetScriptingInterface.h @@ -27,6 +27,11 @@ /**jsdoc * The Assets API allows you to communicate with the Asset Browser. * @namespace Assets + * + * @hifi-interface + * @hifi-client-entity + * @hifi-server-entity + * @hifi-assignment-client */ class AssetScriptingInterface : public BaseAssetScriptingInterface, QScriptable { Q_OBJECT diff --git a/libraries/script-engine/src/BatchLoader.cpp b/libraries/script-engine/src/BatchLoader.cpp index 0c65d5c6f0..4e2943d536 100644 --- a/libraries/script-engine/src/BatchLoader.cpp +++ b/libraries/script-engine/src/BatchLoader.cpp @@ -9,15 +9,17 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include "BatchLoader.h" + #include #include - #include #include -#include "ScriptEngineLogging.h" -#include "BatchLoader.h" + #include #include + +#include "ScriptEngineLogging.h" #include "ResourceManager.h" #include "ScriptEngines.h" #include "ScriptCache.h" diff --git a/libraries/script-engine/src/ConsoleScriptingInterface.cpp b/libraries/script-engine/src/ConsoleScriptingInterface.cpp index b4ef98938d..60de04aa9e 100644 --- a/libraries/script-engine/src/ConsoleScriptingInterface.cpp +++ b/libraries/script-engine/src/ConsoleScriptingInterface.cpp @@ -15,8 +15,10 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -#include #include "ConsoleScriptingInterface.h" + +#include + #include "ScriptEngine.h" #define INDENTATION 4 // 1 Tab - 4 spaces diff --git a/libraries/script-engine/src/DataViewClass.cpp b/libraries/script-engine/src/DataViewClass.cpp index a65bdff617..3cc5443973 100644 --- a/libraries/script-engine/src/DataViewClass.cpp +++ b/libraries/script-engine/src/DataViewClass.cpp @@ -9,10 +9,10 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -#include "DataViewPrototype.h" - #include "DataViewClass.h" +#include "DataViewPrototype.h" + Q_DECLARE_METATYPE(QByteArray*) static const QString DATA_VIEW_NAME = "DataView"; @@ -91,4 +91,4 @@ QString DataViewClass::name() const { QScriptValue DataViewClass::prototype() const { return _proto; -} \ No newline at end of file +} diff --git a/libraries/script-engine/src/DataViewPrototype.cpp b/libraries/script-engine/src/DataViewPrototype.cpp index 8bab574f33..ef757a5cb4 100644 --- a/libraries/script-engine/src/DataViewPrototype.cpp +++ b/libraries/script-engine/src/DataViewPrototype.cpp @@ -8,14 +8,15 @@ // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // + +#include "DataViewPrototype.h" + #include #include #include "DataViewClass.h" -#include "DataViewPrototype.h" - Q_DECLARE_METATYPE(QByteArray*) DataViewPrototype::DataViewPrototype(QObject* parent) : QObject(parent) { diff --git a/libraries/script-engine/src/EventTypes.cpp b/libraries/script-engine/src/EventTypes.cpp index abdd934e5a..94c074d44e 100644 --- a/libraries/script-engine/src/EventTypes.cpp +++ b/libraries/script-engine/src/EventTypes.cpp @@ -9,6 +9,8 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include "EventTypes.h" + #include "KeyEvent.h" #include "MouseEvent.h" #include "SpatialEvent.h" @@ -16,8 +18,6 @@ #include "TouchEvent.h" #include "WheelEvent.h" -#include "EventTypes.h" - void registerEventTypes(QScriptEngine* engine) { qScriptRegisterMetaType(engine, KeyEvent::toScriptValue, KeyEvent::fromScriptValue); qScriptRegisterMetaType(engine, MouseEvent::toScriptValue, MouseEvent::fromScriptValue); diff --git a/libraries/script-engine/src/KeyEvent.cpp b/libraries/script-engine/src/KeyEvent.cpp index 581f9a816b..b0e622a774 100644 --- a/libraries/script-engine/src/KeyEvent.cpp +++ b/libraries/script-engine/src/KeyEvent.cpp @@ -9,13 +9,13 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include "KeyEvent.h" + #include #include #include "ScriptEngineLogging.h" -#include "KeyEvent.h" - KeyEvent::KeyEvent() : key(0), text(""), diff --git a/libraries/script-engine/src/Mat4.cpp b/libraries/script-engine/src/Mat4.cpp index 15015782e2..3e75d815c3 100644 --- a/libraries/script-engine/src/Mat4.cpp +++ b/libraries/script-engine/src/Mat4.cpp @@ -9,14 +9,17 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -#include -#include +#include "Mat4.h" + #include #include #include + +#include +#include + #include "ScriptEngineLogging.h" #include "ScriptEngine.h" -#include "Mat4.h" glm::mat4 Mat4::multiply(const glm::mat4& m1, const glm::mat4& m2) const { return m1 * m2; diff --git a/libraries/script-engine/src/MenuItemProperties.cpp b/libraries/script-engine/src/MenuItemProperties.cpp index 40254eeccb..2662ba406d 100644 --- a/libraries/script-engine/src/MenuItemProperties.cpp +++ b/libraries/script-engine/src/MenuItemProperties.cpp @@ -9,10 +9,10 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -#include -#include #include "MenuItemProperties.h" +#include +#include MenuItemProperties::MenuItemProperties(const QString& menuName, const QString& menuItemName, diff --git a/libraries/script-engine/src/MouseEvent.cpp b/libraries/script-engine/src/MouseEvent.cpp index 20bac96087..1bace0425f 100644 --- a/libraries/script-engine/src/MouseEvent.cpp +++ b/libraries/script-engine/src/MouseEvent.cpp @@ -9,11 +9,11 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include "MouseEvent.h" + #include #include -#include "MouseEvent.h" - MouseEvent::MouseEvent() : x(0.0f), y(0.0f), @@ -104,4 +104,4 @@ QScriptValue MouseEvent::toScriptValue(QScriptEngine* engine, const MouseEvent& void MouseEvent::fromScriptValue(const QScriptValue& object, MouseEvent& event) { // nothing for now... -} \ No newline at end of file +} diff --git a/libraries/script-engine/src/MouseEvent.h b/libraries/script-engine/src/MouseEvent.h index 0fbc688e5f..d9b00a8e01 100644 --- a/libraries/script-engine/src/MouseEvent.h +++ b/libraries/script-engine/src/MouseEvent.h @@ -13,6 +13,9 @@ #define hifi_MouseEvent_h #include +#include + +class QScriptEngine; class MouseEvent { public: @@ -38,4 +41,4 @@ public: Q_DECLARE_METATYPE(MouseEvent) -#endif // hifi_MouseEvent_h \ No newline at end of file +#endif // hifi_MouseEvent_h diff --git a/libraries/script-engine/src/Quat.cpp b/libraries/script-engine/src/Quat.cpp index a6f7acffc8..afff0a6b03 100644 --- a/libraries/script-engine/src/Quat.cpp +++ b/libraries/script-engine/src/Quat.cpp @@ -9,16 +9,17 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include "Quat.h" + #include +#include #include #include -#include -#include + #include "ScriptEngineLogging.h" #include "ScriptEngine.h" -#include "Quat.h" quat Quat::normalize(const glm::quat& q) { return glm::normalize(q); diff --git a/libraries/script-engine/src/Quat.h b/libraries/script-engine/src/Quat.h index e6e395d9bf..1ccdfdbf31 100644 --- a/libraries/script-engine/src/Quat.h +++ b/libraries/script-engine/src/Quat.h @@ -20,6 +20,8 @@ #include #include +#include + /**jsdoc * A quaternion value. See also the {@link Quat(0)|Quat} object. * @typedef {object} Quat @@ -35,6 +37,12 @@ * of gimbal lock. * @namespace Quat * @variation 0 + * + * @hifi-interface + * @hifi-client-entity + * @hifi-server-entity + * @hifi-assignment-client + * * @property IDENTITY {Quat} { x: 0, y: 0, z: 0, w: 1 } : The identity rotation, i.e., no rotation. * Read-only. * @example Print the IDENTITY value. diff --git a/libraries/script-engine/src/RecordingScriptingInterface.h b/libraries/script-engine/src/RecordingScriptingInterface.h index 0e4f90b928..29d9b31049 100644 --- a/libraries/script-engine/src/RecordingScriptingInterface.h +++ b/libraries/script-engine/src/RecordingScriptingInterface.h @@ -25,6 +25,10 @@ class QScriptValue; /**jsdoc * @namespace Recording + * + * @hifi-interface + * @hifi-client-entity + * @hifi-assignment-client */ class RecordingScriptingInterface : public QObject, public Dependency { Q_OBJECT diff --git a/libraries/script-engine/src/SceneScriptingInterface.h b/libraries/script-engine/src/SceneScriptingInterface.h index c69cd7090d..fdfbc6f6c0 100644 --- a/libraries/script-engine/src/SceneScriptingInterface.h +++ b/libraries/script-engine/src/SceneScriptingInterface.h @@ -112,6 +112,10 @@ namespace SceneScripting { /**jsdoc * @class Scene.Stage + * + * @hifi-interface + * @hifi-client-entity + * * @property {string} backgroundMode * @property {Scene.Stage.KeyLight} keyLight * @property {Scene.Stage.Location} location @@ -171,6 +175,10 @@ namespace SceneScripting { /**jsdoc * @namespace Scene + * + * @hifi-interface + * @hifi-client-entity + * * @property {boolean} shouldRenderAvatars * @property {boolean} shouldRenderEntities * @property {Scene.Stage} stage diff --git a/libraries/script-engine/src/ScriptAudioInjector.cpp b/libraries/script-engine/src/ScriptAudioInjector.cpp index 516f62401f..8b51377bff 100644 --- a/libraries/script-engine/src/ScriptAudioInjector.cpp +++ b/libraries/script-engine/src/ScriptAudioInjector.cpp @@ -9,9 +9,10 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -#include "ScriptEngineLogging.h" #include "ScriptAudioInjector.h" +#include "ScriptEngineLogging.h" + QScriptValue injectorToScriptValue(QScriptEngine* engine, ScriptAudioInjector* const& in) { // The AudioScriptingInterface::playSound method can return null, so we need to account for that. if (!in) { diff --git a/libraries/script-engine/src/ScriptEngine.cpp b/libraries/script-engine/src/ScriptEngine.cpp index f0a13cc62b..9a383454d4 100644 --- a/libraries/script-engine/src/ScriptEngine.cpp +++ b/libraries/script-engine/src/ScriptEngine.cpp @@ -9,6 +9,8 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include "ScriptEngine.h" + #include #include @@ -67,7 +69,6 @@ #include "ScriptAvatarData.h" #include "ScriptCache.h" #include "ScriptEngineLogging.h" -#include "ScriptEngine.h" #include "TypedArrays.h" #include "XMLHttpRequestClass.h" #include "WebSocketClass.h" @@ -180,6 +181,21 @@ ScriptEngine::ScriptEngine(Context context, const QString& scriptContents, const // don't delete `ScriptEngines` until all `ScriptEngine`s are gone _scriptEngines(DependencyManager::get()) { + switch (_context) { + case Context::CLIENT_SCRIPT: + _type = Type::CLIENT; + break; + case Context::ENTITY_CLIENT_SCRIPT: + _type = Type::ENTITY_CLIENT; + break; + case Context::ENTITY_SERVER_SCRIPT: + _type = Type::ENTITY_SERVER; + break; + case Context::AGENT_SCRIPT: + _type = Type::AGENT; + break; + } + connect(this, &QScriptEngine::signalHandlerException, this, [this](const QScriptValue& exception) { if (hasUncaughtException()) { // the engine's uncaughtException() seems to produce much better stack traces here diff --git a/libraries/script-engine/src/ScriptEngine.h b/libraries/script-engine/src/ScriptEngine.h index 63a4ba4f90..3001666b5d 100644 --- a/libraries/script-engine/src/ScriptEngine.h +++ b/libraries/script-engine/src/ScriptEngine.h @@ -89,6 +89,12 @@ public: /**jsdoc * @namespace Script + * + * @hifi-interface + * @hifi-client-entity + * @hifi-server-entity + * @hifi-assignment-client + * * @property {string} context */ class ScriptEngine : public BaseScriptEngine, public EntitiesScriptEngineProvider { @@ -103,6 +109,14 @@ public: AGENT_SCRIPT }; + enum Type { + CLIENT, + ENTITY_CLIENT, + ENTITY_SERVER, + AGENT, + AVATAR + }; + static int processLevelMaxRetries; ScriptEngine(Context context, const QString& scriptContents = NO_SCRIPT, const QString& fileNameString = QString("about:ScriptEngine")); ~ScriptEngine(); @@ -493,6 +507,9 @@ public: */ Q_INVOKABLE QUuid generateUUID() { return QUuid::createUuid(); } + void setType(Type type) { _type = type; }; + Type getType() { return _type; }; + bool isFinished() const { return _isFinished; } // used by Application and ScriptWidget bool isRunning() const { return _isRunning; } // used by ScriptWidget @@ -509,6 +526,9 @@ public: void setUserLoaded(bool isUserLoaded) { _isUserLoaded = isUserLoaded; } bool isUserLoaded() const { return _isUserLoaded; } + void setQuitWhenFinished(const bool quitWhenFinished) { _quitWhenFinished = quitWhenFinished; } + bool isQuitWhenFinished() const { return _quitWhenFinished; } + // NOTE - this is used by the TypedArray implementation. we need to review this for thread safety ArrayBufferClass* getArrayBufferClass() { return _arrayBufferClass; } @@ -724,6 +744,7 @@ protected: void callWithEnvironment(const EntityItemID& entityID, const QUrl& sandboxURL, QScriptValue function, QScriptValue thisObject, QScriptValueList args); Context _context; + Type _type; QString _scriptContents; QString _parentURL; std::atomic _isFinished { false }; @@ -750,6 +771,8 @@ protected: std::atomic _isUserLoaded { false }; bool _isReloading { false }; + std::atomic _quitWhenFinished; + ArrayBufferClass* _arrayBufferClass; AssetScriptingInterface* _assetScriptingInterface; diff --git a/libraries/script-engine/src/ScriptEngines.cpp b/libraries/script-engine/src/ScriptEngines.cpp index a788cd9f0e..ad6e1debe9 100644 --- a/libraries/script-engine/src/ScriptEngines.cpp +++ b/libraries/script-engine/src/ScriptEngines.cpp @@ -347,7 +347,8 @@ void ScriptEngines::saveScripts() { { QReadLocker lock(&_scriptEnginesHashLock); for (auto it = _scriptEnginesHash.begin(); it != _scriptEnginesHash.end(); ++it) { - if (it.value() && it.value()->isUserLoaded()) { + // Save user-loaded scripts, only if they are set to quit when finished + if (it.value() && it.value()->isUserLoaded() && !it.value()->isQuitWhenFinished()) { auto normalizedUrl = normalizeScriptURL(it.key()); list.append(normalizedUrl.toString()); } @@ -427,11 +428,13 @@ bool ScriptEngines::stopScript(const QString& rawScriptURL, bool restart) { if (_scriptEnginesHash.contains(scriptURL)) { ScriptEnginePointer scriptEngine = _scriptEnginesHash[scriptURL]; if (restart) { + bool isUserLoaded = scriptEngine->isUserLoaded(); + ScriptEngine::Type type = scriptEngine->getType(); auto scriptCache = DependencyManager::get(); scriptCache->deleteScript(scriptURL); connect(scriptEngine.data(), &ScriptEngine::finished, - this, [this](QString scriptName, ScriptEnginePointer engine) { - reloadScript(scriptName); + this, [this, isUserLoaded, type](QString scriptName, ScriptEnginePointer engine) { + reloadScript(scriptName, isUserLoaded)->setType(type); }); } scriptEngine->stop(); @@ -454,7 +457,7 @@ void ScriptEngines::reloadAllScripts() { } ScriptEnginePointer ScriptEngines::loadScript(const QUrl& scriptFilename, bool isUserLoaded, bool loadScriptFromEditor, - bool activateMainWindow, bool reload) { + bool activateMainWindow, bool reload, bool quitWhenFinished) { if (thread() != QThread::currentThread()) { ScriptEnginePointer result { nullptr }; BLOCKING_INVOKE_METHOD(this, "loadScript", Q_RETURN_ARG(ScriptEnginePointer, result), @@ -486,6 +489,7 @@ ScriptEnginePointer ScriptEngines::loadScript(const QUrl& scriptFilename, bool i scriptEngine = ScriptEnginePointer(new ScriptEngine(_context, NO_SCRIPT, "about:" + scriptFilename.fileName())); addScriptEngine(scriptEngine); scriptEngine->setUserLoaded(isUserLoaded); + scriptEngine->setQuitWhenFinished(quitWhenFinished); if (scriptFilename.isEmpty() || !scriptUrl.isValid()) { launchScriptEngine(scriptEngine); @@ -494,6 +498,11 @@ ScriptEnginePointer ScriptEngines::loadScript(const QUrl& scriptFilename, bool i connect(scriptEngine.data(), &ScriptEngine::scriptLoaded, this, &ScriptEngines::onScriptEngineLoaded); connect(scriptEngine.data(), &ScriptEngine::errorLoadingScript, this, &ScriptEngines::onScriptEngineError); + // Shutdown Interface when script finishes, if requested + if (quitWhenFinished) { + connect(scriptEngine.data(), &ScriptEngine::finished, this, &ScriptEngines::quitWhenFinished); + } + // get the script engine object to load the script at the designated script URL scriptEngine->loadURL(scriptUrl, reload); } @@ -534,6 +543,10 @@ void ScriptEngines::onScriptEngineLoaded(const QString& rawScriptURL) { emit scriptCountChanged(); } +void ScriptEngines::quitWhenFinished() { + qApp->quit(); +} + int ScriptEngines::runScriptInitializers(ScriptEnginePointer scriptEngine) { int ii=0; for (auto initializer : _scriptInitializers) { diff --git a/libraries/script-engine/src/ScriptEngines.h b/libraries/script-engine/src/ScriptEngines.h index 1200168420..4d5964e462 100644 --- a/libraries/script-engine/src/ScriptEngines.h +++ b/libraries/script-engine/src/ScriptEngines.h @@ -29,6 +29,10 @@ class ScriptEngine; /**jsdoc * @namespace ScriptDiscoveryService + * + * @hifi-interface + * @hifi-client-entity + * * @property {string} debugScriptUrl * @property {string} defaultScriptsPath * @property {ScriptsModel} scriptsModel @@ -84,10 +88,11 @@ public: * @param {boolean} [loadScriptFromEditor=false] * @param {boolean} [activateMainWindow=false] * @param {boolean} [reload=false] + * @param {boolean} [quitWhenFinished=false] * @returns {boolean} */ Q_INVOKABLE ScriptEnginePointer loadScript(const QUrl& scriptFilename = QString(), - bool isUserLoaded = true, bool loadScriptFromEditor = false, bool activateMainWindow = false, bool reload = false); + bool isUserLoaded = true, bool loadScriptFromEditor = false, bool activateMainWindow = false, bool reload = false, bool quitWhenFinished = false); /**jsdoc * @function ScriptDiscoveryService.stopScript @@ -259,9 +264,10 @@ protected slots: protected: friend class ScriptEngine; - void reloadScript(const QString& scriptName) { loadScript(scriptName, true, false, false, true); } + ScriptEnginePointer reloadScript(const QString& scriptName, bool isUserLoaded = true) { return loadScript(scriptName, isUserLoaded, false, false, true); } void removeScriptEngine(ScriptEnginePointer); void onScriptEngineLoaded(const QString& scriptFilename); + void quitWhenFinished(); void onScriptEngineError(const QString& scriptFilename); void launchScriptEngine(ScriptEnginePointer); diff --git a/libraries/script-engine/src/ScriptUUID.cpp b/libraries/script-engine/src/ScriptUUID.cpp index ee15f1a760..f88803c87c 100644 --- a/libraries/script-engine/src/ScriptUUID.cpp +++ b/libraries/script-engine/src/ScriptUUID.cpp @@ -11,11 +11,12 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include "ScriptUUID.h" + #include #include "ScriptEngineLogging.h" #include "ScriptEngine.h" -#include "ScriptUUID.h" QUuid ScriptUUID::fromString(const QString& s) { return QUuid(s); diff --git a/libraries/script-engine/src/ScriptUUID.h b/libraries/script-engine/src/ScriptUUID.h index 303a871d1d..0af0c1cf8e 100644 --- a/libraries/script-engine/src/ScriptUUID.h +++ b/libraries/script-engine/src/ScriptUUID.h @@ -15,6 +15,7 @@ #define hifi_ScriptUUID_h #include +#include #include /**jsdoc @@ -23,6 +24,12 @@ * hexadecimal digits. * * @namespace Uuid + * + * @hifi-interface + * @hifi-client-entity + * @hifi-server-entity + * @hifi-assignment-client + * * @property NULL {Uuid} The null UUID, {00000000-0000-0000-0000-000000000000}. */ diff --git a/libraries/script-engine/src/ScriptsModel.h b/libraries/script-engine/src/ScriptsModel.h index a4ffc192f9..2466347baa 100644 --- a/libraries/script-engine/src/ScriptsModel.h +++ b/libraries/script-engine/src/ScriptsModel.h @@ -68,6 +68,9 @@ public: *

Has properties and functions below in addition to those of * http://doc.qt.io/qt-5/qabstractitemmodel.html.

* @class ScriptsModel + * + * @hifi-interface + * @hifi-client-entity */ class ScriptsModel : public QAbstractItemModel { Q_OBJECT diff --git a/libraries/script-engine/src/ScriptsModelFilter.h b/libraries/script-engine/src/ScriptsModelFilter.h index 26efde02e8..05a76334bb 100644 --- a/libraries/script-engine/src/ScriptsModelFilter.h +++ b/libraries/script-engine/src/ScriptsModelFilter.h @@ -20,6 +20,9 @@ *

Has properties and functions per * http://doc.qt.io/qt-5/qsortfilterproxymodel.html.

* @class ScriptsModelFilter + * + * @hifi-interface + * @hifi-client-entity */ class ScriptsModelFilter : public QSortFilterProxyModel { Q_OBJECT diff --git a/libraries/script-engine/src/SpatialEvent.cpp b/libraries/script-engine/src/SpatialEvent.cpp index f20a0c2b1e..d06cc556d3 100644 --- a/libraries/script-engine/src/SpatialEvent.cpp +++ b/libraries/script-engine/src/SpatialEvent.cpp @@ -9,10 +9,10 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -#include - #include "SpatialEvent.h" +#include + SpatialEvent::SpatialEvent() : locTranslation(0.0f), locRotation(), @@ -43,4 +43,4 @@ QScriptValue SpatialEvent::toScriptValue(QScriptEngine* engine, const SpatialEve void SpatialEvent::fromScriptValue(const QScriptValue& object,SpatialEvent& event) { // nothing for now... -} \ No newline at end of file +} diff --git a/libraries/script-engine/src/TouchEvent.cpp b/libraries/script-engine/src/TouchEvent.cpp index 097639d4e8..6ff591decf 100644 --- a/libraries/script-engine/src/TouchEvent.cpp +++ b/libraries/script-engine/src/TouchEvent.cpp @@ -9,15 +9,14 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include "TouchEvent.h" + #include #include -#include #include #include -#include "TouchEvent.h" - TouchEvent::TouchEvent() : x(0.0f), y(0.0f), diff --git a/libraries/script-engine/src/TouchEvent.h b/libraries/script-engine/src/TouchEvent.h index d9eedf50d0..62cb1b1801 100644 --- a/libraries/script-engine/src/TouchEvent.h +++ b/libraries/script-engine/src/TouchEvent.h @@ -13,8 +13,13 @@ #define hifi_TouchEvent_h #include + +#include #include +class QScriptValue; +class QScriptEngine; + class TouchEvent { public: TouchEvent(); @@ -54,4 +59,4 @@ private: Q_DECLARE_METATYPE(TouchEvent) -#endif // hifi_TouchEvent_h \ No newline at end of file +#endif // hifi_TouchEvent_h diff --git a/libraries/script-engine/src/TypedArrayPrototype.cpp b/libraries/script-engine/src/TypedArrayPrototype.cpp index 4de948e806..a1f3ff87e8 100644 --- a/libraries/script-engine/src/TypedArrayPrototype.cpp +++ b/libraries/script-engine/src/TypedArrayPrototype.cpp @@ -9,10 +9,10 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -#include "TypedArrays.h" - #include "TypedArrayPrototype.h" +#include "TypedArrays.h" + Q_DECLARE_METATYPE(QByteArray*) TypedArrayPrototype::TypedArrayPrototype(QObject* parent) : QObject(parent) { diff --git a/libraries/script-engine/src/TypedArrays.cpp b/libraries/script-engine/src/TypedArrays.cpp index 4d5181ff33..f2c3d3fd3d 100644 --- a/libraries/script-engine/src/TypedArrays.cpp +++ b/libraries/script-engine/src/TypedArrays.cpp @@ -9,13 +9,13 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include "TypedArrays.h" + #include #include "ScriptEngine.h" #include "TypedArrayPrototype.h" -#include "TypedArrays.h" - Q_DECLARE_METATYPE(QByteArray*) TypedArray::TypedArray(ScriptEngine* scriptEngine, QString name) : ArrayBufferViewClass(scriptEngine) { diff --git a/libraries/script-engine/src/UndoStackScriptingInterface.cpp b/libraries/script-engine/src/UndoStackScriptingInterface.cpp index 17bf8b1aa6..1171625c04 100644 --- a/libraries/script-engine/src/UndoStackScriptingInterface.cpp +++ b/libraries/script-engine/src/UndoStackScriptingInterface.cpp @@ -9,13 +9,13 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include "UndoStackScriptingInterface.h" + #include #include #include #include -#include "UndoStackScriptingInterface.h" - UndoStackScriptingInterface::UndoStackScriptingInterface(QUndoStack* undoStack) : _undoStack(undoStack) { } diff --git a/libraries/script-engine/src/UsersScriptingInterface.h b/libraries/script-engine/src/UsersScriptingInterface.h index 6728c471f6..e80d38239f 100644 --- a/libraries/script-engine/src/UsersScriptingInterface.h +++ b/libraries/script-engine/src/UsersScriptingInterface.h @@ -18,7 +18,12 @@ /**jsdoc * @namespace Users - * @property {boolean} canKick - true if the domain server allows the node or avatar to kick (ban) avatars, + * + * @hifi-interface + * @hifi-client-entity + * @hifi-assignment-client + * + * @property {boolean} canKick - true if the domain server allows the node or avatar to kick (ban) avatars, * otherwise false. Read-only. * @property {boolean} requestsDomainListData - true if the avatar requests extra data from the mixers (such as * positional data of an avatar you've ignored). Read-only. @@ -101,10 +106,11 @@ public slots: void mute(const QUuid& nodeID); /**jsdoc - * Get the user name and machine fingerprint associated with the given UUID. This will only do anything if you're an admin - * of the domain you're in. - * @function Users.getUsernameFromID - * @param {Uuid} nodeID The node or session ID of the user whose username you want. + * Request the user name and machine fingerprint associated with the given UUID. The user name will be returned in a + * {@link Users.usernameFromIDReply|usernameFromIDReply} signal. This will only do anything if you're an admin of the domain + * you're in. + * @function Users.requestUsernameFromID + * @param {Uuid} nodeID The node or session ID of the user whose user name you want. */ void requestUsernameFromID(const QUuid& nodeID); @@ -165,7 +171,8 @@ signals: void enteredIgnoreRadius(); /**jsdoc - * Notifies scripts of the user name and machine fingerprint associated with a UUID. + * Triggered in response to a {@link Users.requestUsernameFromID|requestUsernameFromID} call. Provides the user name and + * machine fingerprint associated with a UUID. * Username and machineFingerprint will be their default constructor output if the requesting user isn't an admin. * @function Users.usernameFromIDReply * @param {Uuid} nodeID diff --git a/libraries/script-engine/src/Vec3.cpp b/libraries/script-engine/src/Vec3.cpp index c21f96cd47..2d3d4454c3 100644 --- a/libraries/script-engine/src/Vec3.cpp +++ b/libraries/script-engine/src/Vec3.cpp @@ -9,6 +9,8 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include "Vec3.h" + #include #include @@ -16,11 +18,10 @@ #include #include -#include "ScriptEngineLogging.h" #include "NumericalConstants.h" -#include "Vec3.h" - #include "ScriptEngine.h" +#include "ScriptEngineLogging.h" + float Vec3::orientedAngle(const glm::vec3& v1, const glm::vec3& v2, const glm::vec3& v3) { float radians = glm::orientedAngle(glm::normalize(v1), glm::normalize(v2), glm::normalize(v3)); diff --git a/libraries/script-engine/src/Vec3.h b/libraries/script-engine/src/Vec3.h index 635f2a530c..eb9438c5c2 100644 --- a/libraries/script-engine/src/Vec3.h +++ b/libraries/script-engine/src/Vec3.h @@ -47,6 +47,12 @@ * * @namespace Vec3 * @variation 0 + * + * @hifi-interface + * @hifi-client-entity + * @hifi-server-entity + * @hifi-assignment-client + * * @property {Vec3} UNIT_X - { x: 1, y: 0, z: 0 } : Unit vector in the x-axis direction. Read-only. * @property {Vec3} UNIT_Y - { x: 0, y: 1, z: 0 } : Unit vector in the y-axis direction. Read-only. * @property {Vec3} UNIT_Z - { x: 0, y: 0, z: 1 } : Unit vector in the z-axis direction. Read-only. diff --git a/libraries/script-engine/src/WebSocketClass.cpp b/libraries/script-engine/src/WebSocketClass.cpp index 76faaab415..56753f07d1 100644 --- a/libraries/script-engine/src/WebSocketClass.cpp +++ b/libraries/script-engine/src/WebSocketClass.cpp @@ -12,9 +12,10 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -#include "ScriptEngine.h" #include "WebSocketClass.h" +#include "ScriptEngine.h" + WebSocketClass::WebSocketClass(QScriptEngine* engine, QString url) : _webSocket(new QWebSocket()), _engine(engine) diff --git a/libraries/script-engine/src/WebSocketServerClass.cpp b/libraries/script-engine/src/WebSocketServerClass.cpp index 3b723d5b3f..860170a3f9 100644 --- a/libraries/script-engine/src/WebSocketServerClass.cpp +++ b/libraries/script-engine/src/WebSocketServerClass.cpp @@ -11,9 +11,10 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -#include "ScriptEngine.h" #include "WebSocketServerClass.h" +#include "ScriptEngine.h" + WebSocketServerClass::WebSocketServerClass(QScriptEngine* engine, const QString& serverName, const quint16 port) : _webSocketServer(serverName, QWebSocketServer::SslMode::NonSecureMode), _engine(engine) diff --git a/libraries/script-engine/src/WheelEvent.cpp b/libraries/script-engine/src/WheelEvent.cpp index 70004d0d3f..a0a897c991 100644 --- a/libraries/script-engine/src/WheelEvent.cpp +++ b/libraries/script-engine/src/WheelEvent.cpp @@ -9,11 +9,11 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -#include -#include - #include "WheelEvent.h" +#include +#include + WheelEvent::WheelEvent() : x(0.0f), y(0.0f), @@ -99,4 +99,4 @@ QScriptValue WheelEvent::toScriptValue(QScriptEngine* engine, const WheelEvent& void WheelEvent::fromScriptValue(const QScriptValue& object, WheelEvent& event) { // nothing for now... -} \ No newline at end of file +} diff --git a/libraries/script-engine/src/WheelEvent.h b/libraries/script-engine/src/WheelEvent.h index edac4bc3c3..88ac828578 100644 --- a/libraries/script-engine/src/WheelEvent.h +++ b/libraries/script-engine/src/WheelEvent.h @@ -12,8 +12,12 @@ #ifndef hifi_WheelEvent_h #define hifi_WheelEvent_h +#include #include +class QScriptValue; +class QScriptEngine; + class WheelEvent { public: WheelEvent(); @@ -37,4 +41,4 @@ public: Q_DECLARE_METATYPE(WheelEvent) -#endif // hifi_WheelEvent_h \ No newline at end of file +#endif // hifi_WheelEvent_h diff --git a/libraries/script-engine/src/XMLHttpRequestClass.cpp b/libraries/script-engine/src/XMLHttpRequestClass.cpp index 62384f9d97..ebc459b2d1 100644 --- a/libraries/script-engine/src/XMLHttpRequestClass.cpp +++ b/libraries/script-engine/src/XMLHttpRequestClass.cpp @@ -12,6 +12,8 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include "XMLHttpRequestClass.h" + #include #include @@ -20,7 +22,6 @@ #include #include "ScriptEngine.h" -#include "XMLHttpRequestClass.h" const QString METAVERSE_API_URL = NetworkingConstants::METAVERSE_SERVER_URL().toString() + "/api/"; diff --git a/libraries/shared/src/AACube.cpp b/libraries/shared/src/AACube.cpp index 8cff3255b3..7dd2f8cb5b 100644 --- a/libraries/shared/src/AACube.cpp +++ b/libraries/shared/src/AACube.cpp @@ -9,8 +9,9 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -#include "AABox.h" #include "AACube.h" + +#include "AABox.h" #include "Extents.h" #include "GeometryUtil.h" #include "NumericalConstants.h" diff --git a/libraries/shared/src/CrashHelpers.cpp b/libraries/shared/src/CrashHelpers.cpp new file mode 100644 index 0000000000..f8ca90bc4c --- /dev/null +++ b/libraries/shared/src/CrashHelpers.cpp @@ -0,0 +1,77 @@ +// +// CrashHelpers.cpp +// libraries/shared/src +// +// Created by Clement Brisset on 4/30/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 +// + +#include "CrashHelpers.h" + +namespace crash { + +class B; +class A { +public: + A(B* b) : _b(b) { } + ~A(); + virtual void virtualFunction() = 0; + +private: + B* _b; +}; + +class B : public A { +public: + B() : A(this) { } + virtual void virtualFunction() override { } +}; + +A::~A() { + _b->virtualFunction(); +} + +void pureVirtualCall() { + qCDebug(shared) << "About to make a pure virtual call"; + B b; +} + +void doubleFree() { + qCDebug(shared) << "About to double delete memory"; + int* blah = new int(200); + delete blah; + delete blah; +} + +void nullDeref() { + qCDebug(shared) << "About to dereference a null pointer"; + int* p = nullptr; + *p = 1; +} + +void doAbort() { + qCDebug(shared) << "About to abort"; + abort(); +} + +void outOfBoundsVectorCrash() { + qCDebug(shared) << "std::vector out of bounds crash!"; + std::vector v; + v[0] = 42; +} + +void newFault() { + qCDebug(shared) << "About to crash inside new fault"; + + // Force crash with multiple large allocations + while (true) { + const size_t GIGABYTE = 1024 * 1024 * 1024; + new char[GIGABYTE]; + } + +} + +} diff --git a/libraries/shared/src/CrashHelpers.h b/libraries/shared/src/CrashHelpers.h index 1cc6749182..ad988c8906 100644 --- a/libraries/shared/src/CrashHelpers.h +++ b/libraries/shared/src/CrashHelpers.h @@ -18,66 +18,12 @@ namespace crash { -class B; -class A { -public: - A(B* b) : _b(b) { } - ~A(); - virtual void virtualFunction() = 0; - -private: - B* _b; -}; - -class B : public A { -public: - B() : A(this) { } - virtual void virtualFunction() override { } -}; - -A::~A() { - _b->virtualFunction(); -} - -void pureVirtualCall() { - qCDebug(shared) << "About to make a pure virtual call"; - B b; -} - -void doubleFree() { - qCDebug(shared) << "About to double delete memory"; - int* blah = new int(200); - delete blah; - delete blah; -} - -void nullDeref() { - qCDebug(shared) << "About to dereference a null pointer"; - int* p = nullptr; - *p = 1; -} - -void doAbort() { - qCDebug(shared) << "About to abort"; - abort(); -} - -void outOfBoundsVectorCrash() { - qCDebug(shared) << "std::vector out of bounds crash!"; - std::vector v; - v[0] = 42; -} - -void newFault() { - qCDebug(shared) << "About to crash inside new fault"; - - // Force crash with multiple large allocations - while (true) { - const size_t GIGABYTE = 1024 * 1024 * 1024; - new char[GIGABYTE]; - } - -} +void pureVirtualCall(); +void doubleFree(); +void nullDeref(); +void doAbort(); +void outOfBoundsVectorCrash(); +void newFault(); } diff --git a/libraries/shared/src/CubeProjectedPolygon.cpp b/libraries/shared/src/CubeProjectedPolygon.cpp index 04d6e8bb4e..acd2fc11d6 100644 --- a/libraries/shared/src/CubeProjectedPolygon.cpp +++ b/libraries/shared/src/CubeProjectedPolygon.cpp @@ -9,6 +9,8 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include "CubeProjectedPolygon.h" + #include #include @@ -16,8 +18,6 @@ #include "GeometryUtil.h" #include "SharedUtil.h" #include "SharedLogging.h" -#include "CubeProjectedPolygon.h" - glm::vec2 BoundingRectangle::getVertex(int vertexNumber) const { switch (vertexNumber) { diff --git a/libraries/shared/src/DebugDraw.h b/libraries/shared/src/DebugDraw.h index 64327585fb..7dd19415c9 100644 --- a/libraries/shared/src/DebugDraw.h +++ b/libraries/shared/src/DebugDraw.h @@ -25,6 +25,11 @@ * Helper functions to render ephemeral debug markers and lines. * DebugDraw markers and lines are only visible locally, they are not visible by other users. * @namespace DebugDraw + * + * @hifi-interface + * @hifi-client-entity + * @hifi-server-entity + * @hifi-assignment-client */ class DebugDraw : public QObject { Q_OBJECT diff --git a/libraries/shared/src/GLMHelpers.cpp b/libraries/shared/src/GLMHelpers.cpp index 72710a6a7d..75446754d5 100644 --- a/libraries/shared/src/GLMHelpers.cpp +++ b/libraries/shared/src/GLMHelpers.cpp @@ -76,13 +76,15 @@ glm::quat safeMix(const glm::quat& q1, const glm::quat& q2, float proportion) { // Allows sending of fixed-point numbers: radix 1 makes 15.1 number, radix 8 makes 8.8 number, etc int packFloatScalarToSignedTwoByteFixed(unsigned char* buffer, float scalar, int radix) { - int16_t outVal = (int16_t)(scalar * (float)(1 << radix)); - memcpy(buffer, &outVal, sizeof(uint16_t)); - return sizeof(uint16_t); + int16_t twoByteFixed = (int16_t)(scalar * (float)(1 << radix)); + memcpy(buffer, &twoByteFixed, sizeof(int16_t)); + return sizeof(int16_t); } int unpackFloatScalarFromSignedTwoByteFixed(const int16_t* byteFixedPointer, float* destinationPointer, int radix) { - *destinationPointer = *byteFixedPointer / (float)(1 << radix); + int16_t twoByteFixed; + memcpy(&twoByteFixed, byteFixedPointer, sizeof(int16_t)); + *destinationPointer = twoByteFixed / (float)(1 << radix); return sizeof(int16_t); } @@ -102,18 +104,19 @@ int unpackFloatVec3FromSignedTwoByteFixed(const unsigned char* sourceBuffer, glm return sourceBuffer - startPosition; } - int packFloatAngleToTwoByte(unsigned char* buffer, float degrees) { const float ANGLE_CONVERSION_RATIO = (std::numeric_limits::max() / 360.0f); - uint16_t angleHolder = floorf((degrees + 180.0f) * ANGLE_CONVERSION_RATIO); - memcpy(buffer, &angleHolder, sizeof(uint16_t)); + uint16_t twoByteAngle = floorf((degrees + 180.0f) * ANGLE_CONVERSION_RATIO); + memcpy(buffer, &twoByteAngle, sizeof(uint16_t)); return sizeof(uint16_t); } int unpackFloatAngleFromTwoByte(const uint16_t* byteAnglePointer, float* destinationPointer) { - *destinationPointer = (*byteAnglePointer / (float) std::numeric_limits::max()) * 360.0f - 180.0f; + uint16_t twoByteAngle; + memcpy(&twoByteAngle, byteAnglePointer, sizeof(uint16_t)); + *destinationPointer = (twoByteAngle / (float) std::numeric_limits::max()) * 360.0f - 180.0f; return sizeof(uint16_t); } @@ -222,6 +225,12 @@ int unpackOrientationQuatFromSixBytes(const unsigned char* buffer, glm::quat& qu return 6; } +bool closeEnough(float a, float b, float relativeError) { + assert(relativeError >= 0.0f); + // NOTE: we add EPSILON to the denominator so we can avoid checking for division by zero. + // This method works fine when: fabsf(a + b) >> EPSILON + return fabsf(a - b) / (0.5f * fabsf(a + b) + EPSILON) < relativeError; +} // Safe version of glm::eulerAngles; uses the factorization method described in David Eberly's // http://www.geometrictools.com/Documentation/EulerAngles.pdf (via Clyde, diff --git a/libraries/shared/src/GLMHelpers.h b/libraries/shared/src/GLMHelpers.h index 5c9a8b5ca1..0e1af27cd2 100644 --- a/libraries/shared/src/GLMHelpers.h +++ b/libraries/shared/src/GLMHelpers.h @@ -137,6 +137,8 @@ int unpackFloatScalarFromSignedTwoByteFixed(const int16_t* byteFixedPointer, flo int packFloatVec3ToSignedTwoByteFixed(unsigned char* destBuffer, const glm::vec3& srcVector, int radix); int unpackFloatVec3FromSignedTwoByteFixed(const unsigned char* sourceBuffer, glm::vec3& destination, int radix); +bool closeEnough(float a, float b, float relativeError); + /// \return vec3 with euler angles in radians glm::vec3 safeEulerAngles(const glm::quat& q); diff --git a/libraries/shared/src/GPUIdent.cpp b/libraries/shared/src/GPUIdent.cpp index 309cb30728..3b7a6cee40 100644 --- a/libraries/shared/src/GPUIdent.cpp +++ b/libraries/shared/src/GPUIdent.cpp @@ -8,8 +8,7 @@ // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -#include - +#include "GPUIdent.h" #ifdef Q_OS_WIN #include @@ -24,8 +23,9 @@ #include #endif +#include + #include "SharedLogging.h" -#include "GPUIdent.h" GPUIdent GPUIdent::_instance {}; diff --git a/libraries/shared/src/GPUIdent.h b/libraries/shared/src/GPUIdent.h index 8615e61b08..f780a4ddbd 100644 --- a/libraries/shared/src/GPUIdent.h +++ b/libraries/shared/src/GPUIdent.h @@ -16,6 +16,8 @@ #include +#include + class GPUIdent { public: diff --git a/libraries/shared/src/GenericThread.cpp b/libraries/shared/src/GenericThread.cpp index 230b9590f1..e35c74e68a 100644 --- a/libraries/shared/src/GenericThread.cpp +++ b/libraries/shared/src/GenericThread.cpp @@ -9,11 +9,10 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -#include -#include - #include "GenericThread.h" +#include +#include GenericThread::GenericThread() : _stopThread(false), diff --git a/libraries/shared/src/Gzip.cpp b/libraries/shared/src/Gzip.cpp index 25e214fffb..06b499b88a 100644 --- a/libraries/shared/src/Gzip.cpp +++ b/libraries/shared/src/Gzip.cpp @@ -9,9 +9,10 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -#include #include "Gzip.h" +#include + const int GZIP_WINDOWS_BIT = 31; const int GZIP_CHUNK_SIZE = 4096; const int DEFAULT_MEM_LEVEL = 8; diff --git a/libraries/shared/src/LogUtils.cpp b/libraries/shared/src/LogUtils.cpp index 73667116a0..11a4665ab1 100644 --- a/libraries/shared/src/LogUtils.cpp +++ b/libraries/shared/src/LogUtils.cpp @@ -9,10 +9,10 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -#include - #include "LogUtils.h" +#include + void LogUtils::init() { #ifdef Q_OS_WIN // Windows applications buffer stdout/err hard when not run from a terminal, diff --git a/libraries/shared/src/NumericalConstants.h b/libraries/shared/src/NumericalConstants.h index e2d2409d56..4c24a73226 100644 --- a/libraries/shared/src/NumericalConstants.h +++ b/libraries/shared/src/NumericalConstants.h @@ -48,6 +48,8 @@ const int BYTES_PER_KILOBYTE = 1000; const int BYTES_PER_KILOBIT = BYTES_PER_KILOBYTE / BITS_IN_BYTE; const int KILO_PER_MEGA = 1000; +const float SQRT_THREE = 1.73205080f; + #define KB_TO_BYTES_SHIFT 10 #define MB_TO_BYTES_SHIFT 20 #define GB_TO_BYTES_SHIFT 30 diff --git a/libraries/shared/src/OctalCode.cpp b/libraries/shared/src/OctalCode.cpp index c7ad4a790d..7f7d03c335 100644 --- a/libraries/shared/src/OctalCode.cpp +++ b/libraries/shared/src/OctalCode.cpp @@ -9,6 +9,8 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include "OctalCode.h" + #include // std:min #include #include @@ -17,7 +19,6 @@ #include #include "NumericalConstants.h" -#include "OctalCode.h" #include "SharedUtil.h" int numberOfThreeBitSectionsInCode(const unsigned char* octalCode, int maxBytes) { diff --git a/libraries/shared/src/PIDController.cpp b/libraries/shared/src/PIDController.cpp index 790c26ac25..5850e345cb 100644 --- a/libraries/shared/src/PIDController.cpp +++ b/libraries/shared/src/PIDController.cpp @@ -9,11 +9,14 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -#include -#include -#include "SharedLogging.h" #include "PIDController.h" +#include + +#include + +#include "SharedLogging.h" + float PIDController::update(float measuredValue, float dt, bool resetAccumulator) { const float error = getMeasuredValueSetpoint() - measuredValue; // Sign is the direction we want measuredValue to go. Positive means go higher. diff --git a/libraries/shared/src/PathUtils.h b/libraries/shared/src/PathUtils.h index d879ac968d..fc933b6b8c 100644 --- a/libraries/shared/src/PathUtils.h +++ b/libraries/shared/src/PathUtils.h @@ -22,6 +22,10 @@ * The Paths API provides absolute paths to the scripts and resources directories. * * @namespace Paths + * + * @hifi-interface + * @hifi-client-entity + * * @deprecated The Paths API is deprecated. Use {@link Script.resolvePath} and {@link Script.resourcesPath} instead. * @readonly * @property {string} defaultScripts - The path to the scripts directory. Read-only. diff --git a/libraries/shared/src/PerfStat.cpp b/libraries/shared/src/PerfStat.cpp index 13b3d44eda..c3bc44b7d3 100644 --- a/libraries/shared/src/PerfStat.cpp +++ b/libraries/shared/src/PerfStat.cpp @@ -9,6 +9,8 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include "PerfStat.h" + #include #include #include @@ -16,8 +18,6 @@ #include #include -#include "PerfStat.h" - #include "NumericalConstants.h" #include "SharedLogging.h" diff --git a/libraries/shared/src/PrioritySortUtil.h b/libraries/shared/src/PrioritySortUtil.h index 279fa42ea4..34ec074d45 100644 --- a/libraries/shared/src/PrioritySortUtil.h +++ b/libraries/shared/src/PrioritySortUtil.h @@ -15,7 +15,7 @@ #include #include "NumericalConstants.h" -#include "ViewFrustum.h" +#include "shared/ConicalViewFrustum.h" /* PrioritySortUtil is a helper for sorting 3D things relative to a ViewFrustum. To use: @@ -84,14 +84,12 @@ namespace PrioritySortUtil { class PriorityQueue { public: PriorityQueue() = delete; - - PriorityQueue(const ViewFrustum& view) : _view(view) { } - - PriorityQueue(const ViewFrustum& view, float angularWeight, float centerWeight, float ageWeight) - : _view(view), _angularWeight(angularWeight), _centerWeight(centerWeight), _ageWeight(ageWeight) + PriorityQueue(const ConicalViewFrustums& views) : _views(views) { } + PriorityQueue(const ConicalViewFrustums& views, float angularWeight, float centerWeight, float ageWeight) + : _views(views), _angularWeight(angularWeight), _centerWeight(centerWeight), _ageWeight(ageWeight) { } - void setView(const ViewFrustum& view) { _view = view; } + void setViews(const ConicalViewFrustums& views) { _views = views; } void setWeights(float angularWeight, float centerWeight, float ageWeight) { _angularWeight = angularWeight; @@ -109,7 +107,18 @@ namespace PrioritySortUtil { bool empty() const { return _queue.empty(); } private: + float computePriority(const T& thing) const { + float priority = std::numeric_limits::min(); + + for (const auto& view : _views) { + priority = std::max(priority, computePriority(view, thing)); + } + + return priority; + } + + float computePriority(const ConicalViewFrustum& view, const T& thing) const { // priority = weighted linear combination of multiple values: // (a) angular size // (b) proximity to center of view @@ -117,11 +126,11 @@ namespace PrioritySortUtil { // where the relative "weights" are tuned to scale the contributing values into units of "priority". glm::vec3 position = thing.getPosition(); - glm::vec3 offset = position - _view.getPosition(); + glm::vec3 offset = position - view.getPosition(); float distance = glm::length(offset) + 0.001f; // add 1mm to avoid divide by zero const float MIN_RADIUS = 0.1f; // WORKAROUND for zero size objects (we still want them to sort by distance) float radius = glm::min(thing.getRadius(), MIN_RADIUS); - float cosineAngle = (glm::dot(offset, _view.getDirection()) / distance); + float cosineAngle = (glm::dot(offset, view.getDirection()) / distance); float age = (float)(usecTimestampNow() - thing.getTimestamp()); // we modulatate "age" drift rate by the cosineAngle term to make periphrial objects sort forward @@ -134,8 +143,8 @@ namespace PrioritySortUtil { + _ageWeight * cosineAngleFactor * age; // decrement priority of things outside keyhole - if (distance - radius > _view.getCenterRadius()) { - if (!_view.sphereIntersectsFrustum(position, radius)) { + if (distance - radius > view.getRadius()) { + if (!view.intersects(offset, distance, radius)) { constexpr float OUT_OF_VIEW_PENALTY = -10.0f; priority += OUT_OF_VIEW_PENALTY; } @@ -143,7 +152,7 @@ namespace PrioritySortUtil { return priority; } - ViewFrustum _view; + ConicalViewFrustums _views; std::priority_queue _queue; float _angularWeight { DEFAULT_ANGULAR_COEF }; float _centerWeight { DEFAULT_CENTER_COEF }; diff --git a/libraries/shared/src/RegisteredMetaTypes.h b/libraries/shared/src/RegisteredMetaTypes.h index 689d1a3f42..467d6374a5 100644 --- a/libraries/shared/src/RegisteredMetaTypes.h +++ b/libraries/shared/src/RegisteredMetaTypes.h @@ -361,6 +361,12 @@ using MeshPointer = std::shared_ptr; /**jsdoc * A handle for a mesh in an entity, such as returned by {@link Entities.getMeshes}. * @class MeshProxy + * + * @hifi-interface + * @hifi-client-entity + * @hifi-server-entity + * @hifi-assignment-client + * * @deprecated Use the {@link Graphics} API instead. */ class MeshProxy : public QObject { diff --git a/libraries/shared/src/SimpleMovingAverage.cpp b/libraries/shared/src/SimpleMovingAverage.cpp index f75180afb5..9bcc6b732f 100644 --- a/libraries/shared/src/SimpleMovingAverage.cpp +++ b/libraries/shared/src/SimpleMovingAverage.cpp @@ -9,9 +9,10 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -#include "SharedUtil.h" #include "SimpleMovingAverage.h" +#include "SharedUtil.h" + SimpleMovingAverage::SimpleMovingAverage(int numSamplesToAverage) : _numSamples(0), _lastEventTimestamp(0), diff --git a/libraries/shared/src/StDev.cpp b/libraries/shared/src/StDev.cpp index 23afd12b98..99280ba42e 100644 --- a/libraries/shared/src/StDev.cpp +++ b/libraries/shared/src/StDev.cpp @@ -9,12 +9,12 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include "StDev.h" + #include #include #include -#include "StDev.h" - StDev::StDev() : _sampleCount(0) { diff --git a/libraries/shared/src/StreamUtils.cpp b/libraries/shared/src/StreamUtils.cpp index 876de2e698..9ed0e24593 100644 --- a/libraries/shared/src/StreamUtils.cpp +++ b/libraries/shared/src/StreamUtils.cpp @@ -9,11 +9,11 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -#include +#include "StreamUtils.h" #include -#include "StreamUtils.h" +#include void StreamUtil::dump(std::ostream& s, const QByteArray& buffer) { diff --git a/libraries/shared/src/TriangleSet.cpp b/libraries/shared/src/TriangleSet.cpp index 3f8f748720..d7f685f8d3 100644 --- a/libraries/shared/src/TriangleSet.cpp +++ b/libraries/shared/src/TriangleSet.cpp @@ -9,9 +9,9 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -#include "GLMHelpers.h" #include "TriangleSet.h" +#include "GLMHelpers.h" void TriangleSet::insert(const Triangle& t) { _isBalanced = false; diff --git a/libraries/shared/src/VariantMapToScriptValue.cpp b/libraries/shared/src/VariantMapToScriptValue.cpp index 00fc2cd682..008c3a5d9b 100644 --- a/libraries/shared/src/VariantMapToScriptValue.cpp +++ b/libraries/shared/src/VariantMapToScriptValue.cpp @@ -9,10 +9,11 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -#include -#include "SharedLogging.h" #include "VariantMapToScriptValue.h" +#include + +#include "SharedLogging.h" QScriptValue variantToScriptValue(QVariant& qValue, QScriptEngine& scriptEngine) { switch(qValue.type()) { diff --git a/libraries/shared/src/ViewFrustum.cpp b/libraries/shared/src/ViewFrustum.cpp index 2a2eebc0a7..3e03c13fa4 100644 --- a/libraries/shared/src/ViewFrustum.cpp +++ b/libraries/shared/src/ViewFrustum.cpp @@ -9,6 +9,8 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include "ViewFrustum.h" + #include #include @@ -16,15 +18,13 @@ #include #include #include -#include +#include #include "GeometryUtil.h" #include "GLMHelpers.h" #include "NumericalConstants.h" #include "SharedLogging.h" -//#include "OctreeConstants.h" -#include "ViewFrustum.h" using namespace std; @@ -75,6 +75,10 @@ void ViewFrustum::setProjection(const glm::mat4& projection) { _width = _corners[TOP_RIGHT_NEAR].x - _corners[TOP_LEFT_NEAR].x; } +void ViewFrustum::setProjection(float cameraFov, float cameraAspectRatio, float cameraNearClip, float cameraFarClip) { + setProjection(glm::perspective(glm::radians(cameraFov), cameraAspectRatio, cameraNearClip, cameraFarClip)); +} + // ViewFrustum::calculate() // // Description: this will calculate the view frustum bounds for a given position and direction @@ -134,71 +138,6 @@ const char* ViewFrustum::debugPlaneName (int plane) const { return "Unknown"; } -void ViewFrustum::fromByteArray(const QByteArray& input) { - - // From the wire! - glm::vec3 cameraPosition; - glm::quat cameraOrientation; - float cameraCenterRadius; - float cameraFov; - float cameraAspectRatio; - float cameraNearClip; - float cameraFarClip; - - const unsigned char* startPosition = reinterpret_cast(input.constData()); - const unsigned char* sourceBuffer = startPosition; - - // camera details - memcpy(&cameraPosition, sourceBuffer, sizeof(cameraPosition)); - sourceBuffer += sizeof(cameraPosition); - sourceBuffer += unpackOrientationQuatFromBytes(sourceBuffer, cameraOrientation); - sourceBuffer += unpackFloatAngleFromTwoByte((uint16_t*)sourceBuffer, &cameraFov); - sourceBuffer += unpackFloatRatioFromTwoByte(sourceBuffer, cameraAspectRatio); - sourceBuffer += unpackClipValueFromTwoByte(sourceBuffer, cameraNearClip); - sourceBuffer += unpackClipValueFromTwoByte(sourceBuffer, cameraFarClip); - memcpy(&cameraCenterRadius, sourceBuffer, sizeof(cameraCenterRadius)); - sourceBuffer += sizeof(cameraCenterRadius); - - setPosition(cameraPosition); - setOrientation(cameraOrientation); - setCenterRadius(cameraCenterRadius); - - // Also make sure it's got the correct lens details from the camera - if (0.0f != cameraAspectRatio && - 0.0f != cameraNearClip && - 0.0f != cameraFarClip && - cameraNearClip != cameraFarClip) { - setProjection(glm::perspective( - glm::radians(cameraFov), - cameraAspectRatio, - cameraNearClip, - cameraFarClip)); - - calculate(); - } -} - - -QByteArray ViewFrustum::toByteArray() { - static const int LARGE_ENOUGH = 1024; - QByteArray viewFrustumDataByteArray(LARGE_ENOUGH, 0); - unsigned char* destinationBuffer = reinterpret_cast(viewFrustumDataByteArray.data()); - unsigned char* startPosition = destinationBuffer; - - // camera details - memcpy(destinationBuffer, &_position, sizeof(_position)); - destinationBuffer += sizeof(_position); - destinationBuffer += packOrientationQuatToBytes(destinationBuffer, _orientation); - destinationBuffer += packFloatAngleToTwoByte(destinationBuffer, _fieldOfView); - destinationBuffer += packFloatRatioToTwoByte(destinationBuffer, _aspectRatio); - destinationBuffer += packClipValueToTwoByte(destinationBuffer, _nearClip); - destinationBuffer += packClipValueToTwoByte(destinationBuffer, _farClip); - memcpy(destinationBuffer, &_centerSphereRadius, sizeof(_centerSphereRadius)); - destinationBuffer += sizeof(_centerSphereRadius); - - return viewFrustumDataByteArray.left(destinationBuffer - startPosition); -} - ViewFrustum::intersection ViewFrustum::calculateCubeFrustumIntersection(const AACube& cube) const { // only check against frustum ViewFrustum::intersection result = INSIDE; @@ -336,13 +275,6 @@ bool ViewFrustum::boxIntersectsKeyhole(const AABox& box) const { return true; } -bool closeEnough(float a, float b, float relativeError) { - assert(relativeError >= 0.0f); - // NOTE: we add EPSILON to the denominator so we can avoid checking for division by zero. - // This method works fine when: fabsf(a + b) >> EPSILON - return fabsf(a - b) / (0.5f * fabsf(a + b) + EPSILON) < relativeError; -} - // TODO: the slop and relative error should be passed in by argument rather than hard-coded. bool ViewFrustum::isVerySimilar(const ViewFrustum& other) const { const float MIN_POSITION_SLOP_SQUARED = 25.0f; // 5 meters squared diff --git a/libraries/shared/src/ViewFrustum.h b/libraries/shared/src/ViewFrustum.h index 981aabe70c..eada65468d 100644 --- a/libraries/shared/src/ViewFrustum.h +++ b/libraries/shared/src/ViewFrustum.h @@ -48,6 +48,7 @@ public: // setters for lens attributes void setProjection(const glm::mat4 & projection); + void setProjection(float cameraFov, float cameraAspectRatio, float cameraNearClip, float cameraFarClip); void setFocalLength(float focalLength) { _focalLength = focalLength; } bool isPerspective() const; @@ -146,9 +147,6 @@ public: void invalidate(); // causes all reasonable intersection tests to fail - QByteArray toByteArray(); - void fromByteArray(const QByteArray& input); - private: glm::mat4 _view; glm::mat4 _projection; @@ -188,5 +186,6 @@ private: }; using ViewFrustumPointer = std::shared_ptr; +using ViewFrustums = std::vector; #endif // hifi_ViewFrustum_h diff --git a/libraries/shared/src/shared/Camera.h b/libraries/shared/src/shared/Camera.h index ea2e9cddab..32e753d0f9 100644 --- a/libraries/shared/src/shared/Camera.h +++ b/libraries/shared/src/shared/Camera.h @@ -40,6 +40,10 @@ class Camera : public QObject { * The Camera API provides access to the "camera" that defines your view in desktop and HMD display modes. * * @namespace Camera + * + * @hifi-interface + * @hifi-client-entity + * * @property position {Vec3} The position of the camera. You can set this value only when the camera is in independent mode. * @property orientation {Quat} The orientation of the camera. You can set this value only when the camera is in independent * mode. diff --git a/libraries/shared/src/shared/ConicalViewFrustum.cpp b/libraries/shared/src/shared/ConicalViewFrustum.cpp new file mode 100644 index 0000000000..2ef096e3a8 --- /dev/null +++ b/libraries/shared/src/shared/ConicalViewFrustum.cpp @@ -0,0 +1,146 @@ +// +// ConicalViewFrustum.cpp +// libraries/shared/src/shared +// +// Created by Clement Brisset 4/26/18 +// Copyright 2017 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "ConicalViewFrustum.h" + + +#include "../NumericalConstants.h" +#include "../ViewFrustum.h" + +void ConicalViewFrustum::set(const ViewFrustum& viewFrustum) { + // The ConicalViewFrustum has two parts: a central sphere (same as ViewFrustum) and a circular cone that bounds the frustum part. + // Why? Because approximate intersection tests are much faster to compute for a cone than for a frustum. + _position = viewFrustum.getPosition(); + _radius = viewFrustum.getCenterRadius(); + _farClip = viewFrustum.getFarClip(); + + auto topLeft = viewFrustum.getNearTopLeft() - _position; + auto topRight = viewFrustum.getNearTopRight() - _position; + auto bottomLeft = viewFrustum.getNearBottomLeft() - _position; + auto bottomRight = viewFrustum.getNearBottomRight() - _position; + auto centerAxis = 0.25f * (topLeft + topRight + bottomLeft + bottomRight); // Take the average + + _direction = glm::normalize(centerAxis); + _angle = std::max(std::max(angleBetween(_direction, topLeft), + angleBetween(_direction, topRight)), + std::max(angleBetween(_direction, bottomLeft), + angleBetween(_direction, bottomRight))); +} + +void ConicalViewFrustum::calculate() { + // Pre-compute cos and sin for faster checks + _cosAngle = cosf(_angle); + _sinAngle = sqrtf(1.0f - _cosAngle * _cosAngle); +} + +bool ConicalViewFrustum::isVerySimilar(const ConicalViewFrustum& other) const { + const float MIN_POSITION_SLOP_SQUARED = 25.0f; // 5 meters squared + const float MIN_ANGLE_BETWEEN = 0.174533f; // radian angle between 2 vectors 10 degrees apart + const float MIN_RELATIVE_ERROR = 0.01f; // 1% + + return glm::distance2(_position, other._position) < MIN_POSITION_SLOP_SQUARED && + angleBetween(_direction, other._direction) < MIN_ANGLE_BETWEEN && + closeEnough(_angle, other._angle, MIN_RELATIVE_ERROR) && + closeEnough(_farClip, other._farClip, MIN_RELATIVE_ERROR) && + closeEnough(_radius, other._radius, MIN_RELATIVE_ERROR); +} + +bool ConicalViewFrustum::intersects(const AACube& cube) const { + auto radius = 0.5f * SQRT_THREE * cube.getScale(); // radius of bounding sphere + auto position = cube.calcCenter() - _position; // position of bounding sphere in view-frame + float distance = glm::length(position); + + return intersects(position, distance, radius); +} + +bool ConicalViewFrustum::intersects(const AABox& box) const { + auto radius = 0.5f * glm::length(box.getScale()); // radius of bounding sphere + auto position = box.calcCenter() - _position; // position of bounding sphere in view-frame + float distance = glm::length(position); + + return intersects(position, distance, radius); +} + +bool ConicalViewFrustum::getAngularSize(const AACube& cube) const { + auto radius = 0.5f * SQRT_THREE * cube.getScale(); // radius of bounding sphere + auto position = cube.calcCenter() - _position; // position of bounding sphere in view-frame + float distance = glm::length(position); + + return getAngularSize(distance, radius); +} + +bool ConicalViewFrustum::getAngularSize(const AABox& box) const { + auto radius = 0.5f * glm::length(box.getScale()); // radius of bounding sphere + auto position = box.calcCenter() - _position; // position of bounding sphere in view-frame + float distance = glm::length(position); + + return getAngularSize(distance, radius); +} + + +bool ConicalViewFrustum::intersects(const glm::vec3& relativePosition, float distance, float radius) const { + if (distance < _radius + radius) { + // Inside keyhole radius + return true; + } + if (distance > _farClip + radius) { + // Past far clip + return false; + } + + // We check the angle between the center of the cube and the _direction of the view. + // If it is less than the sum of the half-angle from center of cone to outer edge plus + // the half apparent angle of the bounding sphere then it is in view. + // + // The math here is left as an exercise for the reader with the following hints: + // (1) We actually check the dot product of the cube's local position rather than the angle and + // (2) we take advantage of this trig identity: cos(A+B) = cos(A)*cos(B) - sin(A)*sin(B) + return glm::dot(relativePosition, _direction) > + sqrtf(distance * distance - radius * radius) * _cosAngle - radius * _sinAngle; +} + +bool ConicalViewFrustum::getAngularSize(float distance, float radius) const { + const float AVOID_DIVIDE_BY_ZERO = 0.001f; + float angularSize = radius / (distance + AVOID_DIVIDE_BY_ZERO); + return angularSize; +} + +int ConicalViewFrustum::serialize(unsigned char* destinationBuffer) const { + const unsigned char* startPosition = destinationBuffer; + + memcpy(destinationBuffer, &_position, sizeof(_position)); + destinationBuffer += sizeof(_position); + memcpy(destinationBuffer, &_direction, sizeof(_direction)); + destinationBuffer += sizeof(_direction); + destinationBuffer += packFloatAngleToTwoByte(destinationBuffer, _angle); + destinationBuffer += packClipValueToTwoByte(destinationBuffer, _farClip); + memcpy(destinationBuffer, &_radius, sizeof(_radius)); + destinationBuffer += sizeof(_radius); + + return destinationBuffer - startPosition; +} + +int ConicalViewFrustum::deserialize(const unsigned char* sourceBuffer) { + const unsigned char* startPosition = sourceBuffer; + + memcpy(&_position, sourceBuffer, sizeof(_position)); + sourceBuffer += sizeof(_position); + memcpy(&_direction, sourceBuffer, sizeof(_direction)); + sourceBuffer += sizeof(_direction); + sourceBuffer += unpackFloatAngleFromTwoByte((uint16_t*)sourceBuffer, &_angle); + sourceBuffer += unpackClipValueFromTwoByte(sourceBuffer, _farClip); + memcpy(&_radius, sourceBuffer, sizeof(_radius)); + sourceBuffer += sizeof(_radius); + + calculate(); + + return sourceBuffer - startPosition; +} diff --git a/libraries/shared/src/shared/ConicalViewFrustum.h b/libraries/shared/src/shared/ConicalViewFrustum.h new file mode 100644 index 0000000000..dc372d560e --- /dev/null +++ b/libraries/shared/src/shared/ConicalViewFrustum.h @@ -0,0 +1,70 @@ +// +// ConicalViewFrustum.h +// libraries/shared/src/shared +// +// Created by Clement Brisset 4/26/18 +// Copyright 2017 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef hifi_ConicalViewFrustum_h +#define hifi_ConicalViewFrustum_h + +#include + +#include + +class AACube; +class AABox; +class ViewFrustum; +using ViewFrustums = std::vector; + +const float SQRT_TWO_OVER_TWO = 0.7071067811865f; +const float DEFAULT_VIEW_ANGLE = 1.0f; +const float DEFAULT_VIEW_RADIUS = 10.0f; +const float DEFAULT_VIEW_FAR_CLIP = 100.0f; + +// ConicalViewFrustum is an approximation of a ViewFrustum for fast calculation of sort priority. +class ConicalViewFrustum { +public: + ConicalViewFrustum() = default; + ConicalViewFrustum(const ViewFrustum& viewFrustum) { set(viewFrustum); } + + void set(const ViewFrustum& viewFrustum); + void calculate(); + + const glm::vec3& getPosition() const { return _position; } + const glm::vec3& getDirection() const { return _direction; } + float getAngle() const { return _angle; } + float getRadius() const { return _radius; } + float getFarClip() const { return _farClip; } + + bool isVerySimilar(const ConicalViewFrustum& other) const; + + bool intersects(const AACube& cube) const; + bool intersects(const AABox& box) const; + bool getAngularSize(const AACube& cube) const; + bool getAngularSize(const AABox& box) const; + + bool intersects(const glm::vec3& relativePosition, float distance, float radius) const; + bool getAngularSize(float distance, float radius) const; + + int serialize(unsigned char* destinationBuffer) const; + int deserialize(const unsigned char* sourceBuffer); + +private: + glm::vec3 _position { 0.0f, 0.0f, 0.0f }; + glm::vec3 _direction { 0.0f, 0.0f, 1.0f }; + float _angle { DEFAULT_VIEW_ANGLE }; + float _radius { DEFAULT_VIEW_RADIUS }; + float _farClip { DEFAULT_VIEW_FAR_CLIP }; + + float _sinAngle { SQRT_TWO_OVER_TWO }; + float _cosAngle { SQRT_TWO_OVER_TWO }; +}; +using ConicalViewFrustums = std::vector; + + +#endif /* hifi_ConicalViewFrustum_h */ diff --git a/libraries/shared/src/shared/FileLogger.cpp b/libraries/shared/src/shared/FileLogger.cpp index 8ceb378574..6a10629ee5 100644 --- a/libraries/shared/src/shared/FileLogger.cpp +++ b/libraries/shared/src/shared/FileLogger.cpp @@ -36,17 +36,14 @@ protected: private: const FileLogger& _logger; QMutex _fileMutex; - uint64_t _lastRollTime; }; - - static const QString FILENAME_FORMAT = "hifi-log_%1%2.txt"; static const QString DATETIME_FORMAT = "yyyy-MM-dd_hh.mm.ss"; static const QString LOGS_DIRECTORY = "Logs"; -static const QString IPADDR_WILDCARD = "[0-9]*.[0-9]*.[0-9]*.[0-9]*"; -static const QString DATETIME_WILDCARD = "20[0-9][0-9]-[0,1][0-9]-[0-3][0-9]_[0-2][0-9].[0-6][0-9].[0-6][0-9]"; -static const QString FILENAME_WILDCARD = "hifi-log_" + IPADDR_WILDCARD + "_" + DATETIME_WILDCARD + ".txt"; +static const QString DATETIME_WILDCARD = "20[0-9][0-9]-[01][0-9]-[0-3][0-9]_[0-2][0-9]\\.[0-6][0-9]\\.[0-6][0-9]"; +static const QString SESSION_WILDCARD = "[0-9a-z]{8}(-[0-9a-z]{4}){3}-[0-9a-z]{12}"; +static QRegExp LOG_FILENAME_REGEX { "hifi-log_" + DATETIME_WILDCARD + "(_" + SESSION_WILDCARD + ")?\\.txt" }; static QUuid SESSION_ID; // Max log size is 512 KB. We send log files to our crash reporter, so we want to keep this relatively @@ -54,8 +51,6 @@ static QUuid SESSION_ID; static const qint64 MAX_LOG_SIZE = 512 * 1024; // Max log files found in the log directory is 100. static const qint64 MAX_LOG_DIR_SIZE = 512 * 1024 * 100; -// Max log age is 1 hour -static const uint64_t MAX_LOG_AGE_USECS = USECS_PER_SECOND * 3600; static FilePersistThread* _persistThreadInstance; @@ -86,38 +81,34 @@ FilePersistThread::FilePersistThread(const FileLogger& logger) : _logger(logger) if (file.exists()) { rollFileIfNecessary(file, false); } - _lastRollTime = usecTimestampNow(); } void FilePersistThread::rollFileIfNecessary(QFile& file, bool notifyListenersIfRolled) { - uint64_t now = usecTimestampNow(); - if ((file.size() > MAX_LOG_SIZE) || (now - _lastRollTime) > MAX_LOG_AGE_USECS) { + if (file.size() > MAX_LOG_SIZE) { QString newFileName = getLogRollerFilename(); if (file.copy(newFileName)) { file.open(QIODevice::WriteOnly | QIODevice::Truncate); file.close(); - qCDebug(shared) << "Rolled log file:" << newFileName; if (notifyListenersIfRolled) { emit rollingLogFile(newFileName); } - - _lastRollTime = now; } - QStringList nameFilters; - nameFilters << FILENAME_WILDCARD; - QDir logQDir(FileUtils::standardPath(LOGS_DIRECTORY)); - logQDir.setNameFilters(nameFilters); - logQDir.setSorting(QDir::Time); - QFileInfoList filesInDir = logQDir.entryInfoList(); + QDir logDir(FileUtils::standardPath(LOGS_DIRECTORY)); + logDir.setSorting(QDir::Time); + logDir.setFilter(QDir::Files); qint64 totalSizeOfDir = 0; - foreach(QFileInfo dirItm, filesInDir){ - if (totalSizeOfDir < MAX_LOG_DIR_SIZE){ - totalSizeOfDir += dirItm.size(); - } else { - QFile file(dirItm.filePath()); - file.remove(); + QFileInfoList filesInDir = logDir.entryInfoList(); + for (auto& fileInfo : filesInDir) { + if (!LOG_FILENAME_REGEX.exactMatch(fileInfo.fileName())) { + continue; + } + totalSizeOfDir += fileInfo.size(); + if (totalSizeOfDir > MAX_LOG_DIR_SIZE){ + qDebug() << "Removing log file: " << fileInfo.fileName(); + QFile oldLogFile(fileInfo.filePath()); + oldLogFile.remove(); } } } @@ -129,7 +120,7 @@ bool FilePersistThread::processQueueItems(const Queue& messages) { rollFileIfNecessary(file); if (file.open(QIODevice::WriteOnly | QIODevice::Append | QIODevice::Text)) { QTextStream out(&file); - foreach(const QString& message, messages) { + for (const QString& message : messages) { out << message; } } diff --git a/libraries/shared/src/shared/StringHelpers.cpp b/libraries/shared/src/shared/StringHelpers.cpp index 1c1730bd5a..39ac23e510 100644 --- a/libraries/shared/src/shared/StringHelpers.cpp +++ b/libraries/shared/src/shared/StringHelpers.cpp @@ -6,10 +6,10 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -#include - #include "StringHelpers.h" +#include + /// Note: this will not preserve line breaks in the original input. QString simpleWordWrap(const QString& input, int maxCharactersPerLine) { QStringList words = input.split(QRegExp("\\s+")); diff --git a/libraries/ui/src/VirtualPadManager.cpp b/libraries/ui/src/VirtualPadManager.cpp index c786110bdf..dae19b52c2 100644 --- a/libraries/ui/src/VirtualPadManager.cpp +++ b/libraries/ui/src/VirtualPadManager.cpp @@ -39,9 +39,9 @@ namespace VirtualPad { const float Manager::BASE_MARGIN_PIXELS = 59.0f; const float Manager::STICK_RADIUS_PIXELS = 105.0f; const float Manager::JUMP_BTN_TRIMMED_RADIUS_PIXELS = 67.0f; - const float Manager::JUMP_BTN_FULL_PIXELS = 134.0f; - const float Manager::JUMP_BTN_BOTTOM_MARGIN_PIXELS = 67.0f; - const float Manager::JUMP_BTN_LEFT_MARGIN_PIXELS = 547.0f; + const float Manager::JUMP_BTN_FULL_PIXELS = 164.0f; + const float Manager::JUMP_BTN_BOTTOM_MARGIN_PIXELS = 80.0f; + const float Manager::JUMP_BTN_RIGHT_MARGIN_PIXELS = 13.0f; Manager::Manager() { diff --git a/libraries/ui/src/VirtualPadManager.h b/libraries/ui/src/VirtualPadManager.h index 68b3d4f10f..6f7fbcc921 100644 --- a/libraries/ui/src/VirtualPadManager.h +++ b/libraries/ui/src/VirtualPadManager.h @@ -54,7 +54,7 @@ namespace VirtualPad { static const float JUMP_BTN_TRIMMED_RADIUS_PIXELS; static const float JUMP_BTN_FULL_PIXELS; static const float JUMP_BTN_BOTTOM_MARGIN_PIXELS; - static const float JUMP_BTN_LEFT_MARGIN_PIXELS; + static const float JUMP_BTN_RIGHT_MARGIN_PIXELS; private: Instance _leftVPadInstance; diff --git a/libraries/ui/src/ui/TabletScriptingInterface.h b/libraries/ui/src/ui/TabletScriptingInterface.h index bab15fc7b6..e74b846f02 100644 --- a/libraries/ui/src/ui/TabletScriptingInterface.h +++ b/libraries/ui/src/ui/TabletScriptingInterface.h @@ -40,6 +40,9 @@ class OffscreenQmlSurface; /**jsdoc * @namespace Tablet + * + * @hifi-interface + * @hifi-client-entity */ class TabletScriptingInterface : public QObject, public Dependency { Q_OBJECT @@ -176,6 +179,10 @@ Q_DECLARE_METATYPE(TabletButtonsProxyModel*); /**jsdoc * @class TabletProxy + * + * @hifi-interface + * @hifi-client-entity + * * @property {string} name - Name of this tablet. Read-only. * @property {boolean} toolbarMode - Used to transition this tablet into and out of toolbar mode. * When tablet is in toolbar mode, all its buttons will appear in a floating toolbar. @@ -410,6 +417,10 @@ Q_DECLARE_METATYPE(TabletProxy*); /**jsdoc * @class TabletButtonProxy + * + * @hifi-interface + * @hifi-client-entity + * * @property {Uuid} uuid - Uniquely identifies this button. Read-only. * @property {TabletButtonProxy.ButtonProperties} properties */ diff --git a/plugins/pcmCodec/src/PCMCodecManager.cpp b/plugins/pcmCodec/src/PCMCodecManager.cpp index 051f3973a8..04adb367af 100644 --- a/plugins/pcmCodec/src/PCMCodecManager.cpp +++ b/plugins/pcmCodec/src/PCMCodecManager.cpp @@ -9,12 +9,12 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include "PCMCodecManager.h" + #include #include -#include "PCMCodecManager.h" - const char* PCMCodec::NAME { "pcm" }; void PCMCodec::init() { diff --git a/scripts/+android/defaultScripts.js b/scripts/+android/defaultScripts.js index 11aee6a9d2..98fbb4b1a7 100644 --- a/scripts/+android/defaultScripts.js +++ b/scripts/+android/defaultScripts.js @@ -14,7 +14,7 @@ var DEFAULT_SCRIPTS_COMBINED = [ "system/progress.js", "system/+android/touchscreenvirtualpad.js", - "system/+android/bottombar.js", + "system/+android/actionbar.js", "system/+android/audio.js" , "system/+android/modes.js", "system/+android/stats.js"/*, diff --git a/scripts/system/+android/actionbar.js b/scripts/system/+android/actionbar.js new file mode 100644 index 0000000000..1f0872d5ee --- /dev/null +++ b/scripts/system/+android/actionbar.js @@ -0,0 +1,53 @@ +"use strict"; +// +// backbutton.js +// scripts/system/+android +// +// Created by Gabriel Calero & Cristian Duarte on Apr 06, 2018 +// 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 +// +(function() { // BEGIN LOCAL_SCOPE + +var actionbar; +var backButton; + +var logEnabled = true; + +function printd(str) { + if (logEnabled) + print("[actionbar.js] " + str); +} + +function init() { + actionbar = new QmlFragment({ + qml: "hifi/ActionBar.qml" + }); + backButton = actionbar.addButton({ + icon: "icons/+android/backward.svg", + activeIcon: "icons/+android/backward.svg", + text: "", + bgOpacity: 0.0, + hoverBgOpacity: 0.0, + activeBgOpacity: 0.0 + }); + + backButton.clicked.connect(onBackPressed); +} + +function onBackPressed() { + App.openAndroidActivity("Home"); +} + + +Script.scriptEnding.connect(function() { + if(backButton) { + backButton.clicked.disconnect(onBackPressed); + } +}); + +init(); + +}()); // END LOCAL_SCOPE diff --git a/scripts/system/+android/audio.js b/scripts/system/+android/audio.js index 955f74d63a..4d6d8db008 100644 --- a/scripts/system/+android/audio.js +++ b/scripts/system/+android/audio.js @@ -32,8 +32,9 @@ function init() { activeIcon: "icons/mic-mute-a.svg", text: "", bgOpacity: 0.0, - activeBgOpacity: 0.0, - bgColor: "#FFFFFF" + hoverBgOpacity: 0.0, + activeHoverBgOpacity: 0.0, + activeBgOpacity: 0.0 }); onMuteToggled(); diff --git a/scripts/system/+android/avatarSelection.js b/scripts/system/+android/avatarSelection.js deleted file mode 100644 index 2946e541b5..0000000000 --- a/scripts/system/+android/avatarSelection.js +++ /dev/null @@ -1,164 +0,0 @@ -"use strict"; -// -// avatarSelection.js -// scripts/system/ -// -// Created by Gabriel Calero & Cristian Duarte on 21 Sep 2017 -// Copyright 2017 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -var window; - -var logEnabled = true; -var isVisible = false; - -function printd(str) { - if (logEnabled) - print("[avatarSelection.js] " + str); -} - -function fromQml(message) { // messages are {method, params}, like json-rpc. See also sendToQml. - var data; - printd("fromQml " + JSON.stringify(message)); - switch (message.method) { - case 'selectAvatar': - // use this message.params.avatarUrl - printd("Selected Avatar: [" + message.params.avatarUrl + "]"); - App.askBeforeSetAvatarUrl(message.params.avatarUrl); - break; - case 'openAvatarMarket': - // good - App.openUrl("https://metaverse.highfidelity.com/marketplace?category=avatars"); - break; - case 'hide': - Controller.setVPadHidden(false); - module.exports.hide(); - module.exports.onHidden(); - break; - default: - print('[avatarSelection.js] Unrecognized message from avatarSelection.qml:', JSON.stringify(message)); - } -} - -function sendToQml(message) { - if (!window) { - print("[avatarSelection.js] There is no window object"); - return; - } - window.sendToQml(message); -} - -function refreshSelected(currentAvatarURL) { - sendToQml({ - type: "refreshSelected", - selectedAvatarUrl: currentAvatarURL - }); - - sendToQml({ - type: "showAvatars" - }); -} - -function init() { - if (!window) { - print("[avatarSelection.js] There is no window object for init()"); - return; - } - var DEFAULT_AVATAR_URL = "http://mpassets.highfidelity.com/7fe80a1e-f445-4800-9e89-40e677b03bee-v3/mannequin.fst"; - sendToQml({ - type: "addAvatar", - name: "Wooden Mannequin", - thumbnailUrl: "https://hifi-metaverse.s3-us-west-1.amazonaws.com/marketplace/previews/7fe80a1e-f445-4800-9e89-40e677b03bee/thumbnail/hifi-mp-7fe80a1e-f445-4800-9e89-40e677b03bee.jpg", - avatarUrl: DEFAULT_AVATAR_URL - }); - sendToQml({ - type: "addAvatar", - name: "Cody", - thumbnailUrl: "https://hifi-metaverse.s3-us-west-1.amazonaws.com/marketplace/previews/8c859fca-4cbd-4e82-aad1-5f4cb0ca5d53/thumbnail/hifi-mp-8c859fca-4cbd-4e82-aad1-5f4cb0ca5d53.jpg", - avatarUrl: "http://mpassets.highfidelity.com/8c859fca-4cbd-4e82-aad1-5f4cb0ca5d53-v1/cody.fst" - }); - sendToQml({ - type: "addAvatar", - name: "Mixamo Will", - thumbnailUrl: "https://hifi-metaverse.s3-us-west-1.amazonaws.com/marketplace/previews/d029ae8d-2905-4eb7-ba46-4bd1b8cb9d73/thumbnail/hifi-mp-d029ae8d-2905-4eb7-ba46-4bd1b8cb9d73.jpg", - avatarUrl: "http://mpassets.highfidelity.com/d029ae8d-2905-4eb7-ba46-4bd1b8cb9d73-v1/4618d52e711fbb34df442b414da767bb.fst" - }); - sendToQml({ - type: "addAvatar", - name: "Albert", - thumbnailUrl: "https://hifi-metaverse.s3-us-west-1.amazonaws.com/marketplace/previews/1e57c395-612e-4acd-9561-e79dbda0bc49/thumbnail/hifi-mp-1e57c395-612e-4acd-9561-e79dbda0bc49.jpg", - avatarUrl: "http://mpassets.highfidelity.com/1e57c395-612e-4acd-9561-e79dbda0bc49-v1/albert.fst" - }); - /* We need to implement the wallet, so let's skip this for the moment - sendToQml({ - type: "addExtraOption", - showName: "More choices", - thumbnailUrl: "../../../images/moreAvatars.png", - methodNameWhenClicked: "openAvatarMarket", - actionText: "MARKETPLACE" - }); - */ - var currentAvatarURL = Settings.getValue('Avatar/fullAvatarURL', DEFAULT_AVATAR_URL); - printd("Default Avatar: [" + DEFAULT_AVATAR_URL + "]"); - printd("Current Avatar: [" + currentAvatarURL + "]"); - if (!currentAvatarURL || 0 === currentAvatarURL.length) { - currentAvatarURL = DEFAULT_AVATAR_URL; - } - refreshSelected(currentAvatarURL); -} - -module.exports = { - init: function() { - window = new QmlFragment({ - qml: "hifi/avatarSelection.qml", - visible: false - }); - if (window) { - window.fromQml.connect(fromQml); - } - init(); - }, - show: function() { - Controller.setVPadHidden(true); - if (window) { - window.setVisible(true); - isVisible = true; - } - }, - hide: function() { - Controller.setVPadHidden(false); - if (window) { - window.setVisible(false); - } - isVisible = false; - }, - destroy: function() { - Controller.setVPadHidden(false); - if (window) { - window.fromQml.disconnect(fromQml); - window.close(); - window = null; - } - }, - isVisible: function() { - return isVisible; - }, - width: function() { - return window ? window.size.x : 0; - }, - height: function() { - return window ? window.size.y : 0; - }, - position: function() { - return window && isVisible ? window.position : null; - }, - refreshSelectedAvatar: function(currentAvatarURL) { - refreshSelected(currentAvatarURL); - }, - onHidden: function() { - Controller.setVPadHidden(false); - } -}; diff --git a/scripts/system/+android/bottombar.js b/scripts/system/+android/bottombar.js deleted file mode 100644 index 3435edb548..0000000000 --- a/scripts/system/+android/bottombar.js +++ /dev/null @@ -1,267 +0,0 @@ -"use strict"; -// -// bottombar.js -// scripts/system/ -// -// Created by Gabriel Calero & Cristian Duarte on Jan 18, 2018 -// 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 -// -(function() { // BEGIN LOCAL_SCOPE - -var bottombar; -var bottomHudOptionsBar; -var gotoBtn; -var avatarBtn; -var bubbleBtn; -var loginBtn; - -var gotoScript = Script.require('./goto.js'); -var avatarSelection = Script.require('./avatarSelection.js'); - -var logEnabled = false; - -function printd(str) { - if (logEnabled) { - print("[bottombar.js] " + str); - } -} - -function init() { - gotoScript.init(); - gotoScript.setOnShownChange(function (shown) { - if (shown) { - showAddressBar(); - } else { - hideAddressBar(); - } - }); - avatarSelection.init(); - App.fullAvatarURLChanged.connect(processedNewAvatar); - - setupBottomBar(); - setupBottomHudOptionsBar(); - - raiseBottomBar(); - - GlobalServices.connected.connect(handleLogin); - GlobalServices.disconnected.connect(handleLogout); -} - -function shutdown() { - App.fullAvatarURLChanged.disconnect(processedNewAvatar); -} - -function setupBottomBar() { - bottombar = new QmlFragment({ - qml: "hifi/bottombar.qml" - }); - - bottombar.fromQml.connect(function(message) { - switch (message.method) { - case 'hide': - lowerBottomBar(); - break; - default: - print('[bottombar.js] Unrecognized message from bottomHud.qml:', JSON.stringify(message)); - } - }); - - avatarBtn = bottombar.addButton({ - icon: "icons/avatar-i.svg", - activeIcon: "icons/avatar-a.svg", - bgOpacity: 0, - height: 240, - width: 294, - hoverBgOpacity: 0, - activeBgOpacity: 0, - activeHoverBgOpacity: 0, - iconSize: 108, - textSize: 45, - text: "AVATAR" - }); - avatarBtn.clicked.connect(function() { - printd("Avatar button clicked"); - if (!avatarSelection.isVisible()) { - showAvatarSelection(); - } else { - hideAvatarSelection(); - } - }); - avatarSelection.onHidden = function() { - if (avatarBtn) { - avatarBtn.isActive = false; - } - }; - - gotoBtn = bottombar.addButton({ - icon: "icons/goto-i.svg", - activeIcon: "icons/goto-a.svg", - bgOpacity: 0, - hoverBgOpacity: 0, - activeBgOpacity: 0, - activeHoverBgOpacity: 0, - height: 240, - width: 294, - iconSize: 108, - textSize: 45, - text: "GO TO" - }); - - gotoBtn.clicked.connect(function() { - if (!gotoScript.isVisible()) { - showAddressBar(); - } else { - hideAddressBar(); - } - }); - - bubbleBtn = bottombar.addButton({ - icon: "icons/bubble-i.svg", - activeIcon: "icons/bubble-a.svg", - bgOpacity: 0, - hoverBgOpacity: 0, - activeBgOpacity: 0, - activeHoverBgOpacity: 0, - height: 240, - width: 294, - iconSize: 108, - textSize: 45, - text: "BUBBLE" - }); - - bubbleBtn.editProperties({isActive: Users.getIgnoreRadiusEnabled()}); - - bubbleBtn.clicked.connect(function() { - Users.toggleIgnoreRadius(); - bubbleBtn.editProperties({isActive: Users.getIgnoreRadiusEnabled()}); - }); - - loginBtn = bottombar.addButton({ - icon: "icons/login-i.svg", - activeIcon: "icons/login-a.svg", - height: 240, - width: 294, - iconSize: 108, - textSize: 45, - text: Account.isLoggedIn() ? "LOG OUT" : "LOG IN" - }); - loginBtn.clicked.connect(function() { - if (!Account.isLoggedIn()) { - Account.checkAndSignalForAccessToken(); - } else { - Menu.triggerOption("Login / Sign Up"); - } - }); - - // TODO: setup all the buttons or provide a dynamic interface - - raiseBottomBar(); - - -} - -var setupBottomHudOptionsBar = function() { - var bottomHud = new QmlFragment({ - qml: "hifi/bottomHudOptions.qml" - }); - - bottomHudOptionsBar = { - show: function() { - bottomHud.setVisible(true); - }, - hide: function() { - bottomHud.setVisible(false); - }, - qmlFragment: bottomHud - }; - bottomHud.fromQml.connect( - function(message) { - switch (message.method) { - case 'showUpBar': - printd('[bottombar.js] showUpBar message from bottomHudOptions.qml: ', JSON.stringify(message)); - raiseBottomBar(); - break; - default: - print('[bottombar.js] Unrecognized message from bottomHudOptions.qml:', JSON.stringify(message)); - } - } - ); -} - -function lowerBottomBar() { - if (bottombar) { - bottombar.setVisible(false); - } - if (bottomHudOptionsBar) { - bottomHudOptionsBar.show(); - } - Controller.setVPadExtraBottomMargin(0); -} - -function raiseBottomBar() { - print('[bottombar.js] raiseBottomBar begin'); - if (bottombar) { - bottombar.setVisible(true); - } - if (bottomHudOptionsBar) { - bottomHudOptionsBar.hide(); - } - Controller.setVPadExtraBottomMargin(255); // Height in bottombar.qml - print('[bottombar.js] raiseBottomBar end'); -} - -function showAddressBar() { - gotoScript.show(); - gotoBtn.isActive = true; -} - -function hideAddressBar() { - gotoScript.hide(); - gotoBtn.isActive = false; -} - -function showAvatarSelection() { - avatarSelection.show(); - avatarBtn.isActive = true; -} - -function hideAvatarSelection() { - avatarSelection.hide(); - avatarBtn.isActive = false; -} - -// TODO: Move to avatarSelection.js and make it possible to hide the window from there AND switch the button state here too -function processedNewAvatar(url, modelName) { - avatarSelection.refreshSelectedAvatar(url); - hideAvatarSelection(); -} - -function handleLogin() { - Script.setTimeout(function() { - if (Account.isLoggedIn()) { - MyAvatar.displayName=Account.getUsername(); - } - }, 2000); - if (loginBtn) { - loginBtn.editProperties({text: "LOG OUT"}); - } -} -function handleLogout() { - MyAvatar.displayName=""; - if (loginBtn) { - loginBtn.editProperties({text: "LOG IN"}); - } -} - -Script.scriptEnding.connect(function () { - shutdown(); - GlobalServices.connected.disconnect(handleLogin); - GlobalServices.disconnected.disconnect(handleLogout); -}); - -init(); - -}()); // END LOCAL_SCOPE diff --git a/scripts/system/+android/goto.js b/scripts/system/+android/goto.js deleted file mode 100644 index 2019af9077..0000000000 --- a/scripts/system/+android/goto.js +++ /dev/null @@ -1,96 +0,0 @@ -"use strict"; -// -// goto-android.js -// scripts/system/ -// -// Created by Gabriel Calero & Cristian Duarte on 12 Sep 2017 -// Copyright 2017 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -var window; - - -var logEnabled = false; -function printd(str) { - if (logEnabled) - print("[goto-android.js] " + str); -} - -function init() { -} - -function fromQml(message) { // messages are {method, params}, like json-rpc. See also sendToQml. - switch (message.method) { - case 'shownChanged': - if (notifyShownChange) { - notifyShownChange(message.params.shown); - } ; - break; - case 'hide': - module.exports.hide(); - module.exports.onHidden(); - break; - default: - print('[goto-android.js] Unrecognized message from AddressBarDialog.qml:', JSON.stringify(message)); - } -} - -function sendToQml(message) { - window.sendToQml(message); -} - -var isVisible = false; -var notifyShownChange; -module.exports = { - init: function() { - window = new QmlFragment({ - qml: "AddressBarDialog.qml", - visible: false - }); - }, - show: function() { - Controller.setVPadHidden(true); - if (window) { - window.fromQml.connect(fromQml); - window.setVisible(true); - isVisible = true; - } - }, - hide: function() { - Controller.setVPadHidden(false); - if (window) { - window.fromQml.disconnect(fromQml); - window.setVisible(false); - } - isVisible = false; - }, - destroy: function() { - if (window) { - window.close(); - window = null; - } - }, - isVisible: function() { - return isVisible; - }, - width: function() { - return window ? window.size.x : 0; - }, - height: function() { - return window ? window.size.y : 0; - }, - position: function() { - return window && isVisible ? window.position : null; - }, - setOnShownChange: function(f) { - notifyShownChange = f; - }, - onHidden: function() { } - - -}; - -init(); diff --git a/scripts/system/+android/modes.js b/scripts/system/+android/modes.js index c41ae1f327..f5b3609c26 100644 --- a/scripts/system/+android/modes.js +++ b/scripts/system/+android/modes.js @@ -11,15 +11,21 @@ // (function() { // BEGIN LOCAL_SCOPE -var modesbar; -var modesButtons; -var currentSelectedBtn; +var modeButton; +var currentMode; +var barQml; var SETTING_CURRENT_MODE_KEY = 'Android/Mode'; var MODE_VR = "VR", MODE_RADAR = "RADAR", MODE_MY_VIEW = "MY VIEW"; var DEFAULT_MODE = MODE_MY_VIEW; -var logEnabled = true; +var nextMode = {}; +nextMode[MODE_RADAR]=MODE_MY_VIEW; +nextMode[MODE_MY_VIEW]=MODE_RADAR; +var modeLabel = {}; +modeLabel[MODE_RADAR]="TOP VIEW"; +modeLabel[MODE_MY_VIEW]="MY VIEW"; +var logEnabled = false; var radar = Script.require('./radar.js'); var uniqueColor = Script.require('./uniqueColor.js'); @@ -32,89 +38,35 @@ function printd(str) { function init() { radar.setUniqueColor(uniqueColor); radar.init(); - setupModesBar(); + + barQml = new QmlFragment({ + qml: "hifi/modesbar.qml" + }); + modeButton = barQml.addButton({ + icon: "icons/myview-a.svg", + activeBgOpacity: 0.0, + hoverBgOpacity: 0.0, + activeHoverBgOpacity: 0.0, + text: "MODE", + height:240, + bottomMargin: 16, + textSize: 38, + fontFamily: "Raleway", + fontBold: true + + }); + + switchToMode(getCurrentModeSetting()); + + modeButton.clicked.connect(function() { + switchToMode(nextMode[currentMode]); + }); } function shutdown() { } -function setupModesBar() { - - var bar = new QmlFragment({ - qml: "hifi/modesbar.qml" - }); - var buttonRadarMode = bar.addButton({ - icon: "icons/radar-i.svg", - activeIcon: "icons/radar-a.svg", - hoverIcon: "icons/radar-a.svg", - activeBgOpacity: 0.0, - hoverBgOpacity: 0.0, - activeHoverBgOpacity: 0.0, - text: "RADAR", - height:240, - bottomMargin: 6, - textSize: 45 - }); - var buttonMyViewMode = bar.addButton({ - icon: "icons/myview-i.svg", - activeIcon: "icons/myview-a.svg", - hoverIcon: "icons/myview-a.svg", - activeBgOpacity: 0.0, - hoverBgOpacity: 0.0, - activeHoverBgOpacity: 0.0, - text: "MY VIEW", - height: 240, - bottomMargin: 6, - textSize: 45 - }); - - modesButtons = [buttonRadarMode, buttonMyViewMode]; - - var mode = getCurrentModeSetting(); - - var buttonsRevealed = false; - bar.sendToQml({type: "inactiveButtonsHidden"}); - - modesbar = { - restoreMyViewButton: function() { - switchModeButtons(buttonMyViewMode); - saveCurrentModeSetting(MODE_MY_VIEW); - }, - sendToQml: function(o) { bar.sendToQml(o); }, - qmlFragment: bar - }; - - buttonRadarMode.clicked.connect(function() { - //if (connections.isVisible()) return; - saveCurrentModeSetting(MODE_RADAR); - printd("Radar clicked"); - onButtonClicked(buttonRadarMode, function() { - radar.startRadarMode(); - }); - }); - buttonMyViewMode.clicked.connect(function() { - //if (connections.isVisible()) return; - saveCurrentModeSetting(MODE_MY_VIEW); - printd("My View clicked"); - onButtonClicked(buttonMyViewMode, function() { - if (currentSelectedBtn == buttonRadarMode) { - radar.endRadarMode(); - } - }); - }); - - var savedButton; - if (mode == MODE_MY_VIEW) { - savedButton = buttonMyViewMode; - } else { - savedButton = buttonRadarMode; - } - printd("[MODE] previous mode " + mode); - - savedButton.clicked(); -} - function saveCurrentModeSetting(mode) { Settings.setValue(SETTING_CURRENT_MODE_KEY, mode); } @@ -123,62 +75,29 @@ function getCurrentModeSetting(mode) { return Settings.getValue(SETTING_CURRENT_MODE_KEY, DEFAULT_MODE); } -function showAllButtons() { - for (var i=0; i= 0) { that.selections.splice(idx, 1); Selection.removeFromSelectedItemsList(HIGHLIGHT_LIST_NAME, "entity", entityID); } + } + + that.removeEntity = function (entityID) { + removeEntityByID(entityID); + that._update(true); + }; + + that.removeEntities = function(entityIDs) { + for (var i = 0, length = entityIDs.length; i < length; i++) { + removeEntityByID(entityIDs[i]); + } that._update(true); }; diff --git a/scripts/system/marketplaces/marketplaces.js b/scripts/system/marketplaces/marketplaces.js index a05778e2dd..c3edee264f 100644 --- a/scripts/system/marketplaces/marketplaces.js +++ b/scripts/system/marketplaces/marketplaces.js @@ -789,10 +789,14 @@ var selectionDisplay = null; // for gridTool.js to ignore var savedDisablePreviewOptionLocked = false; var savedDisablePreviewOption = Menu.isOptionChecked("Disable Preview");; function maybeEnableHMDPreview() { - setTabletVisibleInSecondaryCamera(true); - DesktopPreviewProvider.setPreviewDisabledReason("USER"); - Menu.setIsOptionChecked("Disable Preview", savedDisablePreviewOption); - savedDisablePreviewOptionLocked = false; + // Set a small timeout to prevent sensitive data from being shown during + // UI fade + Script.setTimeout(function () { + setTabletVisibleInSecondaryCamera(true); + DesktopPreviewProvider.setPreviewDisabledReason("USER"); + Menu.setIsOptionChecked("Disable Preview", savedDisablePreviewOption); + savedDisablePreviewOptionLocked = false; + }, 150); } // Function Name: fromQml() diff --git a/server-console/package-lock.json b/server-console/package-lock.json index 4311fde51a..4f12f2fa00 100644 --- a/server-console/package-lock.json +++ b/server-console/package-lock.json @@ -20,7 +20,6 @@ "version": "5.5.2", "resolved": "https://registry.npmjs.org/ajv/-/ajv-5.5.2.tgz", "integrity": "sha1-c7Xuyj+rZT49P5Qis0GtQiBdyWU=", - "dev": true, "requires": { "co": "4.6.0", "fast-deep-equal": "1.0.0", @@ -41,11 +40,6 @@ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.0.0.tgz", "integrity": "sha1-xQYbbg74qBd15Q9dZhUb9r83EQc=" }, - "ansi-styles": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", - "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=" - }, "array-find-index": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/array-find-index/-/array-find-index-1.0.1.tgz", @@ -118,16 +112,10 @@ "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-0.2.0.tgz", "integrity": "sha1-104bh+ev/A24qttwIfP+SBAasjQ=" }, - "async": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", - "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=" - }, "asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=", - "dev": true + "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" }, "author-regex": { "version": "1.0.0", @@ -136,17 +124,14 @@ "dev": true }, "aws-sign2": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.6.0.tgz", - "integrity": "sha1-FDQt0428yU0OW4fXY81jYSwOeU8=" + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", + "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=" }, "aws4": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.3.2.tgz", - "integrity": "sha1-054L7kEs7Q6O2Uoj4xTzE6lbn9E=", - "requires": { - "lru-cache": "4.0.1" - } + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.7.0.tgz", + "integrity": "sha512-32NDda82rhwD9/JBCCkB+MRYDp0oSvlo2IL6rQWA10PQi7tDUM3eqMSltXmY+Oyl/7N3P3qNtAlv7X0d9bI28w==" }, "base64-js": { "version": "1.2.0", @@ -204,11 +189,11 @@ "integrity": "sha1-aN/1++YMUes3cl6p4+0xDcwed24=" }, "boom": { - "version": "2.10.1", - "resolved": "https://registry.npmjs.org/boom/-/boom-2.10.1.tgz", - "integrity": "sha1-OciRjO/1eZ+D+UkqhI9iWt0Mdm8=", + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/boom/-/boom-4.3.1.tgz", + "integrity": "sha1-T4owBctKfjiJ90kDD9JbluAdLjE=", "requires": { - "hoek": "2.16.3" + "hoek": "4.2.1" } }, "buffers": { @@ -239,9 +224,9 @@ } }, "caseless": { - "version": "0.11.0", - "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.11.0.tgz", - "integrity": "sha1-cVuW6phBWTzDMGeSP17GDr2k99c=" + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", + "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=" }, "chainsaw": { "version": "0.1.0", @@ -252,18 +237,6 @@ "traverse": "0.3.9" } }, - "chalk": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", - "requires": { - "ansi-styles": "2.2.1", - "escape-string-regexp": "1.0.5", - "has-ansi": "2.0.0", - "strip-ansi": "3.0.1", - "supports-color": "2.0.0" - } - }, "cheerio": { "version": "0.19.0", "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-0.19.0.tgz", @@ -295,8 +268,7 @@ "co": { "version": "4.6.0", "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", - "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=", - "dev": true + "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=" }, "code-point-at": { "version": "1.0.0", @@ -318,6 +290,7 @@ "version": "2.9.0", "resolved": "https://registry.npmjs.org/commander/-/commander-2.9.0.tgz", "integrity": "sha1-nJkJQXbhIkDLItbFFGCYQA/g99Q=", + "dev": true, "requires": { "graceful-readlink": "1.0.1" } @@ -373,11 +346,21 @@ "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" }, "cryptiles": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-2.0.5.tgz", - "integrity": "sha1-O9/s3GCBR8HGcgL6KR59ylnqo7g=", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-3.1.2.tgz", + "integrity": "sha1-qJ+7Ig9c4l7FboxKqKT9e1sNKf4=", "requires": { - "boom": "2.10.1" + "boom": "5.2.0" + }, + "dependencies": { + "boom": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/boom/-/boom-5.2.0.tgz", + "integrity": "sha512-Z5BTk6ZRe4tXXQlkqftmsAUANpXmuwlsF5Oov8ThoMbQRzdGTA1ngYRW160GexgOgjsFOKJz0LYhoNi+2AMBUw==", + "requires": { + "hoek": "4.2.1" + } + } } }, "css-select": { @@ -728,7 +711,7 @@ "minimist": "1.2.0", "pretty-bytes": "1.0.4", "progress-stream": "1.2.0", - "request": "2.71.0", + "request": "2.85.0", "single-line-log": "1.1.2", "throttleit": "0.0.2" }, @@ -828,11 +811,6 @@ "integrity": "sha512-/NdNZVJg+uZgtm9eS3O6lrOLYmQag2DjdEXuPaHlZ6RuVqgqaVZfgYCepEIKsLqwdQArOPtC3XzRLqGGfT8KQQ==", "dev": true }, - "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" - }, "extend": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.0.tgz", @@ -875,14 +853,12 @@ "fast-deep-equal": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.0.0.tgz", - "integrity": "sha1-liVqO8l1WV6zbYLpkp0GDYk0Of8=", - "dev": true + "integrity": "sha1-liVqO8l1WV6zbYLpkp0GDYk0Of8=" }, "fast-json-stable-stringify": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz", - "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=", - "dev": true + "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=" }, "fd-slicer": { "version": "1.0.1", @@ -976,13 +952,23 @@ "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=" }, "form-data": { - "version": "1.0.0-rc4", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-1.0.0-rc4.tgz", - "integrity": "sha1-BaxrwiIntD5EYfSIFhVUaZ1Pi14=", + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.2.tgz", + "integrity": "sha1-SXBJi+YEwgwAXU9cI67NIda0kJk=", "requires": { - "async": "1.5.2", - "combined-stream": "1.0.5", - "mime-types": "2.1.10" + "asynckit": "0.4.0", + "combined-stream": "1.0.6", + "mime-types": "2.1.18" + }, + "dependencies": { + "combined-stream": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.6.tgz", + "integrity": "sha1-cj599ugBrFYTETp+RFqbactjKBg=", + "requires": { + "delayed-stream": "1.0.0" + } + } } }, "fs-extra": { @@ -1058,19 +1044,6 @@ } } }, - "generate-function": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/generate-function/-/generate-function-2.0.0.tgz", - "integrity": "sha1-aFj+fAlpt9TpCTM3ZHrHn2DfvnQ=" - }, - "generate-object-property": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/generate-object-property/-/generate-object-property-1.2.0.tgz", - "integrity": "sha1-nA4cQDCM6AT0eDYYuTf6iPmdUNA=", - "requires": { - "is-property": "1.0.2" - } - }, "get-package-info": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/get-package-info/-/get-package-info-1.0.0.tgz", @@ -1212,7 +1185,8 @@ "graceful-readlink": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/graceful-readlink/-/graceful-readlink-1.0.1.tgz", - "integrity": "sha1-TK+tdrxi8C+gObL5Tpo906ORpyU=" + "integrity": "sha1-TK+tdrxi8C+gObL5Tpo906ORpyU=", + "dev": true }, "growly": { "version": "1.3.0", @@ -1222,43 +1196,32 @@ "har-schema": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", - "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=", - "dev": true + "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=" }, "har-validator": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-2.0.6.tgz", - "integrity": "sha1-zcvAgYgmWtEZtqWnyKtw7s+10n0=", + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.0.3.tgz", + "integrity": "sha1-ukAsJmGU8VlW7xXg/PJCmT9qff0=", "requires": { - "chalk": "1.1.3", - "commander": "2.9.0", - "is-my-json-valid": "2.13.1", - "pinkie-promise": "2.0.1" - } - }, - "has-ansi": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", - "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", - "requires": { - "ansi-regex": "2.0.0" + "ajv": "5.5.2", + "har-schema": "2.0.0" } }, "hawk": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/hawk/-/hawk-3.1.3.tgz", - "integrity": "sha1-B4REvXwWQLD+VA0sm3PVlnjo4cQ=", + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/hawk/-/hawk-6.0.2.tgz", + "integrity": "sha512-miowhl2+U7Qle4vdLqDdPt9m09K6yZhkLDTWGoUiUzrQCn+mHHSmfJgAyGaLRZbPmTqfFFjRV1QWCW0VWUJBbQ==", "requires": { - "boom": "2.10.1", - "cryptiles": "2.0.5", - "hoek": "2.16.3", - "sntp": "1.0.9" + "boom": "4.3.1", + "cryptiles": "3.1.2", + "hoek": "4.2.1", + "sntp": "2.1.0" } }, "hoek": { - "version": "2.16.3", - "resolved": "https://registry.npmjs.org/hoek/-/hoek-2.16.3.tgz", - "integrity": "sha1-ILt0A9POo5jpHcRxCo/xuCdKJe0=" + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/hoek/-/hoek-4.2.1.tgz", + "integrity": "sha512-QLg82fGkfnJ/4iy1xZ81/9SIJiq1NGFUMGs6ParyjBZr6jW2Ufj/snDqTHixNlHdPNwN2RLVD0Pi3igeK9+JfA==" }, "home-path": { "version": "1.0.5", @@ -1301,13 +1264,20 @@ } }, "http-signature": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.1.1.tgz", - "integrity": "sha1-33LiZwZs0Kxn+3at+OE0qPvPkb8=", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", + "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", "requires": { - "assert-plus": "0.2.0", + "assert-plus": "1.0.0", "jsprim": "1.2.2", "sshpk": "1.7.4" + }, + "dependencies": { + "assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" + } } }, "indent-string": { @@ -1388,28 +1358,12 @@ "number-is-nan": "1.0.0" } }, - "is-my-json-valid": { - "version": "2.13.1", - "resolved": "https://registry.npmjs.org/is-my-json-valid/-/is-my-json-valid-2.13.1.tgz", - "integrity": "sha1-1Vd4qC/rawlj/0vhEdXRaE6JBwc=", - "requires": { - "generate-function": "2.0.0", - "generate-object-property": "1.2.0", - "jsonpointer": "2.0.0", - "xtend": "4.0.1" - } - }, "is-promise": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-1.0.1.tgz", "integrity": "sha1-MVc3YcBX4zwukaq56W2gjO++duU=", "dev": true }, - "is-property": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz", - "integrity": "sha1-V/4cTkhHTt1lsJkR8msc1Ald2oQ=" - }, "is-typedarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", @@ -1465,8 +1419,7 @@ "json-schema-traverse": { "version": "0.3.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz", - "integrity": "sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A=", - "dev": true + "integrity": "sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A=" }, "json-stringify-safe": { "version": "5.0.1", @@ -1478,11 +1431,6 @@ "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-2.2.3.tgz", "integrity": "sha1-4lK5mmr5AdPsQfMyWJyQUJp7xgU=" }, - "jsonpointer": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/jsonpointer/-/jsonpointer-2.0.0.tgz", - "integrity": "sha1-OvHdIP6FRjkQ1GmjheMwF9KgMNk=" - }, "jsprim": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.2.2.tgz", @@ -1569,15 +1517,6 @@ "signal-exit": "2.1.2" } }, - "lru-cache": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.0.1.tgz", - "integrity": "sha1-E0OVXtry432bnn7nJB4nxLn7cr4=", - "requires": { - "pseudomap": "1.0.2", - "yallist": "2.0.0" - } - }, "map-obj": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz", @@ -1603,16 +1542,16 @@ } }, "mime-db": { - "version": "1.22.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.22.0.tgz", - "integrity": "sha1-qyOmNy3J2G09yRIb0OvTgQWhkEo=" + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.33.0.tgz", + "integrity": "sha512-BHJ/EKruNIqJf/QahvxwQZXKygOQ256myeN/Ew+THcAa5q+PjyTTMMeNQC4DZw5AwfvelsUrA6B67NKMqXDbzQ==" }, "mime-types": { - "version": "2.1.10", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.10.tgz", - "integrity": "sha1-uTx8tDYuFtQQcqflRTj7TUMHCDc=", + "version": "2.1.18", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.18.tgz", + "integrity": "sha512-lc/aahn+t4/SWV/qcmumYjymLsWfN3ELhpmVuUFjgsORruuZPVSwAQryq+HHGvO/SI2KVX26bx+En+zhM8g8hQ==", "requires": { - "mime-db": "1.22.0" + "mime-db": "1.33.0" } }, "minimist": { @@ -1891,11 +1830,6 @@ } } }, - "node-uuid": { - "version": "1.4.7", - "resolved": "https://registry.npmjs.org/node-uuid/-/node-uuid-1.4.7.tgz", - "integrity": "sha1-baWhdmjEs91ZYjvaEc9/pMH2Cm8=" - }, "nodeify": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/nodeify/-/nodeify-1.0.1.tgz", @@ -1945,7 +1879,7 @@ "minimist": "1.2.0", "pretty-bytes": "1.0.4", "progress-stream": "1.2.0", - "request": "2.71.0", + "request": "2.85.0", "single-line-log": "1.1.2", "throttleit": "0.0.2" }, @@ -1973,9 +1907,9 @@ "integrity": "sha1-wCD1KcUoKt/dIz2R1LGBw9aG3Es=" }, "oauth-sign": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.8.1.tgz", - "integrity": "sha1-GCQ5vbkTeL90YOdcZOpD5kSN7wY=" + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.8.2.tgz", + "integrity": "sha1-Rqarfwrq2N6unsBWV4C31O/rnUM=" }, "object-assign": { "version": "4.0.1", @@ -2099,8 +2033,7 @@ "performance-now": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", - "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=", - "dev": true + "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=" }, "pify": { "version": "2.3.0", @@ -2111,12 +2044,14 @@ "pinkie": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", - "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=" + "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=", + "dev": true }, "pinkie-promise": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", + "dev": true, "requires": { "pinkie": "2.0.4" } @@ -2166,11 +2101,6 @@ "is-promise": "1.0.1" } }, - "pseudomap": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", - "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=" - }, "pump": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/pump/-/pump-1.0.1.tgz", @@ -2183,8 +2113,7 @@ "punycode": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", - "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=", - "dev": true + "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=" }, "q": { "version": "1.5.1", @@ -2193,9 +2122,9 @@ "dev": true }, "qs": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.1.0.tgz", - "integrity": "sha1-7B0WJrJCeNmfD99FSeUk4k7O6yY=" + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.1.tgz", + "integrity": "sha512-eRzhrN1WSINYCDCbrz796z37LOe3m5tmW7RQf6oBntukAG1nmovJvhnwHHRMAfeoItc1m2Hk02WER2aQ/iqs+A==" }, "rc": { "version": "1.1.6", @@ -2252,31 +2181,39 @@ } }, "request": { - "version": "2.71.0", - "resolved": "https://registry.npmjs.org/request/-/request-2.71.0.tgz", - "integrity": "sha1-bxRkPJxaZ8ruapXPjvBHfVYDvZE=", + "version": "2.85.0", + "resolved": "https://registry.npmjs.org/request/-/request-2.85.0.tgz", + "integrity": "sha512-8H7Ehijd4js+s6wuVPLjwORxD4zeuyjYugprdOXlPSqaApmL/QOy+EB/beICHVCHkGMKNh5rvihb5ov+IDw4mg==", "requires": { - "aws-sign2": "0.6.0", - "aws4": "1.3.2", - "bl": "1.1.2", - "caseless": "0.11.0", + "aws-sign2": "0.7.0", + "aws4": "1.7.0", + "caseless": "0.12.0", "combined-stream": "1.0.5", - "extend": "3.0.0", + "extend": "3.0.1", "forever-agent": "0.6.1", - "form-data": "1.0.0-rc4", - "har-validator": "2.0.6", - "hawk": "3.1.3", - "http-signature": "1.1.1", + "form-data": "2.3.2", + "har-validator": "5.0.3", + "hawk": "6.0.2", + "http-signature": "1.2.0", "is-typedarray": "1.0.0", "isstream": "0.1.2", "json-stringify-safe": "5.0.1", - "mime-types": "2.1.10", - "node-uuid": "1.4.7", - "oauth-sign": "0.8.1", - "qs": "6.1.0", + "mime-types": "2.1.18", + "oauth-sign": "0.8.2", + "performance-now": "2.1.0", + "qs": "6.5.1", + "safe-buffer": "5.1.1", "stringstream": "0.0.5", - "tough-cookie": "2.2.2", - "tunnel-agent": "0.4.2" + "tough-cookie": "2.3.4", + "tunnel-agent": "0.6.0", + "uuid": "3.2.1" + }, + "dependencies": { + "extend": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.1.tgz", + "integrity": "sha1-p1Xqe8Gt/MWjHOfnYtuq3F5jZEQ=" + } } }, "request-progress": { @@ -2308,8 +2245,7 @@ "safe-buffer": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz", - "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==", - "dev": true + "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==" }, "sanitize-filename": { "version": "1.6.1", @@ -2347,11 +2283,11 @@ } }, "sntp": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/sntp/-/sntp-1.0.9.tgz", - "integrity": "sha1-ZUEYTMkK7qbG57NeJlkIJEPGYZg=", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/sntp/-/sntp-2.1.0.tgz", + "integrity": "sha512-FL1b58BDrqS3A11lJ0zEdnJ3UOKqVxawAkF3k7F0CVN7VQ34aZrV+G8BZ1WC9ZL7NyrwsW0oviwsWDgRuVYtJg==", "requires": { - "hoek": "2.16.3" + "hoek": "4.2.1" } }, "spdx-correct": { @@ -2483,11 +2419,6 @@ } } }, - "supports-color": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=" - }, "tar-fs": { "version": "1.12.0", "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-1.12.0.tgz", @@ -2585,9 +2516,12 @@ } }, "tough-cookie": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.2.2.tgz", - "integrity": "sha1-yDoYMPTl7wuT7yo0iOck+N4Basc=" + "version": "2.3.4", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.3.4.tgz", + "integrity": "sha512-TZ6TTfI5NtZnuyy/Kecv+CnoROnyXn2DN97LontgQpCwsX2XyLYCC0ENhYkehSOwAp8rTQKc/NUIF7BkQ5rKLA==", + "requires": { + "punycode": "1.4.1" + } }, "traverse": { "version": "0.3.9", @@ -2611,9 +2545,12 @@ } }, "tunnel-agent": { - "version": "0.4.2", - "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.4.2.tgz", - "integrity": "sha1-EQTj82rIcSXChycAZ9WC0YEzv+4=" + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", + "requires": { + "safe-buffer": "5.1.1" + } }, "tweetnacl": { "version": "0.14.3", @@ -2644,6 +2581,11 @@ "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" }, + "uuid": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.2.1.tgz", + "integrity": "sha512-jZnMwlb9Iku/O3smGWvZhauCf6cvvpKi4BKRiliS3cxnI+Gz9j5MEpTz2UFuXiKPJocb7gnsLHwiS05ige5BEA==" + }, "validate-npm-package-license": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.1.tgz", @@ -2710,11 +2652,6 @@ "resolved": "https://registry.npmjs.org/y18n/-/y18n-3.2.1.tgz", "integrity": "sha1-bRX7qITAhnnA136I53WegR4H+kE=" }, - "yallist": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.0.0.tgz", - "integrity": "sha1-MGxUODXwnuGkyyO3vOmrNByRzdQ=" - }, "yargs": { "version": "3.32.0", "resolved": "https://registry.npmjs.org/yargs/-/yargs-3.32.0.tgz", diff --git a/server-console/package.json b/server-console/package.json index 2428d2574e..6dd39ea6f8 100644 --- a/server-console/package.json +++ b/server-console/package.json @@ -30,7 +30,7 @@ "fs-extra": "^1.0.0", "node-notifier": "^5.2.1", "os-homedir": "^1.0.1", - "request": "^2.67.0", + "request": "^2.85.0", "request-progress": "1.0.2", "tar-fs": "^1.12.0", "yargs": "^3.30.0" diff --git a/tests/jitter/src/JitterTests.cpp b/tests/jitter/src/JitterTests.cpp index b09cb40d3e..5c81177b88 100644 --- a/tests/jitter/src/JitterTests.cpp +++ b/tests/jitter/src/JitterTests.cpp @@ -6,6 +6,8 @@ // Copyright (c) 2014 High Fidelity, Inc. All rights reserved. // +#include "JitterTests.h" + #include #ifdef _WINDOWS #include @@ -23,8 +25,6 @@ #include #include -#include "JitterTests.h" - // Uncomment this to run manually //#define RUN_MANUALLY diff --git a/tests/networking/src/ResourceTests.cpp b/tests/networking/src/ResourceTests.cpp index e83eeb66a0..864d7c9939 100644 --- a/tests/networking/src/ResourceTests.cpp +++ b/tests/networking/src/ResourceTests.cpp @@ -7,14 +7,14 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include "ResourceTests.h" + #include #include "ResourceCache.h" #include "NetworkAccessManager.h" #include "DependencyManager.h" -#include "ResourceTests.h" - QTEST_MAIN(ResourceTests) void ResourceTests::initTestCase() { diff --git a/tests/networking/src/SequenceNumberStatsTests.cpp b/tests/networking/src/SequenceNumberStatsTests.cpp index aaaeea53fc..0f01fb5b66 100644 --- a/tests/networking/src/SequenceNumberStatsTests.cpp +++ b/tests/networking/src/SequenceNumberStatsTests.cpp @@ -9,12 +9,12 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include "SequenceNumberStatsTests.h" + #include #include -#include "SequenceNumberStatsTests.h" - QTEST_MAIN(SequenceNumberStatsTests) const quint32 UINT16_RANGE = std::numeric_limits::max() + 1; diff --git a/tests/octree/src/AABoxCubeTests.cpp b/tests/octree/src/AABoxCubeTests.cpp index 8180e6f674..4e0a75e3b9 100644 --- a/tests/octree/src/AABoxCubeTests.cpp +++ b/tests/octree/src/AABoxCubeTests.cpp @@ -9,11 +9,11 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include "AABoxCubeTests.h" + #include #include -#include "AABoxCubeTests.h" - QTEST_MAIN(AABoxCubeTests) void AABoxCubeTests::raycastOutHitsXMinFace() { diff --git a/tests/octree/src/ModelTests.cpp b/tests/octree/src/ModelTests.cpp index c2d170da9a..f3e17a56a5 100644 --- a/tests/octree/src/ModelTests.cpp +++ b/tests/octree/src/ModelTests.cpp @@ -12,6 +12,9 @@ // * need to add expected results and accumulation of test success/failure // +#include "ModelTests.h" // needs to be EntityTests.h soon +//#include "EntityTests.h" + #include #include @@ -22,9 +25,6 @@ #include #include -//#include "EntityTests.h" -#include "ModelTests.h" // needs to be EntityTests.h soon - QTEST_MAIN(EntityTests) /* diff --git a/tests/octree/src/OctreeTests.cpp b/tests/octree/src/OctreeTests.cpp index 81300a1293..ae04313a6a 100644 --- a/tests/octree/src/OctreeTests.cpp +++ b/tests/octree/src/OctreeTests.cpp @@ -12,6 +12,8 @@ // * need to add expected results and accumulation of test success/failure // +#include "OctreeTests.h" + #include #include @@ -23,8 +25,6 @@ #include #include -#include "OctreeTests.h" - enum ExamplePropertyList { EXAMPLE_PROP_PAGED_PROPERTY, EXAMPLE_PROP_CUSTOM_PROPERTIES_INCLUDED, diff --git a/tests/physics/src/ShapeInfoTests.cpp b/tests/physics/src/ShapeInfoTests.cpp index 79d0092dc3..efc88a4032 100644 --- a/tests/physics/src/ShapeInfoTests.cpp +++ b/tests/physics/src/ShapeInfoTests.cpp @@ -9,6 +9,8 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include "ShapeInfoTests.h" + #include #include @@ -19,8 +21,6 @@ #include #include -#include "ShapeInfoTests.h" - QTEST_MAIN(ShapeInfoTests) // Enable this to manually run testHashCollisions diff --git a/tests/physics/src/ShapeManagerTests.cpp b/tests/physics/src/ShapeManagerTests.cpp index f214601a42..393bfdcd07 100644 --- a/tests/physics/src/ShapeManagerTests.cpp +++ b/tests/physics/src/ShapeManagerTests.cpp @@ -9,13 +9,14 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include "ShapeManagerTests.h" + #include + #include #include #include -#include "ShapeManagerTests.h" - QTEST_MAIN(ShapeManagerTests) void ShapeManagerTests::testShapeAccounting() { diff --git a/tests/qml/src/main.cpp b/tests/qml/src/main.cpp index 349ac55d88..d70bb52dde 100644 --- a/tests/qml/src/main.cpp +++ b/tests/qml/src/main.cpp @@ -26,7 +26,7 @@ #include #include #include -#include +#include #include #include #include @@ -88,7 +88,7 @@ private: OffscreenGLCanvas _sharedContext; std::array, DIVISIONS_X> _surfaces; - QOpenGLFunctions_4_5_Core _glf; + QOpenGLFunctions_4_1_Core _glf; std::function _discardLamdba; QSize _size; size_t _surfaceCount{ 0 }; @@ -109,14 +109,6 @@ TestWindow::TestWindow() { Setting::init(); setSurfaceType(QSurface::OpenGLSurface); - QSurfaceFormat format; - format.setDepthBufferSize(24); - format.setStencilBufferSize(8); - format.setVersion(4, 5); - format.setProfile(QSurfaceFormat::OpenGLContextProfile::CoreProfile); - format.setOption(QSurfaceFormat::DebugContext); - QSurfaceFormat::setDefaultFormat(format); - setFormat(format); qmlRegisterType("Hifi", 1, 0, "TestItem"); @@ -145,7 +137,7 @@ void TestWindow::initGl() { gl::initModuleGl(); _glf.initializeOpenGLFunctions(); - _glf.glCreateFramebuffers(1, &_fbo); + _glf.glGenFramebuffers(1, &_fbo); if (!_sharedContext.create(&_glContext) || !_sharedContext.makeCurrent()) { qFatal("Unable to intialize Shared GL context"); @@ -196,6 +188,12 @@ void TestWindow::buildSurface(QmlInfo& qmlInfo, bool video) { void TestWindow::destroySurface(QmlInfo& qmlInfo) { auto& surface = qmlInfo.surface; + auto& currentTexture = qmlInfo.texture; + if (currentTexture) { + auto readFence = _glf.glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0); + glFlush(); + _discardLamdba(currentTexture, readFence); + } auto webView = surface->getRootItem(); if (webView) { // stop loading @@ -274,16 +272,19 @@ void TestWindow::draw() { if (!qmlInfo.surface || !qmlInfo.texture) { continue; } - _glf.glNamedFramebufferTexture(_fbo, GL_COLOR_ATTACHMENT0, qmlInfo.texture, 0); - _glf.glBlitNamedFramebuffer(_fbo, 0, - // src coordinates - 0, 0, _qmlSize.width() - 1, _qmlSize.height() - 1, - // dst coordinates - incrementX * x, incrementY * y, incrementX * (x + 1), incrementY * (y + 1), - // blit mask and filter - GL_COLOR_BUFFER_BIT, GL_NEAREST); + _glf.glBindFramebuffer(GL_READ_FRAMEBUFFER, _fbo); + _glf.glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, qmlInfo.texture, 0); + _glf.glBlitFramebuffer( + // src coordinates + 0, 0, _qmlSize.width() - 1, _qmlSize.height() - 1, + // dst coordinates + incrementX * x, incrementY * y, incrementX * (x + 1), incrementY * (y + 1), + // blit mask and filter + GL_COLOR_BUFFER_BIT, GL_NEAREST); } } + _glf.glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0); + _glf.glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); _glContext.swapBuffers(this); } @@ -292,6 +293,16 @@ void TestWindow::resizeEvent(QResizeEvent* ev) { } int main(int argc, char** argv) { + + QSurfaceFormat format; + format.setDepthBufferSize(24); + format.setStencilBufferSize(8); + format.setVersion(4, 1); + format.setProfile(QSurfaceFormat::OpenGLContextProfile::CoreProfile); + format.setOption(QSurfaceFormat::DebugContext); + QSurfaceFormat::setDefaultFormat(format); + // setFormat(format); + QGuiApplication app(argc, argv); TestWindow window; return app.exec(); diff --git a/tests/render-perf/src/main.cpp b/tests/render-perf/src/main.cpp index 9249b3d957..33aea6dcc9 100644 --- a/tests/render-perf/src/main.cpp +++ b/tests/render-perf/src/main.cpp @@ -34,6 +34,7 @@ #include #include +#include #include #include #include @@ -441,6 +442,10 @@ protected: viewOut = _viewFrustum; } + const ConicalViewFrustums& getConicalViews() const override { + return _view; + } + QThread* getMainThread() override { return QThread::currentThread(); } @@ -1116,6 +1121,7 @@ private: graphics::LightPointer _globalLight { std::make_shared() }; bool _ready { false }; EntitySimulationPointer _entitySimulation; + ConicalViewFrustums _view; QStringList _commands; QString _commandPath; diff --git a/tests/shared/src/AABoxTests.cpp b/tests/shared/src/AABoxTests.cpp index 2e9dfab497..865a82e86c 100644 --- a/tests/shared/src/AABoxTests.cpp +++ b/tests/shared/src/AABoxTests.cpp @@ -9,10 +9,10 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -#include - #include "AABoxTests.h" +#include + #include #include #include diff --git a/tests/shared/src/AACubeTests.cpp b/tests/shared/src/AACubeTests.cpp index 177daf89f1..4d684b4677 100644 --- a/tests/shared/src/AACubeTests.cpp +++ b/tests/shared/src/AACubeTests.cpp @@ -9,10 +9,10 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -#include - #include "AACubeTests.h" +#include + #include #include #include diff --git a/tests/shared/src/DualQuaternionTests.cpp b/tests/shared/src/DualQuaternionTests.cpp index fe14d9d166..276eb44f64 100644 --- a/tests/shared/src/DualQuaternionTests.cpp +++ b/tests/shared/src/DualQuaternionTests.cpp @@ -8,10 +8,10 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -#include - #include "DualQuaternionTests.h" +#include + #include #include #include diff --git a/tests/shared/src/GeometryUtilTests.cpp b/tests/shared/src/GeometryUtilTests.cpp index eb9be4987f..9b4f0f250f 100644 --- a/tests/shared/src/GeometryUtilTests.cpp +++ b/tests/shared/src/GeometryUtilTests.cpp @@ -9,10 +9,10 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -#include - #include "GeometryUtilTests.h" +#include + #include #include #include diff --git a/tools/ac-client/src/ACClientApp.cpp b/tools/ac-client/src/ACClientApp.cpp index 4711dc4102..cfede87c53 100644 --- a/tools/ac-client/src/ACClientApp.cpp +++ b/tools/ac-client/src/ACClientApp.cpp @@ -9,10 +9,13 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include "ACClientApp.h" + #include #include #include #include + #include #include #include @@ -20,8 +23,6 @@ #include #include -#include "ACClientApp.h" - ACClientApp::ACClientApp(int argc, char* argv[]) : QCoreApplication(argc, argv) { diff --git a/tools/atp-client/src/ATPClientApp.cpp b/tools/atp-client/src/ATPClientApp.cpp index 526065b2f7..c688ba9c82 100644 --- a/tools/atp-client/src/ATPClientApp.cpp +++ b/tools/atp-client/src/ATPClientApp.cpp @@ -9,6 +9,8 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include "ATPClientApp.h" + #include #include #include @@ -25,8 +27,6 @@ #include #include -#include "ATPClientApp.h" - #define HIGH_FIDELITY_ATP_CLIENT_USER_AGENT "Mozilla/5.0 (HighFidelityATPClient)" #define TIMEOUT_MILLISECONDS 8000 diff --git a/tools/auto-tester/src/Downloader.cpp b/tools/auto-tester/src/Downloader.cpp index 030aa95a19..530a3b61bd 100644 --- a/tools/auto-tester/src/Downloader.cpp +++ b/tools/auto-tester/src/Downloader.cpp @@ -9,6 +9,8 @@ // #include "Downloader.h" +#include + Downloader::Downloader(QUrl imageUrl, QObject *parent) : QObject(parent) { connect( &_networkAccessManager, SIGNAL (finished(QNetworkReply*)), @@ -20,6 +22,12 @@ Downloader::Downloader(QUrl imageUrl, QObject *parent) : QObject(parent) { } void Downloader::fileDownloaded(QNetworkReply* reply) { + QNetworkReply::NetworkError error = reply->error(); + if (error != QNetworkReply::NetworkError::NoError) { + QMessageBox::information(0, "Test Aborted", "Failed to download image: " + reply->errorString()); + return; + } + _downloadedData = reply->readAll(); //emit a signal diff --git a/tools/auto-tester/src/Test.cpp b/tools/auto-tester/src/Test.cpp index 99f9025fdd..0eec03a782 100644 --- a/tools/auto-tester/src/Test.cpp +++ b/tools/auto-tester/src/Test.cpp @@ -27,7 +27,7 @@ Test::Test() { mismatchWindow.setModal(true); } -bool Test::createTestResultsFolderPath(QString directory) { +bool Test::createTestResultsFolderPath(const QString& directory) { QDateTime now = QDateTime::currentDateTime(); testResultsFolderPath = directory + "/" + TEST_RESULTS_FOLDER + "--" + now.toString(DATETIME_FORMAT); QDir testResultsFolder(testResultsFolderPath); @@ -72,7 +72,7 @@ bool Test::compareImageLists(bool isInteractiveMode, QProgressBar* progressBar) QImage expectedImage(expectedImagesFullFilenames[i]); if (resultImage.width() != expectedImage.width() || resultImage.height() != expectedImage.height()) { - messageBox.critical(0, "Internal error: " + QString(__FILE__) + ":" + QString::number(__LINE__), "Images are not the same size"); + QMessageBox::critical(0, "Internal error: " + QString(__FILE__) + ":" + QString::number(__LINE__), "Images are not the same size"); exit(-1); } @@ -80,7 +80,7 @@ bool Test::compareImageLists(bool isInteractiveMode, QProgressBar* progressBar) try { similarityIndex = imageComparer.compareImages(resultImage, expectedImage); } catch (...) { - messageBox.critical(0, "Internal error: " + QString(__FILE__) + ":" + QString::number(__LINE__), "Image not in expected format"); + QMessageBox::critical(0, "Internal error: " + QString(__FILE__) + ":" + QString::number(__LINE__), "Image not in expected format"); exit(-1); } @@ -125,22 +125,22 @@ bool Test::compareImageLists(bool isInteractiveMode, QProgressBar* progressBar) return success; } -void Test::appendTestResultsToFile(QString testResultsFolderPath, TestFailure testFailure, QPixmap comparisonImage) { +void Test::appendTestResultsToFile(const QString& testResultsFolderPath, TestFailure testFailure, QPixmap comparisonImage) { if (!QDir().exists(testResultsFolderPath)) { - messageBox.critical(0, "Internal error: " + QString(__FILE__) + ":" + QString::number(__LINE__), "Folder " + testResultsFolderPath + " not found"); + QMessageBox::critical(0, "Internal error: " + QString(__FILE__) + ":" + QString::number(__LINE__), "Folder " + testResultsFolderPath + " not found"); exit(-1); } QString failureFolderPath { testResultsFolderPath + "/" + "Failure_" + QString::number(index) }; if (!QDir().mkdir(failureFolderPath)) { - messageBox.critical(0, "Internal error: " + QString(__FILE__) + ":" + QString::number(__LINE__), "Failed to create folder " + failureFolderPath); + QMessageBox::critical(0, "Internal error: " + QString(__FILE__) + ":" + QString::number(__LINE__), "Failed to create folder " + failureFolderPath); exit(-1); } ++index; QFile descriptionFile(failureFolderPath + "/" + TEST_RESULTS_FILENAME); if (!descriptionFile.open(QIODevice::ReadWrite)) { - messageBox.critical(0, "Internal error: " + QString(__FILE__) + ":" + QString::number(__LINE__), "Failed to create file " + TEST_RESULTS_FILENAME); + QMessageBox::critical(0, "Internal error: " + QString(__FILE__) + ":" + QString::number(__LINE__), "Failed to create file " + TEST_RESULTS_FILENAME); exit(-1); } @@ -160,24 +160,30 @@ void Test::appendTestResultsToFile(QString testResultsFolderPath, TestFailure te sourceFile = testFailure._pathname + testFailure._expectedImageFilename; destinationFile = failureFolderPath + "/" + "Expected Image.jpg"; if (!QFile::copy(sourceFile, destinationFile)) { - messageBox.critical(0, "Internal error: " + QString(__FILE__) + ":" + QString::number(__LINE__), "Failed to copy " + sourceFile + " to " + destinationFile); + QMessageBox::critical(0, "Internal error: " + QString(__FILE__) + ":" + QString::number(__LINE__), "Failed to copy " + sourceFile + " to " + destinationFile); exit(-1); } sourceFile = testFailure._pathname + testFailure._actualImageFilename; destinationFile = failureFolderPath + "/" + "Actual Image.jpg"; if (!QFile::copy(sourceFile, destinationFile)) { - messageBox.critical(0, "Internal error: " + QString(__FILE__) + ":" + QString::number(__LINE__), "Failed to copy " + sourceFile + " to " + destinationFile); + QMessageBox::critical(0, "Internal error: " + QString(__FILE__) + ":" + QString::number(__LINE__), "Failed to copy " + sourceFile + " to " + destinationFile); exit(-1); } comparisonImage.save(failureFolderPath + "/" + "Difference Image.jpg"); } -void Test::startTestsEvaluation() { - // Get list of JPEG images in folder, sorted by name - pathToTestResultsDirectory = QFileDialog::getExistingDirectory(nullptr, "Please select folder containing the test images", ".", QFileDialog::ShowDirsOnly); - if (pathToTestResultsDirectory == "") { +void Test::startTestsEvaluation(const QString& testFolder) { + QString pathToTestResultsDirectory; + if (testFolder.isNull()) { + // Get list of JPEG images in folder, sorted by name + pathToTestResultsDirectory = QFileDialog::getExistingDirectory(nullptr, "Please select folder containing the test images", ".", QFileDialog::ShowDirsOnly); + } else { + pathToTestResultsDirectory = testFolder; + } + + if (pathToTestResultsDirectory == QString()) { return; } @@ -221,8 +227,8 @@ void Test::startTestsEvaluation() { QString expectedImageFilenameTail = currentFilename.left(currentFilename.length() - 4).right(NUM_DIGITS); QString expectedImageStoredFilename = EXPECTED_IMAGE_PREFIX + expectedImageFilenameTail + ".png"; - QString imageURLString("https://github.com/" + githubUser + "/hifi_tests/blob/" + gitHubBranch + "/" + - expectedImagePartialSourceDirectory + "/" + expectedImageStoredFilename + "?raw=true"); + QString imageURLString("https://raw.githubusercontent.com/" + githubUser + "/hifi_tests/" + gitHubBranch + "/" + + expectedImagePartialSourceDirectory + "/" + expectedImageStoredFilename); expectedImagesURLs << imageURLString; @@ -237,19 +243,21 @@ void Test::startTestsEvaluation() { autoTester->downloadImages(expectedImagesURLs, pathToTestResultsDirectory, expectedImagesFilenames); } -void Test::finishTestsEvaluation(bool interactiveMode, QProgressBar* progressBar) { - bool success = compareImageLists(interactiveMode, progressBar); +void Test::finishTestsEvaluation(bool isRunningFromCommandline, bool interactiveMode, QProgressBar* progressBar) { + bool success = compareImageLists((!isRunningFromCommandline && interactiveMode), progressBar); - if (success) { - messageBox.information(0, "Success", "All images are as expected"); - } else { - messageBox.information(0, "Failure", "One or more images are not as expected"); + if (!isRunningFromCommandline) { + if (success) { + QMessageBox::information(0, "Success", "All images are as expected"); + } else { + QMessageBox::information(0, "Failure", "One or more images are not as expected"); + } } zipAndDeleteTestResultsFolder(); } -bool Test::isAValidDirectory(QString pathname) { +bool Test::isAValidDirectory(const QString& pathname) { // Only process directories QDir dir(pathname); if (!dir.exists()) { @@ -264,7 +272,7 @@ bool Test::isAValidDirectory(QString pathname) { return true; } -QString Test::extractPathFromTestsDown(QString fullPath) { +QString Test::extractPathFromTestsDown(const QString& fullPath) { // `fullPath` includes the full path to the test. We need the portion below (and including) `tests` QStringList pathParts = fullPath.split('/'); int i{ 0 }; @@ -273,7 +281,7 @@ QString Test::extractPathFromTestsDown(QString fullPath) { } if (i == pathParts.length()) { - messageBox.critical(0, "Internal error: " + QString(__FILE__) + ":" + QString::number(__LINE__), "Bad testPathname"); + QMessageBox::critical(0, "Internal error: " + QString(__FILE__) + ":" + QString::number(__LINE__), "Bad testPathname"); exit(-1); } @@ -342,14 +350,14 @@ void Test::createAllRecursiveScripts() { } } - messageBox.information(0, "Success", "Scripts have been created"); + QMessageBox::information(0, "Success", "Scripts have been created"); } -void Test::createRecursiveScript(QString topLevelDirectory, bool interactiveMode) { +void Test::createRecursiveScript(const QString& topLevelDirectory, bool interactiveMode) { const QString recursiveTestsFilename("testRecursive.js"); QFile allTestsFilename(topLevelDirectory + "/" + recursiveTestsFilename); if (!allTestsFilename.open(QIODevice::WriteOnly | QIODevice::Text)) { - messageBox.critical(0, + QMessageBox::critical(0, "Internal error: " + QString(__FILE__) + ":" + QString::number(__LINE__), "Failed to create \"" + recursiveTestsFilename + "\" in directory \"" + topLevelDirectory + "\"" ); @@ -358,12 +366,15 @@ void Test::createRecursiveScript(QString topLevelDirectory, bool interactiveMode } QTextStream textStream(&allTestsFilename); - textStream << "// This is an automatically generated file, created by auto-tester" << endl << endl; + + const QString DATE_TIME_FORMAT("MMM d yyyy, h:mm"); + textStream << "// This is an automatically generated file, created by auto-tester on " << QDateTime::currentDateTime().toString(DATE_TIME_FORMAT) << endl << endl; textStream << "var autoTester = Script.require(\"https://github.com/" + githubUser + "/hifi_tests/blob/" - + gitHubBranch + "/tests/utils/autoTester.js?raw=true\");" << endl; + + gitHubBranch + "/tests/utils/autoTester.js?raw=true\");" << endl << endl; - textStream << "autoTester.enableRecursive();" << endl << endl; + textStream << "autoTester.enableRecursive();" << endl; + textStream << "autoTester.enableAuto();" << endl << endl; QVector testPathnames; @@ -398,7 +409,7 @@ void Test::createRecursiveScript(QString topLevelDirectory, bool interactiveMode } if (interactiveMode && testPathnames.length() <= 0) { - messageBox.information(0, "Failure", "No \"" + TEST_FILENAME + "\" files found"); + QMessageBox::information(0, "Failure", "No \"" + TEST_FILENAME + "\" files found"); allTestsFilename.close(); return; } @@ -409,7 +420,7 @@ void Test::createRecursiveScript(QString topLevelDirectory, bool interactiveMode allTestsFilename.close(); if (interactiveMode) { - messageBox.information(0, "Success", "Script has been created"); + QMessageBox::information(0, "Success", "Script has been created"); } } @@ -434,7 +445,7 @@ void Test::createTest() { QString fullCurrentFilename = imageSourceDirectory + "/" + currentFilename; if (isInSnapshotFilenameFormat("jpg", currentFilename)) { if (i >= maxImages) { - messageBox.critical(0, "Error", "More than " + QString::number(maxImages) + " images not supported"); + QMessageBox::critical(0, "Error", "More than " + QString::number(maxImages) + " images not supported"); exit(-1); } QString newFilename = "ExpectedImage_" + QString::number(i - 1).rightJustified(5, '0') + ".png"; @@ -443,14 +454,14 @@ void Test::createTest() { try { copyJPGtoPNG(fullCurrentFilename, fullNewFileName); } catch (...) { - messageBox.critical(0, "Error", "Could not delete existing file: " + currentFilename + "\nTest creation aborted"); + QMessageBox::critical(0, "Error", "Could not delete existing file: " + currentFilename + "\nTest creation aborted"); exit(-1); } ++i; } } - messageBox.information(0, "Success", "Test images have been created"); + QMessageBox::information(0, "Success", "Test images have been created"); } ExtractedText Test::getTestScriptLines(QString testFileName) { @@ -459,7 +470,7 @@ ExtractedText Test::getTestScriptLines(QString testFileName) { QFile inputFile(testFileName); inputFile.open(QIODevice::ReadOnly); if (!inputFile.isOpen()) { - messageBox.critical(0, + QMessageBox::critical(0, "Internal error: " + QString(__FILE__) + ":" + QString::number(__LINE__), "Failed to open \"" + testFileName ); @@ -498,6 +509,12 @@ ExtractedText Test::getTestScriptLines(QString testFileName) { const QString regexAssertGPU(ws + functionAssertGPU + ws + "\\(" + ws + quotedString + ".*"); const QRegularExpression lineAssertGPU = QRegularExpression(regexAssertGPU); + // Assert the correct amount of memory + const QString functionAssertPhysicalMemoryGB(ws + "autoTester" + ws + "\\." + ws + "assertPhysicalMemoryGB"); + const QString regexAssertPhysicalMemoryGB(ws + functionAssertPhysicalMemoryGB + ws + "\\(" + ws + quotedString + ".*"); + const QRegularExpression lineAssertPhysicalMemoryGB = QRegularExpression(regexAssertPhysicalMemoryGB); + + // Each step is either of the following forms: // autoTester.addStepSnapshot("Take snapshot"... // autoTester.addStep("Clean up after test"... @@ -514,18 +531,7 @@ ExtractedText Test::getTestScriptLines(QString testFileName) { if (lineContainingTitle.match(line).hasMatch()) { QStringList tokens = line.split('"'); relevantTextFromTest.title = tokens[1]; - } else if (lineAssertPlatform.match(line).hasMatch()) { - QStringList platforms = line.split('"'); - relevantTextFromTest.platform = platforms[1]; - } else if (lineAssertDisplay.match(line).hasMatch()) { - QStringList displays = line.split('"'); - relevantTextFromTest.display = displays[1]; - } else if (lineAssertCPU.match(line).hasMatch()) { - QStringList cpus = line.split('"'); - relevantTextFromTest.cpu = cpus[1]; - } else if (lineAssertGPU.match(line).hasMatch()) { - QStringList gpus = line.split('"'); - relevantTextFromTest.gpu = gpus[1]; + } else if (lineStepSnapshot.match(line).hasMatch()) { QStringList tokens = line.split('"'); QString nameOfStep = tokens[1]; @@ -534,6 +540,7 @@ ExtractedText Test::getTestScriptLines(QString testFileName) { step->text = nameOfStep; step->takeSnapshot = true; relevantTextFromTest.stepList.emplace_back(step); + } else if (lineStep.match(line).hasMatch()) { QStringList tokens = line.split('"'); QString nameOfStep = tokens[1]; @@ -593,15 +600,15 @@ void Test::createAllMDFiles() { } } - messageBox.information(0, "Success", "MD files have been created"); + QMessageBox::information(0, "Success", "MD files have been created"); } -void Test::createMDFile(QString testDirectory) { +void Test::createMDFile(const QString& testDirectory) { // Verify folder contains test.js file QString testFileName(testDirectory + "/" + TEST_FILENAME); QFileInfo testFileInfo(testFileName); if (!testFileInfo.exists()) { - messageBox.critical(0, "Error", "Could not find file: " + TEST_FILENAME); + QMessageBox::critical(0, "Error", "Could not find file: " + TEST_FILENAME); return; } @@ -610,7 +617,7 @@ void Test::createMDFile(QString testDirectory) { QString mdFilename(testDirectory + "/" + "test.md"); QFile mdFile(mdFilename); if (!mdFile.open(QIODevice::WriteOnly)) { - messageBox.critical(0, "Internal error: " + QString(__FILE__) + ":" + QString::number(__LINE__), "Failed to create file " + mdFilename); + QMessageBox::critical(0, "Internal error: " + QString(__FILE__) + ":" + QString::number(__LINE__), "Failed to create file " + mdFilename); exit(-1); } @@ -628,64 +635,24 @@ void Test::createMDFile(QString testDirectory) { stream << "## Preconditions" << "\n"; stream << "- In an empty region of a domain with editing rights." << "\n\n"; - // Platform - QStringList platforms = testScriptLines.platform.split(" ");; - stream << "## Platforms\n"; - stream << "Run the test on each of the following platforms\n"; - for (int i = 0; i < platforms.size(); ++i) { - // Note that the platforms parameter may include extra spaces, these appear as empty strings in the list - if (platforms[i] != QString()) { - stream << " - " << platforms[i] << "\n"; - } - } - - // Display - QStringList displays = testScriptLines.display.split(" "); - stream << "## Displays\n"; - stream << "Run the test on each of the following displays\n"; - for (int i = 0; i < displays.size(); ++i) { - // Note that the displays parameter may include extra spaces, these appear as empty strings in the list - if (displays[i] != QString()) { - stream << " - " << displays[i] << "\n"; - } - } - - // CPU - QStringList cpus = testScriptLines.cpu.split(" "); - stream << "## Processors\n"; - stream << "Run the test on each of the following processors\n"; - for (int i = 0; i < cpus.size(); ++i) { - // Note that the cpus parameter may include extra spaces, these appear as empty strings in the list - if (cpus[i] != QString()) { - stream << " - " << cpus[i] << "\n"; - } - } - - // GPU - QStringList gpus = testScriptLines.gpu.split(" "); - stream << "## Graphics Cards\n"; - stream << "Run the test on graphics cards from each of the following vendors\n"; - for (int i = 0; i < gpus.size(); ++i) { - // Note that the gpus parameter may include extra spaces, these appear as empty strings in the list - if (gpus[i] != QString()) { - stream << " - " << gpus[i] << "\n"; - } - } - stream << "## Steps\n"; stream << "Press space bar to advance step by step\n\n"; + // Note that snapshots of step n are taken in step n+1 + // (this implies that if the LAST step requests a snapshot then this will not work - caveat emptor) int snapShotIndex { 0 }; for (size_t i = 0; i < testScriptLines.stepList.size(); ++i) { stream << "### Step " << QString::number(i + 1) << "\n"; stream << "- " << testScriptLines.stepList[i]->text << "\n"; - if (testScriptLines.stepList[i]->takeSnapshot) { + if ((i + 1 < testScriptLines.stepList.size()) && testScriptLines.stepList[i + 1]->takeSnapshot) { stream << "- ![](./ExpectedImage_" << QString::number(snapShotIndex).rightJustified(5, '0') << ".png)\n"; ++snapShotIndex; } } mdFile.close(); + + QMessageBox::information(0, "Success", "Test MD file " + mdFilename + " has been created"); } void Test::createTestsOutline() { @@ -698,7 +665,7 @@ void Test::createTestsOutline() { QString mdFilename(testsRootDirectory + "/" + testsOutlineFilename); QFile mdFile(mdFilename); if (!mdFile.open(QIODevice::WriteOnly)) { - messageBox.critical(0, "Internal error: " + QString(__FILE__) + ":" + QString::number(__LINE__), "Failed to create file " + mdFilename); + QMessageBox::critical(0, "Internal error: " + QString(__FILE__) + ":" + QString::number(__LINE__), "Failed to create file " + mdFilename); exit(-1); } @@ -756,10 +723,10 @@ void Test::createTestsOutline() { mdFile.close(); - messageBox.information(0, "Success", "Test outline file " + testsOutlineFilename + " has been created"); + QMessageBox::information(0, "Success", "Test outline file " + testsOutlineFilename + " has been created"); } -void Test::copyJPGtoPNG(QString sourceJPGFullFilename, QString destinationPNGFullFilename) { +void Test::copyJPGtoPNG(const QString& sourceJPGFullFilename, const QString& destinationPNGFullFilename) { QFile::remove(destinationPNGFullFilename); QImageReader reader; @@ -772,7 +739,7 @@ void Test::copyJPGtoPNG(QString sourceJPGFullFilename, QString destinationPNGFul writer.write(image); } -QStringList Test::createListOfAll_imagesInDirectory(QString imageFormat, QString pathToImageDirectory) { +QStringList Test::createListOfAll_imagesInDirectory(const QString& imageFormat, const QString& pathToImageDirectory) { imageDirectory = QDir(pathToImageDirectory); QStringList nameFilters; nameFilters << "*." + imageFormat; @@ -785,7 +752,7 @@ QStringList Test::createListOfAll_imagesInDirectory(QString imageFormat, QString // Filename (i.e. without extension) contains _tests_ (this is based on all test scripts being within the tests folder // Last 5 characters in filename are digits // Extension is jpg -bool Test::isInSnapshotFilenameFormat(QString imageFormat, QString filename) { +bool Test::isInSnapshotFilenameFormat(const QString& imageFormat, const QString& filename) { QStringList filenameParts = filename.split("."); bool filnameHasNoPeriods = (filenameParts.size() == 2); @@ -802,7 +769,7 @@ bool Test::isInSnapshotFilenameFormat(QString imageFormat, QString filename) { // For a file named "D_GitHub_hifi-tests_tests_content_entity_zone_create_0.jpg", the test directory is // D:/GitHub/hifi-tests/tests/content/entity/zone/create // This method assumes the filename is in the correct format -QString Test::getExpectedImageDestinationDirectory(QString filename) { +QString Test::getExpectedImageDestinationDirectory(const QString& filename) { QString filenameWithoutExtension = filename.split(".")[0]; QStringList filenameParts = filenameWithoutExtension.split("_"); @@ -819,7 +786,7 @@ QString Test::getExpectedImageDestinationDirectory(QString filename) { // is ...tests/content/entity/zone/create // This is used to create the full URL // This method assumes the filename is in the correct format -QString Test::getExpectedImagePartialSourceDirectory(QString filename) { +QString Test::getExpectedImagePartialSourceDirectory(const QString& filename) { QString filenameWithoutExtension = filename.split(".")[0]; QStringList filenameParts = filenameWithoutExtension.split("_"); @@ -831,7 +798,7 @@ QString Test::getExpectedImagePartialSourceDirectory(QString filename) { } if (i < 0) { - messageBox.critical(0, "Internal error: " + QString(__FILE__) + ":" + QString::number(__LINE__), "Bad filename"); + QMessageBox::critical(0, "Internal error: " + QString(__FILE__) + ":" + QString::number(__LINE__), "Bad filename"); exit(-1); } diff --git a/tools/auto-tester/src/Test.h b/tools/auto-tester/src/Test.h index e69459fef2..bc28d6ad0a 100644 --- a/tools/auto-tester/src/Test.h +++ b/tools/auto-tester/src/Test.h @@ -30,10 +30,6 @@ using StepList = std::vector; class ExtractedText { public: QString title; - QString platform; - QString display; - QString cpu; - QString gpu; StepList stepList; }; @@ -41,61 +37,58 @@ class Test { public: Test(); - void startTestsEvaluation(); - void finishTestsEvaluation(bool interactiveMode, QProgressBar* progressBar); + void startTestsEvaluation(const QString& testFolder = QString()); + void finishTestsEvaluation(bool isRunningFromCommandline, bool interactiveMode, QProgressBar* progressBar); void createRecursiveScript(); void createAllRecursiveScripts(); - void createRecursiveScript(QString topLevelDirectory, bool interactiveMode); + void createRecursiveScript(const QString& topLevelDirectory, bool interactiveMode); void createTest(); void createMDFile(); void createAllMDFiles(); - void createMDFile(QString topLevelDirectory); + void createMDFile(const QString& topLevelDirectory); void createTestsOutline(); bool compareImageLists(bool isInteractiveMode, QProgressBar* progressBar); - QStringList createListOfAll_imagesInDirectory(QString imageFormat, QString pathToImageDirectory); + QStringList createListOfAll_imagesInDirectory(const QString& imageFormat, const QString& pathToImageDirectory); - bool isInSnapshotFilenameFormat(QString imageFormat, QString filename); + bool isInSnapshotFilenameFormat(const QString& imageFormat, const QString& filename); void importTest(QTextStream& textStream, const QString& testPathname); - void appendTestResultsToFile(QString testResultsFolderPath, TestFailure testFailure, QPixmap comparisonImage); + void appendTestResultsToFile(const QString& testResultsFolderPath, TestFailure testFailure, QPixmap comparisonImage); - bool createTestResultsFolderPath(QString directory); + bool createTestResultsFolderPath(const QString& directory); void zipAndDeleteTestResultsFolder(); - bool isAValidDirectory(QString pathname); - QString extractPathFromTestsDown(QString fullPath); - QString getExpectedImageDestinationDirectory(QString filename); - QString getExpectedImagePartialSourceDirectory(QString filename); + bool isAValidDirectory(const QString& pathname); + QString extractPathFromTestsDown(const QString& fullPath); + QString getExpectedImageDestinationDirectory(const QString& filename); + QString getExpectedImagePartialSourceDirectory(const QString& filename); - void copyJPGtoPNG(QString sourceJPGFullFilename, QString destinationPNGFullFilename); + void copyJPGtoPNG(const QString& sourceJPGFullFilename, const QString& destinationPNGFullFilename); private: const QString TEST_FILENAME { "test.js" }; const QString TEST_RESULTS_FOLDER { "TestResults" }; const QString TEST_RESULTS_FILENAME { "TestResults.txt" }; - QMessageBox messageBox; - QDir imageDirectory; MismatchWindow mismatchWindow; ImageComparer imageComparer; - QString testResultsFolderPath { "" }; + QString testResultsFolderPath; int index { 1 }; // Expected images are in the format ExpectedImage_dddd.jpg (d == decimal digit) const int NUM_DIGITS { 5 }; const QString EXPECTED_IMAGE_PREFIX { "ExpectedImage_" }; - QString pathToTestResultsDirectory; QStringList expectedImagesFilenames; QStringList expectedImagesFullFilenames; QStringList resultImagesFullFilenames; diff --git a/tools/auto-tester/src/main.cpp b/tools/auto-tester/src/main.cpp index cd0ce22b13..ffa7a0b237 100644 --- a/tools/auto-tester/src/main.cpp +++ b/tools/auto-tester/src/main.cpp @@ -13,10 +13,23 @@ AutoTester* autoTester; int main(int argc, char *argv[]) { + // Only parameter is "--testFolder" + QString testFolder; + if (argc == 3) { + if (QString(argv[1]) == "--testFolder") { + testFolder = QString(argv[2]); + } + } + QApplication application(argc, argv); autoTester = new AutoTester(); - autoTester->show(); + + if (!testFolder.isNull()) { + autoTester->runFromCommandLine(testFolder); + } else { + autoTester->show(); + } return application.exec(); } diff --git a/tools/auto-tester/src/ui/AutoTester.cpp b/tools/auto-tester/src/ui/AutoTester.cpp index 21acfe9569..db9974a250 100644 --- a/tools/auto-tester/src/ui/AutoTester.cpp +++ b/tools/auto-tester/src/ui/AutoTester.cpp @@ -15,9 +15,17 @@ AutoTester::AutoTester(QWidget *parent) : QMainWindow(parent) { ui.checkBoxInteractiveMode->setChecked(true); ui.progressBar->setVisible(false); - test = new Test(); - signalMapper = new QSignalMapper(); + + connect(ui.actionClose, &QAction::triggered, this, &AutoTester::on_closeButton_clicked); + connect(ui.actionAbout, &QAction::triggered, this, &AutoTester::about); + + test = new Test(); +} + +void AutoTester::runFromCommandLine(const QString& testFolder) { + isRunningFromCommandline = true; + test->startTestsEvaluation(testFolder); } void AutoTester::on_evaluateTestsButton_clicked() { @@ -90,13 +98,21 @@ void AutoTester::saveImage(int index) { image = image.convertToFormat(QImage::Format_ARGB32); QString fullPathname = _directoryName + "/" + _filenames[index]; - image.save(fullPathname, 0, 100); + if (!image.save(fullPathname, 0, 100)) { + QMessageBox::information(0, "Test Aborted", "Failed to save image: " + _filenames[index]); + ui.progressBar->setVisible(false); + return; + } ++_numberOfImagesDownloaded; if (_numberOfImagesDownloaded == _numberOfImagesToDownload) { - test->finishTestsEvaluation(ui.checkBoxInteractiveMode->isChecked(), ui.progressBar); + test->finishTestsEvaluation(isRunningFromCommandline, ui.checkBoxInteractiveMode->isChecked(), ui.progressBar); } else { ui.progressBar->setValue(_numberOfImagesDownloaded); } } + +void AutoTester::about() { + QMessageBox::information(0, "About", QString("Built ") + __DATE__ + " : " + __TIME__); +} diff --git a/tools/auto-tester/src/ui/AutoTester.h b/tools/auto-tester/src/ui/AutoTester.h index 1788e97177..fe37f2298d 100644 --- a/tools/auto-tester/src/ui/AutoTester.h +++ b/tools/auto-tester/src/ui/AutoTester.h @@ -22,6 +22,9 @@ class AutoTester : public QMainWindow { public: AutoTester(QWidget *parent = Q_NULLPTR); + + void runFromCommandLine(const QString& testFolder); + void downloadImage(const QUrl& url); void downloadImages(const QStringList& URLs, const QString& directoryName, const QStringList& filenames); @@ -37,6 +40,8 @@ private slots: void saveImage(int index); + void about(); + private: Ui::AutoTesterClass ui; Test* test; @@ -50,9 +55,11 @@ private: // Used to enable passing a parameter to slots QSignalMapper* signalMapper; - int _numberOfImagesToDownload; - int _numberOfImagesDownloaded; - int _index; + int _numberOfImagesToDownload { 0 }; + int _numberOfImagesDownloaded { 0 }; + int _index { 0 }; + + bool isRunningFromCommandline { false }; }; #endif // hifi_AutoTester_h \ No newline at end of file diff --git a/tools/auto-tester/src/ui/AutoTester.ui b/tools/auto-tester/src/ui/AutoTester.ui index 2eb1314481..8c534eb7c7 100644 --- a/tools/auto-tester/src/ui/AutoTester.ui +++ b/tools/auto-tester/src/ui/AutoTester.ui @@ -95,7 +95,7 @@ 24 - + 360 @@ -157,6 +157,20 @@ 21 + + + File + + + + + + Help + + + + + @@ -167,6 +181,16 @@ + + + Close + + + + + About + + diff --git a/tools/ice-client/src/ICEClientApp.cpp b/tools/ice-client/src/ICEClientApp.cpp index f9e7a76142..0301fad6f4 100644 --- a/tools/ice-client/src/ICEClientApp.cpp +++ b/tools/ice-client/src/ICEClientApp.cpp @@ -9,15 +9,16 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include "ICEClientApp.h" + #include #include #include + #include #include #include -#include "ICEClientApp.h" - ICEClientApp::ICEClientApp(int argc, char* argv[]) : QCoreApplication(argc, argv) { diff --git a/tools/oven/src/BakerCLI.cpp b/tools/oven/src/BakerCLI.cpp index 35550cdca8..a7b8401269 100644 --- a/tools/oven/src/BakerCLI.cpp +++ b/tools/oven/src/BakerCLI.cpp @@ -9,6 +9,8 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include "BakerCLI.h" + #include #include #include @@ -16,7 +18,6 @@ #include "OvenCLIApplication.h" #include "ModelBakingLoggingCategory.h" -#include "BakerCLI.h" #include "FBXBaker.h" #include "JSBaker.h" #include "TextureBaker.h" diff --git a/tools/oven/src/DomainBaker.cpp b/tools/oven/src/DomainBaker.cpp index 3c6799db88..0a75c72f9a 100644 --- a/tools/oven/src/DomainBaker.cpp +++ b/tools/oven/src/DomainBaker.cpp @@ -464,7 +464,7 @@ bool DomainBaker::rewriteSkyboxURL(QJsonValueRef urlValue, TextureBaker* baker) if (oldSkyboxURL.matches(baker->getTextureURL(), QUrl::RemoveQuery | QUrl::RemoveFragment)) { // change the URL to point to the baked texture with its original query and fragment - auto newSkyboxURL = _destinationPath.resolved(baker->getBakedTextureFileName()); + auto newSkyboxURL = _destinationPath.resolved(baker->getMetaTextureFileName()); newSkyboxURL.setQuery(oldSkyboxURL.query()); newSkyboxURL.setFragment(oldSkyboxURL.fragment()); newSkyboxURL.setUserInfo(oldSkyboxURL.userInfo()); diff --git a/tools/oven/src/OvenCLIApplication.cpp b/tools/oven/src/OvenCLIApplication.cpp index 2fb8ea03f2..ab3178db01 100644 --- a/tools/oven/src/OvenCLIApplication.cpp +++ b/tools/oven/src/OvenCLIApplication.cpp @@ -9,13 +9,13 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include "OvenCLIApplication.h" + #include #include #include "BakerCLI.h" -#include "OvenCLIApplication.h" - static const QString CLI_INPUT_PARAMETER = "i"; static const QString CLI_OUTPUT_PARAMETER = "o"; static const QString CLI_TYPE_PARAMETER = "t"; diff --git a/tools/oven/src/ui/BakeWidget.cpp b/tools/oven/src/ui/BakeWidget.cpp index 43f4c50328..931ef1de43 100644 --- a/tools/oven/src/ui/BakeWidget.cpp +++ b/tools/oven/src/ui/BakeWidget.cpp @@ -9,12 +9,12 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include "BakeWidget.h" + #include #include "../OvenGUIApplication.h" -#include "BakeWidget.h" - BakeWidget::BakeWidget(QWidget* parent, Qt::WindowFlags flags) : QWidget(parent, flags) { diff --git a/tools/oven/src/ui/DomainBakeWidget.cpp b/tools/oven/src/ui/DomainBakeWidget.cpp index bf79319458..1121041e39 100644 --- a/tools/oven/src/ui/DomainBakeWidget.cpp +++ b/tools/oven/src/ui/DomainBakeWidget.cpp @@ -9,6 +9,8 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include "DomainBakeWidget.h" + #include #include @@ -23,8 +25,6 @@ #include "../OvenGUIApplication.h" -#include "DomainBakeWidget.h" - static const QString DOMAIN_NAME_SETTING_KEY = "domain_name"; static const QString EXPORT_DIR_SETTING_KEY = "domain_export_directory"; static const QString BROWSE_START_DIR_SETTING_KEY = "domain_search_directory"; diff --git a/tools/oven/src/ui/ModelBakeWidget.cpp b/tools/oven/src/ui/ModelBakeWidget.cpp index f80185df0f..9fa586871e 100644 --- a/tools/oven/src/ui/ModelBakeWidget.cpp +++ b/tools/oven/src/ui/ModelBakeWidget.cpp @@ -9,6 +9,8 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include "ModelBakeWidget.h" + #include #include #include @@ -26,7 +28,6 @@ #include "OvenMainWindow.h" #include "FBXBaker.h" #include "OBJBaker.h" -#include "ModelBakeWidget.h" static const auto EXPORT_DIR_SETTING_KEY = "model_export_directory"; diff --git a/tools/oven/src/ui/ModesWidget.cpp b/tools/oven/src/ui/ModesWidget.cpp index 624aa949cc..1fdfce2c97 100644 --- a/tools/oven/src/ui/ModesWidget.cpp +++ b/tools/oven/src/ui/ModesWidget.cpp @@ -9,6 +9,8 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include "ModesWidget.h" + #include #include #include @@ -17,8 +19,6 @@ #include "ModelBakeWidget.h" #include "SkyboxBakeWidget.h" -#include "ModesWidget.h" - ModesWidget::ModesWidget(QWidget* parent, Qt::WindowFlags flags) : QWidget(parent, flags) { diff --git a/tools/oven/src/ui/OvenMainWindow.cpp b/tools/oven/src/ui/OvenMainWindow.cpp index bebc2fa7dc..59cad3aac5 100644 --- a/tools/oven/src/ui/OvenMainWindow.cpp +++ b/tools/oven/src/ui/OvenMainWindow.cpp @@ -9,12 +9,12 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include "OvenMainWindow.h" + #include #include "ModesWidget.h" -#include "OvenMainWindow.h" - OvenMainWindow::OvenMainWindow(QWidget *parent, Qt::WindowFlags flags) : QMainWindow(parent, flags) { diff --git a/tools/oven/src/ui/ResultsWindow.cpp b/tools/oven/src/ui/ResultsWindow.cpp index 3a37a328de..feb7fbc4f1 100644 --- a/tools/oven/src/ui/ResultsWindow.cpp +++ b/tools/oven/src/ui/ResultsWindow.cpp @@ -9,6 +9,8 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include "ResultsWindow.h" + #include #include #include @@ -17,8 +19,6 @@ #include "OvenMainWindow.h" -#include "ResultsWindow.h" - ResultsWindow::ResultsWindow(QWidget* parent) : QWidget(parent) { diff --git a/tools/oven/src/ui/SkyboxBakeWidget.cpp b/tools/oven/src/ui/SkyboxBakeWidget.cpp index 369b06c39f..71ae0cbab0 100644 --- a/tools/oven/src/ui/SkyboxBakeWidget.cpp +++ b/tools/oven/src/ui/SkyboxBakeWidget.cpp @@ -9,6 +9,8 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include "SkyboxBakeWidget.h" + #include #include #include @@ -21,9 +23,9 @@ #include #include -#include "../OvenGUIApplication.h" +#include -#include "SkyboxBakeWidget.h" +#include "../OvenGUIApplication.h" static const auto EXPORT_DIR_SETTING_KEY = "skybox_export_directory"; static const auto SELECTION_START_DIR_SETTING_KEY = "skybox_search_directory"; diff --git a/tools/vhacd-util/src/VHACDUtilApp.cpp b/tools/vhacd-util/src/VHACDUtilApp.cpp index 4d48bdf2bf..c263dce609 100644 --- a/tools/vhacd-util/src/VHACDUtilApp.cpp +++ b/tools/vhacd-util/src/VHACDUtilApp.cpp @@ -9,10 +9,13 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include "VHACDUtilApp.h" + #include + #include #include -#include "VHACDUtilApp.h" + #include "VHACDUtil.h" #include "PathUtils.h"