mirror of
https://github.com/JulianGro/overte.git
synced 2025-04-09 01:22:21 +02:00
Merge remote-tracking branch 'upstream/master' into animSplineIK
This commit is contained in:
commit
c9db426ce4
116 changed files with 2193 additions and 978 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -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
65
BUILD_QUEST.md
Normal 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_
|
||||
|
|
@ -101,6 +101,13 @@ if (ANDROID)
|
|||
add_definitions(-DCUSTOM_DISPLAY_PLUGINS)
|
||||
set(PLATFORM_PLUGIN_LIBRARIES oculusMobile oculusMobilePlugin)
|
||||
endif()
|
||||
|
||||
# Allow client code to use preprocessor macros to distinguish between quest and non-quest builds
|
||||
if (${HIFI_ANDROID_APP} STREQUAL "questInterface")
|
||||
add_definitions(-DANDROID_APP_QUEST_INTERFACE)
|
||||
elseif(${HIFI_ANDROID_APP} STREQUAL "interface")
|
||||
add_definitions(-DANDROID_APP_INTERFACE)
|
||||
endif()
|
||||
else ()
|
||||
set(PLATFORM_QT_COMPONENTS WebEngine Xml)
|
||||
endif ()
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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>
|
||||
|
|
30
android/apps/questFramePlayer/src/main/cpp/AndroidHelper.cpp
Normal file
30
android/apps/questFramePlayer/src/main/cpp/AndroidHelper.cpp
Normal 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();
|
||||
}
|
||||
|
43
android/apps/questFramePlayer/src/main/cpp/AndroidHelper.h
Normal file
43
android/apps/questFramePlayer/src/main/cpp/AndroidHelper.h
Normal 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
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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();
|
||||
};
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
|
16
android/apps/questInterface/CMakeLists.txt
Normal file
16
android/apps/questInterface/CMakeLists.txt
Normal 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)
|
149
android/apps/questInterface/build.gradle
Normal file
149
android/apps/questInterface/build.gradle
Normal 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')
|
||||
}
|
25
android/apps/questInterface/proguard-rules.pro
vendored
Normal file
25
android/apps/questInterface/proguard-rules.pro
vendored
Normal 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
|
49
android/apps/questInterface/src/main/AndroidManifest.xml
Normal file
49
android/apps/questInterface/src/main/AndroidManifest.xml
Normal 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>
|
106
android/apps/questInterface/src/main/cpp/native.cpp
Normal file
106
android/apps/questInterface/src/main/cpp/native.cpp
Normal 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);
|
||||
}
|
||||
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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>
|
|
@ -0,0 +1,3 @@
|
|||
<resources>
|
||||
<string name="app_name" translatable="false">Interface</string>
|
||||
</resources>
|
|
@ -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')
|
||||
|
|
|
@ -1 +1,2 @@
|
|||
org.gradle.jvmargs=-Xms2g -Xmx4g
|
||||
android.debug.obsoleteApi=true
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -15,3 +15,7 @@ android {
|
|||
targetCompatibility JavaVersion.VERSION_1_8
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation project(path: ':qt')
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
|
|
|
@ -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')
|
||||
}
|
||||
|
|
|
@ -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})
|
||||
|
|
|
@ -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']
|
||||
},
|
||||
|
|
|
@ -23,7 +23,9 @@
|
|||
"invert"
|
||||
],
|
||||
"to": "Actions.Pitch"
|
||||
}
|
||||
},
|
||||
|
||||
{ "from": "TouchscreenVirtualPad.RB", "to": "Standard.RB"}
|
||||
|
||||
]
|
||||
}
|
||||
|
|
BIN
interface/resources/images/handshake.png
Normal file
BIN
interface/resources/images/handshake.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 20 KiB |
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
@ -33,15 +33,19 @@ Rectangle {
|
|||
property bool balanceReceived: false;
|
||||
property bool availableUpdatesReceived: false;
|
||||
property bool itemInfoReceived: false;
|
||||
property bool dataReady: itemInfoReceived && ownershipStatusReceived && balanceReceived && availableUpdatesReceived;
|
||||
property string baseItemName: "";
|
||||
property string itemName;
|
||||
property string itemId;
|
||||
property string itemHref;
|
||||
property string itemAuthor;
|
||||
property int itemEdition: -1;
|
||||
property bool hasSomethingToTradeIn: alreadyOwned && (itemEdition > 0); // i.e., don't trade in your artist's proof
|
||||
property bool isTradingIn: isUpdating && hasSomethingToTradeIn;
|
||||
property bool isStocking: availability === 'not for sale' && creator === Account.username;
|
||||
property string certificateId;
|
||||
property double balanceAfterPurchase;
|
||||
property bool alreadyOwned: false;
|
||||
property bool alreadyOwned: false; // Including proofs
|
||||
property int itemPrice: -1;
|
||||
property bool isCertified;
|
||||
property string itemType: "unknown";
|
||||
|
@ -56,6 +60,8 @@ Rectangle {
|
|||
property string referrer;
|
||||
property bool isInstalled;
|
||||
property bool isUpdating;
|
||||
property string availability: "available";
|
||||
property string creator: "";
|
||||
property string baseAppURL;
|
||||
property int currentUpdatesPage: 1;
|
||||
// Style
|
||||
|
@ -434,7 +440,7 @@ Rectangle {
|
|||
anchors.top: parent.top;
|
||||
anchors.left: itemPreviewImage.right;
|
||||
anchors.leftMargin: 12;
|
||||
anchors.right: itemPriceContainer.left;
|
||||
anchors.right: parent.right;
|
||||
anchors.rightMargin: 8;
|
||||
height: 30;
|
||||
// Style
|
||||
|
@ -449,21 +455,22 @@ Rectangle {
|
|||
Item {
|
||||
id: itemPriceContainer;
|
||||
// Anchors
|
||||
anchors.top: parent.top;
|
||||
anchors.right: parent.right;
|
||||
anchors.top: itemNameText.bottom;
|
||||
anchors.topMargin: 8;
|
||||
anchors.left: itemNameText.left;
|
||||
height: 30;
|
||||
width: itemPriceTextLabel.width + itemPriceText.width + 20;
|
||||
width: itemPriceText.width + 20;
|
||||
|
||||
// "HFC" balance label
|
||||
// "HFC" label
|
||||
HiFiGlyphs {
|
||||
id: itemPriceTextLabel;
|
||||
visible: !(root.isUpdating && root.itemEdition > 0) && (root.itemPrice > 0);
|
||||
visible: !isTradingIn && (root.itemPrice > 0);
|
||||
text: hifi.glyphs.hfc;
|
||||
// Size
|
||||
size: 30;
|
||||
// Anchors
|
||||
anchors.right: itemPriceText.left;
|
||||
anchors.rightMargin: 4;
|
||||
anchors.right: parent.right;
|
||||
//anchors.rightMargin: 4;
|
||||
anchors.top: parent.top;
|
||||
anchors.topMargin: 0;
|
||||
width: paintedWidth;
|
||||
|
@ -473,13 +480,15 @@ Rectangle {
|
|||
}
|
||||
FiraSansSemiBold {
|
||||
id: itemPriceText;
|
||||
text: (root.isUpdating && root.itemEdition > 0) ? "FREE\nUPDATE" : ((root.itemPrice === -1) ? "--" : ((root.itemPrice > 0) ? root.itemPrice : "FREE"));
|
||||
text: isTradingIn ? "FREE\nUPDATE" :
|
||||
(isStocking ? "Free for creator" :
|
||||
((root.itemPrice === -1) ? "--" : ((root.itemPrice > 0) ? root.itemPrice : "FREE")));
|
||||
// Text size
|
||||
size: (root.isUpdating && root.itemEdition > 0) ? 20 : 26;
|
||||
size: isTradingIn ? 20 : 26;
|
||||
// Anchors
|
||||
anchors.top: parent.top;
|
||||
anchors.right: parent.right;
|
||||
anchors.rightMargin: 16;
|
||||
anchors.left: itemPriceTextLabel.visible ? itemPriceTextLabel.right : parent.left;
|
||||
anchors.leftMargin: 4;
|
||||
width: paintedWidth;
|
||||
height: paintedHeight;
|
||||
// Style
|
||||
|
@ -571,7 +580,7 @@ Rectangle {
|
|||
// "View in Inventory" button
|
||||
HifiControlsUit.Button {
|
||||
id: viewInMyPurchasesButton;
|
||||
visible: false;
|
||||
visible: isCertified && dataReady && (isUpdating ? !hasSomethingToTradeIn : alreadyOwned);
|
||||
color: hifi.buttons.blue;
|
||||
colorScheme: hifi.colorSchemes.light;
|
||||
anchors.top: buyTextContainer.visible ? buyTextContainer.bottom : checkoutActionButtonsContainer.top;
|
||||
|
@ -592,8 +601,8 @@ Rectangle {
|
|||
// "Buy" button
|
||||
HifiControlsUit.Button {
|
||||
id: buyButton;
|
||||
visible: !((root.itemType === "avatar" || root.itemType === "app") && viewInMyPurchasesButton.visible)
|
||||
enabled: (root.balanceAfterPurchase >= 0 && ownershipStatusReceived && balanceReceived && availableUpdatesReceived) || (!root.isCertified) || root.isUpdating;
|
||||
visible: isTradingIn || !alreadyOwned || isStocking || !(root.itemType === "avatar" || root.itemType === "app");
|
||||
enabled: (root.balanceAfterPurchase >= 0 && dataReady) || (!root.isCertified) || root.isUpdating;
|
||||
color: viewInMyPurchasesButton.visible ? hifi.buttons.white : hifi.buttons.blue;
|
||||
colorScheme: hifi.colorSchemes.light;
|
||||
anchors.top: viewInMyPurchasesButton.visible ? viewInMyPurchasesButton.bottom :
|
||||
|
@ -602,10 +611,15 @@ Rectangle {
|
|||
height: 50;
|
||||
anchors.left: parent.left;
|
||||
anchors.right: parent.right;
|
||||
text: (root.isUpdating && root.itemEdition > 0) ? "CONFIRM UPDATE" : (((root.isCertified) ? ((ownershipStatusReceived && balanceReceived && availableUpdatesReceived) ?
|
||||
((viewInMyPurchasesButton.visible && !root.isUpdating) ? "Get It Again" : "Confirm") : "--") : "Get Item"));
|
||||
text: isTradingIn ?
|
||||
"CONFIRM UPDATE" :
|
||||
(((root.isCertified) ?
|
||||
(dataReady ?
|
||||
((viewInMyPurchasesButton.visible && !root.isUpdating) ? "Get It Again" : "Confirm") :
|
||||
"--") :
|
||||
"Get Item"));
|
||||
onClicked: {
|
||||
if (root.isUpdating && root.itemEdition > 0) {
|
||||
if (isTradingIn) {
|
||||
// If we're updating an app, the existing app needs to be uninstalled.
|
||||
// This call will fail/return `false` if the app isn't installed, but that's OK.
|
||||
if (root.itemType === "app") {
|
||||
|
@ -1063,7 +1077,11 @@ Rectangle {
|
|||
buyButton.color = hifi.buttons.red;
|
||||
root.shouldBuyWithControlledFailure = true;
|
||||
} else {
|
||||
buyButton.text = (root.isCertified ? ((ownershipStatusReceived && balanceReceived && availableUpdatesReceived) ? (root.alreadyOwned ? "Buy Another" : "Buy"): "--") : "Get Item");
|
||||
buyButton.text = (root.isCertified ?
|
||||
(dataReady ?
|
||||
(root.alreadyOwned ? "Buy Another" : "Buy") :
|
||||
"--") :
|
||||
"Get Item");
|
||||
buyButton.color = hifi.buttons.blue;
|
||||
root.shouldBuyWithControlledFailure = false;
|
||||
}
|
||||
|
@ -1091,6 +1109,8 @@ Rectangle {
|
|||
root.itemPrice = result.data.cost;
|
||||
root.itemAuthor = result.data.creator;
|
||||
root.itemType = result.data.item_type || "unknown";
|
||||
root.availability = result.data.availability;
|
||||
root.creator = result.data.creator;
|
||||
if (root.itemType === "unknown") {
|
||||
root.itemHref = result.data.review_url;
|
||||
} else {
|
||||
|
@ -1139,7 +1159,7 @@ Rectangle {
|
|||
signal sendToScript(var message);
|
||||
|
||||
function canBuyAgain() {
|
||||
return (root.itemType === "entity" || root.itemType === "wearable" || root.itemType === "contentSet" || root.itemType === "unknown");
|
||||
return root.itemType === "entity" || root.itemType === "wearable" || root.itemType === "contentSet" || root.itemType === "unknown" || isStocking;
|
||||
}
|
||||
|
||||
function handleContentSets() {
|
||||
|
@ -1185,29 +1205,23 @@ Rectangle {
|
|||
|
||||
function refreshBuyUI() {
|
||||
if (root.isCertified) {
|
||||
if (root.ownershipStatusReceived && root.balanceReceived && root.availableUpdatesReceived) {
|
||||
if (dataReady) {
|
||||
buyText.text = "";
|
||||
|
||||
// If the user IS on the checkout page for the updated version of an owned item...
|
||||
if (root.isUpdating) {
|
||||
// If the user HAS already selected a specific edition to update...
|
||||
if (root.itemEdition > 0) {
|
||||
if (hasSomethingToTradeIn) {
|
||||
buyText.text = "By pressing \"Confirm Update\", you agree to trade in your old item for the updated item that replaces it.";
|
||||
buyTextContainer.color = "#FFFFFF";
|
||||
buyTextContainer.border.color = "#FFFFFF";
|
||||
// Else if the user HAS NOT selected a specific edition to update...
|
||||
} else {
|
||||
viewInMyPurchasesButton.visible = true;
|
||||
|
||||
handleBuyAgainLogic();
|
||||
}
|
||||
// If the user IS NOT on the checkout page for the updated verison of an owned item...
|
||||
// (i.e. they are checking out an item "normally")
|
||||
} else {
|
||||
if (root.alreadyOwned) {
|
||||
viewInMyPurchasesButton.visible = true;
|
||||
}
|
||||
|
||||
handleBuyAgainLogic();
|
||||
}
|
||||
} else {
|
||||
|
|
|
@ -121,7 +121,7 @@ Rectangle {
|
|||
marketplaceItem.description = result.data.description;
|
||||
marketplaceItem.attributions = result.data.attributions;
|
||||
marketplaceItem.license = result.data.license;
|
||||
marketplaceItem.available = result.data.availability === "available";
|
||||
marketplaceItem.availability = result.data.availability;
|
||||
marketplaceItem.created_at = result.data.created_at;
|
||||
marketplaceItemScrollView.contentHeight = marketplaceItemContent.height;
|
||||
itemsList.visible = false;
|
||||
|
@ -539,7 +539,7 @@ Rectangle {
|
|||
creator: model.creator
|
||||
category: model.primary_category
|
||||
price: model.cost
|
||||
available: model.availability === "available"
|
||||
availability: model.availability
|
||||
isLoggedIn: root.isLoggedIn;
|
||||
|
||||
onShowItem: {
|
||||
|
@ -711,7 +711,7 @@ Rectangle {
|
|||
topMargin: 10;
|
||||
leftMargin: 15;
|
||||
}
|
||||
height: visible ? childrenRect.height : 0
|
||||
height: visible ? 36 : 0
|
||||
|
||||
RalewayRegular {
|
||||
id: sortText
|
||||
|
@ -733,8 +733,9 @@ Rectangle {
|
|||
top: parent.top
|
||||
leftMargin: 20
|
||||
}
|
||||
|
||||
width: root.isLoggedIn ? 342 : 262
|
||||
height: 36
|
||||
height: parent.height
|
||||
|
||||
radius: 4
|
||||
border.width: 1
|
||||
|
|
|
@ -33,11 +33,11 @@ Rectangle {
|
|||
property string creator: ""
|
||||
property var categories: []
|
||||
property int price: 0
|
||||
property string availability: "unknown"
|
||||
property var attributions: []
|
||||
property string description: ""
|
||||
property string license: ""
|
||||
property string posted: ""
|
||||
property bool available: false
|
||||
property string created_at: ""
|
||||
property bool isLoggedIn: false;
|
||||
property int edition: -1;
|
||||
|
@ -264,9 +264,15 @@ Rectangle {
|
|||
}
|
||||
height: 50
|
||||
|
||||
text: root.edition >= 0 ? "UPGRADE FOR FREE" : (root.available ? (root.price ? root.price : "FREE") : "UNAVAILABLE (not for sale)")
|
||||
enabled: root.edition >= 0 || root.available
|
||||
buttonGlyph: root.available ? (root.price ? hifi.glyphs.hfc : "") : ""
|
||||
property bool isNFS: availability === "not for sale" // Note: server will say "sold out" or "invalidated" before it says NFS
|
||||
property bool isMine: creator === Account.username
|
||||
property bool isUpgrade: root.edition >= 0
|
||||
property int costToMe: ((isMine && isNFS) || isUpgrade) ? 0 : price
|
||||
property bool isAvailable: costToMe >= 0
|
||||
|
||||
text: isUpgrade ? "UPGRADE FOR FREE" : (isAvailable ? (costToMe || "FREE") : availability)
|
||||
enabled: isAvailable
|
||||
buttonGlyph: isAvailable ? (costToMe ? hifi.glyphs.hfc : "") : ""
|
||||
color: hifi.buttons.blue
|
||||
|
||||
onClicked: root.buy();
|
||||
|
|
|
@ -34,7 +34,7 @@ Rectangle {
|
|||
property string creator: ""
|
||||
property string category: ""
|
||||
property int price: 0
|
||||
property bool available: false
|
||||
property string availability: "unknown"
|
||||
property bool isLoggedIn: false;
|
||||
|
||||
signal buy()
|
||||
|
@ -299,8 +299,16 @@ Rectangle {
|
|||
bottomMargin: 10
|
||||
}
|
||||
|
||||
text: root.price ? root.price : "FREE"
|
||||
buttonGlyph: root.price ? hifi.glyphs.hfc : ""
|
||||
property bool isNFS: availability === "not for sale" // Note: server will say "sold out" or "invalidated" before it says NFS
|
||||
property bool isMine: creator === Account.username
|
||||
property bool isUpgrade: root.edition >= 0
|
||||
property int costToMe: ((isMine && isNFS) || isUpgrade) ? 0 : price
|
||||
property bool isAvailable: costToMe >= 0
|
||||
|
||||
text: isUpgrade ? "UPGRADE FOR FREE" : (isAvailable ? (costToMe || "FREE") : availability)
|
||||
enabled: isAvailable
|
||||
buttonGlyph: isAvailable ? (costToMe ? hifi.glyphs.hfc : "") : ""
|
||||
|
||||
color: hifi.buttons.blue;
|
||||
|
||||
onClicked: root.buy();
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
@ -1747,7 +1750,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
|
|||
});
|
||||
_applicationStateDevice->setInputVariant(STATE_PLATFORM_ANDROID, []() -> float {
|
||||
#if defined(Q_OS_ANDROID)
|
||||
return 1;
|
||||
return 1 ;
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
|
@ -1850,6 +1853,8 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
|
|||
|
||||
this->installEventFilter(this);
|
||||
|
||||
|
||||
|
||||
#ifdef HAVE_DDE
|
||||
auto ddeTracker = DependencyManager::get<DdeFaceTracker>();
|
||||
ddeTracker->init();
|
||||
|
@ -1911,46 +1916,34 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
|
|||
}
|
||||
}, Qt::QueuedConnection);
|
||||
|
||||
EntityTree::setAddMaterialToEntityOperator([this](const QUuid& entityID, graphics::MaterialLayer material, const std::string& parentMaterialName) {
|
||||
EntityTreeRenderer::setAddMaterialToEntityOperator([this](const QUuid& entityID, graphics::MaterialLayer material, const std::string& parentMaterialName) {
|
||||
if (_aboutToQuit) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// try to find the renderable
|
||||
auto renderable = getEntities()->renderableForEntityId(entityID);
|
||||
if (renderable) {
|
||||
renderable->addMaterial(material, parentMaterialName);
|
||||
}
|
||||
|
||||
// even if we don't find it, try to find the entity
|
||||
auto entity = getEntities()->getEntity(entityID);
|
||||
if (entity) {
|
||||
entity->addMaterial(material, parentMaterialName);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
EntityTree::setRemoveMaterialFromEntityOperator([this](const QUuid& entityID, graphics::MaterialPointer material, const std::string& parentMaterialName) {
|
||||
EntityTreeRenderer::setRemoveMaterialFromEntityOperator([this](const QUuid& entityID, graphics::MaterialPointer material, const std::string& parentMaterialName) {
|
||||
if (_aboutToQuit) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// try to find the renderable
|
||||
auto renderable = getEntities()->renderableForEntityId(entityID);
|
||||
if (renderable) {
|
||||
renderable->removeMaterial(material, parentMaterialName);
|
||||
}
|
||||
|
||||
// even if we don't find it, try to find the entity
|
||||
auto entity = getEntities()->getEntity(entityID);
|
||||
if (entity) {
|
||||
entity->removeMaterial(material, parentMaterialName);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
|
||||
EntityTree::setAddMaterialToAvatarOperator([](const QUuid& avatarID, graphics::MaterialLayer material, const std::string& parentMaterialName) {
|
||||
EntityTreeRenderer::setAddMaterialToAvatarOperator([](const QUuid& avatarID, graphics::MaterialLayer material, const std::string& parentMaterialName) {
|
||||
auto avatarManager = DependencyManager::get<AvatarManager>();
|
||||
auto avatar = avatarManager->getAvatarBySessionID(avatarID);
|
||||
if (avatar) {
|
||||
|
@ -1959,7 +1952,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
|
|||
}
|
||||
return false;
|
||||
});
|
||||
EntityTree::setRemoveMaterialFromAvatarOperator([](const QUuid& avatarID, graphics::MaterialPointer material, const std::string& parentMaterialName) {
|
||||
EntityTreeRenderer::setRemoveMaterialFromAvatarOperator([](const QUuid& avatarID, graphics::MaterialPointer material, const std::string& parentMaterialName) {
|
||||
auto avatarManager = DependencyManager::get<AvatarManager>();
|
||||
auto avatar = avatarManager->getAvatarBySessionID(avatarID);
|
||||
if (avatar) {
|
||||
|
@ -2282,7 +2275,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
|
|||
|
||||
// Setup the mouse ray pick and related operators
|
||||
{
|
||||
auto mouseRayPick = std::make_shared<RayPick>(Vectors::ZERO, Vectors::UP, PickFilter(PickScriptingInterface::PICK_ENTITIES()), 0.0f, true);
|
||||
auto mouseRayPick = std::make_shared<RayPick>(Vectors::ZERO, Vectors::UP, PickFilter(PickScriptingInterface::PICK_ENTITIES() | PickScriptingInterface::PICK_LOCAL_ENTITIES()), 0.0f, true);
|
||||
mouseRayPick->parentTransform = std::make_shared<MouseTransformNode>();
|
||||
mouseRayPick->setJointState(PickQuery::JOINT_STATE_MOUSE);
|
||||
auto mouseRayPickID = DependencyManager::get<PickManager>()->addPick(PickQuery::Ray, mouseRayPick);
|
||||
|
@ -3099,7 +3092,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) {
|
||||
|
@ -3631,10 +3624,14 @@ void Application::handleSandboxStatus(QNetworkReply* reply) {
|
|||
}
|
||||
|
||||
// Get controller availability
|
||||
#ifdef ANDROID_APP_QUEST_INTERFACE
|
||||
bool hasHandControllers = true;
|
||||
#else
|
||||
bool hasHandControllers = false;
|
||||
if (PluginUtils::isViveControllerAvailable() || PluginUtils::isOculusTouchControllerAvailable()) {
|
||||
hasHandControllers = true;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Check HMD use (may be technically available without being in use)
|
||||
bool hasHMD = PluginUtils::isHMDAvailable();
|
||||
|
@ -8251,6 +8248,7 @@ void Application::loadDomainConnectionDialog() {
|
|||
}
|
||||
|
||||
void Application::toggleLogDialog() {
|
||||
#ifndef ANDROID_APP_QUEST_INTERFACE
|
||||
if (getLoginDialogPoppedUp()) {
|
||||
return;
|
||||
}
|
||||
|
@ -8274,6 +8272,7 @@ void Application::toggleLogDialog() {
|
|||
} else {
|
||||
_logDialog->show();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void Application::recreateLogWindow(int keepOnTop) {
|
||||
|
@ -9139,17 +9138,23 @@ void Application::beforeEnterBackground() {
|
|||
void Application::enterBackground() {
|
||||
QMetaObject::invokeMethod(DependencyManager::get<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);
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -137,13 +137,14 @@ PickResultPointer StylusPick::getDefaultResult(const QVariantMap& pickVariant) c
|
|||
}
|
||||
|
||||
PickResultPointer StylusPick::getEntityIntersection(const StylusTip& pick) {
|
||||
std::vector<StylusPickResult> results;
|
||||
auto entityTree = qApp->getEntities()->getTree();
|
||||
StylusPickResult nearestTarget(pick.toVariantMap());
|
||||
for (const auto& target : getIncludeItems()) {
|
||||
if (target.isNull()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
auto entity = qApp->getEntities()->getTree()->findEntityByEntityItemID(target);
|
||||
auto entity = entityTree->findEntityByEntityItemID(target);
|
||||
if (!entity) {
|
||||
continue;
|
||||
}
|
||||
|
@ -157,28 +158,24 @@ PickResultPointer StylusPick::getEntityIntersection(const StylusTip& pick) {
|
|||
|
||||
glm::vec3 normal = entityRotation * Vectors::UNIT_Z;
|
||||
float distance = glm::dot(pick.position - entityPosition, normal);
|
||||
glm::vec3 intersection = pick.position - (normal * distance);
|
||||
|
||||
glm::vec2 pos2D = RayPick::projectOntoEntityXYPlane(target, intersection, false);
|
||||
if (pos2D == glm::clamp(pos2D, glm::vec2(0), glm::vec2(1))) {
|
||||
IntersectionType type = IntersectionType::ENTITY;
|
||||
if (getFilter().doesPickLocalEntities()) {
|
||||
EntityPropertyFlags desiredProperties;
|
||||
desiredProperties += PROP_ENTITY_HOST_TYPE;
|
||||
if (DependencyManager::get<EntityScriptingInterface>()->getEntityProperties(target, desiredProperties).getEntityHostType() == entity::HostType::LOCAL) {
|
||||
type = IntersectionType::LOCAL_ENTITY;
|
||||
if (distance < nearestTarget.distance) {
|
||||
const auto entityDimensions = entity->getScaledDimensions();
|
||||
const auto entityRegistrationPoint = entity->getRegistrationPoint();
|
||||
glm::vec3 intersection = pick.position - (normal * distance);
|
||||
glm::vec2 pos2D = RayPick::projectOntoXYPlane(intersection, entityPosition, entityRotation,
|
||||
entityDimensions, entityRegistrationPoint, false);
|
||||
if (pos2D == glm::clamp(pos2D, glm::vec2(0), glm::vec2(1))) {
|
||||
IntersectionType type = IntersectionType::ENTITY;
|
||||
if (getFilter().doesPickLocalEntities()) {
|
||||
if (entity->getEntityHostType() == entity::HostType::LOCAL) {
|
||||
type = IntersectionType::LOCAL_ENTITY;
|
||||
}
|
||||
}
|
||||
nearestTarget = StylusPickResult(type, target, distance, intersection, pick, normal);
|
||||
}
|
||||
results.push_back(StylusPickResult(type, target, distance, intersection, pick, normal));
|
||||
}
|
||||
}
|
||||
|
||||
StylusPickResult nearestTarget(pick.toVariantMap());
|
||||
for (const auto& result : results) {
|
||||
if (result.distance < nearestTarget.distance) {
|
||||
nearestTarget = result;
|
||||
}
|
||||
}
|
||||
return std::make_shared<StylusPickResult>(nearestTarget);
|
||||
}
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -157,6 +157,7 @@ private:
|
|||
bool shouldProcessEntityAndPointerEvent(const PointerEvent& event) const;
|
||||
bool shouldProcessPointerEvent(const PointerEvent& event) const;
|
||||
bool shouldProcessEntity() const;
|
||||
void addIncludeItemsToMallets();
|
||||
|
||||
void startLayerSwitchTimer();
|
||||
bool isLayerSwitchTimerFinished() const;
|
||||
|
@ -178,7 +179,12 @@ private:
|
|||
mutable ReadWriteLockable _handLaserLock;
|
||||
mutable ReadWriteLockable _preferMalletsOverLasersSettingLock;
|
||||
mutable ReadWriteLockable _ignoreItemsLock;
|
||||
|
||||
#ifdef Q_OS_ANDROID
|
||||
Setting::Handle<bool> _use3DKeyboard { "use3DKeyboard", false };
|
||||
#else
|
||||
Setting::Handle<bool> _use3DKeyboard { "use3DKeyboard", true };
|
||||
#endif
|
||||
|
||||
QString _typedCharacters;
|
||||
TextDisplay _textDisplay;
|
||||
|
|
|
@ -70,7 +70,6 @@ ContextOverlayInterface::ContextOverlayInterface() {
|
|||
}
|
||||
});
|
||||
connect(entityScriptingInterface, &EntityScriptingInterface::deletingEntity, this, &ContextOverlayInterface::deletingEntity);
|
||||
connect(&qApp->getOverlays(), &Overlays::mousePressOnOverlay, this, &ContextOverlayInterface::contextOverlays_mousePressOnOverlay);
|
||||
connect(&qApp->getOverlays(), &Overlays::hoverEnterOverlay, this, &ContextOverlayInterface::contextOverlays_hoverEnterOverlay);
|
||||
connect(&qApp->getOverlays(), &Overlays::hoverLeaveOverlay, this, &ContextOverlayInterface::contextOverlays_hoverLeaveOverlay);
|
||||
|
||||
|
@ -103,10 +102,14 @@ void ContextOverlayInterface::setEnabled(bool enabled) {
|
|||
}
|
||||
}
|
||||
|
||||
void ContextOverlayInterface::clickDownOnEntity(const EntityItemID& entityItemID, const PointerEvent& event) {
|
||||
if (_enabled && event.getButton() == PointerEvent::SecondaryButton && contextOverlayFilterPassed(entityItemID)) {
|
||||
_mouseDownEntity = entityItemID;
|
||||
void ContextOverlayInterface::clickDownOnEntity(const EntityItemID& id, const PointerEvent& event) {
|
||||
if (_enabled && event.getButton() == PointerEvent::SecondaryButton && contextOverlayFilterPassed(id)) {
|
||||
_mouseDownEntity = id;
|
||||
_mouseDownEntityTimestamp = usecTimestampNow();
|
||||
} else if (id == _contextOverlayID && event.getButton() == PointerEvent::PrimaryButton) {
|
||||
qCDebug(context_overlay) << "Clicked Context Overlay. Entity ID:" << _currentEntityWithContextOverlay << "ID:" << id;
|
||||
emit contextOverlayClicked(_currentEntityWithContextOverlay);
|
||||
_contextOverlayJustClicked = true;
|
||||
} else {
|
||||
if (!_currentEntityWithContextOverlay.isNull()) {
|
||||
disableEntityHighlight(_currentEntityWithContextOverlay);
|
||||
|
@ -249,14 +252,6 @@ bool ContextOverlayInterface::destroyContextOverlay(const EntityItemID& entityIt
|
|||
return ContextOverlayInterface::destroyContextOverlay(entityItemID, PointerEvent());
|
||||
}
|
||||
|
||||
void ContextOverlayInterface::contextOverlays_mousePressOnOverlay(const QUuid& id, const PointerEvent& event) {
|
||||
if (id == _contextOverlayID && event.getButton() == PointerEvent::PrimaryButton) {
|
||||
qCDebug(context_overlay) << "Clicked Context Overlay. Entity ID:" << _currentEntityWithContextOverlay << "ID:" << id;
|
||||
emit contextOverlayClicked(_currentEntityWithContextOverlay);
|
||||
_contextOverlayJustClicked = true;
|
||||
}
|
||||
}
|
||||
|
||||
void ContextOverlayInterface::contextOverlays_hoverEnterOverlay(const QUuid& id, const PointerEvent& event) {
|
||||
if (_contextOverlayID != UNKNOWN_ENTITY_ID) {
|
||||
qCDebug(context_overlay) << "Started hovering over Context Overlay. ID:" << id;
|
||||
|
|
|
@ -65,7 +65,6 @@ public slots:
|
|||
bool createOrDestroyContextOverlay(const EntityItemID& entityItemID, const PointerEvent& event);
|
||||
bool destroyContextOverlay(const EntityItemID& entityItemID, const PointerEvent& event);
|
||||
bool destroyContextOverlay(const EntityItemID& entityItemID);
|
||||
void contextOverlays_mousePressOnOverlay(const QUuid& id, const PointerEvent& event);
|
||||
void contextOverlays_hoverEnterOverlay(const QUuid& id, const PointerEvent& event);
|
||||
void contextOverlays_hoverLeaveOverlay(const QUuid& id, const PointerEvent& event);
|
||||
void contextOverlays_hoverEnterEntity(const EntityItemID& entityID, const PointerEvent& event);
|
||||
|
|
|
@ -63,13 +63,6 @@ Overlays::Overlays() {
|
|||
ADD_TYPE_MAP(PolyLine, line3d);
|
||||
ADD_TYPE_MAP(Grid, grid);
|
||||
ADD_TYPE_MAP(Gizmo, circle3d);
|
||||
|
||||
auto mouseRayPick = std::make_shared<RayPick>(Vectors::ZERO, Vectors::UP,
|
||||
PickFilter(PickFilter::getBitMask(PickFilter::FlagBit::LOCAL_ENTITIES) |
|
||||
PickFilter::getBitMask(PickFilter::FlagBit::VISIBLE)), 0.0f, true);
|
||||
mouseRayPick->parentTransform = std::make_shared<MouseTransformNode>();
|
||||
mouseRayPick->setJointState(PickQuery::JOINT_STATE_MOUSE);
|
||||
_mouseRayPickID = DependencyManager::get<PickManager>()->addPick(PickQuery::Ray, mouseRayPick);
|
||||
}
|
||||
|
||||
void Overlays::cleanupAllOverlays() {
|
||||
|
@ -87,13 +80,14 @@ void Overlays::cleanupAllOverlays() {
|
|||
}
|
||||
|
||||
void Overlays::init() {
|
||||
auto entityScriptingInterface = DependencyManager::get<EntityScriptingInterface>();
|
||||
connect(this, &Overlays::hoverEnterOverlay, entityScriptingInterface.data(), &EntityScriptingInterface::hoverEnterEntity);
|
||||
connect(this, &Overlays::hoverOverOverlay, entityScriptingInterface.data(), &EntityScriptingInterface::hoverOverEntity);
|
||||
connect(this, &Overlays::hoverLeaveOverlay, entityScriptingInterface.data(), &EntityScriptingInterface::hoverLeaveEntity);
|
||||
connect(this, &Overlays::mousePressOnOverlay, entityScriptingInterface.data(), &EntityScriptingInterface::mousePressOnEntity);
|
||||
connect(this, &Overlays::mouseMoveOnOverlay, entityScriptingInterface.data(), &EntityScriptingInterface::mouseMoveOnEntity);
|
||||
connect(this, &Overlays::mouseReleaseOnOverlay, entityScriptingInterface.data(), &EntityScriptingInterface::mouseReleaseOnEntity);
|
||||
auto entityScriptingInterface = DependencyManager::get<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) {
|
||||
|
@ -358,6 +352,17 @@ EntityItemProperties Overlays::convertOverlayToEntityProperties(QVariantMap& ove
|
|||
return "none";
|
||||
});
|
||||
|
||||
RENAME_PROP_CONVERT(textures, textures, [](const QVariant& v) {
|
||||
auto map = v.toMap();
|
||||
if (!map.isEmpty()) {
|
||||
auto json = QJsonDocument::fromVariant(map);
|
||||
if (!json.isNull()) {
|
||||
return QVariant(QString(json.toJson()));
|
||||
}
|
||||
}
|
||||
return v;
|
||||
});
|
||||
|
||||
if (type == "Shape" || type == "Box" || type == "Sphere" || type == "Gizmo") {
|
||||
RENAME_PROP(solid, isSolid);
|
||||
RENAME_PROP(isFilled, isSolid);
|
||||
|
@ -375,6 +380,8 @@ EntityItemProperties Overlays::convertOverlayToEntityProperties(QVariantMap& ove
|
|||
RENAME_PROP(animationSettings, animation);
|
||||
} else if (type == "Image") {
|
||||
RENAME_PROP(url, imageURL);
|
||||
} else if (type == "Text") {
|
||||
RENAME_PROP(color, textColor);
|
||||
} else if (type == "Web") {
|
||||
RENAME_PROP(url, sourceUrl);
|
||||
RENAME_PROP_CONVERT(inputMode, inputMode, [](const QVariant& v) { return v.toString() == "Mouse" ? "mouse" : "touch"; });
|
||||
|
@ -675,6 +682,8 @@ QVariantMap Overlays::convertEntityToOverlayProperties(const EntityItemPropertie
|
|||
RENAME_PROP(animation, animationSettings);
|
||||
} else if (type == "Image") {
|
||||
RENAME_PROP(imageURL, url);
|
||||
} else if (type == "Text") {
|
||||
RENAME_PROP(textColor, color);
|
||||
} else if (type == "Web") {
|
||||
RENAME_PROP(sourceUrl, url);
|
||||
RENAME_PROP_CONVERT(inputMode, inputMode, [](const QVariant& v) { return v.toString() == "mouse" ? "Mouse" : "Touch"; });
|
||||
|
@ -1228,12 +1237,12 @@ static PointerEvent::Button toPointerButton(const QMouseEvent& event) {
|
|||
}
|
||||
}
|
||||
|
||||
RayToOverlayIntersectionResult getPrevPickResult(unsigned int mouseRayPickID) {
|
||||
RayToOverlayIntersectionResult getPrevPickResult() {
|
||||
RayToOverlayIntersectionResult overlayResult;
|
||||
overlayResult.intersects = false;
|
||||
auto pickResult = DependencyManager::get<PickManager>()->getPrevPickResultTyped<RayPickResult>(mouseRayPickID);
|
||||
auto pickResult = DependencyManager::get<PickManager>()->getPrevPickResultTyped<RayPickResult>(DependencyManager::get<EntityTreeRenderer>()->getMouseRayPickID());
|
||||
if (pickResult) {
|
||||
overlayResult.intersects = pickResult->type != IntersectionType::NONE;
|
||||
overlayResult.intersects = pickResult->type == IntersectionType::LOCAL_ENTITY;
|
||||
if (overlayResult.intersects) {
|
||||
overlayResult.intersection = pickResult->intersection;
|
||||
overlayResult.distance = pickResult->distance;
|
||||
|
@ -1281,7 +1290,7 @@ std::pair<float, QUuid> Overlays::mousePressEvent(QMouseEvent* event) {
|
|||
PerformanceTimer perfTimer("Overlays::mousePressEvent");
|
||||
|
||||
PickRay ray = qApp->computePickRay(event->x(), event->y());
|
||||
RayToOverlayIntersectionResult rayPickResult = getPrevPickResult(_mouseRayPickID);
|
||||
RayToOverlayIntersectionResult rayPickResult = getPrevPickResult();
|
||||
if (rayPickResult.intersects) {
|
||||
_currentClickingOnOverlayID = rayPickResult.overlayID;
|
||||
|
||||
|
@ -1305,7 +1314,7 @@ bool Overlays::mouseDoublePressEvent(QMouseEvent* event) {
|
|||
PerformanceTimer perfTimer("Overlays::mouseDoublePressEvent");
|
||||
|
||||
PickRay ray = qApp->computePickRay(event->x(), event->y());
|
||||
RayToOverlayIntersectionResult rayPickResult = getPrevPickResult(_mouseRayPickID);
|
||||
RayToOverlayIntersectionResult rayPickResult = getPrevPickResult();
|
||||
if (rayPickResult.intersects) {
|
||||
_currentClickingOnOverlayID = rayPickResult.overlayID;
|
||||
|
||||
|
@ -1321,7 +1330,7 @@ bool Overlays::mouseReleaseEvent(QMouseEvent* event) {
|
|||
PerformanceTimer perfTimer("Overlays::mouseReleaseEvent");
|
||||
|
||||
PickRay ray = qApp->computePickRay(event->x(), event->y());
|
||||
RayToOverlayIntersectionResult rayPickResult = getPrevPickResult(_mouseRayPickID);
|
||||
RayToOverlayIntersectionResult rayPickResult = getPrevPickResult();
|
||||
if (rayPickResult.intersects) {
|
||||
auto pointerEvent = calculateOverlayPointerEvent(rayPickResult.overlayID, ray, rayPickResult, event, PointerEvent::Release);
|
||||
mouseReleasePointerEvent(rayPickResult.overlayID, pointerEvent);
|
||||
|
@ -1343,7 +1352,7 @@ bool Overlays::mouseMoveEvent(QMouseEvent* event) {
|
|||
PerformanceTimer perfTimer("Overlays::mouseMoveEvent");
|
||||
|
||||
PickRay ray = qApp->computePickRay(event->x(), event->y());
|
||||
RayToOverlayIntersectionResult rayPickResult = getPrevPickResult(_mouseRayPickID);
|
||||
RayToOverlayIntersectionResult rayPickResult = getPrevPickResult();
|
||||
if (rayPickResult.intersects) {
|
||||
auto pointerEvent = calculateOverlayPointerEvent(rayPickResult.overlayID, ray, rayPickResult, event, PointerEvent::Move);
|
||||
mouseMovePointerEvent(rayPickResult.overlayID, pointerEvent);
|
||||
|
|
|
@ -719,7 +719,6 @@ private:
|
|||
PointerEvent calculateOverlayPointerEvent(const QUuid& id, const PickRay& ray, const RayToOverlayIntersectionResult& rayPickResult,
|
||||
QMouseEvent* event, PointerEvent::EventType eventType);
|
||||
|
||||
unsigned int _mouseRayPickID;
|
||||
QUuid _currentClickingOnOverlayID;
|
||||
QUuid _currentHoverOverOverlayID;
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -65,7 +65,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);
|
||||
|
@ -76,10 +80,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;
|
||||
}
|
||||
|
@ -627,12 +636,18 @@ void Avatar::addToScene(AvatarSharedPointer self, const render::ScenePointer& sc
|
|||
_skeletonModel->setVisibleInScene(_isMeshVisible, scene);
|
||||
|
||||
processMaterials();
|
||||
bool attachmentRenderingNeedsUpdate = false;
|
||||
for (auto& attachmentModel : _attachmentModels) {
|
||||
attachmentModel->addToScene(scene, transaction);
|
||||
attachmentModel->setTagMask(render::hifi::TAG_ALL_VIEWS);
|
||||
attachmentModel->setGroupCulled(false);
|
||||
attachmentModel->setGroupCulled(true);
|
||||
attachmentModel->setCanCastShadow(true);
|
||||
attachmentModel->setVisibleInScene(_isMeshVisible, scene);
|
||||
attachmentRenderingNeedsUpdate = true;
|
||||
}
|
||||
|
||||
if (attachmentRenderingNeedsUpdate) {
|
||||
updateAttachmentRenderIDs();
|
||||
}
|
||||
|
||||
_mustFadeIn = true;
|
||||
|
@ -856,15 +871,17 @@ void Avatar::fixupModelsInScene(const render::ScenePointer& scene) {
|
|||
canTryFade = true;
|
||||
_isAnimatingScale = true;
|
||||
}
|
||||
bool attachmentRenderingNeedsUpdate = false;
|
||||
for (auto attachmentModel : _attachmentModels) {
|
||||
if (attachmentModel->isRenderable() && attachmentModel->needsFixupInScene()) {
|
||||
attachmentModel->removeFromScene(scene, transaction);
|
||||
attachmentModel->addToScene(scene, transaction);
|
||||
|
||||
attachmentModel->setTagMask(render::hifi::TAG_ALL_VIEWS);
|
||||
attachmentModel->setGroupCulled(false);
|
||||
attachmentModel->setGroupCulled(true);
|
||||
attachmentModel->setCanCastShadow(true);
|
||||
attachmentModel->setVisibleInScene(_isMeshVisible, scene);
|
||||
attachmentRenderingNeedsUpdate = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -887,9 +904,15 @@ void Avatar::fixupModelsInScene(const render::ScenePointer& scene) {
|
|||
|
||||
for (auto attachmentModelToRemove : _attachmentsToRemove) {
|
||||
attachmentModelToRemove->removeFromScene(scene, transaction);
|
||||
attachmentRenderingNeedsUpdate = true;
|
||||
}
|
||||
_attachmentsToDelete.insert(_attachmentsToDelete.end(), _attachmentsToRemove.begin(), _attachmentsToRemove.end());
|
||||
_attachmentsToRemove.clear();
|
||||
|
||||
if (attachmentRenderingNeedsUpdate) {
|
||||
updateAttachmentRenderIDs();
|
||||
}
|
||||
|
||||
scene->enqueueTransaction(transaction);
|
||||
}
|
||||
|
||||
|
@ -932,6 +955,11 @@ void Avatar::simulateAttachments(float deltaTime) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (_ancestorChainRenderableVersion != _lastAncestorChainRenderableVersion) {
|
||||
_lastAncestorChainRenderableVersion = _ancestorChainRenderableVersion;
|
||||
updateDescendantRenderIDs();
|
||||
}
|
||||
}
|
||||
|
||||
float Avatar::getBoundingRadius() const {
|
||||
|
@ -1611,7 +1639,6 @@ void Avatar::setAttachmentData(const QVector<AttachmentData>& attachmentData) {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
int Avatar::parseDataFromBuffer(const QByteArray& buffer) {
|
||||
PerformanceTimer perfTimer("unpack");
|
||||
if (!_initialized) {
|
||||
|
@ -2120,3 +2147,60 @@ void Avatar::clearAvatarGrabData(const QUuid& id) {
|
|||
}
|
||||
});
|
||||
}
|
||||
|
||||
uint32_t Avatar::appendSubMetaItems(render::ItemIDs& subItems) {
|
||||
return _subItemLock.resultWithReadLock<uint32_t>([&] {
|
||||
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());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
@ -500,6 +500,8 @@ public:
|
|||
const std::vector<MultiSphereShape>& getMultiSphereShapes() const { return _multiSphereShapes; }
|
||||
void tearDownGrabs();
|
||||
|
||||
uint32_t appendSubMetaItems(render::ItemIDs& subItems);
|
||||
|
||||
signals:
|
||||
void targetScaleChanged(float targetScale);
|
||||
|
||||
|
@ -642,8 +644,6 @@ protected:
|
|||
RateCounter<> _skeletonModelSimulationRate;
|
||||
RateCounter<> _jointDataSimulationRate;
|
||||
|
||||
|
||||
protected:
|
||||
class AvatarEntityDataHash {
|
||||
public:
|
||||
AvatarEntityDataHash(uint32_t h) : hash(h) {};
|
||||
|
@ -705,6 +705,13 @@ protected:
|
|||
MapOfGrabs _avatarGrabs;
|
||||
SetOfIDs _grabsToChange; // updated grab IDs -- changes needed to entities or physics
|
||||
VectorOfIDs _grabsToDelete; // deleted grab IDs -- changes needed to entities or physics
|
||||
|
||||
ReadWriteLockable _subItemLock;
|
||||
void updateAttachmentRenderIDs();
|
||||
render::ItemIDs _attachmentRenderIDs;
|
||||
void updateDescendantRenderIDs();
|
||||
render::ItemIDs _descendantRenderIDs;
|
||||
uint32_t _lastAncestorChainRenderableVersion { 0 };
|
||||
};
|
||||
|
||||
#endif // hifi_Avatar_h
|
||||
|
|
|
@ -208,16 +208,16 @@ AvatarSharedPointer AvatarHashMap::addAvatar(const QUuid& sessionUUID, const QWe
|
|||
avatar->setSessionUUID(sessionUUID);
|
||||
avatar->setOwningAvatarMixer(mixerWeakPointer);
|
||||
|
||||
// addAvatar is only called from newOrExistingAvatar, which already locks _hashLock
|
||||
_avatarHash.insert(sessionUUID, avatar);
|
||||
{
|
||||
QWriteLocker locker(&_hashLock);
|
||||
_avatarHash.insert(sessionUUID, avatar);
|
||||
}
|
||||
emit avatarAddedEvent(sessionUUID);
|
||||
return avatar;
|
||||
}
|
||||
|
||||
AvatarSharedPointer AvatarHashMap::newOrExistingAvatar(const QUuid& sessionUUID, const QWeakPointer<Node>& mixerWeakPointer,
|
||||
bool& isNew) {
|
||||
QWriteLocker locker(&_hashLock);
|
||||
auto avatar = _avatarHash.value(sessionUUID);
|
||||
AvatarSharedPointer AvatarHashMap::newOrExistingAvatar(const QUuid& sessionUUID, const QWeakPointer<Node>& mixerWeakPointer, bool& isNew) {
|
||||
auto avatar = findAvatar(sessionUUID);
|
||||
if (!avatar) {
|
||||
avatar = addAvatar(sessionUUID, mixerWeakPointer);
|
||||
isNew = true;
|
||||
|
|
|
@ -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
|
|
@ -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
|
||||
};
|
||||
|
|
|
@ -86,7 +86,7 @@ EntityTreeRenderer::EntityTreeRenderer(bool wantScripts, AbstractViewStateInterf
|
|||
auto handlePointerEvent = [&](const QUuid& entityID, const PointerEvent& event) {
|
||||
std::shared_ptr<render::entities::WebEntityRenderer> thisEntity;
|
||||
auto entity = getEntity(entityID);
|
||||
if (entity && entity->getType() == EntityTypes::Web) {
|
||||
if (entity && entity->isVisible() && entity->getType() == EntityTypes::Web) {
|
||||
thisEntity = std::static_pointer_cast<render::entities::WebEntityRenderer>(renderableForEntityId(entityID));
|
||||
}
|
||||
if (thisEntity) {
|
||||
|
@ -99,7 +99,7 @@ EntityTreeRenderer::EntityTreeRenderer(bool wantScripts, AbstractViewStateInterf
|
|||
connect(entityScriptingInterface.data(), &EntityScriptingInterface::hoverEnterEntity, this, [&](const QUuid& entityID, const PointerEvent& event) {
|
||||
std::shared_ptr<render::entities::WebEntityRenderer> thisEntity;
|
||||
auto entity = getEntity(entityID);
|
||||
if (entity && entity->getType() == EntityTypes::Web) {
|
||||
if (entity && entity->isVisible() && entity->getType() == EntityTypes::Web) {
|
||||
thisEntity = std::static_pointer_cast<render::entities::WebEntityRenderer>(renderableForEntityId(entityID));
|
||||
}
|
||||
if (thisEntity) {
|
||||
|
@ -110,7 +110,7 @@ EntityTreeRenderer::EntityTreeRenderer(bool wantScripts, AbstractViewStateInterf
|
|||
connect(entityScriptingInterface.data(), &EntityScriptingInterface::hoverLeaveEntity, this, [&](const QUuid& entityID, const PointerEvent& event) {
|
||||
std::shared_ptr<render::entities::WebEntityRenderer> thisEntity;
|
||||
auto entity = getEntity(entityID);
|
||||
if (entity && entity->getType() == EntityTypes::Web) {
|
||||
if (entity && entity->isVisible() && entity->getType() == EntityTypes::Web) {
|
||||
thisEntity = std::static_pointer_cast<render::entities::WebEntityRenderer>(renderableForEntityId(entityID));
|
||||
}
|
||||
if (thisEntity) {
|
||||
|
@ -1360,3 +1360,36 @@ EntityEditPacketSender* EntityTreeRenderer::getPacketSender() {
|
|||
EntityEditPacketSender* packetSender = peSimulation ? peSimulation->getPacketSender() : nullptr;
|
||||
return packetSender;
|
||||
}
|
||||
|
||||
std::function<bool(const QUuid&, graphics::MaterialLayer, const std::string&)> EntityTreeRenderer::_addMaterialToEntityOperator = nullptr;
|
||||
std::function<bool(const QUuid&, graphics::MaterialPointer, const std::string&)> EntityTreeRenderer::_removeMaterialFromEntityOperator = nullptr;
|
||||
std::function<bool(const QUuid&, graphics::MaterialLayer, const std::string&)> EntityTreeRenderer::_addMaterialToAvatarOperator = nullptr;
|
||||
std::function<bool(const QUuid&, graphics::MaterialPointer, const std::string&)> EntityTreeRenderer::_removeMaterialFromAvatarOperator = nullptr;
|
||||
|
||||
bool EntityTreeRenderer::addMaterialToEntity(const QUuid& entityID, graphics::MaterialLayer material, const std::string& parentMaterialName) {
|
||||
if (_addMaterialToEntityOperator) {
|
||||
return _addMaterialToEntityOperator(entityID, material, parentMaterialName);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool EntityTreeRenderer::removeMaterialFromEntity(const QUuid& entityID, graphics::MaterialPointer material, const std::string& parentMaterialName) {
|
||||
if (_removeMaterialFromEntityOperator) {
|
||||
return _removeMaterialFromEntityOperator(entityID, material, parentMaterialName);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool EntityTreeRenderer::addMaterialToAvatar(const QUuid& avatarID, graphics::MaterialLayer material, const std::string& parentMaterialName) {
|
||||
if (_addMaterialToAvatarOperator) {
|
||||
return _addMaterialToAvatarOperator(avatarID, material, parentMaterialName);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool EntityTreeRenderer::removeMaterialFromAvatar(const QUuid& avatarID, graphics::MaterialPointer material, const std::string& parentMaterialName) {
|
||||
if (_removeMaterialFromAvatarOperator) {
|
||||
return _removeMaterialFromAvatarOperator(avatarID, material, parentMaterialName);
|
||||
}
|
||||
return false;
|
||||
}
|
|
@ -73,6 +73,7 @@ public:
|
|||
static void setEntityLoadingPriorityFunction(CalculateEntityLoadingPriority fn) { _calculateEntityLoadingPriorityFunc = fn; }
|
||||
|
||||
void setMouseRayPickID(unsigned int rayPickID) { _mouseRayPickID = rayPickID; }
|
||||
unsigned int getMouseRayPickID() { return _mouseRayPickID; }
|
||||
void setMouseRayPickResultOperator(std::function<RayToEntityIntersectionResult(unsigned int)> getPrevRayPickResultOperator) { _getPrevRayPickResultOperator = getPrevRayPickResultOperator; }
|
||||
void setSetPrecisionPickingOperator(std::function<void(unsigned int, bool)> setPrecisionPickingOperator) { _setPrecisionPickingOperator = setPrecisionPickingOperator; }
|
||||
|
||||
|
@ -120,6 +121,16 @@ public:
|
|||
|
||||
EntityEditPacketSender* getPacketSender();
|
||||
|
||||
static void setAddMaterialToEntityOperator(std::function<bool(const QUuid&, graphics::MaterialLayer, const std::string&)> addMaterialToEntityOperator) { _addMaterialToEntityOperator = addMaterialToEntityOperator; }
|
||||
static void setRemoveMaterialFromEntityOperator(std::function<bool(const QUuid&, graphics::MaterialPointer, const std::string&)> removeMaterialFromEntityOperator) { _removeMaterialFromEntityOperator = removeMaterialFromEntityOperator; }
|
||||
static bool addMaterialToEntity(const QUuid& entityID, graphics::MaterialLayer material, const std::string& parentMaterialName);
|
||||
static bool removeMaterialFromEntity(const QUuid& entityID, graphics::MaterialPointer material, const std::string& parentMaterialName);
|
||||
|
||||
static void setAddMaterialToAvatarOperator(std::function<bool(const QUuid&, graphics::MaterialLayer, const std::string&)> addMaterialToAvatarOperator) { _addMaterialToAvatarOperator = addMaterialToAvatarOperator; }
|
||||
static void setRemoveMaterialFromAvatarOperator(std::function<bool(const QUuid&, graphics::MaterialPointer, const std::string&)> removeMaterialFromAvatarOperator) { _removeMaterialFromAvatarOperator = removeMaterialFromAvatarOperator; }
|
||||
static bool addMaterialToAvatar(const QUuid& avatarID, graphics::MaterialLayer material, const std::string& parentMaterialName);
|
||||
static bool removeMaterialFromAvatar(const QUuid& avatarID, graphics::MaterialPointer material, const std::string& parentMaterialName);
|
||||
|
||||
signals:
|
||||
void enterEntity(const EntityItemID& entityItemID);
|
||||
void leaveEntity(const EntityItemID& entityItemID);
|
||||
|
@ -255,6 +266,11 @@ private:
|
|||
workload::SpacePointer _space{ new workload::Space() };
|
||||
workload::Transaction::Updates _spaceUpdates;
|
||||
|
||||
static std::function<bool(const QUuid&, graphics::MaterialLayer, const std::string&)> _addMaterialToEntityOperator;
|
||||
static std::function<bool(const QUuid&, graphics::MaterialPointer, const std::string&)> _removeMaterialFromEntityOperator;
|
||||
static std::function<bool(const QUuid&, graphics::MaterialLayer, const std::string&)> _addMaterialToAvatarOperator;
|
||||
static std::function<bool(const QUuid&, graphics::MaterialPointer, const std::string&)> _removeMaterialFromAvatarOperator;
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -146,7 +146,6 @@ EntityRenderer::EntityRenderer(const EntityItemPointer& entity) : _created(entit
|
|||
_needsRenderUpdate = true;
|
||||
emit requestRenderUpdate();
|
||||
});
|
||||
_materials = entity->getMaterials();
|
||||
}
|
||||
|
||||
EntityRenderer::~EntityRenderer() { }
|
||||
|
@ -321,6 +320,7 @@ bool EntityRenderer::addToScene(const ScenePointer& scene, Transaction& transact
|
|||
transaction.resetItem(_renderItemID, renderPayload);
|
||||
onAddToScene(_entity);
|
||||
updateInScene(scene, transaction);
|
||||
_entity->bumpAncestorChainRenderableVersion();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -328,6 +328,7 @@ void EntityRenderer::removeFromScene(const ScenePointer& scene, Transaction& tra
|
|||
onRemoveFromScene(_entity);
|
||||
transaction.removeItem(_renderItemID);
|
||||
Item::clearID(_renderItemID);
|
||||
_entity->bumpAncestorChainRenderableVersion();
|
||||
}
|
||||
|
||||
void EntityRenderer::updateInScene(const ScenePointer& scene, Transaction& transaction) {
|
||||
|
@ -353,14 +354,6 @@ void EntityRenderer::updateInScene(const ScenePointer& scene, Transaction& trans
|
|||
});
|
||||
}
|
||||
|
||||
void EntityRenderer::clearSubRenderItemIDs() {
|
||||
_subRenderItemIDs.clear();
|
||||
}
|
||||
|
||||
void EntityRenderer::setSubRenderItemIDs(const render::ItemIDs& ids) {
|
||||
_subRenderItemIDs = ids;
|
||||
}
|
||||
|
||||
//
|
||||
// Internal methods
|
||||
//
|
||||
|
|
|
@ -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()() };
|
||||
|
|
|
@ -14,42 +14,210 @@
|
|||
using namespace render;
|
||||
using namespace render::entities;
|
||||
|
||||
bool MaterialEntityRenderer::needsRenderUpdateFromTypedEntity(const TypedEntityPointer& entity) const {
|
||||
if (entity->getMaterial() != _drawMaterial) {
|
||||
return true;
|
||||
}
|
||||
if (entity->getParentID() != _parentID) {
|
||||
return true;
|
||||
}
|
||||
if (entity->getMaterialMappingPos() != _materialMappingPos || entity->getMaterialMappingScale() != _materialMappingScale || entity->getMaterialMappingRot() != _materialMappingRot) {
|
||||
bool MaterialEntityRenderer::needsRenderUpdate() const {
|
||||
if (_retryApply) {
|
||||
return true;
|
||||
}
|
||||
if (!_texturesLoaded) {
|
||||
return true;
|
||||
}
|
||||
return Parent::needsRenderUpdate();
|
||||
}
|
||||
|
||||
bool MaterialEntityRenderer::needsRenderUpdateFromTypedEntity(const TypedEntityPointer& entity) const {
|
||||
if (resultWithReadLock<bool>([&] {
|
||||
if (entity->getMaterialMappingMode() != _materialMappingMode) {
|
||||
return true;
|
||||
}
|
||||
if (entity->getMaterialRepeat() != _materialRepeat) {
|
||||
return true;
|
||||
}
|
||||
if (entity->getMaterialMappingPos() != _materialMappingPos || entity->getMaterialMappingScale() != _materialMappingScale || entity->getMaterialMappingRot() != _materialMappingRot) {
|
||||
return true;
|
||||
}
|
||||
if (entity->getTransform() != _transform) {
|
||||
return true;
|
||||
}
|
||||
if (entity->getUnscaledDimensions() != _dimensions) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (entity->getMaterialURL() != _materialURL) {
|
||||
return true;
|
||||
}
|
||||
if (entity->getMaterialData() != _materialData) {
|
||||
return true;
|
||||
}
|
||||
if (entity->getParentMaterialName() != _parentMaterialName) {
|
||||
return true;
|
||||
}
|
||||
if (entity->getParentID() != _parentID) {
|
||||
return true;
|
||||
}
|
||||
if (entity->getPriority() != _priority) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
})) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void MaterialEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& scene, Transaction& transaction, const TypedEntityPointer& entity) {
|
||||
void MaterialEntityRenderer::doRenderUpdateAsynchronousTyped(const TypedEntityPointer& entity) {
|
||||
withWriteLock([&] {
|
||||
if (_drawMaterial != entity->getMaterial()) {
|
||||
_texturesLoaded = false;
|
||||
_drawMaterial = entity->getMaterial();
|
||||
bool deleteNeeded = false;
|
||||
bool addNeeded = _retryApply;
|
||||
bool transformChanged = false;
|
||||
{
|
||||
MaterialMappingMode mode = entity->getMaterialMappingMode();
|
||||
if (mode != _materialMappingMode) {
|
||||
_materialMappingMode = mode;
|
||||
transformChanged = true;
|
||||
}
|
||||
}
|
||||
_parentID = entity->getParentID();
|
||||
_materialMappingPos = entity->getMaterialMappingPos();
|
||||
_materialMappingScale = entity->getMaterialMappingScale();
|
||||
_materialMappingRot = entity->getMaterialMappingRot();
|
||||
{
|
||||
bool repeat = entity->getMaterialRepeat();
|
||||
if (repeat != _materialRepeat) {
|
||||
_materialRepeat = repeat;
|
||||
transformChanged = true;
|
||||
}
|
||||
}
|
||||
{
|
||||
glm::vec2 mappingPos = entity->getMaterialMappingPos();
|
||||
glm::vec2 mappingScale = entity->getMaterialMappingScale();
|
||||
float mappingRot = entity->getMaterialMappingRot();
|
||||
if (mappingPos != _materialMappingPos || mappingScale != _materialMappingScale || mappingRot != _materialMappingRot) {
|
||||
_materialMappingPos = mappingPos;
|
||||
_materialMappingScale = mappingScale;
|
||||
_materialMappingRot = mappingRot;
|
||||
transformChanged |= _materialMappingMode == MaterialMappingMode::UV;
|
||||
}
|
||||
}
|
||||
{
|
||||
Transform transform = entity->getTransform();
|
||||
glm::vec3 dimensions = entity->getUnscaledDimensions();
|
||||
if (transform != _transform || dimensions != _dimensions) {
|
||||
_transform = transform;
|
||||
_dimensions = dimensions;
|
||||
transformChanged |= _materialMappingMode == MaterialMappingMode::PROJECTED;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
auto material = getMaterial();
|
||||
// Update the old material regardless of if it's going to change
|
||||
if (transformChanged && material && !_parentID.isNull()) {
|
||||
deleteNeeded = true;
|
||||
addNeeded = true;
|
||||
applyTextureTransform(material);
|
||||
}
|
||||
}
|
||||
|
||||
bool urlChanged = false;
|
||||
std::string newCurrentMaterialName = _currentMaterialName;
|
||||
{
|
||||
QString materialURL = entity->getMaterialURL();
|
||||
if (materialURL != _materialURL) {
|
||||
_materialURL = materialURL;
|
||||
if (_materialURL.contains("?")) {
|
||||
auto split = _materialURL.split("?");
|
||||
newCurrentMaterialName = split.last().toStdString();
|
||||
}
|
||||
urlChanged = true;
|
||||
}
|
||||
}
|
||||
|
||||
bool usingMaterialData = _materialURL.startsWith("materialData");
|
||||
bool materialDataChanged = false;
|
||||
QUuid oldParentID = _parentID;
|
||||
QString oldParentMaterialName = _parentMaterialName;
|
||||
{
|
||||
QString materialData = entity->getMaterialData();
|
||||
if (materialData != _materialData) {
|
||||
_materialData = materialData;
|
||||
if (usingMaterialData) {
|
||||
materialDataChanged = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
{
|
||||
QString parentMaterialName = entity->getParentMaterialName();
|
||||
if (parentMaterialName != _parentMaterialName) {
|
||||
_parentMaterialName = parentMaterialName;
|
||||
deleteNeeded = true;
|
||||
addNeeded = true;
|
||||
}
|
||||
}
|
||||
{
|
||||
QUuid parentID = entity->getParentID();
|
||||
if (parentID != _parentID) {
|
||||
_parentID = parentID;
|
||||
deleteNeeded = true;
|
||||
addNeeded = true;
|
||||
}
|
||||
}
|
||||
{
|
||||
quint16 priority = entity->getPriority();
|
||||
if (priority != _priority) {
|
||||
_priority = priority;
|
||||
deleteNeeded = true;
|
||||
addNeeded = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (urlChanged && !usingMaterialData) {
|
||||
_networkMaterial = MaterialCache::instance().getMaterial(_materialURL);
|
||||
auto onMaterialRequestFinished = [&, oldParentID, oldParentMaterialName, newCurrentMaterialName](bool success) {
|
||||
if (success) {
|
||||
deleteMaterial(oldParentID, oldParentMaterialName);
|
||||
_texturesLoaded = false;
|
||||
_parsedMaterials = _networkMaterial->parsedMaterials;
|
||||
setCurrentMaterialName(newCurrentMaterialName);
|
||||
applyMaterial();
|
||||
} else {
|
||||
deleteMaterial(oldParentID, oldParentMaterialName);
|
||||
_retryApply = false;
|
||||
_texturesLoaded = true;
|
||||
}
|
||||
};
|
||||
if (_networkMaterial) {
|
||||
if (_networkMaterial->isLoaded()) {
|
||||
onMaterialRequestFinished(!_networkMaterial->isFailed());
|
||||
} else {
|
||||
connect(_networkMaterial.data(), &Resource::finished, this, onMaterialRequestFinished);
|
||||
}
|
||||
}
|
||||
} else if (materialDataChanged && usingMaterialData) {
|
||||
deleteMaterial(oldParentID, oldParentMaterialName);
|
||||
_texturesLoaded = false;
|
||||
_parsedMaterials = NetworkMaterialResource::parseJSONMaterials(QJsonDocument::fromJson(_materialData.toUtf8()), _materialURL);
|
||||
// Since our material changed, the current name might not be valid anymore, so we need to update
|
||||
setCurrentMaterialName(newCurrentMaterialName);
|
||||
applyMaterial();
|
||||
} else {
|
||||
if (deleteNeeded) {
|
||||
deleteMaterial(oldParentID, oldParentMaterialName);
|
||||
}
|
||||
if (addNeeded) {
|
||||
applyMaterial();
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
auto material = getMaterial();
|
||||
bool newTexturesLoaded = material ? !material->isMissingTexture() : false;
|
||||
if (!_texturesLoaded && newTexturesLoaded) {
|
||||
material->checkResetOpacityMap();
|
||||
}
|
||||
_texturesLoaded = newTexturesLoaded;
|
||||
}
|
||||
|
||||
_renderTransform = getModelTransform();
|
||||
const float MATERIAL_ENTITY_SCALE = 0.5f;
|
||||
_renderTransform.postScale(MATERIAL_ENTITY_SCALE);
|
||||
_renderTransform.postScale(ENTITY_ITEM_DEFAULT_DIMENSIONS);
|
||||
|
||||
bool newTexturesLoaded = _drawMaterial ? !_drawMaterial->isMissingTexture() : false;
|
||||
if (!_texturesLoaded && newTexturesLoaded) {
|
||||
_drawMaterial->checkResetOpacityMap();
|
||||
}
|
||||
_texturesLoaded = newTexturesLoaded;
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -61,8 +229,9 @@ ItemKey MaterialEntityRenderer::getKey() {
|
|||
builder.withInvisible();
|
||||
}
|
||||
|
||||
if (_drawMaterial) {
|
||||
auto matKey = _drawMaterial->getKey();
|
||||
const auto drawMaterial = getMaterial();
|
||||
if (drawMaterial) {
|
||||
auto matKey = drawMaterial->getKey();
|
||||
if (matKey.isTranslucent()) {
|
||||
builder.withTransparent();
|
||||
}
|
||||
|
@ -73,8 +242,9 @@ ItemKey MaterialEntityRenderer::getKey() {
|
|||
|
||||
ShapeKey MaterialEntityRenderer::getShapeKey() {
|
||||
graphics::MaterialKey drawMaterialKey;
|
||||
if (_drawMaterial) {
|
||||
drawMaterialKey = _drawMaterial->getKey();
|
||||
const auto drawMaterial = getMaterial();
|
||||
if (drawMaterial) {
|
||||
drawMaterialKey = drawMaterial->getKey();
|
||||
}
|
||||
|
||||
bool isTranslucent = drawMaterialKey.isTranslucent();
|
||||
|
@ -112,18 +282,24 @@ void MaterialEntityRenderer::doRender(RenderArgs* args) {
|
|||
|
||||
// Don't render if our parent is set or our material is null
|
||||
QUuid parentID;
|
||||
withReadLock([&] {
|
||||
parentID = _parentID;
|
||||
});
|
||||
if (!parentID.isNull()) {
|
||||
return;
|
||||
}
|
||||
|
||||
Transform renderTransform;
|
||||
graphics::MaterialPointer drawMaterial;
|
||||
Transform textureTransform;
|
||||
withReadLock([&] {
|
||||
parentID = _parentID;
|
||||
renderTransform = _renderTransform;
|
||||
drawMaterial = _drawMaterial;
|
||||
drawMaterial = getMaterial();
|
||||
textureTransform.setTranslation(glm::vec3(_materialMappingPos, 0));
|
||||
textureTransform.setRotation(glm::vec3(0, 0, glm::radians(_materialMappingRot)));
|
||||
textureTransform.setScale(glm::vec3(_materialMappingScale, 1));
|
||||
});
|
||||
if (!parentID.isNull() || !drawMaterial) {
|
||||
if (!drawMaterial) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -142,3 +318,86 @@ void MaterialEntityRenderer::doRender(RenderArgs* args) {
|
|||
|
||||
args->_details._trianglesRendered += (int)DependencyManager::get<GeometryCache>()->getSphereTriangleCount();
|
||||
}
|
||||
|
||||
void MaterialEntityRenderer::setCurrentMaterialName(const std::string& currentMaterialName) {
|
||||
if (_parsedMaterials.networkMaterials.find(currentMaterialName) != _parsedMaterials.networkMaterials.end()) {
|
||||
_currentMaterialName = currentMaterialName;
|
||||
} else if (_parsedMaterials.names.size() > 0) {
|
||||
_currentMaterialName = _parsedMaterials.names[0];
|
||||
}
|
||||
}
|
||||
|
||||
std::shared_ptr<NetworkMaterial> MaterialEntityRenderer::getMaterial() const {
|
||||
auto material = _parsedMaterials.networkMaterials.find(_currentMaterialName);
|
||||
if (material != _parsedMaterials.networkMaterials.end()) {
|
||||
return material->second;
|
||||
} else {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void MaterialEntityRenderer::deleteMaterial(const QUuid& oldParentID, const QString& oldParentMaterialName) {
|
||||
std::shared_ptr<NetworkMaterial> material = _appliedMaterial;
|
||||
if (!material || oldParentID.isNull()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Our parent could be an entity or an avatar
|
||||
std::string oldParentMaterialNameStd = oldParentMaterialName.toStdString();
|
||||
if (EntityTreeRenderer::removeMaterialFromEntity(oldParentID, material, oldParentMaterialNameStd)) {
|
||||
_appliedMaterial = nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
if (EntityTreeRenderer::removeMaterialFromAvatar(oldParentID, material, oldParentMaterialNameStd)) {
|
||||
_appliedMaterial = nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
// if a remove fails, our parent is gone, so we don't need to retry
|
||||
}
|
||||
|
||||
void MaterialEntityRenderer::applyTextureTransform(std::shared_ptr<NetworkMaterial>& material) {
|
||||
Transform textureTransform;
|
||||
if (_materialMappingMode == MaterialMappingMode::UV) {
|
||||
textureTransform.setTranslation(glm::vec3(_materialMappingPos, 0.0f));
|
||||
textureTransform.setRotation(glm::vec3(0.0f, 0.0f, glm::radians(_materialMappingRot)));
|
||||
textureTransform.setScale(glm::vec3(_materialMappingScale, 1.0f));
|
||||
} else if (_materialMappingMode == MaterialMappingMode::PROJECTED) {
|
||||
textureTransform = _transform;
|
||||
textureTransform.postScale(_dimensions);
|
||||
// Pass the inverse transform here so we don't need to compute it in the shaders
|
||||
textureTransform.evalFromRawMatrix(textureTransform.getInverseMatrix());
|
||||
}
|
||||
material->setTextureTransforms(textureTransform, _materialMappingMode, _materialRepeat);
|
||||
}
|
||||
|
||||
void MaterialEntityRenderer::applyMaterial() {
|
||||
_retryApply = false;
|
||||
|
||||
std::shared_ptr<NetworkMaterial> material = getMaterial();
|
||||
QUuid parentID = _parentID;
|
||||
if (!material || parentID.isNull()) {
|
||||
_appliedMaterial = nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
applyTextureTransform(material);
|
||||
|
||||
graphics::MaterialLayer materialLayer = graphics::MaterialLayer(material, _priority);
|
||||
|
||||
// Our parent could be an entity or an avatar
|
||||
std::string parentMaterialName = _parentMaterialName.toStdString();
|
||||
if (EntityTreeRenderer::addMaterialToEntity(parentID, materialLayer, parentMaterialName)) {
|
||||
_appliedMaterial = material;
|
||||
return;
|
||||
}
|
||||
|
||||
if (EntityTreeRenderer::addMaterialToAvatar(parentID, materialLayer, parentMaterialName)) {
|
||||
_appliedMaterial = material;
|
||||
return;
|
||||
}
|
||||
|
||||
// if we've reached this point, we couldn't find our parent, so we need to try again later
|
||||
_retryApply = true;
|
||||
}
|
|
@ -13,6 +13,8 @@
|
|||
|
||||
#include <MaterialEntityItem.h>
|
||||
|
||||
#include <material-networking/MaterialCache.h>
|
||||
|
||||
class NetworkMaterial;
|
||||
|
||||
namespace render { namespace entities {
|
||||
|
@ -22,22 +24,46 @@ class MaterialEntityRenderer : public TypedEntityRenderer<MaterialEntityItem> {
|
|||
using Pointer = std::shared_ptr<MaterialEntityRenderer>;
|
||||
public:
|
||||
MaterialEntityRenderer(const EntityItemPointer& entity) : Parent(entity) {}
|
||||
~MaterialEntityRenderer() { deleteMaterial(_parentID, _parentMaterialName); }
|
||||
|
||||
private:
|
||||
virtual bool needsRenderUpdate() const override;
|
||||
virtual bool needsRenderUpdateFromTypedEntity(const TypedEntityPointer& entity) const override;
|
||||
virtual void doRenderUpdateSynchronousTyped(const ScenePointer& scene, Transaction& transaction, const TypedEntityPointer& entity) override;
|
||||
virtual void doRenderUpdateAsynchronousTyped(const TypedEntityPointer& entity) override;
|
||||
virtual void doRender(RenderArgs* args) override;
|
||||
|
||||
ItemKey getKey() override;
|
||||
ShapeKey getShapeKey() override;
|
||||
|
||||
QString _materialURL;
|
||||
QString _materialData;
|
||||
QString _parentMaterialName;
|
||||
quint16 _priority;
|
||||
QUuid _parentID;
|
||||
|
||||
MaterialMappingMode _materialMappingMode;
|
||||
bool _materialRepeat;
|
||||
glm::vec2 _materialMappingPos;
|
||||
glm::vec2 _materialMappingScale;
|
||||
float _materialMappingRot;
|
||||
bool _texturesLoaded { false };
|
||||
Transform _transform;
|
||||
glm::vec3 _dimensions;
|
||||
|
||||
bool _texturesLoaded { false };
|
||||
bool _retryApply { false };
|
||||
|
||||
std::shared_ptr<NetworkMaterial> getMaterial() const;
|
||||
void setCurrentMaterialName(const std::string& currentMaterialName);
|
||||
|
||||
void applyTextureTransform(std::shared_ptr<NetworkMaterial>& material);
|
||||
void applyMaterial();
|
||||
void deleteMaterial(const QUuid& oldParentID, const QString& oldParentMaterialName);
|
||||
|
||||
NetworkMaterialResourcePointer _networkMaterial;
|
||||
NetworkMaterialResource::ParsedMaterials _parsedMaterials;
|
||||
std::shared_ptr<NetworkMaterial> _appliedMaterial;
|
||||
std::string _currentMaterialName;
|
||||
|
||||
std::shared_ptr<NetworkMaterial> _drawMaterial;
|
||||
};
|
||||
|
||||
} }
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2935,6 +2935,7 @@ void EntityItem::setVisible(bool value) {
|
|||
});
|
||||
|
||||
if (changed) {
|
||||
bumpAncestorChainRenderableVersion();
|
||||
emit requestRenderUpdate();
|
||||
}
|
||||
}
|
||||
|
@ -3250,25 +3251,6 @@ void EntityItem::setSpaceIndex(int32_t index) {
|
|||
void EntityItem::preDelete() {
|
||||
}
|
||||
|
||||
void EntityItem::addMaterial(graphics::MaterialLayer material, const std::string& parentMaterialName) {
|
||||
std::lock_guard<std::mutex> lock(_materialsLock);
|
||||
_materials[parentMaterialName].push(material);
|
||||
}
|
||||
|
||||
void EntityItem::removeMaterial(graphics::MaterialPointer material, const std::string& parentMaterialName) {
|
||||
std::lock_guard<std::mutex> lock(_materialsLock);
|
||||
_materials[parentMaterialName].remove(material);
|
||||
}
|
||||
|
||||
std::unordered_map<std::string, graphics::MultiMaterial> EntityItem::getMaterials() {
|
||||
std::unordered_map<std::string, graphics::MultiMaterial> toReturn;
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(_materialsLock);
|
||||
toReturn = _materials;
|
||||
}
|
||||
return toReturn;
|
||||
}
|
||||
|
||||
bool EntityItem::getCloneable() const {
|
||||
bool result;
|
||||
withReadLock([&] {
|
||||
|
|
|
@ -37,8 +37,6 @@
|
|||
#include "EntityDynamicInterface.h"
|
||||
#include "GrabPropertyGroup.h"
|
||||
|
||||
#include "graphics/Material.h"
|
||||
|
||||
class EntitySimulation;
|
||||
class EntityTreeElement;
|
||||
class EntityTreeElementExtraEncodeData;
|
||||
|
@ -542,10 +540,6 @@ public:
|
|||
virtual void preDelete();
|
||||
virtual void postParentFixup() {}
|
||||
|
||||
void addMaterial(graphics::MaterialLayer material, const std::string& parentMaterialName);
|
||||
void removeMaterial(graphics::MaterialPointer material, const std::string& parentMaterialName);
|
||||
std::unordered_map<std::string, graphics::MultiMaterial> getMaterials();
|
||||
|
||||
void setSimulationOwnershipExpiry(uint64_t expiry) { _simulationOwnershipExpiry = expiry; }
|
||||
uint64_t getSimulationOwnershipExpiry() const { return _simulationOwnershipExpiry; }
|
||||
|
||||
|
@ -754,11 +748,7 @@ protected:
|
|||
QHash<QUuid, EntityDynamicPointer> _grabActions;
|
||||
|
||||
private:
|
||||
std::unordered_map<std::string, graphics::MultiMaterial> _materials;
|
||||
std::mutex _materialsLock;
|
||||
|
||||
static std::function<glm::quat(const glm::vec3&, const glm::quat&, BillboardMode)> _getBillboardRotationOperator;
|
||||
|
||||
};
|
||||
|
||||
#endif // hifi_EntityItem_h
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -2953,41 +2953,9 @@ QStringList EntityTree::getJointNames(const QUuid& entityID) const {
|
|||
return entity->getJointNames();
|
||||
}
|
||||
|
||||
std::function<bool(const QUuid&, graphics::MaterialLayer, const std::string&)> EntityTree::_addMaterialToEntityOperator = nullptr;
|
||||
std::function<bool(const QUuid&, graphics::MaterialPointer, const std::string&)> EntityTree::_removeMaterialFromEntityOperator = nullptr;
|
||||
std::function<bool(const QUuid&, graphics::MaterialLayer, const std::string&)> EntityTree::_addMaterialToAvatarOperator = nullptr;
|
||||
std::function<bool(const QUuid&, graphics::MaterialPointer, const std::string&)> EntityTree::_removeMaterialFromAvatarOperator = nullptr;
|
||||
std::function<QObject*(const QUuid&)> EntityTree::_getEntityObjectOperator = nullptr;
|
||||
std::function<QSizeF(const QUuid&, const QString&)> EntityTree::_textSizeOperator = nullptr;
|
||||
|
||||
bool EntityTree::addMaterialToEntity(const QUuid& entityID, graphics::MaterialLayer material, const std::string& parentMaterialName) {
|
||||
if (_addMaterialToEntityOperator) {
|
||||
return _addMaterialToEntityOperator(entityID, material, parentMaterialName);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool EntityTree::removeMaterialFromEntity(const QUuid& entityID, graphics::MaterialPointer material, const std::string& parentMaterialName) {
|
||||
if (_removeMaterialFromEntityOperator) {
|
||||
return _removeMaterialFromEntityOperator(entityID, material, parentMaterialName);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool EntityTree::addMaterialToAvatar(const QUuid& avatarID, graphics::MaterialLayer material, const std::string& parentMaterialName) {
|
||||
if (_addMaterialToAvatarOperator) {
|
||||
return _addMaterialToAvatarOperator(avatarID, material, parentMaterialName);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool EntityTree::removeMaterialFromAvatar(const QUuid& avatarID, graphics::MaterialPointer material, const std::string& parentMaterialName) {
|
||||
if (_removeMaterialFromAvatarOperator) {
|
||||
return _removeMaterialFromAvatarOperator(avatarID, material, parentMaterialName);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
QObject* EntityTree::getEntityObject(const QUuid& id) {
|
||||
if (_getEntityObjectOperator) {
|
||||
return _getEntityObjectOperator(id);
|
||||
|
|
|
@ -262,16 +262,6 @@ public:
|
|||
void setIsServerlessMode(bool value) { _serverlessDomain = value; }
|
||||
bool isServerlessMode() const { return _serverlessDomain; }
|
||||
|
||||
static void setAddMaterialToEntityOperator(std::function<bool(const QUuid&, graphics::MaterialLayer, const std::string&)> addMaterialToEntityOperator) { _addMaterialToEntityOperator = addMaterialToEntityOperator; }
|
||||
static void setRemoveMaterialFromEntityOperator(std::function<bool(const QUuid&, graphics::MaterialPointer, const std::string&)> removeMaterialFromEntityOperator) { _removeMaterialFromEntityOperator = removeMaterialFromEntityOperator; }
|
||||
static bool addMaterialToEntity(const QUuid& entityID, graphics::MaterialLayer material, const std::string& parentMaterialName);
|
||||
static bool removeMaterialFromEntity(const QUuid& entityID, graphics::MaterialPointer material, const std::string& parentMaterialName);
|
||||
|
||||
static void setAddMaterialToAvatarOperator(std::function<bool(const QUuid&, graphics::MaterialLayer, const std::string&)> addMaterialToAvatarOperator) { _addMaterialToAvatarOperator = addMaterialToAvatarOperator; }
|
||||
static void setRemoveMaterialFromAvatarOperator(std::function<bool(const QUuid&, graphics::MaterialPointer, const std::string&)> removeMaterialFromAvatarOperator) { _removeMaterialFromAvatarOperator = removeMaterialFromAvatarOperator; }
|
||||
static bool addMaterialToAvatar(const QUuid& avatarID, graphics::MaterialLayer material, const std::string& parentMaterialName);
|
||||
static bool removeMaterialFromAvatar(const QUuid& avatarID, graphics::MaterialPointer material, const std::string& parentMaterialName);
|
||||
|
||||
static void setGetEntityObjectOperator(std::function<QObject*(const QUuid&)> getEntityObjectOperator) { _getEntityObjectOperator = getEntityObjectOperator; }
|
||||
static QObject* getEntityObject(const QUuid& id);
|
||||
|
||||
|
@ -386,10 +376,6 @@ private:
|
|||
|
||||
std::shared_ptr<AvatarData> _myAvatar{ nullptr };
|
||||
|
||||
static std::function<bool(const QUuid&, graphics::MaterialLayer, const std::string&)> _addMaterialToEntityOperator;
|
||||
static std::function<bool(const QUuid&, graphics::MaterialPointer, const std::string&)> _removeMaterialFromEntityOperator;
|
||||
static std::function<bool(const QUuid&, graphics::MaterialLayer, const std::string&)> _addMaterialToAvatarOperator;
|
||||
static std::function<bool(const QUuid&, graphics::MaterialPointer, const std::string&)> _removeMaterialFromAvatarOperator;
|
||||
static std::function<QObject*(const QUuid&)> _getEntityObjectOperator;
|
||||
static std::function<QSizeF(const QUuid&, const QString&)> _textSizeOperator;
|
||||
|
||||
|
|
|
@ -16,9 +16,6 @@
|
|||
EntityItemPointer MaterialEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) {
|
||||
Pointer entity(new MaterialEntityItem(entityID), [](EntityItem* ptr) { ptr->deleteLater(); });
|
||||
entity->setProperties(properties);
|
||||
// When you reload content, setProperties doesn't have any of the propertiesChanged flags set, so it won't trigger a material add
|
||||
entity->removeMaterial();
|
||||
entity->applyMaterial();
|
||||
return entity;
|
||||
}
|
||||
|
||||
|
@ -27,10 +24,6 @@ MaterialEntityItem::MaterialEntityItem(const EntityItemID& entityItemID) : Entit
|
|||
_type = EntityTypes::Material;
|
||||
}
|
||||
|
||||
MaterialEntityItem::~MaterialEntityItem() {
|
||||
removeMaterial();
|
||||
}
|
||||
|
||||
EntityItemProperties MaterialEntityItem::getProperties(const EntityPropertyFlags& desiredProperties, bool allowEmptyDesiredProperties) const {
|
||||
EntityItemProperties properties = EntityItem::getProperties(desiredProperties, allowEmptyDesiredProperties); // get the properties from our base class
|
||||
COPY_ENTITY_PROPERTY_TO_PROPERTIES(materialURL, getMaterialURL);
|
||||
|
@ -131,7 +124,6 @@ void MaterialEntityItem::debugDump() const {
|
|||
qCDebug(entities) << " MATERIAL EntityItem id:" << getEntityItemID() << "---------------------------------------------";
|
||||
qCDebug(entities) << " name:" << _name;
|
||||
qCDebug(entities) << " material url:" << _materialURL;
|
||||
qCDebug(entities) << " current material name:" << _currentMaterialName.c_str();
|
||||
qCDebug(entities) << " material mapping mode:" << _materialMappingMode;
|
||||
qCDebug(entities) << " material repeat:" << _materialRepeat;
|
||||
qCDebug(entities) << " priority:" << _priority;
|
||||
|
@ -154,208 +146,101 @@ void MaterialEntityItem::setUnscaledDimensions(const glm::vec3& value) {
|
|||
}
|
||||
}
|
||||
|
||||
std::shared_ptr<NetworkMaterial> MaterialEntityItem::getMaterial() const {
|
||||
auto material = _parsedMaterials.networkMaterials.find(_currentMaterialName);
|
||||
if (material != _parsedMaterials.networkMaterials.end()) {
|
||||
return material->second;
|
||||
} else {
|
||||
return nullptr;
|
||||
}
|
||||
QString MaterialEntityItem::getMaterialURL() const {
|
||||
return resultWithReadLock<QString>([&] {
|
||||
return _materialURL;
|
||||
});
|
||||
}
|
||||
|
||||
void MaterialEntityItem::setMaterialURL(const QString& materialURLString, bool materialDataChanged) {
|
||||
bool usingMaterialData = materialDataChanged || materialURLString.startsWith("materialData");
|
||||
if (_materialURL != materialURLString || (usingMaterialData && materialDataChanged)) {
|
||||
removeMaterial();
|
||||
_materialURL = materialURLString;
|
||||
|
||||
if (materialURLString.contains("?")) {
|
||||
auto split = materialURLString.split("?");
|
||||
_currentMaterialName = split.last().toStdString();
|
||||
}
|
||||
|
||||
if (usingMaterialData) {
|
||||
_parsedMaterials = NetworkMaterialResource::parseJSONMaterials(QJsonDocument::fromJson(getMaterialData().toUtf8()), materialURLString);
|
||||
|
||||
// Since our material changed, the current name might not be valid anymore, so we need to update
|
||||
setCurrentMaterialName(_currentMaterialName);
|
||||
applyMaterial();
|
||||
} else {
|
||||
_networkMaterial = MaterialCache::instance().getMaterial(materialURLString);
|
||||
auto onMaterialRequestFinished = [&](bool success) {
|
||||
if (success) {
|
||||
_parsedMaterials = _networkMaterial->parsedMaterials;
|
||||
|
||||
setCurrentMaterialName(_currentMaterialName);
|
||||
applyMaterial();
|
||||
}
|
||||
};
|
||||
if (_networkMaterial) {
|
||||
if (_networkMaterial->isLoaded()) {
|
||||
onMaterialRequestFinished(!_networkMaterial->isFailed());
|
||||
} else {
|
||||
connect(_networkMaterial.data(), &Resource::finished, this, onMaterialRequestFinished);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
void MaterialEntityItem::setMaterialURL(const QString& materialURL) {
|
||||
withWriteLock([&] {
|
||||
_materialURL = materialURL;
|
||||
});
|
||||
}
|
||||
|
||||
void MaterialEntityItem::setCurrentMaterialName(const std::string& currentMaterialName) {
|
||||
if (_parsedMaterials.networkMaterials.find(currentMaterialName) != _parsedMaterials.networkMaterials.end()) {
|
||||
_currentMaterialName = currentMaterialName;
|
||||
} else if (_parsedMaterials.names.size() > 0) {
|
||||
_currentMaterialName = _parsedMaterials.names[0];
|
||||
}
|
||||
QString MaterialEntityItem::getMaterialData() const {
|
||||
return resultWithReadLock<QString>([&] {
|
||||
return _materialData;
|
||||
});
|
||||
}
|
||||
|
||||
void MaterialEntityItem::setMaterialData(const QString& materialData) {
|
||||
if (_materialData != materialData) {
|
||||
withWriteLock([&] {
|
||||
_materialData = materialData;
|
||||
if (_materialURL.startsWith("materialData")) {
|
||||
// Trigger material update when material data changes
|
||||
setMaterialURL(_materialURL, true);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
MaterialMappingMode MaterialEntityItem::getMaterialMappingMode() const {
|
||||
return resultWithReadLock<MaterialMappingMode>([&] {
|
||||
return _materialMappingMode;
|
||||
});
|
||||
}
|
||||
|
||||
void MaterialEntityItem::setMaterialMappingMode(MaterialMappingMode mode) {
|
||||
if (_materialMappingMode != mode) {
|
||||
removeMaterial();
|
||||
withWriteLock([&] {
|
||||
_materialMappingMode = mode;
|
||||
setUnscaledDimensions(_desiredDimensions);
|
||||
applyMaterial();
|
||||
}
|
||||
});
|
||||
setUnscaledDimensions(_desiredDimensions);
|
||||
}
|
||||
|
||||
void MaterialEntityItem::setMaterialRepeat(bool repeat) {
|
||||
if (_materialRepeat != repeat) {
|
||||
removeMaterial();
|
||||
_materialRepeat = repeat;
|
||||
applyMaterial();
|
||||
}
|
||||
}
|
||||
|
||||
void MaterialEntityItem::setMaterialMappingPos(const glm::vec2& materialMappingPos) {
|
||||
if (_materialMappingPos != materialMappingPos) {
|
||||
removeMaterial();
|
||||
_materialMappingPos = materialMappingPos;
|
||||
applyMaterial();
|
||||
}
|
||||
}
|
||||
|
||||
void MaterialEntityItem::setMaterialMappingScale(const glm::vec2& materialMappingScale) {
|
||||
if (_materialMappingScale != materialMappingScale) {
|
||||
removeMaterial();
|
||||
_materialMappingScale = materialMappingScale;
|
||||
applyMaterial();
|
||||
}
|
||||
}
|
||||
|
||||
void MaterialEntityItem::setMaterialMappingRot(const float& materialMappingRot) {
|
||||
if (_materialMappingRot != materialMappingRot) {
|
||||
removeMaterial();
|
||||
_materialMappingRot = materialMappingRot;
|
||||
applyMaterial();
|
||||
}
|
||||
quint16 MaterialEntityItem::getPriority() const {
|
||||
return resultWithReadLock<quint16>([&] {
|
||||
return _priority;
|
||||
});
|
||||
}
|
||||
|
||||
void MaterialEntityItem::setPriority(quint16 priority) {
|
||||
if (_priority != priority) {
|
||||
removeMaterial();
|
||||
withWriteLock([&] {
|
||||
_priority = priority;
|
||||
applyMaterial();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
QString MaterialEntityItem::getParentMaterialName() const {
|
||||
return resultWithReadLock<QString>([&] {
|
||||
return _parentMaterialName;
|
||||
});
|
||||
}
|
||||
|
||||
void MaterialEntityItem::setParentMaterialName(const QString& parentMaterialName) {
|
||||
if (_parentMaterialName != parentMaterialName) {
|
||||
removeMaterial();
|
||||
withWriteLock([&] {
|
||||
_parentMaterialName = parentMaterialName;
|
||||
applyMaterial();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void MaterialEntityItem::setParentID(const QUuid& parentID) {
|
||||
if (getParentID() != parentID) {
|
||||
removeMaterial();
|
||||
EntityItem::setParentID(parentID);
|
||||
applyMaterial();
|
||||
}
|
||||
glm::vec2 MaterialEntityItem::getMaterialMappingPos() const {
|
||||
return resultWithReadLock<glm::vec2>([&] {
|
||||
return _materialMappingPos;
|
||||
});
|
||||
}
|
||||
|
||||
void MaterialEntityItem::locationChanged(bool tellPhysics) {
|
||||
EntityItem::locationChanged();
|
||||
if (_materialMappingMode == MaterialMappingMode::PROJECTED) {
|
||||
removeMaterial();
|
||||
applyMaterial();
|
||||
}
|
||||
void MaterialEntityItem::setMaterialMappingPos(const glm::vec2& materialMappingPos) {
|
||||
withWriteLock([&] {
|
||||
_materialMappingPos = materialMappingPos;
|
||||
});
|
||||
}
|
||||
|
||||
void MaterialEntityItem::dimensionsChanged() {
|
||||
EntityItem::dimensionsChanged();
|
||||
if (_materialMappingMode == MaterialMappingMode::PROJECTED) {
|
||||
removeMaterial();
|
||||
applyMaterial();
|
||||
}
|
||||
glm::vec2 MaterialEntityItem::getMaterialMappingScale() const {
|
||||
return resultWithReadLock<glm::vec2>([&] {
|
||||
return _materialMappingScale;
|
||||
});
|
||||
}
|
||||
|
||||
void MaterialEntityItem::removeMaterial() {
|
||||
graphics::MaterialPointer material = getMaterial();
|
||||
if (!material) {
|
||||
return;
|
||||
}
|
||||
QUuid parentID = getParentID();
|
||||
if (parentID.isNull()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Our parent could be an entity or an avatar
|
||||
if (EntityTree::removeMaterialFromEntity(parentID, material, getParentMaterialName().toStdString())) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (EntityTree::removeMaterialFromAvatar(parentID, material, getParentMaterialName().toStdString())) {
|
||||
return;
|
||||
}
|
||||
|
||||
// if a remove fails, our parent is gone, so we don't need to retry
|
||||
void MaterialEntityItem::setMaterialMappingScale(const glm::vec2& materialMappingScale) {
|
||||
withWriteLock([&] {
|
||||
_materialMappingScale = materialMappingScale;
|
||||
});
|
||||
}
|
||||
|
||||
void MaterialEntityItem::applyMaterial() {
|
||||
_retryApply = false;
|
||||
graphics::MaterialPointer material = getMaterial();
|
||||
QUuid parentID = getParentID();
|
||||
if (!material || parentID.isNull()) {
|
||||
return;
|
||||
}
|
||||
float MaterialEntityItem::getMaterialMappingRot() const {
|
||||
return resultWithReadLock<float>([&] {
|
||||
return _materialMappingRot;
|
||||
});
|
||||
}
|
||||
|
||||
Transform textureTransform;
|
||||
if (_materialMappingMode == MaterialMappingMode::UV) {
|
||||
textureTransform.setTranslation(glm::vec3(_materialMappingPos, 0.0f));
|
||||
textureTransform.setRotation(glm::vec3(0.0f, 0.0f, glm::radians(_materialMappingRot)));
|
||||
textureTransform.setScale(glm::vec3(_materialMappingScale, 1.0f));
|
||||
} else if (_materialMappingMode == MaterialMappingMode::PROJECTED) {
|
||||
textureTransform = getTransform();
|
||||
textureTransform.postScale(getUnscaledDimensions());
|
||||
// Pass the inverse transform here so we don't need to compute it in the shaders
|
||||
textureTransform.evalFromRawMatrix(textureTransform.getInverseMatrix());
|
||||
}
|
||||
material->setTextureTransforms(textureTransform, _materialMappingMode, _materialRepeat);
|
||||
|
||||
graphics::MaterialLayer materialLayer = graphics::MaterialLayer(material, getPriority());
|
||||
|
||||
// Our parent could be an entity or an avatar
|
||||
if (EntityTree::addMaterialToEntity(parentID, materialLayer, getParentMaterialName().toStdString())) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (EntityTree::addMaterialToAvatar(parentID, materialLayer, getParentMaterialName().toStdString())) {
|
||||
return;
|
||||
}
|
||||
|
||||
// if we've reached this point, we couldn't find our parent, so we need to try again later
|
||||
_retryApply = true;
|
||||
void MaterialEntityItem::setMaterialMappingRot(float materialMappingRot) {
|
||||
withWriteLock([&] {
|
||||
_materialMappingRot = materialMappingRot;
|
||||
});
|
||||
}
|
||||
|
||||
AACube MaterialEntityItem::calculateInitialQueryAACube(bool& success) {
|
||||
|
@ -372,18 +257,3 @@ AACube MaterialEntityItem::calculateInitialQueryAACube(bool& success) {
|
|||
}
|
||||
return aaCube;
|
||||
}
|
||||
|
||||
void MaterialEntityItem::postParentFixup() {
|
||||
removeMaterial();
|
||||
_queryAACubeSet = false; // force an update so we contain our parent
|
||||
updateQueryAACube();
|
||||
applyMaterial();
|
||||
}
|
||||
|
||||
void MaterialEntityItem::update(const quint64& now) {
|
||||
if (_retryApply) {
|
||||
applyMaterial();
|
||||
}
|
||||
|
||||
EntityItem::update(now);
|
||||
}
|
||||
|
|
|
@ -12,8 +12,6 @@
|
|||
#include "EntityItem.h"
|
||||
|
||||
#include "MaterialMappingMode.h"
|
||||
#include <model-networking/ModelCache.h>
|
||||
#include <material-networking/MaterialCache.h>
|
||||
|
||||
class MaterialEntityItem : public EntityItem {
|
||||
using Pointer = std::shared_ptr<MaterialEntityItem>;
|
||||
|
@ -21,13 +19,9 @@ public:
|
|||
static EntityItemPointer factory(const EntityItemID& entityID, const EntityItemProperties& properties);
|
||||
|
||||
MaterialEntityItem(const EntityItemID& entityItemID);
|
||||
~MaterialEntityItem();
|
||||
|
||||
ALLOW_INSTANTIATION // This class can be instantiated
|
||||
|
||||
void update(const quint64& now) override;
|
||||
bool needsToCallUpdate() const override { return true; }
|
||||
|
||||
// methods for getting/setting all properties of an entity
|
||||
virtual EntityItemProperties getProperties(const EntityPropertyFlags& desiredProperties, bool allowEmptyDesiredProperties) const override;
|
||||
virtual bool setProperties(const EntityItemProperties& properties) override;
|
||||
|
@ -52,44 +46,30 @@ public:
|
|||
|
||||
virtual void setUnscaledDimensions(const glm::vec3& value) override;
|
||||
|
||||
QString getMaterialURL() const { return _materialURL; }
|
||||
void setMaterialURL(const QString& materialURLString, bool materialDataChanged = false);
|
||||
QString getMaterialURL() const;
|
||||
void setMaterialURL(const QString& materialURL);
|
||||
|
||||
void setCurrentMaterialName(const std::string& currentMaterialName);
|
||||
QString getMaterialData() const;
|
||||
void setMaterialData(const QString& materialData);
|
||||
|
||||
MaterialMappingMode getMaterialMappingMode() const { return _materialMappingMode; }
|
||||
MaterialMappingMode getMaterialMappingMode() const;
|
||||
void setMaterialMappingMode(MaterialMappingMode mode);
|
||||
|
||||
bool getMaterialRepeat() const { return _materialRepeat; }
|
||||
void setMaterialRepeat(bool repeat);
|
||||
void setMaterialRepeat(bool repeat) { _materialRepeat = repeat; }
|
||||
|
||||
quint16 getPriority() const { return _priority; }
|
||||
quint16 getPriority() const;
|
||||
void setPriority(quint16 priority);
|
||||
|
||||
QString getParentMaterialName() const { return _parentMaterialName; }
|
||||
QString getParentMaterialName() const;
|
||||
void setParentMaterialName(const QString& parentMaterialName);
|
||||
|
||||
glm::vec2 getMaterialMappingPos() const { return _materialMappingPos; }
|
||||
glm::vec2 getMaterialMappingPos() const;
|
||||
void setMaterialMappingPos(const glm::vec2& materialMappingPos);
|
||||
glm::vec2 getMaterialMappingScale() const { return _materialMappingScale; }
|
||||
glm::vec2 getMaterialMappingScale() const;
|
||||
void setMaterialMappingScale(const glm::vec2& materialMappingScale);
|
||||
float getMaterialMappingRot() const { return _materialMappingRot; }
|
||||
void setMaterialMappingRot(const float& materialMappingRot);
|
||||
|
||||
QString getMaterialData() const { return _materialData; }
|
||||
void setMaterialData(const QString& materialData);
|
||||
|
||||
std::shared_ptr<NetworkMaterial> getMaterial() const;
|
||||
|
||||
void setParentID(const QUuid& parentID) override;
|
||||
|
||||
void locationChanged(bool tellPhysics) override;
|
||||
void dimensionsChanged() override;
|
||||
|
||||
void applyMaterial();
|
||||
void removeMaterial();
|
||||
|
||||
void postParentFixup() override;
|
||||
float getMaterialMappingRot() const;
|
||||
void setMaterialMappingRot(float materialMappingRot);
|
||||
|
||||
AACube calculateInitialQueryAACube(bool& success) override;
|
||||
|
||||
|
@ -128,12 +108,6 @@ private:
|
|||
float _materialMappingRot { 0 };
|
||||
QString _materialData;
|
||||
|
||||
NetworkMaterialResourcePointer _networkMaterial;
|
||||
NetworkMaterialResource::ParsedMaterials _parsedMaterials;
|
||||
std::string _currentMaterialName;
|
||||
|
||||
bool _retryApply { false };
|
||||
|
||||
};
|
||||
|
||||
#endif // hifi_MaterialEntityItem_h
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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; }
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -205,7 +205,7 @@ gpu::TexturePointer AmbientOcclusionFramebuffer::getNormalTexture() {
|
|||
}
|
||||
|
||||
AmbientOcclusionEffectConfig::AmbientOcclusionEffectConfig() :
|
||||
render::GPUJobConfig::Persistent(QStringList() << "Render" << "Engine" << "Ambient Occlusion", false),
|
||||
render::GPUJobConfig::Persistent(QStringList() << "Render" << "Engine" << "Ambient Occlusion"),
|
||||
perspectiveScale{ 1.0f },
|
||||
edgeSharpness{ 1.0f },
|
||||
blurRadius{ 4 },
|
||||
|
|
|
@ -118,7 +118,7 @@ protected:
|
|||
float enableSkinning{ 1.0f };
|
||||
float enableBlendshape{ 1.0f };
|
||||
|
||||
float enableAmbientOcclusion{ 0.0f };
|
||||
float enableAmbientOcclusion{ 0.0f }; // false by default
|
||||
float enableShadow{ 1.0f };
|
||||
float spare1{ 1.0f };
|
||||
float spare2{ 1.0f };
|
||||
|
@ -196,15 +196,13 @@ public:
|
|||
bool enableSkinning{ true };
|
||||
bool enableBlendshape{ true };
|
||||
|
||||
bool enableAmbientOcclusion{ true };
|
||||
bool enableAmbientOcclusion{ false }; // false by default
|
||||
bool enableShadow{ true };
|
||||
|
||||
|
||||
void setAmbientOcclusion(bool enable) { enableAmbientOcclusion = enable; emit dirty();}
|
||||
bool isAmbientOcclusionEnabled() const { return enableAmbientOcclusion; }
|
||||
void setShadow(bool enable) {
|
||||
enableShadow = enable; emit dirty();
|
||||
}
|
||||
void setShadow(bool enable) { enableShadow = enable; emit dirty(); }
|
||||
bool isShadowEnabled() const { return enableShadow; }
|
||||
|
||||
signals:
|
||||
|
|
7
libraries/render-utils/src/parabola_forward.slv
Normal file
7
libraries/render-utils/src/parabola_forward.slv
Normal file
|
@ -0,0 +1,7 @@
|
|||
layout(location=0) in vec4 _color;
|
||||
|
||||
layout(location=0) out vec4 _fragColor0;
|
||||
|
||||
void main(void) {
|
||||
_fragColor0 = _color;
|
||||
}
|
|
@ -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;
|
||||
|
|
3
libraries/shaders/headers/310es/version.glsl
Normal file
3
libraries/shaders/headers/310es/version.glsl
Normal file
|
@ -0,0 +1,3 @@
|
|||
#version 310 es
|
||||
#define GPU_GLES
|
||||
#define GPU_GLES_310
|
|
@ -1,5 +1,3 @@
|
|||
#version 410 core
|
||||
#define GPU_GL410
|
||||
#define BITFIELD int
|
||||
#if defined(VULKAN)
|
||||
#extension GL_ARB_shading_language_420pack : require
|
||||
|
|
2
libraries/shaders/headers/410/version.glsl
Normal file
2
libraries/shaders/headers/410/version.glsl
Normal file
|
@ -0,0 +1,2 @@
|
|||
#version 410 core
|
||||
#define GPU_GL410
|
|
@ -1,5 +1,3 @@
|
|||
#version 450 core
|
||||
#define GPU_GL450
|
||||
#define GPU_SSBO_TRANSFORM_OBJECT
|
||||
#define BITFIELD int
|
||||
#define LAYOUT(X) layout(X)
|
||||
|
|
2
libraries/shaders/headers/450/version.glsl
Normal file
2
libraries/shaders/headers/450/version.glsl
Normal file
|
@ -0,0 +1,2 @@
|
|||
#version 450 core
|
||||
#define GPU_GL450
|
|
@ -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;
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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) {
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue