diff --git a/.gitignore b/.gitignore index 5a965b494c..4c262f9f4a 100644 --- a/.gitignore +++ b/.gitignore @@ -24,6 +24,7 @@ android/**/bin android/**/src/main/res/values/libs.xml android/**/src/main/assets android/**/gradle* +*.class # VSCode # List taken from Github Global Ignores master@435c4d92 diff --git a/BUILD_QUEST.md b/BUILD_QUEST.md new file mode 100644 index 0000000000..e093969f83 --- /dev/null +++ b/BUILD_QUEST.md @@ -0,0 +1,65 @@ +Please read the [general build guide](BUILD.md) for information on building other platform. Only Quest specific instructions are found in this file. + +# Dependencies + +Building is currently supported on OSX, Windows and Linux platforms, but developers intending to do work on the library dependencies are strongly urged to use 64 bit Linux as a build platform + +You will need the following tools to build Android targets. + +* [Android Studio](https://developer.android.com/studio/index.html) + +### Android Studio + +Download the Android Studio installer and run it. Once installed, at the welcome screen, click configure in the lower right corner and select SDK manager + +From the SDK Platforms tab, select API levels 24 and 26. + +From the SDK Tools tab select the following + +* Android SDK Build-Tools +* GPU Debugging Tools +* CMake (even if you have a separate CMake installation) +* LLDB +* Android SDK Platform-Tools +* Android SDK Tools +* NDK (even if you have the NDK installed separately) + +Make sure the NDK installed version is 18 (or higher) + +# Environment + +Setting up the environment for android builds requires some additional steps + +#### Set up machine specific Gradle properties + +Create a `gradle.properties` file in $HOME/.gradle. Edit the file to contain the following + + HIFI_ANDROID_PRECOMPILED=/Android/hifi_externals + HIFI_ANDROID_KEYSTORE=/.jks + HIFI_ANDROID_KEYSTORE_PASSWORD= + HIFI_ANDROID_KEY_ALIAS= + HIFI_ANDROID_KEY_PASSWORD= + +Note, do not use `$HOME` for the path. It must be a fully qualified path name. + +### Setup the repository + +Clone the repository + +`git clone https://github.com/highfidelity/hifi.git` + +Enter the repository `android` directory + +`cd hifi/android` + +# Building & Running + +* Open Android Studio +* Choose _Open Existing Android Studio Project_ +* Navigate to the `hifi` repository and choose the `android` folder and select _OK_ +* Open Gradle.settings and comment out any projects not necessary +* From _File_ menu select _Sync with File System_ to resync Gradle settings +* From the _Build_ menu select _Make Project_ +* From +* Once the build completes, from the _Run_ menu select _Run App_ + diff --git a/CMakeLists.txt b/CMakeLists.txt index f88f8fbff7..1ba5e1264f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -101,6 +101,13 @@ if (ANDROID) add_definitions(-DCUSTOM_DISPLAY_PLUGINS) set(PLATFORM_PLUGIN_LIBRARIES oculusMobile oculusMobilePlugin) endif() + + # Allow client code to use preprocessor macros to distinguish between quest and non-quest builds + if (${HIFI_ANDROID_APP} STREQUAL "questInterface") + add_definitions(-DANDROID_APP_QUEST_INTERFACE) + elseif(${HIFI_ANDROID_APP} STREQUAL "interface") + add_definitions(-DANDROID_APP_INTERFACE) + endif() else () set(PLATFORM_QT_COMPONENTS WebEngine Xml) endif () diff --git a/android/apps/interface/src/main/java/io/highfidelity/hifiinterface/InterfaceActivity.java b/android/apps/interface/src/main/java/io/highfidelity/hifiinterface/InterfaceActivity.java index a7bda3c29b..3cdb9f5a09 100644 --- a/android/apps/interface/src/main/java/io/highfidelity/hifiinterface/InterfaceActivity.java +++ b/android/apps/interface/src/main/java/io/highfidelity/hifiinterface/InterfaceActivity.java @@ -81,6 +81,7 @@ public class InterfaceActivity extends QtActivity implements WebViewFragment.OnW private boolean nativeEnterBackgroundCallEnqueued = false; private SlidingDrawer mWebSlidingDrawer; private boolean mStartInDomain; + private boolean isLoading; // private GvrApi gvrApi; // Opaque native pointer to the Application C++ object. // This object is owned by the InterfaceActivity instance and passed to the native methods. @@ -94,7 +95,7 @@ public class InterfaceActivity extends QtActivity implements WebViewFragment.OnW @Override public void onCreate(Bundle savedInstanceState) { - super.isLoading = true; + isLoading = true; Intent intent = getIntent(); if (intent.hasExtra(DOMAIN_URL) && !TextUtils.isEmpty(intent.getStringExtra(DOMAIN_URL))) { intent.putExtra("applicationArguments", "--url " + intent.getStringExtra(DOMAIN_URL)); @@ -145,7 +146,7 @@ public class InterfaceActivity extends QtActivity implements WebViewFragment.OnW @Override protected void onPause() { super.onPause(); - if (super.isLoading) { + if (isLoading) { nativeEnterBackgroundCallEnqueued = true; } else { nativeEnterBackground(); @@ -172,7 +173,6 @@ public class InterfaceActivity extends QtActivity implements WebViewFragment.OnW super.onResume(); nativeEnterForeground(); surfacesWorkaround(); - keepInterfaceRunning = false; registerReceiver(headsetStateReceiver, new IntentFilter(Intent.ACTION_HEADSET_PLUG)); //gvrApi.resumeTracking(); } @@ -382,7 +382,7 @@ public class InterfaceActivity extends QtActivity implements WebViewFragment.OnW } public void onAppLoadedComplete() { - super.isLoading = false; + isLoading = false; if (nativeEnterBackgroundCallEnqueued) { nativeEnterBackground(); } @@ -413,7 +413,6 @@ public class InterfaceActivity extends QtActivity implements WebViewFragment.OnW @Override public void onExpand() { - keepInterfaceRunning = true; } @Override diff --git a/android/apps/questFramePlayer/CMakeLists.txt b/android/apps/questFramePlayer/CMakeLists.txt index 5889585a6c..ea60e27a7d 100644 --- a/android/apps/questFramePlayer/CMakeLists.txt +++ b/android/apps/questFramePlayer/CMakeLists.txt @@ -1,7 +1,7 @@ set(TARGET_NAME questFramePlayer) setup_hifi_library(AndroidExtras) link_hifi_libraries(shared ktx shaders gpu gl oculusMobile ${PLATFORM_GL_BACKEND}) -target_include_directories(${TARGET_NAME} PRIVATE ${HIFI_ANDROID_PRECOMPILED}/ovr/VrApi/Include) + target_link_libraries(${TARGET_NAME} android log m) target_opengl() target_oculus_mobile() diff --git a/android/apps/questFramePlayer/src/main/AndroidManifest.xml b/android/apps/questFramePlayer/src/main/AndroidManifest.xml index 721e8cee89..ba14b04532 100644 --- a/android/apps/questFramePlayer/src/main/AndroidManifest.xml +++ b/android/apps/questFramePlayer/src/main/AndroidManifest.xml @@ -19,24 +19,6 @@ android:name="org.qtproject.qt5.android.bindings.QtApplication" tools:ignore="GoogleAppIndexingWarning,MissingApplicationIcon"> - - - - - - - - - + + + + + + + diff --git a/android/apps/questFramePlayer/src/main/cpp/AndroidHelper.cpp b/android/apps/questFramePlayer/src/main/cpp/AndroidHelper.cpp new file mode 100644 index 0000000000..797040ab69 --- /dev/null +++ b/android/apps/questFramePlayer/src/main/cpp/AndroidHelper.cpp @@ -0,0 +1,30 @@ +// +// Created by Bradley Austin Davis on 2019/02/15 +// Copyright 2013-2019 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 +#include + +AndroidHelper::AndroidHelper() { +} + +AndroidHelper::~AndroidHelper() { +} + +void AndroidHelper::notifyLoadComplete() { + emit qtAppLoadComplete(); +} + +void AndroidHelper::notifyEnterForeground() { + emit enterForeground(); +} + +void AndroidHelper::notifyEnterBackground() { + emit enterBackground(); +} + diff --git a/android/apps/questFramePlayer/src/main/cpp/AndroidHelper.h b/android/apps/questFramePlayer/src/main/cpp/AndroidHelper.h new file mode 100644 index 0000000000..ef6722462c --- /dev/null +++ b/android/apps/questFramePlayer/src/main/cpp/AndroidHelper.h @@ -0,0 +1,43 @@ +// +// Created by Bradley Austin Davis on 2019/02/15 +// Copyright 2013-2019 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 +#include +#include +#include + +class AndroidHelper : public QObject { + Q_OBJECT +public: + AndroidHelper(AndroidHelper const&) = delete; + void operator=(AndroidHelper const&) = delete; + + static AndroidHelper& instance() { + static AndroidHelper instance; + return instance; + } + + void notifyLoadComplete(); + void notifyEnterForeground(); + void notifyEnterBackground(); + + +signals: + void qtAppLoadComplete(); + void enterForeground(); + void enterBackground(); + +private: + AndroidHelper(); + ~AndroidHelper(); +}; + +#endif diff --git a/android/apps/questFramePlayer/src/main/cpp/PlayerWindow.cpp b/android/apps/questFramePlayer/src/main/cpp/PlayerWindow.cpp index ec2986298e..8f78b1946a 100644 --- a/android/apps/questFramePlayer/src/main/cpp/PlayerWindow.cpp +++ b/android/apps/questFramePlayer/src/main/cpp/PlayerWindow.cpp @@ -11,15 +11,11 @@ #include PlayerWindow::PlayerWindow() { - installEventFilter(this); - setFlags(Qt::MSWindowsOwnDC | Qt::Window | Qt::Dialog | Qt::WindowMinMaxButtonsHint | Qt::WindowTitleHint); + setFlags(Qt::Window); setSurfaceType(QSurface::OpenGLSurface); create(); showFullScreen(); // Ensure the window is visible and the GL context is valid QCoreApplication::processEvents(); - _renderThread.initialize(this); -} - -PlayerWindow::~PlayerWindow() { + _renderThread.initialize(); } diff --git a/android/apps/questFramePlayer/src/main/cpp/PlayerWindow.h b/android/apps/questFramePlayer/src/main/cpp/PlayerWindow.h index e4dd6cef43..5e7dc82781 100644 --- a/android/apps/questFramePlayer/src/main/cpp/PlayerWindow.h +++ b/android/apps/questFramePlayer/src/main/cpp/PlayerWindow.h @@ -8,22 +8,13 @@ #pragma once #include -#include - -#include #include "RenderThread.h" -// Create a simple OpenGL window that renders text in various ways class PlayerWindow : public QWindow { public: PlayerWindow(); - virtual ~PlayerWindow(); - -protected: - //bool eventFilter(QObject* obj, QEvent* event) override; - //void keyPressEvent(QKeyEvent* event) override; + virtual ~PlayerWindow() {} private: - QSettings _settings; RenderThread _renderThread; }; diff --git a/android/apps/questFramePlayer/src/main/cpp/RenderThread.cpp b/android/apps/questFramePlayer/src/main/cpp/RenderThread.cpp index 5eabe6b9b1..78a4487284 100644 --- a/android/apps/questFramePlayer/src/main/cpp/RenderThread.cpp +++ b/android/apps/questFramePlayer/src/main/cpp/RenderThread.cpp @@ -16,6 +16,7 @@ #include #include #include +#include #include #include @@ -29,9 +30,7 @@ #include #include -static JNIEnv* _env { nullptr }; -static JavaVM* _vm { nullptr }; -static jobject _activity { nullptr }; +#include "AndroidHelper.h" struct HandController{ ovrInputTrackedRemoteCapabilities caps {}; @@ -48,21 +47,43 @@ struct HandController{ }; std::vector devices; +QAndroidJniObject __interfaceActivity; extern "C" { -JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *, void *) { +JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void *) { __android_log_write(ANDROID_LOG_WARN, "QQQ", __FUNCTION__); return JNI_VERSION_1_6; } +JNIEXPORT void JNICALL +Java_io_highfidelity_oculus_OculusMobileActivity_questNativeOnCreate(JNIEnv *env, jobject obj) { + __android_log_print(ANDROID_LOG_INFO, "QQQ", __FUNCTION__); + __interfaceActivity = QAndroidJniObject(obj); + QObject::connect(&AndroidHelper::instance(), &AndroidHelper::qtAppLoadComplete, []() { + __interfaceActivity.callMethod("onAppLoadedComplete", "()V"); + QObject::disconnect(&AndroidHelper::instance(), &AndroidHelper::qtAppLoadComplete, nullptr, nullptr); + }); +} -JNIEXPORT void JNICALL Java_io_highfidelity_frameplayer_QuestQtActivity_nativeOnCreate(JNIEnv* env, jobject obj) { - env->GetJavaVM(&_vm); - _activity = env->NewGlobalRef(obj); +JNIEXPORT void +Java_io_highfidelity_oculus_OculusMobileActivity_questOnAppAfterLoad(JNIEnv *env, jobject obj) { + AndroidHelper::instance().moveToThread(qApp->thread()); } + +JNIEXPORT void JNICALL +Java_io_highfidelity_oculus_OculusMobileActivity_questNativeOnPause(JNIEnv *env, jobject obj) { + AndroidHelper::instance().notifyEnterBackground(); } +JNIEXPORT void JNICALL +Java_io_highfidelity_oculus_OculusMobileActivity_questNativeOnResume(JNIEnv *env, jobject obj) { + AndroidHelper::instance().notifyEnterForeground(); +} + +} + + static const char* FRAME_FILE = "assets:/frames/20190121_1220.json"; static void textureLoader(const std::string& filename, const gpu::TexturePointer& texture, uint16_t layer) { @@ -84,11 +105,10 @@ void RenderThread::move(const glm::vec3& v) { _correction = glm::inverse(glm::translate(mat4(), v)) * _correction; } -void RenderThread::initialize(QWindow* window) { +void RenderThread::initialize() { std::unique_lock lock(_frameLock); setObjectName("RenderThread"); Parent::initialize(); - _window = window; _thread->setObjectName("RenderThread"); } @@ -96,14 +116,7 @@ void RenderThread::setup() { // Wait until the context has been moved to this thread { std::unique_lock lock(_frameLock); } - ovr::VrHandler::initVr(); - __android_log_write(ANDROID_LOG_WARN, "QQQ", "Launching oculus activity"); - _vm->AttachCurrentThread(&_env, nullptr); - jclass cls = _env->GetObjectClass(_activity); - jmethodID mid = _env->GetMethodID(cls, "launchOculusActivity", "()V"); - _env->CallVoidMethod(_activity, mid); - __android_log_write(ANDROID_LOG_WARN, "QQQ", "Launching oculus activity done"); ovr::VrHandler::setHandler(this); makeCurrent(); @@ -169,7 +182,6 @@ void RenderThread::handleInput() { const auto &remote = controller.state; if (remote.Joystick.x != 0.0f || remote.Joystick.y != 0.0f) { glm::vec3 translation; - float rotation = 0.0f; if (caps.ControllerCapabilities & ovrControllerCaps_LeftHand) { translation = glm::vec3{0.0f, -remote.Joystick.y, 0.0f}; } else { diff --git a/android/apps/questFramePlayer/src/main/cpp/RenderThread.h b/android/apps/questFramePlayer/src/main/cpp/RenderThread.h index 701cd25f5b..747d0d9e8d 100644 --- a/android/apps/questFramePlayer/src/main/cpp/RenderThread.h +++ b/android/apps/questFramePlayer/src/main/cpp/RenderThread.h @@ -20,11 +20,9 @@ class RenderThread : public GenericThread, ovr::VrHandler { using Parent = GenericThread; public: - QWindow* _window{ nullptr }; std::mutex _mutex; gpu::ContextPointer _gpuContext; // initialized during window creation std::shared_ptr _backend; - std::atomic _presentCount{ 0 }; std::mutex _frameLock; std::queue _pendingFrames; gpu::FramePointer _activeFrame; @@ -39,6 +37,6 @@ public: void handleInput(); void submitFrame(const gpu::FramePointer& frame); - void initialize(QWindow* window); + void initialize(); void renderFrame(); }; diff --git a/android/apps/questFramePlayer/src/main/cpp/main.cpp b/android/apps/questFramePlayer/src/main/cpp/main.cpp index 4730d3fa15..123ba904f4 100644 --- a/android/apps/questFramePlayer/src/main/cpp/main.cpp +++ b/android/apps/questFramePlayer/src/main/cpp/main.cpp @@ -11,30 +11,33 @@ #include #include #include +#include #include #include "PlayerWindow.h" +#include "AndroidHelper.h" + void messageHandler(QtMsgType type, const QMessageLogContext& context, const QString& message) { if (!message.isEmpty()) { - const char * local=message.toStdString().c_str(); + const char* local = message.toStdString().c_str(); switch (type) { case QtDebugMsg: - __android_log_write(ANDROID_LOG_DEBUG,"Interface",local); + __android_log_write(ANDROID_LOG_DEBUG, "Interface", local); break; case QtInfoMsg: - __android_log_write(ANDROID_LOG_INFO,"Interface",local); + __android_log_write(ANDROID_LOG_INFO, "Interface", local); break; case QtWarningMsg: - __android_log_write(ANDROID_LOG_WARN,"Interface",local); + __android_log_write(ANDROID_LOG_WARN, "Interface", local); break; case QtCriticalMsg: - __android_log_write(ANDROID_LOG_ERROR,"Interface",local); + __android_log_write(ANDROID_LOG_ERROR, "Interface", local); break; case QtFatalMsg: default: - __android_log_write(ANDROID_LOG_FATAL,"Interface",local); + __android_log_write(ANDROID_LOG_FATAL, "Interface", local); abort(); } } @@ -46,11 +49,13 @@ int main(int argc, char** argv) { auto oldMessageHandler = qInstallMessageHandler(messageHandler); DependencyManager::set(); PlayerWindow window; - __android_log_write(ANDROID_LOG_FATAL,"QQQ","Exec"); + QTimer::singleShot(10, []{ + __android_log_write(ANDROID_LOG_WARN, "QQQ", "notifyLoadComplete"); + AndroidHelper::instance().notifyLoadComplete(); + }); + __android_log_write(ANDROID_LOG_WARN, "QQQ", "Exec"); app.exec(); - __android_log_write(ANDROID_LOG_FATAL,"QQQ","Exec done"); + __android_log_write(ANDROID_LOG_WARN, "QQQ", "Exec done"); qInstallMessageHandler(oldMessageHandler); return 0; } - - diff --git a/android/apps/questFramePlayer/src/main/java/io/highfidelity/frameplayer/QuestQtActivity.java b/android/apps/questFramePlayer/src/main/java/io/highfidelity/frameplayer/QuestQtActivity.java deleted file mode 100644 index d498e27547..0000000000 --- a/android/apps/questFramePlayer/src/main/java/io/highfidelity/frameplayer/QuestQtActivity.java +++ /dev/null @@ -1,53 +0,0 @@ -// -// Created by Bradley Austin Davis on 2018/11/20 -// Copyright 2013-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 -// -package io.highfidelity.frameplayer; - -import android.content.Intent; -import android.os.Bundle; -import android.util.Log; - -import org.qtproject.qt5.android.bindings.QtActivity; - -import io.highfidelity.oculus.OculusMobileActivity; - - -public class QuestQtActivity extends QtActivity { - private native void nativeOnCreate(); - private boolean launchedQuestMode = false; - - @Override - public void onCreate(Bundle savedInstanceState) { - Log.w("QQQ_Qt", "QuestQtActivity::onCreate"); - super.onCreate(savedInstanceState); - nativeOnCreate(); - } - - @Override - public void onDestroy() { - Log.w("QQQ_Qt", "QuestQtActivity::onDestroy"); - super.onDestroy(); - } - - public void launchOculusActivity() { - Log.w("QQQ_Qt", "QuestQtActivity::launchOculusActivity"); - runOnUiThread(()->{ - keepInterfaceRunning = true; - launchedQuestMode = true; - moveTaskToBack(true); - startActivity(new Intent(this, QuestRenderActivity.class)); - }); - } - - @Override - public void onResume() { - super.onResume(); - if (launchedQuestMode) { - moveTaskToBack(true); - } - } -} diff --git a/android/apps/questFramePlayer/src/main/java/io/highfidelity/frameplayer/QuestRenderActivity.java b/android/apps/questFramePlayer/src/main/java/io/highfidelity/frameplayer/QuestRenderActivity.java index a395a32b68..9e7c0ab973 100644 --- a/android/apps/questFramePlayer/src/main/java/io/highfidelity/frameplayer/QuestRenderActivity.java +++ b/android/apps/questFramePlayer/src/main/java/io/highfidelity/frameplayer/QuestRenderActivity.java @@ -1,14 +1,6 @@ package io.highfidelity.frameplayer; -import android.content.Intent; -import android.os.Bundle; - import io.highfidelity.oculus.OculusMobileActivity; public class QuestRenderActivity extends OculusMobileActivity { - @Override - public void onCreate(Bundle savedState) { - super.onCreate(savedState); - startActivity(new Intent(this, QuestQtActivity.class)); - } } diff --git a/android/apps/questInterface/CMakeLists.txt b/android/apps/questInterface/CMakeLists.txt new file mode 100644 index 0000000000..97ca46f6e5 --- /dev/null +++ b/android/apps/questInterface/CMakeLists.txt @@ -0,0 +1,16 @@ +set(TARGET_NAME questInterface) +setup_hifi_library() +link_hifi_libraries( + shared task networking qml + image fbx hfm render-utils physics entities octree + oculusMobile oculusMobilePlugin + gl gpu ${PLATFORM_GL_BACKEND} +) +target_opengl() +target_bullet() +target_oculus_mobile() + +add_subdirectory("${CMAKE_SOURCE_DIR}/interface" "libraries/interface") +include_directories("${CMAKE_SOURCE_DIR}/interface/src") +add_subdirectory("${CMAKE_SOURCE_DIR}/plugins/hifiCodec" "libraries/hifiCodecPlugin") +target_link_libraries(questInterface android log m interface) diff --git a/android/apps/questInterface/build.gradle b/android/apps/questInterface/build.gradle new file mode 100644 index 0000000000..3d13877607 --- /dev/null +++ b/android/apps/questInterface/build.gradle @@ -0,0 +1,149 @@ +import org.apache.tools.ant.taskdefs.condition.Os +apply plugin: 'com.android.application' + +task renameHifiACTaskDebug() { + doLast { + def sourceFile = new File("${appDir}/build/intermediates/cmake/debug/obj/arm64-v8a/","libhifiCodec.so") + def destinationFile = new File("${appDir}/src/main/jniLibs/arm64-v8a", "libplugins_libhifiCodec.so") + copy { from sourceFile; into destinationFile.parent; rename(sourceFile.name, destinationFile.name) } + } +} +task renameHifiACTaskRelease(type: Copy) { + doLast { + def sourceFile = new File("${appDir}/build/intermediates/cmake/release/obj/arm64-v8a/","libhifiCodec.so") + def destinationFile = new File("${appDir}/src/main/jniLibs/arm64-v8a", "libplugins_libhifiCodec.so") + copy { from sourceFile; into destinationFile.parent; rename(sourceFile.name, destinationFile.name) } + } +} + +android { + compileSdkVersion 28 + + defaultConfig { + applicationId "io.highfidelity.questInterface" + minSdkVersion 24 + targetSdkVersion 28 + versionCode 1 + versionName appVersionName + ndk { abiFilters 'arm64-v8a' } + externalNativeBuild { + cmake { + arguments '-DHIFI_ANDROID=1', + '-DHIFI_ANDROID_APP=questInterface', + '-DANDROID_TOOLCHAIN=clang', + '-DANDROID_STL=c++_shared', + '-DCMAKE_VERBOSE_MAKEFILE=ON', + '-DRELEASE_NUMBER=' + RELEASE_NUMBER, + '-DRELEASE_TYPE=' + RELEASE_TYPE, + '-DSTABLE_BUILD=' + STABLE_BUILD, + '-DDISABLE_QML=OFF', + '-DDISABLE_KTX_CACHE=OFF', + '-DUSE_BREAKPAD=OFF' + targets = ['questInterface'] + } + } + signingConfigs { + release { + storeFile project.hasProperty("HIFI_ANDROID_KEYSTORE") ? file(HIFI_ANDROID_KEYSTORE) : null + storePassword project.hasProperty("HIFI_ANDROID_KEYSTORE_PASSWORD") ? HIFI_ANDROID_KEYSTORE_PASSWORD : '' + keyAlias project.hasProperty("HIFI_ANDROID_KEY_ALIAS") ? HIFI_ANDROID_KEY_ALIAS : '' + keyPassword project.hasProperty("HIFI_ANDROID_KEY_PASSWORD") ? HIFI_ANDROID_KEY_PASSWORD : '' + v2SigningEnabled false + } + } + } + + + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } + + buildTypes { + debug { + buildConfigField "String", "BACKTRACE_URL", "\"" + (System.getenv("CMAKE_BACKTRACE_URL") ? System.getenv("CMAKE_BACKTRACE_URL") : '') + "\"" + buildConfigField "String", "BACKTRACE_TOKEN", "\"" + (System.getenv("CMAKE_BACKTRACE_TOKEN") ? System.getenv("CMAKE_BACKTRACE_TOKEN") : '') + "\"" + buildConfigField "String", "OAUTH_CLIENT_ID", "\"" + (System.getenv("OAUTH_CLIENT_ID") ? System.getenv("OAUTH_CLIENT_ID") : '') + "\"" + buildConfigField "String", "OAUTH_CLIENT_SECRET", "\"" + (System.getenv("OAUTH_CLIENT_SECRET") ? System.getenv("OAUTH_CLIENT_SECRET") : '') + "\"" + buildConfigField "String", "OAUTH_REDIRECT_URI", "\"" + (System.getenv("OAUTH_REDIRECT_URI") ? System.getenv("OAUTH_REDIRECT_URI") : '') + "\"" + } + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + signingConfig signingConfigs.release + buildConfigField "String", "BACKTRACE_URL", "\"" + (System.getenv("CMAKE_BACKTRACE_URL") ? System.getenv("CMAKE_BACKTRACE_URL") : '') + "\"" + buildConfigField "String", "BACKTRACE_TOKEN", "\"" + (System.getenv("CMAKE_BACKTRACE_TOKEN") ? System.getenv("CMAKE_BACKTRACE_TOKEN") : '') + "\"" + buildConfigField "String", "OAUTH_CLIENT_ID", "\"" + (System.getenv("OAUTH_CLIENT_ID") ? System.getenv("OAUTH_CLIENT_ID") : '') + "\"" + buildConfigField "String", "OAUTH_CLIENT_SECRET", "\"" + (System.getenv("OAUTH_CLIENT_SECRET") ? System.getenv("OAUTH_CLIENT_SECRET") : '') + "\"" + buildConfigField "String", "OAUTH_REDIRECT_URI", "\"" + (System.getenv("OAUTH_REDIRECT_URI") ? System.getenv("OAUTH_REDIRECT_URI") : '') + "\"" + } + } + + externalNativeBuild { + cmake { + path '../../../CMakeLists.txt' + } + } + + applicationVariants.all { variant -> + // Our asset contents depend on items produced in the CMake build + // so our merge has to depend on the external native build + variant.externalNativeBuildTasks.each { task -> + variant.mergeResources.dependsOn(task) + if (Os.isFamily(Os.FAMILY_UNIX)) { + // FIXME + def uploadDumpSymsTask = rootProject.getTasksByName("uploadBreakpadDumpSyms${variant.name.capitalize()}", false).first() + def runDumpSymsTask = rootProject.getTasksByName("runBreakpadDumpSyms${variant.name.capitalize()}", false).first() + def renameHifiACTask = rootProject.getTasksByName("renameHifiACTask${variant.name.capitalize()}", false).first() + runDumpSymsTask.dependsOn(task) + variant.assemble.dependsOn(uploadDumpSymsTask) + variant.mergeResources.dependsOn(renameHifiACTask) + } + } + + variant.mergeAssets.doLast { + def assetList = new LinkedList() + def youngestLastModified = 0 + + // Copy the compiled resources generated by the external native build + copy { + from new File(projectDir, "../../../interface/compiledResources") + into outputDir + duplicatesStrategy DuplicatesStrategy.INCLUDE + eachFile { details -> + youngestLastModified = Math.max(youngestLastModified, details.lastModified) + assetList.add(details.path) + } + } + + // Copy the scripts directory + copy { + from new File(projectDir, "../../../scripts") + into new File(outputDir, "scripts") + duplicatesStrategy DuplicatesStrategy.INCLUDE + eachFile { details-> + youngestLastModified = Math.max(youngestLastModified, details.lastModified) + assetList.add("scripts/" + details.path) + } + } + + // Write a list of files to be unpacked to the cache folder + new File(outputDir, 'cache_assets.txt').withWriter { out -> + out.println(Long.toString(youngestLastModified)) + assetList.each { file -> out.println(file) } + } + } + + variant.outputs.all { + if (RELEASE_NUMBER != '0') { + outputFileName = "app_" + RELEASE_NUMBER + "_" + RELEASE_TYPE + ".apk" + } + } + } +} + +dependencies { + implementation fileTree(include: ['*.jar'], dir: '../../libraries/qt/libs') + implementation project(':oculus') + implementation project(':qt') +} diff --git a/android/apps/questInterface/proguard-rules.pro b/android/apps/questInterface/proguard-rules.pro new file mode 100644 index 0000000000..b3c0078513 --- /dev/null +++ b/android/apps/questInterface/proguard-rules.pro @@ -0,0 +1,25 @@ +# Add project specific ProGuard rules here. +# By default, the flags in this file are appended to flags specified +# in C:\Android\SDK/tools/proguard/proguard-android.txt +# You can edit the include path and order by changing the proguardFiles +# directive in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# Add any project specific keep options here: + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile diff --git a/android/apps/questInterface/src/main/AndroidManifest.xml b/android/apps/questInterface/src/main/AndroidManifest.xml new file mode 100644 index 0000000000..a5de47bdce --- /dev/null +++ b/android/apps/questInterface/src/main/AndroidManifest.xml @@ -0,0 +1,49 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/android/apps/questInterface/src/main/cpp/native.cpp b/android/apps/questInterface/src/main/cpp/native.cpp new file mode 100644 index 0000000000..3c1563c93d --- /dev/null +++ b/android/apps/questInterface/src/main/cpp/native.cpp @@ -0,0 +1,106 @@ +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + +#include +#include +#include + +#include +#include + +void initOculusPlatform(JNIEnv* env, jobject obj) { + static std::once_flag once; + std::call_once(once, [&]{ + // static const char* appID = "2343652845669354"; + // if (ovr_PlatformInitializeAndroid(appID, obj, env) != ovrPlatformInitialize_Success) { + // __android_log_write(ANDROID_LOG_WARN, "QQQ", "Failed to init platform SDK"); + // return; + // } + // ovr_Voip_SetSystemVoipSuppressed(true); + }); +} + +void getClassName(JNIEnv *env, jobject obj){ + jclass cls = env->GetObjectClass(obj); + jmethodID mid = env->GetMethodID(cls,"getClass", "()Ljava/lang/Class;"); + jobject clsObj = env->CallObjectMethod(obj, mid); + + cls= env->GetObjectClass(clsObj); + + mid= env->GetMethodID(cls, "getName", "()Ljava/lang/String;"); + + jstring strObj = (jstring) env->CallObjectMethod(clsObj, mid); + + const char* str = env->GetStringUTFChars(strObj, NULL); + + __android_log_print(ANDROID_LOG_ERROR,__FUNCTION__, "Native Class call: %s",str); + + env->ReleaseStringUTFChars(strObj, str); +} + + +extern "C" { + JNIEXPORT void JNICALL + Java_io_highfidelity_oculus_OculusMobileActivity_nativeInitOculusPlatform(JNIEnv *env, jobject obj){ + initOculusPlatform(env, obj); + } +QAndroidJniObject __interfaceActivity; + + JNIEXPORT void JNICALL + Java_io_highfidelity_oculus_OculusMobileActivity_questNativeOnCreate(JNIEnv *env, jobject obj) { + __android_log_print(ANDROID_LOG_INFO, "QQQ", __FUNCTION__); + initOculusPlatform(env, obj); + getClassName(env, obj); + + __interfaceActivity = QAndroidJniObject(obj); + + QObject::connect(&AndroidHelper::instance(), &AndroidHelper::qtAppLoadComplete, []() { + __interfaceActivity.callMethod("onAppLoadedComplete", "()V"); + + QObject::disconnect(&AndroidHelper::instance(), &AndroidHelper::qtAppLoadComplete, + nullptr, + nullptr); + }); + } + + + +JNIEXPORT void Java_io_highfidelity_oculus_OculusMobileActivity_questOnAppAfterLoad(JNIEnv* env, jobject obj) { + AndroidHelper::instance().moveToThread(qApp->thread()); +} + + JNIEXPORT void JNICALL + Java_io_highfidelity_oculus_OculusMobileActivity_questNativeOnPause(JNIEnv *env, jobject obj) { + AndroidHelper::instance().notifyEnterBackground(); + } + + JNIEXPORT void JNICALL + Java_io_highfidelity_oculus_OculusMobileActivity_questNativeOnResume(JNIEnv *env, jobject obj) { + AndroidHelper::instance().notifyEnterForeground(); + } + + JNIEXPORT void JNICALL + Java_io_highfidelity_questInterface_receiver_HeadsetStateReceiver_notifyHeadsetOn(JNIEnv *env, + jobject instance, + jboolean pluggedIn) { + AndroidHelper::instance().notifyHeadsetOn(pluggedIn); + } + +} diff --git a/android/apps/questInterface/src/main/java/io/highfidelity/questInterface/InterfaceActivity.java b/android/apps/questInterface/src/main/java/io/highfidelity/questInterface/InterfaceActivity.java new file mode 100644 index 0000000000..d55f97ad49 --- /dev/null +++ b/android/apps/questInterface/src/main/java/io/highfidelity/questInterface/InterfaceActivity.java @@ -0,0 +1,13 @@ +package io.highfidelity.questInterface; + +import android.os.Bundle; +import io.highfidelity.oculus.OculusMobileActivity; +import io.highfidelity.utils.HifiUtils; + +public class InterfaceActivity extends OculusMobileActivity { + @Override + public void onCreate(Bundle savedInstanceState) { + HifiUtils.upackAssets(getAssets(), getCacheDir().getAbsolutePath()); + super.onCreate(savedInstanceState); + } +} diff --git a/android/apps/questInterface/src/main/java/io/highfidelity/questInterface/PermissionsChecker.java b/android/apps/questInterface/src/main/java/io/highfidelity/questInterface/PermissionsChecker.java new file mode 100644 index 0000000000..154435fcaf --- /dev/null +++ b/android/apps/questInterface/src/main/java/io/highfidelity/questInterface/PermissionsChecker.java @@ -0,0 +1,68 @@ +package io.highfidelity.questInterface; + +import android.Manifest; +import android.app.Activity; +import android.content.Intent; +import android.content.pm.PackageManager; +import android.os.Bundle; + +import io.highfidelity.oculus.OculusMobileActivity; +import io.highfidelity.utils.HifiUtils; + +public class PermissionsChecker extends Activity { + private static final int REQUEST_PERMISSIONS = 20; + private static final String TAG = PermissionsChecker.class.getName(); + private static final String[] REQUIRED_PERMISSIONS = new String[]{ + Manifest.permission.READ_EXTERNAL_STORAGE, + Manifest.permission.WRITE_EXTERNAL_STORAGE, + Manifest.permission.RECORD_AUDIO, + Manifest.permission.CAMERA + }; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + requestAppPermissions(REQUIRED_PERMISSIONS,REQUEST_PERMISSIONS); + } + + public void requestAppPermissions(final String[] requestedPermissions, + final int requestCode) { + int permissionCheck = PackageManager.PERMISSION_GRANTED; + boolean shouldShowRequestPermissionRationale = false; + for (String permission : requestedPermissions) { + permissionCheck = permissionCheck + checkSelfPermission(permission); + shouldShowRequestPermissionRationale = shouldShowRequestPermissionRationale || shouldShowRequestPermissionRationale(permission); + } + if (permissionCheck != PackageManager.PERMISSION_GRANTED) { + System.out.println("Permission was not granted. Ask for permissions"); + if (shouldShowRequestPermissionRationale) { + requestPermissions(requestedPermissions, requestCode); + } else { + requestPermissions(requestedPermissions, requestCode); + } + } else { + System.out.println("Launching the other activity.."); + launchActivityWithPermissions(); + } + } + + private void launchActivityWithPermissions() { + startActivity(new Intent(this, InterfaceActivity.class)); + finish(); + } + + @Override + public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) { + super.onRequestPermissionsResult(requestCode, permissions, grantResults); + int permissionCheck = PackageManager.PERMISSION_GRANTED; + for (int permission : grantResults) { + permissionCheck = permissionCheck + permission; + } + if ((grantResults.length > 0) && permissionCheck == PackageManager.PERMISSION_GRANTED) { + launchActivityWithPermissions(); + } else if (grantResults.length > 0) { + System.out.println("User has deliberately denied Permissions. Launching anyways"); + launchActivityWithPermissions(); + } + } +} diff --git a/android/apps/questInterface/src/main/res/drawable/ic_launcher.xml b/android/apps/questInterface/src/main/res/drawable/ic_launcher.xml new file mode 100644 index 0000000000..03b1edc4e9 --- /dev/null +++ b/android/apps/questInterface/src/main/res/drawable/ic_launcher.xml @@ -0,0 +1,17 @@ + + + + + + + \ No newline at end of file diff --git a/android/apps/questInterface/src/main/res/values/strings.xml b/android/apps/questInterface/src/main/res/values/strings.xml new file mode 100644 index 0000000000..99e8d501ac --- /dev/null +++ b/android/apps/questInterface/src/main/res/values/strings.xml @@ -0,0 +1,3 @@ + + Interface + diff --git a/android/build.gradle b/android/build.gradle index ed2ca1c47e..5a4dbc0033 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -42,6 +42,8 @@ ext { RELEASE_TYPE = project.hasProperty('RELEASE_TYPE') ? project.getProperty('RELEASE_TYPE') : 'DEV' STABLE_BUILD = project.hasProperty('STABLE_BUILD') ? project.getProperty('STABLE_BUILD') : '0' EXEC_SUFFIX = Os.isFamily(Os.FAMILY_WINDOWS) ? '.exe' : '' + appVersionCode = Integer.valueOf(VERSION_CODE ?: 1) + appVersionName = RELEASE_NUMBER ?: "1.0" } def appDir = new File(projectDir, 'apps/interface') diff --git a/android/gradle.properties b/android/gradle.properties index ac639c5ae7..4236282c8b 100644 --- a/android/gradle.properties +++ b/android/gradle.properties @@ -1 +1,2 @@ org.gradle.jvmargs=-Xms2g -Xmx4g +android.debug.obsoleteApi=true diff --git a/android/gradle/wrapper/gradle-wrapper.properties b/android/gradle/wrapper/gradle-wrapper.properties index 36dba9b2f5..4c0f3c1035 100644 --- a/android/gradle/wrapper/gradle-wrapper.properties +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ -#Sat Dec 01 08:32:47 PST 2018 +#Wed Dec 19 13:46:46 PST 2018 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-4.6-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.1-all.zip diff --git a/android/libraries/oculus/build.gradle b/android/libraries/oculus/build.gradle index b072f99eb7..f31efcfe95 100644 --- a/android/libraries/oculus/build.gradle +++ b/android/libraries/oculus/build.gradle @@ -15,3 +15,7 @@ android { targetCompatibility JavaVersion.VERSION_1_8 } } + +dependencies { + implementation project(path: ':qt') +} diff --git a/android/libraries/oculus/src/main/java/io/highfidelity/oculus/OculusMobileActivity.java b/android/libraries/oculus/src/main/java/io/highfidelity/oculus/OculusMobileActivity.java index 01d74ea94d..9ab07bb4dd 100644 --- a/android/libraries/oculus/src/main/java/io/highfidelity/oculus/OculusMobileActivity.java +++ b/android/libraries/oculus/src/main/java/io/highfidelity/oculus/OculusMobileActivity.java @@ -7,62 +7,65 @@ // package io.highfidelity.oculus; -import android.app.Activity; -import android.content.Intent; import android.os.Bundle; import android.util.Log; import android.view.Surface; import android.view.SurfaceHolder; import android.view.SurfaceView; -import android.view.WindowManager; + +import org.qtproject.qt5.android.bindings.QtActivity; +import io.highfidelity.utils.HifiUtils; /** * Contains a native surface and forwards the activity lifecycle and surface lifecycle * events to the OculusMobileDisplayPlugin */ -public class OculusMobileActivity extends Activity implements SurfaceHolder.Callback { +public class OculusMobileActivity extends QtActivity implements SurfaceHolder.Callback { private static final String TAG = OculusMobileActivity.class.getSimpleName(); static { System.loadLibrary("oculusMobile"); } + private native void nativeOnCreate(); private native static void nativeOnResume(); private native static void nativeOnPause(); - private native static void nativeOnDestroy(); private native static void nativeOnSurfaceChanged(Surface s); + private native void questNativeOnCreate(); + private native void questNativeOnPause(); + private native void questNativeOnResume(); + private native void questOnAppAfterLoad(); + + private SurfaceView mView; private SurfaceHolder mSurfaceHolder; - - public static void launch(Activity activity) { - if (activity != null) { - activity.runOnUiThread(()->{ - activity.startActivity(new Intent(activity, OculusMobileActivity.class)); - }); - } - } - - @Override public void onCreate(Bundle savedInstanceState) { - Log.w(TAG, "QQQ onCreate"); super.onCreate(savedInstanceState); - getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); + + Log.w(TAG, "QQQ onCreate"); // Create a native surface for VR rendering (Qt GL surfaces are not suitable // because of the lack of fine control over the surface callbacks) + // Forward the create message to the JNI code mView = new SurfaceView(this); - setContentView(mView); mView.getHolder().addCallback(this); - // Forward the create message to the JNI code nativeOnCreate(); + questNativeOnCreate(); + } + public void onAppLoadedComplete() { + Log.w(TAG, "QQQ Load Completed"); + runOnUiThread(() -> { + setContentView(mView); + questOnAppAfterLoad(); + }); } @Override protected void onDestroy() { Log.w(TAG, "QQQ onDestroy"); - if (mSurfaceHolder != null) { - nativeOnSurfaceChanged(null); - } - nativeOnDestroy(); + + nativeOnSurfaceChanged(null); + + Log.w(TAG, "QQQ onDestroy -- SUPER onDestroy"); super.onDestroy(); } @@ -70,19 +73,38 @@ public class OculusMobileActivity extends Activity implements SurfaceHolder.Call protected void onResume() { Log.w(TAG, "QQQ onResume"); super.onResume(); + //Reconnect the global reference back to handler + nativeOnCreate(); + + questNativeOnResume(); nativeOnResume(); } @Override protected void onPause() { Log.w(TAG, "QQQ onPause"); - nativeOnPause(); super.onPause(); + + questNativeOnPause(); + nativeOnPause(); + } + + @Override + protected void onStop(){ + super.onStop(); + Log.w(TAG, "QQQ Onstop called"); + } + + @Override + protected void onRestart(){ + super.onRestart(); + Log.w(TAG, "QQQ onRestart called ****"); + questOnAppAfterLoad(); } @Override public void surfaceCreated(SurfaceHolder holder) { - Log.w(TAG, "QQQ surfaceCreated"); + Log.w(TAG, "QQQ surfaceCreated ************************************"); nativeOnSurfaceChanged(holder.getSurface()); mSurfaceHolder = holder; } @@ -96,8 +118,9 @@ public class OculusMobileActivity extends Activity implements SurfaceHolder.Call @Override public void surfaceDestroyed(SurfaceHolder holder) { - Log.w(TAG, "QQQ surfaceDestroyed"); + Log.w(TAG, "QQQ surfaceDestroyed ***************************************************"); nativeOnSurfaceChanged(null); mSurfaceHolder = null; + } } \ No newline at end of file diff --git a/android/libraries/qt/src/main/java/org/qtproject/qt5/android/bindings/QtActivity.java b/android/libraries/qt/src/main/java/org/qtproject/qt5/android/bindings/QtActivity.java index 6a6688ac41..46f2af46e7 100644 --- a/android/libraries/qt/src/main/java/org/qtproject/qt5/android/bindings/QtActivity.java +++ b/android/libraries/qt/src/main/java/org/qtproject/qt5/android/bindings/QtActivity.java @@ -70,9 +70,6 @@ public class QtActivity extends Activity { public final String QT_ANDROID_DEFAULT_THEME = QT_ANDROID_THEMES[0]; // sets the default theme. private QtActivityLoader m_loader = new QtActivityLoader(this); - public boolean isLoading; - public boolean keepInterfaceRunning; - public QtActivity() { } @@ -229,10 +226,13 @@ public class QtActivity extends Activity { //--------------------------------------------------------------------------- protected void onCreateHook(Bundle savedInstanceState) { + m_loader.APPLICATION_PARAMETERS = APPLICATION_PARAMETERS; m_loader.ENVIRONMENT_VARIABLES = ENVIRONMENT_VARIABLES; m_loader.QT_ANDROID_THEMES = QT_ANDROID_THEMES; m_loader.QT_ANDROID_DEFAULT_THEME = QT_ANDROID_DEFAULT_THEME; + + m_loader.onCreate(savedInstanceState); } @@ -364,7 +364,10 @@ public class QtActivity extends Activity { @Override protected void onDestroy() { super.onDestroy(); - QtApplication.invokeDelegate(); + + QtNative.terminateQt(); + QtNative.setActivity(null,null); + System.exit(0); } //--------------------------------------------------------------------------- @@ -506,9 +509,9 @@ public class QtActivity extends Activity { super.onPause(); // GC: this trick allow us to show a splash activity until Qt app finishes // loading - if (!isLoading && !keepInterfaceRunning) { - QtApplication.invokeDelegate(); - } + //QtApplication.invokeDelegate(); + + //TODO(Amer): looking into why this messes up pause. } //--------------------------------------------------------------------------- @@ -647,11 +650,7 @@ public class QtActivity extends Activity { @Override protected void onStop() { super.onStop(); - if (!keepInterfaceRunning) { - QtApplication.invokeDelegate(); - } - QtNative.terminateQt(); - QtNative.setActivity(null,null); + QtApplication.invokeDelegate(); } //--------------------------------------------------------------------------- diff --git a/android/settings.gradle b/android/settings.gradle index 699f617cce..c7b70cfde2 100644 --- a/android/settings.gradle +++ b/android/settings.gradle @@ -12,15 +12,26 @@ project(':qt').projectDir = new File(settingsDir, 'libraries/qt') // Applications // -include ':interface' -project(':interface').projectDir = new File(settingsDir, 'apps/interface') +if (!getSettings().hasProperty("SUPPRESS_INTERFACE")) { + include ':interface' + project(':interface').projectDir = new File(settingsDir, 'apps/interface') +} + +if (!getSettings().hasProperty("SUPPRESS_QUEST_INTERFACE")) { + include ':questInterface' + project(':questInterface').projectDir = new File(settingsDir, 'apps/questInterface') +} // // Test projects // -include ':framePlayer' -project(':framePlayer').projectDir = new File(settingsDir, 'apps/framePlayer') +if (!getSettings().hasProperty("SUPPRESS_FRAME_PLAYER")) { + include ':framePlayer' + project(':framePlayer').projectDir = new File(settingsDir, 'apps/framePlayer') +} -include ':questFramePlayer' -project(':questFramePlayer').projectDir = new File(settingsDir, 'apps/questFramePlayer') +if (!getSettings().hasProperty("SUPPRESS_QUEST_FRAME_PLAYER")) { + include ':questFramePlayer' + project(':questFramePlayer').projectDir = new File(settingsDir, 'apps/questFramePlayer') +} diff --git a/cmake/macros/AutoScribeShader.cmake b/cmake/macros/AutoScribeShader.cmake index 64fbcc4ea6..c5bb2b4054 100755 --- a/cmake/macros/AutoScribeShader.cmake +++ b/cmake/macros/AutoScribeShader.cmake @@ -270,6 +270,16 @@ macro(AUTOSCRIBE_SHADER_LIBS) set(AUTOSCRIBE_SHADERGEN_COMMANDS_FILE ${CMAKE_CURRENT_BINARY_DIR}/shadergen.txt) file(WRITE ${AUTOSCRIBE_SHADERGEN_COMMANDS_FILE} "${AUTOSCRIBE_SHADERGEN_COMMANDS}") + if (HIFI_ANDROID) + if ( + (${HIFI_ANDROID_APP} STREQUAL "questInterface") OR + (${HIFI_ANDROID_APP} STREQUAL "questFramePlayer") OR + (${HIFI_ANDROID_APP} STREQUAL "framePlayer") + ) + set(EXTRA_SHADERGEN_ARGS --extensions EXT_clip_cull_distance) + endif() + endif() + # A custom python script which will generate all our shader artifacts add_custom_command( OUTPUT ${SCRIBED_SHADERS} ${SPIRV_SHADERS} ${REFLECTED_SHADERS} @@ -279,6 +289,7 @@ macro(AUTOSCRIBE_SHADER_LIBS) --tools-dir ${VCPKG_TOOLS_DIR} --build-dir ${CMAKE_CURRENT_BINARY_DIR} --source-dir ${CMAKE_SOURCE_DIR} + ${EXTRA_SHADERGEN_ARGS} DEPENDS ${AUTOSCRIBE_SHADER_HEADERS} ${CMAKE_SOURCE_DIR}/tools/shadergen.py ${ALL_SCRIBE_SHADERS}) add_custom_target(shadergen DEPENDS ${SCRIBED_SHADERS} ${SPIRV_SHADERS} ${REFLECTED_SHADERS}) diff --git a/hifi_android.py b/hifi_android.py index 2e6a42d127..b8a606a82f 100644 --- a/hifi_android.py +++ b/hifi_android.py @@ -53,9 +53,9 @@ ANDROID_PACKAGES = { 'includeLibs': ['libvrapi.so'] }, 'oculusPlatform': { - 'file': 'OVRPlatformSDK_v1.32.0.zip', - 'versionId': 'jG9DB16zOGxSrmtZy4jcQnwO0TJUuaeL', - 'checksum': 'ab5b203b3a39a56ab148d68fff769e05', + 'file': 'OVRPlatformSDK_v1.34.0.zip', + 'versionId': 'vbRUkkyzUAXfTGSEtuiUr_7.Fm5h5BZk', + 'checksum': '16e4c5f39520f122bc49cb6d5bb88289', 'sharedLibFolder': 'Android/libs/arm64-v8a', 'includeLibs': ['libovrplatformloader.so'] }, diff --git a/interface/resources/controllers/touchscreenvirtualpad.json b/interface/resources/controllers/touchscreenvirtualpad.json index bae1172152..e98fb7ff2f 100644 --- a/interface/resources/controllers/touchscreenvirtualpad.json +++ b/interface/resources/controllers/touchscreenvirtualpad.json @@ -23,7 +23,9 @@ "invert" ], "to": "Actions.Pitch" - } + }, + + { "from": "TouchscreenVirtualPad.RB", "to": "Standard.RB"} ] } diff --git a/interface/resources/images/handshake.png b/interface/resources/images/handshake.png new file mode 100644 index 0000000000..ae4252e9e5 Binary files /dev/null and b/interface/resources/images/handshake.png differ diff --git a/interface/resources/qml/desktop/Desktop.qml b/interface/resources/qml/desktop/Desktop.qml index a1b89e1529..9a9252112c 100644 --- a/interface/resources/qml/desktop/Desktop.qml +++ b/interface/resources/qml/desktop/Desktop.qml @@ -425,11 +425,12 @@ FocusScope { console.warn("Could not find top level window for " + item); return; } - +/* if (typeof Controller === "undefined") { console.warn("Controller not yet available... can't center"); return; } +*/ var newRecommendedRectJS = (typeof Controller === "undefined") ? Qt.rect(0,0,0,0) : Controller.getRecommendedHUDRect(); var newRecommendedRect = Qt.rect(newRecommendedRectJS.x, newRecommendedRectJS.y, @@ -455,15 +456,17 @@ FocusScope { console.warn("Could not find top level window for " + item); return; } - +/* if (typeof Controller === "undefined") { console.warn("Controller not yet available... can't reposition targetWindow:" + targetWindow); return; } +*/ var oldRecommendedRect = recommendedRect; var oldRecommendedDimmensions = { x: oldRecommendedRect.width, y: oldRecommendedRect.height }; - var newRecommendedRect = Controller.getRecommendedHUDRect(); + var newRecommendedRect = { width: 1280, height: 720, x: 0, y: 0 }; + if (typeof Controller !== "undefined") newRecommendedRect = Controller.getRecommendedHUDRect(); var newRecommendedDimmensions = { x: newRecommendedRect.width, y: newRecommendedRect.height }; repositionWindow(targetWindow, false, oldRecommendedRect, oldRecommendedDimmensions, newRecommendedRect, newRecommendedDimmensions); } @@ -480,7 +483,8 @@ FocusScope { return; } - var recommended = Controller.getRecommendedHUDRect(); + var recommended = { width: 1280, height: 720, x: 0, y: 0 }; + if (typeof Controller !== "undefined") recommended = Controller.getRecommendedHUDRect(); var maxX = recommended.x + recommended.width; var maxY = recommended.y + recommended.height; var newPosition = Qt.vector2d(targetWindow.x, targetWindow.y); diff --git a/interface/resources/qml/hifi/Desktop.qml b/interface/resources/qml/hifi/Desktop.qml index c44ebdbab1..a97d94d91c 100644 --- a/interface/resources/qml/hifi/Desktop.qml +++ b/interface/resources/qml/hifi/Desktop.qml @@ -18,8 +18,8 @@ OriginalDesktop.Desktop { hoverEnabled: true propagateComposedEvents: true scrollGestureEnabled: false // we don't need/want these - onEntered: ApplicationCompositor.reticleOverDesktop = true - onExited: ApplicationCompositor.reticleOverDesktop = false + onEntered: if (typeof ApplicationCompositor !== "undefined") ApplicationCompositor.reticleOverDesktop = true + onExited: if (typeof ApplicationCompositor !== "undefined") ApplicationCompositor.reticleOverDesktop = false acceptedButtons: Qt.NoButton } diff --git a/interface/resources/qml/hifi/commerce/checkout/Checkout.qml b/interface/resources/qml/hifi/commerce/checkout/Checkout.qml index 2d5f77f006..9589c842e6 100644 --- a/interface/resources/qml/hifi/commerce/checkout/Checkout.qml +++ b/interface/resources/qml/hifi/commerce/checkout/Checkout.qml @@ -33,15 +33,19 @@ Rectangle { property bool balanceReceived: false; property bool availableUpdatesReceived: false; property bool itemInfoReceived: false; + property bool dataReady: itemInfoReceived && ownershipStatusReceived && balanceReceived && availableUpdatesReceived; property string baseItemName: ""; property string itemName; property string itemId; property string itemHref; property string itemAuthor; property int itemEdition: -1; + property bool hasSomethingToTradeIn: alreadyOwned && (itemEdition > 0); // i.e., don't trade in your artist's proof + property bool isTradingIn: isUpdating && hasSomethingToTradeIn; + property bool isStocking: availability === 'not for sale' && creator === Account.username; property string certificateId; property double balanceAfterPurchase; - property bool alreadyOwned: false; + property bool alreadyOwned: false; // Including proofs property int itemPrice: -1; property bool isCertified; property string itemType: "unknown"; @@ -56,6 +60,8 @@ Rectangle { property string referrer; property bool isInstalled; property bool isUpdating; + property string availability: "available"; + property string creator: ""; property string baseAppURL; property int currentUpdatesPage: 1; // Style @@ -434,7 +440,7 @@ Rectangle { anchors.top: parent.top; anchors.left: itemPreviewImage.right; anchors.leftMargin: 12; - anchors.right: itemPriceContainer.left; + anchors.right: parent.right; anchors.rightMargin: 8; height: 30; // Style @@ -449,21 +455,22 @@ Rectangle { Item { id: itemPriceContainer; // Anchors - anchors.top: parent.top; - anchors.right: parent.right; + anchors.top: itemNameText.bottom; + anchors.topMargin: 8; + anchors.left: itemNameText.left; height: 30; - width: itemPriceTextLabel.width + itemPriceText.width + 20; + width: itemPriceText.width + 20; - // "HFC" balance label + // "HFC" label HiFiGlyphs { id: itemPriceTextLabel; - visible: !(root.isUpdating && root.itemEdition > 0) && (root.itemPrice > 0); + visible: !isTradingIn && (root.itemPrice > 0); text: hifi.glyphs.hfc; // Size size: 30; // Anchors - anchors.right: itemPriceText.left; - anchors.rightMargin: 4; + anchors.right: parent.right; + //anchors.rightMargin: 4; anchors.top: parent.top; anchors.topMargin: 0; width: paintedWidth; @@ -473,13 +480,15 @@ Rectangle { } FiraSansSemiBold { id: itemPriceText; - text: (root.isUpdating && root.itemEdition > 0) ? "FREE\nUPDATE" : ((root.itemPrice === -1) ? "--" : ((root.itemPrice > 0) ? root.itemPrice : "FREE")); + text: isTradingIn ? "FREE\nUPDATE" : + (isStocking ? "Free for creator" : + ((root.itemPrice === -1) ? "--" : ((root.itemPrice > 0) ? root.itemPrice : "FREE"))); // Text size - size: (root.isUpdating && root.itemEdition > 0) ? 20 : 26; + size: isTradingIn ? 20 : 26; // Anchors anchors.top: parent.top; - anchors.right: parent.right; - anchors.rightMargin: 16; + anchors.left: itemPriceTextLabel.visible ? itemPriceTextLabel.right : parent.left; + anchors.leftMargin: 4; width: paintedWidth; height: paintedHeight; // Style @@ -571,7 +580,7 @@ Rectangle { // "View in Inventory" button HifiControlsUit.Button { id: viewInMyPurchasesButton; - visible: false; + visible: isCertified && dataReady && (isUpdating ? !hasSomethingToTradeIn : alreadyOwned); color: hifi.buttons.blue; colorScheme: hifi.colorSchemes.light; anchors.top: buyTextContainer.visible ? buyTextContainer.bottom : checkoutActionButtonsContainer.top; @@ -592,8 +601,8 @@ Rectangle { // "Buy" button HifiControlsUit.Button { id: buyButton; - visible: !((root.itemType === "avatar" || root.itemType === "app") && viewInMyPurchasesButton.visible) - enabled: (root.balanceAfterPurchase >= 0 && ownershipStatusReceived && balanceReceived && availableUpdatesReceived) || (!root.isCertified) || root.isUpdating; + visible: isTradingIn || !alreadyOwned || isStocking || !(root.itemType === "avatar" || root.itemType === "app"); + enabled: (root.balanceAfterPurchase >= 0 && dataReady) || (!root.isCertified) || root.isUpdating; color: viewInMyPurchasesButton.visible ? hifi.buttons.white : hifi.buttons.blue; colorScheme: hifi.colorSchemes.light; anchors.top: viewInMyPurchasesButton.visible ? viewInMyPurchasesButton.bottom : @@ -602,10 +611,15 @@ Rectangle { height: 50; anchors.left: parent.left; anchors.right: parent.right; - text: (root.isUpdating && root.itemEdition > 0) ? "CONFIRM UPDATE" : (((root.isCertified) ? ((ownershipStatusReceived && balanceReceived && availableUpdatesReceived) ? - ((viewInMyPurchasesButton.visible && !root.isUpdating) ? "Get It Again" : "Confirm") : "--") : "Get Item")); + text: isTradingIn ? + "CONFIRM UPDATE" : + (((root.isCertified) ? + (dataReady ? + ((viewInMyPurchasesButton.visible && !root.isUpdating) ? "Get It Again" : "Confirm") : + "--") : + "Get Item")); onClicked: { - if (root.isUpdating && root.itemEdition > 0) { + if (isTradingIn) { // If we're updating an app, the existing app needs to be uninstalled. // This call will fail/return `false` if the app isn't installed, but that's OK. if (root.itemType === "app") { @@ -1063,7 +1077,11 @@ Rectangle { buyButton.color = hifi.buttons.red; root.shouldBuyWithControlledFailure = true; } else { - buyButton.text = (root.isCertified ? ((ownershipStatusReceived && balanceReceived && availableUpdatesReceived) ? (root.alreadyOwned ? "Buy Another" : "Buy"): "--") : "Get Item"); + buyButton.text = (root.isCertified ? + (dataReady ? + (root.alreadyOwned ? "Buy Another" : "Buy") : + "--") : + "Get Item"); buyButton.color = hifi.buttons.blue; root.shouldBuyWithControlledFailure = false; } @@ -1091,6 +1109,8 @@ Rectangle { root.itemPrice = result.data.cost; root.itemAuthor = result.data.creator; root.itemType = result.data.item_type || "unknown"; + root.availability = result.data.availability; + root.creator = result.data.creator; if (root.itemType === "unknown") { root.itemHref = result.data.review_url; } else { @@ -1139,7 +1159,7 @@ Rectangle { signal sendToScript(var message); function canBuyAgain() { - return (root.itemType === "entity" || root.itemType === "wearable" || root.itemType === "contentSet" || root.itemType === "unknown"); + return root.itemType === "entity" || root.itemType === "wearable" || root.itemType === "contentSet" || root.itemType === "unknown" || isStocking; } function handleContentSets() { @@ -1185,29 +1205,23 @@ Rectangle { function refreshBuyUI() { if (root.isCertified) { - if (root.ownershipStatusReceived && root.balanceReceived && root.availableUpdatesReceived) { + if (dataReady) { buyText.text = ""; // If the user IS on the checkout page for the updated version of an owned item... if (root.isUpdating) { // If the user HAS already selected a specific edition to update... - if (root.itemEdition > 0) { + if (hasSomethingToTradeIn) { buyText.text = "By pressing \"Confirm Update\", you agree to trade in your old item for the updated item that replaces it."; buyTextContainer.color = "#FFFFFF"; buyTextContainer.border.color = "#FFFFFF"; // Else if the user HAS NOT selected a specific edition to update... } else { - viewInMyPurchasesButton.visible = true; - handleBuyAgainLogic(); } // If the user IS NOT on the checkout page for the updated verison of an owned item... // (i.e. they are checking out an item "normally") } else { - if (root.alreadyOwned) { - viewInMyPurchasesButton.visible = true; - } - handleBuyAgainLogic(); } } else { diff --git a/interface/resources/qml/hifi/commerce/marketplace/Marketplace.qml b/interface/resources/qml/hifi/commerce/marketplace/Marketplace.qml index cdb8368296..ca6838efea 100644 --- a/interface/resources/qml/hifi/commerce/marketplace/Marketplace.qml +++ b/interface/resources/qml/hifi/commerce/marketplace/Marketplace.qml @@ -121,7 +121,7 @@ Rectangle { marketplaceItem.description = result.data.description; marketplaceItem.attributions = result.data.attributions; marketplaceItem.license = result.data.license; - marketplaceItem.available = result.data.availability === "available"; + marketplaceItem.availability = result.data.availability; marketplaceItem.created_at = result.data.created_at; marketplaceItemScrollView.contentHeight = marketplaceItemContent.height; itemsList.visible = false; @@ -539,7 +539,7 @@ Rectangle { creator: model.creator category: model.primary_category price: model.cost - available: model.availability === "available" + availability: model.availability isLoggedIn: root.isLoggedIn; onShowItem: { @@ -711,7 +711,7 @@ Rectangle { topMargin: 10; leftMargin: 15; } - height: visible ? childrenRect.height : 0 + height: visible ? 36 : 0 RalewayRegular { id: sortText @@ -733,8 +733,9 @@ Rectangle { top: parent.top leftMargin: 20 } + width: root.isLoggedIn ? 342 : 262 - height: 36 + height: parent.height radius: 4 border.width: 1 diff --git a/interface/resources/qml/hifi/commerce/marketplace/MarketplaceItem.qml b/interface/resources/qml/hifi/commerce/marketplace/MarketplaceItem.qml index 2c7a50033c..97e5c10a6b 100644 --- a/interface/resources/qml/hifi/commerce/marketplace/MarketplaceItem.qml +++ b/interface/resources/qml/hifi/commerce/marketplace/MarketplaceItem.qml @@ -33,11 +33,11 @@ Rectangle { property string creator: "" property var categories: [] property int price: 0 + property string availability: "unknown" property var attributions: [] property string description: "" property string license: "" property string posted: "" - property bool available: false property string created_at: "" property bool isLoggedIn: false; property int edition: -1; @@ -264,9 +264,15 @@ Rectangle { } height: 50 - text: root.edition >= 0 ? "UPGRADE FOR FREE" : (root.available ? (root.price ? root.price : "FREE") : "UNAVAILABLE (not for sale)") - enabled: root.edition >= 0 || root.available - buttonGlyph: root.available ? (root.price ? hifi.glyphs.hfc : "") : "" + property bool isNFS: availability === "not for sale" // Note: server will say "sold out" or "invalidated" before it says NFS + property bool isMine: creator === Account.username + property bool isUpgrade: root.edition >= 0 + property int costToMe: ((isMine && isNFS) || isUpgrade) ? 0 : price + property bool isAvailable: costToMe >= 0 + + text: isUpgrade ? "UPGRADE FOR FREE" : (isAvailable ? (costToMe || "FREE") : availability) + enabled: isAvailable + buttonGlyph: isAvailable ? (costToMe ? hifi.glyphs.hfc : "") : "" color: hifi.buttons.blue onClicked: root.buy(); diff --git a/interface/resources/qml/hifi/commerce/marketplace/MarketplaceListItem.qml b/interface/resources/qml/hifi/commerce/marketplace/MarketplaceListItem.qml index 2f37637e40..587d71da28 100644 --- a/interface/resources/qml/hifi/commerce/marketplace/MarketplaceListItem.qml +++ b/interface/resources/qml/hifi/commerce/marketplace/MarketplaceListItem.qml @@ -34,7 +34,7 @@ Rectangle { property string creator: "" property string category: "" property int price: 0 - property bool available: false + property string availability: "unknown" property bool isLoggedIn: false; signal buy() @@ -299,8 +299,16 @@ Rectangle { bottomMargin: 10 } - text: root.price ? root.price : "FREE" - buttonGlyph: root.price ? hifi.glyphs.hfc : "" + property bool isNFS: availability === "not for sale" // Note: server will say "sold out" or "invalidated" before it says NFS + property bool isMine: creator === Account.username + property bool isUpgrade: root.edition >= 0 + property int costToMe: ((isMine && isNFS) || isUpgrade) ? 0 : price + property bool isAvailable: costToMe >= 0 + + text: isUpgrade ? "UPGRADE FOR FREE" : (isAvailable ? (costToMe || "FREE") : availability) + enabled: isAvailable + buttonGlyph: isAvailable ? (costToMe ? hifi.glyphs.hfc : "") : "" + color: hifi.buttons.blue; onClicked: root.buy(); diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index b65f39ffd7..a611738445 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -9,6 +9,7 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // + #include "Application.h" #include @@ -37,7 +38,6 @@ #include #include - #include #include #include @@ -51,6 +51,7 @@ #include #include + #include #include #include @@ -191,6 +192,9 @@ #include "scripting/WalletScriptingInterface.h" #include "scripting/TTSScriptingInterface.h" #include "scripting/KeyboardScriptingInterface.h" + + + #if defined(Q_OS_MAC) || defined(Q_OS_WIN) #include "SpeechRecognizer.h" #endif @@ -239,6 +243,7 @@ #include "webbrowser/WebBrowserSuggestionsEngine.h" #include + #include "AboutUtil.h" #if defined(Q_OS_WIN) @@ -622,8 +627,6 @@ public: switch (type) { case NestableType::Entity: return getEntityModelProvider(static_cast(uuid)); - case NestableType::Overlay: - return nullptr; case NestableType::Avatar: return getAvatarModelProvider(uuid); } @@ -1747,7 +1750,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo }); _applicationStateDevice->setInputVariant(STATE_PLATFORM_ANDROID, []() -> float { #if defined(Q_OS_ANDROID) - return 1; + return 1 ; #else return 0; #endif @@ -1850,6 +1853,8 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo this->installEventFilter(this); + + #ifdef HAVE_DDE auto ddeTracker = DependencyManager::get(); ddeTracker->init(); @@ -1911,46 +1916,34 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo } }, Qt::QueuedConnection); - EntityTree::setAddMaterialToEntityOperator([this](const QUuid& entityID, graphics::MaterialLayer material, const std::string& parentMaterialName) { + EntityTreeRenderer::setAddMaterialToEntityOperator([this](const QUuid& entityID, graphics::MaterialLayer material, const std::string& parentMaterialName) { if (_aboutToQuit) { return false; } - // try to find the renderable auto renderable = getEntities()->renderableForEntityId(entityID); if (renderable) { renderable->addMaterial(material, parentMaterialName); - } - - // even if we don't find it, try to find the entity - auto entity = getEntities()->getEntity(entityID); - if (entity) { - entity->addMaterial(material, parentMaterialName); return true; } + return false; }); - EntityTree::setRemoveMaterialFromEntityOperator([this](const QUuid& entityID, graphics::MaterialPointer material, const std::string& parentMaterialName) { + EntityTreeRenderer::setRemoveMaterialFromEntityOperator([this](const QUuid& entityID, graphics::MaterialPointer material, const std::string& parentMaterialName) { if (_aboutToQuit) { return false; } - // try to find the renderable auto renderable = getEntities()->renderableForEntityId(entityID); if (renderable) { renderable->removeMaterial(material, parentMaterialName); - } - - // even if we don't find it, try to find the entity - auto entity = getEntities()->getEntity(entityID); - if (entity) { - entity->removeMaterial(material, parentMaterialName); return true; } + return false; }); - EntityTree::setAddMaterialToAvatarOperator([](const QUuid& avatarID, graphics::MaterialLayer material, const std::string& parentMaterialName) { + EntityTreeRenderer::setAddMaterialToAvatarOperator([](const QUuid& avatarID, graphics::MaterialLayer material, const std::string& parentMaterialName) { auto avatarManager = DependencyManager::get(); auto avatar = avatarManager->getAvatarBySessionID(avatarID); if (avatar) { @@ -1959,7 +1952,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo } return false; }); - EntityTree::setRemoveMaterialFromAvatarOperator([](const QUuid& avatarID, graphics::MaterialPointer material, const std::string& parentMaterialName) { + EntityTreeRenderer::setRemoveMaterialFromAvatarOperator([](const QUuid& avatarID, graphics::MaterialPointer material, const std::string& parentMaterialName) { auto avatarManager = DependencyManager::get(); auto avatar = avatarManager->getAvatarBySessionID(avatarID); if (avatar) { @@ -2282,7 +2275,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo // Setup the mouse ray pick and related operators { - auto mouseRayPick = std::make_shared(Vectors::ZERO, Vectors::UP, PickFilter(PickScriptingInterface::PICK_ENTITIES()), 0.0f, true); + auto mouseRayPick = std::make_shared(Vectors::ZERO, Vectors::UP, PickFilter(PickScriptingInterface::PICK_ENTITIES() | PickScriptingInterface::PICK_LOCAL_ENTITIES()), 0.0f, true); mouseRayPick->parentTransform = std::make_shared(); mouseRayPick->setJointState(PickQuery::JOINT_STATE_MOUSE); auto mouseRayPickID = DependencyManager::get()->addPick(PickQuery::Ray, mouseRayPick); @@ -3099,7 +3092,7 @@ void Application::initializeUi() { } if (TouchscreenVirtualPadDevice::NAME == inputPlugin->getName()) { _touchscreenVirtualPadDevice = std::dynamic_pointer_cast(inputPlugin); -#if defined(Q_OS_ANDROID) +#if defined(ANDROID_APP_INTERFACE) auto& virtualPadManager = VirtualPad::Manager::instance(); connect(&virtualPadManager, &VirtualPad::Manager::hapticFeedbackRequested, this, [](int duration) { @@ -3631,10 +3624,14 @@ void Application::handleSandboxStatus(QNetworkReply* reply) { } // Get controller availability +#ifdef ANDROID_APP_QUEST_INTERFACE + bool hasHandControllers = true; +#else bool hasHandControllers = false; if (PluginUtils::isViveControllerAvailable() || PluginUtils::isOculusTouchControllerAvailable()) { hasHandControllers = true; } +#endif // Check HMD use (may be technically available without being in use) bool hasHMD = PluginUtils::isHMDAvailable(); @@ -8251,6 +8248,7 @@ void Application::loadDomainConnectionDialog() { } void Application::toggleLogDialog() { +#ifndef ANDROID_APP_QUEST_INTERFACE if (getLoginDialogPoppedUp()) { return; } @@ -8274,6 +8272,7 @@ void Application::toggleLogDialog() { } else { _logDialog->show(); } +#endif } void Application::recreateLogWindow(int keepOnTop) { @@ -9139,17 +9138,23 @@ void Application::beforeEnterBackground() { void Application::enterBackground() { QMetaObject::invokeMethod(DependencyManager::get().data(), "stop", Qt::BlockingQueuedConnection); +// Quest only supports one plugin which can't be deactivated currently +#if !defined(ANDROID_APP_QUEST_INTERFACE) if (getActiveDisplayPlugin()->isActive()) { getActiveDisplayPlugin()->deactivate(); } +#endif } void Application::enterForeground() { QMetaObject::invokeMethod(DependencyManager::get().data(), "start", Qt::BlockingQueuedConnection); +// Quest only supports one plugin which can't be deactivated currently +#if !defined(ANDROID_APP_QUEST_INTERFACE) if (!getActiveDisplayPlugin() || getActiveDisplayPlugin()->isActive() || !getActiveDisplayPlugin()->activate()) { qWarning() << "Could not re-activate display plugin"; } +#endif auto nodeList = DependencyManager::get(); nodeList->setSendDomainServerCheckInEnabled(true); } diff --git a/interface/src/raypick/PickScriptingInterface.cpp b/interface/src/raypick/PickScriptingInterface.cpp index ce01db3a56..09f4b68cb9 100644 --- a/interface/src/raypick/PickScriptingInterface.cpp +++ b/interface/src/raypick/PickScriptingInterface.cpp @@ -71,6 +71,18 @@ PickFilter getPickFilter(unsigned int filter) { unsigned int PickScriptingInterface::createRayPick(const QVariant& properties) { QVariantMap propMap = properties.toMap(); + +#if defined (Q_OS_ANDROID) + QString jointName { "" }; + if (propMap["joint"].isValid()) { + QString jointName = propMap["joint"].toString(); + const QString MOUSE_JOINT = "Mouse"; + if (jointName == MOUSE_JOINT) { + return PointerEvent::INVALID_POINTER_ID; + } + } +#endif + bool enabled = false; if (propMap["enabled"].isValid()) { enabled = propMap["enabled"].toBool(); diff --git a/interface/src/raypick/PointerScriptingInterface.cpp b/interface/src/raypick/PointerScriptingInterface.cpp index 19c20f0c06..1c80caff88 100644 --- a/interface/src/raypick/PointerScriptingInterface.cpp +++ b/interface/src/raypick/PointerScriptingInterface.cpp @@ -150,6 +150,17 @@ unsigned int PointerScriptingInterface::createStylus(const QVariant& properties) unsigned int PointerScriptingInterface::createLaserPointer(const QVariant& properties) const { QVariantMap propertyMap = properties.toMap(); +#if defined (Q_OS_ANDROID) + QString jointName { "" }; + if (propertyMap["joint"].isValid()) { + QString jointName = propertyMap["joint"].toString(); + const QString MOUSE_JOINT = "Mouse"; + if (jointName == MOUSE_JOINT) { + return PointerEvent::INVALID_POINTER_ID; + } + } +#endif + bool faceAvatar = false; if (propertyMap["faceAvatar"].isValid()) { faceAvatar = propertyMap["faceAvatar"].toBool(); diff --git a/interface/src/raypick/RayPick.h b/interface/src/raypick/RayPick.h index a781795e55..7625146408 100644 --- a/interface/src/raypick/RayPick.h +++ b/interface/src/raypick/RayPick.h @@ -85,9 +85,10 @@ public: static glm::vec3 intersectRayWithEntityXYPlane(const QUuid& entityID, const glm::vec3& origin, const glm::vec3& direction); static glm::vec2 projectOntoEntityXYPlane(const QUuid& entityID, const glm::vec3& worldPos, bool unNormalized = true); + static glm::vec2 projectOntoXYPlane(const glm::vec3& worldPos, const glm::vec3& position, const glm::quat& rotation, const glm::vec3& dimensions, const glm::vec3& registrationPoint, bool unNormalized); + private: static glm::vec3 intersectRayWithXYPlane(const glm::vec3& origin, const glm::vec3& direction, const glm::vec3& point, const glm::quat& rotation, const glm::vec3& registration); - static glm::vec2 projectOntoXYPlane(const glm::vec3& worldPos, const glm::vec3& position, const glm::quat& rotation, const glm::vec3& dimensions, const glm::vec3& registrationPoint, bool unNormalized); }; #endif // hifi_RayPick_h diff --git a/interface/src/raypick/StylusPick.cpp b/interface/src/raypick/StylusPick.cpp index 0e95959566..cf19b68a45 100644 --- a/interface/src/raypick/StylusPick.cpp +++ b/interface/src/raypick/StylusPick.cpp @@ -137,13 +137,14 @@ PickResultPointer StylusPick::getDefaultResult(const QVariantMap& pickVariant) c } PickResultPointer StylusPick::getEntityIntersection(const StylusTip& pick) { - std::vector results; + auto entityTree = qApp->getEntities()->getTree(); + StylusPickResult nearestTarget(pick.toVariantMap()); for (const auto& target : getIncludeItems()) { if (target.isNull()) { continue; } - auto entity = qApp->getEntities()->getTree()->findEntityByEntityItemID(target); + auto entity = entityTree->findEntityByEntityItemID(target); if (!entity) { continue; } @@ -157,28 +158,24 @@ PickResultPointer StylusPick::getEntityIntersection(const StylusTip& pick) { glm::vec3 normal = entityRotation * Vectors::UNIT_Z; float distance = glm::dot(pick.position - entityPosition, normal); - glm::vec3 intersection = pick.position - (normal * distance); - - glm::vec2 pos2D = RayPick::projectOntoEntityXYPlane(target, intersection, false); - if (pos2D == glm::clamp(pos2D, glm::vec2(0), glm::vec2(1))) { - IntersectionType type = IntersectionType::ENTITY; - if (getFilter().doesPickLocalEntities()) { - EntityPropertyFlags desiredProperties; - desiredProperties += PROP_ENTITY_HOST_TYPE; - if (DependencyManager::get()->getEntityProperties(target, desiredProperties).getEntityHostType() == entity::HostType::LOCAL) { - type = IntersectionType::LOCAL_ENTITY; + if (distance < nearestTarget.distance) { + const auto entityDimensions = entity->getScaledDimensions(); + const auto entityRegistrationPoint = entity->getRegistrationPoint(); + glm::vec3 intersection = pick.position - (normal * distance); + glm::vec2 pos2D = RayPick::projectOntoXYPlane(intersection, entityPosition, entityRotation, + entityDimensions, entityRegistrationPoint, false); + if (pos2D == glm::clamp(pos2D, glm::vec2(0), glm::vec2(1))) { + IntersectionType type = IntersectionType::ENTITY; + if (getFilter().doesPickLocalEntities()) { + if (entity->getEntityHostType() == entity::HostType::LOCAL) { + type = IntersectionType::LOCAL_ENTITY; + } } + nearestTarget = StylusPickResult(type, target, distance, intersection, pick, normal); } - results.push_back(StylusPickResult(type, target, distance, intersection, pick, normal)); } } - StylusPickResult nearestTarget(pick.toVariantMap()); - for (const auto& result : results) { - if (result.distance < nearestTarget.distance) { - nearestTarget = result; - } - } return std::make_shared(nearestTarget); } diff --git a/interface/src/ui/Keyboard.cpp b/interface/src/ui/Keyboard.cpp index 8102df6dc6..1ff1c0248b 100644 --- a/interface/src/ui/Keyboard.cpp +++ b/interface/src/ui/Keyboard.cpp @@ -309,12 +309,22 @@ void Keyboard::setRaised(bool raised) { _layerIndex = 0; _capsEnabled = false; _typedCharacters.clear(); + addIncludeItemsToMallets(); }); updateTextDisplay(); } } +void Keyboard::addIncludeItemsToMallets() { + if (_layerIndex >= 0 && _layerIndex < (int)_keyboardLayers.size()) { + QVector includeItems = _keyboardLayers[_layerIndex].keys().toVector(); + auto pointerManager = DependencyManager::get(); + pointerManager->setIncludeItems(_leftHandStylus, includeItems); + pointerManager->setIncludeItems(_rightHandStylus, includeItems); + } +} + void Keyboard::updateTextDisplay() { auto myAvatar = DependencyManager::get()->getMyAvatar(); auto entityScriptingInterface = DependencyManager::get(); @@ -463,6 +473,8 @@ void Keyboard::switchToLayer(int layerIndex) { properties.setRotation(currentOrientation); entityScriptingInterface->editEntity(_anchor.entityID, properties); + addIncludeItemsToMallets(); + startLayerSwitchTimer(); } } @@ -718,8 +730,6 @@ void Keyboard::loadKeyboardFile(const QString& keyboardFile) { clearKeyboardKeys(); auto requestData = request->getData(); - QVector includeItems; - QJsonParseError parseError; QJsonDocument jsonDoc = QJsonDocument::fromJson(requestData, &parseError); @@ -840,7 +850,6 @@ void Keyboard::loadKeyboardFile(const QString& keyboardFile) { key.setKeyString(keyString); key.saveDimensionsAndLocalPosition(); - includeItems.append(key.getID()); _itemsToIgnore.insert(key.getID()); keyboardLayerKeys.insert(id, key); } @@ -886,9 +895,7 @@ void Keyboard::loadKeyboardFile(const QString& keyboardFile) { _itemsToIgnore.insert(_anchor.entityID); }); _layerIndex = 0; - auto pointerManager = DependencyManager::get(); - pointerManager->setIncludeItems(_leftHandStylus, includeItems); - pointerManager->setIncludeItems(_rightHandStylus, includeItems); + addIncludeItemsToMallets(); }); request->send(); diff --git a/interface/src/ui/Keyboard.h b/interface/src/ui/Keyboard.h index 958c862520..627eb68dfd 100644 --- a/interface/src/ui/Keyboard.h +++ b/interface/src/ui/Keyboard.h @@ -157,6 +157,7 @@ private: bool shouldProcessEntityAndPointerEvent(const PointerEvent& event) const; bool shouldProcessPointerEvent(const PointerEvent& event) const; bool shouldProcessEntity() const; + void addIncludeItemsToMallets(); void startLayerSwitchTimer(); bool isLayerSwitchTimerFinished() const; @@ -178,7 +179,12 @@ private: mutable ReadWriteLockable _handLaserLock; mutable ReadWriteLockable _preferMalletsOverLasersSettingLock; mutable ReadWriteLockable _ignoreItemsLock; + +#ifdef Q_OS_ANDROID + Setting::Handle _use3DKeyboard { "use3DKeyboard", false }; +#else Setting::Handle _use3DKeyboard { "use3DKeyboard", true }; +#endif QString _typedCharacters; TextDisplay _textDisplay; diff --git a/interface/src/ui/overlays/ContextOverlayInterface.cpp b/interface/src/ui/overlays/ContextOverlayInterface.cpp index c382c3de43..24c0986d09 100644 --- a/interface/src/ui/overlays/ContextOverlayInterface.cpp +++ b/interface/src/ui/overlays/ContextOverlayInterface.cpp @@ -70,7 +70,6 @@ ContextOverlayInterface::ContextOverlayInterface() { } }); connect(entityScriptingInterface, &EntityScriptingInterface::deletingEntity, this, &ContextOverlayInterface::deletingEntity); - connect(&qApp->getOverlays(), &Overlays::mousePressOnOverlay, this, &ContextOverlayInterface::contextOverlays_mousePressOnOverlay); connect(&qApp->getOverlays(), &Overlays::hoverEnterOverlay, this, &ContextOverlayInterface::contextOverlays_hoverEnterOverlay); connect(&qApp->getOverlays(), &Overlays::hoverLeaveOverlay, this, &ContextOverlayInterface::contextOverlays_hoverLeaveOverlay); @@ -103,10 +102,14 @@ void ContextOverlayInterface::setEnabled(bool enabled) { } } -void ContextOverlayInterface::clickDownOnEntity(const EntityItemID& entityItemID, const PointerEvent& event) { - if (_enabled && event.getButton() == PointerEvent::SecondaryButton && contextOverlayFilterPassed(entityItemID)) { - _mouseDownEntity = entityItemID; +void ContextOverlayInterface::clickDownOnEntity(const EntityItemID& id, const PointerEvent& event) { + if (_enabled && event.getButton() == PointerEvent::SecondaryButton && contextOverlayFilterPassed(id)) { + _mouseDownEntity = id; _mouseDownEntityTimestamp = usecTimestampNow(); + } else if (id == _contextOverlayID && event.getButton() == PointerEvent::PrimaryButton) { + qCDebug(context_overlay) << "Clicked Context Overlay. Entity ID:" << _currentEntityWithContextOverlay << "ID:" << id; + emit contextOverlayClicked(_currentEntityWithContextOverlay); + _contextOverlayJustClicked = true; } else { if (!_currentEntityWithContextOverlay.isNull()) { disableEntityHighlight(_currentEntityWithContextOverlay); @@ -249,14 +252,6 @@ bool ContextOverlayInterface::destroyContextOverlay(const EntityItemID& entityIt return ContextOverlayInterface::destroyContextOverlay(entityItemID, PointerEvent()); } -void ContextOverlayInterface::contextOverlays_mousePressOnOverlay(const QUuid& id, const PointerEvent& event) { - if (id == _contextOverlayID && event.getButton() == PointerEvent::PrimaryButton) { - qCDebug(context_overlay) << "Clicked Context Overlay. Entity ID:" << _currentEntityWithContextOverlay << "ID:" << id; - emit contextOverlayClicked(_currentEntityWithContextOverlay); - _contextOverlayJustClicked = true; - } -} - void ContextOverlayInterface::contextOverlays_hoverEnterOverlay(const QUuid& id, const PointerEvent& event) { if (_contextOverlayID != UNKNOWN_ENTITY_ID) { qCDebug(context_overlay) << "Started hovering over Context Overlay. ID:" << id; diff --git a/interface/src/ui/overlays/ContextOverlayInterface.h b/interface/src/ui/overlays/ContextOverlayInterface.h index b87535acf2..57fc8ebe6e 100644 --- a/interface/src/ui/overlays/ContextOverlayInterface.h +++ b/interface/src/ui/overlays/ContextOverlayInterface.h @@ -65,7 +65,6 @@ public slots: bool createOrDestroyContextOverlay(const EntityItemID& entityItemID, const PointerEvent& event); bool destroyContextOverlay(const EntityItemID& entityItemID, const PointerEvent& event); bool destroyContextOverlay(const EntityItemID& entityItemID); - void contextOverlays_mousePressOnOverlay(const QUuid& id, const PointerEvent& event); void contextOverlays_hoverEnterOverlay(const QUuid& id, const PointerEvent& event); void contextOverlays_hoverLeaveOverlay(const QUuid& id, const PointerEvent& event); void contextOverlays_hoverEnterEntity(const EntityItemID& entityID, const PointerEvent& event); diff --git a/interface/src/ui/overlays/Overlays.cpp b/interface/src/ui/overlays/Overlays.cpp index e1708c14fe..660220c731 100644 --- a/interface/src/ui/overlays/Overlays.cpp +++ b/interface/src/ui/overlays/Overlays.cpp @@ -63,13 +63,6 @@ Overlays::Overlays() { ADD_TYPE_MAP(PolyLine, line3d); ADD_TYPE_MAP(Grid, grid); ADD_TYPE_MAP(Gizmo, circle3d); - - auto mouseRayPick = std::make_shared(Vectors::ZERO, Vectors::UP, - PickFilter(PickFilter::getBitMask(PickFilter::FlagBit::LOCAL_ENTITIES) | - PickFilter::getBitMask(PickFilter::FlagBit::VISIBLE)), 0.0f, true); - mouseRayPick->parentTransform = std::make_shared(); - mouseRayPick->setJointState(PickQuery::JOINT_STATE_MOUSE); - _mouseRayPickID = DependencyManager::get()->addPick(PickQuery::Ray, mouseRayPick); } void Overlays::cleanupAllOverlays() { @@ -87,13 +80,14 @@ void Overlays::cleanupAllOverlays() { } void Overlays::init() { - auto entityScriptingInterface = DependencyManager::get(); - connect(this, &Overlays::hoverEnterOverlay, entityScriptingInterface.data(), &EntityScriptingInterface::hoverEnterEntity); - connect(this, &Overlays::hoverOverOverlay, entityScriptingInterface.data(), &EntityScriptingInterface::hoverOverEntity); - connect(this, &Overlays::hoverLeaveOverlay, entityScriptingInterface.data(), &EntityScriptingInterface::hoverLeaveEntity); - connect(this, &Overlays::mousePressOnOverlay, entityScriptingInterface.data(), &EntityScriptingInterface::mousePressOnEntity); - connect(this, &Overlays::mouseMoveOnOverlay, entityScriptingInterface.data(), &EntityScriptingInterface::mouseMoveOnEntity); - connect(this, &Overlays::mouseReleaseOnOverlay, entityScriptingInterface.data(), &EntityScriptingInterface::mouseReleaseOnEntity); + auto entityScriptingInterface = DependencyManager::get().data(); + auto pointerManager = DependencyManager::get(); + connect(pointerManager.data(), &PointerManager::hoverBeginOverlay, entityScriptingInterface , &EntityScriptingInterface::hoverEnterEntity); + connect(pointerManager.data(), &PointerManager::hoverContinueOverlay, entityScriptingInterface, &EntityScriptingInterface::hoverOverEntity); + connect(pointerManager.data(), &PointerManager::hoverEndOverlay, entityScriptingInterface, &EntityScriptingInterface::hoverLeaveEntity); + connect(pointerManager.data(), &PointerManager::triggerBeginOverlay, entityScriptingInterface, &EntityScriptingInterface::mousePressOnEntity); + connect(pointerManager.data(), &PointerManager::triggerContinueOverlay, entityScriptingInterface, &EntityScriptingInterface::mouseMoveOnEntity); + connect(pointerManager.data(), &PointerManager::triggerEndOverlay, entityScriptingInterface, &EntityScriptingInterface::mouseReleaseOnEntity); } void Overlays::update(float deltatime) { @@ -358,6 +352,17 @@ EntityItemProperties Overlays::convertOverlayToEntityProperties(QVariantMap& ove return "none"; }); + RENAME_PROP_CONVERT(textures, textures, [](const QVariant& v) { + auto map = v.toMap(); + if (!map.isEmpty()) { + auto json = QJsonDocument::fromVariant(map); + if (!json.isNull()) { + return QVariant(QString(json.toJson())); + } + } + return v; + }); + if (type == "Shape" || type == "Box" || type == "Sphere" || type == "Gizmo") { RENAME_PROP(solid, isSolid); RENAME_PROP(isFilled, isSolid); @@ -375,6 +380,8 @@ EntityItemProperties Overlays::convertOverlayToEntityProperties(QVariantMap& ove RENAME_PROP(animationSettings, animation); } else if (type == "Image") { RENAME_PROP(url, imageURL); + } else if (type == "Text") { + RENAME_PROP(color, textColor); } else if (type == "Web") { RENAME_PROP(url, sourceUrl); RENAME_PROP_CONVERT(inputMode, inputMode, [](const QVariant& v) { return v.toString() == "Mouse" ? "mouse" : "touch"; }); @@ -675,6 +682,8 @@ QVariantMap Overlays::convertEntityToOverlayProperties(const EntityItemPropertie RENAME_PROP(animation, animationSettings); } else if (type == "Image") { RENAME_PROP(imageURL, url); + } else if (type == "Text") { + RENAME_PROP(textColor, color); } else if (type == "Web") { RENAME_PROP(sourceUrl, url); RENAME_PROP_CONVERT(inputMode, inputMode, [](const QVariant& v) { return v.toString() == "mouse" ? "Mouse" : "Touch"; }); @@ -1228,12 +1237,12 @@ static PointerEvent::Button toPointerButton(const QMouseEvent& event) { } } -RayToOverlayIntersectionResult getPrevPickResult(unsigned int mouseRayPickID) { +RayToOverlayIntersectionResult getPrevPickResult() { RayToOverlayIntersectionResult overlayResult; overlayResult.intersects = false; - auto pickResult = DependencyManager::get()->getPrevPickResultTyped(mouseRayPickID); + auto pickResult = DependencyManager::get()->getPrevPickResultTyped(DependencyManager::get()->getMouseRayPickID()); if (pickResult) { - overlayResult.intersects = pickResult->type != IntersectionType::NONE; + overlayResult.intersects = pickResult->type == IntersectionType::LOCAL_ENTITY; if (overlayResult.intersects) { overlayResult.intersection = pickResult->intersection; overlayResult.distance = pickResult->distance; @@ -1281,7 +1290,7 @@ std::pair Overlays::mousePressEvent(QMouseEvent* event) { PerformanceTimer perfTimer("Overlays::mousePressEvent"); PickRay ray = qApp->computePickRay(event->x(), event->y()); - RayToOverlayIntersectionResult rayPickResult = getPrevPickResult(_mouseRayPickID); + RayToOverlayIntersectionResult rayPickResult = getPrevPickResult(); if (rayPickResult.intersects) { _currentClickingOnOverlayID = rayPickResult.overlayID; @@ -1305,7 +1314,7 @@ bool Overlays::mouseDoublePressEvent(QMouseEvent* event) { PerformanceTimer perfTimer("Overlays::mouseDoublePressEvent"); PickRay ray = qApp->computePickRay(event->x(), event->y()); - RayToOverlayIntersectionResult rayPickResult = getPrevPickResult(_mouseRayPickID); + RayToOverlayIntersectionResult rayPickResult = getPrevPickResult(); if (rayPickResult.intersects) { _currentClickingOnOverlayID = rayPickResult.overlayID; @@ -1321,7 +1330,7 @@ bool Overlays::mouseReleaseEvent(QMouseEvent* event) { PerformanceTimer perfTimer("Overlays::mouseReleaseEvent"); PickRay ray = qApp->computePickRay(event->x(), event->y()); - RayToOverlayIntersectionResult rayPickResult = getPrevPickResult(_mouseRayPickID); + RayToOverlayIntersectionResult rayPickResult = getPrevPickResult(); if (rayPickResult.intersects) { auto pointerEvent = calculateOverlayPointerEvent(rayPickResult.overlayID, ray, rayPickResult, event, PointerEvent::Release); mouseReleasePointerEvent(rayPickResult.overlayID, pointerEvent); @@ -1343,7 +1352,7 @@ bool Overlays::mouseMoveEvent(QMouseEvent* event) { PerformanceTimer perfTimer("Overlays::mouseMoveEvent"); PickRay ray = qApp->computePickRay(event->x(), event->y()); - RayToOverlayIntersectionResult rayPickResult = getPrevPickResult(_mouseRayPickID); + RayToOverlayIntersectionResult rayPickResult = getPrevPickResult(); if (rayPickResult.intersects) { auto pointerEvent = calculateOverlayPointerEvent(rayPickResult.overlayID, ray, rayPickResult, event, PointerEvent::Move); mouseMovePointerEvent(rayPickResult.overlayID, pointerEvent); diff --git a/interface/src/ui/overlays/Overlays.h b/interface/src/ui/overlays/Overlays.h index 7612779099..838a38eb54 100644 --- a/interface/src/ui/overlays/Overlays.h +++ b/interface/src/ui/overlays/Overlays.h @@ -719,7 +719,6 @@ private: PointerEvent calculateOverlayPointerEvent(const QUuid& id, const PickRay& ray, const RayToOverlayIntersectionResult& rayPickResult, QMouseEvent* event, PointerEvent::EventType eventType); - unsigned int _mouseRayPickID; QUuid _currentClickingOnOverlayID; QUuid _currentHoverOverOverlayID; diff --git a/libraries/animation/src/AnimInverseKinematics.cpp b/libraries/animation/src/AnimInverseKinematics.cpp index a1809f3438..d710e9d8ff 100644 --- a/libraries/animation/src/AnimInverseKinematics.cpp +++ b/libraries/animation/src/AnimInverseKinematics.cpp @@ -865,10 +865,6 @@ const AnimPoseVec& AnimInverseKinematics::evaluate(const AnimVariantMap& animVar //virtual const AnimPoseVec& AnimInverseKinematics::overlay(const AnimVariantMap& animVars, const AnimContext& context, float dt, AnimVariantMap& triggersOut, const AnimPoseVec& underPoses) { -#ifdef Q_OS_ANDROID - // disable IK on android - return underPoses; -#endif // allows solutionSource to be overridden by an animVar auto solutionSource = animVars.lookup(_solutionSourceVar, (int)_solutionSource); diff --git a/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp b/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp index 2a3b7e8b46..32432ce193 100644 --- a/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp +++ b/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp @@ -65,7 +65,11 @@ namespace render { return keyBuilder.build(); } template <> const Item::Bound payloadGetBound(const AvatarSharedPointer& avatar) { - return static_pointer_cast(avatar)->getRenderBounds(); + auto avatarPtr = static_pointer_cast(avatar); + if (avatarPtr) { + return avatarPtr->getRenderBounds(); + } + return Item::Bound(); } template <> void payloadRender(const AvatarSharedPointer& avatar, RenderArgs* args) { auto avatarPtr = static_pointer_cast(avatar); @@ -76,10 +80,15 @@ namespace render { } template <> uint32_t metaFetchMetaSubItems(const AvatarSharedPointer& avatar, ItemIDs& subItems) { auto avatarPtr = static_pointer_cast(avatar); - if (avatarPtr->getSkeletonModel()) { - auto& metaSubItems = avatarPtr->getSkeletonModel()->fetchRenderItemIDs(); - subItems.insert(subItems.end(), metaSubItems.begin(), metaSubItems.end()); - return (uint32_t) metaSubItems.size(); + if (avatarPtr) { + uint32_t total = 0; + if (avatarPtr->getSkeletonModel()) { + auto& metaSubItems = avatarPtr->getSkeletonModel()->fetchRenderItemIDs(); + subItems.insert(subItems.end(), metaSubItems.begin(), metaSubItems.end()); + total += (uint32_t)metaSubItems.size(); + } + total += avatarPtr->appendSubMetaItems(subItems); + return total; } return 0; } @@ -627,12 +636,18 @@ void Avatar::addToScene(AvatarSharedPointer self, const render::ScenePointer& sc _skeletonModel->setVisibleInScene(_isMeshVisible, scene); processMaterials(); + bool attachmentRenderingNeedsUpdate = false; for (auto& attachmentModel : _attachmentModels) { attachmentModel->addToScene(scene, transaction); attachmentModel->setTagMask(render::hifi::TAG_ALL_VIEWS); - attachmentModel->setGroupCulled(false); + attachmentModel->setGroupCulled(true); attachmentModel->setCanCastShadow(true); attachmentModel->setVisibleInScene(_isMeshVisible, scene); + attachmentRenderingNeedsUpdate = true; + } + + if (attachmentRenderingNeedsUpdate) { + updateAttachmentRenderIDs(); } _mustFadeIn = true; @@ -856,15 +871,17 @@ void Avatar::fixupModelsInScene(const render::ScenePointer& scene) { canTryFade = true; _isAnimatingScale = true; } + bool attachmentRenderingNeedsUpdate = false; for (auto attachmentModel : _attachmentModels) { if (attachmentModel->isRenderable() && attachmentModel->needsFixupInScene()) { attachmentModel->removeFromScene(scene, transaction); attachmentModel->addToScene(scene, transaction); attachmentModel->setTagMask(render::hifi::TAG_ALL_VIEWS); - attachmentModel->setGroupCulled(false); + attachmentModel->setGroupCulled(true); attachmentModel->setCanCastShadow(true); attachmentModel->setVisibleInScene(_isMeshVisible, scene); + attachmentRenderingNeedsUpdate = true; } } @@ -887,9 +904,15 @@ void Avatar::fixupModelsInScene(const render::ScenePointer& scene) { for (auto attachmentModelToRemove : _attachmentsToRemove) { attachmentModelToRemove->removeFromScene(scene, transaction); + attachmentRenderingNeedsUpdate = true; } _attachmentsToDelete.insert(_attachmentsToDelete.end(), _attachmentsToRemove.begin(), _attachmentsToRemove.end()); _attachmentsToRemove.clear(); + + if (attachmentRenderingNeedsUpdate) { + updateAttachmentRenderIDs(); + } + scene->enqueueTransaction(transaction); } @@ -932,6 +955,11 @@ void Avatar::simulateAttachments(float deltaTime) { } } } + + if (_ancestorChainRenderableVersion != _lastAncestorChainRenderableVersion) { + _lastAncestorChainRenderableVersion = _ancestorChainRenderableVersion; + updateDescendantRenderIDs(); + } } float Avatar::getBoundingRadius() const { @@ -1611,7 +1639,6 @@ void Avatar::setAttachmentData(const QVector& attachmentData) { } } - int Avatar::parseDataFromBuffer(const QByteArray& buffer) { PerformanceTimer perfTimer("unpack"); if (!_initialized) { @@ -2120,3 +2147,60 @@ void Avatar::clearAvatarGrabData(const QUuid& id) { } }); } + +uint32_t Avatar::appendSubMetaItems(render::ItemIDs& subItems) { + return _subItemLock.resultWithReadLock([&] { + uint32_t total = 0; + + if (_attachmentRenderIDs.size() > 0) { + subItems.insert(subItems.end(), _attachmentRenderIDs.begin(), _attachmentRenderIDs.end()); + total += (uint32_t)_attachmentRenderIDs.size(); + } + + if (_descendantRenderIDs.size() > 0) { + subItems.insert(subItems.end(), _descendantRenderIDs.begin(), _descendantRenderIDs.end()); + total += (uint32_t)_descendantRenderIDs.size(); + } + + return total; + }); +} + +void Avatar::updateAttachmentRenderIDs() { + _subItemLock.withWriteLock([&] { + _attachmentRenderIDs.clear(); + for (auto& attachmentModel : _attachmentModels) { + if (attachmentModel && attachmentModel->isRenderable()) { + auto& metaSubItems = attachmentModel->fetchRenderItemIDs(); + _attachmentRenderIDs.insert(_attachmentRenderIDs.end(), metaSubItems.begin(), metaSubItems.end()); + } + } + }); +} + +void Avatar::updateDescendantRenderIDs() { + _subItemLock.withWriteLock([&] { + _descendantRenderIDs.clear(); + auto entityTreeRenderer = DependencyManager::get(); + EntityTreePointer entityTree = entityTreeRenderer ? entityTreeRenderer->getTree() : nullptr; + if (entityTree) { + entityTree->withReadLock([&] { + forEachDescendant([&](SpatiallyNestablePointer object) { + if (object && object->getNestableType() == NestableType::Entity) { + EntityItemPointer entity = std::static_pointer_cast(object); + if (entity->isVisible()) { + auto renderer = entityTreeRenderer->renderableForEntityId(object->getID()); + if (renderer) { + render::ItemIDs renderableSubItems; + uint32_t numRenderableSubItems = renderer->metaFetchMetaSubItems(renderableSubItems); + if (numRenderableSubItems > 0) { + _descendantRenderIDs.insert(_descendantRenderIDs.end(), renderableSubItems.begin(), renderableSubItems.end()); + } + } + } + } + }); + }); + } + }); +} diff --git a/libraries/avatars-renderer/src/avatars-renderer/Avatar.h b/libraries/avatars-renderer/src/avatars-renderer/Avatar.h index c9f1c4bdfe..6c31f9fc93 100644 --- a/libraries/avatars-renderer/src/avatars-renderer/Avatar.h +++ b/libraries/avatars-renderer/src/avatars-renderer/Avatar.h @@ -500,6 +500,8 @@ public: const std::vector& getMultiSphereShapes() const { return _multiSphereShapes; } void tearDownGrabs(); + uint32_t appendSubMetaItems(render::ItemIDs& subItems); + signals: void targetScaleChanged(float targetScale); @@ -642,8 +644,6 @@ protected: RateCounter<> _skeletonModelSimulationRate; RateCounter<> _jointDataSimulationRate; - -protected: class AvatarEntityDataHash { public: AvatarEntityDataHash(uint32_t h) : hash(h) {}; @@ -705,6 +705,13 @@ protected: MapOfGrabs _avatarGrabs; SetOfIDs _grabsToChange; // updated grab IDs -- changes needed to entities or physics VectorOfIDs _grabsToDelete; // deleted grab IDs -- changes needed to entities or physics + + ReadWriteLockable _subItemLock; + void updateAttachmentRenderIDs(); + render::ItemIDs _attachmentRenderIDs; + void updateDescendantRenderIDs(); + render::ItemIDs _descendantRenderIDs; + uint32_t _lastAncestorChainRenderableVersion { 0 }; }; #endif // hifi_Avatar_h diff --git a/libraries/avatars/src/AvatarHashMap.cpp b/libraries/avatars/src/AvatarHashMap.cpp index 5f30d98ed6..c16d65506a 100644 --- a/libraries/avatars/src/AvatarHashMap.cpp +++ b/libraries/avatars/src/AvatarHashMap.cpp @@ -208,16 +208,16 @@ AvatarSharedPointer AvatarHashMap::addAvatar(const QUuid& sessionUUID, const QWe avatar->setSessionUUID(sessionUUID); avatar->setOwningAvatarMixer(mixerWeakPointer); - // addAvatar is only called from newOrExistingAvatar, which already locks _hashLock - _avatarHash.insert(sessionUUID, avatar); + { + QWriteLocker locker(&_hashLock); + _avatarHash.insert(sessionUUID, avatar); + } emit avatarAddedEvent(sessionUUID); return avatar; } -AvatarSharedPointer AvatarHashMap::newOrExistingAvatar(const QUuid& sessionUUID, const QWeakPointer& mixerWeakPointer, - bool& isNew) { - QWriteLocker locker(&_hashLock); - auto avatar = _avatarHash.value(sessionUUID); +AvatarSharedPointer AvatarHashMap::newOrExistingAvatar(const QUuid& sessionUUID, const QWeakPointer& mixerWeakPointer, bool& isNew) { + auto avatar = findAvatar(sessionUUID); if (!avatar) { avatar = addAvatar(sessionUUID, mixerWeakPointer); isNew = true; diff --git a/libraries/display-plugins/src/display-plugins/Basic2DWindowOpenGLDisplayPlugin.cpp b/libraries/display-plugins/src/display-plugins/Basic2DWindowOpenGLDisplayPlugin.cpp index d8b8cbd54a..9828a8beda 100644 --- a/libraries/display-plugins/src/display-plugins/Basic2DWindowOpenGLDisplayPlugin.cpp +++ b/libraries/display-plugins/src/display-plugins/Basic2DWindowOpenGLDisplayPlugin.cpp @@ -74,30 +74,15 @@ void Basic2DWindowOpenGLDisplayPlugin::customizeContext() { } } - - _virtualPadJumpBtnPixelSize = dpi * VirtualPad::Manager::JUMP_BTN_FULL_PIXELS / VirtualPad::Manager::DPI; - if (!_virtualPadJumpBtnTexture) { - auto iconPath = PathUtils::resourcesPath() + "images/fly.png"; - auto image = QImage(iconPath); - if (image.format() != QImage::Format_ARGB32) { - image = image.convertToFormat(QImage::Format_ARGB32); - } - if ((image.width() > 0) && (image.height() > 0)) { - image = image.scaled(_virtualPadJumpBtnPixelSize, _virtualPadJumpBtnPixelSize, Qt::KeepAspectRatio); - image = image.mirrored(); - - _virtualPadJumpBtnTexture = gpu::Texture::createStrict( - gpu::Element(gpu::VEC4, gpu::NUINT8, gpu::RGBA), - image.width(), image.height(), - gpu::Texture::MAX_NUM_MIPS, - gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR)); - _virtualPadJumpBtnTexture->setSource("virtualPad jump"); - auto usage = gpu::Texture::Usage::Builder().withColor().withAlpha(); - _virtualPadJumpBtnTexture->setUsage(usage.build()); - _virtualPadJumpBtnTexture->setStoredMipFormat(gpu::Element(gpu::VEC4, gpu::NUINT8, gpu::RGBA)); - _virtualPadJumpBtnTexture->assignStoredMip(0, image.byteCount(), image.constBits()); - _virtualPadJumpBtnTexture->setAutoGenerateMips(true); - } + if (_virtualPadButtons.size() == 0) { + _virtualPadButtons.append(VirtualPadButton( + dpi * VirtualPad::Manager::BTN_FULL_PIXELS / VirtualPad::Manager::DPI, + PathUtils::resourcesPath() + "images/fly.png", + VirtualPad::Manager::Button::JUMP)); + _virtualPadButtons.append(VirtualPadButton( + dpi * VirtualPad::Manager::BTN_FULL_PIXELS / VirtualPad::Manager::DPI, + PathUtils::resourcesPath() + "images/handshake.png", + VirtualPad::Manager::Button::HANDSHAKE)); } #endif Parent::customizeContext(); @@ -133,8 +118,6 @@ void Basic2DWindowOpenGLDisplayPlugin::compositeExtra() { _virtualPadPixelSize, _virtualPadPixelSize); auto stickTransform = DependencyManager::get()->getPoint2DTransform(virtualPadManager.getLeftVirtualPad()->getCurrentTouch(), _virtualPadPixelSize, _virtualPadPixelSize); - auto jumpTransform = DependencyManager::get()->getPoint2DTransform(virtualPadManager.getJumpButtonPosition(), - _virtualPadJumpBtnPixelSize, _virtualPadJumpBtnPixelSize); render([&](gpu::Batch& batch) { batch.enableStereo(false); @@ -151,9 +134,9 @@ void Basic2DWindowOpenGLDisplayPlugin::compositeExtra() { batch.setModelTransform(stickTransform); batch.draw(gpu::TRIANGLE_STRIP, 4); - batch.setResourceTexture(0, _virtualPadJumpBtnTexture); - batch.setModelTransform(jumpTransform); - batch.draw(gpu::TRIANGLE_STRIP, 4); + foreach(VirtualPadButton virtualPadButton, _virtualPadButtons) { + virtualPadButton.draw(batch, virtualPadManager.getButtonPosition(virtualPadButton._button)); + } }); } #endif @@ -178,3 +161,47 @@ bool Basic2DWindowOpenGLDisplayPlugin::isThrottled() const { QScreen* Basic2DWindowOpenGLDisplayPlugin::getFullscreenTarget() { return qApp->primaryScreen(); } + +#if defined(Q_OS_ANDROID) + +Basic2DWindowOpenGLDisplayPlugin::VirtualPadButton::VirtualPadButton(qreal pixelSize, + QString iconPath, + VirtualPad::Manager::Button button) : + _pixelSize { pixelSize }, + _button { button } +{ + if (!_texture) { + auto image = QImage(iconPath); + if (image.format() != QImage::Format_ARGB32) { + image = image.convertToFormat(QImage::Format_ARGB32); + } + if ((image.width() > 0) && (image.height() > 0)) { + image = image.scaled(_pixelSize, _pixelSize, Qt::KeepAspectRatio); + image = image.mirrored(); + + _texture = gpu::Texture::createStrict( + gpu::Element(gpu::VEC4, gpu::NUINT8, gpu::RGBA), + image.width(), image.height(), + gpu::Texture::MAX_NUM_MIPS, + gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR)); + _texture->setSource(iconPath.toStdString()); + auto usage = gpu::Texture::Usage::Builder().withColor().withAlpha(); + _texture->setUsage(usage.build()); + _texture->setStoredMipFormat(gpu::Element(gpu::VEC4, gpu::NUINT8, gpu::RGBA)); + _texture->assignStoredMip(0, image.byteCount(), image.constBits()); + _texture->setAutoGenerateMips(true); + } + } +} + +void Basic2DWindowOpenGLDisplayPlugin::VirtualPadButton::draw(gpu::Batch &batch, + glm::vec2 buttonPosition) { + auto transform = DependencyManager::get()->getPoint2DTransform( + buttonPosition, + _pixelSize, _pixelSize); + batch.setResourceTexture(0, _texture); + batch.setModelTransform(transform); + batch.draw(gpu::TRIANGLE_STRIP, 4); +} + +#endif \ No newline at end of file diff --git a/libraries/display-plugins/src/display-plugins/Basic2DWindowOpenGLDisplayPlugin.h b/libraries/display-plugins/src/display-plugins/Basic2DWindowOpenGLDisplayPlugin.h index 944d5e89d1..cc304c19c2 100644 --- a/libraries/display-plugins/src/display-plugins/Basic2DWindowOpenGLDisplayPlugin.h +++ b/libraries/display-plugins/src/display-plugins/Basic2DWindowOpenGLDisplayPlugin.h @@ -9,6 +9,10 @@ #include "OpenGLDisplayPlugin.h" +#if defined(Q_OS_ANDROID) +#include "VirtualPadManager.h" +#endif + const float TARGET_FRAMERATE_Basic2DWindowOpenGL = 60.0f; class QScreen; @@ -51,5 +55,23 @@ private: gpu::TexturePointer _virtualPadJumpBtnTexture; qreal _virtualPadJumpBtnPixelSize; + + gpu::TexturePointer _virtualPadRbBtnTexture; + qreal _virtualPadRbBtnPixelSize; + + class VirtualPadButton { + public: + + VirtualPadButton() {} + VirtualPadButton(qreal pixelSize, QString iconPath, VirtualPad::Manager::Button button); + + void draw(gpu::Batch& batch, glm::vec2 buttonPosition); + + gpu::TexturePointer _texture; + qreal _pixelSize; + VirtualPad::Manager::Button _button; + }; + QVector _virtualPadButtons; + #endif }; diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.cpp b/libraries/entities-renderer/src/EntityTreeRenderer.cpp index 319acc750f..9d55d936a2 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.cpp +++ b/libraries/entities-renderer/src/EntityTreeRenderer.cpp @@ -86,7 +86,7 @@ EntityTreeRenderer::EntityTreeRenderer(bool wantScripts, AbstractViewStateInterf auto handlePointerEvent = [&](const QUuid& entityID, const PointerEvent& event) { std::shared_ptr thisEntity; auto entity = getEntity(entityID); - if (entity && entity->getType() == EntityTypes::Web) { + if (entity && entity->isVisible() && entity->getType() == EntityTypes::Web) { thisEntity = std::static_pointer_cast(renderableForEntityId(entityID)); } if (thisEntity) { @@ -99,7 +99,7 @@ EntityTreeRenderer::EntityTreeRenderer(bool wantScripts, AbstractViewStateInterf connect(entityScriptingInterface.data(), &EntityScriptingInterface::hoverEnterEntity, this, [&](const QUuid& entityID, const PointerEvent& event) { std::shared_ptr thisEntity; auto entity = getEntity(entityID); - if (entity && entity->getType() == EntityTypes::Web) { + if (entity && entity->isVisible() && entity->getType() == EntityTypes::Web) { thisEntity = std::static_pointer_cast(renderableForEntityId(entityID)); } if (thisEntity) { @@ -110,7 +110,7 @@ EntityTreeRenderer::EntityTreeRenderer(bool wantScripts, AbstractViewStateInterf connect(entityScriptingInterface.data(), &EntityScriptingInterface::hoverLeaveEntity, this, [&](const QUuid& entityID, const PointerEvent& event) { std::shared_ptr thisEntity; auto entity = getEntity(entityID); - if (entity && entity->getType() == EntityTypes::Web) { + if (entity && entity->isVisible() && entity->getType() == EntityTypes::Web) { thisEntity = std::static_pointer_cast(renderableForEntityId(entityID)); } if (thisEntity) { @@ -1360,3 +1360,36 @@ EntityEditPacketSender* EntityTreeRenderer::getPacketSender() { EntityEditPacketSender* packetSender = peSimulation ? peSimulation->getPacketSender() : nullptr; return packetSender; } + +std::function EntityTreeRenderer::_addMaterialToEntityOperator = nullptr; +std::function EntityTreeRenderer::_removeMaterialFromEntityOperator = nullptr; +std::function EntityTreeRenderer::_addMaterialToAvatarOperator = nullptr; +std::function EntityTreeRenderer::_removeMaterialFromAvatarOperator = nullptr; + +bool EntityTreeRenderer::addMaterialToEntity(const QUuid& entityID, graphics::MaterialLayer material, const std::string& parentMaterialName) { + if (_addMaterialToEntityOperator) { + return _addMaterialToEntityOperator(entityID, material, parentMaterialName); + } + return false; +} + +bool EntityTreeRenderer::removeMaterialFromEntity(const QUuid& entityID, graphics::MaterialPointer material, const std::string& parentMaterialName) { + if (_removeMaterialFromEntityOperator) { + return _removeMaterialFromEntityOperator(entityID, material, parentMaterialName); + } + return false; +} + +bool EntityTreeRenderer::addMaterialToAvatar(const QUuid& avatarID, graphics::MaterialLayer material, const std::string& parentMaterialName) { + if (_addMaterialToAvatarOperator) { + return _addMaterialToAvatarOperator(avatarID, material, parentMaterialName); + } + return false; +} + +bool EntityTreeRenderer::removeMaterialFromAvatar(const QUuid& avatarID, graphics::MaterialPointer material, const std::string& parentMaterialName) { + if (_removeMaterialFromAvatarOperator) { + return _removeMaterialFromAvatarOperator(avatarID, material, parentMaterialName); + } + return false; +} \ No newline at end of file diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.h b/libraries/entities-renderer/src/EntityTreeRenderer.h index 204dc50c45..51568ab744 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.h +++ b/libraries/entities-renderer/src/EntityTreeRenderer.h @@ -73,6 +73,7 @@ public: static void setEntityLoadingPriorityFunction(CalculateEntityLoadingPriority fn) { _calculateEntityLoadingPriorityFunc = fn; } void setMouseRayPickID(unsigned int rayPickID) { _mouseRayPickID = rayPickID; } + unsigned int getMouseRayPickID() { return _mouseRayPickID; } void setMouseRayPickResultOperator(std::function getPrevRayPickResultOperator) { _getPrevRayPickResultOperator = getPrevRayPickResultOperator; } void setSetPrecisionPickingOperator(std::function setPrecisionPickingOperator) { _setPrecisionPickingOperator = setPrecisionPickingOperator; } @@ -120,6 +121,16 @@ public: EntityEditPacketSender* getPacketSender(); + static void setAddMaterialToEntityOperator(std::function addMaterialToEntityOperator) { _addMaterialToEntityOperator = addMaterialToEntityOperator; } + static void setRemoveMaterialFromEntityOperator(std::function removeMaterialFromEntityOperator) { _removeMaterialFromEntityOperator = removeMaterialFromEntityOperator; } + static bool addMaterialToEntity(const QUuid& entityID, graphics::MaterialLayer material, const std::string& parentMaterialName); + static bool removeMaterialFromEntity(const QUuid& entityID, graphics::MaterialPointer material, const std::string& parentMaterialName); + + static void setAddMaterialToAvatarOperator(std::function addMaterialToAvatarOperator) { _addMaterialToAvatarOperator = addMaterialToAvatarOperator; } + static void setRemoveMaterialFromAvatarOperator(std::function removeMaterialFromAvatarOperator) { _removeMaterialFromAvatarOperator = removeMaterialFromAvatarOperator; } + static bool addMaterialToAvatar(const QUuid& avatarID, graphics::MaterialLayer material, const std::string& parentMaterialName); + static bool removeMaterialFromAvatar(const QUuid& avatarID, graphics::MaterialPointer material, const std::string& parentMaterialName); + signals: void enterEntity(const EntityItemID& entityItemID); void leaveEntity(const EntityItemID& entityItemID); @@ -255,6 +266,11 @@ private: workload::SpacePointer _space{ new workload::Space() }; workload::Transaction::Updates _spaceUpdates; + static std::function _addMaterialToEntityOperator; + static std::function _removeMaterialFromEntityOperator; + static std::function _addMaterialToAvatarOperator; + static std::function _removeMaterialFromAvatarOperator; + }; diff --git a/libraries/entities-renderer/src/RenderableEntityItem.cpp b/libraries/entities-renderer/src/RenderableEntityItem.cpp index 83f0bdcff3..a6826da91b 100644 --- a/libraries/entities-renderer/src/RenderableEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableEntityItem.cpp @@ -146,7 +146,6 @@ EntityRenderer::EntityRenderer(const EntityItemPointer& entity) : _created(entit _needsRenderUpdate = true; emit requestRenderUpdate(); }); - _materials = entity->getMaterials(); } EntityRenderer::~EntityRenderer() { } @@ -321,6 +320,7 @@ bool EntityRenderer::addToScene(const ScenePointer& scene, Transaction& transact transaction.resetItem(_renderItemID, renderPayload); onAddToScene(_entity); updateInScene(scene, transaction); + _entity->bumpAncestorChainRenderableVersion(); return true; } @@ -328,6 +328,7 @@ void EntityRenderer::removeFromScene(const ScenePointer& scene, Transaction& tra onRemoveFromScene(_entity); transaction.removeItem(_renderItemID); Item::clearID(_renderItemID); + _entity->bumpAncestorChainRenderableVersion(); } void EntityRenderer::updateInScene(const ScenePointer& scene, Transaction& transaction) { @@ -353,14 +354,6 @@ void EntityRenderer::updateInScene(const ScenePointer& scene, Transaction& trans }); } -void EntityRenderer::clearSubRenderItemIDs() { - _subRenderItemIDs.clear(); -} - -void EntityRenderer::setSubRenderItemIDs(const render::ItemIDs& ids) { - _subRenderItemIDs = ids; -} - // // Internal methods // diff --git a/libraries/entities-renderer/src/RenderableEntityItem.h b/libraries/entities-renderer/src/RenderableEntityItem.h index d5e236a76a..e9a6035e3d 100644 --- a/libraries/entities-renderer/src/RenderableEntityItem.h +++ b/libraries/entities-renderer/src/RenderableEntityItem.h @@ -52,9 +52,6 @@ public: virtual bool addToScene(const ScenePointer& scene, Transaction& transaction) final; virtual void removeFromScene(const ScenePointer& scene, Transaction& transaction); - void clearSubRenderItemIDs(); - void setSubRenderItemIDs(const render::ItemIDs& ids); - const uint64_t& getUpdateTime() const { return _updateTime; } virtual void addMaterial(graphics::MaterialLayer material, const std::string& parentMaterialName); @@ -64,6 +61,9 @@ public: static glm::vec4 calculatePulseColor(const glm::vec4& color, const PulsePropertyGroup& pulseProperties, quint64 start); + virtual uint32_t metaFetchMetaSubItems(ItemIDs& subItems) override; + virtual Item::Bound getBound() override; + protected: virtual bool needsRenderUpdateFromEntity() const final { return needsRenderUpdateFromEntity(_entity); } virtual void onAddToScene(const EntityItemPointer& entity); @@ -75,9 +75,7 @@ protected: // Implementing the PayloadProxyInterface methods virtual ItemKey getKey() override; virtual ShapeKey getShapeKey() override; - virtual Item::Bound getBound() override; virtual void render(RenderArgs* args) override final; - virtual uint32_t metaFetchMetaSubItems(ItemIDs& subItems) override; virtual render::hifi::Tag getTagMask() const; virtual render::hifi::Layer getHifiRenderLayer() const; @@ -133,7 +131,6 @@ protected: SharedSoundPointer _collisionSound; QUuid _changeHandlerId; ItemID _renderItemID{ Item::INVALID_ITEM_ID }; - ItemIDs _subRenderItemIDs; uint64_t _fadeStartTime{ usecTimestampNow() }; uint64_t _updateTime{ usecTimestampNow() }; // used when sorting/throttling render updates bool _isFading { EntityTreeRenderer::getEntitiesShouldFadeFunction()() }; diff --git a/libraries/entities-renderer/src/RenderableMaterialEntityItem.cpp b/libraries/entities-renderer/src/RenderableMaterialEntityItem.cpp index 483f9ffe1c..2eb877b0e1 100644 --- a/libraries/entities-renderer/src/RenderableMaterialEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableMaterialEntityItem.cpp @@ -14,42 +14,210 @@ using namespace render; using namespace render::entities; -bool MaterialEntityRenderer::needsRenderUpdateFromTypedEntity(const TypedEntityPointer& entity) const { - if (entity->getMaterial() != _drawMaterial) { - return true; - } - if (entity->getParentID() != _parentID) { - return true; - } - if (entity->getMaterialMappingPos() != _materialMappingPos || entity->getMaterialMappingScale() != _materialMappingScale || entity->getMaterialMappingRot() != _materialMappingRot) { +bool MaterialEntityRenderer::needsRenderUpdate() const { + if (_retryApply) { return true; } if (!_texturesLoaded) { return true; } + return Parent::needsRenderUpdate(); +} + +bool MaterialEntityRenderer::needsRenderUpdateFromTypedEntity(const TypedEntityPointer& entity) const { + if (resultWithReadLock([&] { + if (entity->getMaterialMappingMode() != _materialMappingMode) { + return true; + } + if (entity->getMaterialRepeat() != _materialRepeat) { + return true; + } + if (entity->getMaterialMappingPos() != _materialMappingPos || entity->getMaterialMappingScale() != _materialMappingScale || entity->getMaterialMappingRot() != _materialMappingRot) { + return true; + } + if (entity->getTransform() != _transform) { + return true; + } + if (entity->getUnscaledDimensions() != _dimensions) { + return true; + } + + if (entity->getMaterialURL() != _materialURL) { + return true; + } + if (entity->getMaterialData() != _materialData) { + return true; + } + if (entity->getParentMaterialName() != _parentMaterialName) { + return true; + } + if (entity->getParentID() != _parentID) { + return true; + } + if (entity->getPriority() != _priority) { + return true; + } + + return false; + })) { + return true; + } return false; } -void MaterialEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& scene, Transaction& transaction, const TypedEntityPointer& entity) { +void MaterialEntityRenderer::doRenderUpdateAsynchronousTyped(const TypedEntityPointer& entity) { withWriteLock([&] { - if (_drawMaterial != entity->getMaterial()) { - _texturesLoaded = false; - _drawMaterial = entity->getMaterial(); + bool deleteNeeded = false; + bool addNeeded = _retryApply; + bool transformChanged = false; + { + MaterialMappingMode mode = entity->getMaterialMappingMode(); + if (mode != _materialMappingMode) { + _materialMappingMode = mode; + transformChanged = true; + } } - _parentID = entity->getParentID(); - _materialMappingPos = entity->getMaterialMappingPos(); - _materialMappingScale = entity->getMaterialMappingScale(); - _materialMappingRot = entity->getMaterialMappingRot(); + { + bool repeat = entity->getMaterialRepeat(); + if (repeat != _materialRepeat) { + _materialRepeat = repeat; + transformChanged = true; + } + } + { + glm::vec2 mappingPos = entity->getMaterialMappingPos(); + glm::vec2 mappingScale = entity->getMaterialMappingScale(); + float mappingRot = entity->getMaterialMappingRot(); + if (mappingPos != _materialMappingPos || mappingScale != _materialMappingScale || mappingRot != _materialMappingRot) { + _materialMappingPos = mappingPos; + _materialMappingScale = mappingScale; + _materialMappingRot = mappingRot; + transformChanged |= _materialMappingMode == MaterialMappingMode::UV; + } + } + { + Transform transform = entity->getTransform(); + glm::vec3 dimensions = entity->getUnscaledDimensions(); + if (transform != _transform || dimensions != _dimensions) { + _transform = transform; + _dimensions = dimensions; + transformChanged |= _materialMappingMode == MaterialMappingMode::PROJECTED; + } + } + + { + auto material = getMaterial(); + // Update the old material regardless of if it's going to change + if (transformChanged && material && !_parentID.isNull()) { + deleteNeeded = true; + addNeeded = true; + applyTextureTransform(material); + } + } + + bool urlChanged = false; + std::string newCurrentMaterialName = _currentMaterialName; + { + QString materialURL = entity->getMaterialURL(); + if (materialURL != _materialURL) { + _materialURL = materialURL; + if (_materialURL.contains("?")) { + auto split = _materialURL.split("?"); + newCurrentMaterialName = split.last().toStdString(); + } + urlChanged = true; + } + } + + bool usingMaterialData = _materialURL.startsWith("materialData"); + bool materialDataChanged = false; + QUuid oldParentID = _parentID; + QString oldParentMaterialName = _parentMaterialName; + { + QString materialData = entity->getMaterialData(); + if (materialData != _materialData) { + _materialData = materialData; + if (usingMaterialData) { + materialDataChanged = true; + } + } + } + { + QString parentMaterialName = entity->getParentMaterialName(); + if (parentMaterialName != _parentMaterialName) { + _parentMaterialName = parentMaterialName; + deleteNeeded = true; + addNeeded = true; + } + } + { + QUuid parentID = entity->getParentID(); + if (parentID != _parentID) { + _parentID = parentID; + deleteNeeded = true; + addNeeded = true; + } + } + { + quint16 priority = entity->getPriority(); + if (priority != _priority) { + _priority = priority; + deleteNeeded = true; + addNeeded = true; + } + } + + if (urlChanged && !usingMaterialData) { + _networkMaterial = MaterialCache::instance().getMaterial(_materialURL); + auto onMaterialRequestFinished = [&, oldParentID, oldParentMaterialName, newCurrentMaterialName](bool success) { + if (success) { + deleteMaterial(oldParentID, oldParentMaterialName); + _texturesLoaded = false; + _parsedMaterials = _networkMaterial->parsedMaterials; + setCurrentMaterialName(newCurrentMaterialName); + applyMaterial(); + } else { + deleteMaterial(oldParentID, oldParentMaterialName); + _retryApply = false; + _texturesLoaded = true; + } + }; + if (_networkMaterial) { + if (_networkMaterial->isLoaded()) { + onMaterialRequestFinished(!_networkMaterial->isFailed()); + } else { + connect(_networkMaterial.data(), &Resource::finished, this, onMaterialRequestFinished); + } + } + } else if (materialDataChanged && usingMaterialData) { + deleteMaterial(oldParentID, oldParentMaterialName); + _texturesLoaded = false; + _parsedMaterials = NetworkMaterialResource::parseJSONMaterials(QJsonDocument::fromJson(_materialData.toUtf8()), _materialURL); + // Since our material changed, the current name might not be valid anymore, so we need to update + setCurrentMaterialName(newCurrentMaterialName); + applyMaterial(); + } else { + if (deleteNeeded) { + deleteMaterial(oldParentID, oldParentMaterialName); + } + if (addNeeded) { + applyMaterial(); + } + } + + { + auto material = getMaterial(); + bool newTexturesLoaded = material ? !material->isMissingTexture() : false; + if (!_texturesLoaded && newTexturesLoaded) { + material->checkResetOpacityMap(); + } + _texturesLoaded = newTexturesLoaded; + } + _renderTransform = getModelTransform(); const float MATERIAL_ENTITY_SCALE = 0.5f; _renderTransform.postScale(MATERIAL_ENTITY_SCALE); _renderTransform.postScale(ENTITY_ITEM_DEFAULT_DIMENSIONS); - - bool newTexturesLoaded = _drawMaterial ? !_drawMaterial->isMissingTexture() : false; - if (!_texturesLoaded && newTexturesLoaded) { - _drawMaterial->checkResetOpacityMap(); - } - _texturesLoaded = newTexturesLoaded; }); } @@ -61,8 +229,9 @@ ItemKey MaterialEntityRenderer::getKey() { builder.withInvisible(); } - if (_drawMaterial) { - auto matKey = _drawMaterial->getKey(); + const auto drawMaterial = getMaterial(); + if (drawMaterial) { + auto matKey = drawMaterial->getKey(); if (matKey.isTranslucent()) { builder.withTransparent(); } @@ -73,8 +242,9 @@ ItemKey MaterialEntityRenderer::getKey() { ShapeKey MaterialEntityRenderer::getShapeKey() { graphics::MaterialKey drawMaterialKey; - if (_drawMaterial) { - drawMaterialKey = _drawMaterial->getKey(); + const auto drawMaterial = getMaterial(); + if (drawMaterial) { + drawMaterialKey = drawMaterial->getKey(); } bool isTranslucent = drawMaterialKey.isTranslucent(); @@ -112,18 +282,24 @@ void MaterialEntityRenderer::doRender(RenderArgs* args) { // Don't render if our parent is set or our material is null QUuid parentID; + withReadLock([&] { + parentID = _parentID; + }); + if (!parentID.isNull()) { + return; + } + Transform renderTransform; graphics::MaterialPointer drawMaterial; Transform textureTransform; withReadLock([&] { - parentID = _parentID; renderTransform = _renderTransform; - drawMaterial = _drawMaterial; + drawMaterial = getMaterial(); textureTransform.setTranslation(glm::vec3(_materialMappingPos, 0)); textureTransform.setRotation(glm::vec3(0, 0, glm::radians(_materialMappingRot))); textureTransform.setScale(glm::vec3(_materialMappingScale, 1)); }); - if (!parentID.isNull() || !drawMaterial) { + if (!drawMaterial) { return; } @@ -142,3 +318,86 @@ void MaterialEntityRenderer::doRender(RenderArgs* args) { args->_details._trianglesRendered += (int)DependencyManager::get()->getSphereTriangleCount(); } + +void MaterialEntityRenderer::setCurrentMaterialName(const std::string& currentMaterialName) { + if (_parsedMaterials.networkMaterials.find(currentMaterialName) != _parsedMaterials.networkMaterials.end()) { + _currentMaterialName = currentMaterialName; + } else if (_parsedMaterials.names.size() > 0) { + _currentMaterialName = _parsedMaterials.names[0]; + } +} + +std::shared_ptr MaterialEntityRenderer::getMaterial() const { + auto material = _parsedMaterials.networkMaterials.find(_currentMaterialName); + if (material != _parsedMaterials.networkMaterials.end()) { + return material->second; + } else { + return nullptr; + } +} + +void MaterialEntityRenderer::deleteMaterial(const QUuid& oldParentID, const QString& oldParentMaterialName) { + std::shared_ptr material = _appliedMaterial; + if (!material || oldParentID.isNull()) { + return; + } + + // Our parent could be an entity or an avatar + std::string oldParentMaterialNameStd = oldParentMaterialName.toStdString(); + if (EntityTreeRenderer::removeMaterialFromEntity(oldParentID, material, oldParentMaterialNameStd)) { + _appliedMaterial = nullptr; + return; + } + + if (EntityTreeRenderer::removeMaterialFromAvatar(oldParentID, material, oldParentMaterialNameStd)) { + _appliedMaterial = nullptr; + return; + } + + // if a remove fails, our parent is gone, so we don't need to retry +} + +void MaterialEntityRenderer::applyTextureTransform(std::shared_ptr& material) { + Transform textureTransform; + if (_materialMappingMode == MaterialMappingMode::UV) { + textureTransform.setTranslation(glm::vec3(_materialMappingPos, 0.0f)); + textureTransform.setRotation(glm::vec3(0.0f, 0.0f, glm::radians(_materialMappingRot))); + textureTransform.setScale(glm::vec3(_materialMappingScale, 1.0f)); + } else if (_materialMappingMode == MaterialMappingMode::PROJECTED) { + textureTransform = _transform; + textureTransform.postScale(_dimensions); + // Pass the inverse transform here so we don't need to compute it in the shaders + textureTransform.evalFromRawMatrix(textureTransform.getInverseMatrix()); + } + material->setTextureTransforms(textureTransform, _materialMappingMode, _materialRepeat); +} + +void MaterialEntityRenderer::applyMaterial() { + _retryApply = false; + + std::shared_ptr material = getMaterial(); + QUuid parentID = _parentID; + if (!material || parentID.isNull()) { + _appliedMaterial = nullptr; + return; + } + + applyTextureTransform(material); + + graphics::MaterialLayer materialLayer = graphics::MaterialLayer(material, _priority); + + // Our parent could be an entity or an avatar + std::string parentMaterialName = _parentMaterialName.toStdString(); + if (EntityTreeRenderer::addMaterialToEntity(parentID, materialLayer, parentMaterialName)) { + _appliedMaterial = material; + return; + } + + if (EntityTreeRenderer::addMaterialToAvatar(parentID, materialLayer, parentMaterialName)) { + _appliedMaterial = material; + return; + } + + // if we've reached this point, we couldn't find our parent, so we need to try again later + _retryApply = true; +} \ No newline at end of file diff --git a/libraries/entities-renderer/src/RenderableMaterialEntityItem.h b/libraries/entities-renderer/src/RenderableMaterialEntityItem.h index c90048ecf5..d714727c7a 100644 --- a/libraries/entities-renderer/src/RenderableMaterialEntityItem.h +++ b/libraries/entities-renderer/src/RenderableMaterialEntityItem.h @@ -13,6 +13,8 @@ #include +#include + class NetworkMaterial; namespace render { namespace entities { @@ -22,22 +24,46 @@ class MaterialEntityRenderer : public TypedEntityRenderer { using Pointer = std::shared_ptr; public: MaterialEntityRenderer(const EntityItemPointer& entity) : Parent(entity) {} + ~MaterialEntityRenderer() { deleteMaterial(_parentID, _parentMaterialName); } private: + virtual bool needsRenderUpdate() const override; virtual bool needsRenderUpdateFromTypedEntity(const TypedEntityPointer& entity) const override; - virtual void doRenderUpdateSynchronousTyped(const ScenePointer& scene, Transaction& transaction, const TypedEntityPointer& entity) override; + virtual void doRenderUpdateAsynchronousTyped(const TypedEntityPointer& entity) override; virtual void doRender(RenderArgs* args) override; ItemKey getKey() override; ShapeKey getShapeKey() override; + QString _materialURL; + QString _materialData; + QString _parentMaterialName; + quint16 _priority; QUuid _parentID; + + MaterialMappingMode _materialMappingMode; + bool _materialRepeat; glm::vec2 _materialMappingPos; glm::vec2 _materialMappingScale; float _materialMappingRot; - bool _texturesLoaded { false }; + Transform _transform; + glm::vec3 _dimensions; + + bool _texturesLoaded { false }; + bool _retryApply { false }; + + std::shared_ptr getMaterial() const; + void setCurrentMaterialName(const std::string& currentMaterialName); + + void applyTextureTransform(std::shared_ptr& material); + void applyMaterial(); + void deleteMaterial(const QUuid& oldParentID, const QString& oldParentMaterialName); + + NetworkMaterialResourcePointer _networkMaterial; + NetworkMaterialResource::ParsedMaterials _parsedMaterials; + std::shared_ptr _appliedMaterial; + std::string _currentMaterialName; - std::shared_ptr _drawMaterial; }; } } diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp index ae9fdf572a..e842d98714 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp @@ -1079,7 +1079,7 @@ render::hifi::Tag ModelEntityRenderer::getTagMask() const { uint32_t ModelEntityRenderer::metaFetchMetaSubItems(ItemIDs& subItems) { if (_model) { - auto metaSubItems = _subRenderItemIDs; + auto metaSubItems = _model->fetchRenderItemIDs(); subItems.insert(subItems.end(), metaSubItems.begin(), metaSubItems.end()); return (uint32_t)metaSubItems.size(); } @@ -1321,11 +1321,8 @@ void ModelEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& sce if (!_hasModel) { if (model) { model->removeFromScene(scene, transaction); + entity->bumpAncestorChainRenderableVersion(); withWriteLock([&] { _model.reset(); }); - transaction.updateItem(getRenderItemID(), [](PayloadProxyInterface& data) { - auto entityRenderer = static_cast(&data); - entityRenderer->clearSubRenderItemIDs(); - }); emit DependencyManager::get()-> modelRemovedFromScene(entity->getEntityItemID(), NestableType::Entity, _model); } @@ -1442,12 +1439,7 @@ void ModelEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& sce render::Item::Status::Getters statusGetters; makeStatusGetters(entity, statusGetters); model->addToScene(scene, transaction, statusGetters); - - auto newRenderItemIDs{ model->fetchRenderItemIDs() }; - transaction.updateItem(getRenderItemID(), [newRenderItemIDs](PayloadProxyInterface& data) { - auto entityRenderer = static_cast(&data); - entityRenderer->setSubRenderItemIDs(newRenderItemIDs); - }); + entity->bumpAncestorChainRenderableVersion(); processMaterials(); } } diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 2c6d679b46..9f11b3c018 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -2935,6 +2935,7 @@ void EntityItem::setVisible(bool value) { }); if (changed) { + bumpAncestorChainRenderableVersion(); emit requestRenderUpdate(); } } @@ -3250,25 +3251,6 @@ void EntityItem::setSpaceIndex(int32_t index) { void EntityItem::preDelete() { } -void EntityItem::addMaterial(graphics::MaterialLayer material, const std::string& parentMaterialName) { - std::lock_guard lock(_materialsLock); - _materials[parentMaterialName].push(material); -} - -void EntityItem::removeMaterial(graphics::MaterialPointer material, const std::string& parentMaterialName) { - std::lock_guard lock(_materialsLock); - _materials[parentMaterialName].remove(material); -} - -std::unordered_map EntityItem::getMaterials() { - std::unordered_map toReturn; - { - std::lock_guard lock(_materialsLock); - toReturn = _materials; - } - return toReturn; -} - bool EntityItem::getCloneable() const { bool result; withReadLock([&] { diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index 5d6627d461..824261c022 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -37,8 +37,6 @@ #include "EntityDynamicInterface.h" #include "GrabPropertyGroup.h" -#include "graphics/Material.h" - class EntitySimulation; class EntityTreeElement; class EntityTreeElementExtraEncodeData; @@ -542,10 +540,6 @@ public: virtual void preDelete(); virtual void postParentFixup() {} - void addMaterial(graphics::MaterialLayer material, const std::string& parentMaterialName); - void removeMaterial(graphics::MaterialPointer material, const std::string& parentMaterialName); - std::unordered_map getMaterials(); - void setSimulationOwnershipExpiry(uint64_t expiry) { _simulationOwnershipExpiry = expiry; } uint64_t getSimulationOwnershipExpiry() const { return _simulationOwnershipExpiry; } @@ -754,11 +748,7 @@ protected: QHash _grabActions; private: - std::unordered_map _materials; - std::mutex _materialsLock; - static std::function _getBillboardRotationOperator; - }; #endif // hifi_EntityItem_h diff --git a/libraries/entities/src/EntityScriptingInterface.cpp b/libraries/entities/src/EntityScriptingInterface.cpp index 150aa6b0cf..22cd26eac6 100644 --- a/libraries/entities/src/EntityScriptingInterface.cpp +++ b/libraries/entities/src/EntityScriptingInterface.cpp @@ -941,7 +941,7 @@ QUuid EntityScriptingInterface::editEntity(const QUuid& id, const EntityItemProp auto nestable = nestableWP.lock(); if (nestable) { NestableType nestableType = nestable->getNestableType(); - if (nestableType == NestableType::Overlay || nestableType == NestableType::Avatar) { + if (nestableType == NestableType::Avatar) { qCWarning(entities) << "attempted edit on non-entity: " << id << nestable->getName(); return QUuid(); // null script value to indicate failure } diff --git a/libraries/entities/src/EntityTree.cpp b/libraries/entities/src/EntityTree.cpp index cfae8e250b..53b4fb4fe4 100644 --- a/libraries/entities/src/EntityTree.cpp +++ b/libraries/entities/src/EntityTree.cpp @@ -2953,41 +2953,9 @@ QStringList EntityTree::getJointNames(const QUuid& entityID) const { return entity->getJointNames(); } -std::function EntityTree::_addMaterialToEntityOperator = nullptr; -std::function EntityTree::_removeMaterialFromEntityOperator = nullptr; -std::function EntityTree::_addMaterialToAvatarOperator = nullptr; -std::function EntityTree::_removeMaterialFromAvatarOperator = nullptr; std::function EntityTree::_getEntityObjectOperator = nullptr; std::function EntityTree::_textSizeOperator = nullptr; -bool EntityTree::addMaterialToEntity(const QUuid& entityID, graphics::MaterialLayer material, const std::string& parentMaterialName) { - if (_addMaterialToEntityOperator) { - return _addMaterialToEntityOperator(entityID, material, parentMaterialName); - } - return false; -} - -bool EntityTree::removeMaterialFromEntity(const QUuid& entityID, graphics::MaterialPointer material, const std::string& parentMaterialName) { - if (_removeMaterialFromEntityOperator) { - return _removeMaterialFromEntityOperator(entityID, material, parentMaterialName); - } - return false; -} - -bool EntityTree::addMaterialToAvatar(const QUuid& avatarID, graphics::MaterialLayer material, const std::string& parentMaterialName) { - if (_addMaterialToAvatarOperator) { - return _addMaterialToAvatarOperator(avatarID, material, parentMaterialName); - } - return false; -} - -bool EntityTree::removeMaterialFromAvatar(const QUuid& avatarID, graphics::MaterialPointer material, const std::string& parentMaterialName) { - if (_removeMaterialFromAvatarOperator) { - return _removeMaterialFromAvatarOperator(avatarID, material, parentMaterialName); - } - return false; -} - QObject* EntityTree::getEntityObject(const QUuid& id) { if (_getEntityObjectOperator) { return _getEntityObjectOperator(id); diff --git a/libraries/entities/src/EntityTree.h b/libraries/entities/src/EntityTree.h index 9df01267ea..dcce0e4b99 100644 --- a/libraries/entities/src/EntityTree.h +++ b/libraries/entities/src/EntityTree.h @@ -262,16 +262,6 @@ public: void setIsServerlessMode(bool value) { _serverlessDomain = value; } bool isServerlessMode() const { return _serverlessDomain; } - static void setAddMaterialToEntityOperator(std::function addMaterialToEntityOperator) { _addMaterialToEntityOperator = addMaterialToEntityOperator; } - static void setRemoveMaterialFromEntityOperator(std::function removeMaterialFromEntityOperator) { _removeMaterialFromEntityOperator = removeMaterialFromEntityOperator; } - static bool addMaterialToEntity(const QUuid& entityID, graphics::MaterialLayer material, const std::string& parentMaterialName); - static bool removeMaterialFromEntity(const QUuid& entityID, graphics::MaterialPointer material, const std::string& parentMaterialName); - - static void setAddMaterialToAvatarOperator(std::function addMaterialToAvatarOperator) { _addMaterialToAvatarOperator = addMaterialToAvatarOperator; } - static void setRemoveMaterialFromAvatarOperator(std::function removeMaterialFromAvatarOperator) { _removeMaterialFromAvatarOperator = removeMaterialFromAvatarOperator; } - static bool addMaterialToAvatar(const QUuid& avatarID, graphics::MaterialLayer material, const std::string& parentMaterialName); - static bool removeMaterialFromAvatar(const QUuid& avatarID, graphics::MaterialPointer material, const std::string& parentMaterialName); - static void setGetEntityObjectOperator(std::function getEntityObjectOperator) { _getEntityObjectOperator = getEntityObjectOperator; } static QObject* getEntityObject(const QUuid& id); @@ -386,10 +376,6 @@ private: std::shared_ptr _myAvatar{ nullptr }; - static std::function _addMaterialToEntityOperator; - static std::function _removeMaterialFromEntityOperator; - static std::function _addMaterialToAvatarOperator; - static std::function _removeMaterialFromAvatarOperator; static std::function _getEntityObjectOperator; static std::function _textSizeOperator; diff --git a/libraries/entities/src/MaterialEntityItem.cpp b/libraries/entities/src/MaterialEntityItem.cpp index 1baa0b213a..3a363f2e83 100644 --- a/libraries/entities/src/MaterialEntityItem.cpp +++ b/libraries/entities/src/MaterialEntityItem.cpp @@ -16,9 +16,6 @@ EntityItemPointer MaterialEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) { Pointer entity(new MaterialEntityItem(entityID), [](EntityItem* ptr) { ptr->deleteLater(); }); entity->setProperties(properties); - // When you reload content, setProperties doesn't have any of the propertiesChanged flags set, so it won't trigger a material add - entity->removeMaterial(); - entity->applyMaterial(); return entity; } @@ -27,10 +24,6 @@ MaterialEntityItem::MaterialEntityItem(const EntityItemID& entityItemID) : Entit _type = EntityTypes::Material; } -MaterialEntityItem::~MaterialEntityItem() { - removeMaterial(); -} - EntityItemProperties MaterialEntityItem::getProperties(const EntityPropertyFlags& desiredProperties, bool allowEmptyDesiredProperties) const { EntityItemProperties properties = EntityItem::getProperties(desiredProperties, allowEmptyDesiredProperties); // get the properties from our base class COPY_ENTITY_PROPERTY_TO_PROPERTIES(materialURL, getMaterialURL); @@ -131,7 +124,6 @@ void MaterialEntityItem::debugDump() const { qCDebug(entities) << " MATERIAL EntityItem id:" << getEntityItemID() << "---------------------------------------------"; qCDebug(entities) << " name:" << _name; qCDebug(entities) << " material url:" << _materialURL; - qCDebug(entities) << " current material name:" << _currentMaterialName.c_str(); qCDebug(entities) << " material mapping mode:" << _materialMappingMode; qCDebug(entities) << " material repeat:" << _materialRepeat; qCDebug(entities) << " priority:" << _priority; @@ -154,208 +146,101 @@ void MaterialEntityItem::setUnscaledDimensions(const glm::vec3& value) { } } -std::shared_ptr MaterialEntityItem::getMaterial() const { - auto material = _parsedMaterials.networkMaterials.find(_currentMaterialName); - if (material != _parsedMaterials.networkMaterials.end()) { - return material->second; - } else { - return nullptr; - } +QString MaterialEntityItem::getMaterialURL() const { + return resultWithReadLock([&] { + return _materialURL; + }); } -void MaterialEntityItem::setMaterialURL(const QString& materialURLString, bool materialDataChanged) { - bool usingMaterialData = materialDataChanged || materialURLString.startsWith("materialData"); - if (_materialURL != materialURLString || (usingMaterialData && materialDataChanged)) { - removeMaterial(); - _materialURL = materialURLString; - - if (materialURLString.contains("?")) { - auto split = materialURLString.split("?"); - _currentMaterialName = split.last().toStdString(); - } - - if (usingMaterialData) { - _parsedMaterials = NetworkMaterialResource::parseJSONMaterials(QJsonDocument::fromJson(getMaterialData().toUtf8()), materialURLString); - - // Since our material changed, the current name might not be valid anymore, so we need to update - setCurrentMaterialName(_currentMaterialName); - applyMaterial(); - } else { - _networkMaterial = MaterialCache::instance().getMaterial(materialURLString); - auto onMaterialRequestFinished = [&](bool success) { - if (success) { - _parsedMaterials = _networkMaterial->parsedMaterials; - - setCurrentMaterialName(_currentMaterialName); - applyMaterial(); - } - }; - if (_networkMaterial) { - if (_networkMaterial->isLoaded()) { - onMaterialRequestFinished(!_networkMaterial->isFailed()); - } else { - connect(_networkMaterial.data(), &Resource::finished, this, onMaterialRequestFinished); - } - } - } - } +void MaterialEntityItem::setMaterialURL(const QString& materialURL) { + withWriteLock([&] { + _materialURL = materialURL; + }); } -void MaterialEntityItem::setCurrentMaterialName(const std::string& currentMaterialName) { - if (_parsedMaterials.networkMaterials.find(currentMaterialName) != _parsedMaterials.networkMaterials.end()) { - _currentMaterialName = currentMaterialName; - } else if (_parsedMaterials.names.size() > 0) { - _currentMaterialName = _parsedMaterials.names[0]; - } +QString MaterialEntityItem::getMaterialData() const { + return resultWithReadLock([&] { + return _materialData; + }); } void MaterialEntityItem::setMaterialData(const QString& materialData) { - if (_materialData != materialData) { + withWriteLock([&] { _materialData = materialData; - if (_materialURL.startsWith("materialData")) { - // Trigger material update when material data changes - setMaterialURL(_materialURL, true); - } - } + }); +} + +MaterialMappingMode MaterialEntityItem::getMaterialMappingMode() const { + return resultWithReadLock([&] { + return _materialMappingMode; + }); } void MaterialEntityItem::setMaterialMappingMode(MaterialMappingMode mode) { - if (_materialMappingMode != mode) { - removeMaterial(); + withWriteLock([&] { _materialMappingMode = mode; - setUnscaledDimensions(_desiredDimensions); - applyMaterial(); - } + }); + setUnscaledDimensions(_desiredDimensions); } -void MaterialEntityItem::setMaterialRepeat(bool repeat) { - if (_materialRepeat != repeat) { - removeMaterial(); - _materialRepeat = repeat; - applyMaterial(); - } -} - -void MaterialEntityItem::setMaterialMappingPos(const glm::vec2& materialMappingPos) { - if (_materialMappingPos != materialMappingPos) { - removeMaterial(); - _materialMappingPos = materialMappingPos; - applyMaterial(); - } -} - -void MaterialEntityItem::setMaterialMappingScale(const glm::vec2& materialMappingScale) { - if (_materialMappingScale != materialMappingScale) { - removeMaterial(); - _materialMappingScale = materialMappingScale; - applyMaterial(); - } -} - -void MaterialEntityItem::setMaterialMappingRot(const float& materialMappingRot) { - if (_materialMappingRot != materialMappingRot) { - removeMaterial(); - _materialMappingRot = materialMappingRot; - applyMaterial(); - } +quint16 MaterialEntityItem::getPriority() const { + return resultWithReadLock([&] { + return _priority; + }); } void MaterialEntityItem::setPriority(quint16 priority) { - if (_priority != priority) { - removeMaterial(); + withWriteLock([&] { _priority = priority; - applyMaterial(); - } + }); +} + +QString MaterialEntityItem::getParentMaterialName() const { + return resultWithReadLock([&] { + return _parentMaterialName; + }); } void MaterialEntityItem::setParentMaterialName(const QString& parentMaterialName) { - if (_parentMaterialName != parentMaterialName) { - removeMaterial(); + withWriteLock([&] { _parentMaterialName = parentMaterialName; - applyMaterial(); - } + }); } -void MaterialEntityItem::setParentID(const QUuid& parentID) { - if (getParentID() != parentID) { - removeMaterial(); - EntityItem::setParentID(parentID); - applyMaterial(); - } +glm::vec2 MaterialEntityItem::getMaterialMappingPos() const { + return resultWithReadLock([&] { + return _materialMappingPos; + }); } -void MaterialEntityItem::locationChanged(bool tellPhysics) { - EntityItem::locationChanged(); - if (_materialMappingMode == MaterialMappingMode::PROJECTED) { - removeMaterial(); - applyMaterial(); - } +void MaterialEntityItem::setMaterialMappingPos(const glm::vec2& materialMappingPos) { + withWriteLock([&] { + _materialMappingPos = materialMappingPos; + }); } -void MaterialEntityItem::dimensionsChanged() { - EntityItem::dimensionsChanged(); - if (_materialMappingMode == MaterialMappingMode::PROJECTED) { - removeMaterial(); - applyMaterial(); - } +glm::vec2 MaterialEntityItem::getMaterialMappingScale() const { + return resultWithReadLock([&] { + return _materialMappingScale; + }); } -void MaterialEntityItem::removeMaterial() { - graphics::MaterialPointer material = getMaterial(); - if (!material) { - return; - } - QUuid parentID = getParentID(); - if (parentID.isNull()) { - return; - } - - // Our parent could be an entity or an avatar - if (EntityTree::removeMaterialFromEntity(parentID, material, getParentMaterialName().toStdString())) { - return; - } - - if (EntityTree::removeMaterialFromAvatar(parentID, material, getParentMaterialName().toStdString())) { - return; - } - - // if a remove fails, our parent is gone, so we don't need to retry +void MaterialEntityItem::setMaterialMappingScale(const glm::vec2& materialMappingScale) { + withWriteLock([&] { + _materialMappingScale = materialMappingScale; + }); } -void MaterialEntityItem::applyMaterial() { - _retryApply = false; - graphics::MaterialPointer material = getMaterial(); - QUuid parentID = getParentID(); - if (!material || parentID.isNull()) { - return; - } +float MaterialEntityItem::getMaterialMappingRot() const { + return resultWithReadLock([&] { + return _materialMappingRot; + }); +} - Transform textureTransform; - if (_materialMappingMode == MaterialMappingMode::UV) { - textureTransform.setTranslation(glm::vec3(_materialMappingPos, 0.0f)); - textureTransform.setRotation(glm::vec3(0.0f, 0.0f, glm::radians(_materialMappingRot))); - textureTransform.setScale(glm::vec3(_materialMappingScale, 1.0f)); - } else if (_materialMappingMode == MaterialMappingMode::PROJECTED) { - textureTransform = getTransform(); - textureTransform.postScale(getUnscaledDimensions()); - // Pass the inverse transform here so we don't need to compute it in the shaders - textureTransform.evalFromRawMatrix(textureTransform.getInverseMatrix()); - } - material->setTextureTransforms(textureTransform, _materialMappingMode, _materialRepeat); - - graphics::MaterialLayer materialLayer = graphics::MaterialLayer(material, getPriority()); - - // Our parent could be an entity or an avatar - if (EntityTree::addMaterialToEntity(parentID, materialLayer, getParentMaterialName().toStdString())) { - return; - } - - if (EntityTree::addMaterialToAvatar(parentID, materialLayer, getParentMaterialName().toStdString())) { - return; - } - - // if we've reached this point, we couldn't find our parent, so we need to try again later - _retryApply = true; +void MaterialEntityItem::setMaterialMappingRot(float materialMappingRot) { + withWriteLock([&] { + _materialMappingRot = materialMappingRot; + }); } AACube MaterialEntityItem::calculateInitialQueryAACube(bool& success) { @@ -372,18 +257,3 @@ AACube MaterialEntityItem::calculateInitialQueryAACube(bool& success) { } return aaCube; } - -void MaterialEntityItem::postParentFixup() { - removeMaterial(); - _queryAACubeSet = false; // force an update so we contain our parent - updateQueryAACube(); - applyMaterial(); -} - -void MaterialEntityItem::update(const quint64& now) { - if (_retryApply) { - applyMaterial(); - } - - EntityItem::update(now); -} diff --git a/libraries/entities/src/MaterialEntityItem.h b/libraries/entities/src/MaterialEntityItem.h index 069c71c1d6..b9e83a7fe5 100644 --- a/libraries/entities/src/MaterialEntityItem.h +++ b/libraries/entities/src/MaterialEntityItem.h @@ -12,8 +12,6 @@ #include "EntityItem.h" #include "MaterialMappingMode.h" -#include -#include class MaterialEntityItem : public EntityItem { using Pointer = std::shared_ptr; @@ -21,13 +19,9 @@ public: static EntityItemPointer factory(const EntityItemID& entityID, const EntityItemProperties& properties); MaterialEntityItem(const EntityItemID& entityItemID); - ~MaterialEntityItem(); ALLOW_INSTANTIATION // This class can be instantiated - void update(const quint64& now) override; - bool needsToCallUpdate() const override { return true; } - // methods for getting/setting all properties of an entity virtual EntityItemProperties getProperties(const EntityPropertyFlags& desiredProperties, bool allowEmptyDesiredProperties) const override; virtual bool setProperties(const EntityItemProperties& properties) override; @@ -52,44 +46,30 @@ public: virtual void setUnscaledDimensions(const glm::vec3& value) override; - QString getMaterialURL() const { return _materialURL; } - void setMaterialURL(const QString& materialURLString, bool materialDataChanged = false); + QString getMaterialURL() const; + void setMaterialURL(const QString& materialURL); - void setCurrentMaterialName(const std::string& currentMaterialName); + QString getMaterialData() const; + void setMaterialData(const QString& materialData); - MaterialMappingMode getMaterialMappingMode() const { return _materialMappingMode; } + MaterialMappingMode getMaterialMappingMode() const; void setMaterialMappingMode(MaterialMappingMode mode); bool getMaterialRepeat() const { return _materialRepeat; } - void setMaterialRepeat(bool repeat); + void setMaterialRepeat(bool repeat) { _materialRepeat = repeat; } - quint16 getPriority() const { return _priority; } + quint16 getPriority() const; void setPriority(quint16 priority); - QString getParentMaterialName() const { return _parentMaterialName; } + QString getParentMaterialName() const; void setParentMaterialName(const QString& parentMaterialName); - glm::vec2 getMaterialMappingPos() const { return _materialMappingPos; } + glm::vec2 getMaterialMappingPos() const; void setMaterialMappingPos(const glm::vec2& materialMappingPos); - glm::vec2 getMaterialMappingScale() const { return _materialMappingScale; } + glm::vec2 getMaterialMappingScale() const; void setMaterialMappingScale(const glm::vec2& materialMappingScale); - float getMaterialMappingRot() const { return _materialMappingRot; } - void setMaterialMappingRot(const float& materialMappingRot); - - QString getMaterialData() const { return _materialData; } - void setMaterialData(const QString& materialData); - - std::shared_ptr getMaterial() const; - - void setParentID(const QUuid& parentID) override; - - void locationChanged(bool tellPhysics) override; - void dimensionsChanged() override; - - void applyMaterial(); - void removeMaterial(); - - void postParentFixup() override; + float getMaterialMappingRot() const; + void setMaterialMappingRot(float materialMappingRot); AACube calculateInitialQueryAACube(bool& success) override; @@ -128,12 +108,6 @@ private: float _materialMappingRot { 0 }; QString _materialData; - NetworkMaterialResourcePointer _networkMaterial; - NetworkMaterialResource::ParsedMaterials _parsedMaterials; - std::string _currentMaterialName; - - bool _retryApply { false }; - }; #endif // hifi_MaterialEntityItem_h diff --git a/libraries/gpu/src/gpu/FrameReader.cpp b/libraries/gpu/src/gpu/FrameReader.cpp index 6e39a38097..2fe143ee90 100644 --- a/libraries/gpu/src/gpu/FrameReader.cpp +++ b/libraries/gpu/src/gpu/FrameReader.cpp @@ -388,10 +388,23 @@ ShaderPointer Deserializer::readShader(const json& node) { return nullptr; } + static std::map shadersIdsByName; + if (shadersIdsByName.empty()) { + for (const auto id : shader::allShaders()) { + const auto& shaderSource = shader::Source::get(id); + shadersIdsByName[shaderSource.name] = id; + } + } + // FIXME support procedural shaders Shader::Type type = node[keys::type]; std::string name = node[keys::name]; - uint32_t id = node[keys::id]; + // Using the serialized ID is bad, because it's generated at + // cmake time, and can change across platforms or when + // shaders are added or removed + // uint32_t id = node[keys::id]; + + uint32_t id = shadersIdsByName[name]; ShaderPointer result; switch (type) { //case Shader::Type::GEOMETRY: diff --git a/libraries/gpu/src/gpu/Transform.slh b/libraries/gpu/src/gpu/Transform.slh index 43205ba4c2..3015de7e0e 100644 --- a/libraries/gpu/src/gpu/Transform.slh +++ b/libraries/gpu/src/gpu/Transform.slh @@ -167,7 +167,7 @@ TransformObject getTransformObject() { vec4 eyeClipEdge[2]= vec4[2](vec4(-1,0,0,1), vec4(1,0,0,1)); vec2 eyeOffsetScale = vec2(-0.5, +0.5); uint eyeIndex = uint(_stereoSide); -#ifndef GPU_GLES +#if !defined(GPU_GLES) || (defined(HAVE_EXT_clip_cull_distance) && !defined(VULKAN)) gl_ClipDistance[0] = dot(<$clipPos$>, eyeClipEdge[eyeIndex]); #endif float newClipPosX = <$clipPos$>.x * 0.5 + eyeOffsetScale[eyeIndex] * <$clipPos$>.w; diff --git a/libraries/input-plugins/src/input-plugins/TouchscreenVirtualPadDevice.cpp b/libraries/input-plugins/src/input-plugins/TouchscreenVirtualPadDevice.cpp index 247f484c95..6bb743bad0 100644 --- a/libraries/input-plugins/src/input-plugins/TouchscreenVirtualPadDevice.cpp +++ b/libraries/input-plugins/src/input-plugins/TouchscreenVirtualPadDevice.cpp @@ -66,7 +66,7 @@ void TouchscreenVirtualPadDevice::resize() { _fixedRadius = _screenDPI * 0.5f * VirtualPad::Manager::BASE_DIAMETER_PIXELS / VirtualPad::Manager::DPI; _fixedRadiusForCalc = _fixedRadius - _screenDPI * VirtualPad::Manager::STICK_RADIUS_PIXELS / VirtualPad::Manager::DPI; - _jumpButtonRadius = _screenDPI * VirtualPad::Manager::JUMP_BTN_TRIMMED_RADIUS_PIXELS / VirtualPad::Manager::DPI; + _buttonRadius = _screenDPI * VirtualPad::Manager::BTN_TRIMMED_RADIUS_PIXELS / VirtualPad::Manager::DPI; } auto& virtualPadManager = VirtualPad::Manager::instance(); @@ -86,11 +86,21 @@ void TouchscreenVirtualPadDevice::setupControlsPositions(VirtualPad::Manager& vi virtualPadManager.getLeftVirtualPad()->setFirstTouch(_moveRefTouchPoint); // Jump button - 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( eventScreen->availableSize().width() - rightMargin - jumpBtnPixelSize, eventScreen->availableSize().height() - bottomMargin - _jumpButtonRadius - _extraBottomMargin); - virtualPadManager.setJumpButtonPosition(_jumpButtonPosition); + float btnPixelSize = _screenDPI * VirtualPad::Manager::BTN_FULL_PIXELS / VirtualPad::Manager::DPI; + float rightMargin = _screenDPI * VirtualPad::Manager::BTN_RIGHT_MARGIN_PIXELS / VirtualPad::Manager::DPI; + float bottomMargin = _screenDPI * VirtualPad::Manager::BTN_BOTTOM_MARGIN_PIXELS/ VirtualPad::Manager::DPI; + glm::vec2 jumpButtonPosition = glm::vec2( eventScreen->availableSize().width() - rightMargin - btnPixelSize, eventScreen->availableSize().height() - bottomMargin - _buttonRadius - _extraBottomMargin); + glm::vec2 rbButtonPosition = glm::vec2( eventScreen->availableSize().width() - rightMargin - btnPixelSize, eventScreen->availableSize().height() - 2 * bottomMargin - 3 * _buttonRadius - _extraBottomMargin); + + // Avoid generating buttons in portrait mode + if ( eventScreen->availableSize().width() > eventScreen->availableSize().height() && _buttonsManager.buttonsCount() == 0) { + _buttonsManager.addButton(TouchscreenButton(JUMP, JUMP_BUTTON, _buttonRadius, jumpButtonPosition, _inputDevice )); + _buttonsManager.addButton(TouchscreenButton(RB, RB_BUTTON, _buttonRadius, rbButtonPosition, _inputDevice )); + + virtualPadManager.setButtonPosition(VirtualPad::Manager::Button::JUMP, jumpButtonPosition); + virtualPadManager.setButtonPosition(VirtualPad::Manager::Button::HANDSHAKE, rbButtonPosition); + } + } float clip(float n, float lower, float upper) { @@ -237,7 +247,7 @@ void TouchscreenVirtualPadDevice::touchEndEvent(const QTouchEvent* event) { if (!virtualPadManager.isEnabled() && !virtualPadManager.isHidden()) { moveTouchEnd(); viewTouchEnd(); - jumpTouchEnd(); + _buttonsManager.endTouchForAll(); return; } // touch end here is a big reset -> resets both pads @@ -246,7 +256,7 @@ void TouchscreenVirtualPadDevice::touchEndEvent(const QTouchEvent* event) { debugPoints(event, " END ----------------"); moveTouchEnd(); viewTouchEnd(); - jumpTouchEnd(); + _buttonsManager.endTouchForAll(); _inputDevice->_axisStateMap.clear(); _inputDevice->_buttonPressedMap.clear(); } @@ -282,11 +292,11 @@ void TouchscreenVirtualPadDevice::touchUpdateEvent(const QTouchEvent* event) { const QList& tPoints = event->touchPoints(); bool moveTouchFound = false; bool viewTouchFound = false; - bool jumpTouchFound = false; int idxMoveStartingPointCandidate = -1; int idxViewStartingPointCandidate = -1; - int idxJumpStartingPointCandidate = -1; + + _buttonsManager.resetEventValues(); glm::vec2 thisPoint; int thisPointId; @@ -311,10 +321,7 @@ void TouchscreenVirtualPadDevice::touchUpdateEvent(const QTouchEvent* event) { continue; } - if (!jumpTouchFound && _jumpHasValidTouch && _jumpCurrentTouchId == thisPointId) { - // valid if it's an ongoing touch - jumpTouchFound = true; - jumpTouchUpdate(thisPoint); + if (_buttonsManager.processOngoingTouch(thisPoint, thisPointId)) { continue; } @@ -330,18 +337,16 @@ void TouchscreenVirtualPadDevice::touchUpdateEvent(const QTouchEvent* event) { continue; } - if (!jumpTouchFound && idxJumpStartingPointCandidate == -1 && jumpTouchBeginIsValid(thisPoint) && - (!_unusedTouches.count(thisPointId) || _unusedTouches[thisPointId] == JUMP )) { - idxJumpStartingPointCandidate = i; + if (_buttonsManager.findStartingTouchPointCandidate(thisPoint, thisPointId, i, _unusedTouches)) { continue; } if (moveTouchBeginIsValid(thisPoint)) { unusedTouchesInEvent[thisPointId] = MOVE; - } else if (jumpTouchBeginIsValid(thisPoint)) { - unusedTouchesInEvent[thisPointId] = JUMP; } else if (viewTouchBeginIsValid(thisPoint)) { unusedTouchesInEvent[thisPointId] = VIEW; + } else { + _buttonsManager.saveUnusedTouches(unusedTouchesInEvent, thisPoint, thisPointId); } } @@ -370,24 +375,13 @@ void TouchscreenVirtualPadDevice::touchUpdateEvent(const QTouchEvent* event) { viewTouchEnd(); } } - if (!jumpTouchFound) { - if (idxJumpStartingPointCandidate != -1) { - _jumpCurrentTouchId = tPoints[idxJumpStartingPointCandidate].id(); - _unusedTouches.erase(_jumpCurrentTouchId); - thisPoint.x = tPoints[idxJumpStartingPointCandidate].pos().x(); - thisPoint.y = tPoints[idxJumpStartingPointCandidate].pos().y(); - jumpTouchBegin(thisPoint); - } else { - if (_jumpHasValidTouch) { - jumpTouchEnd(); - } - } - } + + _buttonsManager.processBeginOrEnd(thisPoint, tPoints, _unusedTouches); } bool TouchscreenVirtualPadDevice::viewTouchBeginIsValid(glm::vec2 touchPoint) { - return !moveTouchBeginIsValid(touchPoint) && !jumpTouchBeginIsValid(touchPoint); + return !moveTouchBeginIsValid(touchPoint) && _buttonsManager.touchBeginInvalidForAllButtons(touchPoint); } bool TouchscreenVirtualPadDevice::moveTouchBeginIsValid(glm::vec2 touchPoint) { @@ -400,30 +394,6 @@ bool TouchscreenVirtualPadDevice::moveTouchBeginIsValid(glm::vec2 touchPoint) { } } -bool TouchscreenVirtualPadDevice::jumpTouchBeginIsValid(glm::vec2 touchPoint) { - // position of button and boundaries - return glm::distance2(touchPoint, _jumpButtonPosition) < _jumpButtonRadius * _jumpButtonRadius; -} - -void TouchscreenVirtualPadDevice::jumpTouchBegin(glm::vec2 touchPoint) { - auto& virtualPadManager = VirtualPad::Manager::instance(); - if (virtualPadManager.isEnabled() && !virtualPadManager.isHidden()) { - _jumpHasValidTouch = true; - - _inputDevice->_buttonPressedMap.insert(TouchButtonChannel::JUMP_BUTTON_PRESS); - } -} - -void TouchscreenVirtualPadDevice::jumpTouchUpdate(glm::vec2 touchPoint) {} - -void TouchscreenVirtualPadDevice::jumpTouchEnd() { - if (_jumpHasValidTouch) { - _jumpHasValidTouch = false; - - _inputDevice->_buttonPressedMap.erase(TouchButtonChannel::JUMP_BUTTON_PRESS); - } -} - void TouchscreenVirtualPadDevice::moveTouchBegin(glm::vec2 touchPoint) { auto& virtualPadManager = VirtualPad::Manager::instance(); if (virtualPadManager.isEnabled() && !virtualPadManager.isHidden()) { @@ -498,7 +468,8 @@ controller::Input::NamedVector TouchscreenVirtualPadDevice::InputDevice::getAvai Input::NamedPair(makeInput(TouchAxisChannel::LY), "LY"), Input::NamedPair(makeInput(TouchAxisChannel::RX), "RX"), Input::NamedPair(makeInput(TouchAxisChannel::RY), "RY"), - Input::NamedPair(makeInput(TouchButtonChannel::JUMP_BUTTON_PRESS), "JUMP_BUTTON_PRESS") + Input::NamedPair(makeInput(TouchButtonChannel::JUMP), "JUMP_BUTTON_PRESS"), + Input::NamedPair(makeInput(TouchButtonChannel::RB), "RB") }; return availableInputs; } @@ -507,3 +478,146 @@ QString TouchscreenVirtualPadDevice::InputDevice::getDefaultMappingConfig() cons static const QString MAPPING_JSON = PathUtils::resourcesPath() + "/controllers/touchscreenvirtualpad.json"; return MAPPING_JSON; } + +TouchscreenVirtualPadDevice::TouchscreenButton::TouchscreenButton( + TouchscreenVirtualPadDevice::TouchButtonChannel channelIn, + TouchscreenVirtualPadDevice::TouchType touchTypeIn, float buttonRadiusIn, + glm::vec2 buttonPositionIn, std::shared_ptr inputDeviceIn) : + buttonPosition(buttonPositionIn), + buttonRadius(buttonRadiusIn), + touchType(touchTypeIn), + channel(channelIn), + _inputDevice(inputDeviceIn) +{ +} + +void TouchscreenVirtualPadDevice::TouchscreenButton::touchBegin(glm::vec2 touchPoint) { + auto& virtualPadManager = VirtualPad::Manager::instance(); + if (virtualPadManager.isEnabled() && !virtualPadManager.isHidden()) { + hasValidTouch = true; + + _inputDevice->_buttonPressedMap.insert(channel); + } +} + +void TouchscreenVirtualPadDevice::TouchscreenButton::touchUpdate(glm::vec2 touchPoint) { + +} + +void TouchscreenVirtualPadDevice::TouchscreenButton::touchEnd() { + if (hasValidTouch) { + hasValidTouch = false; + + _inputDevice->_buttonPressedMap.erase(channel); + } +} + +bool TouchscreenVirtualPadDevice::TouchscreenButton::touchBeginIsValid(glm::vec2 touchPoint) { + return glm::distance2(touchPoint, buttonPosition) < buttonRadius * buttonRadius; +} + +void TouchscreenVirtualPadDevice::TouchscreenButton::resetEventValues() { + _candidatePointIdx = -1; + _found = false; +} + +TouchscreenVirtualPadDevice::TouchscreenButtonsManager::TouchscreenButtonsManager() {} + +void TouchscreenVirtualPadDevice::TouchscreenButtonsManager::addButton( + TouchscreenVirtualPadDevice::TouchscreenButton button) { + buttons.push_back(button); +} + +void TouchscreenVirtualPadDevice::TouchscreenButtonsManager::resetEventValues() { + for(int i = 0; i < buttons.size(); i++) { + TouchscreenButton &button = buttons[i]; + button.resetEventValues(); + } +} + +bool +TouchscreenVirtualPadDevice::TouchscreenButtonsManager::processOngoingTouch(glm::vec2 thisPoint, + int thisPointId) { + for(int i = 0; i < buttons.size(); i++) { + TouchscreenButton &button = buttons[i]; + + if (!button._found && button.hasValidTouch && button.currentTouchId == thisPointId) { + // valid if it's an ongoing touch + button._found = true; + button.touchUpdate(thisPoint); + return true; + } + } + return false; + +} + +bool TouchscreenVirtualPadDevice::TouchscreenButtonsManager::findStartingTouchPointCandidate( + glm::vec2 thisPoint, int thisPointId, int thisPointIdx, std::map &globalUnusedTouches) { + + for(int i = 0; i < buttons.size(); i++) { + TouchscreenButton &button = buttons[i]; + if (!button._found && button._candidatePointIdx == -1 && button.touchBeginIsValid(thisPoint)) { + if (!globalUnusedTouches.count(thisPointId) ) { + button._candidatePointIdx = thisPointIdx; + return true; + } else if (globalUnusedTouches[thisPointId] == button.touchType) { + button._candidatePointIdx = thisPointIdx; + return true; + } + } + } + return false; + +} + +void TouchscreenVirtualPadDevice::TouchscreenButtonsManager::saveUnusedTouches( + std::map &unusedTouchesInEvent, glm::vec2 thisPoint, + int thisPointId) { + for(int i = 0; i < buttons.size(); i++) { + TouchscreenButton &button = buttons[i]; + if (button.touchBeginIsValid(thisPoint)) { + unusedTouchesInEvent[thisPointId] = button.touchType; + return; + } + } + +} + +void TouchscreenVirtualPadDevice::TouchscreenButtonsManager::processBeginOrEnd( + glm::vec2 thisPoint, const QList &tPoints, std::map globalUnusedTouches) { + for(int i = 0; i < buttons.size(); i++) { + TouchscreenButton &button = buttons[i]; + if (!button._found) { + if (button._candidatePointIdx != -1) { + button.currentTouchId = tPoints[button._candidatePointIdx].id(); + globalUnusedTouches.erase(button.currentTouchId); + thisPoint.x = tPoints[button._candidatePointIdx].pos().x(); + thisPoint.y = tPoints[button._candidatePointIdx].pos().y(); + button.touchBegin(thisPoint); + } else { + if (button.hasValidTouch) { + button.touchEnd(); + } + } + } + } + +} + +void TouchscreenVirtualPadDevice::TouchscreenButtonsManager::endTouchForAll() { + for(int i = 0; i < buttons.size(); i++) { + TouchscreenButton &button = buttons[i]; + button.touchEnd(); + } +} + +bool TouchscreenVirtualPadDevice::TouchscreenButtonsManager::touchBeginInvalidForAllButtons(glm::vec2 touchPoint) { + for(int i = 0; i < buttons.size(); i++) { + TouchscreenButton &button = buttons[i]; + if (button.touchBeginIsValid(touchPoint)) { + return false; + } + } + return true; +} diff --git a/libraries/input-plugins/src/input-plugins/TouchscreenVirtualPadDevice.h b/libraries/input-plugins/src/input-plugins/TouchscreenVirtualPadDevice.h index ef1e7a4d89..4ef1dbd4f6 100644 --- a/libraries/input-plugins/src/input-plugins/TouchscreenVirtualPadDevice.h +++ b/libraries/input-plugins/src/input-plugins/TouchscreenVirtualPadDevice.h @@ -15,6 +15,7 @@ #include #include "InputPlugin.h" #include +#include #include "VirtualPadManager.h" class QTouchEvent; @@ -51,7 +52,8 @@ public: }; enum TouchButtonChannel { - JUMP_BUTTON_PRESS + JUMP, + RB }; protected: @@ -82,7 +84,60 @@ protected: enum TouchType { MOVE = 1, VIEW, - JUMP + JUMP_BUTTON, + RB_BUTTON + }; + + class TouchscreenButton { + public: + + TouchscreenButton() {}; + + TouchscreenButton(TouchButtonChannel channelIn, TouchType touchTypeIn, float buttonRadiusIn, glm::vec2 buttonPositionIn, + std::shared_ptr inputDeviceIn); + + void touchBegin(glm::vec2 touchPoint); + void touchUpdate(glm::vec2 touchPoint); + void touchEnd(); + bool touchBeginIsValid(glm::vec2 touchPoint); + + bool hasValidTouch { false }; + int currentTouchId; + + // per event tmp values + int _candidatePointIdx { -1 }; + bool _found { false }; + void resetEventValues(); + + glm::vec2 buttonPosition; + float buttonRadius; + TouchType touchType; + TouchButtonChannel channel; + + std::shared_ptr _inputDevice; + + }; + + class TouchscreenButtonsManager { + public: + + TouchscreenButtonsManager(); + + QVector buttons; + + void addButton(TouchscreenButton button); + int buttonsCount() { + return buttons.size(); + } + + void resetEventValues(); + bool processOngoingTouch(glm::vec2 thisPoint, int thisPointId); + bool findStartingTouchPointCandidate(glm::vec2 thisPoint, int thisPointId, int thisPointIdx, std::map &globalUnusedTouches); + void saveUnusedTouches(std::map &unusedTouchesInEvent, glm::vec2 thisPoint, int thisPointId); + void processBeginOrEnd(glm::vec2 thisPoint, const QList& tPoints, std::map globalUnusedTouches); + + void endTouchForAll(); + bool touchBeginInvalidForAllButtons(glm::vec2 touchPoint); }; float _lastPinchScale; @@ -101,9 +156,6 @@ protected: glm::vec2 _viewCurrentTouchPoint; int _viewCurrentTouchId; - bool _jumpHasValidTouch; - int _jumpCurrentTouchId; - std::map _unusedTouches; int _touchPointCount; @@ -116,8 +168,9 @@ protected: float _fixedRadiusForCalc; int _extraBottomMargin {0}; - glm::vec2 _jumpButtonPosition; - float _jumpButtonRadius; + float _buttonRadius; + + TouchscreenButtonsManager _buttonsManager; void moveTouchBegin(glm::vec2 touchPoint); void moveTouchUpdate(glm::vec2 touchPoint); @@ -129,11 +182,6 @@ protected: void viewTouchEnd(); bool viewTouchBeginIsValid(glm::vec2 touchPoint); - void jumpTouchBegin(glm::vec2 touchPoint); - void jumpTouchUpdate(glm::vec2 touchPoint); - void jumpTouchEnd(); - bool jumpTouchBeginIsValid(glm::vec2 touchPoint); - void setupControlsPositions(VirtualPad::Manager& virtualPadManager, bool force = false); void processInputDeviceForMove(VirtualPad::Manager& virtualPadManager); diff --git a/libraries/material-networking/src/material-networking/TextureCache.cpp b/libraries/material-networking/src/material-networking/TextureCache.cpp index 9a9720c87d..43f467266a 100644 --- a/libraries/material-networking/src/material-networking/TextureCache.cpp +++ b/libraries/material-networking/src/material-networking/TextureCache.cpp @@ -354,7 +354,8 @@ NetworkTexture::NetworkTexture(const NetworkTexture& other) : _originalHeight(other._originalHeight), _width(other._width), _height(other._height), - _maxNumPixels(other._maxNumPixels) + _maxNumPixels(other._maxNumPixels), + _content(other._content) { if (_width == 0 || _height == 0 || other._currentlyLoadingResourceType == ResourceType::META || @@ -368,17 +369,30 @@ static bool isLocalUrl(const QUrl& url) { return (scheme == HIFI_URL_SCHEME_FILE || scheme == URL_SCHEME_QRC || scheme == RESOURCE_SCHEME); } -void NetworkTexture::setExtra(void* extra, bool isNewExtra) { +void NetworkTexture::setExtra(void* extra) { const TextureExtra* textureExtra = static_cast(extra); - _type = textureExtra ? textureExtra->type : image::TextureUsage::DEFAULT_TEXTURE; _maxNumPixels = textureExtra ? textureExtra->maxNumPixels : ABSOLUTE_MAX_TEXTURE_NUM_PIXELS; - _sourceChannel = textureExtra ? textureExtra->sourceChannel : image::ColorChannel::NONE; - if (isNewExtra && !_loaded) { + bool needsNewTextureSource = false; + auto type = textureExtra ? textureExtra->type : image::TextureUsage::DEFAULT_TEXTURE; + auto sourceChannel = textureExtra ? textureExtra->sourceChannel : image::ColorChannel::NONE; + if (type != _type || sourceChannel != _sourceChannel) { + needsNewTextureSource = true; + } + _type = type; + _sourceChannel = sourceChannel; + + auto content = textureExtra ? textureExtra->content : QByteArray(); + if (_content.isEmpty() && !content.isEmpty()) { + _content = content; + needsNewTextureSource = true; + } + + if (needsNewTextureSource) { _startedLoading = false; } - if (!_textureSource || isNewExtra) { + if (!_textureSource || needsNewTextureSource) { _textureSource = std::make_shared(_url, (int)_type); } _lowestRequestedMipLevel = 0; @@ -405,10 +419,9 @@ void NetworkTexture::setExtra(void* extra, bool isNewExtra) { } // if we have content, load it after we have our self pointer - auto content = textureExtra ? textureExtra->content : QByteArray(); - if (!content.isEmpty()) { + if (!_content.isEmpty()) { _startedLoading = true; - QMetaObject::invokeMethod(this, "downloadFinished", Qt::QueuedConnection, Q_ARG(const QByteArray&, content)); + QMetaObject::invokeMethod(this, "downloadFinished", Qt::QueuedConnection, Q_ARG(const QByteArray&, _content)); } } diff --git a/libraries/material-networking/src/material-networking/TextureCache.h b/libraries/material-networking/src/material-networking/TextureCache.h index a8b152c40e..dcab527e4a 100644 --- a/libraries/material-networking/src/material-networking/TextureCache.h +++ b/libraries/material-networking/src/material-networking/TextureCache.h @@ -64,7 +64,7 @@ public: Q_INVOKABLE void setOriginalDescriptor(ktx::KTXDescriptor* descriptor) { _originalKtxDescriptor.reset(descriptor); } - void setExtra(void* extra, bool isNewExtra) override; + void setExtra(void* extra) override; signals: void networkTextureCreated(const QWeakPointer& self); @@ -136,12 +136,12 @@ private: // mip offsets to change. ktx::KTXDescriptorPointer _originalKtxDescriptor; - int _originalWidth { 0 }; int _originalHeight { 0 }; int _width { 0 }; int _height { 0 }; int _maxNumPixels { ABSOLUTE_MAX_TEXTURE_NUM_PIXELS }; + QByteArray _content; friend class TextureCache; }; diff --git a/libraries/model-networking/src/model-networking/ModelCache.cpp b/libraries/model-networking/src/model-networking/ModelCache.cpp index b2645d20c8..581196b2cc 100644 --- a/libraries/model-networking/src/model-networking/ModelCache.cpp +++ b/libraries/model-networking/src/model-networking/ModelCache.cpp @@ -309,7 +309,7 @@ public: virtual void downloadFinished(const QByteArray& data) override; - void setExtra(void* extra, bool isNewExtra) override; + void setExtra(void* extra) override; protected: Q_INVOKABLE void setGeometryDefinition(HFMModel::Pointer hfmModel, QVariantHash mapping); @@ -320,7 +320,7 @@ private: bool _combineParts; }; -void GeometryDefinitionResource::setExtra(void* extra, bool isNewExtra) { +void GeometryDefinitionResource::setExtra(void* extra) { const GeometryExtra* geometryExtra = static_cast(extra); _mapping = geometryExtra ? geometryExtra->mapping : QVariantHash(); _textureBaseUrl = geometryExtra ? resolveTextureBaseUrl(_url, geometryExtra->textureBaseUrl) : QUrl(); diff --git a/libraries/networking/src/ResourceCache.cpp b/libraries/networking/src/ResourceCache.cpp index 8ad1b41020..7345081380 100644 --- a/libraries/networking/src/ResourceCache.cpp +++ b/libraries/networking/src/ResourceCache.cpp @@ -355,7 +355,7 @@ QSharedPointer ResourceCache::getResource(const QUrl& url, const QUrl& } else if (resourcesWithExtraHash.size() > 0.0f) { // We haven't seen this extra info before, but we've already downloaded the resource. We need a new copy of this object (with any old hash). resource = createResourceCopy(resourcesWithExtraHash.begin().value().lock()); - resource->setExtra(extra, true); + resource->setExtra(extra); resource->setExtraHash(extraHash); resource->setSelf(resource); resource->setCache(this); @@ -375,7 +375,7 @@ QSharedPointer ResourceCache::getResource(const QUrl& url, const QUrl& if (!resource) { resource = createResource(url); - resource->setExtra(extra, false); + resource->setExtra(extra); resource->setExtraHash(extraHash); resource->setSelf(resource); resource->setCache(this); diff --git a/libraries/networking/src/ResourceCache.h b/libraries/networking/src/ResourceCache.h index 62800a6ac2..2096213273 100644 --- a/libraries/networking/src/ResourceCache.h +++ b/libraries/networking/src/ResourceCache.h @@ -417,7 +417,7 @@ public: unsigned int getDownloadAttempts() { return _attempts; } unsigned int getDownloadAttemptsRemaining() { return _attemptsRemaining; } - virtual void setExtra(void* extra, bool isNewExtra) {}; + virtual void setExtra(void* extra) {}; void setExtraHash(size_t extraHash) { _extraHash = extraHash; } size_t getExtraHash() const { return _extraHash; } diff --git a/libraries/oculusMobile/src/ovr/VrHandler.cpp b/libraries/oculusMobile/src/ovr/VrHandler.cpp index de2b4e1ff6..b3b1416785 100644 --- a/libraries/oculusMobile/src/ovr/VrHandler.cpp +++ b/libraries/oculusMobile/src/ovr/VrHandler.cpp @@ -315,10 +315,6 @@ JNIEXPORT void JNICALL Java_io_highfidelity_oculus_OculusMobileActivity_nativeOn SURFACE.onCreate(env, obj); } -JNIEXPORT void JNICALL Java_io_highfidelity_oculus_OculusMobileActivity_nativeOnDestroy(JNIEnv*, jclass) { - __android_log_write(ANDROID_LOG_WARN, "QQQ_JNI", __FUNCTION__); -} - JNIEXPORT void JNICALL Java_io_highfidelity_oculus_OculusMobileActivity_nativeOnResume(JNIEnv*, jclass) { __android_log_write(ANDROID_LOG_WARN, "QQQ_JNI", __FUNCTION__); SURFACE.setResumed(true); diff --git a/libraries/pointers/src/PickManager.cpp b/libraries/pointers/src/PickManager.cpp index d3326ea8b4..0cf5f90e3d 100644 --- a/libraries/pointers/src/PickManager.cpp +++ b/libraries/pointers/src/PickManager.cpp @@ -6,6 +6,8 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // #include "PickManager.h" +#include "PerfStat.h" +#include "Profile.h" PickManager::PickManager() { setShouldPickHUDOperator([]() { return false; }); @@ -119,10 +121,26 @@ void PickManager::update() { bool shouldPickHUD = _shouldPickHUDOperator(); // FIXME: give each type its own expiry // Each type will update at least one pick, regardless of the expiry - _updatedPickCounts[PickQuery::Stylus] = _stylusPickCacheOptimizer.update(cachedPicks[PickQuery::Stylus], _nextPickToUpdate[PickQuery::Stylus], expiry, false); - _updatedPickCounts[PickQuery::Ray] = _rayPickCacheOptimizer.update(cachedPicks[PickQuery::Ray], _nextPickToUpdate[PickQuery::Ray], expiry, shouldPickHUD); - _updatedPickCounts[PickQuery::Parabola] = _parabolaPickCacheOptimizer.update(cachedPicks[PickQuery::Parabola], _nextPickToUpdate[PickQuery::Parabola], expiry, shouldPickHUD); - _updatedPickCounts[PickQuery::Collision] = _collisionPickCacheOptimizer.update(cachedPicks[PickQuery::Collision], _nextPickToUpdate[PickQuery::Collision], expiry, false); + { + PROFILE_RANGE(picks, "StylusPicks"); + PerformanceTimer perfTimer("StylusPicks"); + _updatedPickCounts[PickQuery::Stylus] = _stylusPickCacheOptimizer.update(cachedPicks[PickQuery::Stylus], _nextPickToUpdate[PickQuery::Stylus], expiry, false); + } + { + PROFILE_RANGE(picks, "RayPicks"); + PerformanceTimer perfTimer("RayPicks"); + _updatedPickCounts[PickQuery::Ray] = _rayPickCacheOptimizer.update(cachedPicks[PickQuery::Ray], _nextPickToUpdate[PickQuery::Ray], expiry, shouldPickHUD); + } + { + PROFILE_RANGE(picks, "ParabolaPick"); + PerformanceTimer perfTimer("ParabolaPick"); + _updatedPickCounts[PickQuery::Parabola] = _parabolaPickCacheOptimizer.update(cachedPicks[PickQuery::Parabola], _nextPickToUpdate[PickQuery::Parabola], expiry, shouldPickHUD); + } + { + PROFILE_RANGE(picks, "CollisoinPicks"); + PerformanceTimer perfTimer("CollisionPicks"); + _updatedPickCounts[PickQuery::Collision] = _collisionPickCacheOptimizer.update(cachedPicks[PickQuery::Collision], _nextPickToUpdate[PickQuery::Collision], expiry, false); + } } bool PickManager::isLeftHand(unsigned int uid) { diff --git a/libraries/render-utils/src/AmbientOcclusionEffect.cpp b/libraries/render-utils/src/AmbientOcclusionEffect.cpp index b1ca24de1f..ee53347158 100644 --- a/libraries/render-utils/src/AmbientOcclusionEffect.cpp +++ b/libraries/render-utils/src/AmbientOcclusionEffect.cpp @@ -205,7 +205,7 @@ gpu::TexturePointer AmbientOcclusionFramebuffer::getNormalTexture() { } AmbientOcclusionEffectConfig::AmbientOcclusionEffectConfig() : - render::GPUJobConfig::Persistent(QStringList() << "Render" << "Engine" << "Ambient Occlusion", false), + render::GPUJobConfig::Persistent(QStringList() << "Render" << "Engine" << "Ambient Occlusion"), perspectiveScale{ 1.0f }, edgeSharpness{ 1.0f }, blurRadius{ 4 }, diff --git a/libraries/render-utils/src/LightingModel.h b/libraries/render-utils/src/LightingModel.h index 571eadb60b..f6bd6dcd46 100644 --- a/libraries/render-utils/src/LightingModel.h +++ b/libraries/render-utils/src/LightingModel.h @@ -118,7 +118,7 @@ protected: float enableSkinning{ 1.0f }; float enableBlendshape{ 1.0f }; - float enableAmbientOcclusion{ 0.0f }; + float enableAmbientOcclusion{ 0.0f }; // false by default float enableShadow{ 1.0f }; float spare1{ 1.0f }; float spare2{ 1.0f }; @@ -196,15 +196,13 @@ public: bool enableSkinning{ true }; bool enableBlendshape{ true }; - bool enableAmbientOcclusion{ true }; + bool enableAmbientOcclusion{ false }; // false by default bool enableShadow{ true }; void setAmbientOcclusion(bool enable) { enableAmbientOcclusion = enable; emit dirty();} bool isAmbientOcclusionEnabled() const { return enableAmbientOcclusion; } - void setShadow(bool enable) { - enableShadow = enable; emit dirty(); - } + void setShadow(bool enable) { enableShadow = enable; emit dirty(); } bool isShadowEnabled() const { return enableShadow; } signals: diff --git a/libraries/render-utils/src/parabola_forward.slv b/libraries/render-utils/src/parabola_forward.slv new file mode 100644 index 0000000000..4eb1456666 --- /dev/null +++ b/libraries/render-utils/src/parabola_forward.slv @@ -0,0 +1,7 @@ +layout(location=0) in vec4 _color; + +layout(location=0) out vec4 _fragColor0; + +void main(void) { + _fragColor0 = _color; +} \ No newline at end of file diff --git a/libraries/shaders/headers/310es/header.glsl b/libraries/shaders/headers/310es/header.glsl index 9a0af85281..a21b2ec5d6 100644 --- a/libraries/shaders/headers/310es/header.glsl +++ b/libraries/shaders/headers/310es/header.glsl @@ -1,6 +1,3 @@ -#version 310 es -#define GPU_GLES -#define GPU_GLES_310 #define BITFIELD highp int #define LAYOUT(X) layout(X) #define LAYOUT_STD140(X) layout(std140, X) @@ -9,6 +6,9 @@ #define gl_VertexID gl_VertexIndex #endif #extension GL_EXT_texture_buffer : enable +#if defined(HAVE_EXT_clip_cull_distance) && !defined(VULKAN) +#extension GL_EXT_clip_cull_distance : enable +#endif precision highp float; precision highp samplerBuffer; precision highp sampler2DShadow; diff --git a/libraries/shaders/headers/310es/version.glsl b/libraries/shaders/headers/310es/version.glsl new file mode 100644 index 0000000000..52e5edea8b --- /dev/null +++ b/libraries/shaders/headers/310es/version.glsl @@ -0,0 +1,3 @@ +#version 310 es +#define GPU_GLES +#define GPU_GLES_310 diff --git a/libraries/shaders/headers/410/header.glsl b/libraries/shaders/headers/410/header.glsl index 901ae6f9db..20bd6b2505 100644 --- a/libraries/shaders/headers/410/header.glsl +++ b/libraries/shaders/headers/410/header.glsl @@ -1,5 +1,3 @@ -#version 410 core -#define GPU_GL410 #define BITFIELD int #if defined(VULKAN) #extension GL_ARB_shading_language_420pack : require diff --git a/libraries/shaders/headers/410/version.glsl b/libraries/shaders/headers/410/version.glsl new file mode 100644 index 0000000000..01ab7e5398 --- /dev/null +++ b/libraries/shaders/headers/410/version.glsl @@ -0,0 +1,2 @@ +#version 410 core +#define GPU_GL410 diff --git a/libraries/shaders/headers/450/header.glsl b/libraries/shaders/headers/450/header.glsl index 6ce61b4378..ef0ec09414 100644 --- a/libraries/shaders/headers/450/header.glsl +++ b/libraries/shaders/headers/450/header.glsl @@ -1,5 +1,3 @@ -#version 450 core -#define GPU_GL450 #define GPU_SSBO_TRANSFORM_OBJECT #define BITFIELD int #define LAYOUT(X) layout(X) diff --git a/libraries/shaders/headers/450/version.glsl b/libraries/shaders/headers/450/version.glsl new file mode 100644 index 0000000000..874d578bd9 --- /dev/null +++ b/libraries/shaders/headers/450/version.glsl @@ -0,0 +1,2 @@ +#version 450 core +#define GPU_GL450 diff --git a/libraries/shaders/src/shaders/Shaders.cpp b/libraries/shaders/src/shaders/Shaders.cpp index c7e39b2940..a074c2f0c9 100644 --- a/libraries/shaders/src/shaders/Shaders.cpp +++ b/libraries/shaders/src/shaders/Shaders.cpp @@ -224,7 +224,7 @@ String Source::getSource(Dialect dialect, Variant variant) const { } } -#ifdef Q_OS_ANDROID +#if defined(Q_OS_ANDROID) || defined(USE_GLES) // SPIRV cross injects "#extension GL_OES_texture_buffer : require" into the GLSL shaders, // which breaks android rendering return variantSource.scribe; diff --git a/libraries/shared/src/Profile.cpp b/libraries/shared/src/Profile.cpp index 778b39aca5..272538e26d 100644 --- a/libraries/shared/src/Profile.cpp +++ b/libraries/shared/src/Profile.cpp @@ -12,6 +12,7 @@ Q_LOGGING_CATEGORY(trace_app, "trace.app") Q_LOGGING_CATEGORY(trace_app_detail, "trace.app.detail") Q_LOGGING_CATEGORY(trace_metadata, "trace.metadata") Q_LOGGING_CATEGORY(trace_network, "trace.network") +Q_LOGGING_CATEGORY(trace_picks, "trace.picks") Q_LOGGING_CATEGORY(trace_parse, "trace.parse") Q_LOGGING_CATEGORY(trace_render, "trace.render") Q_LOGGING_CATEGORY(trace_render_detail, "trace.render.detail") diff --git a/libraries/shared/src/Profile.h b/libraries/shared/src/Profile.h index 01d86f8f2e..dc2ed6e754 100644 --- a/libraries/shared/src/Profile.h +++ b/libraries/shared/src/Profile.h @@ -18,6 +18,7 @@ Q_DECLARE_LOGGING_CATEGORY(trace_app) Q_DECLARE_LOGGING_CATEGORY(trace_app_detail) Q_DECLARE_LOGGING_CATEGORY(trace_metadata) Q_DECLARE_LOGGING_CATEGORY(trace_network) +Q_DECLARE_LOGGING_CATEGORY(trace_picks) Q_DECLARE_LOGGING_CATEGORY(trace_render) Q_DECLARE_LOGGING_CATEGORY(trace_render_detail) Q_DECLARE_LOGGING_CATEGORY(trace_render_gpu) diff --git a/libraries/shared/src/RegisteredMetaTypes.cpp b/libraries/shared/src/RegisteredMetaTypes.cpp index ec1126c92f..47549b639a 100644 --- a/libraries/shared/src/RegisteredMetaTypes.cpp +++ b/libraries/shared/src/RegisteredMetaTypes.cpp @@ -1269,7 +1269,14 @@ QVariantMap parseTexturesToMap(QString newTextures, const QVariantMap& defaultTe QVariantMap newTexturesMap = newTexturesJson.toVariant().toMap(); QVariantMap toReturn = defaultTextures; for (auto& texture : newTexturesMap.keys()) { - toReturn[texture] = newTexturesMap[texture]; + auto newURL = newTexturesMap[texture]; + if (newURL.canConvert()) { + toReturn[texture] = newURL.toUrl(); + } else if (newURL.canConvert()) { + toReturn[texture] = QUrl(newURL.toString()); + } else { + toReturn[texture] = newURL; + } } return toReturn; diff --git a/libraries/shared/src/SpatiallyNestable.cpp b/libraries/shared/src/SpatiallyNestable.cpp index d3ed79faf4..19fafdccf4 100644 --- a/libraries/shared/src/SpatiallyNestable.cpp +++ b/libraries/shared/src/SpatiallyNestable.cpp @@ -67,6 +67,7 @@ const QUuid SpatiallyNestable::getParentID() const { } void SpatiallyNestable::setParentID(const QUuid& parentID) { + bumpAncestorChainRenderableVersion(); _idLock.withWriteLock([&] { if (_parentID != parentID) { _parentID = parentID; @@ -78,6 +79,7 @@ void SpatiallyNestable::setParentID(const QUuid& parentID) { bool success = false; auto parent = getParentPointer(success); if (success && parent) { + bumpAncestorChainRenderableVersion(); parent->updateQueryAACube(); } } @@ -1337,8 +1339,6 @@ QString SpatiallyNestable::nestableTypeToString(NestableType nestableType) { return "entity"; case NestableType::Avatar: return "avatar"; - case NestableType::Overlay: - return "overlay"; default: return "unknown"; } @@ -1419,3 +1419,12 @@ QUuid SpatiallyNestable::getEditSenderID() { }); return editSenderID; } + +void SpatiallyNestable::bumpAncestorChainRenderableVersion() const { + _ancestorChainRenderableVersion++; + bool success = false; + auto parent = getParentPointer(success); + if (success && parent) { + parent->bumpAncestorChainRenderableVersion(); + } +} \ No newline at end of file diff --git a/libraries/shared/src/SpatiallyNestable.h b/libraries/shared/src/SpatiallyNestable.h index e7a449f73f..495c941c07 100644 --- a/libraries/shared/src/SpatiallyNestable.h +++ b/libraries/shared/src/SpatiallyNestable.h @@ -30,8 +30,7 @@ static const uint16_t INVALID_JOINT_INDEX = -1; enum class NestableType { Entity, - Avatar, - Overlay + Avatar }; class SpatiallyNestable : public std::enable_shared_from_this { @@ -222,6 +221,8 @@ public: bool hasGrabs(); virtual QUuid getEditSenderID(); + void bumpAncestorChainRenderableVersion() const; + protected: QUuid _id; mutable SpatiallyNestableWeakPointer _parent; @@ -244,6 +245,8 @@ protected: mutable ReadWriteLockable _grabsLock; QSet _grabs; // upon this thing + mutable std::atomic _ancestorChainRenderableVersion { 0 }; + private: SpatiallyNestable() = delete; const NestableType _nestableType; // EntityItem or an AvatarData diff --git a/libraries/shared/src/VariantMapToScriptValue.cpp b/libraries/shared/src/VariantMapToScriptValue.cpp index 1a747a4e5b..437f60a2ed 100644 --- a/libraries/shared/src/VariantMapToScriptValue.cpp +++ b/libraries/shared/src/VariantMapToScriptValue.cpp @@ -26,10 +26,10 @@ QScriptValue variantToScriptValue(QVariant& qValue, QScriptEngine& scriptEngine) case QVariant::Double: return qValue.toDouble(); break; - case QVariant::String: { + case QVariant::String: + case QVariant::Url: return scriptEngine.newVariant(qValue); break; - } case QVariant::Map: { QVariantMap childMap = qValue.toMap(); return variantMapToScriptValue(childMap, scriptEngine); diff --git a/libraries/ui/src/QmlFragmentClass.cpp b/libraries/ui/src/QmlFragmentClass.cpp index 13e3527ded..fbd045fdb1 100644 --- a/libraries/ui/src/QmlFragmentClass.cpp +++ b/libraries/ui/src/QmlFragmentClass.cpp @@ -24,7 +24,7 @@ QmlFragmentClass::QmlFragmentClass(bool restricted, QString id) : QmlWindowClass // Method called by Qt scripts to create a new bottom menu bar in Android QScriptValue QmlFragmentClass::internal_constructor(QScriptContext* context, QScriptEngine* engine, bool restricted) { - +#ifndef DISABLE_QML std::lock_guard guard(_mutex); auto qml = context->argument(0).toVariant().toMap().value("qml"); if (qml.isValid()) { @@ -53,6 +53,9 @@ QScriptValue QmlFragmentClass::internal_constructor(QScriptContext* context, QSc QScriptValue scriptObject = engine->newQObject(retVal); _fragments[qml.toString()] = scriptObject; return scriptObject; +#else + return QScriptValue(); +#endif } void QmlFragmentClass::close() { @@ -61,6 +64,7 @@ void QmlFragmentClass::close() { } QObject* QmlFragmentClass::addButton(const QVariant& properties) { +#ifndef DISABLE_QML QVariant resultVar; Qt::ConnectionType connectionType = Qt::AutoConnection; @@ -79,8 +83,10 @@ QObject* QmlFragmentClass::addButton(const QVariant& properties) { qWarning() << "QmlFragmentClass addButton result not a QObject"; return NULL; } - return qmlButton; +#else + return nullptr; +#endif } void QmlFragmentClass::removeButton(QObject* button) { diff --git a/libraries/ui/src/QmlWindowClass.cpp b/libraries/ui/src/QmlWindowClass.cpp index 0182e3adc3..1140dbb079 100644 --- a/libraries/ui/src/QmlWindowClass.cpp +++ b/libraries/ui/src/QmlWindowClass.cpp @@ -98,6 +98,7 @@ QmlWindowClass::QmlWindowClass(bool restricted) : _restricted(restricted) { * @property {boolean} visible */ void QmlWindowClass::initQml(QVariantMap properties) { +#ifndef DISABLE_QML auto offscreenUi = DependencyManager::get(); _source = properties[SOURCE_PROPERTY].toString(); @@ -150,6 +151,7 @@ void QmlWindowClass::initQml(QVariantMap properties) { Q_ASSERT(_qmlWindow); Q_ASSERT(dynamic_cast(_qmlWindow.data())); +#endif } void QmlWindowClass::qmlToScript(const QVariant& message) { diff --git a/libraries/ui/src/VirtualPadManager.cpp b/libraries/ui/src/VirtualPadManager.cpp index ef2b8670cc..bf325a0bd6 100644 --- a/libraries/ui/src/VirtualPadManager.cpp +++ b/libraries/ui/src/VirtualPadManager.cpp @@ -38,10 +38,10 @@ namespace VirtualPad { const float Manager::BASE_DIAMETER_PIXELS = 512.0f; 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 = 164.0f; - const float Manager::JUMP_BTN_BOTTOM_MARGIN_PIXELS = 80.0f; - const float Manager::JUMP_BTN_RIGHT_MARGIN_PIXELS = 13.0f; + const float Manager::BTN_TRIMMED_RADIUS_PIXELS = 67.0f; + const float Manager::BTN_FULL_PIXELS = 164.0f; + const float Manager::BTN_BOTTOM_MARGIN_PIXELS = 80.0f; + const float Manager::BTN_RIGHT_MARGIN_PIXELS = 13.0f; Manager::Manager() { @@ -76,14 +76,6 @@ namespace VirtualPad { _extraBottomMargin = margin; } - glm::vec2 Manager::getJumpButtonPosition() { - return _jumpButtonPosition; - } - - void Manager::setJumpButtonPosition(glm::vec2 point) { - _jumpButtonPosition = point; - } - void Manager::requestHapticFeedback(int duration) { emit hapticFeedbackRequested(duration); } @@ -92,6 +84,17 @@ namespace VirtualPad { return &_leftVPadInstance; } + glm::vec2 Manager::getButtonPosition(Manager::Button button) { + if (_buttonsPositions.count(button)) { + return _buttonsPositions.at(button); + } + return glm::vec2(); + } + + void Manager::setButtonPosition(Manager::Button button, glm::vec2 point) { + _buttonsPositions[button] = point; + } + bool Instance::isShown() { return _shown; } diff --git a/libraries/ui/src/VirtualPadManager.h b/libraries/ui/src/VirtualPadManager.h index 3c3aa9ec9f..a1f2e17597 100644 --- a/libraries/ui/src/VirtualPadManager.h +++ b/libraries/ui/src/VirtualPadManager.h @@ -44,28 +44,35 @@ namespace VirtualPad { void hide(bool hide); int extraBottomMargin(); void setExtraBottomMargin(int margin); - glm::vec2 getJumpButtonPosition(); - void setJumpButtonPosition(glm::vec2 point); + + enum Button { + JUMP, + HANDSHAKE + }; + + glm::vec2 getButtonPosition(Button button); + void setButtonPosition(Button button, glm::vec2 point); + void requestHapticFeedback(int duration); static const float DPI; static const float BASE_DIAMETER_PIXELS; static const float BASE_MARGIN_PIXELS; static const float STICK_RADIUS_PIXELS; - 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_RIGHT_MARGIN_PIXELS; + static const float BTN_TRIMMED_RADIUS_PIXELS; + static const float BTN_FULL_PIXELS; + static const float BTN_BOTTOM_MARGIN_PIXELS; + static const float BTN_RIGHT_MARGIN_PIXELS; signals: void hapticFeedbackRequested(int duration); private: Instance _leftVPadInstance; - bool _enabled {true}; + bool _enabled { true }; bool _hidden; - glm::vec2 _jumpButtonPosition; - int _extraBottomMargin {0}; + int _extraBottomMargin { 0 }; + std::map _buttonsPositions; }; } diff --git a/prebuild.py b/prebuild.py index 060e1fd3b0..5325ca34bc 100644 --- a/prebuild.py +++ b/prebuild.py @@ -58,6 +58,9 @@ logging.setLoggerClass(TrackableLogger) logger = logging.getLogger('prebuild') def headSha(): + if shutil.which('git') is None: + logger.warn("Unable to find git executable, can't caclulate commit ID") + return '0xDEADBEEF' repo_dir = os.path.dirname(os.path.abspath(__file__)) git = subprocess.Popen( 'git rev-parse --short HEAD', @@ -67,7 +70,7 @@ def headSha(): stdout, _ = git.communicate() sha = stdout.split('\n')[0] if not sha: - raise RuntimeError("couldn't find git sha") + raise RuntimeError("couldn't find git sha for repository {}".format(repo_dir)) return sha @contextmanager diff --git a/scripts/+android_interface/defaultScripts.js b/scripts/+android_interface/defaultScripts.js index e6971f5a6b..8b3082d81a 100644 --- a/scripts/+android_interface/defaultScripts.js +++ b/scripts/+android_interface/defaultScripts.js @@ -16,7 +16,8 @@ var DEFAULT_SCRIPTS_COMBINED = [ "system/+android_interface/touchscreenvirtualpad.js", "system/+android_interface/actionbar.js", "system/+android_interface/audio.js" , - "system/+android_interface/modes.js"/*, + "system/+android_interface/modes.js", + "system/makeUserConnection.js"/*, "system/away.js", "system/controllers/controllerDisplayManager.js", "system/controllers/handControllerGrabAndroid.js", diff --git a/scripts/developer/utilities/render/deferredLighting.qml b/scripts/developer/utilities/render/deferredLighting.qml index 6d98e96780..f5c0b8c5da 100644 --- a/scripts/developer/utilities/render/deferredLighting.qml +++ b/scripts/developer/utilities/render/deferredLighting.qml @@ -47,7 +47,7 @@ Rectangle { "Lightmap:LightingModel:enableLightmap", "Background:LightingModel:enableBackground", "Haze:LightingModel:enableHaze", - "ssao:LightingModel:enableAmbientOcclusion", + "AO:LightingModel:enableAmbientOcclusion", "Textures:LightingModel:enableMaterialTexturing" ] HifiControls.CheckBox { diff --git a/scripts/system/away.js b/scripts/system/away.js index a2e73ae63c..45b6f43b73 100644 --- a/scripts/system/away.js +++ b/scripts/system/away.js @@ -45,7 +45,8 @@ var OVERLAY_DATA_HMD = { emissive: true, drawInFront: true, parentID: MyAvatar.SELF_ID, - parentJointIndex: CAMERA_MATRIX + parentJointIndex: CAMERA_MATRIX, + ignorePickIntersection: true }; var AWAY_INTRO = { diff --git a/scripts/system/controllers/+android_questInterface/controllerScripts.js b/scripts/system/controllers/+android_questInterface/controllerScripts.js new file mode 100644 index 0000000000..d313efaca1 --- /dev/null +++ b/scripts/system/controllers/+android_questInterface/controllerScripts.js @@ -0,0 +1,58 @@ +"use strict"; + +// controllerScripts.js +// +// Created by David Rowe on 15 Mar 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 +// + +/* global Script, Menu */ + +var CONTOLLER_SCRIPTS = [ + "squeezeHands.js", + "controllerDisplayManager.js", + "toggleAdvancedMovementForHandControllers.js", + "controllerDispatcher.js", + "controllerModules/nearParentGrabOverlay.js", + "controllerModules/stylusInput.js", + "controllerModules/equipEntity.js", + "controllerModules/nearTrigger.js", + "controllerModules/webSurfaceLaserInput.js", + "controllerModules/inVREditMode.js", + "controllerModules/disableOtherModule.js", + "controllerModules/farTrigger.js", + "controllerModules/teleport.js", + "controllerModules/hudOverlayPointer.js", + "controllerModules/scaleEntity.js", + "controllerModules/nearGrabHyperLinkEntity.js", + "controllerModules/nearTabletHighlight.js", + "controllerModules/nearGrabEntity.js", + "controllerModules/farGrabEntity.js" +]; + +var DEBUG_MENU_ITEM = "Debug defaultScripts.js"; + +function runDefaultsTogether() { + for (var j in CONTOLLER_SCRIPTS) { + if (CONTOLLER_SCRIPTS.hasOwnProperty(j)) { + Script.include(CONTOLLER_SCRIPTS[j]); + } + } +} + +function runDefaultsSeparately() { + for (var i in CONTOLLER_SCRIPTS) { + if (CONTOLLER_SCRIPTS.hasOwnProperty(i)) { + Script.load(CONTOLLER_SCRIPTS[i]); + } + } +} + +if (Menu.isOptionChecked(DEBUG_MENU_ITEM)) { + runDefaultsSeparately(); +} else { + runDefaultsTogether(); +} diff --git a/scripts/system/controllers/controllerDispatcher.js b/scripts/system/controllers/controllerDispatcher.js index 2a5cf5a727..28c3e2a299 100644 --- a/scripts/system/controllers/controllerDispatcher.js +++ b/scripts/system/controllers/controllerDispatcher.js @@ -497,6 +497,7 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js"); distanceScaleEnd: true, hand: RIGHT_HAND }); + this.mouseRayPick = Pointers.createPointer(PickType.Ray, { joint: "Mouse", filter: Picks.PICK_OVERLAYS | Picks.PICK_ENTITIES | Picks.PICK_INCLUDE_NONCOLLIDABLE, diff --git a/scripts/system/controllers/controllerModules/teleport.js b/scripts/system/controllers/controllerModules/teleport.js index 8770ae8dde..23457cdd85 100644 --- a/scripts/system/controllers/controllerModules/teleport.js +++ b/scripts/system/controllers/controllerModules/teleport.js @@ -196,14 +196,14 @@ Script.include("/~/system/libraries/controllers.js"); var playAreaOverlayProperties = { dimensions: - Vec3.multiply(this.teleportScaleFactor * avatarScale, { - x: this.playArea.width, - y: this.PLAY_AREA_OVERLAY_MODEL_DIMENSIONS.y, - z: this.playArea.height + Vec3.multiply(_this.teleportScaleFactor * avatarScale, { + x: _this.playArea.width, + y: _this.PLAY_AREA_OVERLAY_MODEL_DIMENSIONS.y, + z: _this.playArea.height }) }; - if (this.teleportScaleFactor < 1) { + if (_this.teleportScaleFactor < 1) { // Adjust position of playAreOverlay so that its base is at correct height. // Always parenting to teleport target is good enough for this. var sensorToWorldMatrix = MyAvatar.sensorToWorldMatrix; @@ -212,37 +212,37 @@ Script.include("/~/system/libraries/controllers.js"); var avatarSensorPosition = Mat4.transformPoint(worldToSensorMatrix, MyAvatar.position); avatarSensorPosition.y = 0; - var targetRotation = Overlays.getProperty(this.targetOverlayID, "rotation"); + var targetRotation = Overlays.getProperty(_this.targetOverlayID, "rotation"); var relativePlayAreaCenterOffset = - Vec3.sum(this.playAreaCenterOffset, { x: 0, y: -TARGET_MODEL_DIMENSIONS.y / 2, z: 0 }); + Vec3.sum(_this.playAreaCenterOffset, { x: 0, y: -TARGET_MODEL_DIMENSIONS.y / 2, z: 0 }); var localPosition = Vec3.multiplyQbyV(Quat.inverse(targetRotation), Vec3.multiplyQbyV(sensorToWorldRotation, Vec3.multiply(avatarScale, Vec3.subtract(relativePlayAreaCenterOffset, avatarSensorPosition)))); - localPosition.y = this.teleportScaleFactor * localPosition.y; + localPosition.y = _this.teleportScaleFactor * localPosition.y; - playAreaOverlayProperties.parentID = this.targetOverlayID; + playAreaOverlayProperties.parentID = _this.targetOverlayID; playAreaOverlayProperties.localPosition = localPosition; } - Overlays.editOverlay(this.playAreaOverlay, playAreaOverlayProperties); + Overlays.editOverlay(_this.playAreaOverlay, playAreaOverlayProperties); - for (var i = 0; i < this.playAreaSensorPositionOverlays.length; i++) { - localPosition = this.playAreaSensorPositions[i]; + for (var i = 0; i < _this.playAreaSensorPositionOverlays.length; i++) { + localPosition = _this.playAreaSensorPositions[i]; localPosition = Vec3.multiply(avatarScale, localPosition); // Position relative to the play area. - localPosition.y = avatarScale * (this.PLAY_AREA_SENSOR_OVERLAY_DIMENSIONS.y / 2 - - this.PLAY_AREA_OVERLAY_MODEL_DIMENSIONS.y / 2); - Overlays.editOverlay(this.playAreaSensorPositionOverlays[i], { - dimensions: Vec3.multiply(this.teleportScaleFactor * avatarScale, this.PLAY_AREA_SENSOR_OVERLAY_DIMENSIONS), - parentID: this.playAreaOverlay, + localPosition.y = avatarScale * (_this.PLAY_AREA_SENSOR_OVERLAY_DIMENSIONS.y / 2 + - _this.PLAY_AREA_OVERLAY_MODEL_DIMENSIONS.y / 2); + Overlays.editOverlay(_this.playAreaSensorPositionOverlays[i], { + dimensions: Vec3.multiply(_this.teleportScaleFactor * avatarScale, _this.PLAY_AREA_SENSOR_OVERLAY_DIMENSIONS), + parentID: _this.playAreaOverlay, localPosition: localPosition }); } }; this.updatePlayAreaScale = function () { - if (this.isPlayAreaAvailable) { - this.setPlayAreaDimensions(); + if (_this.isPlayAreaAvailable) { + _this.setPlayAreaDimensions(); } }; @@ -265,7 +265,7 @@ Script.include("/~/system/libraries/controllers.js"); for (var i = 0, length = teleportRenderStates.length; i < length; i++) { var state = properties.renderStates[teleportRenderStates[i].name]; if (state && state.end) { - Selection.addToSelectedItemsList(this.teleporterSelectionName, "overlay", state.end); + Selection.addToSelectedItemsList(_this.teleporterSelectionName, "overlay", state.end); } } }; @@ -448,34 +448,34 @@ Script.include("/~/system/libraries/controllers.js"); this.translateZAction = Controller.findAction("TranslateZ"); this.setPlayAreaVisible = function (visible, targetOverlayID, fade) { - if (!this.isPlayAreaAvailable || this.isPlayAreaVisible === visible) { + if (!_this.isPlayAreaAvailable || _this.isPlayAreaVisible === visible) { return; } - this.wasPlayAreaVisible = this.isPlayAreaVisible; - this.isPlayAreaVisible = visible; - this.targetOverlayID = targetOverlayID; + _this.wasPlayAreaVisible = _this.isPlayAreaVisible; + _this.isPlayAreaVisible = visible; + _this.targetOverlayID = targetOverlayID; - if (this.teleportedFadeTimer !== null) { - Script.clearTimeout(this.teleportedFadeTimer); - this.teleportedFadeTimer = null; + if (_this.teleportedFadeTimer !== null) { + Script.clearTimeout(_this.teleportedFadeTimer); + _this.teleportedFadeTimer = null; } if (visible || !fade) { // Immediately make visible or invisible. - this.isPlayAreaVisible = visible; - Overlays.editOverlay(this.playAreaOverlay, { + _this.isPlayAreaVisible = visible; + Overlays.editOverlay(_this.playAreaOverlay, { dimensions: Vec3.ZERO, - alpha: this.PLAY_AREA_BOX_ALPHA, + alpha: _this.PLAY_AREA_BOX_ALPHA, visible: visible }); - for (var i = 0; i < this.playAreaSensorPositionOverlays.length; i++) { - Overlays.editOverlay(this.playAreaSensorPositionOverlays[i], { + for (var i = 0; i < _this.playAreaSensorPositionOverlays.length; i++) { + Overlays.editOverlay(_this.playAreaSensorPositionOverlays[i], { dimensions: Vec3.ZERO, - alpha: this.PLAY_AREA_SENSOR_ALPHA, + alpha: _this.PLAY_AREA_SENSOR_ALPHA, visible: visible }); } - Overlays.editOverlay(this.teleportedTargetOverlay, { visible: false }); + Overlays.editOverlay(_this.teleportedTargetOverlay, { visible: false }); } else { // Fading out of overlays is initiated in setTeleportVisible(). } @@ -494,22 +494,22 @@ Script.include("/~/system/libraries/controllers.js"); var MIN_PARENTING_DISTANCE = 0.2; // Parenting under this distance results in the play area's rotation jittering. if (Vec3.distance(targetXZPosition, avatarXZPosition) < MIN_PARENTING_DISTANCE) { // Set play area position and rotation in world coordinates with no parenting. - Overlays.editOverlay(this.playAreaOverlay, { + Overlays.editOverlay(_this.playAreaOverlay, { parentID: Uuid.NULL, position: Vec3.sum(position, Vec3.multiplyQbyV(sensorToWorldRotation, Vec3.multiply(MyAvatar.sensorToWorldScale, - Vec3.subtract(this.playAreaCenterOffset, avatarSensorPosition)))), + Vec3.subtract(_this.playAreaCenterOffset, avatarSensorPosition)))), rotation: sensorToWorldRotation }); } else { // Set play area position and rotation in local coordinates with parenting. - var targetRotation = Overlays.getProperty(this.targetOverlayID, "rotation"); + var targetRotation = Overlays.getProperty(_this.targetOverlayID, "rotation"); var sensorToTargetRotation = Quat.multiply(Quat.inverse(targetRotation), sensorToWorldRotation); var relativePlayAreaCenterOffset = - Vec3.sum(this.playAreaCenterOffset, { x: 0, y: -TARGET_MODEL_DIMENSIONS.y / 2, z: 0 }); - Overlays.editOverlay(this.playAreaOverlay, { - parentID: this.targetOverlayID, + Vec3.sum(_this.playAreaCenterOffset, { x: 0, y: -TARGET_MODEL_DIMENSIONS.y / 2, z: 0 }); + Overlays.editOverlay(_this.playAreaOverlay, { + parentID: _this.targetOverlayID, localPosition: Vec3.multiplyQbyV(Quat.inverse(targetRotation), Vec3.multiplyQbyV(sensorToWorldRotation, Vec3.multiply(MyAvatar.sensorToWorldScale, @@ -578,33 +578,33 @@ Script.include("/~/system/libraries/controllers.js"); } } _this.teleportedFadeTimer = null; - Selection.disableListHighlight(this.teleporterSelectionName); + Selection.disableListHighlight(_this.teleporterSelectionName); } }; this.cancelFade = function () { // Other hand may call this to immediately hide fading overlays. var i, length; - if (this.teleportedFadeTimer) { - Overlays.editOverlay(this.teleportedTargetOverlay, { visible: false }); - if (this.wasPlayAreaVisible) { - Overlays.editOverlay(this.playAreaOverlay, { visible: false }); - for (i = 0, length = this.playAreaSensorPositionOverlays.length; i < length; i++) { - Overlays.editOverlay(this.playAreaSensorPositionOverlays[i], { visible: false }); + if (_this.teleportedFadeTimer) { + Overlays.editOverlay(_this.teleportedTargetOverlay, { visible: false }); + if (_this.wasPlayAreaVisible) { + Overlays.editOverlay(_this.playAreaOverlay, { visible: false }); + for (i = 0, length = _this.playAreaSensorPositionOverlays.length; i < length; i++) { + Overlays.editOverlay(_this.playAreaSensorPositionOverlays[i], { visible: false }); } } - this.teleportedFadeTimer = null; + _this.teleportedFadeTimer = null; } }; this.setTeleportVisible = function (visible, mode, fade) { // Scales in teleport target and play area when start displaying them. - if (visible === this.isTeleportVisible) { + if (visible === _this.isTeleportVisible) { return; } if (visible) { - this.teleportScaleMode = mode; + _this.teleportScaleMode = mode; Pointers.editRenderState( mode === "head" ? _this.teleportParabolaHeadVisuals : _this.teleportParabolaHandVisuals, "teleport", @@ -613,42 +613,42 @@ Script.include("/~/system/libraries/controllers.js"); end: { dimensions: Vec3.ZERO } } ); - this.getOtherModule().cancelFade(); - this.teleportScaleStart = Date.now(); - this.teleportScaleFactor = 0; - this.scaleInTeleport(); - Selection.enableListHighlight(this.teleporterSelectionName, this.TELEPORTER_SELECTION_STYLE); + _this.getOtherModule().cancelFade(); + _this.teleportScaleStart = Date.now(); + _this.teleportScaleFactor = 0; + _this.scaleInTeleport(); + Selection.enableListHighlight(_this.teleporterSelectionName, _this.TELEPORTER_SELECTION_STYLE); } else { - if (this.teleportScaleTimer !== null) { - Script.clearTimeout(this.teleportScaleTimer); - this.teleportScaleTimer = null; + if (_this.teleportScaleTimer !== null) { + Script.clearTimeout(_this.teleportScaleTimer); + _this.teleportScaleTimer = null; } if (fade) { // Copy of target at teleported position for fading. var avatarScale = MyAvatar.sensorToWorldScale; - Overlays.editOverlay(this.teleportedTargetOverlay, { - position: Vec3.sum(this.teleportedPosition, { + Overlays.editOverlay(_this.teleportedTargetOverlay, { + position: Vec3.sum(_this.teleportedPosition, { x: 0, y: -getAvatarFootOffset() + avatarScale * TARGET_MODEL_DIMENSIONS.y / 2, z: 0 }), - rotation: Quat.multiply(this.TELEPORTED_TARGET_ROTATION, MyAvatar.orientation), + rotation: Quat.multiply(_this.TELEPORTED_TARGET_ROTATION, MyAvatar.orientation), dimensions: Vec3.multiply(avatarScale, TARGET_MODEL_DIMENSIONS), - alpha: this.TELEPORTED_TARGET_ALPHA, + alpha: _this.TELEPORTED_TARGET_ALPHA, visible: true }); // Fade out over time. - this.teleportedFadeDelayFactor = 1.0; - this.teleportedFadeFactor = 1.0; - this.teleportedFadeTimer = Script.setTimeout(this.fadeOutTeleport, this.TELEPORTED_FADE_DELAY); + _this.teleportedFadeDelayFactor = 1.0; + _this.teleportedFadeFactor = 1.0; + _this.teleportedFadeTimer = Script.setTimeout(_this.fadeOutTeleport, _this.TELEPORTED_FADE_DELAY); } else { - Selection.disableListHighlight(this.teleporterSelectionName); + Selection.disableListHighlight(_this.teleporterSelectionName); } } - this.isTeleportVisible = visible; + _this.isTeleportVisible = visible; }; @@ -697,7 +697,7 @@ Script.include("/~/system/libraries/controllers.js"); 100); this.enterTeleport = function() { - this.state = TELEPORTER_STATES.TARGETTING; + _this.state = TELEPORTER_STATES.TARGETTING; }; this.isReady = function(controllerData, deltaTime) { @@ -761,23 +761,23 @@ Script.include("/~/system/libraries/controllers.js"); if (teleportLocationType === TARGET.NONE) { // Use the cancel default state - this.setTeleportState(mode, "cancel", ""); + _this.setTeleportState(mode, "cancel", ""); } else if (teleportLocationType === TARGET.INVALID) { - this.setTeleportState(mode, "", "cancel"); + _this.setTeleportState(mode, "", "cancel"); } else if (teleportLocationType === TARGET.COLLIDES) { - this.setTeleportState(mode, "cancel", "collision"); + _this.setTeleportState(mode, "cancel", "collision"); } else if (teleportLocationType === TARGET.SURFACE || teleportLocationType === TARGET.DISCREPANCY) { - this.setTeleportState(mode, "teleport", "collision"); - this.updatePlayArea(result.intersection); + _this.setTeleportState(mode, "teleport", "collision"); + _this.updatePlayArea(result.intersection); } else if (teleportLocationType === TARGET.SEAT) { - this.setTeleportState(mode, "collision", "seat"); + _this.setTeleportState(mode, "collision", "seat"); } - return this.teleport(result, teleportLocationType); + return _this.teleport(result, teleportLocationType); }; this.teleport = function(newResult, target) { var result = newResult; - this.teleportedPosition = newResult.intersection; + _this.teleportedPosition = newResult.intersection; if (_this.buttonValue !== 0) { return makeRunningValues(true, [], []); } @@ -795,14 +795,14 @@ Script.include("/~/system/libraries/controllers.js"); MyAvatar.centerBody(); } - this.disableLasers(); - this.active = false; + _this.disableLasers(); + _this.active = false; return makeRunningValues(false, [], []); }; this.disableLasers = function() { - this.setPlayAreaVisible(false, null, true); - this.setTeleportVisible(false, null, true); + _this.setPlayAreaVisible(false, null, true); + _this.setTeleportVisible(false, null, true); Pointers.disablePointer(_this.teleportParabolaHandVisuals); Pointers.disablePointer(_this.teleportParabolaHandCollisions); Pointers.disablePointer(_this.teleportParabolaHeadVisuals); @@ -815,10 +815,10 @@ Script.include("/~/system/libraries/controllers.js"); this.setTeleportState = function (mode, visibleState, invisibleState) { var teleportState = mode + visibleState + invisibleState; - if (teleportState === this.teleportState) { + if (teleportState === _this.teleportState) { return; } - this.teleportState = teleportState; + _this.teleportState = teleportState; var pointerID; if (mode === 'head') { @@ -831,16 +831,16 @@ Script.include("/~/system/libraries/controllers.js"); pointerID = _this.teleportParabolaHandVisuals; } var visible = visibleState === "teleport"; - this.setPlayAreaVisible(visible && MyAvatar.showPlayArea, + _this.setPlayAreaVisible(visible && MyAvatar.showPlayArea, Pointers.getPointerProperties(pointerID).renderStates.teleport.end, false); - this.setTeleportVisible(visible, mode, false); + _this.setTeleportVisible(visible, mode, false); }; this.setIgnoreEntities = function(entitiesToIgnore) { - Pointers.setIgnoreItems(this.teleportParabolaHandVisuals, entitiesToIgnore); - Pointers.setIgnoreItems(this.teleportParabolaHandCollisions, entitiesToIgnore); - Pointers.setIgnoreItems(this.teleportParabolaHeadVisuals, entitiesToIgnore); - Pointers.setIgnoreItems(this.teleportParabolaHeadCollisions, entitiesToIgnore); + Pointers.setIgnoreItems(_this.teleportParabolaHandVisuals, entitiesToIgnore); + Pointers.setIgnoreItems(_this.teleportParabolaHandCollisions, entitiesToIgnore); + Pointers.setIgnoreItems(_this.teleportParabolaHeadVisuals, entitiesToIgnore); + Pointers.setIgnoreItems(_this.teleportParabolaHeadCollisions, entitiesToIgnore); Picks.setIgnoreItems(_this.teleportHeadCollisionPick, entitiesToIgnore); Picks.setIgnoreItems(_this.teleportHandCollisionPick, entitiesToIgnore); }; diff --git a/scripts/system/html/js/SnapshotReview.js b/scripts/system/html/js/SnapshotReview.js index 91866605a4..1e8be9d644 100644 --- a/scripts/system/html/js/SnapshotReview.js +++ b/scripts/system/html/js/SnapshotReview.js @@ -450,7 +450,7 @@ function updateShareInfo(containerID, storyID) { facebookButton.setAttribute("href", 'https://www.facebook.com/dialog/feed?app_id=1585088821786423&link=' + shareURL); twitterButton.setAttribute("target", "_blank"); - twitterButton.setAttribute("href", 'https://twitter.com/intent/tweet?text=I%20just%20took%20a%20snapshot!&url=' + shareURL + '&via=highfidelityinc&hashtags=VR,HiFi'); + twitterButton.setAttribute("href", 'https://twitter.com/intent/tweet?text=I%20just%20took%20a%20snapshot!&url=' + shareURL + '&via=highfidelityVR&hashtags=VR,HiFi'); hideUploadingMessageAndMaybeShare(containerID, storyID); } diff --git a/scripts/system/pal.js b/scripts/system/pal.js index 141ea03330..0c4338b31d 100644 --- a/scripts/system/pal.js +++ b/scripts/system/pal.js @@ -161,7 +161,8 @@ ExtendedOverlay.unHover = function () { // calls hover(false) on lastHoveringId // hit(overlay) on the one overlay intersected by pickRay, if any. // noHit() if no ExtendedOverlay was intersected (helps with hover) ExtendedOverlay.applyPickRay = function (pickRay, hit, noHit) { - var pickedOverlay = Overlays.findRayIntersection(pickRay); // Depends on nearer coverOverlays to extend closer to us than farther ones. + // TODO: this could just include the necessary overlays for better performance + var pickedOverlay = Overlays.findRayIntersection(pickRay, true); // Depends on nearer coverOverlays to extend closer to us than farther ones. if (!pickedOverlay.intersects) { if (noHit) { return noHit(); diff --git a/scripts/system/tablet-ui/tabletUI.js b/scripts/system/tablet-ui/tabletUI.js index f9e9165f2e..60848224bb 100644 --- a/scripts/system/tablet-ui/tabletUI.js +++ b/scripts/system/tablet-ui/tabletUI.js @@ -137,11 +137,11 @@ UIWebTablet.calculateTabletAttachmentProperties(activeHand, true, tabletProperties); } tabletProperties.visible = true; + tabletProperties.ignorePickIntersection = false; Overlays.editOverlay(HMD.tabletID, tabletProperties); - Overlays.editOverlay(HMD.homeButtonID, { visible: true }); - Overlays.editOverlay(HMD.homeButtonHighlightID, { visible: true }); - Overlays.editOverlay(HMD.tabletScreenID, { visible: true }); - Overlays.editOverlay(HMD.tabletScreenID, { maxFPS: 90 }); + Overlays.editOverlay(HMD.homeButtonID, { visible: true, ignorePickIntersection: false }); + Overlays.editOverlay(HMD.homeButtonHighlightID, { visible: true, ignorePickIntersection: false }); + Overlays.editOverlay(HMD.tabletScreenID, { visible: true, ignorePickIntersection: false, maxFPS: 90 }); updateTabletWidthFromSettings(true); } gTablet.tabletShown = true; @@ -158,11 +158,10 @@ print("TABLET hide"); } - Overlays.editOverlay(HMD.tabletID, { visible: false }); - Overlays.editOverlay(HMD.homeButtonID, { visible: false }); - Overlays.editOverlay(HMD.homeButtonHighlightID, { visible: false }); - Overlays.editOverlay(HMD.tabletScreenID, { visible: false }); - Overlays.editOverlay(HMD.tabletScreenID, { maxFPS: 1 }); + Overlays.editOverlay(HMD.tabletID, { visible: false, ignorePickIntersection: true }); + Overlays.editOverlay(HMD.homeButtonID, { visible: false, ignorePickIntersection: true }); + Overlays.editOverlay(HMD.homeButtonHighlightID, { visible: false, ignorePickIntersection: true }); + Overlays.editOverlay(HMD.tabletScreenID, { visible: false, ignorePickIntersection: true, maxFPS: 1 }); } function closeTabletUI() { diff --git a/tools/jsdoc/.gitignore b/tools/jsdoc/.gitignore index 148363ca03..b64f841525 100644 --- a/tools/jsdoc/.gitignore +++ b/tools/jsdoc/.gitignore @@ -1,2 +1,6 @@ -out +out/* +!out/README.md + + + diff --git a/tools/jsdoc/out/README.md b/tools/jsdoc/out/README.md new file mode 100644 index 0000000000..3f9519555e --- /dev/null +++ b/tools/jsdoc/out/README.md @@ -0,0 +1 @@ +This is the output directory for the JavaScript API documentation generated by jsdoc. \ No newline at end of file diff --git a/tools/shadergen.py b/tools/shadergen.py index ffbe1662ec..f82b471f17 100644 --- a/tools/shadergen.py +++ b/tools/shadergen.py @@ -49,11 +49,36 @@ def getCommonScribeArgs(scribefile, includeLibs): scribeArgs.append(scribefile) return scribeArgs -def getDialectAndVariantHeaders(dialect, variant): +extensionsHeaderMutex = Lock() + +def getExtensionsHeader(dialect, variant, extensions): + extensionHeader = '{}/extensions_{}_{}.glsl'.format(args.build_dir, dialect, variant) + global extensionsHeaderMutex + extensionsHeaderMutex.acquire() + if not os.path.exists(extensionHeader): + extensionsDefines = [] + for extension in extensions: + extensionsDefines.append('#define HAVE_{}'.format(extension)) + # make sure we end with a line feed + extensionsDefines.append("\r\n") + with open(extensionHeader, "w") as f: + f.write('\r\n'.join(extensionsDefines)) + extensionsHeaderMutex.release() + return extensionHeader + + +def getDialectAndVariantHeaders(dialect, variant, extensions=None): + result = [] headerPath = args.source_dir + '/libraries/shaders/headers/' - variantHeader = headerPath + ('stereo.glsl' if (variant == 'stereo') else 'mono.glsl') + versionHeader = headerPath + dialect + '/version.glsl' + result.append(versionHeader) + if extensions is not None: + result.append(getExtensionsHeader(dialect, variant, extensions)) dialectHeader = headerPath + dialect + '/header.glsl' - return [dialectHeader, variantHeader] + result.append(dialectHeader) + variantHeader = headerPath + ('stereo.glsl' if (variant == 'stereo') else 'mono.glsl') + result.append(variantHeader) + return result class ScribeDependenciesCache: cache = {} @@ -170,7 +195,7 @@ def processCommand(line): scribeDepCache.gen(scribeFile, libs, dialect, variant) scribeArgs = getCommonScribeArgs(scribeFile, libs) - for header in getDialectAndVariantHeaders(dialect, variant): + for header in getDialectAndVariantHeaders(dialect, variant, args.extensions): scribeArgs.extend(['-H', header]) scribeArgs.extend(['-o', unoptGlslFile]) executeSubprocess(scribeArgs) @@ -218,6 +243,7 @@ def main(): parser = ArgumentParser(description='Generate shader artifacts.') +parser.add_argument('--extensions', type=str, nargs='*', help='Available extensions for the shaders') parser.add_argument('--commands', type=argparse.FileType('r'), help='list of commands to execute') parser.add_argument('--tools-dir', type=str, help='location of the host compatible binaries') parser.add_argument('--build-dir', type=str, help='The build directory base path') @@ -230,8 +256,8 @@ args = None if len(sys.argv) == 1: # for debugging sourceDir = expanduser('~/git/hifi') - toolsDir = os.path.join(expanduser('~/git/vcpkg'), 'installed', 'x64-windows', 'tools') - buildPath = sourceDir + '/build' + toolsDir = 'd:/hifi/vcpkg/android/fd82f0a8/installed/x64-windows/tools' + buildPath = sourceDir + '/build_android' commandsPath = buildPath + '/libraries/shaders/shadergen.txt' shaderDir = buildPath + '/libraries/shaders' testArgs = '--commands {} --tools-dir {} --build-dir {} --source-dir {}'.format( @@ -239,6 +265,7 @@ if len(sys.argv) == 1: ).split() testArgs.append('--debug') testArgs.append('--force') + testArgs.extend('--extensions EXT_clip_cull_distance'.split()) #testArgs.append('--dry-run') args = parser.parse_args(testArgs) else: