Resolve conflict with hifi/master.
1
.gitattributes
vendored
|
@ -10,6 +10,7 @@
|
||||||
*.json text
|
*.json text
|
||||||
*.js text
|
*.js text
|
||||||
*.qml text
|
*.qml text
|
||||||
|
*.qrc text
|
||||||
*.slf text
|
*.slf text
|
||||||
*.slh text
|
*.slh text
|
||||||
*.slv text
|
*.slv text
|
||||||
|
|
5
.gitignore
vendored
|
@ -12,6 +12,11 @@ ext/
|
||||||
Makefile
|
Makefile
|
||||||
*.user
|
*.user
|
||||||
|
|
||||||
|
# Android Studio
|
||||||
|
*.iml
|
||||||
|
local.properties
|
||||||
|
android/libraries
|
||||||
|
|
||||||
# Xcode
|
# Xcode
|
||||||
*.xcodeproj
|
*.xcodeproj
|
||||||
*.xcworkspace
|
*.xcworkspace
|
||||||
|
|
|
@ -1,19 +1,56 @@
|
||||||
Please read the [general build guide](BUILD.md) for information on dependencies required for all platforms. Only Android specific instructions are found in this file.
|
Please read the [general build guide](BUILD.md) for information on dependencies required for all platforms. Only Android specific instructions are found in this file.
|
||||||
|
|
||||||
### Android Dependencies
|
# Android Dependencies
|
||||||
|
|
||||||
You will need the following tools to build our Android targets.
|
You will need the following tools to build our Android targets.
|
||||||
|
|
||||||
* [cmake](http://www.cmake.org/download/) ~> 3.5.1
|
* [Qt](http://www.qt.io/download-open-source/#) ~> 5.9.1
|
||||||
* [Qt](http://www.qt.io/download-open-source/#) ~> 5.6.2
|
* [Android Studio](https://developer.android.com/studio/index.html)
|
||||||
* [ant](http://ant.apache.org/bindownload.cgi) ~> 1.9.4
|
* [Google VR SDK](https://github.com/googlevr/gvr-android-sdk/releases)
|
||||||
* [Android NDK](https://developer.android.com/tools/sdk/ndk/index.html) ~> r10d
|
* [Gradle](https://gradle.org/releases/)
|
||||||
* [Android SDK](http://developer.android.com/sdk/installing/index.html) ~> 24.4.1.1
|
|
||||||
* Install the latest Platform-tools
|
### Qt
|
||||||
* Install the latest Build-tools
|
|
||||||
* Install the SDK Platform for API Level 19
|
Download the Qt online installer. Run the installer and select the android_armv7 binaries. Installing to the default path is recommended
|
||||||
* Install Sources for Android SDK for API Level 19
|
|
||||||
* Install the ARM EABI v7a System Image if you want to run an emulator.
|
### 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 level 26.
|
||||||
|
|
||||||
|
* Install the ARM EABI v7a System Image if you want to run an emulator.
|
||||||
|
|
||||||
|
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
|
||||||
|
* Android SDK Tools
|
||||||
|
* NDK (even if you have the NDK installed separately)
|
||||||
|
|
||||||
|
### Google VR SDK
|
||||||
|
|
||||||
|
Download the 1.8 Google VR SDK [release](https://github.com/googlevr/gvr-android-sdk/archive/v1.80.0.zip). Unzip the archive to a location on your drive.
|
||||||
|
|
||||||
|
### Gradle
|
||||||
|
|
||||||
|
Download [Gradle 4.1](https://services.gradle.org/distributions/gradle-4.1-all.zip) and unzip it on your local drive. You may wish to add the location of the bin directory within the archive to your path
|
||||||
|
|
||||||
|
#### Set up machine specific Gradle properties
|
||||||
|
|
||||||
|
Create a `gradle.properties` file in ~/.gradle. Edit the file to contain the following
|
||||||
|
|
||||||
|
QT5_ROOT=C\:\\Qt\\5.9.1\\android_armv7
|
||||||
|
GVR_ROOT=C\:\\Android\\gvr-android-sdk
|
||||||
|
|
||||||
|
Replace the paths with your local installations of Qt5 and the Google VR SDK
|
||||||
|
|
||||||
|
|
||||||
|
# TODO fix the rest
|
||||||
|
|
||||||
You will also need to cross-compile the dependencies required for all platforms for Android, and help CMake find these compiled libraries on your machine.
|
You will also need to cross-compile the dependencies required for all platforms for Android, and help CMake find these compiled libraries on your machine.
|
||||||
|
|
||||||
|
|
|
@ -1,13 +1,16 @@
|
||||||
if (WIN32)
|
# If we're running under the gradle build, HIFI_ANDROID will be set here, but
|
||||||
|
# ANDROID will not be set until after the `project` statement. This is the *ONLY*
|
||||||
|
# place you need to use `HIFI_ANDROID` instead of `ANDROID`
|
||||||
|
if (WIN32 AND NOT HIFI_ANDROID)
|
||||||
cmake_minimum_required(VERSION 3.7)
|
cmake_minimum_required(VERSION 3.7)
|
||||||
else()
|
else()
|
||||||
cmake_minimum_required(VERSION 3.2)
|
cmake_minimum_required(VERSION 3.2)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
include("cmake/init.cmake")
|
|
||||||
|
|
||||||
project(hifi)
|
project(hifi)
|
||||||
|
|
||||||
|
include("cmake/init.cmake")
|
||||||
|
|
||||||
include("cmake/compiler.cmake")
|
include("cmake/compiler.cmake")
|
||||||
|
|
||||||
if (NOT DEFINED SERVER_ONLY)
|
if (NOT DEFINED SERVER_ONLY)
|
||||||
|
@ -54,11 +57,13 @@ endif()
|
||||||
file(GLOB_RECURSE CMAKE_SRC cmake/*.cmake cmake/CMakeLists.txt)
|
file(GLOB_RECURSE CMAKE_SRC cmake/*.cmake cmake/CMakeLists.txt)
|
||||||
add_custom_target(cmake SOURCES ${CMAKE_SRC})
|
add_custom_target(cmake SOURCES ${CMAKE_SRC})
|
||||||
GroupSources("cmake")
|
GroupSources("cmake")
|
||||||
|
unset(CMAKE_SRC)
|
||||||
|
|
||||||
file(GLOB_RECURSE JS_SRC scripts/*.js unpublishedScripts/*.js)
|
file(GLOB_RECURSE JS_SRC scripts/*.js unpublishedScripts/*.js)
|
||||||
add_custom_target(js SOURCES ${JS_SRC})
|
add_custom_target(js SOURCES ${JS_SRC})
|
||||||
GroupSources("scripts")
|
GroupSources("scripts")
|
||||||
GroupSources("unpublishedScripts")
|
GroupSources("unpublishedScripts")
|
||||||
|
unset(JS_SRC)
|
||||||
|
|
||||||
# Locate the required Qt build on the filesystem
|
# Locate the required Qt build on the filesystem
|
||||||
setup_qt()
|
setup_qt()
|
||||||
|
@ -77,6 +82,12 @@ option(USE_NSIGHT "Attempt to find the nSight libraries" 1)
|
||||||
|
|
||||||
set_packaging_parameters()
|
set_packaging_parameters()
|
||||||
|
|
||||||
|
# FIXME hack to work on the proper Android toolchain
|
||||||
|
if (ANDROID)
|
||||||
|
add_subdirectory(android/app)
|
||||||
|
return()
|
||||||
|
endif()
|
||||||
|
|
||||||
# add subdirectories for all targets
|
# add subdirectories for all targets
|
||||||
if (BUILD_SERVER)
|
if (BUILD_SERVER)
|
||||||
add_subdirectory(assignment-client)
|
add_subdirectory(assignment-client)
|
||||||
|
|
8
android/app/CMakeLists.txt
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
set(TARGET_NAME native-lib)
|
||||||
|
setup_hifi_library()
|
||||||
|
link_hifi_libraries(shared networking gl gpu gpu-gles render-utils)
|
||||||
|
autoscribe_shader_lib(gpu model render render-utils)
|
||||||
|
target_opengl()
|
||||||
|
target_link_libraries(native-lib android log m)
|
||||||
|
target_include_directories(native-lib PRIVATE "${GVR_ROOT}/libraries/headers")
|
||||||
|
target_link_libraries(native-lib "C:/Users/bdavis/Git/hifi/android/libraries/jni/armeabi-v7a/libgvr.so")
|
57
android/app/build.gradle
Normal file
|
@ -0,0 +1,57 @@
|
||||||
|
apply plugin: 'com.android.application'
|
||||||
|
|
||||||
|
android {
|
||||||
|
compileSdkVersion 26
|
||||||
|
buildToolsVersion "26.0.1"
|
||||||
|
defaultConfig {
|
||||||
|
applicationId "org.saintandreas.testapp"
|
||||||
|
minSdkVersion 24
|
||||||
|
targetSdkVersion 26
|
||||||
|
versionCode 1
|
||||||
|
versionName "1.0"
|
||||||
|
ndk { abiFilters 'armeabi-v7a' }
|
||||||
|
externalNativeBuild {
|
||||||
|
cmake {
|
||||||
|
arguments '-DHIFI_ANDROID=1',
|
||||||
|
'-DANDROID_PLATFORM=android-24',
|
||||||
|
'-DANDROID_TOOLCHAIN=clang',
|
||||||
|
'-DANDROID_STL=gnustl_shared',
|
||||||
|
'-DGVR_ROOT=' + GVR_ROOT,
|
||||||
|
'-DNATIVE_SCRIBE=c:/bin/scribe.exe',
|
||||||
|
"-DHIFI_ANDROID_PRECOMPILED=${project.rootDir}/libraries/jni/armeabi-v7a"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
jackOptions { enabled true }
|
||||||
|
compileOptions {
|
||||||
|
sourceCompatibility JavaVersion.VERSION_1_8
|
||||||
|
targetCompatibility JavaVersion.VERSION_1_8
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
buildTypes {
|
||||||
|
release {
|
||||||
|
minifyEnabled false
|
||||||
|
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sourceSets {
|
||||||
|
main {
|
||||||
|
jniLibs.srcDirs += '../libraries/jni';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
externalNativeBuild {
|
||||||
|
cmake {
|
||||||
|
path '../../CMakeLists.txt'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
compile fileTree(dir: "${project.rootDir}/libraries/jar", include: 'QtAndroid-bundled.jar')
|
||||||
|
compile fileTree(dir: 'libs', include: ['*.jar'])
|
||||||
|
compile 'com.google.vr:sdk-audio:1.80.0'
|
||||||
|
compile 'com.google.vr:sdk-base:1.80.0'
|
||||||
|
}
|
||||||
|
|
||||||
|
build.dependsOn(':extractQt5')
|
25
android/app/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
|
37
android/app/src/main/AndroidManifest.xml
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="org.saintandreas.testapp">
|
||||||
|
|
||||||
|
<uses-sdk android:minSdkVersion="24" android:targetSdkVersion="26" />
|
||||||
|
<uses-feature android:glEsVersion="0x00030001" android:required="true" />
|
||||||
|
<uses-permission android:name="android.permission.VIBRATE"/>
|
||||||
|
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
|
||||||
|
<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="false"/>
|
||||||
|
<uses-feature android:name="android.hardware.vr.high_performance" android:required="false"/>
|
||||||
|
|
||||||
|
<application
|
||||||
|
android:allowBackup="true"
|
||||||
|
android:theme="@style/VrActivityTheme"
|
||||||
|
android:icon="@mipmap/ic_launcher"
|
||||||
|
android:roundIcon="@mipmap/ic_launcher_round">
|
||||||
|
<activity
|
||||||
|
android:name=".MainActivity"
|
||||||
|
android:label="@string/app_name"
|
||||||
|
android:screenOrientation="landscape"
|
||||||
|
android:configChanges="orientation|keyboardHidden|screenSize"
|
||||||
|
android:enableVrMode="@string/gvr_vr_mode_component"
|
||||||
|
android:resizeableActivity="false">
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.intent.action.MAIN" />
|
||||||
|
<category android:name="android.intent.category.LAUNCHER" />
|
||||||
|
<category android:name="com.google.intent.category.DAYDREAM"/>
|
||||||
|
</intent-filter>
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.intent.action.MAIN" />
|
||||||
|
<category android:name="android.intent.category.LAUNCHER" />
|
||||||
|
<category android:name="com.google.intent.category.CARDBOARD" />
|
||||||
|
</intent-filter>
|
||||||
|
</activity>
|
||||||
|
</application>
|
||||||
|
</manifest>
|
50
android/app/src/main/cpp/GoogleVRHelpers.h
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
#include <glm/glm.hpp>
|
||||||
|
#include <glm/gtc/quaternion.hpp>
|
||||||
|
#include <vr/gvr/capi/include/gvr.h>
|
||||||
|
|
||||||
|
namespace googlevr {
|
||||||
|
|
||||||
|
// Convert a GVR matrix to GLM matrix
|
||||||
|
glm::mat4 toGlm(const gvr::Mat4f &matrix) {
|
||||||
|
glm::mat4 result;
|
||||||
|
for (int i = 0; i < 4; ++i) {
|
||||||
|
for (int j = 0; j < 4; ++j) {
|
||||||
|
result[j][i] = matrix.m[i][j];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Given a field of view in degrees, compute the corresponding projection
|
||||||
|
// matrix.
|
||||||
|
glm::mat4 perspectiveMatrixFromView(const gvr::Rectf& fov, float z_near, float z_far) {
|
||||||
|
const float x_left = -std::tan(fov.left * M_PI / 180.0f) * z_near;
|
||||||
|
const float x_right = std::tan(fov.right * M_PI / 180.0f) * z_near;
|
||||||
|
const float y_bottom = -std::tan(fov.bottom * M_PI / 180.0f) * z_near;
|
||||||
|
const float y_top = std::tan(fov.top * M_PI / 180.0f) * z_near;
|
||||||
|
const float Y = (2 * z_near) / (y_top - y_bottom);
|
||||||
|
const float A = (x_right + x_left) / (x_right - x_left);
|
||||||
|
const float B = (y_top + y_bottom) / (y_top - y_bottom);
|
||||||
|
const float C = (z_near + z_far) / (z_near - z_far);
|
||||||
|
const float D = (2 * z_near * z_far) / (z_near - z_far);
|
||||||
|
|
||||||
|
glm::mat4 result { 0 };
|
||||||
|
result[2][0] = A;
|
||||||
|
result[1][1] = Y;
|
||||||
|
result[2][1] = B;
|
||||||
|
result[2][2] = C;
|
||||||
|
result[3][2] = D;
|
||||||
|
result[2][3] = -1;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
glm::quat toGlm(const gvr::ControllerQuat& q) {
|
||||||
|
glm::quat result;
|
||||||
|
result.w = q.qw;
|
||||||
|
result.x = q.qx;
|
||||||
|
result.y = q.qy;
|
||||||
|
result.z = q.qz;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
78
android/app/src/main/cpp/native-lib.cpp
Normal file
|
@ -0,0 +1,78 @@
|
||||||
|
#include <jni.h>
|
||||||
|
|
||||||
|
#include <android/log.h>
|
||||||
|
#include <QtCore/QDebug>
|
||||||
|
|
||||||
|
#include "renderer.h"
|
||||||
|
|
||||||
|
int QtMsgTypeToAndroidPriority(QtMsgType type) {
|
||||||
|
int priority = ANDROID_LOG_UNKNOWN;
|
||||||
|
switch (type) {
|
||||||
|
case QtDebugMsg: priority = ANDROID_LOG_DEBUG; break;
|
||||||
|
case QtWarningMsg: priority = ANDROID_LOG_WARN; break;
|
||||||
|
case QtCriticalMsg: priority = ANDROID_LOG_ERROR; break;
|
||||||
|
case QtFatalMsg: priority = ANDROID_LOG_FATAL; break;
|
||||||
|
case QtInfoMsg: priority = ANDROID_LOG_INFO; break;
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
return priority;
|
||||||
|
}
|
||||||
|
|
||||||
|
void messageHandler(QtMsgType type, const QMessageLogContext& context, const QString& message) {
|
||||||
|
__android_log_write(QtMsgTypeToAndroidPriority(type), "Interface", message.toStdString().c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
static jlong toJni(NativeRenderer *renderer) {
|
||||||
|
return reinterpret_cast<intptr_t>(renderer);
|
||||||
|
}
|
||||||
|
|
||||||
|
static NativeRenderer *fromJni(jlong renderer) {
|
||||||
|
return reinterpret_cast<NativeRenderer*>(renderer);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define JNI_METHOD(r, name) JNIEXPORT r JNICALL Java_org_saintandreas_testapp_MainActivity_##name
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
|
||||||
|
JNI_METHOD(jlong, nativeCreateRenderer)
|
||||||
|
(JNIEnv *env, jclass clazz, jobject class_loader, jobject android_context, jlong native_gvr_api) {
|
||||||
|
qInstallMessageHandler(messageHandler);
|
||||||
|
#if defined(GVR)
|
||||||
|
auto gvrContext = reinterpret_cast<gvr_context *>(native_gvr_api);
|
||||||
|
return toJni(new NativeRenderer(gvrContext));
|
||||||
|
#else
|
||||||
|
return toJni(new NativeRenderer(nullptr));
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
JNI_METHOD(void, nativeDestroyRenderer)
|
||||||
|
(JNIEnv *env, jclass clazz, jlong renderer) {
|
||||||
|
delete fromJni(renderer);
|
||||||
|
}
|
||||||
|
|
||||||
|
JNI_METHOD(void, nativeInitializeGl)
|
||||||
|
(JNIEnv *env, jobject obj, jlong renderer) {
|
||||||
|
fromJni(renderer)->InitializeGl();
|
||||||
|
}
|
||||||
|
|
||||||
|
JNI_METHOD(void, nativeDrawFrame)
|
||||||
|
(JNIEnv *env, jobject obj, jlong renderer) {
|
||||||
|
fromJni(renderer)->DrawFrame();
|
||||||
|
}
|
||||||
|
|
||||||
|
JNI_METHOD(void, nativeOnTriggerEvent)
|
||||||
|
(JNIEnv *env, jobject obj, jlong renderer) {
|
||||||
|
fromJni(renderer)->OnTriggerEvent();
|
||||||
|
}
|
||||||
|
|
||||||
|
JNI_METHOD(void, nativeOnPause)
|
||||||
|
(JNIEnv *env, jobject obj, jlong renderer) {
|
||||||
|
fromJni(renderer)->OnPause();
|
||||||
|
}
|
||||||
|
|
||||||
|
JNI_METHOD(void, nativeOnResume)
|
||||||
|
(JNIEnv *env, jobject obj, jlong renderer) {
|
||||||
|
fromJni(renderer)->OnResume();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // extern "C"
|
636
android/app/src/main/cpp/renderer.cpp
Normal file
|
@ -0,0 +1,636 @@
|
||||||
|
#include "renderer.h"
|
||||||
|
|
||||||
|
#include <mutex>
|
||||||
|
|
||||||
|
#include <QtCore/QDebug>
|
||||||
|
#include <gl/Config.h>
|
||||||
|
|
||||||
|
#include "GoogleVRHelpers.h"
|
||||||
|
|
||||||
|
#include <gl/GLShaders.h>
|
||||||
|
#include <shared/Bilateral.h>
|
||||||
|
|
||||||
|
#include <gpu/DrawTransformUnitQuad_vert.h>
|
||||||
|
#include <gpu/DrawTexcoordRectTransformUnitQuad_vert.h>
|
||||||
|
#include <gpu/DrawViewportQuadTransformTexcoord_vert.h>
|
||||||
|
#include <gpu/DrawTexture_frag.h>
|
||||||
|
#include <gpu/DrawTextureOpaque_frag.h>
|
||||||
|
#include <gpu/DrawColoredTexture_frag.h>
|
||||||
|
|
||||||
|
#include <render-utils/simple_vert.h>
|
||||||
|
#include <render-utils/simple_frag.h>
|
||||||
|
#include <render-utils/simple_textured_frag.h>
|
||||||
|
#include <render-utils/simple_textured_unlit_frag.h>
|
||||||
|
|
||||||
|
#include <render-utils/deferred_light_vert.h>
|
||||||
|
#include <render-utils/deferred_light_point_vert.h>
|
||||||
|
#include <render-utils/deferred_light_spot_vert.h>
|
||||||
|
|
||||||
|
#include <render-utils/directional_ambient_light_frag.h>
|
||||||
|
#include <render-utils/directional_skybox_light_frag.h>
|
||||||
|
|
||||||
|
#include <render-utils/standardTransformPNTC_vert.h>
|
||||||
|
#include <render-utils/standardDrawTexture_frag.h>
|
||||||
|
|
||||||
|
#include <render-utils/model_vert.h>
|
||||||
|
#include <render-utils/model_shadow_vert.h>
|
||||||
|
#include <render-utils/model_normal_map_vert.h>
|
||||||
|
#include <render-utils/model_lightmap_vert.h>
|
||||||
|
#include <render-utils/model_lightmap_normal_map_vert.h>
|
||||||
|
#include <render-utils/skin_model_vert.h>
|
||||||
|
#include <render-utils/skin_model_shadow_vert.h>
|
||||||
|
#include <render-utils/skin_model_normal_map_vert.h>
|
||||||
|
|
||||||
|
#include <render-utils/model_frag.h>
|
||||||
|
#include <render-utils/model_shadow_frag.h>
|
||||||
|
#include <render-utils/model_normal_map_frag.h>
|
||||||
|
#include <render-utils/model_normal_specular_map_frag.h>
|
||||||
|
#include <render-utils/model_specular_map_frag.h>
|
||||||
|
#include <render-utils/model_lightmap_frag.h>
|
||||||
|
#include <render-utils/model_lightmap_normal_map_frag.h>
|
||||||
|
#include <render-utils/model_lightmap_normal_specular_map_frag.h>
|
||||||
|
#include <render-utils/model_lightmap_specular_map_frag.h>
|
||||||
|
#include <render-utils/model_translucent_frag.h>
|
||||||
|
#include <render-utils/overlay3D_vert.h>
|
||||||
|
#include <render-utils/overlay3D_frag.h>
|
||||||
|
|
||||||
|
#include <render-utils/sdf_text3D_vert.h>
|
||||||
|
#include <render-utils/sdf_text3D_frag.h>
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
#include <model/skybox_vert.h>
|
||||||
|
#include <model/skybox_frag.h>
|
||||||
|
#include <entities-renderer/textured_particle_frag.h>
|
||||||
|
#include <entities-renderer/textured_particle_vert.h>
|
||||||
|
#include <entities-renderer/paintStroke_vert.h>
|
||||||
|
#include <entities-renderer/paintStroke_frag.h>
|
||||||
|
#include <entities-renderer/polyvox_vert.h>
|
||||||
|
#include <entities-renderer/polyvox_frag.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
template <typename F>
|
||||||
|
void withFrameBuffer(gvr::Frame& frame, int32_t index, F f) {
|
||||||
|
frame.BindBuffer(index);
|
||||||
|
f();
|
||||||
|
frame.Unbind();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static const uint64_t kPredictionTimeWithoutVsyncNanos = 50000000;
|
||||||
|
|
||||||
|
// Each shader has two variants: a single-eye ES 2.0 variant, and a multiview
|
||||||
|
// ES 3.0 variant. The multiview vertex shaders use transforms defined by
|
||||||
|
// arrays of mat4 uniforms, using gl_ViewID_OVR to determine the array index.
|
||||||
|
|
||||||
|
#define UNIFORM_LIGHT_POS 20
|
||||||
|
#define UNIFORM_M 16
|
||||||
|
#define UNIFORM_MV 8
|
||||||
|
#define UNIFORM_MVP 0
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
uniform Transform { // API uses “Transform[2]” to refer to instance 2
|
||||||
|
mat4 u_MVP[2];
|
||||||
|
mat4 u_MVMatrix[2];
|
||||||
|
mat4 u_Model;
|
||||||
|
vec3 u_LightPos[2];
|
||||||
|
};
|
||||||
|
static const char *kDiffuseLightingVertexShader = R"glsl(
|
||||||
|
#version 300 es
|
||||||
|
#extension GL_OVR_multiview2 : enable
|
||||||
|
|
||||||
|
layout(num_views=2) in;
|
||||||
|
|
||||||
|
layout(location = 0) uniform mat4 u_MVP[2];
|
||||||
|
layout(location = 8) uniform mat4 u_MVMatrix[2];
|
||||||
|
layout(location = 16) uniform mat4 u_Model;
|
||||||
|
layout(location = 20) uniform vec3 u_LightPos[2];
|
||||||
|
|
||||||
|
layout(location = 0) in vec4 a_Position;
|
||||||
|
layout(location = 1) in vec4 a_Color;
|
||||||
|
layout(location = 2) in vec3 a_Normal;
|
||||||
|
|
||||||
|
out vec4 v_Color;
|
||||||
|
out vec3 v_Grid;
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
mat4 mvp = u_MVP[gl_ViewID_OVR];
|
||||||
|
mat4 modelview = u_MVMatrix[gl_ViewID_OVR];
|
||||||
|
vec3 lightpos = u_LightPos[gl_ViewID_OVR];
|
||||||
|
v_Grid = vec3(u_Model * a_Position);
|
||||||
|
vec3 modelViewVertex = vec3(modelview * a_Position);
|
||||||
|
vec3 modelViewNormal = vec3(modelview * vec4(a_Normal, 0.0));
|
||||||
|
float distance = length(lightpos - modelViewVertex);
|
||||||
|
vec3 lightVector = normalize(lightpos - modelViewVertex);
|
||||||
|
float diffuse = max(dot(modelViewNormal, lightVector), 0.5);
|
||||||
|
diffuse = diffuse * (1.0 / (1.0 + (0.00001 * distance * distance)));
|
||||||
|
v_Color = vec4(a_Color.rgb * diffuse, a_Color.a);
|
||||||
|
gl_Position = mvp * a_Position;
|
||||||
|
}
|
||||||
|
)glsl";
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
static const char *kSimepleVertexShader = R"glsl(
|
||||||
|
#version 300 es
|
||||||
|
#extension GL_OVR_multiview2 : enable
|
||||||
|
|
||||||
|
layout(num_views=2) in;
|
||||||
|
|
||||||
|
layout(location = 0) in vec4 a_Position;
|
||||||
|
|
||||||
|
out vec4 v_Color;
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
v_Color = vec4(a_Position.xyz, 1.0);
|
||||||
|
gl_Position = vec4(a_Position.xyz, 1.0);
|
||||||
|
}
|
||||||
|
)glsl";
|
||||||
|
|
||||||
|
|
||||||
|
static const char *kPassthroughFragmentShader = R"glsl(
|
||||||
|
#version 300 es
|
||||||
|
precision mediump float;
|
||||||
|
in vec4 v_Color;
|
||||||
|
out vec4 FragColor;
|
||||||
|
|
||||||
|
void main() { FragColor = v_Color; }
|
||||||
|
)glsl";
|
||||||
|
|
||||||
|
static void CheckGLError(const char* label) {
|
||||||
|
int gl_error = glGetError();
|
||||||
|
if (gl_error != GL_NO_ERROR) {
|
||||||
|
qWarning("GL error @ %s: %d", label, gl_error);
|
||||||
|
// Crash immediately to make OpenGL errors obvious.
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Contains vertex, normal and other data.
|
||||||
|
namespace cube {
|
||||||
|
const std::array<float, 108> CUBE_COORDS{{
|
||||||
|
// Front face
|
||||||
|
-1.0f, 1.0f, 1.0f,
|
||||||
|
-1.0f, -1.0f, 1.0f,
|
||||||
|
1.0f, 1.0f, 1.0f,
|
||||||
|
-1.0f, -1.0f, 1.0f,
|
||||||
|
1.0f, -1.0f, 1.0f,
|
||||||
|
1.0f, 1.0f, 1.0f,
|
||||||
|
|
||||||
|
// Right face
|
||||||
|
1.0f, 1.0f, 1.0f,
|
||||||
|
1.0f, -1.0f, 1.0f,
|
||||||
|
1.0f, 1.0f, -1.0f,
|
||||||
|
1.0f, -1.0f, 1.0f,
|
||||||
|
1.0f, -1.0f, -1.0f,
|
||||||
|
1.0f, 1.0f, -1.0f,
|
||||||
|
|
||||||
|
// Back face
|
||||||
|
1.0f, 1.0f, -1.0f,
|
||||||
|
1.0f, -1.0f, -1.0f,
|
||||||
|
-1.0f, 1.0f, -1.0f,
|
||||||
|
1.0f, -1.0f, -1.0f,
|
||||||
|
-1.0f, -1.0f, -1.0f,
|
||||||
|
-1.0f, 1.0f, -1.0f,
|
||||||
|
|
||||||
|
// Left face
|
||||||
|
-1.0f, 1.0f, -1.0f,
|
||||||
|
-1.0f, -1.0f, -1.0f,
|
||||||
|
-1.0f, 1.0f, 1.0f,
|
||||||
|
-1.0f, -1.0f, -1.0f,
|
||||||
|
-1.0f, -1.0f, 1.0f,
|
||||||
|
-1.0f, 1.0f, 1.0f,
|
||||||
|
|
||||||
|
// Top face
|
||||||
|
-1.0f, 1.0f, -1.0f,
|
||||||
|
-1.0f, 1.0f, 1.0f,
|
||||||
|
1.0f, 1.0f, -1.0f,
|
||||||
|
-1.0f, 1.0f, 1.0f,
|
||||||
|
1.0f, 1.0f, 1.0f,
|
||||||
|
1.0f, 1.0f, -1.0f,
|
||||||
|
|
||||||
|
// Bottom face
|
||||||
|
1.0f, -1.0f, -1.0f,
|
||||||
|
1.0f, -1.0f, 1.0f,
|
||||||
|
-1.0f, -1.0f, -1.0f,
|
||||||
|
1.0f, -1.0f, 1.0f,
|
||||||
|
-1.0f, -1.0f, 1.0f,
|
||||||
|
-1.0f, -1.0f, -1.0f
|
||||||
|
}};
|
||||||
|
|
||||||
|
const std::array<float, 108> CUBE_COLORS{{
|
||||||
|
// front, green
|
||||||
|
0.0f, 0.5273f, 0.2656f,
|
||||||
|
0.0f, 0.5273f, 0.2656f,
|
||||||
|
0.0f, 0.5273f, 0.2656f,
|
||||||
|
0.0f, 0.5273f, 0.2656f,
|
||||||
|
0.0f, 0.5273f, 0.2656f,
|
||||||
|
0.0f, 0.5273f, 0.2656f,
|
||||||
|
|
||||||
|
// right, blue
|
||||||
|
0.0f, 0.3398f, 0.9023f,
|
||||||
|
0.0f, 0.3398f, 0.9023f,
|
||||||
|
0.0f, 0.3398f, 0.9023f,
|
||||||
|
0.0f, 0.3398f, 0.9023f,
|
||||||
|
0.0f, 0.3398f, 0.9023f,
|
||||||
|
0.0f, 0.3398f, 0.9023f,
|
||||||
|
|
||||||
|
// back, also green
|
||||||
|
0.0f, 0.5273f, 0.2656f,
|
||||||
|
0.0f, 0.5273f, 0.2656f,
|
||||||
|
0.0f, 0.5273f, 0.2656f,
|
||||||
|
0.0f, 0.5273f, 0.2656f,
|
||||||
|
0.0f, 0.5273f, 0.2656f,
|
||||||
|
0.0f, 0.5273f, 0.2656f,
|
||||||
|
|
||||||
|
// left, also blue
|
||||||
|
0.0f, 0.3398f, 0.9023f,
|
||||||
|
0.0f, 0.3398f, 0.9023f,
|
||||||
|
0.0f, 0.3398f, 0.9023f,
|
||||||
|
0.0f, 0.3398f, 0.9023f,
|
||||||
|
0.0f, 0.3398f, 0.9023f,
|
||||||
|
0.0f, 0.3398f, 0.9023f,
|
||||||
|
|
||||||
|
// top, red
|
||||||
|
0.8359375f, 0.17578125f, 0.125f,
|
||||||
|
0.8359375f, 0.17578125f, 0.125f,
|
||||||
|
0.8359375f, 0.17578125f, 0.125f,
|
||||||
|
0.8359375f, 0.17578125f, 0.125f,
|
||||||
|
0.8359375f, 0.17578125f, 0.125f,
|
||||||
|
0.8359375f, 0.17578125f, 0.125f,
|
||||||
|
|
||||||
|
// bottom, also red
|
||||||
|
0.8359375f, 0.17578125f, 0.125f,
|
||||||
|
0.8359375f, 0.17578125f, 0.125f,
|
||||||
|
0.8359375f, 0.17578125f, 0.125f,
|
||||||
|
0.8359375f, 0.17578125f, 0.125f,
|
||||||
|
0.8359375f, 0.17578125f, 0.125f,
|
||||||
|
0.8359375f, 0.17578125f, 0.125f
|
||||||
|
}};
|
||||||
|
|
||||||
|
const std::array<float, 108> CUBE_NORMALS{{
|
||||||
|
// Front face
|
||||||
|
0.0f, 0.0f, 1.0f,
|
||||||
|
0.0f, 0.0f, 1.0f,
|
||||||
|
0.0f, 0.0f, 1.0f,
|
||||||
|
0.0f, 0.0f, 1.0f,
|
||||||
|
0.0f, 0.0f, 1.0f,
|
||||||
|
0.0f, 0.0f, 1.0f,
|
||||||
|
|
||||||
|
// Right face
|
||||||
|
1.0f, 0.0f, 0.0f,
|
||||||
|
1.0f, 0.0f, 0.0f,
|
||||||
|
1.0f, 0.0f, 0.0f,
|
||||||
|
1.0f, 0.0f, 0.0f,
|
||||||
|
1.0f, 0.0f, 0.0f,
|
||||||
|
1.0f, 0.0f, 0.0f,
|
||||||
|
|
||||||
|
// Back face
|
||||||
|
0.0f, 0.0f, -1.0f,
|
||||||
|
0.0f, 0.0f, -1.0f,
|
||||||
|
0.0f, 0.0f, -1.0f,
|
||||||
|
0.0f, 0.0f, -1.0f,
|
||||||
|
0.0f, 0.0f, -1.0f,
|
||||||
|
0.0f, 0.0f, -1.0f,
|
||||||
|
|
||||||
|
// Left face
|
||||||
|
-1.0f, 0.0f, 0.0f,
|
||||||
|
-1.0f, 0.0f, 0.0f,
|
||||||
|
-1.0f, 0.0f, 0.0f,
|
||||||
|
-1.0f, 0.0f, 0.0f,
|
||||||
|
-1.0f, 0.0f, 0.0f,
|
||||||
|
-1.0f, 0.0f, 0.0f,
|
||||||
|
|
||||||
|
// Top face
|
||||||
|
0.0f, 1.0f, 0.0f,
|
||||||
|
0.0f, 1.0f, 0.0f,
|
||||||
|
0.0f, 1.0f, 0.0f,
|
||||||
|
0.0f, 1.0f, 0.0f,
|
||||||
|
0.0f, 1.0f, 0.0f,
|
||||||
|
0.0f, 1.0f, 0.0f,
|
||||||
|
|
||||||
|
// Bottom face
|
||||||
|
0.0f, -1.0f, 0.0f,
|
||||||
|
0.0f, -1.0f, 0.0f,
|
||||||
|
0.0f, -1.0f, 0.0f,
|
||||||
|
0.0f, -1.0f, 0.0f,
|
||||||
|
0.0f, -1.0f, 0.0f,
|
||||||
|
0.0f, -1.0f, 0.0f
|
||||||
|
}};
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace triangle {
|
||||||
|
static std::array<float, 9> TRIANGLE_VERTS {{
|
||||||
|
-0.5f, -0.5f, 0.0f,
|
||||||
|
0.5f, -0.5f, 0.0f,
|
||||||
|
0.0f, 0.5f, 0.0f
|
||||||
|
}};
|
||||||
|
}
|
||||||
|
|
||||||
|
std::array<gvr::BufferViewport, 2> buildViewports(const std::unique_ptr<gvr::GvrApi> &gvrapi) {
|
||||||
|
return { {gvrapi->CreateBufferViewport(), gvrapi->CreateBufferViewport()} };
|
||||||
|
};
|
||||||
|
|
||||||
|
const std::string VERTEX_SHADER_DEFINES{ R"GLSL(
|
||||||
|
#version 300 es
|
||||||
|
#extension GL_EXT_clip_cull_distance : enable
|
||||||
|
#define GPU_VERTEX_SHADER
|
||||||
|
#define GPU_SSBO_TRANSFORM_OBJECT 1
|
||||||
|
#define GPU_TRANSFORM_IS_STEREO
|
||||||
|
#define GPU_TRANSFORM_STEREO_CAMERA
|
||||||
|
#define GPU_TRANSFORM_STEREO_CAMERA_INSTANCED
|
||||||
|
#define GPU_TRANSFORM_STEREO_SPLIT_SCREEN
|
||||||
|
)GLSL" };
|
||||||
|
|
||||||
|
const std::string PIXEL_SHADER_DEFINES{ R"GLSL(
|
||||||
|
#version 300 es
|
||||||
|
precision mediump float;
|
||||||
|
#define GPU_PIXEL_SHADER
|
||||||
|
#define GPU_TRANSFORM_IS_STEREO
|
||||||
|
#define GPU_TRANSFORM_STEREO_CAMERA
|
||||||
|
#define GPU_TRANSFORM_STEREO_CAMERA_INSTANCED
|
||||||
|
#define GPU_TRANSFORM_STEREO_SPLIT_SCREEN
|
||||||
|
)GLSL" };
|
||||||
|
|
||||||
|
|
||||||
|
#if defined(GVR)
|
||||||
|
NativeRenderer::NativeRenderer(gvr_context *vrContext) :
|
||||||
|
_gvrapi(new gvr::GvrApi(vrContext, false)),
|
||||||
|
_viewports(buildViewports(_gvrapi)),
|
||||||
|
_gvr_viewer_type(_gvrapi->GetViewerType())
|
||||||
|
#else
|
||||||
|
NativeRenderer::NativeRenderer(void *vrContext)
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
start = std::chrono::system_clock::now();
|
||||||
|
qDebug() << "QQQ" << __FUNCTION__;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts a raw text file, saved as a resource, into an OpenGL ES shader.
|
||||||
|
*
|
||||||
|
* @param type The type of shader we will be creating.
|
||||||
|
* @param resId The resource ID of the raw text file.
|
||||||
|
* @return The shader object handler.
|
||||||
|
*/
|
||||||
|
int LoadGLShader(int type, const char *shadercode) {
|
||||||
|
GLuint result = 0;
|
||||||
|
std::string shaderError;
|
||||||
|
static const std::string SHADER_DEFINES;
|
||||||
|
if (!gl::compileShader(type, shadercode, SHADER_DEFINES, result, shaderError)) {
|
||||||
|
qWarning() << "QQQ" << __FUNCTION__ << "Shader compile failure" << shaderError.c_str();
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Computes a texture size that has approximately half as many pixels. This is
|
||||||
|
// equivalent to scaling each dimension by approximately sqrt(2)/2.
|
||||||
|
static gvr::Sizei HalfPixelCount(const gvr::Sizei &in) {
|
||||||
|
// Scale each dimension by sqrt(2)/2 ~= 7/10ths.
|
||||||
|
gvr::Sizei out;
|
||||||
|
out.width = (7 * in.width) / 10;
|
||||||
|
out.height = (7 * in.height) / 10;
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#if defined(GVR)
|
||||||
|
void NativeRenderer::InitializeVR() {
|
||||||
|
_gvrapi->InitializeGl();
|
||||||
|
bool multiviewEnabled = _gvrapi->IsFeatureSupported(GVR_FEATURE_MULTIVIEW);
|
||||||
|
qWarning() << "QQQ" << __FUNCTION__ << "Multiview enabled " << multiviewEnabled;
|
||||||
|
// Because we are using 2X MSAA, we can render to half as many pixels and
|
||||||
|
// achieve similar quality.
|
||||||
|
_renderSize = HalfPixelCount(_gvrapi->GetMaximumEffectiveRenderTargetSize());
|
||||||
|
|
||||||
|
std::vector<gvr::BufferSpec> specs;
|
||||||
|
specs.push_back(_gvrapi->CreateBufferSpec());
|
||||||
|
specs[0].SetColorFormat(GVR_COLOR_FORMAT_RGBA_8888);
|
||||||
|
specs[0].SetDepthStencilFormat(GVR_DEPTH_STENCIL_FORMAT_DEPTH_16);
|
||||||
|
specs[0].SetSamples(2);
|
||||||
|
gvr::Sizei half_size = {_renderSize.width / 2, _renderSize.height};
|
||||||
|
specs[0].SetMultiviewLayers(2);
|
||||||
|
specs[0].SetSize(half_size);
|
||||||
|
|
||||||
|
_swapchain.reset(new gvr::SwapChain(_gvrapi->CreateSwapChain(specs)));
|
||||||
|
_viewportlist.reset(new gvr::BufferViewportList(_gvrapi->CreateEmptyBufferViewportList()));
|
||||||
|
}
|
||||||
|
void NativeRenderer::PrepareFramebuffer() {
|
||||||
|
const gvr::Sizei recommended_size = HalfPixelCount(
|
||||||
|
_gvrapi->GetMaximumEffectiveRenderTargetSize());
|
||||||
|
if (_renderSize.width != recommended_size.width ||
|
||||||
|
_renderSize.height != recommended_size.height) {
|
||||||
|
// We need to resize the framebuffer. Note that multiview uses two texture
|
||||||
|
// layers, each with half the render width.
|
||||||
|
gvr::Sizei framebuffer_size = recommended_size;
|
||||||
|
framebuffer_size.width /= 2;
|
||||||
|
_swapchain->ResizeBuffer(0, framebuffer_size);
|
||||||
|
_renderSize = recommended_size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void testShaderBuild(const char* vs_src, const char * fs_src) {
|
||||||
|
std::string error;
|
||||||
|
GLuint vs, fs;
|
||||||
|
if (!gl::compileShader(GL_VERTEX_SHADER, vs_src, VERTEX_SHADER_DEFINES, vs, error) ||
|
||||||
|
!gl::compileShader(GL_FRAGMENT_SHADER, fs_src, PIXEL_SHADER_DEFINES, fs, error)) {
|
||||||
|
throw std::runtime_error("Failed to compile shader");
|
||||||
|
}
|
||||||
|
auto pr = gl::compileProgram({ vs, fs }, error);
|
||||||
|
if (!pr) {
|
||||||
|
throw std::runtime_error("Failed to link shader");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void NativeRenderer::InitializeGl() {
|
||||||
|
qDebug() << "QQQ" << __FUNCTION__;
|
||||||
|
//gl::initModuleGl();
|
||||||
|
#if defined(GVR)
|
||||||
|
InitializeVR();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
glDisable(GL_DEPTH_TEST);
|
||||||
|
glDisable(GL_CULL_FACE);
|
||||||
|
glDisable(GL_SCISSOR_TEST);
|
||||||
|
glDisable(GL_BLEND);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
const uint32_t vertShader = LoadGLShader(GL_VERTEX_SHADER, kSimepleVertexShader);
|
||||||
|
//const uint32_t vertShader = LoadGLShader(GL_VERTEX_SHADER, kDiffuseLightingVertexShader);
|
||||||
|
const uint32_t fragShader = LoadGLShader(GL_FRAGMENT_SHADER, kPassthroughFragmentShader);
|
||||||
|
std::string error;
|
||||||
|
_cubeProgram = gl::compileProgram({ vertShader, fragShader }, error);
|
||||||
|
CheckGLError("build program");
|
||||||
|
|
||||||
|
glGenBuffers(1, &_cubeBuffer);
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, _cubeBuffer);
|
||||||
|
glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 9, triangle::TRIANGLE_VERTS.data(), GL_STATIC_DRAW);
|
||||||
|
/*
|
||||||
|
glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 108 * 3, NULL, GL_STATIC_DRAW);
|
||||||
|
glBufferSubData(GL_ARRAY_BUFFER, sizeof(float) * 108 * 0, sizeof(float) * 108, cube::CUBE_COORDS.data());
|
||||||
|
glBufferSubData(GL_ARRAY_BUFFER, sizeof(float) * 108 * 1, sizeof(float) * 108, cube::CUBE_COLORS.data());
|
||||||
|
glBufferSubData(GL_ARRAY_BUFFER, sizeof(float) * 108 * 2, sizeof(float) * 108, cube::CUBE_NORMALS.data());
|
||||||
|
*/
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||||
|
CheckGLError("upload vertices");
|
||||||
|
|
||||||
|
glGenVertexArrays(1, &_cubeVao);
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, _cubeBuffer);
|
||||||
|
glBindVertexArray(_cubeVao);
|
||||||
|
|
||||||
|
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
|
||||||
|
glEnableVertexAttribArray(0);
|
||||||
|
/*
|
||||||
|
glVertexAttribPointer(0, 3, GL_FLOAT, false, 0, 0);
|
||||||
|
glEnableVertexAttribArray(0);
|
||||||
|
glVertexAttribPointer(1, 3, GL_FLOAT, false, 0, (const void*)(sizeof(float) * 108 * 1) );
|
||||||
|
glEnableVertexAttribArray(1);
|
||||||
|
glVertexAttribPointer(2, 3, GL_FLOAT, false, 0, (const void*)(sizeof(float) * 108 * 2));
|
||||||
|
glEnableVertexAttribArray(2);
|
||||||
|
*/
|
||||||
|
glBindVertexArray(0);
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||||
|
CheckGLError("build vao ");
|
||||||
|
|
||||||
|
static std::once_flag once;
|
||||||
|
std::call_once(once, [&]{
|
||||||
|
testShaderBuild(sdf_text3D_vert, sdf_text3D_frag);
|
||||||
|
|
||||||
|
testShaderBuild(DrawTransformUnitQuad_vert, DrawTexture_frag);
|
||||||
|
testShaderBuild(DrawTexcoordRectTransformUnitQuad_vert, DrawTexture_frag);
|
||||||
|
testShaderBuild(DrawViewportQuadTransformTexcoord_vert, DrawTexture_frag);
|
||||||
|
testShaderBuild(DrawTransformUnitQuad_vert, DrawTextureOpaque_frag);
|
||||||
|
testShaderBuild(DrawTransformUnitQuad_vert, DrawColoredTexture_frag);
|
||||||
|
|
||||||
|
testShaderBuild(simple_vert, simple_frag);
|
||||||
|
testShaderBuild(simple_vert, simple_textured_frag);
|
||||||
|
testShaderBuild(simple_vert, simple_textured_unlit_frag);
|
||||||
|
testShaderBuild(deferred_light_vert, directional_ambient_light_frag);
|
||||||
|
testShaderBuild(deferred_light_vert, directional_skybox_light_frag);
|
||||||
|
testShaderBuild(standardTransformPNTC_vert, standardDrawTexture_frag);
|
||||||
|
testShaderBuild(standardTransformPNTC_vert, DrawTextureOpaque_frag);
|
||||||
|
|
||||||
|
testShaderBuild(model_vert, model_frag);
|
||||||
|
testShaderBuild(model_normal_map_vert, model_normal_map_frag);
|
||||||
|
testShaderBuild(model_vert, model_specular_map_frag);
|
||||||
|
testShaderBuild(model_normal_map_vert, model_normal_specular_map_frag);
|
||||||
|
testShaderBuild(model_vert, model_translucent_frag);
|
||||||
|
testShaderBuild(model_normal_map_vert, model_translucent_frag);
|
||||||
|
testShaderBuild(model_lightmap_vert, model_lightmap_frag);
|
||||||
|
testShaderBuild(model_lightmap_normal_map_vert, model_lightmap_normal_map_frag);
|
||||||
|
testShaderBuild(model_lightmap_vert, model_lightmap_specular_map_frag);
|
||||||
|
testShaderBuild(model_lightmap_normal_map_vert, model_lightmap_normal_specular_map_frag);
|
||||||
|
|
||||||
|
testShaderBuild(skin_model_vert, model_frag);
|
||||||
|
testShaderBuild(skin_model_normal_map_vert, model_normal_map_frag);
|
||||||
|
testShaderBuild(skin_model_vert, model_specular_map_frag);
|
||||||
|
testShaderBuild(skin_model_normal_map_vert, model_normal_specular_map_frag);
|
||||||
|
testShaderBuild(skin_model_vert, model_translucent_frag);
|
||||||
|
testShaderBuild(skin_model_normal_map_vert, model_translucent_frag);
|
||||||
|
|
||||||
|
testShaderBuild(model_shadow_vert, model_shadow_frag);
|
||||||
|
|
||||||
|
testShaderBuild(overlay3D_vert, overlay3D_frag);
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
testShaderBuild(textured_particle_vert, textured_particle_frag);
|
||||||
|
testShaderBuild(skybox_vert, skybox_frag);
|
||||||
|
testShaderBuild(paintStroke_vert,paintStroke_frag);
|
||||||
|
testShaderBuild(polyvox_vert, polyvox_frag);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
qDebug() << "done";
|
||||||
|
}
|
||||||
|
|
||||||
|
static const float kZNear = 1.0f;
|
||||||
|
static const float kZFar = 100.0f;
|
||||||
|
static const gvr_rectf fullscreen = {0, 1, 0, 1};
|
||||||
|
|
||||||
|
void NativeRenderer::DrawFrame() {
|
||||||
|
auto now = std::chrono::duration_cast<std::chrono::milliseconds>(
|
||||||
|
std::chrono::system_clock::now() - start);
|
||||||
|
glm::vec3 v;
|
||||||
|
v.r = (float) (now.count() % 1000) / 1000.0f;
|
||||||
|
v.g = 1.0f - v.r;
|
||||||
|
v.b = 1.0f;
|
||||||
|
|
||||||
|
PrepareFramebuffer();
|
||||||
|
|
||||||
|
// A client app does its rendering here.
|
||||||
|
gvr::ClockTimePoint target_time = gvr::GvrApi::GetTimePointNow();
|
||||||
|
target_time.monotonic_system_time_nanos += kPredictionTimeWithoutVsyncNanos;
|
||||||
|
|
||||||
|
using namespace googlevr;
|
||||||
|
using namespace bilateral;
|
||||||
|
const auto gvrHeadPose = _gvrapi->GetHeadSpaceFromStartSpaceRotation(target_time);
|
||||||
|
_head_view = toGlm(gvrHeadPose);
|
||||||
|
_viewportlist->SetToRecommendedBufferViewports();
|
||||||
|
|
||||||
|
glm::mat4 eye_views[2];
|
||||||
|
for_each_side([&](bilateral::Side side) {
|
||||||
|
int eye = index(side);
|
||||||
|
const gvr::Eye gvr_eye = eye == 0 ? GVR_LEFT_EYE : GVR_RIGHT_EYE;
|
||||||
|
const auto& eyeView = eye_views[eye] = toGlm(_gvrapi->GetEyeFromHeadMatrix(gvr_eye)) * _head_view;
|
||||||
|
auto& viewport = _viewports[eye];
|
||||||
|
|
||||||
|
_viewportlist->GetBufferViewport(eye, &viewport);
|
||||||
|
viewport.SetSourceUv(fullscreen);
|
||||||
|
viewport.SetSourceLayer(eye);
|
||||||
|
_viewportlist->SetBufferViewport(eye, viewport);
|
||||||
|
const auto &mvc = _modelview_cube[eye] = eyeView * _model_cube;
|
||||||
|
const auto &mvf = _modelview_floor[eye] = eyeView * _model_floor;
|
||||||
|
const gvr_rectf fov = viewport.GetSourceFov();
|
||||||
|
const glm::mat4 perspective = perspectiveMatrixFromView(fov, kZNear, kZFar);
|
||||||
|
_modelview_projection_cube[eye] = perspective * mvc;
|
||||||
|
_modelview_projection_floor[eye] = perspective * mvf;
|
||||||
|
_light_pos_eye_space[eye] = glm::vec3(eyeView * _light_pos_world_space);
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
gvr::Frame frame = _swapchain->AcquireFrame();
|
||||||
|
withFrameBuffer(frame, 0, [&]{
|
||||||
|
glClearColor(v.r, v.g, v.b, 1);
|
||||||
|
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||||
|
glViewport(0, 0, _renderSize.width / 2, _renderSize.height);
|
||||||
|
glUseProgram(_cubeProgram);
|
||||||
|
glBindVertexArray(_cubeVao);
|
||||||
|
glDrawArrays(GL_TRIANGLES, 0, 3);
|
||||||
|
/*
|
||||||
|
float* fp;
|
||||||
|
fp = (float*)&_light_pos_eye_space[0];
|
||||||
|
glUniform3fv(UNIFORM_LIGHT_POS, 2, fp);
|
||||||
|
fp = (float*)&_modelview_cube[0];
|
||||||
|
glUniformMatrix4fv(UNIFORM_MV, 2, GL_FALSE, fp);
|
||||||
|
fp = (float*)&_modelview_projection_cube[0];
|
||||||
|
glUniformMatrix4fv(UNIFORM_MVP, 2, GL_FALSE, fp);
|
||||||
|
fp = (float*)&_model_cube;
|
||||||
|
glUniformMatrix4fv(UNIFORM_M, 1, GL_FALSE, fp);
|
||||||
|
glDrawArrays(GL_TRIANGLES, 0, 36);
|
||||||
|
*/
|
||||||
|
glBindVertexArray(0);
|
||||||
|
});
|
||||||
|
|
||||||
|
frame.Submit(*_viewportlist, gvrHeadPose);
|
||||||
|
CheckGLError("onDrawFrame");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void NativeRenderer::OnTriggerEvent() {
|
||||||
|
qDebug() << "QQQ" << __FUNCTION__;
|
||||||
|
}
|
||||||
|
|
||||||
|
void NativeRenderer::OnPause() {
|
||||||
|
qDebug() << "QQQ" << __FUNCTION__;
|
||||||
|
_gvrapi->PauseTracking();
|
||||||
|
}
|
||||||
|
|
||||||
|
void NativeRenderer::OnResume() {
|
||||||
|
qDebug() << "QQQ" << __FUNCTION__;
|
||||||
|
_gvrapi->ResumeTracking();
|
||||||
|
_gvrapi->RefreshViewerProfile();
|
||||||
|
}
|
60
android/app/src/main/cpp/renderer.h
Normal file
|
@ -0,0 +1,60 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <chrono>
|
||||||
|
#include <array>
|
||||||
|
#include <glm/glm.hpp>
|
||||||
|
|
||||||
|
#define GVR
|
||||||
|
|
||||||
|
#if defined(GVR)
|
||||||
|
#include <vr/gvr/capi/include/gvr.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
class NativeRenderer {
|
||||||
|
public:
|
||||||
|
|
||||||
|
#if defined(GVR)
|
||||||
|
NativeRenderer(gvr_context* vrContext);
|
||||||
|
#else
|
||||||
|
NativeRenderer(void* vrContext);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void InitializeGl();
|
||||||
|
void DrawFrame();
|
||||||
|
void OnTriggerEvent();
|
||||||
|
void OnPause();
|
||||||
|
void OnResume();
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
|
||||||
|
std::chrono::time_point<std::chrono::system_clock> start;
|
||||||
|
#if defined(GVR)
|
||||||
|
void InitializeVR();
|
||||||
|
void PrepareFramebuffer();
|
||||||
|
|
||||||
|
std::unique_ptr<gvr::GvrApi> _gvrapi;
|
||||||
|
gvr::ViewerType _gvr_viewer_type;
|
||||||
|
std::unique_ptr<gvr::BufferViewportList> _viewportlist;
|
||||||
|
std::unique_ptr<gvr::SwapChain> _swapchain;
|
||||||
|
std::array<gvr::BufferViewport, 2> _viewports;
|
||||||
|
gvr::Sizei _renderSize;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
uint32_t _cubeBuffer { 0 };
|
||||||
|
uint32_t _cubeVao { 0 };
|
||||||
|
uint32_t _cubeProgram { 0 };
|
||||||
|
|
||||||
|
glm::mat4 _head_view;
|
||||||
|
glm::mat4 _model_cube;
|
||||||
|
glm::mat4 _camera;
|
||||||
|
glm::mat4 _view;
|
||||||
|
glm::mat4 _model_floor;
|
||||||
|
|
||||||
|
std::array<glm::mat4, 2> _modelview_cube;
|
||||||
|
std::array<glm::mat4, 2> _modelview_floor;
|
||||||
|
std::array<glm::mat4, 2> _modelview_projection_cube;
|
||||||
|
std::array<glm::mat4, 2> _modelview_projection_floor;
|
||||||
|
std::array<glm::vec3, 2> _light_pos_eye_space;
|
||||||
|
const glm::vec4 _light_pos_world_space{ 0, 2, 0, 1};
|
||||||
|
};
|
|
@ -0,0 +1,105 @@
|
||||||
|
package org.saintandreas.testapp;
|
||||||
|
|
||||||
|
import android.app.Activity;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.opengl.GLSurfaceView;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.view.View;
|
||||||
|
|
||||||
|
import com.google.vr.ndk.base.AndroidCompat;
|
||||||
|
import com.google.vr.ndk.base.GvrLayout;
|
||||||
|
|
||||||
|
import javax.microedition.khronos.egl.EGLConfig;
|
||||||
|
import javax.microedition.khronos.opengles.GL10;
|
||||||
|
|
||||||
|
public class MainActivity extends Activity {
|
||||||
|
private final static int IMMERSIVE_STICKY_VIEW_FLAGS = View.SYSTEM_UI_FLAG_LAYOUT_STABLE |
|
||||||
|
View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION |
|
||||||
|
View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN |
|
||||||
|
View.SYSTEM_UI_FLAG_HIDE_NAVIGATION |
|
||||||
|
View.SYSTEM_UI_FLAG_FULLSCREEN |
|
||||||
|
View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY;
|
||||||
|
|
||||||
|
static {
|
||||||
|
System.loadLibrary("gvr");
|
||||||
|
System.loadLibrary("native-lib");
|
||||||
|
}
|
||||||
|
|
||||||
|
private long nativeRenderer;
|
||||||
|
private GvrLayout gvrLayout;
|
||||||
|
private GLSurfaceView surfaceView;
|
||||||
|
|
||||||
|
private native long nativeCreateRenderer(ClassLoader appClassLoader, Context context, long nativeGvrContext);
|
||||||
|
private native void nativeDestroyRenderer(long renderer);
|
||||||
|
private native void nativeInitializeGl(long renderer);
|
||||||
|
private native void nativeDrawFrame(long renderer);
|
||||||
|
private native void nativeOnTriggerEvent(long renderer);
|
||||||
|
private native void nativeOnPause(long renderer);
|
||||||
|
private native void nativeOnResume(long renderer);
|
||||||
|
|
||||||
|
class NativeRenderer implements GLSurfaceView.Renderer {
|
||||||
|
@Override public void onSurfaceCreated(GL10 gl, EGLConfig config) { nativeInitializeGl(nativeRenderer); }
|
||||||
|
@Override public void onSurfaceChanged(GL10 gl, int width, int height) { }
|
||||||
|
@Override public void onDrawFrame(GL10 gl) {
|
||||||
|
nativeDrawFrame(nativeRenderer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
setImmersiveSticky();
|
||||||
|
getWindow()
|
||||||
|
.getDecorView()
|
||||||
|
.setOnSystemUiVisibilityChangeListener((int visibility)->{
|
||||||
|
if ((visibility & View.SYSTEM_UI_FLAG_FULLSCREEN) == 0) { setImmersiveSticky(); }
|
||||||
|
});
|
||||||
|
|
||||||
|
gvrLayout = new GvrLayout(this);
|
||||||
|
nativeRenderer = nativeCreateRenderer(
|
||||||
|
getClass().getClassLoader(),
|
||||||
|
getApplicationContext(),
|
||||||
|
gvrLayout.getGvrApi().getNativeGvrContext());
|
||||||
|
|
||||||
|
surfaceView = new GLSurfaceView(this);
|
||||||
|
surfaceView.setEGLContextClientVersion(3);
|
||||||
|
surfaceView.setEGLConfigChooser(8, 8, 8, 0, 0, 0);
|
||||||
|
surfaceView.setPreserveEGLContextOnPause(true);
|
||||||
|
surfaceView.setRenderer(new NativeRenderer());
|
||||||
|
|
||||||
|
gvrLayout.setPresentationView(surfaceView);
|
||||||
|
setContentView(gvrLayout);
|
||||||
|
if (gvrLayout.setAsyncReprojectionEnabled(true)) {
|
||||||
|
AndroidCompat.setSustainedPerformanceMode(this, true);
|
||||||
|
}
|
||||||
|
AndroidCompat.setVrModeEnabled(this, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onDestroy() {
|
||||||
|
super.onDestroy();
|
||||||
|
gvrLayout.shutdown();
|
||||||
|
nativeDestroyRenderer(nativeRenderer);
|
||||||
|
nativeRenderer = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onPause() {
|
||||||
|
surfaceView.queueEvent(()->nativeOnPause(nativeRenderer));
|
||||||
|
surfaceView.onPause();
|
||||||
|
gvrLayout.onPause();
|
||||||
|
super.onPause();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onResume() {
|
||||||
|
super.onResume();
|
||||||
|
gvrLayout.onResume();
|
||||||
|
surfaceView.onResume();
|
||||||
|
surfaceView.queueEvent(()->nativeOnResume(nativeRenderer));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setImmersiveSticky() {
|
||||||
|
getWindow().getDecorView().setSystemUiVisibility(IMMERSIVE_STICKY_VIEW_FLAGS);
|
||||||
|
}
|
||||||
|
}
|
BIN
android/app/src/main/res/mipmap-hdpi/ic_launcher.png
Normal file
After Width: | Height: | Size: 3.3 KiB |
BIN
android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
Normal file
After Width: | Height: | Size: 4.1 KiB |
BIN
android/app/src/main/res/mipmap-mdpi/ic_launcher.png
Normal file
After Width: | Height: | Size: 2.2 KiB |
BIN
android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
Normal file
After Width: | Height: | Size: 2.5 KiB |
BIN
android/app/src/main/res/mipmap-xhdpi/ic_launcher.png
Normal file
After Width: | Height: | Size: 4.7 KiB |
BIN
android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
Normal file
After Width: | Height: | Size: 6 KiB |
BIN
android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
Normal file
After Width: | Height: | Size: 7.5 KiB |
BIN
android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
Normal file
After Width: | Height: | Size: 9.8 KiB |
BIN
android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
Normal file
After Width: | Height: | Size: 10 KiB |
BIN
android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
Normal file
After Width: | Height: | Size: 14 KiB |
4
android/app/src/main/res/values/colors.xml
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources>
|
||||||
|
<color name="white_opaque">#ffffff</color>
|
||||||
|
</resources>
|
3
android/app/src/main/res/values/strings.xml
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
<resources>
|
||||||
|
<string name="app_name">TestApp</string>
|
||||||
|
</resources>
|
15
android/app/src/main/res/values/styles.xml
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
<resources>
|
||||||
|
|
||||||
|
<!-- Base application theme. -->
|
||||||
|
<style name="AppTheme" parent="android:style/Theme.NoTitleBar.Fullscreen">
|
||||||
|
<!-- Customize your theme here. -->
|
||||||
|
<!--item name="android:windowFullscreen">true</item-->
|
||||||
|
<!--item name="android:windowNoTitle">true</item-->
|
||||||
|
<!--item name="android:windowActionBar">false</item-->
|
||||||
|
|
||||||
|
<!--item name="android:windowContentOverlay">@null</item-->
|
||||||
|
<!--item name="android:background">@color/white_opaque</item-->
|
||||||
|
</style>
|
||||||
|
|
||||||
|
|
||||||
|
</resources>
|
91
android/build.gradle
Normal file
|
@ -0,0 +1,91 @@
|
||||||
|
// Top-level build file where you can add configuration options common to all sub-projects/modules.
|
||||||
|
buildscript {
|
||||||
|
repositories {
|
||||||
|
jcenter()
|
||||||
|
}
|
||||||
|
dependencies {
|
||||||
|
classpath 'com.android.tools.build:gradle:2.3.3'
|
||||||
|
|
||||||
|
// NOTE: Do not place your application dependencies here; they belong
|
||||||
|
// in the individual module build.gradle files
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
allprojects {
|
||||||
|
repositories {
|
||||||
|
jcenter()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
task clean(type: Delete) {
|
||||||
|
delete rootProject.buildDir
|
||||||
|
}
|
||||||
|
|
||||||
|
task extractQt5jars(type: Copy) {
|
||||||
|
from fileTree(QT5_ROOT + "/jar")
|
||||||
|
into("${project.rootDir}/libraries/jar")
|
||||||
|
include("*.jar")
|
||||||
|
}
|
||||||
|
|
||||||
|
task extractQt5so(type: Copy) {
|
||||||
|
from fileTree(QT5_ROOT + "/lib")
|
||||||
|
into("${project.rootDir}/libraries/jni/armeabi-v7a/")
|
||||||
|
include("libQt5AndroidExtras.so")
|
||||||
|
include("libQt5Concurrent.so")
|
||||||
|
include("libQt5Core.so")
|
||||||
|
include("libQt5Gamepad.so")
|
||||||
|
include("libQt5Gui.so")
|
||||||
|
include("libQt5Location.so")
|
||||||
|
include("libQt5Multimedia.so")
|
||||||
|
include("libQt5MultimediaQuick_p.so")
|
||||||
|
include("libQt5Network.so")
|
||||||
|
include("libQt5NetworkAuth.so")
|
||||||
|
include("libQt5OpenGL.so")
|
||||||
|
include("libQt5Positioning.so")
|
||||||
|
include("libQt5Qml.so")
|
||||||
|
include("libQt5Quick.so")
|
||||||
|
include("libQt5QuickControls2.so")
|
||||||
|
include("libQt5QuickParticles.so")
|
||||||
|
include("libQt5QuickTemplates2.so")
|
||||||
|
include("libQt5QuickWidgets.so")
|
||||||
|
include("libQt5Script.so")
|
||||||
|
include("libQt5ScriptTools.so")
|
||||||
|
include("libQt5Sensors.so")
|
||||||
|
include("libQt5Svg.so")
|
||||||
|
include("libQt5WebChannel.so")
|
||||||
|
include("libQt5WebSockets.so")
|
||||||
|
include("libQt5WebView.so")
|
||||||
|
include("libQt5Widgets.so")
|
||||||
|
include("libQt5Xml.so")
|
||||||
|
include("libQt5XmlPatterns.so")
|
||||||
|
}
|
||||||
|
|
||||||
|
task extractAudioSo(type: Copy) {
|
||||||
|
from zipTree(GVR_ROOT + "/libraries/sdk-audio-1.80.0.aar")
|
||||||
|
into "${project.rootDir}/libraries/"
|
||||||
|
include "jni/armeabi-v7a/libgvr_audio.so"
|
||||||
|
}
|
||||||
|
|
||||||
|
task extractGvrSo(type: Copy) {
|
||||||
|
from zipTree(GVR_ROOT + "/libraries/sdk-base-1.80.0.aar")
|
||||||
|
into "${project.rootDir}/libraries/"
|
||||||
|
include "jni/armeabi-v7a/libgvr.so"
|
||||||
|
}
|
||||||
|
|
||||||
|
task extractNdk { }
|
||||||
|
extractNdk.dependsOn extractAudioSo
|
||||||
|
extractNdk.dependsOn extractGvrSo
|
||||||
|
|
||||||
|
task extractQt5 { }
|
||||||
|
extractQt5.dependsOn extractQt5so
|
||||||
|
extractQt5.dependsOn extractQt5jars
|
||||||
|
|
||||||
|
task extractBinaries { }
|
||||||
|
extractBinaries.dependsOn extractQt5
|
||||||
|
extractBinaries.dependsOn extractNdk
|
||||||
|
|
||||||
|
task deleteBinaries(type: Delete) {
|
||||||
|
delete "${project.rootDir}/libraries/jni"
|
||||||
|
}
|
||||||
|
|
||||||
|
//clean.dependsOn(deleteBinaries)
|
17
android/gradle.properties
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
# Project-wide Gradle settings.
|
||||||
|
|
||||||
|
# IDE (e.g. Android Studio) users:
|
||||||
|
# Gradle settings configured through the IDE *will override*
|
||||||
|
# any settings specified in this file.
|
||||||
|
|
||||||
|
# For more details on how to configure your build environment visit
|
||||||
|
# http://www.gradle.org/docs/current/userguide/build_environment.html
|
||||||
|
|
||||||
|
# Specifies the JVM arguments used for the daemon process.
|
||||||
|
# The setting is particularly useful for tweaking memory settings.
|
||||||
|
org.gradle.jvmargs=-Xmx1536m
|
||||||
|
|
||||||
|
# When configured, Gradle will run in incubating parallel mode.
|
||||||
|
# This option should only be used with decoupled projects. More details, visit
|
||||||
|
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
|
||||||
|
# org.gradle.parallel=true
|
1
android/settings.gradle
Normal file
|
@ -0,0 +1 @@
|
||||||
|
include ':app'
|
|
@ -1,82 +0,0 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
|
|
||||||
<!-- IMPORTANT: Do not manually manipulate this automatically generated file, changes will be gone after the next build! -->
|
|
||||||
|
|
||||||
<manifest package="${ANDROID_APK_PACKAGE}" xmlns:android="http://schemas.android.com/apk/res/android" android:versionName="${ANDROID_APK_VERSION_NAME}" android:versionCode="${ANDROID_APK_VERSION_CODE}" android:installLocation="auto">
|
|
||||||
<application
|
|
||||||
android:hardwareAccelerated="true"
|
|
||||||
android:name="org.qtproject.qt5.android.bindings.QtApplication"
|
|
||||||
android:label="@string/AppDisplayName"
|
|
||||||
android:icon="@drawable/icon"
|
|
||||||
android:debuggable="${ANDROID_APK_DEBUGGABLE}">
|
|
||||||
|
|
||||||
<!-- VR MODE -->
|
|
||||||
<meta-data android:name="com.samsung.android.vr.application.mode" android:value="vr_only"/>
|
|
||||||
|
|
||||||
<activity
|
|
||||||
android:configChanges="orientation|uiMode|screenLayout|screenSize|smallestScreenSize|locale|fontScale|keyboard|keyboardHidden|navigation"
|
|
||||||
android:name="${ANDROID_ACTIVITY_NAME}"
|
|
||||||
android:label="@string/AppDisplayName"
|
|
||||||
android:screenOrientation="landscape"
|
|
||||||
android:launchMode="singleTop"
|
|
||||||
${ANDROID_APK_THEME}>
|
|
||||||
|
|
||||||
<intent-filter>
|
|
||||||
<action android:name="android.intent.action.MAIN"/>
|
|
||||||
<category android:name="android.intent.category.LAUNCHER"/>
|
|
||||||
</intent-filter>
|
|
||||||
|
|
||||||
<meta-data android:name="android.app.lib_name" android:value="-- %%INSERT_APP_LIB_NAME%% --"/>
|
|
||||||
<meta-data android:name="android.app.qt_sources_resource_id" android:resource="@array/qt_sources"/>
|
|
||||||
<meta-data android:name="android.app.repository" android:value="default"/>
|
|
||||||
<meta-data android:name="android.app.qt_libs_resource_id" android:resource="@array/qt_libs"/>
|
|
||||||
<meta-data android:name="android.app.bundled_libs_resource_id" android:resource="@array/bundled_libs"/>
|
|
||||||
<!-- Deploy Qt libs as part of package -->
|
|
||||||
<meta-data android:name="android.app.bundle_local_qt_libs" android:value="-- %%BUNDLE_LOCAL_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"/>
|
|
||||||
<!-- Run with local libs -->
|
|
||||||
<meta-data android:name="android.app.use_local_qt_libs" android:value="-- %%USE_LOCAL_QT_LIBS%% --"/>
|
|
||||||
<meta-data android:name="android.app.libs_prefix" android:value="/data/local/tmp/qt/"/>
|
|
||||||
<meta-data android:name="android.app.load_local_libs" android:value="-- %%INSERT_LOCAL_LIBS%% --"/>
|
|
||||||
<meta-data android:name="android.app.load_local_jars" android:value="-- %%INSERT_LOCAL_JARS%% --"/>
|
|
||||||
<meta-data android:name="android.app.static_init_classes" android:value="-- %%INSERT_INIT_CLASSES%% --"/>
|
|
||||||
<!-- Messages maps -->
|
|
||||||
<meta-data android:value="@string/ministro_not_found_msg" android:name="android.app.ministro_not_found_msg"/>
|
|
||||||
<meta-data android:value="@string/ministro_needed_msg" android:name="android.app.ministro_needed_msg"/>
|
|
||||||
<meta-data android:value="@string/fatal_error_msg" android:name="android.app.fatal_error_msg"/>
|
|
||||||
<!-- Messages maps -->
|
|
||||||
|
|
||||||
<!-- Splash screen -->
|
|
||||||
<!-- <meta-data android:name="android.app.splash_screen_drawable" android:resource="@drawable/logo"/> -->
|
|
||||||
|
|
||||||
${ANDROID_EXTRA_ACTIVITY_XML}
|
|
||||||
</activity>
|
|
||||||
|
|
||||||
<activity
|
|
||||||
android:name="com.oculusvr.vrlib.PlatformActivity"
|
|
||||||
android:theme="@android:style/Theme.Black.NoTitleBar.Fullscreen"
|
|
||||||
android:launchMode="singleTask"
|
|
||||||
android:screenOrientation="landscape"
|
|
||||||
android:configChanges="screenSize|orientation|keyboardHidden|keyboard">
|
|
||||||
</activity>
|
|
||||||
|
|
||||||
${ANDROID_EXTRA_APPLICATION_XML}
|
|
||||||
</application>
|
|
||||||
<uses-sdk android:minSdkVersion="${ANDROID_API_LEVEL}" android:targetSdkVersion="${ANDROID_API_LEVEL}"/>
|
|
||||||
|
|
||||||
<!-- The following comment will be replaced upon deployment with default permissions based on the dependencies of the application.
|
|
||||||
Remove the comment if you do not require these default permissions. -->
|
|
||||||
<uses-permission android:name="android.permission.INTERNET" />
|
|
||||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
|
||||||
<uses-permission android:name="android.permission.RECORD_AUDIO" />
|
|
||||||
|
|
||||||
<!-- camera permission required for GEAR VR passthrough camera -->
|
|
||||||
<uses-permission android:name="android.permission.CAMERA" />
|
|
||||||
|
|
||||||
<!-- The following comment will be replaced upon deployment with default features based on the dependencies of the application.
|
|
||||||
Remove the comment if you do not require these default features. -->
|
|
||||||
|
|
||||||
<!-- Tell the system this app requires OpenGL ES 3.0. -->
|
|
||||||
<uses-feature android:glEsVersion="0x00030000" android:required="true" />
|
|
||||||
</manifest>
|
|
|
@ -1,159 +0,0 @@
|
||||||
#
|
|
||||||
# QtCreateAPK.cmake
|
|
||||||
#
|
|
||||||
# Created by Stephen Birarda on 11/18/14.
|
|
||||||
# Copyright 2013 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
|
|
||||||
#
|
|
||||||
|
|
||||||
#
|
|
||||||
# OPTIONS
|
|
||||||
# These options will modify how QtCreateAPK behaves. May be useful if somebody wants to fork.
|
|
||||||
# For High Fidelity purposes these should not need to be changed.
|
|
||||||
#
|
|
||||||
set(ANDROID_THIS_DIRECTORY ${CMAKE_CURRENT_LIST_DIR}) # Directory this CMake file is in
|
|
||||||
|
|
||||||
if (POLICY CMP0026)
|
|
||||||
cmake_policy(SET CMP0026 OLD)
|
|
||||||
endif ()
|
|
||||||
|
|
||||||
macro(qt_create_apk)
|
|
||||||
if(ANDROID_APK_FULLSCREEN)
|
|
||||||
set(ANDROID_APK_THEME "android:theme=\"@android:style/Theme.NoTitleBar.Fullscreen\"")
|
|
||||||
else()
|
|
||||||
set(ANDROID_APK_THEME "")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if (UPPER_CMAKE_BUILD_TYPE MATCHES RELEASE)
|
|
||||||
set(ANDROID_APK_DEBUGGABLE "false")
|
|
||||||
set(ANDROID_APK_RELEASE_LOCAL ${ANDROID_APK_RELEASE})
|
|
||||||
else ()
|
|
||||||
set(ANDROID_APK_DEBUGGABLE "true")
|
|
||||||
set(ANDROID_APK_RELEASE_LOCAL "0")
|
|
||||||
endif ()
|
|
||||||
|
|
||||||
# Create "AndroidManifest.xml"
|
|
||||||
configure_file("${ANDROID_THIS_DIRECTORY}/AndroidManifest.xml.in" "${ANDROID_APK_BUILD_DIR}/AndroidManifest.xml")
|
|
||||||
|
|
||||||
# create "strings.xml"
|
|
||||||
configure_file("${ANDROID_THIS_DIRECTORY}/strings.xml.in" "${ANDROID_APK_BUILD_DIR}/res/values/strings.xml")
|
|
||||||
|
|
||||||
# find androiddeployqt
|
|
||||||
find_program(ANDROID_DEPLOY_QT androiddeployqt HINTS "${QT_DIR}/bin")
|
|
||||||
|
|
||||||
# set the path to our app shared library
|
|
||||||
set(EXECUTABLE_DESTINATION_PATH "${ANDROID_APK_OUTPUT_DIR}/libs/${ANDROID_ABI}/lib${TARGET_NAME}.so")
|
|
||||||
|
|
||||||
# add our dependencies to the deployment file
|
|
||||||
get_property(_DEPENDENCIES TARGET ${TARGET_NAME} PROPERTY INTERFACE_LINK_LIBRARIES)
|
|
||||||
|
|
||||||
foreach(_IGNORE_COPY IN LISTS IGNORE_COPY_LIBS)
|
|
||||||
list(REMOVE_ITEM _DEPENDENCIES ${_IGNORE_COPY})
|
|
||||||
endforeach()
|
|
||||||
|
|
||||||
foreach(_DEP IN LISTS _DEPENDENCIES)
|
|
||||||
if (NOT TARGET ${_DEP})
|
|
||||||
list(APPEND _DEPS_LIST ${_DEP})
|
|
||||||
else ()
|
|
||||||
if(NOT _DEP MATCHES "Qt5::.*")
|
|
||||||
get_property(_DEP_LOCATION TARGET ${_DEP} PROPERTY "LOCATION_${CMAKE_BUILD_TYPE}")
|
|
||||||
|
|
||||||
# recurisvely add libraries which are dependencies of this target
|
|
||||||
get_property(_DEP_DEPENDENCIES TARGET ${_DEP} PROPERTY INTERFACE_LINK_LIBRARIES)
|
|
||||||
|
|
||||||
foreach(_SUB_DEP IN LISTS _DEP_DEPENDENCIES)
|
|
||||||
if (NOT TARGET ${_SUB_DEP} AND NOT _SUB_DEP MATCHES "Qt5::.*")
|
|
||||||
list(APPEND _DEPS_LIST ${_SUB_DEP})
|
|
||||||
endif()
|
|
||||||
endforeach()
|
|
||||||
|
|
||||||
list(APPEND _DEPS_LIST ${_DEP_LOCATION})
|
|
||||||
endif()
|
|
||||||
endif ()
|
|
||||||
endforeach()
|
|
||||||
|
|
||||||
list(REMOVE_DUPLICATES _DEPS_LIST)
|
|
||||||
|
|
||||||
# just copy static libs to apk libs folder - don't add to deps list
|
|
||||||
foreach(_LOCATED_DEP IN LISTS _DEPS_LIST)
|
|
||||||
if (_LOCATED_DEP MATCHES "\\.a$")
|
|
||||||
add_custom_command(
|
|
||||||
TARGET ${TARGET_NAME}
|
|
||||||
POST_BUILD
|
|
||||||
COMMAND ${CMAKE_COMMAND} -E copy ${_LOCATED_DEP} "${ANDROID_APK_OUTPUT_DIR}/libs/${ANDROID_ABI}"
|
|
||||||
)
|
|
||||||
list(REMOVE_ITEM _DEPS_LIST ${_LOCATED_DEP})
|
|
||||||
endif ()
|
|
||||||
endforeach()
|
|
||||||
|
|
||||||
string(REPLACE ";" "," _DEPS "${_DEPS_LIST}")
|
|
||||||
|
|
||||||
configure_file("${ANDROID_THIS_DIRECTORY}/deployment-file.json.in" "${TARGET_NAME}-deployment.json")
|
|
||||||
|
|
||||||
# copy the res folder from the target to the apk build dir
|
|
||||||
add_custom_target(
|
|
||||||
${TARGET_NAME}-copy-res
|
|
||||||
COMMAND ${CMAKE_COMMAND} -E copy_directory "${CMAKE_CURRENT_SOURCE_DIR}/res" "${ANDROID_APK_BUILD_DIR}/res"
|
|
||||||
)
|
|
||||||
|
|
||||||
# copy the assets folder from the target to the apk build dir
|
|
||||||
add_custom_target(
|
|
||||||
${TARGET_NAME}-copy-assets
|
|
||||||
COMMAND ${CMAKE_COMMAND} -E copy_directory "${CMAKE_CURRENT_SOURCE_DIR}/assets" "${ANDROID_APK_BUILD_DIR}/assets"
|
|
||||||
)
|
|
||||||
|
|
||||||
# copy the java folder from src to the apk build dir
|
|
||||||
add_custom_target(
|
|
||||||
${TARGET_NAME}-copy-java
|
|
||||||
COMMAND ${CMAKE_COMMAND} -E copy_directory "${CMAKE_CURRENT_SOURCE_DIR}/src/java" "${ANDROID_APK_BUILD_DIR}/src"
|
|
||||||
)
|
|
||||||
|
|
||||||
# copy the libs folder from src to the apk build dir
|
|
||||||
add_custom_target(
|
|
||||||
${TARGET_NAME}-copy-libs
|
|
||||||
COMMAND ${CMAKE_COMMAND} -E copy_directory "${CMAKE_CURRENT_SOURCE_DIR}/libs" "${ANDROID_APK_BUILD_DIR}/libs"
|
|
||||||
)
|
|
||||||
|
|
||||||
# handle setup for ndk-gdb
|
|
||||||
add_custom_target(${TARGET_NAME}-gdb DEPENDS ${TARGET_NAME})
|
|
||||||
|
|
||||||
if (ANDROID_APK_DEBUGGABLE)
|
|
||||||
get_property(TARGET_LOCATION TARGET ${TARGET_NAME} PROPERTY LOCATION)
|
|
||||||
|
|
||||||
set(GDB_SOLIB_PATH ${ANDROID_APK_BUILD_DIR}/obj/local/${ANDROID_NDK_ABI_NAME}/)
|
|
||||||
|
|
||||||
# generate essential Android Makefiles
|
|
||||||
file(WRITE ${ANDROID_APK_BUILD_DIR}/jni/Android.mk "APP_ABI := ${ANDROID_NDK_ABI_NAME}\n")
|
|
||||||
file(WRITE ${ANDROID_APK_BUILD_DIR}/jni/Application.mk "APP_ABI := ${ANDROID_NDK_ABI_NAME}\n")
|
|
||||||
|
|
||||||
# create gdb.setup
|
|
||||||
get_directory_property(PROJECT_INCLUDES DIRECTORY ${PROJECT_SOURCE_DIR} INCLUDE_DIRECTORIES)
|
|
||||||
string(REGEX REPLACE ";" " " PROJECT_INCLUDES "${PROJECT_INCLUDES}")
|
|
||||||
file(WRITE ${ANDROID_APK_BUILD_DIR}/libs/${ANDROID_NDK_ABI_NAME}/gdb.setup "set solib-search-path ${GDB_SOLIB_PATH}\n")
|
|
||||||
file(APPEND ${ANDROID_APK_BUILD_DIR}/libs/${ANDROID_NDK_ABI_NAME}/gdb.setup "directory ${PROJECT_INCLUDES}\n")
|
|
||||||
|
|
||||||
# copy lib to obj
|
|
||||||
add_custom_command(TARGET ${TARGET_NAME}-gdb PRE_BUILD COMMAND ${CMAKE_COMMAND} -E make_directory ${GDB_SOLIB_PATH})
|
|
||||||
add_custom_command(TARGET ${TARGET_NAME}-gdb PRE_BUILD COMMAND cp ${TARGET_LOCATION} ${GDB_SOLIB_PATH})
|
|
||||||
|
|
||||||
# strip symbols
|
|
||||||
add_custom_command(TARGET ${TARGET_NAME}-gdb PRE_BUILD COMMAND ${CMAKE_STRIP} ${TARGET_LOCATION})
|
|
||||||
endif ()
|
|
||||||
|
|
||||||
# use androiddeployqt to create the apk
|
|
||||||
add_custom_target(${TARGET_NAME}-apk
|
|
||||||
COMMAND ${ANDROID_DEPLOY_QT} --input "${TARGET_NAME}-deployment.json" --output "${ANDROID_APK_OUTPUT_DIR}" --android-platform android-${ANDROID_API_LEVEL} ${ANDROID_DEPLOY_QT_INSTALL} --verbose --deployment bundled "\\$(ARGS)"
|
|
||||||
DEPENDS ${TARGET_NAME} ${TARGET_NAME}-copy-res ${TARGET_NAME}-copy-assets ${TARGET_NAME}-copy-java ${TARGET_NAME}-copy-libs ${TARGET_NAME}-gdb
|
|
||||||
)
|
|
||||||
|
|
||||||
# rename the APK if the caller asked us to
|
|
||||||
if (ANDROID_APK_CUSTOM_NAME)
|
|
||||||
add_custom_command(
|
|
||||||
TARGET ${TARGET_NAME}-apk
|
|
||||||
POST_BUILD
|
|
||||||
COMMAND ${CMAKE_COMMAND} -E rename "${ANDROID_APK_OUTPUT_DIR}/bin/QtApp-debug.apk" "${ANDROID_APK_OUTPUT_DIR}/bin/${ANDROID_APK_CUSTOM_NAME}"
|
|
||||||
)
|
|
||||||
endif ()
|
|
||||||
endmacro()
|
|
|
@ -1,13 +0,0 @@
|
||||||
{
|
|
||||||
"qt": "@QT_DIR@",
|
|
||||||
"sdk": "@ANDROID_SDK_ROOT@",
|
|
||||||
"ndk": "@ANDROID_NDK@",
|
|
||||||
"toolchain-prefix": "@ANDROID_TOOLCHAIN_MACHINE_NAME@",
|
|
||||||
"tool-prefix": "@ANDROID_TOOLCHAIN_MACHINE_NAME@",
|
|
||||||
"toolchain-version": "@ANDROID_COMPILER_VERSION@",
|
|
||||||
"ndk-host": "@ANDROID_NDK_HOST_SYSTEM_NAME@",
|
|
||||||
"target-architecture": "@ANDROID_ABI@",
|
|
||||||
"application-binary": "@EXECUTABLE_DESTINATION_PATH@",
|
|
||||||
"android-extra-libs": "@_DEPS@",
|
|
||||||
"android-package-source-directory": "@ANDROID_APK_BUILD_DIR@"
|
|
||||||
}
|
|
|
@ -1,11 +0,0 @@
|
||||||
<?xml version='1.0' encoding='utf-8'?>
|
|
||||||
|
|
||||||
<!-- IMPORTANT: Do not manually manipulate this automatically generated file, changes will be gone after the next build! -->
|
|
||||||
|
|
||||||
<resources>
|
|
||||||
<string name="AppDisplayName">${ANDROID_APP_DISPLAY_NAME}</string>
|
|
||||||
|
|
||||||
<string name="ministro_not_found_msg">Can\'t find Ministro service.\nThe application can\'t start.</string>
|
|
||||||
<string name="ministro_needed_msg">This application requires Ministro service. Would you like to install it?</string>
|
|
||||||
<string name="fatal_error_msg">Your application encountered a fatal error and cannot continue.</string>
|
|
||||||
</resources>
|
|
2
cmake/externals/glm/CMakeLists.txt
vendored
|
@ -6,7 +6,7 @@ ExternalProject_Add(
|
||||||
URL https://hifi-public.s3.amazonaws.com/dependencies/glm-0.9.8.zip
|
URL https://hifi-public.s3.amazonaws.com/dependencies/glm-0.9.8.zip
|
||||||
URL_MD5 579ac77a3110befa3244d68c0ceb7281
|
URL_MD5 579ac77a3110befa3244d68c0ceb7281
|
||||||
BINARY_DIR ${EXTERNAL_PROJECT_PREFIX}/build
|
BINARY_DIR ${EXTERNAL_PROJECT_PREFIX}/build
|
||||||
CMAKE_ARGS -DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR>
|
CMAKE_ARGS -DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR> ${EXTERNAL_ARGS}
|
||||||
LOG_DOWNLOAD 1
|
LOG_DOWNLOAD 1
|
||||||
LOG_CONFIGURE 1
|
LOG_CONFIGURE 1
|
||||||
LOG_BUILD 1
|
LOG_BUILD 1
|
||||||
|
|
4
cmake/externals/tbb/CMakeLists.txt
vendored
|
@ -8,9 +8,6 @@ if (WIN32)
|
||||||
elseif (APPLE)
|
elseif (APPLE)
|
||||||
set(DOWNLOAD_URL http://s3.amazonaws.com/hifi-public/dependencies/tbb2017_20170604oss_mac_slim.tar.gz)
|
set(DOWNLOAD_URL http://s3.amazonaws.com/hifi-public/dependencies/tbb2017_20170604oss_mac_slim.tar.gz)
|
||||||
set(DOWNLOAD_MD5 62bde626b396f8e1a85c6a8ded1d8105)
|
set(DOWNLOAD_MD5 62bde626b396f8e1a85c6a8ded1d8105)
|
||||||
elseif (ANDROID)
|
|
||||||
set(DOWNLOAD_URL http://hifi-public.s3.amazonaws.com/dependencies/tbb2017_20170604oss_and_slim.tar.gz)
|
|
||||||
set(DOWNLOAD_MD5 04d50b64e1d81245a1be5f75f34d64c7)
|
|
||||||
else ()
|
else ()
|
||||||
set(DOWNLOAD_URL http://hifi-public.s3.amazonaws.com/dependencies/tbb2017_20170604oss_lin_slim.tar.gz)
|
set(DOWNLOAD_URL http://hifi-public.s3.amazonaws.com/dependencies/tbb2017_20170604oss_lin_slim.tar.gz)
|
||||||
set(DOWNLOAD_MD5 2a5c721f40fa3503ffc12c18dd00011c)
|
set(DOWNLOAD_MD5 2a5c721f40fa3503ffc12c18dd00011c)
|
||||||
|
@ -107,3 +104,4 @@ endif ()
|
||||||
if (DEFINED ${EXTERNAL_NAME_UPPER}_LIBRARY_RELEASE)
|
if (DEFINED ${EXTERNAL_NAME_UPPER}_LIBRARY_RELEASE)
|
||||||
set(${EXTERNAL_NAME_UPPER}_INCLUDE_DIRS ${SOURCE_DIR}/include CACHE TYPE "List of tbb include directories")
|
set(${EXTERNAL_NAME_UPPER}_INCLUDE_DIRS ${SOURCE_DIR}/include CACHE TYPE "List of tbb include directories")
|
||||||
endif ()
|
endif ()
|
||||||
|
|
||||||
|
|
|
@ -34,10 +34,23 @@ file(GLOB HIFI_CUSTOM_MACROS "cmake/macros/*.cmake")
|
||||||
foreach(CUSTOM_MACRO ${HIFI_CUSTOM_MACROS})
|
foreach(CUSTOM_MACRO ${HIFI_CUSTOM_MACROS})
|
||||||
include(${CUSTOM_MACRO})
|
include(${CUSTOM_MACRO})
|
||||||
endforeach()
|
endforeach()
|
||||||
|
unset(HIFI_CUSTOM_MACROS)
|
||||||
|
|
||||||
if (ANDROID)
|
if (ANDROID)
|
||||||
file(GLOB ANDROID_CUSTOM_MACROS "cmake/android/*.cmake")
|
set(BUILD_SHARED_LIBS ON)
|
||||||
foreach(CUSTOM_MACRO ${ANDROID_CUSTOM_MACROS})
|
set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE BOTH)
|
||||||
include(${CUSTOM_MACRO})
|
|
||||||
endforeach()
|
string(REGEX REPLACE "\\\\" "/" ANDROID_NDK ${ANDROID_NDK})
|
||||||
|
string(REGEX REPLACE "\\\\" "/" CMAKE_TOOLCHAIN_FILE ${CMAKE_TOOLCHAIN_FILE})
|
||||||
|
string(REGEX REPLACE "\\\\" "/" ANDROID_TOOLCHAIN ${ANDROID_TOOLCHAIN})
|
||||||
|
string(REGEX REPLACE "\\\\" "/" CMAKE_MAKE_PROGRAM ${CMAKE_MAKE_PROGRAM})
|
||||||
|
list(APPEND EXTERNAL_ARGS -DANDROID_ABI=${ANDROID_ABI})
|
||||||
|
list(APPEND EXTERNAL_ARGS -DANDROID_NDK=${ANDROID_NDK})
|
||||||
|
list(APPEND EXTERNAL_ARGS -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE})
|
||||||
|
list(APPEND EXTERNAL_ARGS -DCMAKE_MAKE_PROGRAM=${CMAKE_MAKE_PROGRAM})
|
||||||
|
list(APPEND EXTERNAL_ARGS -DCMAKE_TOOLCHAIN_FILE=${CMAKE_TOOLCHAIN_FILE})
|
||||||
|
list(APPEND EXTERNAL_ARGS -DHIFI_ANDROID=${HIFI_ANDROID})
|
||||||
|
list(APPEND EXTERNAL_ARGS -DANDROID_PLATFORM=${ANDROID_PLATFORM})
|
||||||
|
list(APPEND EXTERNAL_ARGS -DANDROID_TOOLCHAIN=${ANDROID_TOOLCHAIN})
|
||||||
|
list(APPEND EXTERNAL_ARGS -DANDROID_STL=${ANDROID_STL})
|
||||||
endif ()
|
endif ()
|
||||||
|
|
|
@ -62,7 +62,9 @@ function(AUTOSCRIBE_SHADER SHADER_FILE)
|
||||||
# since it's unrunnable by the cross-compiling build machine
|
# since it's unrunnable by the cross-compiling build machine
|
||||||
|
|
||||||
# so, we require the compiling user to point us at a compiled executable version for their native toolchain
|
# so, we require the compiling user to point us at a compiled executable version for their native toolchain
|
||||||
find_program(NATIVE_SCRIBE scribe PATHS ${SCRIBE_PATH} ENV SCRIBE_PATH)
|
if (NOT NATIVE_SCRIBE)
|
||||||
|
find_program(NATIVE_SCRIBE scribe PATHS ${SCRIBE_PATH} ENV SCRIBE_PATH)
|
||||||
|
endif()
|
||||||
|
|
||||||
if (NOT NATIVE_SCRIBE)
|
if (NOT NATIVE_SCRIBE)
|
||||||
message(FATAL_ERROR "The High Fidelity scribe tool is required for shader pre-processing. \
|
message(FATAL_ERROR "The High Fidelity scribe tool is required for shader pre-processing. \
|
||||||
|
|
|
@ -162,5 +162,6 @@ macro(SET_PACKAGING_PARAMETERS)
|
||||||
# create a header file our targets can use to find out the application version
|
# create a header file our targets can use to find out the application version
|
||||||
file(MAKE_DIRECTORY "${CMAKE_BINARY_DIR}/includes")
|
file(MAKE_DIRECTORY "${CMAKE_BINARY_DIR}/includes")
|
||||||
configure_file("${HF_CMAKE_DIR}/templates/BuildInfo.h.in" "${CMAKE_BINARY_DIR}/includes/BuildInfo.h")
|
configure_file("${HF_CMAKE_DIR}/templates/BuildInfo.h.in" "${CMAKE_BINARY_DIR}/includes/BuildInfo.h")
|
||||||
|
include_directories("${CMAKE_BINARY_DIR}/includes")
|
||||||
|
|
||||||
endmacro(SET_PACKAGING_PARAMETERS)
|
endmacro(SET_PACKAGING_PARAMETERS)
|
||||||
|
|
|
@ -12,7 +12,7 @@ macro(SETUP_HIFI_LIBRARY)
|
||||||
project(${TARGET_NAME})
|
project(${TARGET_NAME})
|
||||||
|
|
||||||
# grab the implementation and header files
|
# grab the implementation and header files
|
||||||
file(GLOB_RECURSE LIB_SRCS "src/*.h" "src/*.cpp" "src/*.c")
|
file(GLOB_RECURSE LIB_SRCS "src/*.h" "src/*.cpp" "src/*.c" "src/*.qrc")
|
||||||
list(APPEND ${TARGET_NAME}_SRCS ${LIB_SRCS})
|
list(APPEND ${TARGET_NAME}_SRCS ${LIB_SRCS})
|
||||||
|
|
||||||
# add compiler flags to AVX source files
|
# add compiler flags to AVX source files
|
||||||
|
@ -65,7 +65,7 @@ macro(SETUP_HIFI_LIBRARY)
|
||||||
list(APPEND ${TARGET_NAME}_DEPENDENCY_QT_MODULES Core)
|
list(APPEND ${TARGET_NAME}_DEPENDENCY_QT_MODULES Core)
|
||||||
|
|
||||||
# find these Qt modules and link them to our own target
|
# find these Qt modules and link them to our own target
|
||||||
find_package(Qt5 COMPONENTS ${${TARGET_NAME}_DEPENDENCY_QT_MODULES} REQUIRED)
|
find_package(Qt5 COMPONENTS ${${TARGET_NAME}_DEPENDENCY_QT_MODULES} REQUIRED CMAKE_FIND_ROOT_PATH_BOTH)
|
||||||
|
|
||||||
foreach(QT_MODULE ${${TARGET_NAME}_DEPENDENCY_QT_MODULES})
|
foreach(QT_MODULE ${${TARGET_NAME}_DEPENDENCY_QT_MODULES})
|
||||||
target_link_libraries(${TARGET_NAME} Qt5::${QT_MODULE})
|
target_link_libraries(${TARGET_NAME} Qt5::${QT_MODULE})
|
||||||
|
|
|
@ -28,7 +28,7 @@ function(calculate_default_qt_dir _RESULT_NAME)
|
||||||
set(QT_DEFAULT_ARCH "gcc_64")
|
set(QT_DEFAULT_ARCH "gcc_64")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if (WIN32)
|
if (WIN32 OR (ANDROID AND ("${CMAKE_HOST_SYSTEM_NAME}" STREQUAL "Windows")))
|
||||||
set(QT_DEFAULT_ROOT "c:/Qt")
|
set(QT_DEFAULT_ROOT "c:/Qt")
|
||||||
else()
|
else()
|
||||||
set(QT_DEFAULT_ROOT "$ENV{HOME}/Qt")
|
set(QT_DEFAULT_ROOT "$ENV{HOME}/Qt")
|
||||||
|
|
|
@ -6,9 +6,11 @@
|
||||||
# See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
# See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
#
|
#
|
||||||
macro(TARGET_GLEW)
|
macro(TARGET_GLEW)
|
||||||
add_dependency_external_projects(glew)
|
if (NOT ANDROID)
|
||||||
find_package(GLEW REQUIRED)
|
add_definitions(-DGLEW_STATIC)
|
||||||
add_definitions(-DGLEW_STATIC)
|
add_dependency_external_projects(glew)
|
||||||
target_include_directories(${TARGET_NAME} PUBLIC ${GLEW_INCLUDE_DIRS})
|
find_package(GLEW REQUIRED)
|
||||||
target_link_libraries(${TARGET_NAME} ${GLEW_LIBRARY})
|
target_include_directories(${TARGET_NAME} PUBLIC ${GLEW_INCLUDE_DIRS})
|
||||||
|
target_link_libraries(${TARGET_NAME} ${GLEW_LIBRARY})
|
||||||
|
endif()
|
||||||
endmacro()
|
endmacro()
|
|
@ -6,15 +6,13 @@
|
||||||
# See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
# See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
#
|
#
|
||||||
macro(TARGET_OPENGL)
|
macro(TARGET_OPENGL)
|
||||||
add_definitions(-DGLEW_STATIC)
|
|
||||||
if (APPLE)
|
if (APPLE)
|
||||||
# link in required OS X frameworks and include the right GL headers
|
# link in required OS X frameworks and include the right GL headers
|
||||||
find_library(OpenGL OpenGL)
|
find_library(OpenGL OpenGL)
|
||||||
target_link_libraries(${TARGET_NAME} ${OpenGL})
|
target_link_libraries(${TARGET_NAME} ${OpenGL})
|
||||||
elseif(ANDROID)
|
elseif(ANDROID)
|
||||||
target_link_libraries(${TARGET_NAME} "-lGLESv3" "-lEGL")
|
target_link_libraries(${TARGET_NAME} GLESv3 EGL)
|
||||||
else()
|
else()
|
||||||
target_nsight()
|
|
||||||
find_package(OpenGL REQUIRED)
|
find_package(OpenGL REQUIRED)
|
||||||
if (${OPENGL_INCLUDE_DIR})
|
if (${OPENGL_INCLUDE_DIR})
|
||||||
include_directories(SYSTEM "${OPENGL_INCLUDE_DIR}")
|
include_directories(SYSTEM "${OPENGL_INCLUDE_DIR}")
|
||||||
|
@ -22,4 +20,6 @@ macro(TARGET_OPENGL)
|
||||||
target_link_libraries(${TARGET_NAME} "${OPENGL_LIBRARY}")
|
target_link_libraries(${TARGET_NAME} "${OPENGL_LIBRARY}")
|
||||||
target_include_directories(${TARGET_NAME} PUBLIC ${OPENGL_INCLUDE_DIR})
|
target_include_directories(${TARGET_NAME} PUBLIC ${OPENGL_INCLUDE_DIR})
|
||||||
endif()
|
endif()
|
||||||
|
target_nsight()
|
||||||
|
target_glew()
|
||||||
endmacro()
|
endmacro()
|
||||||
|
|
32
cmake/macros/TargetOpenSSL.cmake
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
#
|
||||||
|
# Copyright 2015 High Fidelity, Inc.
|
||||||
|
# Created by Bradley Austin Davis on 2015/10/10
|
||||||
|
#
|
||||||
|
# Distributed under the Apache License, Version 2.0.
|
||||||
|
# See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
|
#
|
||||||
|
macro(TARGET_OPENSSL)
|
||||||
|
|
||||||
|
if (ANDROID)
|
||||||
|
|
||||||
|
# FIXME use a distributable binary
|
||||||
|
set(OPENSSL_INSTALL_DIR C:/Android/openssl)
|
||||||
|
set(OPENSSL_INCLUDE_DIR "${OPENSSL_INSTALL_DIR}/include" CACHE TYPE INTERNAL)
|
||||||
|
set(OPENSSL_LIBRARIES "${OPENSSL_INSTALL_DIR}/lib/libcrypto.a;${OPENSSL_INSTALL_DIR}/lib/libssl.a" CACHE TYPE INTERNAL)
|
||||||
|
|
||||||
|
else()
|
||||||
|
|
||||||
|
find_package(OpenSSL REQUIRED)
|
||||||
|
|
||||||
|
if (APPLE AND ${OPENSSL_INCLUDE_DIR} STREQUAL "/usr/include")
|
||||||
|
# this is a user on OS X using system OpenSSL, which is going to throw warnings since they're deprecating for their common crypto
|
||||||
|
message(WARNING "The found version of OpenSSL is the OS X system version. This will produce deprecation warnings."
|
||||||
|
"\nWe recommend you install a newer version (at least 1.0.1h) in a different directory and set OPENSSL_ROOT_DIR in your env so Cmake can find it.")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
endif()
|
||||||
|
|
||||||
|
include_directories(SYSTEM "${OPENSSL_INCLUDE_DIR}")
|
||||||
|
target_link_libraries(${TARGET_NAME} ${OPENSSL_LIBRARIES})
|
||||||
|
|
||||||
|
endmacro()
|
24
cmake/macros/TargetTBB.cmake
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
#
|
||||||
|
# Copyright 2015 High Fidelity, Inc.
|
||||||
|
# Created by Bradley Austin Davis on 2015/10/10
|
||||||
|
#
|
||||||
|
# Distributed under the Apache License, Version 2.0.
|
||||||
|
# See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
|
#
|
||||||
|
macro(TARGET_TBB)
|
||||||
|
|
||||||
|
if (ANDROID)
|
||||||
|
set(TBB_INSTALL_DIR C:/tbb-2018/built)
|
||||||
|
set(TBB_LIBRARY ${HIFI_ANDROID_PRECOMPILED}/libtbb.so CACHE FILEPATH "TBB library location")
|
||||||
|
set(TBB_MALLOC_LIBRARY ${HIFI_ANDROID_PRECOMPILED}/libtbbmalloc.so CACHE FILEPATH "TBB malloc library location")
|
||||||
|
set(TBB_INCLUDE_DIRS ${TBB_INSTALL_DIR}/include CACHE TYPE "List of tbb include directories" CACHE FILEPATH "TBB includes location")
|
||||||
|
set(TBB_LIBRARIES ${TBB_LIBRARY} ${TBB_MALLOC_LIBRARY})
|
||||||
|
else()
|
||||||
|
add_dependency_external_projects(tbb)
|
||||||
|
find_package(TBB REQUIRED)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
target_link_libraries(${TARGET_NAME} ${TBB_LIBRARIES})
|
||||||
|
target_include_directories(${TARGET_NAME} SYSTEM PUBLIC ${TBB_INCLUDE_DIRS})
|
||||||
|
|
||||||
|
endmacro()
|
|
@ -171,8 +171,6 @@ else ()
|
||||||
add_executable(${TARGET_NAME} ${INTERFACE_SRCS} ${QM})
|
add_executable(${TARGET_NAME} ${INTERFACE_SRCS} ${QM})
|
||||||
endif ()
|
endif ()
|
||||||
|
|
||||||
target_include_directories(${TARGET_NAME} PRIVATE "${CMAKE_BINARY_DIR}/includes")
|
|
||||||
|
|
||||||
if (WIN32)
|
if (WIN32)
|
||||||
# These are external plugins, but we need to do the 'add dependency' here so that their
|
# These are external plugins, but we need to do the 'add dependency' here so that their
|
||||||
# binary directories get added to the fixup path
|
# binary directories get added to the fixup path
|
||||||
|
@ -214,10 +212,6 @@ target_include_directories(${TARGET_NAME} PRIVATE "${CMAKE_BINARY_DIR}/libraries
|
||||||
target_bullet()
|
target_bullet()
|
||||||
target_opengl()
|
target_opengl()
|
||||||
|
|
||||||
if (NOT ANDROID)
|
|
||||||
target_glew()
|
|
||||||
endif ()
|
|
||||||
|
|
||||||
# perform standard include and linking for found externals
|
# perform standard include and linking for found externals
|
||||||
foreach(EXTERNAL ${OPTIONAL_EXTERNALS})
|
foreach(EXTERNAL ${OPTIONAL_EXTERNALS})
|
||||||
|
|
||||||
|
|
|
@ -116,6 +116,13 @@ Item {
|
||||||
wrapMode: Text.WordWrap
|
wrapMode: Text.WordWrap
|
||||||
readOnly: false // we need to leave this property read-only to allow control to accept QKeyEvent
|
readOnly: false // we need to leave this property read-only to allow control to accept QKeyEvent
|
||||||
selectByMouse: false
|
selectByMouse: false
|
||||||
|
|
||||||
|
Keys.onPressed: {
|
||||||
|
if (event.key == Qt.Key_Return) {
|
||||||
|
mirrorText.text = "";
|
||||||
|
event.accepted = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
MouseArea { // ... and we need this mouse area to prevent mirrorText from getting mouse events to ensure it will never get focus
|
MouseArea { // ... and we need this mouse area to prevent mirrorText from getting mouse events to ensure it will never get focus
|
||||||
|
|
|
@ -21,9 +21,9 @@ Item {
|
||||||
property alias text: label.text
|
property alias text: label.text
|
||||||
property var source
|
property var source
|
||||||
|
|
||||||
implicitHeight: source.visible ? 2 * label.implicitHeight : 0
|
implicitHeight: source !== null ? source.visible ? 2 * label.implicitHeight : 0 : 0
|
||||||
implicitWidth: 2 * hifi.dimensions.menuPadding.x + check.width + label.width + tail.width
|
implicitWidth: 2 * hifi.dimensions.menuPadding.x + check.width + label.width + tail.width
|
||||||
visible: source.visible
|
visible: source !== null ? source.visible : false
|
||||||
width: parent.width
|
width: parent.width
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
|
@ -42,7 +42,9 @@ Item {
|
||||||
id: checkbox
|
id: checkbox
|
||||||
// FIXME: Should use radio buttons if source.exclusiveGroup.
|
// FIXME: Should use radio buttons if source.exclusiveGroup.
|
||||||
width: 20
|
width: 20
|
||||||
visible: source.visible && source.type === 1 && source.checkable && !source.exclusiveGroup
|
visible: source !== null ?
|
||||||
|
source.visible && source.type === 1 && source.checkable && !source.exclusiveGroup :
|
||||||
|
false
|
||||||
checked: setChecked()
|
checked: setChecked()
|
||||||
function setChecked() {
|
function setChecked() {
|
||||||
if (!source || source.type !== 1 || !source.checkable) {
|
if (!source || source.type !== 1 || !source.checkable) {
|
||||||
|
@ -58,7 +60,9 @@ Item {
|
||||||
id: radiobutton
|
id: radiobutton
|
||||||
// FIXME: Should use radio buttons if source.exclusiveGroup.
|
// FIXME: Should use radio buttons if source.exclusiveGroup.
|
||||||
width: 20
|
width: 20
|
||||||
visible: source.visible && source.type === 1 && source.checkable && source.exclusiveGroup
|
visible: source !== null ?
|
||||||
|
source.visible && source.type === 1 && source.checkable && source.exclusiveGroup :
|
||||||
|
false
|
||||||
checked: setChecked()
|
checked: setChecked()
|
||||||
function setChecked() {
|
function setChecked() {
|
||||||
if (!source || source.type !== 1 || !source.checkable) {
|
if (!source || source.type !== 1 || !source.checkable) {
|
||||||
|
@ -80,9 +84,13 @@ Item {
|
||||||
anchors.left: check.right
|
anchors.left: check.right
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
verticalAlignment: Text.AlignVCenter
|
verticalAlignment: Text.AlignVCenter
|
||||||
color: source.enabled ? hifi.colors.baseGrayShadow : hifi.colors.baseGrayShadow50
|
color: source !== null ?
|
||||||
enabled: source.visible && (source.type !== 0 ? source.enabled : false)
|
source.enabled ? hifi.colors.baseGrayShadow :
|
||||||
visible: source.visible
|
hifi.colors.baseGrayShadow50 :
|
||||||
|
"transparent"
|
||||||
|
|
||||||
|
enabled: source !== null ? source.visible && (source.type !== 0 ? source.enabled : false) : false
|
||||||
|
visible: source !== null ? source.visible : false
|
||||||
wrapMode: Text.WordWrap
|
wrapMode: Text.WordWrap
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -93,7 +101,7 @@ Item {
|
||||||
leftMargin: hifi.dimensions.menuPadding.x + check.width
|
leftMargin: hifi.dimensions.menuPadding.x + check.width
|
||||||
rightMargin: hifi.dimensions.menuPadding.x + tail.width
|
rightMargin: hifi.dimensions.menuPadding.x + tail.width
|
||||||
}
|
}
|
||||||
visible: source.type === MenuItemType.Separator
|
visible: source !== null ? source.type === MenuItemType.Separator : false
|
||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
anchors {
|
anchors {
|
||||||
|
@ -117,23 +125,23 @@ Item {
|
||||||
|
|
||||||
RalewayLight {
|
RalewayLight {
|
||||||
id: shortcut
|
id: shortcut
|
||||||
text: source.shortcut ? source.shortcut : ""
|
text: source !== null ? source.shortcut ? source.shortcut : "" : ""
|
||||||
size: hifi.fontSizes.shortcutText
|
size: hifi.fontSizes.shortcutText
|
||||||
color: hifi.colors.baseGrayShadow
|
color: hifi.colors.baseGrayShadow
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
anchors.rightMargin: 15
|
anchors.rightMargin: 15
|
||||||
visible: source.visible && text != ""
|
visible: source !== null ? source.visible && text != "" : false
|
||||||
}
|
}
|
||||||
|
|
||||||
HiFiGlyphs {
|
HiFiGlyphs {
|
||||||
text: hifi.glyphs.disclosureExpand
|
text: hifi.glyphs.disclosureExpand
|
||||||
color: source.enabled ? hifi.colors.baseGrayShadow : hifi.colors.baseGrayShadow25
|
color: source !== null ? source.enabled ? hifi.colors.baseGrayShadow : hifi.colors.baseGrayShadow25 : "transparent"
|
||||||
size: 70
|
size: 70
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
horizontalAlignment: Text.AlignRight
|
horizontalAlignment: Text.AlignRight
|
||||||
visible: source.visible && (source.type === 2)
|
visible: source !== null ? source.visible && (source.type === 2) : false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -70,7 +70,6 @@ Item {
|
||||||
|
|
||||||
for (var i = 0; i < items.length; ++i) {
|
for (var i = 0; i < items.length; ++i) {
|
||||||
var item = items[i];
|
var item = items[i];
|
||||||
if (!item.visible) continue;
|
|
||||||
switch (item.type) {
|
switch (item.type) {
|
||||||
case MenuItemType.Menu:
|
case MenuItemType.Menu:
|
||||||
result.append({"name": item.title, "item": item})
|
result.append({"name": item.title, "item": item})
|
||||||
|
@ -216,5 +215,4 @@ Item {
|
||||||
function nextItem() { d.topMenu.nextItem(); }
|
function nextItem() { d.topMenu.nextItem(); }
|
||||||
function selectCurrentItem() { d.topMenu.selectCurrentItem(); }
|
function selectCurrentItem() { d.topMenu.selectCurrentItem(); }
|
||||||
function previousPage() { d.topMenu.previousPage(); }
|
function previousPage() { d.topMenu.previousPage(); }
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,8 +9,6 @@
|
||||||
//
|
//
|
||||||
|
|
||||||
import QtQuick 2.5
|
import QtQuick 2.5
|
||||||
import QtQuick.Controls 1.4
|
|
||||||
import QtQuick.Controls.Styles 1.4
|
|
||||||
|
|
||||||
import "../../styles-uit"
|
import "../../styles-uit"
|
||||||
import "."
|
import "."
|
||||||
|
@ -36,7 +34,6 @@ FocusScope {
|
||||||
//color: isSubMenu ? hifi.colors.faintGray : hifi.colors.faintGray80
|
//color: isSubMenu ? hifi.colors.faintGray : hifi.colors.faintGray80
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
ListView {
|
ListView {
|
||||||
id: listView
|
id: listView
|
||||||
x: 0
|
x: 0
|
||||||
|
@ -68,8 +65,8 @@ FocusScope {
|
||||||
delegate: TabletMenuItem {
|
delegate: TabletMenuItem {
|
||||||
text: name
|
text: name
|
||||||
source: item
|
source: item
|
||||||
onImplicitHeightChanged: listView.recalcSize()
|
onImplicitHeightChanged: listView !== null ? listView.recalcSize() : 0
|
||||||
onImplicitWidthChanged: listView.recalcSize()
|
onImplicitWidthChanged: listView !== null ? listView.recalcSize() : 0
|
||||||
|
|
||||||
MouseArea {
|
MouseArea {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
|
@ -124,8 +121,6 @@ FocusScope {
|
||||||
function nextItem() { listView.currentIndex = (listView.currentIndex + listView.count + 1) % listView.count; }
|
function nextItem() { listView.currentIndex = (listView.currentIndex + listView.count + 1) % listView.count; }
|
||||||
function selectCurrentItem() { if (listView.currentIndex != -1) root.selected(currentItem.source); }
|
function selectCurrentItem() { if (listView.currentIndex != -1) root.selected(currentItem.source); }
|
||||||
function previousPage() { root.parent.pop(); }
|
function previousPage() { root.parent.pop(); }
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -980,7 +980,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
|
||||||
|
|
||||||
connect(scriptEngines, &ScriptEngines::scriptLoadError,
|
connect(scriptEngines, &ScriptEngines::scriptLoadError,
|
||||||
scriptEngines, [](const QString& filename, const QString& error){
|
scriptEngines, [](const QString& filename, const QString& error){
|
||||||
OffscreenUi::warning(nullptr, "Error Loading Script", filename + " failed to load.");
|
OffscreenUi::asyncWarning(nullptr, "Error Loading Script", filename + " failed to load.");
|
||||||
}, Qt::QueuedConnection);
|
}, Qt::QueuedConnection);
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
|
@ -1845,7 +1845,7 @@ void Application::domainConnectionRefused(const QString& reasonMessage, int reas
|
||||||
case DomainHandler::ConnectionRefusedReason::Unknown: {
|
case DomainHandler::ConnectionRefusedReason::Unknown: {
|
||||||
QString message = "Unable to connect to the location you are visiting.\n";
|
QString message = "Unable to connect to the location you are visiting.\n";
|
||||||
message += reasonMessage;
|
message += reasonMessage;
|
||||||
OffscreenUi::warning("", message);
|
OffscreenUi::asyncWarning("", message);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
|
@ -2369,6 +2369,7 @@ void Application::initializeUi() {
|
||||||
|
|
||||||
// Pre-create a couple of Web3D overlays to speed up tablet UI
|
// Pre-create a couple of Web3D overlays to speed up tablet UI
|
||||||
auto offscreenSurfaceCache = DependencyManager::get<OffscreenQmlSurfaceCache>();
|
auto offscreenSurfaceCache = DependencyManager::get<OffscreenQmlSurfaceCache>();
|
||||||
|
offscreenSurfaceCache->reserve(TabletScriptingInterface::QML, 1);
|
||||||
offscreenSurfaceCache->reserve(Web3DOverlay::QML, 2);
|
offscreenSurfaceCache->reserve(Web3DOverlay::QML, 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2581,7 +2582,6 @@ void Application::paintGL() {
|
||||||
// scale IPD by sensorToWorldScale, to make the world seem larger or smaller accordingly.
|
// scale IPD by sensorToWorldScale, to make the world seem larger or smaller accordingly.
|
||||||
ipdScale *= sensorToWorldScale;
|
ipdScale *= sensorToWorldScale;
|
||||||
|
|
||||||
mat4 eyeProjections[2];
|
|
||||||
{
|
{
|
||||||
PROFILE_RANGE(render, "/mainRender");
|
PROFILE_RANGE(render, "/mainRender");
|
||||||
PerformanceTimer perfTimer("mainRender");
|
PerformanceTimer perfTimer("mainRender");
|
||||||
|
@ -2638,17 +2638,8 @@ void Application::paintGL() {
|
||||||
PerformanceTimer perfTimer("postComposite");
|
PerformanceTimer perfTimer("postComposite");
|
||||||
renderArgs._batch = &postCompositeBatch;
|
renderArgs._batch = &postCompositeBatch;
|
||||||
renderArgs._batch->setViewportTransform(ivec4(0, 0, finalFramebufferSize.width(), finalFramebufferSize.height()));
|
renderArgs._batch->setViewportTransform(ivec4(0, 0, finalFramebufferSize.width(), finalFramebufferSize.height()));
|
||||||
for_each_eye([&](Eye eye) {
|
renderArgs._batch->setViewTransform(renderArgs.getViewFrustum().getView());
|
||||||
|
_overlays.render3DHUDOverlays(&renderArgs);
|
||||||
// apply eye offset and IPD scale to the view matrix
|
|
||||||
mat4 eyeToHead = displayPlugin->getEyeToHeadTransform(eye);
|
|
||||||
vec3 eyeOffset = glm::vec3(eyeToHead[3]);
|
|
||||||
mat4 eyeOffsetTransform = glm::translate(mat4(), eyeOffset * -1.0f * ipdScale);
|
|
||||||
renderArgs._batch->setViewTransform(renderArgs.getViewFrustum().getView() * eyeOffsetTransform);
|
|
||||||
|
|
||||||
renderArgs._batch->setProjectionTransform(eyeProjections[eye]);
|
|
||||||
_overlays.render3DHUDOverlays(&renderArgs);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
auto frame = _gpuContext->endFrame();
|
auto frame = _gpuContext->endFrame();
|
||||||
|
@ -3751,7 +3742,7 @@ bool Application::acceptSnapshot(const QString& urlString) {
|
||||||
DependencyManager::get<AddressManager>()->handleLookupString(snapshotData->getURL().toString());
|
DependencyManager::get<AddressManager>()->handleLookupString(snapshotData->getURL().toString());
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
OffscreenUi::warning("", "No location details were found in the file\n" +
|
OffscreenUi::asyncWarning("", "No location details were found in the file\n" +
|
||||||
snapshotPath + "\nTry dragging in an authentic Hifi snapshot.");
|
snapshotPath + "\nTry dragging in an authentic Hifi snapshot.");
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
@ -6151,7 +6142,7 @@ void Application::setSessionUUID(const QUuid& sessionUUID) const {
|
||||||
bool Application::askToSetAvatarUrl(const QString& url) {
|
bool Application::askToSetAvatarUrl(const QString& url) {
|
||||||
QUrl realUrl(url);
|
QUrl realUrl(url);
|
||||||
if (realUrl.isLocalFile()) {
|
if (realUrl.isLocalFile()) {
|
||||||
OffscreenUi::warning("", "You can not use local files for avatar components.");
|
OffscreenUi::asyncWarning("", "You can not use local files for avatar components.");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6163,41 +6154,55 @@ bool Application::askToSetAvatarUrl(const QString& url) {
|
||||||
QString modelName = fstMapping["name"].toString();
|
QString modelName = fstMapping["name"].toString();
|
||||||
QString modelLicense = fstMapping["license"].toString();
|
QString modelLicense = fstMapping["license"].toString();
|
||||||
|
|
||||||
bool agreeToLicence = true; // assume true
|
bool agreeToLicense = true; // assume true
|
||||||
|
//create set avatar callback
|
||||||
|
auto setAvatar = [=] (QString url, QString modelName) {
|
||||||
|
ModalDialogListener* dlg = OffscreenUi::asyncQuestion("Set Avatar",
|
||||||
|
"Would you like to use '" + modelName + "' for your avatar?",
|
||||||
|
QMessageBox::Ok | QMessageBox::Cancel, QMessageBox::Ok);
|
||||||
|
QObject::connect(dlg, &ModalDialogListener::response, this, [=] (QVariant answer) {
|
||||||
|
QObject::disconnect(dlg, &ModalDialogListener::response, this, nullptr);
|
||||||
|
|
||||||
|
bool ok = (QMessageBox::Ok == static_cast<QMessageBox::StandardButton>(answer.toInt()));
|
||||||
|
if (ok) {
|
||||||
|
getMyAvatar()->useFullAvatarURL(url, modelName);
|
||||||
|
emit fullAvatarURLChanged(url, modelName);
|
||||||
|
} else {
|
||||||
|
qCDebug(interfaceapp) << "Declined to use the avatar: " << url;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
if (!modelLicense.isEmpty()) {
|
if (!modelLicense.isEmpty()) {
|
||||||
// word wrap the licence text to fit in a reasonable shaped message box.
|
// word wrap the license text to fit in a reasonable shaped message box.
|
||||||
const int MAX_CHARACTERS_PER_LINE = 90;
|
const int MAX_CHARACTERS_PER_LINE = 90;
|
||||||
modelLicense = simpleWordWrap(modelLicense, MAX_CHARACTERS_PER_LINE);
|
modelLicense = simpleWordWrap(modelLicense, MAX_CHARACTERS_PER_LINE);
|
||||||
|
|
||||||
agreeToLicence = QMessageBox::Yes == OffscreenUi::question("Avatar Usage License",
|
ModalDialogListener* dlg = OffscreenUi::asyncQuestion("Avatar Usage License",
|
||||||
modelLicense + "\nDo you agree to these terms?",
|
modelLicense + "\nDo you agree to these terms?",
|
||||||
QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes);
|
QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes);
|
||||||
}
|
QObject::connect(dlg, &ModalDialogListener::response, this, [=, &agreeToLicense] (QVariant answer) {
|
||||||
|
QObject::disconnect(dlg, &ModalDialogListener::response, this, nullptr);
|
||||||
|
|
||||||
bool ok = false;
|
agreeToLicense = (static_cast<QMessageBox::StandardButton>(answer.toInt()) == QMessageBox::Yes);
|
||||||
|
if (agreeToLicense) {
|
||||||
|
switch (modelType) {
|
||||||
|
case FSTReader::HEAD_AND_BODY_MODEL: {
|
||||||
|
setAvatar(url, modelName);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
OffscreenUi::asyncWarning("", modelName + "Does not support a head and body as required.");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
qCDebug(interfaceapp) << "Declined to agree to avatar license: " << url;
|
||||||
|
}
|
||||||
|
|
||||||
if (!agreeToLicence) {
|
//auto offscreenUi = DependencyManager::get<OffscreenUi>();
|
||||||
qCDebug(interfaceapp) << "Declined to agree to avatar license: " << url;
|
});
|
||||||
} else {
|
} else {
|
||||||
switch (modelType) {
|
setAvatar(url, modelName);
|
||||||
|
|
||||||
case FSTReader::HEAD_AND_BODY_MODEL:
|
|
||||||
ok = QMessageBox::Ok == OffscreenUi::question("Set Avatar",
|
|
||||||
"Would you like to use '" + modelName + "' for your avatar?",
|
|
||||||
QMessageBox::Ok | QMessageBox::Cancel, QMessageBox::Ok);
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
OffscreenUi::warning("", modelName + "Does not support a head and body as required.");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ok) {
|
|
||||||
getMyAvatar()->useFullAvatarURL(url, modelName);
|
|
||||||
emit fullAvatarURLChanged(url, modelName);
|
|
||||||
} else {
|
|
||||||
qCDebug(interfaceapp) << "Declined to use the avatar: " << url;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -6205,8 +6210,6 @@ bool Application::askToSetAvatarUrl(const QString& url) {
|
||||||
|
|
||||||
|
|
||||||
bool Application::askToLoadScript(const QString& scriptFilenameOrURL) {
|
bool Application::askToLoadScript(const QString& scriptFilenameOrURL) {
|
||||||
QMessageBox::StandardButton reply;
|
|
||||||
|
|
||||||
QString shortName = scriptFilenameOrURL;
|
QString shortName = scriptFilenameOrURL;
|
||||||
|
|
||||||
QUrl scriptURL { scriptFilenameOrURL };
|
QUrl scriptURL { scriptFilenameOrURL };
|
||||||
|
@ -6218,15 +6221,20 @@ bool Application::askToLoadScript(const QString& scriptFilenameOrURL) {
|
||||||
}
|
}
|
||||||
|
|
||||||
QString message = "Would you like to run this script:\n" + shortName;
|
QString message = "Would you like to run this script:\n" + shortName;
|
||||||
|
ModalDialogListener* dlg = OffscreenUi::asyncQuestion(getWindow(), "Run Script", message,
|
||||||
|
QMessageBox::Yes | QMessageBox::No);
|
||||||
|
|
||||||
reply = OffscreenUi::question(getWindow(), "Run Script", message, QMessageBox::Yes | QMessageBox::No);
|
QObject::connect(dlg, &ModalDialogListener::response, this, [=] (QVariant answer) {
|
||||||
|
const QString& fileName = scriptFilenameOrURL;
|
||||||
|
if (static_cast<QMessageBox::StandardButton>(answer.toInt()) == QMessageBox::Yes) {
|
||||||
|
qCDebug(interfaceapp) << "Chose to run the script: " << fileName;
|
||||||
|
DependencyManager::get<ScriptEngines>()->loadScript(fileName);
|
||||||
|
} else {
|
||||||
|
qCDebug(interfaceapp) << "Declined to run the script: " << scriptFilenameOrURL;
|
||||||
|
}
|
||||||
|
QObject::disconnect(dlg, &ModalDialogListener::response, this, nullptr);
|
||||||
|
});
|
||||||
|
|
||||||
if (reply == QMessageBox::Yes) {
|
|
||||||
qCDebug(interfaceapp) << "Chose to run the script: " << scriptFilenameOrURL;
|
|
||||||
DependencyManager::get<ScriptEngines>()->loadScript(scriptFilenameOrURL);
|
|
||||||
} else {
|
|
||||||
qCDebug(interfaceapp) << "Declined to run the script: " << scriptFilenameOrURL;
|
|
||||||
}
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6263,22 +6271,26 @@ bool Application::askToWearAvatarAttachmentUrl(const QString& url) {
|
||||||
name = nameValue.toString();
|
name = nameValue.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
// display confirmation dialog
|
auto avatarAttachmentConfirmationTitle = tr("Avatar Attachment Confirmation");
|
||||||
if (displayAvatarAttachmentConfirmationDialog(name)) {
|
auto avatarAttachmentConfirmationMessage = tr("Would you like to wear '%1' on your avatar?").arg(name);
|
||||||
|
ModalDialogListener* dlg = OffscreenUi::asyncQuestion(avatarAttachmentConfirmationTitle,
|
||||||
// add attachment to avatar
|
avatarAttachmentConfirmationMessage,
|
||||||
auto myAvatar = getMyAvatar();
|
QMessageBox::Ok | QMessageBox::Cancel);
|
||||||
assert(myAvatar);
|
QObject::connect(dlg, &ModalDialogListener::response, this, [=] (QVariant answer) {
|
||||||
auto attachmentDataVec = myAvatar->getAttachmentData();
|
QObject::disconnect(dlg, &ModalDialogListener::response, this, nullptr);
|
||||||
AttachmentData attachmentData;
|
if (static_cast<QMessageBox::StandardButton>(answer.toInt()) == QMessageBox::Yes) {
|
||||||
attachmentData.fromJson(jsonObject);
|
// add attachment to avatar
|
||||||
attachmentDataVec.push_back(attachmentData);
|
auto myAvatar = getMyAvatar();
|
||||||
myAvatar->setAttachmentData(attachmentDataVec);
|
assert(myAvatar);
|
||||||
|
auto attachmentDataVec = myAvatar->getAttachmentData();
|
||||||
} else {
|
AttachmentData attachmentData;
|
||||||
qCDebug(interfaceapp) << "User declined to wear the avatar attachment: " << url;
|
attachmentData.fromJson(jsonObject);
|
||||||
}
|
attachmentDataVec.push_back(attachmentData);
|
||||||
|
myAvatar->setAttachmentData(attachmentDataVec);
|
||||||
|
} else {
|
||||||
|
qCDebug(interfaceapp) << "User declined to wear the avatar attachment: " << url;
|
||||||
|
}
|
||||||
|
});
|
||||||
} else {
|
} else {
|
||||||
// json parse error
|
// json parse error
|
||||||
auto avatarAttachmentParseErrorString = tr("Error parsing attachment JSON from url: \"%1\"");
|
auto avatarAttachmentParseErrorString = tr("Error parsing attachment JSON from url: \"%1\"");
|
||||||
|
@ -6351,20 +6363,7 @@ bool Application::askToReplaceDomainContent(const QString& url) {
|
||||||
|
|
||||||
void Application::displayAvatarAttachmentWarning(const QString& message) const {
|
void Application::displayAvatarAttachmentWarning(const QString& message) const {
|
||||||
auto avatarAttachmentWarningTitle = tr("Avatar Attachment Failure");
|
auto avatarAttachmentWarningTitle = tr("Avatar Attachment Failure");
|
||||||
OffscreenUi::warning(avatarAttachmentWarningTitle, message);
|
OffscreenUi::asyncWarning(avatarAttachmentWarningTitle, message);
|
||||||
}
|
|
||||||
|
|
||||||
bool Application::displayAvatarAttachmentConfirmationDialog(const QString& name) const {
|
|
||||||
auto avatarAttachmentConfirmationTitle = tr("Avatar Attachment Confirmation");
|
|
||||||
auto avatarAttachmentConfirmationMessage = tr("Would you like to wear '%1' on your avatar?").arg(name);
|
|
||||||
auto reply = OffscreenUi::question(avatarAttachmentConfirmationTitle,
|
|
||||||
avatarAttachmentConfirmationMessage,
|
|
||||||
QMessageBox::Ok | QMessageBox::Cancel);
|
|
||||||
if (QMessageBox::Ok == reply) {
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Application::showDialog(const QUrl& widgetUrl, const QUrl& tabletUrl, const QString& name) const {
|
void Application::showDialog(const QUrl& widgetUrl, const QUrl& tabletUrl, const QString& name) const {
|
||||||
|
@ -6686,7 +6685,7 @@ void Application::addAssetToWorldCheckModelSize() {
|
||||||
if (dimensions != DEFAULT_DIMENSIONS) {
|
if (dimensions != DEFAULT_DIMENSIONS) {
|
||||||
|
|
||||||
// Scale model so that its maximum is exactly specific size.
|
// Scale model so that its maximum is exactly specific size.
|
||||||
const float MAXIMUM_DIMENSION = 1.0f * getMyAvatar()->getSensorToWorldScale();
|
const float MAXIMUM_DIMENSION = getMyAvatar()->getSensorToWorldScale();
|
||||||
auto previousDimensions = dimensions;
|
auto previousDimensions = dimensions;
|
||||||
auto scale = std::min(MAXIMUM_DIMENSION / dimensions.x, std::min(MAXIMUM_DIMENSION / dimensions.y,
|
auto scale = std::min(MAXIMUM_DIMENSION / dimensions.x, std::min(MAXIMUM_DIMENSION / dimensions.y,
|
||||||
MAXIMUM_DIMENSION / dimensions.z));
|
MAXIMUM_DIMENSION / dimensions.z));
|
||||||
|
@ -6945,12 +6944,17 @@ void Application::openUrl(const QUrl& url) const {
|
||||||
|
|
||||||
void Application::loadDialog() {
|
void Application::loadDialog() {
|
||||||
auto scriptEngines = DependencyManager::get<ScriptEngines>();
|
auto scriptEngines = DependencyManager::get<ScriptEngines>();
|
||||||
QString fileNameString = OffscreenUi::getOpenFileName(
|
ModalDialogListener* dlg = OffscreenUi::getOpenFileNameAsync(_glWidget, tr("Open Script"),
|
||||||
_glWidget, tr("Open Script"), getPreviousScriptLocation(), tr("JavaScript Files (*.js)"));
|
getPreviousScriptLocation(),
|
||||||
if (!fileNameString.isEmpty() && QFile(fileNameString).exists()) {
|
tr("JavaScript Files (*.js)"));
|
||||||
setPreviousScriptLocation(QFileInfo(fileNameString).absolutePath());
|
connect(dlg, &ModalDialogListener::response, this, [=] (QVariant answer) {
|
||||||
DependencyManager::get<ScriptEngines>()->loadScript(fileNameString, true, false, false, true); // Don't load from cache
|
disconnect(dlg, &ModalDialogListener::response, this, nullptr);
|
||||||
}
|
const QString& response = answer.toString();
|
||||||
|
if (!response.isEmpty() && QFile(response).exists()) {
|
||||||
|
setPreviousScriptLocation(QFileInfo(response).absolutePath());
|
||||||
|
DependencyManager::get<ScriptEngines>()->loadScript(response, true, false, false, true); // Don't load from cache
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
QString Application::getPreviousScriptLocation() {
|
QString Application::getPreviousScriptLocation() {
|
||||||
|
@ -6963,12 +6967,16 @@ void Application::setPreviousScriptLocation(const QString& location) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Application::loadScriptURLDialog() const {
|
void Application::loadScriptURLDialog() const {
|
||||||
QString newScript = OffscreenUi::getText(OffscreenUi::ICON_NONE, "Open and Run Script", "Script URL");
|
ModalDialogListener* dlg = OffscreenUi::getTextAsync(OffscreenUi::ICON_NONE, "Open and Run Script", "Script URL");
|
||||||
if (QUrl(newScript).scheme() == "atp") {
|
connect(dlg, &ModalDialogListener::response, this, [=] (QVariant response) {
|
||||||
OffscreenUi::warning("Error Loading Script", "Cannot load client script over ATP");
|
disconnect(dlg, &ModalDialogListener::response, this, nullptr);
|
||||||
} else if (!newScript.isEmpty()) {
|
const QString& newScript = response.toString();
|
||||||
DependencyManager::get<ScriptEngines>()->loadScript(newScript.trimmed());
|
if (QUrl(newScript).scheme() == "atp") {
|
||||||
}
|
OffscreenUi::asyncWarning("Error Loading Script", "Cannot load client script over ATP");
|
||||||
|
} else if (!newScript.isEmpty()) {
|
||||||
|
DependencyManager::get<ScriptEngines>()->loadScript(newScript.trimmed());
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void Application::loadLODToolsDialog() {
|
void Application::loadLODToolsDialog() {
|
||||||
|
@ -7085,7 +7093,7 @@ void Application::notifyPacketVersionMismatch() {
|
||||||
QString message = "The location you are visiting is running an incompatible server version.\n";
|
QString message = "The location you are visiting is running an incompatible server version.\n";
|
||||||
message += "Content may not display properly.";
|
message += "Content may not display properly.";
|
||||||
|
|
||||||
OffscreenUi::warning("", message);
|
OffscreenUi::asyncWarning("", message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7094,7 +7102,7 @@ void Application::checkSkeleton() const {
|
||||||
qCDebug(interfaceapp) << "MyAvatar model has no skeleton";
|
qCDebug(interfaceapp) << "MyAvatar model has no skeleton";
|
||||||
|
|
||||||
QString message = "Your selected avatar body has no skeleton.\n\nThe default body will be loaded...";
|
QString message = "Your selected avatar body has no skeleton.\n\nThe default body will be loaded...";
|
||||||
OffscreenUi::warning("", message);
|
OffscreenUi::asyncWarning("", message);
|
||||||
|
|
||||||
getMyAvatar()->useFullAvatarURL(AvatarData::defaultFullAvatarModelUrl(), DEFAULT_FULL_AVATAR_MODEL_NAME);
|
getMyAvatar()->useFullAvatarURL(AvatarData::defaultFullAvatarModelUrl(), DEFAULT_FULL_AVATAR_MODEL_NAME);
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -429,7 +429,6 @@ private slots:
|
||||||
|
|
||||||
bool askToWearAvatarAttachmentUrl(const QString& url);
|
bool askToWearAvatarAttachmentUrl(const QString& url);
|
||||||
void displayAvatarAttachmentWarning(const QString& message) const;
|
void displayAvatarAttachmentWarning(const QString& message) const;
|
||||||
bool displayAvatarAttachmentConfirmationDialog(const QString& name) const;
|
|
||||||
|
|
||||||
bool askToReplaceDomainContent(const QString& url);
|
bool askToReplaceDomainContent(const QString& url);
|
||||||
|
|
||||||
|
|
|
@ -106,30 +106,30 @@ void AvatarBookmarks::changeToBookmarkedAvatar() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void AvatarBookmarks::addBookmark() {
|
void AvatarBookmarks::addBookmark() {
|
||||||
bool ok = false;
|
ModalDialogListener* dlg = OffscreenUi::getTextAsync(OffscreenUi::ICON_PLACEMARK, "Bookmark Avatar", "Name", QString());
|
||||||
auto bookmarkName = OffscreenUi::getText(OffscreenUi::ICON_PLACEMARK, "Bookmark Avatar", "Name", QString(), &ok);
|
connect(dlg, &ModalDialogListener::response, this, [=] (QVariant response) {
|
||||||
if (!ok) {
|
disconnect(dlg, &ModalDialogListener::response, this, nullptr);
|
||||||
return;
|
auto bookmarkName = response.toString();
|
||||||
}
|
bookmarkName = bookmarkName.trimmed().replace(QRegExp("(\r\n|[\r\n\t\v ])+"), " ");
|
||||||
|
if (bookmarkName.length() == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
bookmarkName = bookmarkName.trimmed().replace(QRegExp("(\r\n|[\r\n\t\v ])+"), " ");
|
auto myAvatar = DependencyManager::get<AvatarManager>()->getMyAvatar();
|
||||||
if (bookmarkName.length() == 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto myAvatar = DependencyManager::get<AvatarManager>()->getMyAvatar();
|
const QString& avatarUrl = myAvatar->getSkeletonModelURL().toString();
|
||||||
|
const QVariant& avatarScale = myAvatar->getAvatarScale();
|
||||||
|
|
||||||
const QString& avatarUrl = myAvatar->getSkeletonModelURL().toString();
|
// If Avatar attachments ever change, this is where to update them, when saving remember to also append to AVATAR_BOOKMARK_VERSION
|
||||||
const QVariant& avatarScale = myAvatar->getAvatarScale();
|
QVariantMap *bookmark = new QVariantMap;
|
||||||
|
bookmark->insert(ENTRY_VERSION, AVATAR_BOOKMARK_VERSION);
|
||||||
|
bookmark->insert(ENTRY_AVATAR_URL, avatarUrl);
|
||||||
|
bookmark->insert(ENTRY_AVATAR_SCALE, avatarScale);
|
||||||
|
bookmark->insert(ENTRY_AVATAR_ATTACHMENTS, myAvatar->getAttachmentsVariant());
|
||||||
|
|
||||||
|
Bookmarks::addBookmarkToFile(bookmarkName, *bookmark);
|
||||||
|
});
|
||||||
|
|
||||||
// If Avatar attachments ever change, this is where to update them, when saving remember to also append to AVATAR_BOOKMARK_VERSION
|
|
||||||
QVariantMap *bookmark = new QVariantMap;
|
|
||||||
bookmark->insert(ENTRY_VERSION, AVATAR_BOOKMARK_VERSION);
|
|
||||||
bookmark->insert(ENTRY_AVATAR_URL, avatarUrl);
|
|
||||||
bookmark->insert(ENTRY_AVATAR_SCALE, avatarScale);
|
|
||||||
bookmark->insert(ENTRY_AVATAR_ATTACHMENTS, myAvatar->getAttachmentsVariant());
|
|
||||||
|
|
||||||
Bookmarks::addBookmarkToFile(bookmarkName, *bookmark);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void AvatarBookmarks::addBookmarkToMenu(Menu* menubar, const QString& name, const QVariant& bookmark) {
|
void AvatarBookmarks::addBookmarkToMenu(Menu* menubar, const QString& name, const QVariant& bookmark) {
|
||||||
|
|
|
@ -58,20 +58,25 @@ void Bookmarks::addBookmarkToFile(const QString& bookmarkName, const QVariant& b
|
||||||
Menu* menubar = Menu::getInstance();
|
Menu* menubar = Menu::getInstance();
|
||||||
if (contains(bookmarkName)) {
|
if (contains(bookmarkName)) {
|
||||||
auto offscreenUi = DependencyManager::get<OffscreenUi>();
|
auto offscreenUi = DependencyManager::get<OffscreenUi>();
|
||||||
auto duplicateBookmarkMessage = offscreenUi->createMessageBox(OffscreenUi::ICON_WARNING, "Duplicate Bookmark",
|
ModalDialogListener* dlg = OffscreenUi::asyncWarning("Duplicate Bookmark",
|
||||||
"The bookmark name you entered already exists in your list.",
|
"The bookmark name you entered already exists in your list.",
|
||||||
QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes);
|
QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes);
|
||||||
duplicateBookmarkMessage->setProperty("informativeText", "Would you like to overwrite it?");
|
dlg->setProperty("informativeText", "Would you like to overwrite it?");
|
||||||
auto result = offscreenUi->waitForMessageBoxResult(duplicateBookmarkMessage);
|
QObject::connect(dlg, &ModalDialogListener::response, this, [=] (QVariant answer) {
|
||||||
if (result != QMessageBox::Yes) {
|
QObject::disconnect(dlg, &ModalDialogListener::response, this, nullptr);
|
||||||
return;
|
|
||||||
}
|
|
||||||
removeBookmarkFromMenu(menubar, bookmarkName);
|
|
||||||
}
|
|
||||||
|
|
||||||
addBookmarkToMenu(menubar, bookmarkName, bookmark);
|
if (QMessageBox::Yes == static_cast<QMessageBox::StandardButton>(answer.toInt())) {
|
||||||
insert(bookmarkName, bookmark); // Overwrites any item with the same bookmarkName.
|
removeBookmarkFromMenu(menubar, bookmarkName);
|
||||||
enableMenuItems(true);
|
addBookmarkToMenu(menubar, bookmarkName, bookmark);
|
||||||
|
insert(bookmarkName, bookmark); // Overwrites any item with the same bookmarkName.
|
||||||
|
enableMenuItems(true);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
addBookmarkToMenu(menubar, bookmarkName, bookmark);
|
||||||
|
insert(bookmarkName, bookmark); // Overwrites any item with the same bookmarkName.
|
||||||
|
enableMenuItems(true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Bookmarks::insert(const QString& name, const QVariant& bookmark) {
|
void Bookmarks::insert(const QString& name, const QVariant& bookmark) {
|
||||||
|
|
|
@ -74,20 +74,21 @@ void LocationBookmarks::teleportToBookmark() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void LocationBookmarks::addBookmark() {
|
void LocationBookmarks::addBookmark() {
|
||||||
bool ok = false;
|
ModalDialogListener* dlg = OffscreenUi::getTextAsync(OffscreenUi::ICON_PLACEMARK, "Bookmark Location", "Name", QString());
|
||||||
auto bookmarkName = OffscreenUi::getText(OffscreenUi::ICON_PLACEMARK, "Bookmark Location", "Name", QString(), &ok);
|
|
||||||
if (!ok) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
bookmarkName = bookmarkName.trimmed().replace(QRegExp("(\r\n|[\r\n\t\v ])+"), " ");
|
connect(dlg, &ModalDialogListener::response, this, [=] (QVariant response) {
|
||||||
if (bookmarkName.length() == 0) {
|
disconnect(dlg, &ModalDialogListener::response, this, nullptr);
|
||||||
return;
|
auto bookmarkName = response.toString();
|
||||||
}
|
|
||||||
|
|
||||||
auto addressManager = DependencyManager::get<AddressManager>();
|
bookmarkName = bookmarkName.trimmed().replace(QRegExp("(\r\n|[\r\n\t\v ])+"), " ");
|
||||||
QString bookmarkAddress = addressManager->currentAddress().toString();
|
if (bookmarkName.length() == 0) {
|
||||||
Bookmarks::addBookmarkToFile(bookmarkName, bookmarkAddress);
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto addressManager = DependencyManager::get<AddressManager>();
|
||||||
|
QString bookmarkAddress = addressManager->currentAddress().toString();
|
||||||
|
Bookmarks::addBookmarkToFile(bookmarkName, bookmarkAddress);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void LocationBookmarks::addBookmarkToMenu(Menu* menubar, const QString& name, const QVariant& address) {
|
void LocationBookmarks::addBookmarkToMenu(Menu* menubar, const QString& name, const QVariant& address) {
|
||||||
|
@ -101,4 +102,4 @@ void LocationBookmarks::addBookmarkToMenu(Menu* menubar, const QString& name, co
|
||||||
menubar->addActionToQMenuAndActionHash(_bookmarksMenu, teleportAction, name, 0, QAction::NoRole);
|
menubar->addActionToQMenuAndActionHash(_bookmarksMenu, teleportAction, name, 0, QAction::NoRole);
|
||||||
Bookmarks::sortActions(menubar, _bookmarksMenu);
|
Bookmarks::sortActions(menubar, _bookmarksMenu);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -367,6 +367,20 @@ Menu::Menu() {
|
||||||
QString("../../hifi/tablet/TabletGraphicsPreferences.qml"), "GraphicsPreferencesDialog");
|
QString("../../hifi/tablet/TabletGraphicsPreferences.qml"), "GraphicsPreferencesDialog");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Developer > UI >>>
|
||||||
|
MenuWrapper* uiOptionsMenu = developerMenu->addMenu("UI");
|
||||||
|
action = addCheckableActionToQMenuAndActionHash(uiOptionsMenu, MenuOption::DesktopTabletToToolbar, 0,
|
||||||
|
qApp->getDesktopTabletBecomesToolbarSetting());
|
||||||
|
connect(action, &QAction::triggered, [action] {
|
||||||
|
qApp->setDesktopTabletBecomesToolbarSetting(action->isChecked());
|
||||||
|
});
|
||||||
|
|
||||||
|
action = addCheckableActionToQMenuAndActionHash(uiOptionsMenu, MenuOption::HMDTabletToToolbar, 0,
|
||||||
|
qApp->getHmdTabletBecomesToolbarSetting());
|
||||||
|
connect(action, &QAction::triggered, [action] {
|
||||||
|
qApp->setHmdTabletBecomesToolbarSetting(action->isChecked());
|
||||||
|
});
|
||||||
|
|
||||||
// Developer > Render >>>
|
// Developer > Render >>>
|
||||||
MenuWrapper* renderOptionsMenu = developerMenu->addMenu("Render");
|
MenuWrapper* renderOptionsMenu = developerMenu->addMenu("Render");
|
||||||
addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::WorldAxes);
|
addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::WorldAxes);
|
||||||
|
|
|
@ -200,6 +200,8 @@ namespace MenuOption {
|
||||||
const QString VisibleToFriends = "Friends";
|
const QString VisibleToFriends = "Friends";
|
||||||
const QString VisibleToNoOne = "No one";
|
const QString VisibleToNoOne = "No one";
|
||||||
const QString WorldAxes = "World Axes";
|
const QString WorldAxes = "World Axes";
|
||||||
|
const QString DesktopTabletToToolbar = "Desktop Tablet Becomes Toolbar";
|
||||||
|
const QString HMDTabletToToolbar = "HMD Tablet Becomes Toolbar";
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // hifi_Menu_h
|
#endif // hifi_Menu_h
|
||||||
|
|
|
@ -79,7 +79,7 @@ bool ModelPackager::loadModel() {
|
||||||
if (_modelFile.completeSuffix().contains("fst")) {
|
if (_modelFile.completeSuffix().contains("fst")) {
|
||||||
QFile fst(_modelFile.filePath());
|
QFile fst(_modelFile.filePath());
|
||||||
if (!fst.open(QFile::ReadOnly | QFile::Text)) {
|
if (!fst.open(QFile::ReadOnly | QFile::Text)) {
|
||||||
OffscreenUi::warning(NULL,
|
OffscreenUi::asyncWarning(NULL,
|
||||||
QString("ModelPackager::loadModel()"),
|
QString("ModelPackager::loadModel()"),
|
||||||
QString("Could not open FST file %1").arg(_modelFile.filePath()),
|
QString("Could not open FST file %1").arg(_modelFile.filePath()),
|
||||||
QMessageBox::Ok);
|
QMessageBox::Ok);
|
||||||
|
@ -98,7 +98,7 @@ bool ModelPackager::loadModel() {
|
||||||
// open the fbx file
|
// open the fbx file
|
||||||
QFile fbx(_fbxInfo.filePath());
|
QFile fbx(_fbxInfo.filePath());
|
||||||
if (!_fbxInfo.exists() || !_fbxInfo.isFile() || !fbx.open(QIODevice::ReadOnly)) {
|
if (!_fbxInfo.exists() || !_fbxInfo.isFile() || !fbx.open(QIODevice::ReadOnly)) {
|
||||||
OffscreenUi::warning(NULL,
|
OffscreenUi::asyncWarning(NULL,
|
||||||
QString("ModelPackager::loadModel()"),
|
QString("ModelPackager::loadModel()"),
|
||||||
QString("Could not open FBX file %1").arg(_fbxInfo.filePath()),
|
QString("Could not open FBX file %1").arg(_fbxInfo.filePath()),
|
||||||
QMessageBox::Ok);
|
QMessageBox::Ok);
|
||||||
|
@ -408,7 +408,7 @@ bool ModelPackager::copyTextures(const QString& oldDir, const QDir& newDir) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!errors.isEmpty()) {
|
if (!errors.isEmpty()) {
|
||||||
OffscreenUi::warning(nullptr, "ModelPackager::copyTextures()",
|
OffscreenUi::asyncWarning(nullptr, "ModelPackager::copyTextures()",
|
||||||
"Missing textures:" + errors);
|
"Missing textures:" + errors);
|
||||||
qCDebug(interfaceapp) << "ModelPackager::copyTextures():" << errors;
|
qCDebug(interfaceapp) << "ModelPackager::copyTextures():" << errors;
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -201,7 +201,7 @@ void ModelPropertiesDialog::chooseTextureDirectory() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!directory.startsWith(_basePath)) {
|
if (!directory.startsWith(_basePath)) {
|
||||||
OffscreenUi::warning(NULL, "Invalid texture directory", "Texture directory must be child of base path.");
|
OffscreenUi::asyncWarning(NULL, "Invalid texture directory", "Texture directory must be child of base path.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
_textureDirectory->setText(directory.length() == _basePath.length() ? "." : directory.mid(_basePath.length() + 1));
|
_textureDirectory->setText(directory.length() == _basePath.length() ? "." : directory.mid(_basePath.length() + 1));
|
||||||
|
|
|
@ -42,117 +42,161 @@ static const QString COMPOUND_SHAPE_URL_KEY = "compoundShapeURL";
|
||||||
static const QString MESSAGE_BOX_TITLE = "ATP Asset Migration";
|
static const QString MESSAGE_BOX_TITLE = "ATP Asset Migration";
|
||||||
|
|
||||||
void ATPAssetMigrator::loadEntityServerFile() {
|
void ATPAssetMigrator::loadEntityServerFile() {
|
||||||
auto filename = OffscreenUi::getOpenFileName(_dialogParent, tr("Select an entity-server content file to migrate"), QString(), tr("Entity-Server Content (*.gz)"));
|
ModalDialogListener* dlg = OffscreenUi::getOpenFileNameAsync(_dialogParent, tr("Select an entity-server content file to migrate"),
|
||||||
|
QString(), tr("Entity-Server Content (*.gz)"));
|
||||||
if (!filename.isEmpty()) {
|
|
||||||
qCDebug(asset_migrator) << "Selected filename for ATP asset migration: " << filename;
|
|
||||||
|
|
||||||
static const QString MIGRATION_CONFIRMATION_TEXT {
|
|
||||||
"The ATP Asset Migration process will scan the selected entity-server file,\nupload discovered resources to the"\
|
|
||||||
" current asset-server\nand then save a new entity-server file with the ATP URLs.\n\nAre you ready to"\
|
|
||||||
" continue?\n\nMake sure you are connected to the right domain."
|
|
||||||
};
|
|
||||||
|
|
||||||
auto button = OffscreenUi::question(_dialogParent, MESSAGE_BOX_TITLE, MIGRATION_CONFIRMATION_TEXT,
|
|
||||||
QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes);
|
|
||||||
|
|
||||||
if (button == QMessageBox::No) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// try to open the file at the given filename
|
|
||||||
QFile modelsFile { filename };
|
|
||||||
|
|
||||||
if (modelsFile.open(QIODevice::ReadOnly)) {
|
|
||||||
QByteArray compressedJsonData = modelsFile.readAll();
|
|
||||||
QByteArray jsonData;
|
|
||||||
|
|
||||||
if (!gunzip(compressedJsonData, jsonData)) {
|
|
||||||
OffscreenUi::warning(_dialogParent, "Error", "The file at" + filename + "was not in gzip format.");
|
|
||||||
}
|
|
||||||
|
|
||||||
QJsonDocument modelsJSON = QJsonDocument::fromJson(jsonData);
|
|
||||||
_entitiesArray = modelsJSON.object()["Entities"].toArray();
|
|
||||||
|
|
||||||
for (auto jsonValue : _entitiesArray) {
|
|
||||||
QJsonObject entityObject = jsonValue.toObject();
|
|
||||||
QString modelURLString = entityObject.value(MODEL_URL_KEY).toString();
|
|
||||||
QString compoundURLString = entityObject.value(COMPOUND_SHAPE_URL_KEY).toString();
|
|
||||||
|
|
||||||
for (int i = 0; i < 2; ++i) {
|
connect(dlg, &ModalDialogListener::response, this, [=] (QVariant response) {
|
||||||
bool isModelURL = (i == 0);
|
const QString& filename = response.toString();
|
||||||
quint8 replacementType = i;
|
disconnect(dlg, &ModalDialogListener::response, this, nullptr);
|
||||||
auto migrationURLString = (isModelURL) ? modelURLString : compoundURLString;
|
if (!filename.isEmpty()) {
|
||||||
|
qCDebug(asset_migrator) << "Selected filename for ATP asset migration: " << filename;
|
||||||
|
|
||||||
if (!migrationURLString.isEmpty()) {
|
auto migrateResources = [=](QUrl migrationURL, QJsonValueRef jsonValue, bool isModelURL) {
|
||||||
QUrl migrationURL = QUrl(migrationURLString);
|
auto request =
|
||||||
|
DependencyManager::get<ResourceManager>()->createResourceRequest(this, migrationURL);
|
||||||
|
|
||||||
if (!_ignoredUrls.contains(migrationURL)
|
if (request) {
|
||||||
&& (migrationURL.scheme() == URL_SCHEME_HTTP || migrationURL.scheme() == URL_SCHEME_HTTPS
|
qCDebug(asset_migrator) << "Requesting" << migrationURL << "for ATP asset migration";
|
||||||
|| migrationURL.scheme() == URL_SCHEME_FILE || migrationURL.scheme() == URL_SCHEME_FTP)) {
|
|
||||||
|
|
||||||
if (_pendingReplacements.contains(migrationURL)) {
|
// add this combination of QUrl and QJsonValueRef to our multi hash so we can change the URL
|
||||||
// we already have a request out for this asset, just store the QJsonValueRef
|
// to an ATP one once ready
|
||||||
// so we can do the hash replacement when the request comes back
|
_pendingReplacements.insert(migrationURL, { jsonValue, (isModelURL ? 0 : 1)});
|
||||||
_pendingReplacements.insert(migrationURL, { jsonValue, replacementType });
|
|
||||||
} else if (_uploadedAssets.contains(migrationURL)) {
|
|
||||||
// we already have a hash for this asset
|
|
||||||
// so just do the replacement immediately
|
|
||||||
if (isModelURL) {
|
|
||||||
entityObject[MODEL_URL_KEY] = _uploadedAssets.value(migrationURL).toString();
|
|
||||||
} else {
|
|
||||||
entityObject[COMPOUND_SHAPE_URL_KEY] = _uploadedAssets.value(migrationURL).toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
jsonValue = entityObject;
|
connect(request, &ResourceRequest::finished, this, [=]() {
|
||||||
} else if (wantsToMigrateResource(migrationURL)) {
|
if (request->getResult() == ResourceRequest::Success) {
|
||||||
auto request =
|
migrateResource(request);
|
||||||
DependencyManager::get<ResourceManager>()->createResourceRequest(this, migrationURL);
|
} else {
|
||||||
|
++_errorCount;
|
||||||
|
_pendingReplacements.remove(migrationURL);
|
||||||
|
qWarning() << "Could not retrieve asset at" << migrationURL.toString();
|
||||||
|
|
||||||
if (request) {
|
checkIfFinished();
|
||||||
qCDebug(asset_migrator) << "Requesting" << migrationURL << "for ATP asset migration";
|
}
|
||||||
|
request->deleteLater();
|
||||||
|
});
|
||||||
|
|
||||||
// add this combination of QUrl and QJsonValueRef to our multi hash so we can change the URL
|
request->send();
|
||||||
// to an ATP one once ready
|
} else {
|
||||||
_pendingReplacements.insert(migrationURL, { jsonValue, (isModelURL ? 0 : 1)});
|
++_errorCount;
|
||||||
|
qWarning() << "Count not create request for asset at" << migrationURL.toString();
|
||||||
connect(request, &ResourceRequest::finished, this, [=]() {
|
|
||||||
if (request->getResult() == ResourceRequest::Success) {
|
|
||||||
migrateResource(request);
|
|
||||||
} else {
|
|
||||||
++_errorCount;
|
|
||||||
_pendingReplacements.remove(migrationURL);
|
|
||||||
qWarning() << "Could not retrieve asset at" << migrationURL.toString();
|
|
||||||
|
|
||||||
checkIfFinished();
|
|
||||||
}
|
|
||||||
request->deleteLater();
|
|
||||||
});
|
|
||||||
|
|
||||||
request->send();
|
|
||||||
} else {
|
|
||||||
++_errorCount;
|
|
||||||
qWarning() << "Count not create request for asset at" << migrationURL.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
_ignoredUrls.insert(migrationURL);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
};
|
||||||
|
static const QString MIGRATION_CONFIRMATION_TEXT {
|
||||||
_doneReading = true;
|
"The ATP Asset Migration process will scan the selected entity-server file,\nupload discovered resources to the"\
|
||||||
|
" current asset-server\nand then save a new entity-server file with the ATP URLs.\n\nAre you ready to"\
|
||||||
|
" continue?\n\nMake sure you are connected to the right domain."
|
||||||
|
};
|
||||||
|
ModalDialogListener* migrationConfirmDialog = OffscreenUi::asyncQuestion(_dialogParent, MESSAGE_BOX_TITLE, MIGRATION_CONFIRMATION_TEXT,
|
||||||
|
QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes);
|
||||||
|
QObject::connect(migrationConfirmDialog, &ModalDialogListener::response, this, [=] (QVariant answer) {
|
||||||
|
QObject::disconnect(migrationConfirmDialog, &ModalDialogListener::response, this, nullptr);
|
||||||
|
|
||||||
checkIfFinished();
|
if (QMessageBox::Yes == static_cast<QMessageBox::StandardButton>(answer.toInt())) {
|
||||||
|
// try to open the file at the given filename
|
||||||
} else {
|
QFile modelsFile { filename };
|
||||||
OffscreenUi::warning(_dialogParent, "Error",
|
|
||||||
"There was a problem loading that entity-server file for ATP asset migration. Please try again");
|
if (modelsFile.open(QIODevice::ReadOnly)) {
|
||||||
|
QByteArray compressedJsonData = modelsFile.readAll();
|
||||||
|
QByteArray jsonData;
|
||||||
|
|
||||||
|
if (!gunzip(compressedJsonData, jsonData)) {
|
||||||
|
OffscreenUi::asyncWarning(_dialogParent, "Error", "The file at" + filename + "was not in gzip format.");
|
||||||
|
}
|
||||||
|
|
||||||
|
QJsonDocument modelsJSON = QJsonDocument::fromJson(jsonData);
|
||||||
|
_entitiesArray = modelsJSON.object()["Entities"].toArray();
|
||||||
|
|
||||||
|
for (auto jsonValue : _entitiesArray) {
|
||||||
|
QJsonObject entityObject = jsonValue.toObject();
|
||||||
|
QString modelURLString = entityObject.value(MODEL_URL_KEY).toString();
|
||||||
|
QString compoundURLString = entityObject.value(COMPOUND_SHAPE_URL_KEY).toString();
|
||||||
|
|
||||||
|
for (int i = 0; i < 2; ++i) {
|
||||||
|
bool isModelURL = (i == 0);
|
||||||
|
quint8 replacementType = i;
|
||||||
|
auto migrationURLString = (isModelURL) ? modelURLString : compoundURLString;
|
||||||
|
|
||||||
|
if (!migrationURLString.isEmpty()) {
|
||||||
|
QUrl migrationURL = QUrl(migrationURLString);
|
||||||
|
|
||||||
|
if (!_ignoredUrls.contains(migrationURL)
|
||||||
|
&& (migrationURL.scheme() == URL_SCHEME_HTTP || migrationURL.scheme() == URL_SCHEME_HTTPS
|
||||||
|
|| migrationURL.scheme() == URL_SCHEME_FILE || migrationURL.scheme() == URL_SCHEME_FTP)) {
|
||||||
|
|
||||||
|
if (_pendingReplacements.contains(migrationURL)) {
|
||||||
|
// we already have a request out for this asset, just store the QJsonValueRef
|
||||||
|
// so we can do the hash replacement when the request comes back
|
||||||
|
_pendingReplacements.insert(migrationURL, { jsonValue, replacementType });
|
||||||
|
} else if (_uploadedAssets.contains(migrationURL)) {
|
||||||
|
// we already have a hash for this asset
|
||||||
|
// so just do the replacement immediately
|
||||||
|
if (isModelURL) {
|
||||||
|
entityObject[MODEL_URL_KEY] = _uploadedAssets.value(migrationURL).toString();
|
||||||
|
} else {
|
||||||
|
entityObject[COMPOUND_SHAPE_URL_KEY] = _uploadedAssets.value(migrationURL).toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
jsonValue = entityObject;
|
||||||
|
} else {
|
||||||
|
|
||||||
|
static bool hasAskedForCompleteMigration { false };
|
||||||
|
static bool wantsCompleteMigration { false };
|
||||||
|
|
||||||
|
if (!hasAskedForCompleteMigration) {
|
||||||
|
// this is the first resource migration - ask the user if they just want to migrate everything
|
||||||
|
static const QString COMPLETE_MIGRATION_TEXT { "Do you want to migrate all assets found in this entity-server file?\n"\
|
||||||
|
"Select \"Yes\" to upload all discovered assets to the current asset-server immediately.\n"\
|
||||||
|
"Select \"No\" to be prompted for each discovered asset."
|
||||||
|
};
|
||||||
|
ModalDialogListener* migrationConfirmDialog1 = OffscreenUi::asyncQuestion(_dialogParent, MESSAGE_BOX_TITLE,
|
||||||
|
"Would you like to migrate the following resource?\n" + migrationURL.toString(),
|
||||||
|
QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes);
|
||||||
|
|
||||||
|
QObject::connect(migrationConfirmDialog1, &ModalDialogListener::response, this, [=] (QVariant answer) {
|
||||||
|
QObject::disconnect(migrationConfirmDialog1, &ModalDialogListener::response, this, nullptr);
|
||||||
|
if (static_cast<QMessageBox::StandardButton>(answer.toInt()) ==
|
||||||
|
QMessageBox::Yes) {
|
||||||
|
wantsCompleteMigration = true;
|
||||||
|
migrateResources(migrationURL, jsonValue, isModelURL);
|
||||||
|
} else {
|
||||||
|
ModalDialogListener* migrationConfirmDialog2 = OffscreenUi::asyncQuestion(_dialogParent, MESSAGE_BOX_TITLE, COMPLETE_MIGRATION_TEXT,
|
||||||
|
QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes);
|
||||||
|
|
||||||
|
QObject::connect(migrationConfirmDialog2, &ModalDialogListener::response, this, [=] (QVariant answer) {
|
||||||
|
QObject::disconnect(migrationConfirmDialog2, &ModalDialogListener::response, this, nullptr);
|
||||||
|
if (static_cast<QMessageBox::StandardButton>(answer.toInt()) ==
|
||||||
|
QMessageBox::Yes) {
|
||||||
|
migrateResources(migrationURL, jsonValue, isModelURL);
|
||||||
|
} else {
|
||||||
|
_ignoredUrls.insert(migrationURL);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
hasAskedForCompleteMigration = true;
|
||||||
|
}
|
||||||
|
if (wantsCompleteMigration) {
|
||||||
|
migrateResources(migrationURL, jsonValue, isModelURL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_doneReading = true;
|
||||||
|
|
||||||
|
checkIfFinished();
|
||||||
|
|
||||||
|
} else {
|
||||||
|
OffscreenUi::asyncWarning(_dialogParent, "Error",
|
||||||
|
"There was a problem loading that entity-server file for ATP asset migration. Please try again");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void ATPAssetMigrator::migrateResource(ResourceRequest* request) {
|
void ATPAssetMigrator::migrateResource(ResourceRequest* request) {
|
||||||
|
@ -248,9 +292,6 @@ void ATPAssetMigrator::checkIfFinished() {
|
||||||
// are we out of pending replacements? if so it is time to save the entity-server file
|
// are we out of pending replacements? if so it is time to save the entity-server file
|
||||||
if (_doneReading && _pendingReplacements.empty()) {
|
if (_doneReading && _pendingReplacements.empty()) {
|
||||||
saveEntityServerFile();
|
saveEntityServerFile();
|
||||||
|
|
||||||
// reset after the attempted save, success or fail
|
|
||||||
reset();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -288,39 +329,43 @@ bool ATPAssetMigrator::wantsToMigrateResource(const QUrl& url) {
|
||||||
|
|
||||||
void ATPAssetMigrator::saveEntityServerFile() {
|
void ATPAssetMigrator::saveEntityServerFile() {
|
||||||
// show a dialog to ask the user where they want to save the file
|
// show a dialog to ask the user where they want to save the file
|
||||||
QString saveName = OffscreenUi::getSaveFileName(_dialogParent, "Save Migrated Entities File");
|
ModalDialogListener* dlg = OffscreenUi::getSaveFileNameAsync(_dialogParent, "Save Migrated Entities File");
|
||||||
|
connect(dlg, &ModalDialogListener::response, this, [=] (QVariant response) {
|
||||||
QFile saveFile { saveName };
|
const QString& saveName = response.toString();
|
||||||
|
QFile saveFile { saveName };
|
||||||
if (saveFile.open(QIODevice::WriteOnly)) {
|
|
||||||
QJsonObject rootObject;
|
|
||||||
rootObject[ENTITIES_OBJECT_KEY] = _entitiesArray;
|
|
||||||
|
|
||||||
QJsonDocument newDocument { rootObject };
|
|
||||||
QByteArray jsonDataForFile;
|
|
||||||
|
|
||||||
if (gzip(newDocument.toJson(), jsonDataForFile, -1)) {
|
|
||||||
|
|
||||||
saveFile.write(jsonDataForFile);
|
|
||||||
saveFile.close();
|
|
||||||
|
|
||||||
QString infoMessage = QString("Your new entities file has been saved at\n%1.").arg(saveName);
|
if (saveFile.open(QIODevice::WriteOnly)) {
|
||||||
|
QJsonObject rootObject;
|
||||||
|
rootObject[ENTITIES_OBJECT_KEY] = _entitiesArray;
|
||||||
|
|
||||||
if (_errorCount > 0) {
|
QJsonDocument newDocument { rootObject };
|
||||||
infoMessage += QString("\nThere were %1 models that could not be migrated.\n").arg(_errorCount);
|
QByteArray jsonDataForFile;
|
||||||
infoMessage += "Check the warnings in your log for details.\n";
|
|
||||||
infoMessage += "You can re-attempt migration on those models\nby restarting this process with the newly saved file.";
|
if (gzip(newDocument.toJson(), jsonDataForFile, -1)) {
|
||||||
|
|
||||||
|
saveFile.write(jsonDataForFile);
|
||||||
|
saveFile.close();
|
||||||
|
|
||||||
|
QString infoMessage = QString("Your new entities file has been saved at\n%1.").arg(saveName);
|
||||||
|
|
||||||
|
if (_errorCount > 0) {
|
||||||
|
infoMessage += QString("\nThere were %1 models that could not be migrated.\n").arg(_errorCount);
|
||||||
|
infoMessage += "Check the warnings in your log for details.\n";
|
||||||
|
infoMessage += "You can re-attempt migration on those models\nby restarting this process with the newly saved file.";
|
||||||
|
}
|
||||||
|
|
||||||
|
OffscreenUi::asyncInformation(_dialogParent, "Success", infoMessage);
|
||||||
|
} else {
|
||||||
|
OffscreenUi::asyncWarning(_dialogParent, "Error", "Could not gzip JSON data for new entities file.");
|
||||||
}
|
}
|
||||||
|
|
||||||
OffscreenUi::information(_dialogParent, "Success", infoMessage);
|
|
||||||
} else {
|
} else {
|
||||||
OffscreenUi::warning(_dialogParent, "Error", "Could not gzip JSON data for new entities file.");
|
OffscreenUi::asyncWarning(_dialogParent, "Error",
|
||||||
|
QString("Could not open file at %1 to write new entities file to.").arg(saveName));
|
||||||
}
|
}
|
||||||
|
// reset after the attempted save, success or fail
|
||||||
} else {
|
reset();
|
||||||
OffscreenUi::warning(_dialogParent, "Error",
|
});
|
||||||
QString("Could not open file at %1 to write new entities file to.").arg(saveName));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ATPAssetMigrator::reset() {
|
void ATPAssetMigrator::reset() {
|
||||||
|
|
|
@ -3043,9 +3043,9 @@ glm::mat4 MyAvatar::getCenterEyeCalibrationMat() const {
|
||||||
if (rightEyeIndex >= 0 && leftEyeIndex >= 0) {
|
if (rightEyeIndex >= 0 && leftEyeIndex >= 0) {
|
||||||
auto centerEyePos = (getAbsoluteDefaultJointTranslationInObjectFrame(rightEyeIndex) + getAbsoluteDefaultJointTranslationInObjectFrame(leftEyeIndex)) * 0.5f;
|
auto centerEyePos = (getAbsoluteDefaultJointTranslationInObjectFrame(rightEyeIndex) + getAbsoluteDefaultJointTranslationInObjectFrame(leftEyeIndex)) * 0.5f;
|
||||||
auto centerEyeRot = Quaternions::Y_180;
|
auto centerEyeRot = Quaternions::Y_180;
|
||||||
return createMatFromQuatAndPos(centerEyeRot, centerEyePos);
|
return createMatFromQuatAndPos(centerEyeRot, centerEyePos / getSensorToWorldScale());
|
||||||
} else {
|
} else {
|
||||||
return createMatFromQuatAndPos(DEFAULT_AVATAR_MIDDLE_EYE_ROT, DEFAULT_AVATAR_MIDDLE_EYE_POS);
|
return createMatFromQuatAndPos(DEFAULT_AVATAR_MIDDLE_EYE_ROT, DEFAULT_AVATAR_MIDDLE_EYE_POS / getSensorToWorldScale());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3055,9 +3055,9 @@ glm::mat4 MyAvatar::getHeadCalibrationMat() const {
|
||||||
if (headIndex >= 0) {
|
if (headIndex >= 0) {
|
||||||
auto headPos = getAbsoluteDefaultJointTranslationInObjectFrame(headIndex);
|
auto headPos = getAbsoluteDefaultJointTranslationInObjectFrame(headIndex);
|
||||||
auto headRot = getAbsoluteDefaultJointRotationInObjectFrame(headIndex);
|
auto headRot = getAbsoluteDefaultJointRotationInObjectFrame(headIndex);
|
||||||
return createMatFromQuatAndPos(headRot, headPos);
|
return createMatFromQuatAndPos(headRot, headPos / getSensorToWorldScale());
|
||||||
} else {
|
} else {
|
||||||
return createMatFromQuatAndPos(DEFAULT_AVATAR_HEAD_ROT, DEFAULT_AVATAR_HEAD_POS);
|
return createMatFromQuatAndPos(DEFAULT_AVATAR_HEAD_ROT, DEFAULT_AVATAR_HEAD_POS / getSensorToWorldScale());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3067,9 +3067,9 @@ glm::mat4 MyAvatar::getSpine2CalibrationMat() const {
|
||||||
if (spine2Index >= 0) {
|
if (spine2Index >= 0) {
|
||||||
auto spine2Pos = getAbsoluteDefaultJointTranslationInObjectFrame(spine2Index);
|
auto spine2Pos = getAbsoluteDefaultJointTranslationInObjectFrame(spine2Index);
|
||||||
auto spine2Rot = getAbsoluteDefaultJointRotationInObjectFrame(spine2Index);
|
auto spine2Rot = getAbsoluteDefaultJointRotationInObjectFrame(spine2Index);
|
||||||
return createMatFromQuatAndPos(spine2Rot, spine2Pos);
|
return createMatFromQuatAndPos(spine2Rot, spine2Pos / getSensorToWorldScale());
|
||||||
} else {
|
} else {
|
||||||
return createMatFromQuatAndPos(DEFAULT_AVATAR_SPINE2_ROT, DEFAULT_AVATAR_SPINE2_POS);
|
return createMatFromQuatAndPos(DEFAULT_AVATAR_SPINE2_ROT, DEFAULT_AVATAR_SPINE2_POS / getSensorToWorldScale());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3079,9 +3079,9 @@ glm::mat4 MyAvatar::getHipsCalibrationMat() const {
|
||||||
if (hipsIndex >= 0) {
|
if (hipsIndex >= 0) {
|
||||||
auto hipsPos = getAbsoluteDefaultJointTranslationInObjectFrame(hipsIndex);
|
auto hipsPos = getAbsoluteDefaultJointTranslationInObjectFrame(hipsIndex);
|
||||||
auto hipsRot = getAbsoluteDefaultJointRotationInObjectFrame(hipsIndex);
|
auto hipsRot = getAbsoluteDefaultJointRotationInObjectFrame(hipsIndex);
|
||||||
return createMatFromQuatAndPos(hipsRot, hipsPos);
|
return createMatFromQuatAndPos(hipsRot, hipsPos / getSensorToWorldScale());
|
||||||
} else {
|
} else {
|
||||||
return createMatFromQuatAndPos(DEFAULT_AVATAR_HIPS_ROT, DEFAULT_AVATAR_HIPS_POS);
|
return createMatFromQuatAndPos(DEFAULT_AVATAR_HIPS_ROT, DEFAULT_AVATAR_HIPS_POS / getSensorToWorldScale());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3091,9 +3091,9 @@ glm::mat4 MyAvatar::getLeftFootCalibrationMat() const {
|
||||||
if (leftFootIndex >= 0) {
|
if (leftFootIndex >= 0) {
|
||||||
auto leftFootPos = getAbsoluteDefaultJointTranslationInObjectFrame(leftFootIndex);
|
auto leftFootPos = getAbsoluteDefaultJointTranslationInObjectFrame(leftFootIndex);
|
||||||
auto leftFootRot = getAbsoluteDefaultJointRotationInObjectFrame(leftFootIndex);
|
auto leftFootRot = getAbsoluteDefaultJointRotationInObjectFrame(leftFootIndex);
|
||||||
return createMatFromQuatAndPos(leftFootRot, leftFootPos);
|
return createMatFromQuatAndPos(leftFootRot, leftFootPos / getSensorToWorldScale());
|
||||||
} else {
|
} else {
|
||||||
return createMatFromQuatAndPos(DEFAULT_AVATAR_LEFTFOOT_ROT, DEFAULT_AVATAR_LEFTFOOT_POS);
|
return createMatFromQuatAndPos(DEFAULT_AVATAR_LEFTFOOT_ROT, DEFAULT_AVATAR_LEFTFOOT_POS / getSensorToWorldScale());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3103,9 +3103,9 @@ glm::mat4 MyAvatar::getRightFootCalibrationMat() const {
|
||||||
if (rightFootIndex >= 0) {
|
if (rightFootIndex >= 0) {
|
||||||
auto rightFootPos = getAbsoluteDefaultJointTranslationInObjectFrame(rightFootIndex);
|
auto rightFootPos = getAbsoluteDefaultJointTranslationInObjectFrame(rightFootIndex);
|
||||||
auto rightFootRot = getAbsoluteDefaultJointRotationInObjectFrame(rightFootIndex);
|
auto rightFootRot = getAbsoluteDefaultJointRotationInObjectFrame(rightFootIndex);
|
||||||
return createMatFromQuatAndPos(rightFootRot, rightFootPos);
|
return createMatFromQuatAndPos(rightFootRot, rightFootPos / getSensorToWorldScale());
|
||||||
} else {
|
} else {
|
||||||
return createMatFromQuatAndPos(DEFAULT_AVATAR_RIGHTFOOT_ROT, DEFAULT_AVATAR_RIGHTFOOT_POS);
|
return createMatFromQuatAndPos(DEFAULT_AVATAR_RIGHTFOOT_ROT, DEFAULT_AVATAR_RIGHTFOOT_POS / getSensorToWorldScale());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3115,9 +3115,9 @@ glm::mat4 MyAvatar::getRightArmCalibrationMat() const {
|
||||||
if (rightArmIndex >= 0) {
|
if (rightArmIndex >= 0) {
|
||||||
auto rightArmPos = getAbsoluteDefaultJointTranslationInObjectFrame(rightArmIndex);
|
auto rightArmPos = getAbsoluteDefaultJointTranslationInObjectFrame(rightArmIndex);
|
||||||
auto rightArmRot = getAbsoluteDefaultJointRotationInObjectFrame(rightArmIndex);
|
auto rightArmRot = getAbsoluteDefaultJointRotationInObjectFrame(rightArmIndex);
|
||||||
return createMatFromQuatAndPos(rightArmRot, rightArmPos);
|
return createMatFromQuatAndPos(rightArmRot, rightArmPos / getSensorToWorldScale());
|
||||||
} else {
|
} else {
|
||||||
return createMatFromQuatAndPos(DEFAULT_AVATAR_RIGHTARM_ROT, DEFAULT_AVATAR_RIGHTARM_POS);
|
return createMatFromQuatAndPos(DEFAULT_AVATAR_RIGHTARM_ROT, DEFAULT_AVATAR_RIGHTARM_POS / getSensorToWorldScale());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3126,9 +3126,9 @@ glm::mat4 MyAvatar::getLeftArmCalibrationMat() const {
|
||||||
if (leftArmIndex >= 0) {
|
if (leftArmIndex >= 0) {
|
||||||
auto leftArmPos = getAbsoluteDefaultJointTranslationInObjectFrame(leftArmIndex);
|
auto leftArmPos = getAbsoluteDefaultJointTranslationInObjectFrame(leftArmIndex);
|
||||||
auto leftArmRot = getAbsoluteDefaultJointRotationInObjectFrame(leftArmIndex);
|
auto leftArmRot = getAbsoluteDefaultJointRotationInObjectFrame(leftArmIndex);
|
||||||
return createMatFromQuatAndPos(leftArmRot, leftArmPos);
|
return createMatFromQuatAndPos(leftArmRot, leftArmPos / getSensorToWorldScale());
|
||||||
} else {
|
} else {
|
||||||
return createMatFromQuatAndPos(DEFAULT_AVATAR_LEFTARM_ROT, DEFAULT_AVATAR_LEFTARM_POS);
|
return createMatFromQuatAndPos(DEFAULT_AVATAR_LEFTARM_ROT, DEFAULT_AVATAR_LEFTARM_POS / getSensorToWorldScale());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3137,9 +3137,9 @@ glm::mat4 MyAvatar::getRightHandCalibrationMat() const {
|
||||||
if (rightHandIndex >= 0) {
|
if (rightHandIndex >= 0) {
|
||||||
auto rightHandPos = getAbsoluteDefaultJointTranslationInObjectFrame(rightHandIndex);
|
auto rightHandPos = getAbsoluteDefaultJointTranslationInObjectFrame(rightHandIndex);
|
||||||
auto rightHandRot = getAbsoluteDefaultJointRotationInObjectFrame(rightHandIndex);
|
auto rightHandRot = getAbsoluteDefaultJointRotationInObjectFrame(rightHandIndex);
|
||||||
return createMatFromQuatAndPos(rightHandRot, rightHandPos);
|
return createMatFromQuatAndPos(rightHandRot, rightHandPos / getSensorToWorldScale());
|
||||||
} else {
|
} else {
|
||||||
return createMatFromQuatAndPos(DEFAULT_AVATAR_RIGHTHAND_ROT, DEFAULT_AVATAR_RIGHTHAND_POS);
|
return createMatFromQuatAndPos(DEFAULT_AVATAR_RIGHTHAND_ROT, DEFAULT_AVATAR_RIGHTHAND_POS / getSensorToWorldScale());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3148,9 +3148,9 @@ glm::mat4 MyAvatar::getLeftHandCalibrationMat() const {
|
||||||
if (leftHandIndex >= 0) {
|
if (leftHandIndex >= 0) {
|
||||||
auto leftHandPos = getAbsoluteDefaultJointTranslationInObjectFrame(leftHandIndex);
|
auto leftHandPos = getAbsoluteDefaultJointTranslationInObjectFrame(leftHandIndex);
|
||||||
auto leftHandRot = getAbsoluteDefaultJointRotationInObjectFrame(leftHandIndex);
|
auto leftHandRot = getAbsoluteDefaultJointRotationInObjectFrame(leftHandIndex);
|
||||||
return createMatFromQuatAndPos(leftHandRot, leftHandPos);
|
return createMatFromQuatAndPos(leftHandRot, leftHandPos / getSensorToWorldScale());
|
||||||
} else {
|
} else {
|
||||||
return createMatFromQuatAndPos(DEFAULT_AVATAR_LEFTHAND_ROT, DEFAULT_AVATAR_LEFTHAND_POS);
|
return createMatFromQuatAndPos(DEFAULT_AVATAR_LEFTHAND_ROT, DEFAULT_AVATAR_LEFTHAND_POS / getSensorToWorldScale());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -92,8 +92,7 @@ void LaserPointer::updateRenderStateOverlay(const OverlayID& id, const QVariant&
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void LaserPointer::updateRenderState(const RenderState& renderState, const IntersectionType type, const float distance, const QUuid& objectID, const bool defaultState) {
|
void LaserPointer::updateRenderState(const RenderState& renderState, const IntersectionType type, const float distance, const QUuid& objectID, const PickRay& pickRay, const bool defaultState) {
|
||||||
PickRay pickRay = qApp->getRayPickManager().getPickRay(_rayPickUID);
|
|
||||||
if (!renderState.getStartID().isNull()) {
|
if (!renderState.getStartID().isNull()) {
|
||||||
QVariantMap startProps;
|
QVariantMap startProps;
|
||||||
startProps.insert("position", vec3toVariant(pickRay.origin));
|
startProps.insert("position", vec3toVariant(pickRay.origin));
|
||||||
|
@ -185,12 +184,14 @@ void LaserPointer::disableRenderState(const RenderState& renderState) {
|
||||||
|
|
||||||
void LaserPointer::update() {
|
void LaserPointer::update() {
|
||||||
RayPickResult prevRayPickResult = DependencyManager::get<RayPickScriptingInterface>()->getPrevRayPickResult(_rayPickUID);
|
RayPickResult prevRayPickResult = DependencyManager::get<RayPickScriptingInterface>()->getPrevRayPickResult(_rayPickUID);
|
||||||
if (_renderingEnabled && !_currentRenderState.empty() && _renderStates.find(_currentRenderState) != _renderStates.end() && prevRayPickResult.type != IntersectionType::NONE) {
|
if (_renderingEnabled && !_currentRenderState.empty() && _renderStates.find(_currentRenderState) != _renderStates.end() &&
|
||||||
updateRenderState(_renderStates[_currentRenderState], prevRayPickResult.type, prevRayPickResult.distance, prevRayPickResult.objectID, false);
|
(prevRayPickResult.type != IntersectionType::NONE || _laserLength > 0.0f || !_objectLockEnd.first.isNull())) {
|
||||||
|
float distance = _laserLength > 0.0f ? _laserLength : prevRayPickResult.distance;
|
||||||
|
updateRenderState(_renderStates[_currentRenderState], prevRayPickResult.type, distance, prevRayPickResult.objectID, prevRayPickResult.searchRay, false);
|
||||||
disableRenderState(_defaultRenderStates[_currentRenderState].second);
|
disableRenderState(_defaultRenderStates[_currentRenderState].second);
|
||||||
} else if (_renderingEnabled && !_currentRenderState.empty() && _defaultRenderStates.find(_currentRenderState) != _defaultRenderStates.end()) {
|
} else if (_renderingEnabled && !_currentRenderState.empty() && _defaultRenderStates.find(_currentRenderState) != _defaultRenderStates.end()) {
|
||||||
disableRenderState(_renderStates[_currentRenderState]);
|
disableRenderState(_renderStates[_currentRenderState]);
|
||||||
updateRenderState(_defaultRenderStates[_currentRenderState].second, IntersectionType::NONE, _defaultRenderStates[_currentRenderState].first, QUuid(), true);
|
updateRenderState(_defaultRenderStates[_currentRenderState].second, IntersectionType::NONE, _defaultRenderStates[_currentRenderState].first, QUuid(), prevRayPickResult.searchRay, true);
|
||||||
} else if (!_currentRenderState.empty()) {
|
} else if (!_currentRenderState.empty()) {
|
||||||
disableRenderState(_renderStates[_currentRenderState]);
|
disableRenderState(_renderStates[_currentRenderState]);
|
||||||
disableRenderState(_defaultRenderStates[_currentRenderState].second);
|
disableRenderState(_defaultRenderStates[_currentRenderState].second);
|
||||||
|
|
|
@ -65,6 +65,7 @@ public:
|
||||||
void editRenderState(const std::string& state, const QVariant& startProps, const QVariant& pathProps, const QVariant& endProps);
|
void editRenderState(const std::string& state, const QVariant& startProps, const QVariant& pathProps, const QVariant& endProps);
|
||||||
|
|
||||||
void setPrecisionPicking(const bool precisionPicking) { DependencyManager::get<RayPickScriptingInterface>()->setPrecisionPicking(_rayPickUID, precisionPicking); }
|
void setPrecisionPicking(const bool precisionPicking) { DependencyManager::get<RayPickScriptingInterface>()->setPrecisionPicking(_rayPickUID, precisionPicking); }
|
||||||
|
void setLaserLength(const float laserLength) { _laserLength = laserLength; }
|
||||||
void setIgnoreEntities(const QScriptValue& ignoreEntities) { DependencyManager::get<RayPickScriptingInterface>()->setIgnoreEntities(_rayPickUID, ignoreEntities); }
|
void setIgnoreEntities(const QScriptValue& ignoreEntities) { DependencyManager::get<RayPickScriptingInterface>()->setIgnoreEntities(_rayPickUID, ignoreEntities); }
|
||||||
void setIncludeEntities(const QScriptValue& includeEntities) { DependencyManager::get<RayPickScriptingInterface>()->setIncludeEntities(_rayPickUID, includeEntities); }
|
void setIncludeEntities(const QScriptValue& includeEntities) { DependencyManager::get<RayPickScriptingInterface>()->setIncludeEntities(_rayPickUID, includeEntities); }
|
||||||
void setIgnoreOverlays(const QScriptValue& ignoreOverlays) { DependencyManager::get<RayPickScriptingInterface>()->setIgnoreOverlays(_rayPickUID, ignoreOverlays); }
|
void setIgnoreOverlays(const QScriptValue& ignoreOverlays) { DependencyManager::get<RayPickScriptingInterface>()->setIgnoreOverlays(_rayPickUID, ignoreOverlays); }
|
||||||
|
@ -78,6 +79,7 @@ public:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool _renderingEnabled;
|
bool _renderingEnabled;
|
||||||
|
float _laserLength { 0.0f };
|
||||||
std::string _currentRenderState { "" };
|
std::string _currentRenderState { "" };
|
||||||
RenderStateMap _renderStates;
|
RenderStateMap _renderStates;
|
||||||
DefaultRenderStateMap _defaultRenderStates;
|
DefaultRenderStateMap _defaultRenderStates;
|
||||||
|
@ -89,7 +91,7 @@ private:
|
||||||
QUuid _rayPickUID;
|
QUuid _rayPickUID;
|
||||||
|
|
||||||
void updateRenderStateOverlay(const OverlayID& id, const QVariant& props);
|
void updateRenderStateOverlay(const OverlayID& id, const QVariant& props);
|
||||||
void updateRenderState(const RenderState& renderState, const IntersectionType type, const float distance, const QUuid& objectID, const bool defaultState);
|
void updateRenderState(const RenderState& renderState, const IntersectionType type, const float distance, const QUuid& objectID, const PickRay& pickRay, const bool defaultState);
|
||||||
void disableRenderState(const RenderState& renderState);
|
void disableRenderState(const RenderState& renderState);
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -14,17 +14,19 @@ QUuid LaserPointerManager::createLaserPointer(const QVariant& rayProps, const La
|
||||||
const bool faceAvatar, const bool centerEndY, const bool lockEnd, const bool enabled) {
|
const bool faceAvatar, const bool centerEndY, const bool lockEnd, const bool enabled) {
|
||||||
std::shared_ptr<LaserPointer> laserPointer = std::make_shared<LaserPointer>(rayProps, renderStates, defaultRenderStates, faceAvatar, centerEndY, lockEnd, enabled);
|
std::shared_ptr<LaserPointer> laserPointer = std::make_shared<LaserPointer>(rayProps, renderStates, defaultRenderStates, faceAvatar, centerEndY, lockEnd, enabled);
|
||||||
if (!laserPointer->getRayUID().isNull()) {
|
if (!laserPointer->getRayUID().isNull()) {
|
||||||
QWriteLocker lock(&_addLock);
|
QWriteLocker containsLock(&_containsLock);
|
||||||
QUuid id = QUuid::createUuid();
|
QUuid id = QUuid::createUuid();
|
||||||
_laserPointersToAdd.push(std::pair<QUuid, std::shared_ptr<LaserPointer>>(id, laserPointer));
|
_laserPointers[id] = laserPointer;
|
||||||
|
_laserPointerLocks[id] = std::make_shared<QReadWriteLock>();
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
return QUuid();
|
return QUuid();
|
||||||
}
|
}
|
||||||
|
|
||||||
void LaserPointerManager::removeLaserPointer(const QUuid uid) {
|
void LaserPointerManager::removeLaserPointer(const QUuid uid) {
|
||||||
QWriteLocker lock(&_removeLock);
|
QWriteLocker lock(&_containsLock);
|
||||||
_laserPointersToRemove.push(uid);
|
_laserPointers.remove(uid);
|
||||||
|
_laserPointerLocks.remove(uid);
|
||||||
}
|
}
|
||||||
|
|
||||||
void LaserPointerManager::enableLaserPointer(const QUuid uid) {
|
void LaserPointerManager::enableLaserPointer(const QUuid uid) {
|
||||||
|
@ -69,32 +71,12 @@ const RayPickResult LaserPointerManager::getPrevRayPickResult(const QUuid uid) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void LaserPointerManager::update() {
|
void LaserPointerManager::update() {
|
||||||
|
QReadLocker lock(&_containsLock);
|
||||||
for (QUuid& uid : _laserPointers.keys()) {
|
for (QUuid& uid : _laserPointers.keys()) {
|
||||||
// This only needs to be a read lock because update won't change any of the properties that can be modified from scripts
|
// This only needs to be a read lock because update won't change any of the properties that can be modified from scripts
|
||||||
QReadLocker laserLock(_laserPointerLocks[uid].get());
|
QReadLocker laserLock(_laserPointerLocks[uid].get());
|
||||||
_laserPointers[uid]->update();
|
_laserPointers[uid]->update();
|
||||||
}
|
}
|
||||||
|
|
||||||
QWriteLocker containsLock(&_containsLock);
|
|
||||||
{
|
|
||||||
QWriteLocker lock(&_addLock);
|
|
||||||
while (!_laserPointersToAdd.empty()) {
|
|
||||||
std::pair<QUuid, std::shared_ptr<LaserPointer>> laserPointerToAdd = _laserPointersToAdd.front();
|
|
||||||
_laserPointersToAdd.pop();
|
|
||||||
_laserPointers[laserPointerToAdd.first] = laserPointerToAdd.second;
|
|
||||||
_laserPointerLocks[laserPointerToAdd.first] = std::make_shared<QReadWriteLock>();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
QWriteLocker lock(&_removeLock);
|
|
||||||
while (!_laserPointersToRemove.empty()) {
|
|
||||||
QUuid uid = _laserPointersToRemove.front();
|
|
||||||
_laserPointersToRemove.pop();
|
|
||||||
_laserPointers.remove(uid);
|
|
||||||
_laserPointerLocks.remove(uid);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void LaserPointerManager::setPrecisionPicking(QUuid uid, const bool precisionPicking) {
|
void LaserPointerManager::setPrecisionPicking(QUuid uid, const bool precisionPicking) {
|
||||||
|
@ -105,6 +87,14 @@ void LaserPointerManager::setPrecisionPicking(QUuid uid, const bool precisionPic
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void LaserPointerManager::setLaserLength(QUuid uid, const float laserLength) {
|
||||||
|
QReadLocker lock(&_containsLock);
|
||||||
|
if (_laserPointers.contains(uid)) {
|
||||||
|
QWriteLocker laserLock(_laserPointerLocks[uid].get());
|
||||||
|
_laserPointers[uid]->setLaserLength(laserLength);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void LaserPointerManager::setIgnoreEntities(QUuid uid, const QScriptValue& ignoreEntities) {
|
void LaserPointerManager::setIgnoreEntities(QUuid uid, const QScriptValue& ignoreEntities) {
|
||||||
QReadLocker lock(&_containsLock);
|
QReadLocker lock(&_containsLock);
|
||||||
if (_laserPointers.contains(uid)) {
|
if (_laserPointers.contains(uid)) {
|
||||||
|
|
|
@ -32,6 +32,7 @@ public:
|
||||||
const RayPickResult getPrevRayPickResult(const QUuid uid);
|
const RayPickResult getPrevRayPickResult(const QUuid uid);
|
||||||
|
|
||||||
void setPrecisionPicking(QUuid uid, const bool precisionPicking);
|
void setPrecisionPicking(QUuid uid, const bool precisionPicking);
|
||||||
|
void setLaserLength(QUuid uid, const float laserLength);
|
||||||
void setIgnoreEntities(QUuid uid, const QScriptValue& ignoreEntities);
|
void setIgnoreEntities(QUuid uid, const QScriptValue& ignoreEntities);
|
||||||
void setIncludeEntities(QUuid uid, const QScriptValue& includeEntities);
|
void setIncludeEntities(QUuid uid, const QScriptValue& includeEntities);
|
||||||
void setIgnoreOverlays(QUuid uid, const QScriptValue& ignoreOverlays);
|
void setIgnoreOverlays(QUuid uid, const QScriptValue& ignoreOverlays);
|
||||||
|
@ -46,10 +47,6 @@ public:
|
||||||
private:
|
private:
|
||||||
QHash<QUuid, std::shared_ptr<LaserPointer>> _laserPointers;
|
QHash<QUuid, std::shared_ptr<LaserPointer>> _laserPointers;
|
||||||
QHash<QUuid, std::shared_ptr<QReadWriteLock>> _laserPointerLocks;
|
QHash<QUuid, std::shared_ptr<QReadWriteLock>> _laserPointerLocks;
|
||||||
QReadWriteLock _addLock;
|
|
||||||
std::queue<std::pair<QUuid, std::shared_ptr<LaserPointer>>> _laserPointersToAdd;
|
|
||||||
QReadWriteLock _removeLock;
|
|
||||||
std::queue<QUuid> _laserPointersToRemove;
|
|
||||||
QReadWriteLock _containsLock;
|
QReadWriteLock _containsLock;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -31,6 +31,7 @@ public slots:
|
||||||
Q_INVOKABLE RayPickResult getPrevRayPickResult(QUuid uid) { return qApp->getLaserPointerManager().getPrevRayPickResult(uid); }
|
Q_INVOKABLE RayPickResult getPrevRayPickResult(QUuid uid) { return qApp->getLaserPointerManager().getPrevRayPickResult(uid); }
|
||||||
|
|
||||||
Q_INVOKABLE void setPrecisionPicking(QUuid uid, const bool precisionPicking) { qApp->getLaserPointerManager().setPrecisionPicking(uid, precisionPicking); }
|
Q_INVOKABLE void setPrecisionPicking(QUuid uid, const bool precisionPicking) { qApp->getLaserPointerManager().setPrecisionPicking(uid, precisionPicking); }
|
||||||
|
Q_INVOKABLE void setLaserLength(QUuid uid, const float laserLength) { qApp->getLaserPointerManager().setLaserLength(uid, laserLength); }
|
||||||
Q_INVOKABLE void setIgnoreEntities(QUuid uid, const QScriptValue& ignoreEntities) { qApp->getLaserPointerManager().setIgnoreEntities(uid, ignoreEntities); }
|
Q_INVOKABLE void setIgnoreEntities(QUuid uid, const QScriptValue& ignoreEntities) { qApp->getLaserPointerManager().setIgnoreEntities(uid, ignoreEntities); }
|
||||||
Q_INVOKABLE void setIncludeEntities(QUuid uid, const QScriptValue& includeEntities) { qApp->getLaserPointerManager().setIncludeEntities(uid, includeEntities); }
|
Q_INVOKABLE void setIncludeEntities(QUuid uid, const QScriptValue& includeEntities) { qApp->getLaserPointerManager().setIncludeEntities(uid, includeEntities); }
|
||||||
Q_INVOKABLE void setIgnoreOverlays(QUuid uid, const QScriptValue& ignoreOverlays) { qApp->getLaserPointerManager().setIgnoreOverlays(uid, ignoreOverlays); }
|
Q_INVOKABLE void setIgnoreOverlays(QUuid uid, const QScriptValue& ignoreOverlays) { qApp->getLaserPointerManager().setIgnoreOverlays(uid, ignoreOverlays); }
|
||||||
|
|
|
@ -70,6 +70,9 @@ public:
|
||||||
if (doesPickNonCollidable()) {
|
if (doesPickNonCollidable()) {
|
||||||
toReturn |= getBitMask(PICK_INCLUDE_NONCOLLIDABLE);
|
toReturn |= getBitMask(PICK_INCLUDE_NONCOLLIDABLE);
|
||||||
}
|
}
|
||||||
|
if (doesPickCourse()) {
|
||||||
|
toReturn |= getBitMask(PICK_COURSE);
|
||||||
|
}
|
||||||
return Flags(toReturn);
|
return Flags(toReturn);
|
||||||
}
|
}
|
||||||
Flags getOverlayFlags() const {
|
Flags getOverlayFlags() const {
|
||||||
|
@ -80,6 +83,9 @@ public:
|
||||||
if (doesPickNonCollidable()) {
|
if (doesPickNonCollidable()) {
|
||||||
toReturn |= getBitMask(PICK_INCLUDE_NONCOLLIDABLE);
|
toReturn |= getBitMask(PICK_INCLUDE_NONCOLLIDABLE);
|
||||||
}
|
}
|
||||||
|
if (doesPickCourse()) {
|
||||||
|
toReturn |= getBitMask(PICK_COURSE);
|
||||||
|
}
|
||||||
return Flags(toReturn);
|
return Flags(toReturn);
|
||||||
}
|
}
|
||||||
Flags getAvatarFlags() const { return Flags(getBitMask(PICK_AVATARS)); }
|
Flags getAvatarFlags() const { return Flags(getBitMask(PICK_AVATARS)); }
|
||||||
|
|
|
@ -38,11 +38,12 @@ void RayPickManager::cacheResult(const bool intersects, const RayPickResult& res
|
||||||
res = resTemp;
|
res = resTemp;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
cache[ray][mask] = RayPickResult();
|
cache[ray][mask] = RayPickResult(res.searchRay);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void RayPickManager::update() {
|
void RayPickManager::update() {
|
||||||
|
QReadLocker lock(&_containsLock);
|
||||||
RayPickCache results;
|
RayPickCache results;
|
||||||
for (auto& uid : _rayPicks.keys()) {
|
for (auto& uid : _rayPicks.keys()) {
|
||||||
std::shared_ptr<RayPick> rayPick = _rayPicks[uid];
|
std::shared_ptr<RayPick> rayPick = _rayPicks[uid];
|
||||||
|
@ -58,7 +59,7 @@ void RayPickManager::update() {
|
||||||
}
|
}
|
||||||
|
|
||||||
QPair<glm::vec3, glm::vec3> rayKey = QPair<glm::vec3, glm::vec3>(ray.origin, ray.direction);
|
QPair<glm::vec3, glm::vec3> rayKey = QPair<glm::vec3, glm::vec3>(ray.origin, ray.direction);
|
||||||
RayPickResult res;
|
RayPickResult res = RayPickResult(ray);
|
||||||
|
|
||||||
if (rayPick->getFilter().doesPickEntities()) {
|
if (rayPick->getFilter().doesPickEntities()) {
|
||||||
RayToEntityIntersectionResult entityRes;
|
RayToEntityIntersectionResult entityRes;
|
||||||
|
@ -73,7 +74,7 @@ void RayPickManager::update() {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!fromCache) {
|
if (!fromCache) {
|
||||||
cacheResult(entityRes.intersects, RayPickResult(IntersectionType::ENTITY, entityRes.entityID, entityRes.distance, entityRes.intersection, entityRes.surfaceNormal),
|
cacheResult(entityRes.intersects, RayPickResult(IntersectionType::ENTITY, entityRes.entityID, entityRes.distance, entityRes.intersection, ray, entityRes.surfaceNormal),
|
||||||
entityMask, res, rayKey, results);
|
entityMask, res, rayKey, results);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -91,7 +92,7 @@ void RayPickManager::update() {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!fromCache) {
|
if (!fromCache) {
|
||||||
cacheResult(overlayRes.intersects, RayPickResult(IntersectionType::OVERLAY, overlayRes.overlayID, overlayRes.distance, overlayRes.intersection, overlayRes.surfaceNormal),
|
cacheResult(overlayRes.intersects, RayPickResult(IntersectionType::OVERLAY, overlayRes.overlayID, overlayRes.distance, overlayRes.intersection, ray, overlayRes.surfaceNormal),
|
||||||
overlayMask, res, rayKey, results);
|
overlayMask, res, rayKey, results);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -100,7 +101,7 @@ void RayPickManager::update() {
|
||||||
RayPickFilter::Flags avatarMask = rayPick->getFilter().getAvatarFlags();
|
RayPickFilter::Flags avatarMask = rayPick->getFilter().getAvatarFlags();
|
||||||
if (!checkAndCompareCachedResults(rayKey, results, res, avatarMask)) {
|
if (!checkAndCompareCachedResults(rayKey, results, res, avatarMask)) {
|
||||||
RayToAvatarIntersectionResult avatarRes = DependencyManager::get<AvatarManager>()->findRayIntersectionVector(ray, rayPick->getIncludeAvatars(), rayPick->getIgnoreAvatars());
|
RayToAvatarIntersectionResult avatarRes = DependencyManager::get<AvatarManager>()->findRayIntersectionVector(ray, rayPick->getIncludeAvatars(), rayPick->getIgnoreAvatars());
|
||||||
cacheResult(avatarRes.intersects, RayPickResult(IntersectionType::AVATAR, avatarRes.avatarID, avatarRes.distance, avatarRes.intersection), avatarMask, res, rayKey, results);
|
cacheResult(avatarRes.intersects, RayPickResult(IntersectionType::AVATAR, avatarRes.avatarID, avatarRes.distance, avatarRes.intersection, ray), avatarMask, res, rayKey, results);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -109,7 +110,7 @@ void RayPickManager::update() {
|
||||||
RayPickFilter::Flags hudMask = rayPick->getFilter().getHUDFlags();
|
RayPickFilter::Flags hudMask = rayPick->getFilter().getHUDFlags();
|
||||||
if (!checkAndCompareCachedResults(rayKey, results, res, hudMask)) {
|
if (!checkAndCompareCachedResults(rayKey, results, res, hudMask)) {
|
||||||
glm::vec3 hudRes = DependencyManager::get<HMDScriptingInterface>()->calculateRayUICollisionPoint(ray.origin, ray.direction);
|
glm::vec3 hudRes = DependencyManager::get<HMDScriptingInterface>()->calculateRayUICollisionPoint(ray.origin, ray.direction);
|
||||||
cacheResult(true, RayPickResult(IntersectionType::HUD, 0, glm::distance(ray.origin, hudRes), hudRes), hudMask, res, rayKey, results);
|
cacheResult(true, RayPickResult(IntersectionType::HUD, 0, glm::distance(ray.origin, hudRes), hudRes, ray), hudMask, res, rayKey, results);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -117,56 +118,39 @@ void RayPickManager::update() {
|
||||||
if (rayPick->getMaxDistance() == 0.0f || (rayPick->getMaxDistance() > 0.0f && res.distance < rayPick->getMaxDistance())) {
|
if (rayPick->getMaxDistance() == 0.0f || (rayPick->getMaxDistance() > 0.0f && res.distance < rayPick->getMaxDistance())) {
|
||||||
rayPick->setRayPickResult(res);
|
rayPick->setRayPickResult(res);
|
||||||
} else {
|
} else {
|
||||||
rayPick->setRayPickResult(RayPickResult());
|
rayPick->setRayPickResult(RayPickResult(ray));
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
QWriteLocker containsLock(&_containsLock);
|
|
||||||
{
|
|
||||||
QWriteLocker lock(&_addLock);
|
|
||||||
while (!_rayPicksToAdd.empty()) {
|
|
||||||
std::pair<QUuid, std::shared_ptr<RayPick>> rayPickToAdd = _rayPicksToAdd.front();
|
|
||||||
_rayPicksToAdd.pop();
|
|
||||||
_rayPicks[rayPickToAdd.first] = rayPickToAdd.second;
|
|
||||||
_rayPickLocks[rayPickToAdd.first] = std::make_shared<QReadWriteLock>();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
QWriteLocker lock(&_removeLock);
|
|
||||||
while (!_rayPicksToRemove.empty()) {
|
|
||||||
QUuid uid = _rayPicksToRemove.front();
|
|
||||||
_rayPicksToRemove.pop();
|
|
||||||
_rayPicks.remove(uid);
|
|
||||||
_rayPickLocks.remove(uid);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
QUuid RayPickManager::createRayPick(const std::string& jointName, const glm::vec3& posOffset, const glm::vec3& dirOffset, const RayPickFilter& filter, const float maxDistance, const bool enabled) {
|
QUuid RayPickManager::createRayPick(const std::string& jointName, const glm::vec3& posOffset, const glm::vec3& dirOffset, const RayPickFilter& filter, const float maxDistance, const bool enabled) {
|
||||||
QWriteLocker lock(&_addLock);
|
QWriteLocker lock(&_containsLock);
|
||||||
QUuid id = QUuid::createUuid();
|
QUuid id = QUuid::createUuid();
|
||||||
_rayPicksToAdd.push(std::pair<QUuid, std::shared_ptr<RayPick>>(id, std::make_shared<JointRayPick>(jointName, posOffset, dirOffset, filter, maxDistance, enabled)));
|
_rayPicks[id] = std::make_shared<JointRayPick>(jointName, posOffset, dirOffset, filter, maxDistance, enabled);
|
||||||
|
_rayPickLocks[id] = std::make_shared<QReadWriteLock>();
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
QUuid RayPickManager::createRayPick(const RayPickFilter& filter, const float maxDistance, const bool enabled) {
|
QUuid RayPickManager::createRayPick(const RayPickFilter& filter, const float maxDistance, const bool enabled) {
|
||||||
QWriteLocker lock(&_addLock);
|
QWriteLocker lock(&_containsLock);
|
||||||
QUuid id = QUuid::createUuid();
|
QUuid id = QUuid::createUuid();
|
||||||
_rayPicksToAdd.push(std::pair<QUuid, std::shared_ptr<RayPick>>(id, std::make_shared<MouseRayPick>(filter, maxDistance, enabled)));
|
_rayPicks[id] = std::make_shared<MouseRayPick>(filter, maxDistance, enabled);
|
||||||
|
_rayPickLocks[id] = std::make_shared<QReadWriteLock>();
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
QUuid RayPickManager::createRayPick(const glm::vec3& position, const glm::vec3& direction, const RayPickFilter& filter, const float maxDistance, const bool enabled) {
|
QUuid RayPickManager::createRayPick(const glm::vec3& position, const glm::vec3& direction, const RayPickFilter& filter, const float maxDistance, const bool enabled) {
|
||||||
QWriteLocker lock(&_addLock);
|
QWriteLocker lock(&_containsLock);
|
||||||
QUuid id = QUuid::createUuid();
|
QUuid id = QUuid::createUuid();
|
||||||
_rayPicksToAdd.push(std::pair<QUuid, std::shared_ptr<RayPick>>(id, std::make_shared<StaticRayPick>(position, direction, filter, maxDistance, enabled)));
|
_rayPicks[id] = std::make_shared<StaticRayPick>(position, direction, filter, maxDistance, enabled);
|
||||||
|
_rayPickLocks[id] = std::make_shared<QReadWriteLock>();
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
void RayPickManager::removeRayPick(const QUuid uid) {
|
void RayPickManager::removeRayPick(const QUuid uid) {
|
||||||
QWriteLocker lock(&_removeLock);
|
QWriteLocker lock(&_containsLock);
|
||||||
_rayPicksToRemove.push(uid);
|
_rayPicks.remove(uid);
|
||||||
|
_rayPickLocks.remove(uid);
|
||||||
}
|
}
|
||||||
|
|
||||||
void RayPickManager::enableRayPick(const QUuid uid) {
|
void RayPickManager::enableRayPick(const QUuid uid) {
|
||||||
|
@ -185,18 +169,6 @@ void RayPickManager::disableRayPick(const QUuid uid) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const PickRay RayPickManager::getPickRay(const QUuid uid) {
|
|
||||||
QReadLocker containsLock(&_containsLock);
|
|
||||||
if (_rayPicks.contains(uid)) {
|
|
||||||
bool valid;
|
|
||||||
PickRay pickRay = _rayPicks[uid]->getPickRay(valid);
|
|
||||||
if (valid) {
|
|
||||||
return pickRay;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return PickRay();
|
|
||||||
}
|
|
||||||
|
|
||||||
const RayPickResult RayPickManager::getPrevRayPickResult(const QUuid uid) {
|
const RayPickResult RayPickManager::getPrevRayPickResult(const QUuid uid) {
|
||||||
QReadLocker containsLock(&_containsLock);
|
QReadLocker containsLock(&_containsLock);
|
||||||
if (_rayPicks.contains(uid)) {
|
if (_rayPicks.contains(uid)) {
|
||||||
|
|
|
@ -28,7 +28,6 @@ class RayPickManager {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
void update();
|
void update();
|
||||||
const PickRay getPickRay(const QUuid uid);
|
|
||||||
|
|
||||||
QUuid createRayPick(const std::string& jointName, const glm::vec3& posOffset, const glm::vec3& dirOffset, const RayPickFilter& filter, const float maxDistance, const bool enabled);
|
QUuid createRayPick(const std::string& jointName, const glm::vec3& posOffset, const glm::vec3& dirOffset, const RayPickFilter& filter, const float maxDistance, const bool enabled);
|
||||||
QUuid createRayPick(const RayPickFilter& filter, const float maxDistance, const bool enabled);
|
QUuid createRayPick(const RayPickFilter& filter, const float maxDistance, const bool enabled);
|
||||||
|
@ -49,10 +48,6 @@ public:
|
||||||
private:
|
private:
|
||||||
QHash<QUuid, std::shared_ptr<RayPick>> _rayPicks;
|
QHash<QUuid, std::shared_ptr<RayPick>> _rayPicks;
|
||||||
QHash<QUuid, std::shared_ptr<QReadWriteLock>> _rayPickLocks;
|
QHash<QUuid, std::shared_ptr<QReadWriteLock>> _rayPickLocks;
|
||||||
QReadWriteLock _addLock;
|
|
||||||
std::queue<std::pair<QUuid, std::shared_ptr<RayPick>>> _rayPicksToAdd;
|
|
||||||
QReadWriteLock _removeLock;
|
|
||||||
std::queue<QUuid> _rayPicksToRemove;
|
|
||||||
QReadWriteLock _containsLock;
|
QReadWriteLock _containsLock;
|
||||||
|
|
||||||
typedef QHash<QPair<glm::vec3, glm::vec3>, std::unordered_map<RayPickFilter::Flags, RayPickResult>> RayPickCache;
|
typedef QHash<QPair<glm::vec3, glm::vec3>, std::unordered_map<RayPickFilter::Flags, RayPickResult>> RayPickCache;
|
||||||
|
|
|
@ -59,7 +59,7 @@ WindowScriptingInterface::WindowScriptingInterface() {
|
||||||
QUrl url(urlString);
|
QUrl url(urlString);
|
||||||
emit svoImportRequested(url.url());
|
emit svoImportRequested(url.url());
|
||||||
} else {
|
} else {
|
||||||
OffscreenUi::warning("Import SVO Error", "You need to be running edit.js to import entities.");
|
OffscreenUi::asyncWarning("Import SVO Error", "You need to be running edit.js to import entities.");
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -103,7 +103,7 @@ void WindowScriptingInterface::raiseMainWindow() {
|
||||||
/// \param const QString& message message to display
|
/// \param const QString& message message to display
|
||||||
/// \return QScriptValue::UndefinedValue
|
/// \return QScriptValue::UndefinedValue
|
||||||
void WindowScriptingInterface::alert(const QString& message) {
|
void WindowScriptingInterface::alert(const QString& message) {
|
||||||
OffscreenUi::warning("", message);
|
OffscreenUi::asyncWarning("", message);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Display a confirmation box with the options 'Yes' and 'No'
|
/// Display a confirmation box with the options 'Yes' and 'No'
|
||||||
|
@ -123,6 +123,17 @@ QScriptValue WindowScriptingInterface::prompt(const QString& message, const QStr
|
||||||
return ok ? QScriptValue(result) : QScriptValue::NullValue;
|
return ok ? QScriptValue(result) : QScriptValue::NullValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Display a prompt with a text box
|
||||||
|
/// \param const QString& message message to display
|
||||||
|
/// \param const QString& defaultText default text in the text box
|
||||||
|
void WindowScriptingInterface::promptAsync(const QString& message, const QString& defaultText) {
|
||||||
|
ModalDialogListener* dlg = OffscreenUi::getTextAsync(nullptr, "", message, QLineEdit::Normal, defaultText);
|
||||||
|
connect(dlg, &ModalDialogListener::response, this, [=] (QVariant result) {
|
||||||
|
disconnect(dlg, &ModalDialogListener::response, this, nullptr);
|
||||||
|
emit promptTextChanged(result.toString());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
CustomPromptResult WindowScriptingInterface::customPrompt(const QVariant& config) {
|
CustomPromptResult WindowScriptingInterface::customPrompt(const QVariant& config) {
|
||||||
CustomPromptResult result;
|
CustomPromptResult result;
|
||||||
bool ok = false;
|
bool ok = false;
|
||||||
|
@ -191,8 +202,31 @@ QScriptValue WindowScriptingInterface::browseDir(const QString& title, const QSt
|
||||||
return result.isEmpty() ? QScriptValue::NullValue : QScriptValue(result);
|
return result.isEmpty() ? QScriptValue::NullValue : QScriptValue(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Display an open file dialog. If `directory` is an invalid file or directory the browser will start at the current
|
/// Display a "browse to directory" dialog. If `directory` is an invalid file or directory the browser will start at the current
|
||||||
/// working directory.
|
/// working directory.
|
||||||
|
/// \param const QString& title title of the window
|
||||||
|
/// \param const QString& directory directory to start the file browser at
|
||||||
|
/// \param const QString& nameFilter filter to filter filenames by - see `QFileDialog`
|
||||||
|
void WindowScriptingInterface::browseDirAsync(const QString& title, const QString& directory) {
|
||||||
|
ensureReticleVisible();
|
||||||
|
QString path = directory;
|
||||||
|
if (path.isEmpty()) {
|
||||||
|
path = getPreviousBrowseLocation();
|
||||||
|
}
|
||||||
|
#ifndef Q_OS_WIN
|
||||||
|
path = fixupPathForMac(directory);
|
||||||
|
#endif
|
||||||
|
ModalDialogListener* dlg = OffscreenUi::getExistingDirectoryAsync(nullptr, title, path);
|
||||||
|
connect(dlg, &ModalDialogListener::response, this, [=] (QVariant response) {
|
||||||
|
const QString& result = response.toString();
|
||||||
|
disconnect(dlg, &ModalDialogListener::response, this, nullptr);
|
||||||
|
if (!result.isEmpty()) {
|
||||||
|
setPreviousBrowseLocation(QFileInfo(result).absolutePath());
|
||||||
|
}
|
||||||
|
emit browseDirChanged(result);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/// \param const QString& title title of the window
|
/// \param const QString& title title of the window
|
||||||
/// \param const QString& directory directory to start the file browser at
|
/// \param const QString& directory directory to start the file browser at
|
||||||
/// \param const QString& nameFilter filter to filter filenames by - see `QFileDialog`
|
/// \param const QString& nameFilter filter to filter filenames by - see `QFileDialog`
|
||||||
|
@ -213,6 +247,31 @@ QScriptValue WindowScriptingInterface::browse(const QString& title, const QStrin
|
||||||
return result.isEmpty() ? QScriptValue::NullValue : QScriptValue(result);
|
return result.isEmpty() ? QScriptValue::NullValue : QScriptValue(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Display an open file dialog. If `directory` is an invalid file or directory the browser will start at the current
|
||||||
|
/// working directory.
|
||||||
|
/// \param const QString& title title of the window
|
||||||
|
/// \param const QString& directory directory to start the file browser at
|
||||||
|
/// \param const QString& nameFilter filter to filter filenames by - see `QFileDialog`
|
||||||
|
void WindowScriptingInterface::browseAsync(const QString& title, const QString& directory, const QString& nameFilter) {
|
||||||
|
ensureReticleVisible();
|
||||||
|
QString path = directory;
|
||||||
|
if (path.isEmpty()) {
|
||||||
|
path = getPreviousBrowseLocation();
|
||||||
|
}
|
||||||
|
#ifndef Q_OS_WIN
|
||||||
|
path = fixupPathForMac(directory);
|
||||||
|
#endif
|
||||||
|
ModalDialogListener* dlg = OffscreenUi::getOpenFileNameAsync(nullptr, title, path, nameFilter);
|
||||||
|
connect(dlg, &ModalDialogListener::response, this, [=] (QVariant response) {
|
||||||
|
const QString& result = response.toString();
|
||||||
|
disconnect(dlg, &ModalDialogListener::response, this, nullptr);
|
||||||
|
if (!result.isEmpty()) {
|
||||||
|
setPreviousBrowseLocation(QFileInfo(result).absolutePath());
|
||||||
|
}
|
||||||
|
emit openFileChanged(result);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/// Display a save file dialog. If `directory` is an invalid file or directory the browser will start at the current
|
/// Display a save file dialog. If `directory` is an invalid file or directory the browser will start at the current
|
||||||
/// working directory.
|
/// working directory.
|
||||||
/// \param const QString& title title of the window
|
/// \param const QString& title title of the window
|
||||||
|
@ -235,7 +294,32 @@ QScriptValue WindowScriptingInterface::save(const QString& title, const QString&
|
||||||
return result.isEmpty() ? QScriptValue::NullValue : QScriptValue(result);
|
return result.isEmpty() ? QScriptValue::NullValue : QScriptValue(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Display a select asset dialog that lets the user select an asset from the Asset Server. If `directory` is an invalid
|
/// Display a save file dialog. If `directory` is an invalid file or directory the browser will start at the current
|
||||||
|
/// working directory.
|
||||||
|
/// \param const QString& title title of the window
|
||||||
|
/// \param const QString& directory directory to start the file browser at
|
||||||
|
/// \param const QString& nameFilter filter to filter filenames by - see `QFileDialog`
|
||||||
|
void WindowScriptingInterface::saveAsync(const QString& title, const QString& directory, const QString& nameFilter) {
|
||||||
|
ensureReticleVisible();
|
||||||
|
QString path = directory;
|
||||||
|
if (path.isEmpty()) {
|
||||||
|
path = getPreviousBrowseLocation();
|
||||||
|
}
|
||||||
|
#ifndef Q_OS_WIN
|
||||||
|
path = fixupPathForMac(directory);
|
||||||
|
#endif
|
||||||
|
ModalDialogListener* dlg = OffscreenUi::getSaveFileNameAsync(nullptr, title, path, nameFilter);
|
||||||
|
connect(dlg, &ModalDialogListener::response, this, [=] (QVariant response) {
|
||||||
|
const QString& result = response.toString();
|
||||||
|
disconnect(dlg, &ModalDialogListener::response, this, nullptr);
|
||||||
|
if (!result.isEmpty()) {
|
||||||
|
setPreviousBrowseLocation(QFileInfo(result).absolutePath());
|
||||||
|
}
|
||||||
|
emit saveFileChanged(result);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Display a select asset dialog that lets the user select an asset from the Asset Server. If `directory` is an invalid
|
||||||
/// directory the browser will start at the root directory.
|
/// directory the browser will start at the root directory.
|
||||||
/// \param const QString& title title of the window
|
/// \param const QString& title title of the window
|
||||||
/// \param const QString& directory directory to start the asset browser at
|
/// \param const QString& directory directory to start the asset browser at
|
||||||
|
@ -260,6 +344,35 @@ QScriptValue WindowScriptingInterface::browseAssets(const QString& title, const
|
||||||
return result.isEmpty() ? QScriptValue::NullValue : QScriptValue(result);
|
return result.isEmpty() ? QScriptValue::NullValue : QScriptValue(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Display a select asset dialog that lets the user select an asset from the Asset Server. If `directory` is an invalid
|
||||||
|
/// directory the browser will start at the root directory.
|
||||||
|
/// \param const QString& title title of the window
|
||||||
|
/// \param const QString& directory directory to start the asset browser at
|
||||||
|
/// \param const QString& nameFilter filter to filter asset names by - see `QFileDialog`
|
||||||
|
void WindowScriptingInterface::browseAssetsAsync(const QString& title, const QString& directory, const QString& nameFilter) {
|
||||||
|
ensureReticleVisible();
|
||||||
|
QString path = directory;
|
||||||
|
if (path.isEmpty()) {
|
||||||
|
path = getPreviousBrowseAssetLocation();
|
||||||
|
}
|
||||||
|
if (path.left(1) != "/") {
|
||||||
|
path = "/" + path;
|
||||||
|
}
|
||||||
|
if (path.right(1) != "/") {
|
||||||
|
path = path + "/";
|
||||||
|
}
|
||||||
|
|
||||||
|
ModalDialogListener* dlg = OffscreenUi::getOpenAssetNameAsync(nullptr, title, path, nameFilter);
|
||||||
|
connect(dlg, &ModalDialogListener::response, this, [=] (QVariant response) {
|
||||||
|
const QString& result = response.toString();
|
||||||
|
disconnect(dlg, &ModalDialogListener::response, this, nullptr);
|
||||||
|
if (!result.isEmpty()) {
|
||||||
|
setPreviousBrowseAssetLocation(QFileInfo(result).absolutePath());
|
||||||
|
}
|
||||||
|
emit assetsDirChanged(result);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
void WindowScriptingInterface::showAssetServer(const QString& upload) {
|
void WindowScriptingInterface::showAssetServer(const QString& upload) {
|
||||||
QMetaObject::invokeMethod(qApp, "showAssetServerWidget", Qt::QueuedConnection, Q_ARG(QString, upload));
|
QMetaObject::invokeMethod(qApp, "showAssetServerWidget", Qt::QueuedConnection, Q_ARG(QString, upload));
|
||||||
}
|
}
|
||||||
|
|
|
@ -51,12 +51,17 @@ public slots:
|
||||||
void raiseMainWindow();
|
void raiseMainWindow();
|
||||||
void alert(const QString& message = "");
|
void alert(const QString& message = "");
|
||||||
QScriptValue confirm(const QString& message = "");
|
QScriptValue confirm(const QString& message = "");
|
||||||
QScriptValue prompt(const QString& message = "", const QString& defaultText = "");
|
QScriptValue prompt(const QString& message, const QString& defaultText);
|
||||||
|
void promptAsync(const QString& message = "", const QString& defaultText = "");
|
||||||
CustomPromptResult customPrompt(const QVariant& config);
|
CustomPromptResult customPrompt(const QVariant& config);
|
||||||
QScriptValue browseDir(const QString& title = "", const QString& directory = "");
|
QScriptValue browseDir(const QString& title = "", const QString& directory = "");
|
||||||
|
void browseDirAsync(const QString& title = "", const QString& directory = "");
|
||||||
QScriptValue browse(const QString& title = "", const QString& directory = "", const QString& nameFilter = "");
|
QScriptValue browse(const QString& title = "", const QString& directory = "", const QString& nameFilter = "");
|
||||||
|
void browseAsync(const QString& title = "", const QString& directory = "", const QString& nameFilter = "");
|
||||||
QScriptValue save(const QString& title = "", const QString& directory = "", const QString& nameFilter = "");
|
QScriptValue save(const QString& title = "", const QString& directory = "", const QString& nameFilter = "");
|
||||||
|
void saveAsync(const QString& title = "", const QString& directory = "", const QString& nameFilter = "");
|
||||||
QScriptValue browseAssets(const QString& title = "", const QString& directory = "", const QString& nameFilter = "");
|
QScriptValue browseAssets(const QString& title = "", const QString& directory = "", const QString& nameFilter = "");
|
||||||
|
void browseAssetsAsync(const QString& title = "", const QString& directory = "", const QString& nameFilter = "");
|
||||||
void showAssetServer(const QString& upload = "");
|
void showAssetServer(const QString& upload = "");
|
||||||
QString checkVersion();
|
QString checkVersion();
|
||||||
void copyToClipboard(const QString& text);
|
void copyToClipboard(const QString& text);
|
||||||
|
@ -89,6 +94,11 @@ signals:
|
||||||
void announcement(const QString& message);
|
void announcement(const QString& message);
|
||||||
|
|
||||||
void messageBoxClosed(int id, int button);
|
void messageBoxClosed(int id, int button);
|
||||||
|
void browseDirChanged(QString browseDir);
|
||||||
|
void assetsDirChanged(QString assetsDir);
|
||||||
|
void saveFileChanged(QString filename);
|
||||||
|
void openFileChanged(QString filename);
|
||||||
|
void promptTextChanged(QString text);
|
||||||
|
|
||||||
// triggered when window size or position changes
|
// triggered when window size or position changes
|
||||||
void geometryChanged(QRect geometry);
|
void geometryChanged(QRect geometry);
|
||||||
|
|
|
@ -73,11 +73,11 @@ void AddressBarDialog::loadForward() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void AddressBarDialog::displayAddressOfflineMessage() {
|
void AddressBarDialog::displayAddressOfflineMessage() {
|
||||||
OffscreenUi::critical("", "That user or place is currently offline");
|
OffscreenUi::asyncCritical("", "That user or place is currently offline");
|
||||||
}
|
}
|
||||||
|
|
||||||
void AddressBarDialog::displayAddressNotFoundMessage() {
|
void AddressBarDialog::displayAddressNotFoundMessage() {
|
||||||
OffscreenUi::critical("", "There is no address information for that user or place");
|
OffscreenUi::asyncCritical("", "There is no address information for that user or place");
|
||||||
}
|
}
|
||||||
|
|
||||||
void AddressBarDialog::observeShownChanged(bool visible) {
|
void AddressBarDialog::observeShownChanged(bool visible) {
|
||||||
|
|
|
@ -91,16 +91,6 @@ void setupPreferences() {
|
||||||
preference->setMax(500);
|
preference->setMax(500);
|
||||||
preferences->addPreference(preference);
|
preferences->addPreference(preference);
|
||||||
}
|
}
|
||||||
{
|
|
||||||
auto getter = []()->bool { return qApp->getDesktopTabletBecomesToolbarSetting(); };
|
|
||||||
auto setter = [](bool value) { qApp->setDesktopTabletBecomesToolbarSetting(value); };
|
|
||||||
preferences->addPreference(new CheckPreference(UI_CATEGORY, "Desktop Tablet Becomes Toolbar", getter, setter));
|
|
||||||
}
|
|
||||||
{
|
|
||||||
auto getter = []()->bool { return qApp->getHmdTabletBecomesToolbarSetting(); };
|
|
||||||
auto setter = [](bool value) { qApp->setHmdTabletBecomesToolbarSetting(value); };
|
|
||||||
preferences->addPreference(new CheckPreference(UI_CATEGORY, "HMD Tablet Becomes Toolbar", getter, setter));
|
|
||||||
}
|
|
||||||
{
|
{
|
||||||
auto getter = []()->bool { return qApp->getPreferAvatarFingerOverStylus(); };
|
auto getter = []()->bool { return qApp->getPreferAvatarFingerOverStylus(); };
|
||||||
auto setter = [](bool value) { qApp->setPreferAvatarFingerOverStylus(value); };
|
auto setter = [](bool value) { qApp->setPreferAvatarFingerOverStylus(value); };
|
||||||
|
|
|
@ -268,18 +268,17 @@ void Base3DOverlay::update(float duration) {
|
||||||
|
|
||||||
// In Base3DOverlay, if its location or bound changed, the renderTrasnformDirty flag is true.
|
// In Base3DOverlay, if its location or bound changed, the renderTrasnformDirty flag is true.
|
||||||
// then the correct transform used for rendering is computed in the update transaction and assigned.
|
// then the correct transform used for rendering is computed in the update transaction and assigned.
|
||||||
// TODO: Fix the value to be computed in main thread now and passed by value to the render item.
|
|
||||||
// This is the simplest fix for the web overlay of the tablet for now
|
|
||||||
if (_renderTransformDirty) {
|
if (_renderTransformDirty) {
|
||||||
_renderTransformDirty = false;
|
|
||||||
auto itemID = getRenderItemID();
|
auto itemID = getRenderItemID();
|
||||||
if (render::Item::isValidID(itemID)) {
|
if (render::Item::isValidID(itemID)) {
|
||||||
|
_renderTransformDirty = false;
|
||||||
|
// Capture the render transform value in game loop before
|
||||||
|
auto latestTransform = evalRenderTransform();
|
||||||
render::ScenePointer scene = qApp->getMain3DScene();
|
render::ScenePointer scene = qApp->getMain3DScene();
|
||||||
render::Transaction transaction;
|
render::Transaction transaction;
|
||||||
transaction.updateItem<Overlay>(itemID, [](Overlay& data) {
|
transaction.updateItem<Overlay>(itemID, [latestTransform](Overlay& data) {
|
||||||
auto overlay3D = dynamic_cast<Base3DOverlay*>(&data);
|
auto overlay3D = dynamic_cast<Base3DOverlay*>(&data);
|
||||||
if (overlay3D) {
|
if (overlay3D) {
|
||||||
auto latestTransform = overlay3D->evalRenderTransform();
|
|
||||||
overlay3D->setRenderTransform(latestTransform);
|
overlay3D->setRenderTransform(latestTransform);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -292,7 +291,7 @@ void Base3DOverlay::notifyRenderTransformChange() const {
|
||||||
_renderTransformDirty = true;
|
_renderTransformDirty = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
Transform Base3DOverlay::evalRenderTransform() const {
|
Transform Base3DOverlay::evalRenderTransform() {
|
||||||
return getTransform();
|
return getTransform();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -72,7 +72,7 @@ protected:
|
||||||
virtual void parentDeleted() override;
|
virtual void parentDeleted() override;
|
||||||
|
|
||||||
mutable Transform _renderTransform;
|
mutable Transform _renderTransform;
|
||||||
virtual Transform evalRenderTransform() const;
|
virtual Transform evalRenderTransform();
|
||||||
virtual void setRenderTransform(const Transform& transform);
|
virtual void setRenderTransform(const Transform& transform);
|
||||||
const Transform& getRenderTransform() const { return _renderTransform; }
|
const Transform& getRenderTransform() const { return _renderTransform; }
|
||||||
|
|
||||||
|
|
|
@ -45,3 +45,14 @@ bool Billboard3DOverlay::applyTransformTo(Transform& transform, bool force) {
|
||||||
}
|
}
|
||||||
return transformChanged;
|
return transformChanged;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Transform Billboard3DOverlay::evalRenderTransform() {
|
||||||
|
Transform transform = getTransform();
|
||||||
|
bool transformChanged = applyTransformTo(transform, true);
|
||||||
|
// If the transform is not modified, setting the transform to
|
||||||
|
// itself will cause drift over time due to floating point errors.
|
||||||
|
if (transformChanged) {
|
||||||
|
setTransform(transform);
|
||||||
|
}
|
||||||
|
return transform;
|
||||||
|
}
|
|
@ -28,6 +28,8 @@ public:
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual bool applyTransformTo(Transform& transform, bool force = false) override;
|
virtual bool applyTransformTo(Transform& transform, bool force = false) override;
|
||||||
|
|
||||||
|
Transform evalRenderTransform() override;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // hifi_Billboard3DOverlay_h
|
#endif // hifi_Billboard3DOverlay_h
|
||||||
|
|
|
@ -84,12 +84,7 @@ void Circle3DOverlay::render(RenderArgs* args) {
|
||||||
batch.setPipeline(args->_shapePipeline->pipeline);
|
batch.setPipeline(args->_shapePipeline->pipeline);
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: THe line width of _lineWidth is not supported anymore, we ll need a workaround
|
batch.setModelTransform(getRenderTransform());
|
||||||
// FIXME Start using the _renderTransform instead of calling for Transform from here, do the custom things needed in evalRenderTransform()
|
|
||||||
|
|
||||||
auto transform = getTransform();
|
|
||||||
transform.postScale(glm::vec3(getDimensions(), 1.0f));
|
|
||||||
batch.setModelTransform(transform);
|
|
||||||
|
|
||||||
// for our overlay, is solid means we draw a ring between the inner and outer radius of the circle, otherwise
|
// for our overlay, is solid means we draw a ring between the inner and outer radius of the circle, otherwise
|
||||||
// we just draw a line...
|
// we just draw a line...
|
||||||
|
|
|
@ -53,18 +53,11 @@ void Cube3DOverlay::render(RenderArgs* args) {
|
||||||
const float MAX_COLOR = 255.0f;
|
const float MAX_COLOR = 255.0f;
|
||||||
glm::vec4 cubeColor(color.red / MAX_COLOR, color.green / MAX_COLOR, color.blue / MAX_COLOR, alpha);
|
glm::vec4 cubeColor(color.red / MAX_COLOR, color.green / MAX_COLOR, color.blue / MAX_COLOR, alpha);
|
||||||
|
|
||||||
// TODO: handle registration point??
|
|
||||||
// FIXME Start using the _renderTransform instead of calling for Transform from here, do the custom things needed in evalRenderTransform()
|
|
||||||
glm::vec3 position = getPosition();
|
|
||||||
glm::vec3 dimensions = getDimensions();
|
|
||||||
glm::quat rotation = getRotation();
|
|
||||||
|
|
||||||
auto batch = args->_batch;
|
auto batch = args->_batch;
|
||||||
|
|
||||||
if (batch) {
|
if (batch) {
|
||||||
Transform transform;
|
Transform transform = getRenderTransform();
|
||||||
transform.setTranslation(position);
|
|
||||||
transform.setRotation(rotation);
|
|
||||||
auto geometryCache = DependencyManager::get<GeometryCache>();
|
auto geometryCache = DependencyManager::get<GeometryCache>();
|
||||||
auto shapePipeline = args->_shapePipeline;
|
auto shapePipeline = args->_shapePipeline;
|
||||||
if (!shapePipeline) {
|
if (!shapePipeline) {
|
||||||
|
@ -72,12 +65,12 @@ void Cube3DOverlay::render(RenderArgs* args) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_isSolid) {
|
if (_isSolid) {
|
||||||
transform.setScale(dimensions);
|
|
||||||
batch->setModelTransform(transform);
|
batch->setModelTransform(transform);
|
||||||
geometryCache->renderSolidCubeInstance(args, *batch, cubeColor, shapePipeline);
|
geometryCache->renderSolidCubeInstance(args, *batch, cubeColor, shapePipeline);
|
||||||
} else {
|
} else {
|
||||||
geometryCache->bindSimpleProgram(*batch, false, false, false, true, true);
|
geometryCache->bindSimpleProgram(*batch, false, false, false, true, true);
|
||||||
if (getIsDashedLine()) {
|
if (getIsDashedLine()) {
|
||||||
|
auto dimensions = transform.getScale();
|
||||||
transform.setScale(1.0f);
|
transform.setScale(1.0f);
|
||||||
batch->setModelTransform(transform);
|
batch->setModelTransform(transform);
|
||||||
|
|
||||||
|
@ -108,7 +101,6 @@ void Cube3DOverlay::render(RenderArgs* args) {
|
||||||
geometryCache->renderDashedLine(*batch, bottomRightFar, topRightFar, cubeColor, _geometryIds[11]);
|
geometryCache->renderDashedLine(*batch, bottomRightFar, topRightFar, cubeColor, _geometryIds[11]);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
transform.setScale(dimensions);
|
|
||||||
batch->setModelTransform(transform);
|
batch->setModelTransform(transform);
|
||||||
geometryCache->renderWireCubeInstance(args, *batch, cubeColor, shapePipeline);
|
geometryCache->renderWireCubeInstance(args, *batch, cubeColor, shapePipeline);
|
||||||
}
|
}
|
||||||
|
@ -149,3 +141,16 @@ QVariant Cube3DOverlay::getProperty(const QString& property) {
|
||||||
|
|
||||||
return Volume3DOverlay::getProperty(property);
|
return Volume3DOverlay::getProperty(property);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Transform Cube3DOverlay::evalRenderTransform() {
|
||||||
|
// TODO: handle registration point??
|
||||||
|
glm::vec3 position = getPosition();
|
||||||
|
glm::vec3 dimensions = getDimensions();
|
||||||
|
glm::quat rotation = getRotation();
|
||||||
|
|
||||||
|
Transform transform;
|
||||||
|
transform.setScale(dimensions);
|
||||||
|
transform.setTranslation(position);
|
||||||
|
transform.setRotation(rotation);
|
||||||
|
return transform;
|
||||||
|
}
|
||||||
|
|
|
@ -36,6 +36,9 @@ public:
|
||||||
void setProperties(const QVariantMap& properties) override;
|
void setProperties(const QVariantMap& properties) override;
|
||||||
QVariant getProperty(const QString& property) override;
|
QVariant getProperty(const QString& property) override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
Transform evalRenderTransform() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
float _borderSize;
|
float _borderSize;
|
||||||
// edges on a cube
|
// edges on a cube
|
||||||
|
|
|
@ -79,10 +79,7 @@ void Grid3DOverlay::render(RenderArgs* args) {
|
||||||
position += glm::vec3(cameraPosition.x, 0.0f, cameraPosition.z);
|
position += glm::vec3(cameraPosition.x, 0.0f, cameraPosition.z);
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME Start using the _renderTransform instead of calling for Transform from here, do the custom things needed in evalRenderTransform()
|
Transform transform = getRenderTransform();
|
||||||
Transform transform;
|
|
||||||
transform.setRotation(getRotation());
|
|
||||||
transform.setScale(glm::vec3(getDimensions(), 1.0f));
|
|
||||||
transform.setTranslation(position);
|
transform.setTranslation(position);
|
||||||
batch->setModelTransform(transform);
|
batch->setModelTransform(transform);
|
||||||
const float MINOR_GRID_EDGE = 0.0025f;
|
const float MINOR_GRID_EDGE = 0.0025f;
|
||||||
|
@ -146,3 +143,10 @@ void Grid3DOverlay::updateGrid() {
|
||||||
_minorGridRowDivisions = getDimensions().x / _minorGridEvery;
|
_minorGridRowDivisions = getDimensions().x / _minorGridEvery;
|
||||||
_minorGridColDivisions = getDimensions().y / _minorGridEvery;
|
_minorGridColDivisions = getDimensions().y / _minorGridEvery;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Transform Grid3DOverlay::evalRenderTransform() {
|
||||||
|
Transform transform;
|
||||||
|
transform.setRotation(getRotation());
|
||||||
|
transform.setScale(glm::vec3(getDimensions(), 1.0f));
|
||||||
|
return transform;
|
||||||
|
}
|
||||||
|
|
|
@ -37,6 +37,9 @@ public:
|
||||||
// Grids are UI tools, and may not be intersected (pickable)
|
// Grids are UI tools, and may not be intersected (pickable)
|
||||||
virtual bool findRayIntersection(const glm::vec3&, const glm::vec3&, float&, BoxFace&, glm::vec3&) override { return false; }
|
virtual bool findRayIntersection(const glm::vec3&, const glm::vec3&, float&, BoxFace&, glm::vec3&) override { return false; }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
Transform evalRenderTransform() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void updateGrid();
|
void updateGrid();
|
||||||
|
|
||||||
|
|
|
@ -58,6 +58,7 @@ void Image3DOverlay::update(float deltatime) {
|
||||||
setTransform(transform);
|
setTransform(transform);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
Parent::update(deltatime);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Image3DOverlay::render(RenderArgs* args) {
|
void Image3DOverlay::render(RenderArgs* args) {
|
||||||
|
@ -116,18 +117,8 @@ void Image3DOverlay::render(RenderArgs* args) {
|
||||||
const float MAX_COLOR = 255.0f;
|
const float MAX_COLOR = 255.0f;
|
||||||
xColor color = getColor();
|
xColor color = getColor();
|
||||||
float alpha = getAlpha();
|
float alpha = getAlpha();
|
||||||
|
|
||||||
// FIXME Start using the _renderTransform instead of calling for Transform from here, do the custom things needed in evalRenderTransform()
|
|
||||||
Transform transform = getTransform();
|
|
||||||
bool transformChanged = applyTransformTo(transform, true);
|
|
||||||
// If the transform is not modified, setting the transform to
|
|
||||||
// itself will cause drift over time due to floating point errors.
|
|
||||||
if (transformChanged) {
|
|
||||||
setTransform(transform);
|
|
||||||
}
|
|
||||||
transform.postScale(glm::vec3(getDimensions(), 1.0f));
|
|
||||||
|
|
||||||
batch->setModelTransform(transform);
|
batch->setModelTransform(getRenderTransform());
|
||||||
batch->setResourceTexture(0, _texture->getGPUTexture());
|
batch->setResourceTexture(0, _texture->getGPUTexture());
|
||||||
|
|
||||||
DependencyManager::get<GeometryCache>()->renderQuad(
|
DependencyManager::get<GeometryCache>()->renderQuad(
|
||||||
|
@ -249,3 +240,9 @@ bool Image3DOverlay::findRayIntersection(const glm::vec3& origin, const glm::vec
|
||||||
Image3DOverlay* Image3DOverlay::createClone() const {
|
Image3DOverlay* Image3DOverlay::createClone() const {
|
||||||
return new Image3DOverlay(this);
|
return new Image3DOverlay(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Transform Image3DOverlay::evalRenderTransform() {
|
||||||
|
auto transform = Parent::evalRenderTransform();
|
||||||
|
transform.postScale(glm::vec3(getDimensions(), 1.0f));
|
||||||
|
return transform;
|
||||||
|
}
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
|
|
||||||
class Image3DOverlay : public Billboard3DOverlay {
|
class Image3DOverlay : public Billboard3DOverlay {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
using Parent = Billboard3DOverlay;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static QString const TYPE;
|
static QString const TYPE;
|
||||||
|
@ -46,6 +47,9 @@ public:
|
||||||
|
|
||||||
virtual Image3DOverlay* createClone() const override;
|
virtual Image3DOverlay* createClone() const override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
Transform evalRenderTransform() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QString _url;
|
QString _url;
|
||||||
NetworkTexturePointer _texture;
|
NetworkTexturePointer _texture;
|
||||||
|
|
|
@ -132,10 +132,10 @@ void Line3DOverlay::render(RenderArgs* args) {
|
||||||
glm::vec4 colorv4(color.red / MAX_COLOR, color.green / MAX_COLOR, color.blue / MAX_COLOR, alpha);
|
glm::vec4 colorv4(color.red / MAX_COLOR, color.green / MAX_COLOR, color.blue / MAX_COLOR, alpha);
|
||||||
auto batch = args->_batch;
|
auto batch = args->_batch;
|
||||||
if (batch) {
|
if (batch) {
|
||||||
// FIXME Start using the _renderTransform instead of calling for Transform and start and end from here, do the custom things needed in evalRenderTransform()
|
|
||||||
batch->setModelTransform(Transform());
|
batch->setModelTransform(Transform());
|
||||||
glm::vec3 start = getStart();
|
auto& renderTransform = getRenderTransform();
|
||||||
glm::vec3 end = getEnd();
|
glm::vec3 start = renderTransform.getTranslation();
|
||||||
|
glm::vec3 end = renderTransform.transform(vec3(0.0, 0.0, -1.0));
|
||||||
|
|
||||||
auto geometryCache = DependencyManager::get<GeometryCache>();
|
auto geometryCache = DependencyManager::get<GeometryCache>();
|
||||||
if (getIsDashedLine()) {
|
if (getIsDashedLine()) {
|
||||||
|
@ -268,3 +268,21 @@ QVariant Line3DOverlay::getProperty(const QString& property) {
|
||||||
Line3DOverlay* Line3DOverlay::createClone() const {
|
Line3DOverlay* Line3DOverlay::createClone() const {
|
||||||
return new Line3DOverlay(this);
|
return new Line3DOverlay(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Transform Line3DOverlay::evalRenderTransform() {
|
||||||
|
// Capture start and endin the renderTransform:
|
||||||
|
// start is the origin
|
||||||
|
// end is at the tip of the front axis aka -Z
|
||||||
|
Transform transform;
|
||||||
|
transform.setTranslation( getStart());
|
||||||
|
auto endPos = getEnd();
|
||||||
|
|
||||||
|
auto vec = endPos - transform.getTranslation();
|
||||||
|
auto scale = glm::length(vec);
|
||||||
|
auto dir = vec / scale;
|
||||||
|
auto orientation = glm::rotation(glm::vec3(0,0,-1), dir);
|
||||||
|
transform.setRotation(orientation);
|
||||||
|
transform.setScale(scale);
|
||||||
|
|
||||||
|
return transform;
|
||||||
|
}
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
|
|
||||||
class Line3DOverlay : public Base3DOverlay {
|
class Line3DOverlay : public Base3DOverlay {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
using Parent = Base3DOverlay;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static QString const TYPE;
|
static QString const TYPE;
|
||||||
|
@ -56,6 +57,9 @@ public:
|
||||||
QUuid getEndParentID() const { return _endParentID; }
|
QUuid getEndParentID() const { return _endParentID; }
|
||||||
quint16 getEndJointIndex() const { return _endParentJointIndex; }
|
quint16 getEndJointIndex() const { return _endParentJointIndex; }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
Transform evalRenderTransform() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QUuid _endParentID;
|
QUuid _endParentID;
|
||||||
quint16 _endParentJointIndex { INVALID_JOINT_INDEX };
|
quint16 _endParentJointIndex { INVALID_JOINT_INDEX };
|
||||||
|
|
|
@ -46,10 +46,7 @@ void ModelOverlay::update(float deltatime) {
|
||||||
if (_updateModel) {
|
if (_updateModel) {
|
||||||
_updateModel = false;
|
_updateModel = false;
|
||||||
_model->setSnapModelToCenter(true);
|
_model->setSnapModelToCenter(true);
|
||||||
Transform transform = getTransform();
|
Transform transform = evalRenderTransform();
|
||||||
#ifndef USE_SN_SCALE
|
|
||||||
transform.setScale(1.0f); // disable inherited scale
|
|
||||||
#endif
|
|
||||||
if (_scaleToFit) {
|
if (_scaleToFit) {
|
||||||
_model->setScaleToFit(true, transform.getScale() * getDimensions());
|
_model->setScaleToFit(true, transform.getScale() * getDimensions());
|
||||||
} else {
|
} else {
|
||||||
|
@ -282,6 +279,12 @@ ModelOverlay* ModelOverlay::createClone() const {
|
||||||
return new ModelOverlay(this);
|
return new ModelOverlay(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Transform ModelOverlay::evalRenderTransform() {
|
||||||
|
Transform transform = getTransform();
|
||||||
|
transform.setScale(1.0f); // disable inherited scale
|
||||||
|
return transform;
|
||||||
|
}
|
||||||
|
|
||||||
void ModelOverlay::locationChanged(bool tellPhysics) {
|
void ModelOverlay::locationChanged(bool tellPhysics) {
|
||||||
Base3DOverlay::locationChanged(tellPhysics);
|
Base3DOverlay::locationChanged(tellPhysics);
|
||||||
|
|
||||||
|
|
|
@ -46,6 +46,8 @@ public:
|
||||||
float getLoadPriority() const { return _loadPriority; }
|
float getLoadPriority() const { return _loadPriority; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
Transform evalRenderTransform() override;
|
||||||
|
|
||||||
// helper to extract metadata from our Model's rigged joints
|
// helper to extract metadata from our Model's rigged joints
|
||||||
template <typename itemType> using mapFunction = std::function<itemType(int jointIndex)>;
|
template <typename itemType> using mapFunction = std::function<itemType(int jointIndex)>;
|
||||||
template <typename vectorType, typename itemType>
|
template <typename vectorType, typename itemType>
|
||||||
|
|
|
@ -35,6 +35,11 @@ AABox Planar3DOverlay::getBounds() const {
|
||||||
return AABox(extents);
|
return AABox(extents);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Planar3DOverlay::setDimensions(const glm::vec2& value) {
|
||||||
|
_dimensions = value;
|
||||||
|
notifyRenderTransformChange();
|
||||||
|
}
|
||||||
|
|
||||||
void Planar3DOverlay::setProperties(const QVariantMap& properties) {
|
void Planar3DOverlay::setProperties(const QVariantMap& properties) {
|
||||||
Base3DOverlay::setProperties(properties);
|
Base3DOverlay::setProperties(properties);
|
||||||
|
|
||||||
|
@ -67,7 +72,7 @@ bool Planar3DOverlay::findRayIntersection(const glm::vec3& origin, const glm::ve
|
||||||
return findRayRectangleIntersection(origin, direction, getRotation(), getPosition(), getDimensions(), distance);
|
return findRayRectangleIntersection(origin, direction, getRotation(), getPosition(), getDimensions(), distance);
|
||||||
}
|
}
|
||||||
|
|
||||||
Transform Planar3DOverlay::evalRenderTransform() const {
|
Transform Planar3DOverlay::evalRenderTransform() {
|
||||||
auto transform = getTransform();
|
auto transform = getTransform();
|
||||||
transform.setScale(1.0f); // ignore inherited scale factor from parents
|
transform.setScale(1.0f); // ignore inherited scale factor from parents
|
||||||
if (glm::length2(getDimensions()) != 1.0f) {
|
if (glm::length2(getDimensions()) != 1.0f) {
|
||||||
|
|
|
@ -24,8 +24,8 @@ public:
|
||||||
virtual glm::vec2 getSize() const { return _dimensions; };
|
virtual glm::vec2 getSize() const { return _dimensions; };
|
||||||
|
|
||||||
glm::vec2 getDimensions() const { return _dimensions; }
|
glm::vec2 getDimensions() const { return _dimensions; }
|
||||||
void setDimensions(float value) { _dimensions = glm::vec2(value); }
|
void setDimensions(float value) { setDimensions(glm::vec2(value)); }
|
||||||
void setDimensions(const glm::vec2& value) { _dimensions = value; }
|
void setDimensions(const glm::vec2& value);
|
||||||
|
|
||||||
void setProperties(const QVariantMap& properties) override;
|
void setProperties(const QVariantMap& properties) override;
|
||||||
QVariant getProperty(const QString& property) override;
|
QVariant getProperty(const QString& property) override;
|
||||||
|
@ -33,10 +33,10 @@ public:
|
||||||
virtual bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance,
|
virtual bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance,
|
||||||
BoxFace& face, glm::vec3& surfaceNormal) override;
|
BoxFace& face, glm::vec3& surfaceNormal) override;
|
||||||
|
|
||||||
Transform evalRenderTransform() const override;
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
glm::vec2 _dimensions;
|
glm::vec2 _dimensions;
|
||||||
|
|
||||||
|
Transform evalRenderTransform() override;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -124,3 +124,8 @@ void Rectangle3DOverlay::setProperties(const QVariantMap& properties) {
|
||||||
Rectangle3DOverlay* Rectangle3DOverlay::createClone() const {
|
Rectangle3DOverlay* Rectangle3DOverlay::createClone() const {
|
||||||
return new Rectangle3DOverlay(this);
|
return new Rectangle3DOverlay(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Transform Rectangle3DOverlay::evalRenderTransform() {
|
||||||
|
return getTransform();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -28,6 +28,10 @@ public:
|
||||||
void setProperties(const QVariantMap& properties) override;
|
void setProperties(const QVariantMap& properties) override;
|
||||||
|
|
||||||
virtual Rectangle3DOverlay* createClone() const override;
|
virtual Rectangle3DOverlay* createClone() const override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
Transform evalRenderTransform() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
int _geometryCacheID;
|
int _geometryCacheID;
|
||||||
std::array<int, 4> _rectGeometryIds;
|
std::array<int, 4> _rectGeometryIds;
|
||||||
|
|
|
@ -33,26 +33,15 @@ void Shape3DOverlay::render(RenderArgs* args) {
|
||||||
const float MAX_COLOR = 255.0f;
|
const float MAX_COLOR = 255.0f;
|
||||||
glm::vec4 cubeColor(color.red / MAX_COLOR, color.green / MAX_COLOR, color.blue / MAX_COLOR, alpha);
|
glm::vec4 cubeColor(color.red / MAX_COLOR, color.green / MAX_COLOR, color.blue / MAX_COLOR, alpha);
|
||||||
|
|
||||||
// FIXME Start using the _renderTransform instead of calling for Transform and Dimensions from here, do the custom things needed in evalRenderTransform()
|
|
||||||
// TODO: handle registration point??
|
|
||||||
glm::vec3 position = getPosition();
|
|
||||||
glm::vec3 dimensions = getDimensions();
|
|
||||||
glm::quat rotation = getRotation();
|
|
||||||
|
|
||||||
auto batch = args->_batch;
|
auto batch = args->_batch;
|
||||||
|
|
||||||
if (batch) {
|
if (batch) {
|
||||||
Transform transform;
|
|
||||||
transform.setTranslation(position);
|
|
||||||
transform.setRotation(rotation);
|
|
||||||
auto geometryCache = DependencyManager::get<GeometryCache>();
|
auto geometryCache = DependencyManager::get<GeometryCache>();
|
||||||
auto shapePipeline = args->_shapePipeline;
|
auto shapePipeline = args->_shapePipeline;
|
||||||
if (!shapePipeline) {
|
if (!shapePipeline) {
|
||||||
shapePipeline = _isSolid ? geometryCache->getOpaqueShapePipeline() : geometryCache->getWireShapePipeline();
|
shapePipeline = _isSolid ? geometryCache->getOpaqueShapePipeline() : geometryCache->getWireShapePipeline();
|
||||||
}
|
}
|
||||||
|
|
||||||
transform.setScale(dimensions);
|
batch->setModelTransform(getRenderTransform());
|
||||||
batch->setModelTransform(transform);
|
|
||||||
if (_isSolid) {
|
if (_isSolid) {
|
||||||
geometryCache->renderSolidShapeInstance(args, *batch, _shape, cubeColor, shapePipeline);
|
geometryCache->renderSolidShapeInstance(args, *batch, _shape, cubeColor, shapePipeline);
|
||||||
} else {
|
} else {
|
||||||
|
@ -129,3 +118,16 @@ QVariant Shape3DOverlay::getProperty(const QString& property) {
|
||||||
|
|
||||||
return Volume3DOverlay::getProperty(property);
|
return Volume3DOverlay::getProperty(property);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Transform Shape3DOverlay::evalRenderTransform() {
|
||||||
|
// TODO: handle registration point??
|
||||||
|
glm::vec3 position = getPosition();
|
||||||
|
glm::vec3 dimensions = getDimensions();
|
||||||
|
glm::quat rotation = getRotation();
|
||||||
|
|
||||||
|
Transform transform;
|
||||||
|
transform.setScale(dimensions);
|
||||||
|
transform.setTranslation(position);
|
||||||
|
transform.setRotation(rotation);
|
||||||
|
return transform;
|
||||||
|
}
|
||||||
|
|
|
@ -37,6 +37,9 @@ public:
|
||||||
void setProperties(const QVariantMap& properties) override;
|
void setProperties(const QVariantMap& properties) override;
|
||||||
QVariant getProperty(const QString& property) override;
|
QVariant getProperty(const QString& property) override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
Transform evalRenderTransform() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
float _borderSize;
|
float _borderSize;
|
||||||
GeometryCache::Shape _shape { GeometryCache::Hexagon };
|
GeometryCache::Shape _shape { GeometryCache::Hexagon };
|
||||||
|
|
|
@ -39,13 +39,7 @@ void Sphere3DOverlay::render(RenderArgs* args) {
|
||||||
auto batch = args->_batch;
|
auto batch = args->_batch;
|
||||||
|
|
||||||
if (batch) {
|
if (batch) {
|
||||||
// FIXME Start using the _renderTransform instead of calling for Transform and Dimensions from here, do the custom things needed in evalRenderTransform()
|
batch->setModelTransform(getRenderTransform());
|
||||||
Transform transform = getTransform();
|
|
||||||
#ifndef USE_SN_SCALE
|
|
||||||
transform.setScale(1.0f); // ignore inherited scale from SpatiallyNestable
|
|
||||||
#endif
|
|
||||||
transform.postScale(getDimensions() * SPHERE_OVERLAY_SCALE);
|
|
||||||
batch->setModelTransform(transform);
|
|
||||||
|
|
||||||
auto geometryCache = DependencyManager::get<GeometryCache>();
|
auto geometryCache = DependencyManager::get<GeometryCache>();
|
||||||
auto shapePipeline = args->_shapePipeline;
|
auto shapePipeline = args->_shapePipeline;
|
||||||
|
@ -75,3 +69,11 @@ const render::ShapeKey Sphere3DOverlay::getShapeKey() {
|
||||||
Sphere3DOverlay* Sphere3DOverlay::createClone() const {
|
Sphere3DOverlay* Sphere3DOverlay::createClone() const {
|
||||||
return new Sphere3DOverlay(this);
|
return new Sphere3DOverlay(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Transform Sphere3DOverlay::evalRenderTransform() {
|
||||||
|
Transform transform = getTransform();
|
||||||
|
transform.setScale(1.0f); // ignore inherited scale from SpatiallyNestable
|
||||||
|
transform.postScale(getDimensions() * SPHERE_OVERLAY_SCALE);
|
||||||
|
|
||||||
|
return transform;
|
||||||
|
}
|
||||||
|
|
|
@ -27,6 +27,9 @@ public:
|
||||||
virtual const render::ShapeKey getShapeKey() override;
|
virtual const render::ShapeKey getShapeKey() override;
|
||||||
|
|
||||||
virtual Sphere3DOverlay* createClone() const override;
|
virtual Sphere3DOverlay* createClone() const override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
Transform evalRenderTransform() override;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -17,6 +17,8 @@
|
||||||
#include <RenderDeferredTask.h>
|
#include <RenderDeferredTask.h>
|
||||||
#include <TextRenderer3D.h>
|
#include <TextRenderer3D.h>
|
||||||
|
|
||||||
|
#include <AbstractViewStateInterface.h>
|
||||||
|
|
||||||
const int FIXED_FONT_POINT_SIZE = 40;
|
const int FIXED_FONT_POINT_SIZE = 40;
|
||||||
const int FIXED_FONT_SCALING_RATIO = FIXED_FONT_POINT_SIZE * 80.0f; // this is a ratio determined through experimentation
|
const int FIXED_FONT_SCALING_RATIO = FIXED_FONT_POINT_SIZE * 80.0f; // this is a ratio determined through experimentation
|
||||||
const float LINE_SCALE_RATIO = 1.2f;
|
const float LINE_SCALE_RATIO = 1.2f;
|
||||||
|
@ -96,10 +98,7 @@ void Text3DOverlay::render(RenderArgs* args) {
|
||||||
Q_ASSERT(args->_batch);
|
Q_ASSERT(args->_batch);
|
||||||
auto& batch = *args->_batch;
|
auto& batch = *args->_batch;
|
||||||
|
|
||||||
// FIXME Start using the _renderTransform instead of calling for Transform and Dimensions from here, do the custom things needed in evalRenderTransform()
|
auto transform = getRenderTransform();
|
||||||
Transform transform = getTransform();
|
|
||||||
applyTransformTo(transform, true);
|
|
||||||
setTransform(transform);
|
|
||||||
batch.setModelTransform(transform);
|
batch.setModelTransform(transform);
|
||||||
|
|
||||||
const float MAX_COLOR = 255.0f;
|
const float MAX_COLOR = 255.0f;
|
||||||
|
@ -114,6 +113,7 @@ void Text3DOverlay::render(RenderArgs* args) {
|
||||||
|
|
||||||
glm::vec3 topLeft(-halfDimensions.x, -halfDimensions.y, SLIGHTLY_BEHIND);
|
glm::vec3 topLeft(-halfDimensions.x, -halfDimensions.y, SLIGHTLY_BEHIND);
|
||||||
glm::vec3 bottomRight(halfDimensions.x, halfDimensions.y, SLIGHTLY_BEHIND);
|
glm::vec3 bottomRight(halfDimensions.x, halfDimensions.y, SLIGHTLY_BEHIND);
|
||||||
|
DependencyManager::get<GeometryCache>()->bindSimpleProgram(batch, false, quadColor.a < 1.0f, false, false, false, false);
|
||||||
DependencyManager::get<GeometryCache>()->renderQuad(batch, topLeft, bottomRight, quadColor, _geometryId);
|
DependencyManager::get<GeometryCache>()->renderQuad(batch, topLeft, bottomRight, quadColor, _geometryId);
|
||||||
|
|
||||||
// Same font properties as textSize()
|
// Same font properties as textSize()
|
||||||
|
@ -133,13 +133,8 @@ void Text3DOverlay::render(RenderArgs* args) {
|
||||||
glm::vec4 textColor = { _color.red / MAX_COLOR, _color.green / MAX_COLOR,
|
glm::vec4 textColor = { _color.red / MAX_COLOR, _color.green / MAX_COLOR,
|
||||||
_color.blue / MAX_COLOR, getTextAlpha() };
|
_color.blue / MAX_COLOR, getTextAlpha() };
|
||||||
|
|
||||||
// FIXME: Factor out textRenderer so that Text3DOverlay overlay parts can be grouped by pipeline
|
// FIXME: Factor out textRenderer so that Text3DOverlay overlay parts can be grouped by pipeline for a gpu performance increase.
|
||||||
// for a gpu performance increase. Currently,
|
_textRenderer->draw(batch, 0, 0, getText(), textColor, glm::vec2(-1.0f), true);
|
||||||
// Text renderer sets its own pipeline,
|
|
||||||
_textRenderer->draw(batch, 0, 0, getText(), textColor, glm::vec2(-1.0f), getDrawInFront());
|
|
||||||
// so before we continue, we must reset the pipeline
|
|
||||||
batch.setPipeline(args->_shapePipeline->pipeline);
|
|
||||||
args->_shapePipeline->prepare(batch, args);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const render::ShapeKey Text3DOverlay::getShapeKey() {
|
const render::ShapeKey Text3DOverlay::getShapeKey() {
|
||||||
|
@ -160,7 +155,18 @@ void Text3DOverlay::setProperties(const QVariantMap& properties) {
|
||||||
|
|
||||||
auto textAlpha = properties["textAlpha"];
|
auto textAlpha = properties["textAlpha"];
|
||||||
if (textAlpha.isValid()) {
|
if (textAlpha.isValid()) {
|
||||||
|
float prevTextAlpha = getTextAlpha();
|
||||||
setTextAlpha(textAlpha.toFloat());
|
setTextAlpha(textAlpha.toFloat());
|
||||||
|
// Update our payload key if necessary to handle transparency
|
||||||
|
if ((prevTextAlpha < 1.0f && _textAlpha >= 1.0f) || (prevTextAlpha >= 1.0f && _textAlpha < 1.0f)) {
|
||||||
|
auto itemID = getRenderItemID();
|
||||||
|
if (render::Item::isValidID(itemID)) {
|
||||||
|
render::ScenePointer scene = AbstractViewStateInterface::instance()->getMain3DScene();
|
||||||
|
render::Transaction transaction;
|
||||||
|
transaction.updateItem(itemID);
|
||||||
|
scene->enqueueTransaction(transaction);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool valid;
|
bool valid;
|
||||||
|
@ -249,3 +255,8 @@ bool Text3DOverlay::findRayIntersection(const glm::vec3 &origin, const glm::vec3
|
||||||
setTransform(transform);
|
setTransform(transform);
|
||||||
return Billboard3DOverlay::findRayIntersection(origin, direction, distance, face, surfaceNormal);
|
return Billboard3DOverlay::findRayIntersection(origin, direction, distance, face, surfaceNormal);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Transform Text3DOverlay::evalRenderTransform() {
|
||||||
|
return Parent::evalRenderTransform();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -19,6 +19,7 @@ class TextRenderer3D;
|
||||||
|
|
||||||
class Text3DOverlay : public Billboard3DOverlay {
|
class Text3DOverlay : public Billboard3DOverlay {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
using Parent = Billboard3DOverlay;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static QString const TYPE;
|
static QString const TYPE;
|
||||||
|
@ -43,6 +44,7 @@ public:
|
||||||
xColor getBackgroundColor();
|
xColor getBackgroundColor();
|
||||||
float getTextAlpha() { return _textAlpha; }
|
float getTextAlpha() { return _textAlpha; }
|
||||||
float getBackgroundAlpha() { return getAlpha(); }
|
float getBackgroundAlpha() { return getAlpha(); }
|
||||||
|
bool isTransparent() override { return Overlay::isTransparent() || _textAlpha < 1.0f; }
|
||||||
|
|
||||||
// setters
|
// setters
|
||||||
void setText(const QString& text);
|
void setText(const QString& text);
|
||||||
|
@ -63,6 +65,9 @@ public:
|
||||||
|
|
||||||
virtual Text3DOverlay* createClone() const override;
|
virtual Text3DOverlay* createClone() const override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
Transform evalRenderTransform() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
TextRenderer3D* _textRenderer = nullptr;
|
TextRenderer3D* _textRenderer = nullptr;
|
||||||
|
|
||||||
|
|
|
@ -26,6 +26,11 @@ AABox Volume3DOverlay::getBounds() const {
|
||||||
return AABox(extents);
|
return AABox(extents);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Volume3DOverlay::setDimensions(const glm::vec3& value) {
|
||||||
|
_localBoundingBox.setBox(-value / 2.0f, value);
|
||||||
|
notifyRenderTransformChange();
|
||||||
|
}
|
||||||
|
|
||||||
void Volume3DOverlay::setProperties(const QVariantMap& properties) {
|
void Volume3DOverlay::setProperties(const QVariantMap& properties) {
|
||||||
Base3DOverlay::setProperties(properties);
|
Base3DOverlay::setProperties(properties);
|
||||||
|
|
||||||
|
@ -57,9 +62,7 @@ bool Volume3DOverlay::findRayIntersection(const glm::vec3& origin, const glm::ve
|
||||||
// extents is the entity relative, scaled, centered extents of the entity
|
// extents is the entity relative, scaled, centered extents of the entity
|
||||||
glm::mat4 worldToEntityMatrix;
|
glm::mat4 worldToEntityMatrix;
|
||||||
Transform transform = getTransform();
|
Transform transform = getTransform();
|
||||||
#ifndef USE_SN_SCALE
|
|
||||||
transform.setScale(1.0f); // ignore any inherited scale from SpatiallyNestable
|
transform.setScale(1.0f); // ignore any inherited scale from SpatiallyNestable
|
||||||
#endif
|
|
||||||
transform.getInverseMatrix(worldToEntityMatrix);
|
transform.getInverseMatrix(worldToEntityMatrix);
|
||||||
|
|
||||||
glm::vec3 overlayFrameOrigin = glm::vec3(worldToEntityMatrix * glm::vec4(origin, 1.0f));
|
glm::vec3 overlayFrameOrigin = glm::vec3(worldToEntityMatrix * glm::vec4(origin, 1.0f));
|
||||||
|
@ -69,3 +72,11 @@ bool Volume3DOverlay::findRayIntersection(const glm::vec3& origin, const glm::ve
|
||||||
// and testing intersection there.
|
// and testing intersection there.
|
||||||
return _localBoundingBox.findRayIntersection(overlayFrameOrigin, overlayFrameDirection, distance, face, surfaceNormal);
|
return _localBoundingBox.findRayIntersection(overlayFrameOrigin, overlayFrameDirection, distance, face, surfaceNormal);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Transform Volume3DOverlay::evalRenderTransform() {
|
||||||
|
Transform transform = getTransform();
|
||||||
|
#ifndef USE_SN_SCALE
|
||||||
|
transform.setScale(1.0f); // ignore any inherited scale from SpatiallyNestable
|
||||||
|
#endif
|
||||||
|
return transform;
|
||||||
|
}
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
|
|
||||||
class Volume3DOverlay : public Base3DOverlay {
|
class Volume3DOverlay : public Base3DOverlay {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
using Parent = Base3DOverlay;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Volume3DOverlay() {}
|
Volume3DOverlay() {}
|
||||||
|
@ -23,8 +24,8 @@ public:
|
||||||
virtual AABox getBounds() const override;
|
virtual AABox getBounds() const override;
|
||||||
|
|
||||||
const glm::vec3& getDimensions() const { return _localBoundingBox.getDimensions(); }
|
const glm::vec3& getDimensions() const { return _localBoundingBox.getDimensions(); }
|
||||||
void setDimensions(float value) { _localBoundingBox.setBox(glm::vec3(-value / 2.0f), value); }
|
void setDimensions(float value) { setDimensions(glm::vec3(value)); }
|
||||||
void setDimensions(const glm::vec3& value) { _localBoundingBox.setBox(-value / 2.0f, value); }
|
void setDimensions(const glm::vec3& value);
|
||||||
|
|
||||||
void setProperties(const QVariantMap& properties) override;
|
void setProperties(const QVariantMap& properties) override;
|
||||||
QVariant getProperty(const QString& property) override;
|
QVariant getProperty(const QString& property) override;
|
||||||
|
@ -35,6 +36,8 @@ public:
|
||||||
protected:
|
protected:
|
||||||
// Centered local bounding box
|
// Centered local bounding box
|
||||||
AABox _localBoundingBox{ vec3(0.0f), 1.0f };
|
AABox _localBoundingBox{ vec3(0.0f), 1.0f };
|
||||||
|
|
||||||
|
Transform evalRenderTransform() override;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|