Merge branch 'master' of https://github.com/highfidelity/hifi into StandaloneTags

This commit is contained in:
Roxanne Skelly 2019-02-20 14:24:47 -08:00
commit 8c058f147e
89 changed files with 1525 additions and 413 deletions

1
.gitignore vendored
View file

@ -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

65
BUILD_QUEST.md Normal file
View file

@ -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=<your_home_directory>/Android/hifi_externals
HIFI_ANDROID_KEYSTORE=<key_store_directory>/<keystore_name>.jks
HIFI_ANDROID_KEYSTORE_PASSWORD=<password>
HIFI_ANDROID_KEY_ALIAS=<key_alias>
HIFI_ANDROID_KEY_PASSWORD=<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_

View file

@ -100,6 +100,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 ()

View file

@ -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

View file

@ -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()

View file

@ -19,24 +19,6 @@
android:name="org.qtproject.qt5.android.bindings.QtApplication"
tools:ignore="GoogleAppIndexingWarning,MissingApplicationIcon">
<meta-data android:name="com.samsung.android.vr.application.mode" android:value="vr_only"/>
<activity
android:name=".QuestQtActivity"
android:theme="@android:style/Theme.Black.NoTitleBar.Fullscreen"
android:launchMode="singleTask"
android:label="@string/app_name"
android:screenOrientation="landscape"
android:excludeFromRecents="false"
android:alwaysRetainTaskState="true"
android:configChanges="screenSize|screenLayout|orientation|keyboardHidden|keyboard|navigation|uiMode"
>
<!-- JNI nonsense -->
<meta-data android:name="android.app.lib_name" android:value="questFramePlayer"/>
<!-- Qt nonsense -->
<meta-data android:name="android.app.qt_libs_resource_id" android:resource="@array/qt_libs"/>
<meta-data android:name="android.app.bundled_in_lib_resource_id" android:resource="@array/bundled_in_lib"/>
<meta-data android:name="android.app.bundled_in_assets_resource_id" android:resource="@array/bundled_in_assets"/>
<meta-data android:name="android.app.load_local_libs" android:value="plugins/platforms/android/libqtforandroid.so:plugins/bearer/libqandroidbearer.so:lib/libQt5QuickParticles.so"/>
</activity>
<activity
android:theme="@android:style/Theme.Black.NoTitleBar.Fullscreen"
@ -50,6 +32,13 @@
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<!-- JNI nonsense -->
<meta-data android:name="android.app.lib_name" android:value="questFramePlayer"/>
<!-- Qt nonsense -->
<meta-data android:name="android.app.qt_libs_resource_id" android:resource="@array/qt_libs"/>
<meta-data android:name="android.app.bundled_in_lib_resource_id" android:resource="@array/bundled_in_lib"/>
<meta-data android:name="android.app.bundled_in_assets_resource_id" android:resource="@array/bundled_in_assets"/>
<meta-data android:name="android.app.load_local_libs" android:value="plugins/platforms/android/libqtforandroid.so:plugins/bearer/libqandroidbearer.so:lib/libQt5QuickParticles.so"/>
</activity>
</application>
</manifest>

View file

@ -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 <QtCore/QDebug>
#include <QtGui/QGuiApplication>
AndroidHelper::AndroidHelper() {
}
AndroidHelper::~AndroidHelper() {
}
void AndroidHelper::notifyLoadComplete() {
emit qtAppLoadComplete();
}
void AndroidHelper::notifyEnterForeground() {
emit enterForeground();
}
void AndroidHelper::notifyEnterBackground() {
emit enterBackground();
}

View file

@ -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 <QtCore/QObject>
#include <QtCore/QMap>
#include <QtCore/QUrl>
#include <QtCore/QEventLoop>
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

View file

@ -11,15 +11,11 @@
#include <QtWidgets/QFileDialog>
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();
}

View file

@ -8,22 +8,13 @@
#pragma once
#include <QtGui/QWindow>
#include <QtCore/QSettings>
#include <gpu/Forward.h>
#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;
};

View file

@ -16,6 +16,7 @@
#include <QtCore/QFileInfo>
#include <QtGui/QWindow>
#include <QtGui/QImageReader>
#include <QtAndroidExtras/QAndroidJniObject>
#include <gl/QOpenGLContextWrapper.h>
#include <gpu/FrameIO.h>
@ -29,9 +30,7 @@
#include <VrApi.h>
#include <VrApi_Input.h>
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<HandController> 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<void>("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<std::mutex> 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<std::mutex> 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 {

View file

@ -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<gpu::Backend> _backend;
std::atomic<size_t> _presentCount{ 0 };
std::mutex _frameLock;
std::queue<gpu::FramePointer> _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();
};

View file

@ -11,30 +11,33 @@
#include <QtGui/QGuiApplication>
#include <QtCore/QTimer>
#include <QtCore/QFileInfo>
#include <QtAndroidExtras/QAndroidJniObject>
#include <Trace.h>
#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<tracing::Tracer>();
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;
}

View file

@ -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);
}
}
}

View file

@ -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));
}
}

View file

@ -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)

View file

@ -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<String>()
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')
}

View file

@ -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

View file

@ -0,0 +1,49 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="io.highfidelity.questInterface"
android:installLocation="auto">
<uses-feature android:glEsVersion="0x00030002" android:required="true" />
<uses-permission android:name="android.permission.VIBRATE"/>
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
<uses-feature android:name="android.hardware.sensor.accelerometer" android:required="true"/>
<uses-feature android:name="android.hardware.sensor.gyroscope" android:required="true"/>
<uses-feature android:name="android.software.vr.mode" android:required="true"/>
<uses-feature android:name="android.hardware.vr.high_performance" android:required="true"/>
<application
android:name="org.qtproject.qt5.android.bindings.QtApplication"
android:label="@string/app_name"
android:allowBackup="true">
<meta-data android:name="com.samsung.android.vr.application.mode" android:value="vr_only"/>
<activity
android:name=".PermissionsChecker"
android:launchMode="singleTask"
android:screenOrientation="landscape"
android:excludeFromRecents="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.INFO" />
</intent-filter>
</activity>
<activity
android:configChanges="orientation|uiMode|screenLayout|screenSize|smallestScreenSize|locale|fontScale|keyboard|keyboardHidden|navigation"
android:name=".InterfaceActivity"
android:label="@string/app_name"
android:launchMode="singleTask">
<meta-data android:name="android.app.lib_name" android:value="questInterface"/>
<meta-data android:name="android.app.qt_libs_resource_id" android:resource="@array/qt_libs"/>
<meta-data android:name="android.app.bundled_in_lib_resource_id" android:resource="@array/bundled_in_lib"/>
<meta-data android:name="android.app.bundled_in_assets_resource_id" android:resource="@array/bundled_in_assets"/>
<meta-data android:name="android.app.load_local_libs" android:value="plugins/platforms/android/libqtforandroid.so:plugins/bearer/libqandroidbearer.so:lib/libQt5QuickParticles.so"/>
<meta-data android:name="android.app.background_running" android:value="false"/>
<meta-data android:name="android.app.auto_screen_scale_factor" android:value="false"/>
<meta-data android:name="android.app.extract_android_style" android:value="full"/>
</activity>
</application>
</manifest>

View file

@ -0,0 +1,106 @@
#include <functional>
#include <QtCore/QBuffer>
#include <QtCore/QDebug>
#include <QtCore/QDir>
#include <QtCore/QFile>
#include <QtCore/QThread>
#include <QtCore/QStringList>
#include <QtCore/QStandardPaths>
#include <QtCore/QTextStream>
#include <QtCore/QObject>
#include <QtAndroidExtras/QAndroidJniObject>
#include <QtAndroidExtras/QtAndroid>
#include <android/log.h>
#include <android/asset_manager.h>
#include <android/asset_manager_jni.h>
#include <shared/Storage.h>
#include <AddressManager.h>
#include <AndroidHelper.h>
#include <udt/PacketHeaders.h>
#include <OVR_Platform.h>
#include <OVR_Functions_Voip.h>
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<void>("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);
}
}

View file

@ -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);
}
}

View file

@ -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();
}
}
}

View file

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<!--suppress AndroidUnknownAttribute -->
<vector xmlns:api24="http://schemas.android.com/apk/res/android" xmlns:android="http://schemas.android.com/apk/res/android"
android:viewportWidth="192"
android:viewportHeight="192"
android:width="192dp"
android:height="192dp">
<path
android:pathData="M189.5 96.5A93.5 93.5 0 0 1 96 190 93.5 93.5 0 0 1 2.5 96.5 93.5 93.5 0 0 1 96 3 93.5 93.5 0 0 1 189.5 96.5Z"
android:fillColor="#333333" />
<path
android:pathData="M96.2 173.1c-10.3 0 -20.4 -2.1 -29.8 -6 -9.2 -3.8 -17.3 -9.4 -24.3 -16.4 -7 -7 -12.6 -15.2 -16.4 -24.3 -4.1 -9.6 -6.2 -19.6 -6.2 -30 0 -10.3 2.1 -20.4 6 -29.8 3.8 -9.2 9.4 -17.3 16.4 -24.3 7 -7 15.2 -12.6 24.3 -16.4 9.5 -4 19.5 -6 29.8 -6 10.3 0 20.4 2.1 29.8 6 9.2 3.8 17.3 9.4 24.3 16.4 7 7 12.6 15.2 16.4 24.3 4 9.5 6 19.5 6 29.8 0 10.3 -2.1 20.4 -6 29.8 -3.8 9.2 -9.4 17.3 -16.4 24.3 -7 7 -15.2 12.6 -24.3 16.4 -9.2 4.1 -19.3 6.2 -29.6 6.2zm0 -145.3c-37.8 0 -68.6 30.8 -68.6 68.6 0 37.8 30.8 68.6 68.6 68.6 37.8 0 68.6 -30.8 68.6 -68.6 0 -37.8 -30.8 -68.6 -68.6 -68.6z"
android:fillColor="#00b4f0" />
<path
android:pathData="M119.6 129l0 -53.8c3.4 -1.1 5.8 -4.3 5.8 -8 0 -4.6 -3.8 -8.4 -8.4 -8.4 -4.6 0 -8.4 3.8 -8.4 8.4 0 3.6 2.2 6.6 5.4 7.9l0 25L79 83.8 79 64c3.4 -1.1 5.8 -4.3 5.8 -8 0 -4.6 -3.8 -8.4 -8.4 -8.4 -4.6 0 -8.4 3.8 -8.4 8.4 0 3.6 2.2 6.6 5.4 7.9l0 54.1c-3.1 1.2 -5.4 4.3 -5.4 7.9 0 4.6 3.8 8.4 8.4 8.4 4.6 0 8.4 -3.8 8.4 -8.4 0 -3.7 -2.4 -6.9 -5.8 -8l0 -27.3 35 16.3 0 22.2c-3.1 1.2 -5.4 4.3 -5.4 7.9 0 4.6 3.8 8.4 8.4 8.4 4.6 0 8.4 -3.8 8.4 -8.4 0 -3.8 -2.4 -6.9 -5.8 -8z"
android:fillColor="#00b4f0" />
</vector>

View file

@ -0,0 +1,3 @@
<resources>
<string name="app_name" translatable="false">Interface</string>
</resources>

View file

@ -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')

View file

@ -1 +1,2 @@
org.gradle.jvmargs=-Xms2g -Xmx4g
android.debug.obsoleteApi=true

View file

@ -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

View file

@ -15,3 +15,7 @@ android {
targetCompatibility JavaVersion.VERSION_1_8
}
}
dependencies {
implementation project(path: ':qt')
}

View file

@ -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;
}
}

View file

@ -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();
}
//---------------------------------------------------------------------------

View file

@ -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')
}

View file

@ -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})

View file

@ -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']
},

View file

@ -23,7 +23,9 @@
"invert"
],
"to": "Actions.Pitch"
}
},
{ "from": "TouchscreenVirtualPad.RB", "to": "Standard.RB"}
]
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

View file

@ -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);

View file

@ -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
}

View file

@ -9,6 +9,7 @@
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include "Application.h"
#include <chrono>
@ -37,7 +38,6 @@
#include <QtNetwork/QLocalSocket>
#include <QtNetwork/QLocalServer>
#include <QtQml/QQmlContext>
#include <QtQml/QQmlEngine>
#include <QtQuick/QQuickWindow>
@ -51,6 +51,7 @@
#include <QProcessEnvironment>
#include <QTemporaryDir>
#include <gl/QOpenGLContextWrapper.h>
#include <gl/GLWindow.h>
#include <gl/GLHelpers.h>
@ -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 <DesktopPreviewProvider.h>
#include "AboutUtil.h"
#if defined(Q_OS_WIN)
@ -622,8 +627,6 @@ public:
switch (type) {
case NestableType::Entity:
return getEntityModelProvider(static_cast<EntityItemID>(uuid));
case NestableType::Overlay:
return nullptr;
case NestableType::Avatar:
return getAvatarModelProvider(uuid);
}
@ -1752,7 +1755,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
@ -1855,6 +1858,8 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
this->installEventFilter(this);
#ifdef HAVE_DDE
auto ddeTracker = DependencyManager::get<DdeFaceTracker>();
ddeTracker->init();
@ -3095,7 +3100,7 @@ void Application::initializeUi() {
}
if (TouchscreenVirtualPadDevice::NAME == inputPlugin->getName()) {
_touchscreenVirtualPadDevice = std::dynamic_pointer_cast<TouchscreenVirtualPadDevice>(inputPlugin);
#if defined(Q_OS_ANDROID)
#if defined(ANDROID_APP_INTERFACE)
auto& virtualPadManager = VirtualPad::Manager::instance();
connect(&virtualPadManager, &VirtualPad::Manager::hapticFeedbackRequested,
this, [](int duration) {
@ -3627,10 +3632,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();
@ -8247,6 +8256,7 @@ void Application::loadDomainConnectionDialog() {
}
void Application::toggleLogDialog() {
#ifndef ANDROID_APP_QUEST_INTERFACE
if (getLoginDialogPoppedUp()) {
return;
}
@ -8270,6 +8280,7 @@ void Application::toggleLogDialog() {
} else {
_logDialog->show();
}
#endif
}
void Application::recreateLogWindow(int keepOnTop) {
@ -9135,17 +9146,23 @@ void Application::beforeEnterBackground() {
void Application::enterBackground() {
QMetaObject::invokeMethod(DependencyManager::get<AudioClient>().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<AudioClient>().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>();
nodeList->setSendDomainServerCheckInEnabled(true);
}

View file

@ -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();

View file

@ -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();

View file

@ -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

View file

@ -137,13 +137,14 @@ PickResultPointer StylusPick::getDefaultResult(const QVariantMap& pickVariant) c
}
PickResultPointer StylusPick::getEntityIntersection(const StylusTip& pick) {
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;
}
@ -158,8 +159,11 @@ PickResultPointer StylusPick::getEntityIntersection(const StylusTip& pick) {
glm::vec3 normal = entityRotation * Vectors::UNIT_Z;
float distance = glm::dot(pick.position - entityPosition, normal);
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::projectOntoEntityXYPlane(target, intersection, false);
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()) {

View file

@ -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<QUuid> includeItems = _keyboardLayers[_layerIndex].keys().toVector();
auto pointerManager = DependencyManager::get<PointerManager>();
pointerManager->setIncludeItems(_leftHandStylus, includeItems);
pointerManager->setIncludeItems(_rightHandStylus, includeItems);
}
}
void Keyboard::updateTextDisplay() {
auto myAvatar = DependencyManager::get<AvatarManager>()->getMyAvatar();
auto entityScriptingInterface = DependencyManager::get<EntityScriptingInterface>();
@ -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<QUuid> 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>();
pointerManager->setIncludeItems(_leftHandStylus, includeItems);
pointerManager->setIncludeItems(_rightHandStylus, includeItems);
addIncludeItemsToMallets();
});
request->send();

View file

@ -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;

View file

@ -79,7 +79,16 @@ void Overlays::cleanupAllOverlays() {
cleanupOverlaysToDelete();
}
void Overlays::init() {}
void Overlays::init() {
auto entityScriptingInterface = DependencyManager::get<EntityScriptingInterface>().data();
auto pointerManager = DependencyManager::get<PointerManager>();
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) {
cleanupOverlaysToDelete();
@ -343,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);

View file

@ -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);

View file

@ -64,7 +64,11 @@ namespace render {
return keyBuilder.build();
}
template <> const Item::Bound payloadGetBound(const AvatarSharedPointer& avatar) {
return static_pointer_cast<Avatar>(avatar)->getRenderBounds();
auto avatarPtr = static_pointer_cast<Avatar>(avatar);
if (avatarPtr) {
return avatarPtr->getRenderBounds();
}
return Item::Bound();
}
template <> void payloadRender(const AvatarSharedPointer& avatar, RenderArgs* args) {
auto avatarPtr = static_pointer_cast<Avatar>(avatar);
@ -75,10 +79,15 @@ namespace render {
}
template <> uint32_t metaFetchMetaSubItems(const AvatarSharedPointer& avatar, ItemIDs& subItems) {
auto avatarPtr = static_pointer_cast<Avatar>(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;
}
@ -626,12 +635,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;
@ -855,15 +870,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;
}
}
@ -886,9 +903,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);
}
@ -931,6 +954,11 @@ void Avatar::simulateAttachments(float deltaTime) {
}
}
}
if (_ancestorChainRenderableVersion != _lastAncestorChainRenderableVersion) {
_lastAncestorChainRenderableVersion = _ancestorChainRenderableVersion;
updateDescendantRenderIDs();
}
}
float Avatar::getBoundingRadius() const {
@ -1608,7 +1636,6 @@ void Avatar::setAttachmentData(const QVector<AttachmentData>& attachmentData) {
}
}
int Avatar::parseDataFromBuffer(const QByteArray& buffer) {
PerformanceTimer perfTimer("unpack");
if (!_initialized) {
@ -2084,3 +2111,60 @@ void Avatar::clearAvatarGrabData(const QUuid& id) {
}
});
}
uint32_t Avatar::appendSubMetaItems(render::ItemIDs& subItems) {
return _subItemLock.resultWithReadLock<uint32_t>([&] {
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<EntityTreeRenderer>();
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<EntityItem>(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());
}
}
}
}
});
});
}
});
}

View file

@ -498,6 +498,8 @@ public:
const std::vector<MultiSphereShape>& getMultiSphereShapes() const { return _multiSphereShapes; }
void tearDownGrabs();
uint32_t appendSubMetaItems(render::ItemIDs& subItems);
signals:
void targetScaleChanged(float targetScale);
@ -638,8 +640,6 @@ protected:
RateCounter<> _skeletonModelSimulationRate;
RateCounter<> _jointDataSimulationRate;
protected:
class AvatarEntityDataHash {
public:
AvatarEntityDataHash(uint32_t h) : hash(h) {};
@ -699,6 +699,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

View file

@ -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<CompositorHelper>()->getPoint2DTransform(virtualPadManager.getLeftVirtualPad()->getCurrentTouch(),
_virtualPadPixelSize, _virtualPadPixelSize);
auto jumpTransform = DependencyManager::get<CompositorHelper>()->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<CompositorHelper>()->getPoint2DTransform(
buttonPosition,
_pixelSize, _pixelSize);
batch.setResourceTexture(0, _texture);
batch.setModelTransform(transform);
batch.draw(gpu::TRIANGLE_STRIP, 4);
}
#endif

View file

@ -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<VirtualPadButton> _virtualPadButtons;
#endif
};

View file

@ -320,6 +320,7 @@ bool EntityRenderer::addToScene(const ScenePointer& scene, Transaction& transact
transaction.resetItem(_renderItemID, renderPayload);
onAddToScene(_entity);
updateInScene(scene, transaction);
_entity->bumpAncestorChainRenderableVersion();
return true;
}
@ -327,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) {
@ -352,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
//

View file

@ -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()() };

View file

@ -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<PayloadProxyInterface>(getRenderItemID(), [](PayloadProxyInterface& data) {
auto entityRenderer = static_cast<EntityRenderer*>(&data);
entityRenderer->clearSubRenderItemIDs();
});
emit DependencyManager::get<scriptable::ModelProviderFactory>()->
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<PayloadProxyInterface>(getRenderItemID(), [newRenderItemIDs](PayloadProxyInterface& data) {
auto entityRenderer = static_cast<EntityRenderer*>(&data);
entityRenderer->setSubRenderItemIDs(newRenderItemIDs);
});
entity->bumpAncestorChainRenderableVersion();
processMaterials();
}
}

View file

@ -2935,6 +2935,7 @@ void EntityItem::setVisible(bool value) {
});
if (changed) {
bumpAncestorChainRenderableVersion();
emit requestRenderUpdate();
}
}

View file

@ -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
}

View file

@ -388,10 +388,23 @@ ShaderPointer Deserializer::readShader(const json& node) {
return nullptr;
}
static std::map<std::string, uint32_t> 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:

View file

@ -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;

View file

@ -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<QTouchEvent::TouchPoint>& 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<InputDevice> 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<int, TouchType> &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<int, TouchscreenVirtualPadDevice::TouchType> &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<QTouchEvent::TouchPoint> &tPoints, std::map<int, TouchType> 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;
}

View file

@ -15,6 +15,7 @@
#include <controllers/InputDevice.h>
#include "InputPlugin.h"
#include <QtGui/qtouchdevice.h>
#include <QtGui/QList>
#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<InputDevice> 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> _inputDevice;
};
class TouchscreenButtonsManager {
public:
TouchscreenButtonsManager();
QVector<TouchscreenButton> 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<int, TouchType> &globalUnusedTouches);
void saveUnusedTouches(std::map<int, TouchType> &unusedTouchesInEvent, glm::vec2 thisPoint, int thisPointId);
void processBeginOrEnd(glm::vec2 thisPoint, const QList<QTouchEvent::TouchPoint>& tPoints, std::map<int, TouchType> 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<int, TouchType> _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);

View file

@ -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<const TextureExtra*>(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<gpu::TextureSource>(_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));
}
}

View file

@ -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<NetworkTexture>& 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;
};

View file

@ -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<const GeometryExtra*>(extra);
_mapping = geometryExtra ? geometryExtra->mapping : QVariantHash();
_textureBaseUrl = geometryExtra ? resolveTextureBaseUrl(_url, geometryExtra->textureBaseUrl) : QUrl();

View file

@ -355,7 +355,7 @@ QSharedPointer<Resource> 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<Resource> 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);

View file

@ -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; }

View file

@ -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);

View file

@ -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) {

View file

@ -0,0 +1,7 @@
layout(location=0) in vec4 _color;
layout(location=0) out vec4 _fragColor0;
void main(void) {
_fragColor0 = _color;
}

View file

@ -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;

View file

@ -0,0 +1,3 @@
#version 310 es
#define GPU_GLES
#define GPU_GLES_310

View file

@ -1,5 +1,3 @@
#version 410 core
#define GPU_GL410
#define BITFIELD int
#if defined(VULKAN)
#extension GL_ARB_shading_language_420pack : require

View file

@ -0,0 +1,2 @@
#version 410 core
#define GPU_GL410

View file

@ -1,5 +1,3 @@
#version 450 core
#define GPU_GL450
#define GPU_SSBO_TRANSFORM_OBJECT
#define BITFIELD int
#define LAYOUT(X) layout(X)

View file

@ -0,0 +1,2 @@
#version 450 core
#define GPU_GL450

View file

@ -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;

View file

@ -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")

View file

@ -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)

View file

@ -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<QUrl>()) {
toReturn[texture] = newURL.toUrl();
} else if (newURL.canConvert<QString>()) {
toReturn[texture] = QUrl(newURL.toString());
} else {
toReturn[texture] = newURL;
}
}
return toReturn;

View file

@ -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();
}
}

View file

@ -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<SpatiallyNestable> {
@ -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<GrabPointer> _grabs; // upon this thing
mutable std::atomic<uint32_t> _ancestorChainRenderableVersion { 0 };
private:
SpatiallyNestable() = delete;
const NestableType _nestableType; // EntityItem or an AvatarData

View file

@ -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);

View file

@ -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<std::mutex> 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) {

View file

@ -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<OffscreenUi>();
_source = properties[SOURCE_PROPERTY].toString();
@ -150,6 +151,7 @@ void QmlWindowClass::initQml(QVariantMap properties) {
Q_ASSERT(_qmlWindow);
Q_ASSERT(dynamic_cast<const QQuickItem*>(_qmlWindow.data()));
#endif
}
void QmlWindowClass::qmlToScript(const QVariant& message) {

View file

@ -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;
}

View file

@ -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<Button, glm::vec2> _buttonsPositions;
};
}

View file

@ -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

View file

@ -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",

View file

@ -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();
}

View file

@ -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,

View file

@ -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: