Merge branch 'master' of https://github.com/highfidelity/hifi into oldPropsFilters
9
.gitignore
vendored
|
@ -77,3 +77,12 @@ TAGS
|
|||
# ignore node files for the console
|
||||
node_modules
|
||||
npm-debug.log
|
||||
|
||||
# Android studio files
|
||||
*___jb_old___
|
||||
|
||||
# Generated assets for Android
|
||||
android/app/src/main/assets
|
||||
|
||||
# Resource binary file
|
||||
interface/compiledResources
|
|
@ -1,5 +1,7 @@
|
|||
# this guide is specific to Ubuntu 16.04.
|
||||
# deb packages of High Fidelity domain server and assignment client are stored on debian.highfidelity.com
|
||||
## This guide is specific to Ubuntu 16.04.
|
||||
Deb packages of High Fidelity domain server and assignment client are stored on debian.highfidelity.com
|
||||
|
||||
```
|
||||
sudo su -
|
||||
apt-get -y update
|
||||
apt-get install -y software-properties-common
|
||||
|
@ -8,20 +10,27 @@ add-apt-repository "deb http://debian.highfidelity.com stable main"
|
|||
apt-get -y update
|
||||
apt-get install -y hifi-domain-server
|
||||
apt-get install -y hifi-assignment-client
|
||||
```
|
||||
|
||||
# When installing master/dev builds, the packages are slightly different and you just need to change the last 2 steps to:
|
||||
When installing master/dev builds, the packages are slightly different and you just need to change the last 2 steps to:
|
||||
```
|
||||
apt-get install -y hifi-dev-domain-server
|
||||
apt-get install -y hifi-dev-assignment-client
|
||||
```
|
||||
|
||||
# domain server and assignment clients should already be running. The processes are controlled via:
|
||||
Domain server and assignment clients should already be running. The processes are controlled via:
|
||||
```
|
||||
systemctl start hifi-domain-server
|
||||
systemctl stop hifi-domain-server
|
||||
```
|
||||
|
||||
# Once the machine is setup and processes are running you should ensure that your firewall exposes port 40100 on TCP and all UDP ports. This will get your domain up and running and you could connect to it (for now) by using High Fidelity Interface and typing in the IP for the place name. (further customizations can be done via http://IPAddress:40100).
|
||||
|
||||
# The server always depends on both hifi-domain-server and hifi-assignment-client running at the same time.
|
||||
# As an additional step, you should ensure that your packages are automatically updated when a new version goes out. You could, for example, set the automatic update checks to happen every hour (though this could potentially result in the domain being unreachable for a whole hour by new clients when they are released - adjust the update checks accordingly).
|
||||
Once the machine is setup and processes are running, you should ensure that your firewall exposes port 40100 on TCP and all UDP ports. This will get your domain up and running and you could connect to it (for now) by using High Fidelity Interface and typing in the IP for the place name. (Further customizations can be done via http://IPAddress:40100).
|
||||
|
||||
The server always depends on both hifi-domain-server and hifi-assignment-client running at the same time.
|
||||
As an additional step, you should ensure that your packages are automatically updated when a new version goes out. You could, for example, set the automatic update checks to happen every hour (though this could potentially result in the domain being unreachable for a whole hour by new clients when they are released - adjust the update checks accordingly).
|
||||
To do this you can modify /etc/crontab by adding the following lines
|
||||
```
|
||||
0 */1 * * * root apt-get update
|
||||
1 */1 * * * root apt-get install --only-upgrade -y hifi-domain-server
|
||||
2 */1 * * * root apt-get install --only-upgrade -y hifi-assignment-client
|
||||
```
|
||||
|
|
|
@ -26,9 +26,11 @@ endif()
|
|||
if (ANDROID OR UWP)
|
||||
option(BUILD_SERVER "Build server components" OFF)
|
||||
option(BUILD_TOOLS "Build tools" OFF)
|
||||
option(BUILD_INSTALLER "Build installer" OFF)
|
||||
else()
|
||||
option(BUILD_SERVER "Build server components" ON)
|
||||
option(BUILD_TOOLS "Build tools" ON)
|
||||
option(BUILD_INSTALLER "Build installer" ON)
|
||||
endif()
|
||||
|
||||
if (SERVER_ONLY)
|
||||
|
@ -40,25 +42,53 @@ else()
|
|||
endif()
|
||||
|
||||
if (ANDROID)
|
||||
set(PLATFORM_QT_COMPONENTS AndroidExtras WebView)
|
||||
set(PLATFORM_GL_BACKEND gpu-gles)
|
||||
option(USE_GLES "Use OpenGL ES" ON)
|
||||
set(PLATFORM_QT_COMPONENTS AndroidExtras WebView)
|
||||
else ()
|
||||
set(PLATFORM_QT_COMPONENTS WebEngine WebEngineWidgets)
|
||||
set(PLATFORM_GL_BACKEND gpu-gl)
|
||||
option(USE_GLES "Use OpenGL ES" OFF)
|
||||
set(PLATFORM_QT_COMPONENTS WebEngine WebEngineWidgets)
|
||||
endif ()
|
||||
|
||||
if (USE_GLES AND (NOT ANDROID))
|
||||
option(DISABLE_QML "Disable QML" ON)
|
||||
else()
|
||||
option(DISABLE_QML "Disable QML" OFF)
|
||||
endif()
|
||||
option(DISABLE_KTX_CACHE "Disable KTX Cache" OFF)
|
||||
|
||||
|
||||
|
||||
set(PLATFORM_QT_GL OpenGL)
|
||||
|
||||
if (USE_GLES)
|
||||
add_definitions(-DUSE_GLES)
|
||||
set(PLATFORM_GL_BACKEND gpu-gles)
|
||||
else()
|
||||
set(PLATFORM_GL_BACKEND gpu-gl)
|
||||
endif()
|
||||
|
||||
|
||||
foreach(PLATFORM_QT_COMPONENT ${PLATFORM_QT_COMPONENTS})
|
||||
list(APPEND PLATFORM_QT_LIBRARIES "Qt5::${PLATFORM_QT_COMPONENT}")
|
||||
endforeach()
|
||||
|
||||
|
||||
option(BUILD_INSTALLER "Build installer" ON)
|
||||
|
||||
MESSAGE(STATUS "Build server: " ${BUILD_SERVER})
|
||||
MESSAGE(STATUS "Build client: " ${BUILD_CLIENT})
|
||||
MESSAGE(STATUS "Build tests: " ${BUILD_TESTS})
|
||||
MESSAGE(STATUS "Build tools: " ${BUILD_TOOLS})
|
||||
MESSAGE(STATUS "Build installer: " ${BUILD_INSTALLER})
|
||||
MESSAGE(STATUS "GL ES: " ${USE_GLES})
|
||||
|
||||
if (DISABLE_QML)
|
||||
MESSAGE(STATUS "QML disabled!")
|
||||
add_definitions(-DDISABLE_QML)
|
||||
endif()
|
||||
|
||||
if (DISABLE_KTX_CACHE)
|
||||
MESSAGE(STATUS "KTX cache disabled!")
|
||||
add_definitions(-DDISABLE_KTX_CACHE)
|
||||
endif()
|
||||
|
||||
if (UNIX AND DEFINED ENV{HIFI_MEMORY_DEBUGGING})
|
||||
MESSAGE(STATUS "Memory debugging is enabled")
|
||||
|
|
|
@ -1,26 +1,28 @@
|
|||
set(TARGET_NAME native-lib)
|
||||
setup_hifi_library(Gui Qml Quick)
|
||||
|
||||
# Minimal dependencies for testing UI compositing
|
||||
#link_hifi_libraries(shared networking gl ui)
|
||||
|
||||
link_hifi_libraries(
|
||||
shared networking octree
|
||||
script-engine recording trackers
|
||||
gl ktx image gpu gpu-gles render render-utils
|
||||
physics
|
||||
audio audio-client
|
||||
ui midi controllers pointers
|
||||
graphics model-networking fbx animation
|
||||
entities entities-renderer
|
||||
avatars avatars-renderer
|
||||
ui-plugins input-plugins
|
||||
# display-plugins
|
||||
# auto-updater
|
||||
)
|
||||
|
||||
|
||||
target_link_libraries(native-lib android log m)
|
||||
setup_hifi_library()
|
||||
link_hifi_libraries(shared networking gl gpu image fbx render-utils physics entities octree ${PLATFORM_GL_BACKEND})
|
||||
target_opengl()
|
||||
target_bullet()
|
||||
|
||||
set(INTERFACE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../../interface")
|
||||
add_subdirectory("${INTERFACE_DIR}" "libraries/interface")
|
||||
include_directories("${INTERFACE_DIR}/src")
|
||||
|
||||
target_link_libraries(native-lib android log m interface)
|
||||
|
||||
set(GVR_ROOT "${HIFI_ANDROID_PRECOMPILED}/gvr/gvr-android-sdk-1.101.0/")
|
||||
target_include_directories(native-lib PRIVATE "${GVR_ROOT}/libraries/headers" "libraries/ui/src")
|
||||
target_link_libraries(native-lib "${GVR_ROOT}/libraries/libgvr.so" ui)
|
||||
|
||||
# finished libraries
|
||||
# core -> qt
|
||||
# networking -> openssl, tbb
|
||||
# fbx -> draco
|
||||
# physics -> bullet
|
||||
# entities-renderer -> polyvox
|
||||
|
||||
# unfinished libraries
|
||||
# image -> nvtt (doesn't look good, but can be made optional)
|
||||
# script-engine -> quazip (probably not required for the android client)
|
||||
|
||||
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
apply plugin: 'com.android.application'
|
||||
|
||||
|
||||
android {
|
||||
compileSdkVersion 26
|
||||
//buildToolsVersion '27.0.3'
|
||||
|
||||
defaultConfig {
|
||||
applicationId "com.highfidelity.iface"
|
||||
applicationId "io.highfidelity.hifiinterface"
|
||||
minSdkVersion 24
|
||||
targetSdkVersion 26
|
||||
versionCode 1
|
||||
|
@ -21,24 +22,19 @@ android {
|
|||
'-DHIFI_ANDROID_PRECOMPILED=' + HIFI_ANDROID_PRECOMPILED,
|
||||
'-DRELEASE_NUMBER=' + RELEASE_NUMBER,
|
||||
'-DRELEASE_TYPE=' + RELEASE_TYPE,
|
||||
'-DBUILD_BRANCH=' + BUILD_BRANCH
|
||||
'-DBUILD_BRANCH=' + BUILD_BRANCH,
|
||||
'-DDISABLE_QML=ON',
|
||||
'-DDISABLE_KTX_CACHE=ON'
|
||||
}
|
||||
}
|
||||
compileOptions {
|
||||
sourceCompatibility JavaVersion.VERSION_1_8
|
||||
targetCompatibility JavaVersion.VERSION_1_8
|
||||
}
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
applicationVariants.all { variant ->
|
||||
variant.outputs.all {
|
||||
if (RELEASE_NUMBER != '0') {
|
||||
outputFileName = "app_" + RELEASE_NUMBER + "_" + RELEASE_TYPE + ".apk"
|
||||
}
|
||||
}
|
||||
}
|
||||
compileOptions {
|
||||
sourceCompatibility JavaVersion.VERSION_1_8
|
||||
targetCompatibility JavaVersion.VERSION_1_8
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
release {
|
||||
minifyEnabled false
|
||||
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
|
||||
|
@ -50,11 +46,58 @@ android {
|
|||
path '../../CMakeLists.txt'
|
||||
}
|
||||
}
|
||||
|
||||
applicationVariants.all { variant ->
|
||||
// Our asset contents depend on items produced in the CMake build
|
||||
// so our merge has to depend on the external native build
|
||||
variant.externalNativeBuildTasks.each { task ->
|
||||
variant.mergeResources.dependsOn(task)
|
||||
}
|
||||
|
||||
variant.mergeAssets.doLast {
|
||||
def assetList = new LinkedList<String>()
|
||||
def youngestLastModified = 0
|
||||
|
||||
// Copy the compiled resources generated by the external native build
|
||||
copy {
|
||||
from new File(projectDir, "../../interface/compiledResources")
|
||||
into outputDir
|
||||
duplicatesStrategy DuplicatesStrategy.INCLUDE
|
||||
eachFile { details ->
|
||||
youngestLastModified = Math.max(youngestLastModified, details.lastModified)
|
||||
assetList.add(details.path)
|
||||
}
|
||||
}
|
||||
|
||||
// Copy the scripts directory
|
||||
copy {
|
||||
from new File(projectDir, "../../scripts")
|
||||
into new File(outputDir, "scripts")
|
||||
duplicatesStrategy DuplicatesStrategy.INCLUDE
|
||||
eachFile { details->
|
||||
youngestLastModified = Math.max(youngestLastModified, details.lastModified)
|
||||
assetList.add("scripts/" + details.path)
|
||||
}
|
||||
}
|
||||
|
||||
// Write a list of files to be unpacked to the cache folder
|
||||
new File(outputDir, 'cache_assets.txt').withWriter { out ->
|
||||
out.println(Long.toString(youngestLastModified))
|
||||
assetList.each { file -> out.println(file) }
|
||||
}
|
||||
}
|
||||
|
||||
variant.outputs.all {
|
||||
if (RELEASE_NUMBER != '0') {
|
||||
outputFileName = "app_" + RELEASE_NUMBER + "_" + RELEASE_TYPE + ".apk"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation 'com.google.vr:sdk-audio:1.80.0'
|
||||
implementation 'com.google.vr:sdk-base:1.80.0'
|
||||
implementation fileTree(dir: 'libs', include: ['*.jar'])
|
||||
implementation fileTree(include: ['*.jar'], dir: 'libs')
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="io.highfidelity.gvrinterface">
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="io.highfidelity.hifiinterface">
|
||||
|
||||
<uses-sdk android:minSdkVersion="24" android:targetSdkVersion="26" />
|
||||
<uses-feature android:glEsVersion="0x00030002" android:required="true" />
|
||||
<uses-permission android:name="android.permission.VIBRATE"/>
|
||||
|
@ -7,11 +8,13 @@
|
|||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
||||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
|
||||
<uses-permission android:name="android.permission.RECORD_AUDIO" />
|
||||
<uses-feature android:name="android.hardware.sensor.accelerometer" android:required="true"/>
|
||||
<uses-feature android:name="android.hardware.sensor.gyroscope" android:required="true"/>
|
||||
|
||||
<application
|
||||
android:name="org.qtproject.qt5.android.bindings.QtApplication"
|
||||
android:label="@string/app_name"
|
||||
android:hardwareAccelerated="true"
|
||||
android:allowBackup="true"
|
||||
android:screenOrientation="unspecified"
|
||||
|
@ -19,18 +22,34 @@
|
|||
android:icon="@mipmap/ic_launcher"
|
||||
android:launchMode="singleTop"
|
||||
android:roundIcon="@mipmap/ic_launcher_round">
|
||||
|
||||
<activity android:name="io.highfidelity.hifiinterface.PermissionChecker">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<activity android:name="io.highfidelity.hifiinterface.WebViewActivity"
|
||||
android:theme="@android:style/Theme.Material.Light.NoActionBar"/>
|
||||
<!-- We don't want to show this on Daydream yet (we need to fix the turn-around problem on this screen)
|
||||
<activity android:name="io.highfidelity.hifiinterface.GvrLoaderActivity">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="com.google.intent.category.DAYDREAM"/>
|
||||
</intent-filter>
|
||||
</activity>
|
||||
-->
|
||||
<activity
|
||||
android:configChanges="orientation|uiMode|screenLayout|screenSize|smallestScreenSize|locale|fontScale|keyboard|keyboardHidden|navigation"
|
||||
android:name=".InterfaceActivity"
|
||||
android:label="@string/app_name"
|
||||
android:configChanges="orientation|uiMode|screenLayout|screenSize|smallestScreenSize|layoutDirection|locale|fontScale|keyboard|keyboardHidden|navigation"
|
||||
android:launchMode="singleTop"
|
||||
android:screenOrientation="landscape"
|
||||
android:resizeableActivity="false">
|
||||
android:launchMode="singleTop"
|
||||
android:enableVrMode="com.google.vr.vrcore/com.google.vr.vrcore.common.VrCoreListenerService"
|
||||
>
|
||||
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
<category android:name="com.google.intent.category.DAYDREAM"/>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
</intent-filter>
|
||||
|
||||
<meta-data android:name="android.app.lib_name" android:value="native-lib"/>
|
||||
|
@ -43,4 +62,8 @@
|
|||
<meta-data android:name="android.app.extract_android_style" android:value="full"/>
|
||||
</activity>
|
||||
</application>
|
||||
</manifest>
|
||||
|
||||
<uses-feature android:name="android.software.vr.mode" android:required="true"/>
|
||||
<uses-feature android:name="android.hardware.vr.high_performance" android:required="true"/>
|
||||
|
||||
</manifest>
|
||||
|
|
|
@ -1,19 +0,0 @@
|
|||
import QtQuick 2.7
|
||||
import QtWebView 1.1
|
||||
|
||||
Rectangle {
|
||||
id: window
|
||||
anchors.fill: parent
|
||||
color: "red"
|
||||
ColorAnimation on color { from: "blue"; to: "yellow"; duration: 1000; loops: Animation.Infinite }
|
||||
|
||||
Text {
|
||||
text: "Hello"
|
||||
anchors.top: parent.top
|
||||
}
|
||||
WebView {
|
||||
anchors.fill: parent
|
||||
anchors.margins: 10
|
||||
url: "http://doc.qt.io/qt-5/qml-qtwebview-webview.html"
|
||||
}
|
||||
}
|
|
@ -1,153 +0,0 @@
|
|||
#include <jni.h>
|
||||
|
||||
#include <android/log.h>
|
||||
#include <QtCore/QDebug>
|
||||
#include <QtCore/QDir>
|
||||
#include <QtGui/QGuiApplication>
|
||||
#include <QtGui/QScreen>
|
||||
#include <QtQml/QQmlEngine>
|
||||
#include <QtQml/QQmlFileSelector>
|
||||
#include <QtQuick/QQuickView>
|
||||
#include <QtGui/QOpenGLContext>
|
||||
#include <QtCore/QLoggingCategory>
|
||||
#include <QtWebView/QtWebView>
|
||||
|
||||
#include <gl/Config.h>
|
||||
#include <gl/OffscreenGLCanvas.h>
|
||||
#include <gl/GLWindow.h>
|
||||
|
||||
#include <ui/OffscreenQmlSurface.h>
|
||||
|
||||
Q_LOGGING_CATEGORY(gpugllogging, "hifi.gl")
|
||||
|
||||
bool checkGLError(const char* name) {
|
||||
GLenum error = glGetError();
|
||||
if (!error) {
|
||||
return false;
|
||||
} else {
|
||||
switch (error) {
|
||||
case GL_INVALID_ENUM:
|
||||
qCDebug(gpugllogging) << "GLBackend::" << name << ": An unacceptable value is specified for an enumerated argument.The offending command is ignored and has no other side effect than to set the error flag.";
|
||||
break;
|
||||
case GL_INVALID_VALUE:
|
||||
qCDebug(gpugllogging) << "GLBackend" << name << ": A numeric argument is out of range.The offending command is ignored and has no other side effect than to set the error flag";
|
||||
break;
|
||||
case GL_INVALID_OPERATION:
|
||||
qCDebug(gpugllogging) << "GLBackend" << name << ": The specified operation is not allowed in the current state.The offending command is ignored and has no other side effect than to set the error flag..";
|
||||
break;
|
||||
case GL_INVALID_FRAMEBUFFER_OPERATION:
|
||||
qCDebug(gpugllogging) << "GLBackend" << name << ": The framebuffer object is not complete.The offending command is ignored and has no other side effect than to set the error flag.";
|
||||
break;
|
||||
case GL_OUT_OF_MEMORY:
|
||||
qCDebug(gpugllogging) << "GLBackend" << name << ": There is not enough memory left to execute the command.The state of the GL is undefined, except for the state of the error flags, after this error is recorded.";
|
||||
break;
|
||||
default:
|
||||
qCDebug(gpugllogging) << "GLBackend" << name << ": Unknown error: " << error;
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
bool checkGLErrorDebug(const char* name) {
|
||||
return checkGLError(name);
|
||||
}
|
||||
|
||||
|
||||
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());
|
||||
}
|
||||
|
||||
void qt_gl_set_global_share_context(QOpenGLContext *context);
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
qInstallMessageHandler(messageHandler);
|
||||
QCoreApplication::setAttribute(Qt::AA_DisableHighDpiScaling);
|
||||
QGuiApplication app(argc,argv);
|
||||
app.setOrganizationName("QtProject");
|
||||
app.setOrganizationDomain("qt-project.org");
|
||||
app.setApplicationName(QFileInfo(app.applicationFilePath()).baseName());
|
||||
QtWebView::initialize();
|
||||
qputenv("QSG_RENDERER_DEBUG", (QStringList() << "render" << "build" << "change" << "upload" << "roots" << "dump").join(';').toUtf8());
|
||||
|
||||
OffscreenGLCanvas sharedCanvas;
|
||||
if (!sharedCanvas.create()) {
|
||||
qFatal("Unable to create primary offscreen context");
|
||||
}
|
||||
qt_gl_set_global_share_context(sharedCanvas.getContext());
|
||||
auto globalContext = QOpenGLContext::globalShareContext();
|
||||
|
||||
GLWindow window;
|
||||
window.create();
|
||||
window.setGeometry(qApp->primaryScreen()->availableGeometry());
|
||||
window.createContext(globalContext);
|
||||
if (!window.makeCurrent()) {
|
||||
qFatal("Unable to make primary window GL context current");
|
||||
}
|
||||
|
||||
GLuint fbo = 0;
|
||||
glGenFramebuffers(1, &fbo);
|
||||
|
||||
static const ivec2 offscreenSize { 640, 480 };
|
||||
|
||||
OffscreenQmlSurface::setSharedContext(sharedCanvas.getContext());
|
||||
OffscreenQmlSurface* qmlSurface = new OffscreenQmlSurface();
|
||||
qmlSurface->create();
|
||||
qmlSurface->resize(fromGlm(offscreenSize));
|
||||
qmlSurface->load("qrc:///simple.qml");
|
||||
qmlSurface->resume();
|
||||
|
||||
auto discardLambda = qmlSurface->getDiscardLambda();
|
||||
|
||||
window.showFullScreen();
|
||||
QTimer timer;
|
||||
timer.setInterval(10);
|
||||
timer.setSingleShot(false);
|
||||
OffscreenQmlSurface::TextureAndFence currentTextureAndFence;
|
||||
timer.connect(&timer, &QTimer::timeout, &app, [&]{
|
||||
window.makeCurrent();
|
||||
glClearColor(0, 1, 0, 1);
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
|
||||
OffscreenQmlSurface::TextureAndFence newTextureAndFence;
|
||||
if (qmlSurface->fetchTexture(newTextureAndFence)) {
|
||||
if (currentTextureAndFence.first) {
|
||||
discardLambda(currentTextureAndFence.first, currentTextureAndFence.second);
|
||||
}
|
||||
currentTextureAndFence = newTextureAndFence;
|
||||
}
|
||||
checkGLErrorDebug(__FUNCTION__);
|
||||
|
||||
if (currentTextureAndFence.second) {
|
||||
glWaitSync((GLsync)currentTextureAndFence.second, 0, GL_TIMEOUT_IGNORED);
|
||||
glDeleteSync((GLsync)currentTextureAndFence.second);
|
||||
currentTextureAndFence.second = nullptr;
|
||||
}
|
||||
|
||||
if (currentTextureAndFence.first) {
|
||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo);
|
||||
glFramebufferTexture(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, currentTextureAndFence.first, 0);
|
||||
glBlitFramebuffer(0, 0, offscreenSize.x, offscreenSize.y, 100, 100, offscreenSize.x + 100, offscreenSize.y + 100, GL_COLOR_BUFFER_BIT, GL_NEAREST);
|
||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
|
||||
}
|
||||
|
||||
window.swapBuffers();
|
||||
window.doneCurrent();
|
||||
});
|
||||
timer.start();
|
||||
return app.exec();
|
||||
}
|
|
@ -1,6 +0,0 @@
|
|||
<RCC>
|
||||
<qresource prefix="/">
|
||||
<file>simple.qml</file>
|
||||
<file>+android/simple.qml</file>
|
||||
</qresource>
|
||||
</RCC>
|
160
android/app/src/main/cpp/native.cpp
Normal file
|
@ -0,0 +1,160 @@
|
|||
#include <functional>
|
||||
|
||||
|
||||
#include <QtCore/QBuffer>
|
||||
#include <QtCore/QDebug>
|
||||
#include <QtCore/QDir>
|
||||
#include <QtCore/QFile>
|
||||
#include <QtCore/QThread>
|
||||
#include <QtCore/QStringList>
|
||||
#include <QtCore/QStandardPaths>
|
||||
#include <QtCore/QTextStream>
|
||||
|
||||
#include <QtAndroidExtras/QAndroidJniObject>
|
||||
|
||||
#include <android/log.h>
|
||||
#include <android/asset_manager.h>
|
||||
#include <android/asset_manager_jni.h>
|
||||
|
||||
#include <shared/Storage.h>
|
||||
|
||||
void tempMessageHandler(QtMsgType type, const QMessageLogContext& context, const QString& message) {
|
||||
if (!message.isEmpty()) {
|
||||
const char * local=message.toStdString().c_str();
|
||||
switch (type) {
|
||||
case QtDebugMsg:
|
||||
__android_log_write(ANDROID_LOG_DEBUG,"Interface",local);
|
||||
break;
|
||||
case QtInfoMsg:
|
||||
__android_log_write(ANDROID_LOG_INFO,"Interface",local);
|
||||
break;
|
||||
case QtWarningMsg:
|
||||
__android_log_write(ANDROID_LOG_WARN,"Interface",local);
|
||||
break;
|
||||
case QtCriticalMsg:
|
||||
__android_log_write(ANDROID_LOG_ERROR,"Interface",local);
|
||||
break;
|
||||
case QtFatalMsg:
|
||||
default:
|
||||
__android_log_write(ANDROID_LOG_FATAL,"Interface",local);
|
||||
abort();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
AAssetManager* g_assetManager = nullptr;
|
||||
|
||||
void withAssetData(const char* filename, const std::function<void(off64_t, const void*)>& callback) {
|
||||
auto asset = AAssetManager_open(g_assetManager, filename, AASSET_MODE_BUFFER);
|
||||
if (!asset) {
|
||||
throw std::runtime_error("Failed to open file");
|
||||
}
|
||||
auto buffer = AAsset_getBuffer(asset);
|
||||
off64_t size = AAsset_getLength64(asset);
|
||||
callback(size, buffer);
|
||||
AAsset_close(asset);
|
||||
}
|
||||
|
||||
QStringList readAssetLines(const char* filename) {
|
||||
QStringList result;
|
||||
withAssetData(filename, [&](off64_t size, const void* data){
|
||||
QByteArray buffer = QByteArray::fromRawData((const char*)data, size);
|
||||
{
|
||||
QTextStream in(&buffer);
|
||||
while (!in.atEnd()) {
|
||||
QString line = in.readLine();
|
||||
result << line;
|
||||
}
|
||||
}
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
void copyAsset(const char* sourceAsset, const QString& destFilename) {
|
||||
withAssetData(sourceAsset, [&](off64_t size, const void* data){
|
||||
QFile file(destFilename);
|
||||
if (!file.open(QFile::ReadWrite | QIODevice::Truncate)) {
|
||||
throw std::runtime_error("Unable to open output file for writing");
|
||||
}
|
||||
if (!file.resize(size)) {
|
||||
throw std::runtime_error("Unable to resize output file");
|
||||
}
|
||||
if (size != 0) {
|
||||
auto mapped = file.map(0, size);
|
||||
if (!mapped) {
|
||||
throw std::runtime_error("Unable to map output file");
|
||||
}
|
||||
memcpy(mapped, data, size);
|
||||
}
|
||||
file.close();
|
||||
});
|
||||
}
|
||||
|
||||
void unpackAndroidAssets() {
|
||||
const QString DEST_PREFIX = QStandardPaths::writableLocation(QStandardPaths::CacheLocation) + "/";
|
||||
|
||||
QStringList filesToCopy = readAssetLines("cache_assets.txt");
|
||||
QString dateStamp = filesToCopy.takeFirst();
|
||||
QString dateStampFilename = DEST_PREFIX + dateStamp;
|
||||
qDebug() << "Checking date stamp" << dateStamp;
|
||||
if (QFileInfo(dateStampFilename).exists()) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto rootDir = QDir::root();
|
||||
for (const auto& fileToCopy : filesToCopy) {
|
||||
auto destFileName = DEST_PREFIX + fileToCopy;
|
||||
auto destFolder = QFileInfo(destFileName).absoluteDir();
|
||||
if (!destFolder.exists()) {
|
||||
qDebug() << "Creating folder" << destFolder.absolutePath();
|
||||
if (!rootDir.mkpath(destFolder.absolutePath())) {
|
||||
throw std::runtime_error("Error creating output path");
|
||||
}
|
||||
}
|
||||
if (QFile::exists(destFileName)) {
|
||||
qDebug() << "Removing old file" << destFileName;
|
||||
if (!QFile::remove(destFileName)) {
|
||||
throw std::runtime_error("Failed to remove existing file");
|
||||
}
|
||||
}
|
||||
|
||||
qDebug() << "Copying asset " << fileToCopy << "to" << destFileName;
|
||||
copyAsset(fileToCopy.toStdString().c_str(), destFileName);
|
||||
}
|
||||
|
||||
{
|
||||
qDebug() << "Writing date stamp" << dateStamp;
|
||||
QFile file(dateStampFilename);
|
||||
if (!file.open(QIODevice::ReadWrite | QIODevice::Truncate)) {
|
||||
throw std::runtime_error("Can't write date stamp");
|
||||
}
|
||||
QTextStream(&file) << "touch" << endl;
|
||||
file.close();
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
|
||||
JNIEXPORT void Java_io_highfidelity_hifiinterface_InterfaceActivity_nativeOnCreate(JNIEnv* env, jobject obj, jobject instance, jobject asset_mgr) {
|
||||
qDebug() << "nativeOnCreate On thread " << QThread::currentThreadId();
|
||||
g_assetManager = AAssetManager_fromJava(env, asset_mgr);
|
||||
auto oldMessageHandler = qInstallMessageHandler(tempMessageHandler);
|
||||
unpackAndroidAssets();
|
||||
qInstallMessageHandler(oldMessageHandler);
|
||||
}
|
||||
|
||||
JNIEXPORT void Java_io_highfidelity_hifiinterface_InterfaceActivity_nativeOnPause(JNIEnv* env, jobject obj) {
|
||||
qDebug() << "nativeOnPause";
|
||||
}
|
||||
|
||||
JNIEXPORT void Java_io_highfidelity_hifiinterface_InterfaceActivity_nativeOnResume(JNIEnv* env, jobject obj) {
|
||||
qDebug() << "nativeOnResume";
|
||||
}
|
||||
|
||||
JNIEXPORT void Java_io_highfidelity_hifiinterface_InterfaceActivity_nativeOnExitVr(JNIEnv* env, jobject obj) {
|
||||
qDebug() << "nativeOnCreate On thread " << QThread::currentThreadId();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -1,10 +0,0 @@
|
|||
import QtQuick 2.0
|
||||
|
||||
Rectangle {
|
||||
id: window
|
||||
width: 320
|
||||
height: 480
|
||||
focus: true
|
||||
color: "red"
|
||||
ColorAnimation on color { from: "red"; to: "yellow"; duration: 1000; loops: Animation.Infinite }
|
||||
}
|
|
@ -0,0 +1,178 @@
|
|||
//
|
||||
// InterfaceActivity.java
|
||||
// android/app/src/main/java
|
||||
//
|
||||
// Created by Stephen Birarda on 1/26/15.
|
||||
// Copyright 2015 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
package io.highfidelity.hifiinterface;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.content.res.AssetManager;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.view.WindowManager;
|
||||
import android.util.Log;
|
||||
import org.qtproject.qt5.android.bindings.QtActivity;
|
||||
|
||||
/*import com.google.vr.cardboard.DisplaySynchronizer;
|
||||
import com.google.vr.cardboard.DisplayUtils;
|
||||
import com.google.vr.ndk.base.GvrApi;*/
|
||||
import android.graphics.Point;
|
||||
import android.content.res.Configuration;
|
||||
import android.content.pm.ActivityInfo;
|
||||
import android.content.pm.PackageInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.view.View;
|
||||
|
||||
public class InterfaceActivity extends QtActivity {
|
||||
|
||||
//public static native void handleHifiURL(String hifiURLString);
|
||||
private native long nativeOnCreate(InterfaceActivity instance, AssetManager assetManager);
|
||||
//private native void nativeOnPause();
|
||||
//private native void nativeOnResume();
|
||||
//private native void nativeOnStop();
|
||||
//private native void nativeOnStart();
|
||||
//private native void saveRealScreenSize(int width, int height);
|
||||
//private native void setAppVersion(String version);
|
||||
private native long nativeOnExitVr();
|
||||
|
||||
private AssetManager assetManager;
|
||||
|
||||
private static boolean inVrMode;
|
||||
// private GvrApi gvrApi;
|
||||
// Opaque native pointer to the Application C++ object.
|
||||
// This object is owned by the InterfaceActivity instance and passed to the native methods.
|
||||
//private long nativeGvrApi;
|
||||
|
||||
public void enterVr() {
|
||||
//Log.d("[VR]", "Entering Vr mode (java)");
|
||||
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);
|
||||
inVrMode = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
|
||||
|
||||
// Get the intent that started this activity in case we have a hifi:// URL to parse
|
||||
Intent intent = getIntent();
|
||||
if (intent.getAction() == Intent.ACTION_VIEW) {
|
||||
Uri data = intent.getData();
|
||||
|
||||
// if (data.getScheme().equals("hifi")) {
|
||||
// handleHifiURL(data.toString());
|
||||
// }
|
||||
}
|
||||
|
||||
/* DisplaySynchronizer displaySynchronizer = new DisplaySynchronizer(this, DisplayUtils.getDefaultDisplay(this));
|
||||
gvrApi = new GvrApi(this, displaySynchronizer);
|
||||
*/
|
||||
// Log.d("GVR", "gvrApi.toString(): " + gvrApi.toString());
|
||||
|
||||
assetManager = getResources().getAssets();
|
||||
|
||||
//nativeGvrApi =
|
||||
nativeOnCreate(this, assetManager /*, gvrApi.getNativeGvrContext()*/);
|
||||
|
||||
Point size = new Point();
|
||||
getWindowManager().getDefaultDisplay().getRealSize(size);
|
||||
// saveRealScreenSize(size.x, size.y);
|
||||
|
||||
try {
|
||||
PackageInfo pInfo = this.getPackageManager().getPackageInfo(getPackageName(), 0);
|
||||
String version = pInfo.versionName;
|
||||
// setAppVersion(version);
|
||||
} catch (PackageManager.NameNotFoundException e) {
|
||||
Log.e("GVR", "Error getting application version", e);
|
||||
}
|
||||
|
||||
final View rootView = getWindow().getDecorView().findViewById(android.R.id.content);
|
||||
|
||||
// This is a workaround to hide the menu bar when the virtual keyboard is shown from Qt
|
||||
rootView.getViewTreeObserver().addOnGlobalLayoutListener(new android.view.ViewTreeObserver.OnGlobalLayoutListener() {
|
||||
@Override
|
||||
public void onGlobalLayout() {
|
||||
int heightDiff = rootView.getRootView().getHeight() - rootView.getHeight();
|
||||
if (getActionBar().isShowing()) {
|
||||
getActionBar().hide();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPause() {
|
||||
super.onPause();
|
||||
//nativeOnPause();
|
||||
//gvrApi.pauseTracking();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onStart() {
|
||||
super.onStart();
|
||||
// nativeOnStart();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onStop() {
|
||||
Log.d("[Background]","Calling nativeOnStop from InterfaceActivity");
|
||||
// nativeOnStop();
|
||||
super.onStop();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onResume() {
|
||||
super.onResume();
|
||||
//nativeOnResume();
|
||||
//gvrApi.resumeTracking();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onConfigurationChanged(Configuration newConfig) {
|
||||
super.onConfigurationChanged(newConfig);
|
||||
// Checks the orientation of the screen
|
||||
if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT){
|
||||
// Log.d("[VR]", "Portrait, forcing landscape");
|
||||
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
|
||||
if (inVrMode) {
|
||||
inVrMode = false;
|
||||
// Log.d("[VR]", "Starting VR exit");
|
||||
nativeOnExitVr();
|
||||
} else {
|
||||
Log.w("[VR]", "Portrait detected but not in VR mode. Should not happen");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void openUrlInAndroidWebView(String urlString) {
|
||||
Log.d("openUrl", "Received in open " + urlString);
|
||||
Intent openUrlIntent = new Intent(this, WebViewActivity.class);
|
||||
openUrlIntent.putExtra(WebViewActivity.WEB_VIEW_ACTIVITY_EXTRA_URL, urlString);
|
||||
startActivity(openUrlIntent);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when view focus is changed
|
||||
*/
|
||||
@Override
|
||||
public void onWindowFocusChanged(boolean hasFocus) {
|
||||
super.onWindowFocusChanged(hasFocus);
|
||||
if (hasFocus) {
|
||||
final int uiOptions = 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;
|
||||
|
||||
getWindow().getDecorView().setSystemUiVisibility(uiOptions);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,130 @@
|
|||
package io.highfidelity.hifiinterface;
|
||||
|
||||
import android.Manifest;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.os.Bundle;
|
||||
import android.app.Activity;
|
||||
|
||||
import android.content.DialogInterface;
|
||||
import android.app.AlertDialog;
|
||||
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
import android.util.Log;
|
||||
import java.io.BufferedWriter;
|
||||
import java.io.File;
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
import java.io.Writer;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
public class PermissionChecker extends Activity {
|
||||
private static final int REQUEST_PERMISSIONS = 20;
|
||||
|
||||
private static final boolean CHOOSE_AVATAR_ON_STARTUP = false;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
if (CHOOSE_AVATAR_ON_STARTUP) {
|
||||
showMenu();
|
||||
}
|
||||
this.requestAppPermissions(new
|
||||
String[]{
|
||||
Manifest.permission.READ_EXTERNAL_STORAGE,
|
||||
Manifest.permission.WRITE_EXTERNAL_STORAGE,
|
||||
Manifest.permission.RECORD_AUDIO,
|
||||
Manifest.permission.CAMERA}
|
||||
,2,REQUEST_PERMISSIONS);
|
||||
|
||||
}
|
||||
|
||||
public void requestAppPermissions(final String[] requestedPermissions,
|
||||
final int stringId, final int requestCode) {
|
||||
int permissionCheck = PackageManager.PERMISSION_GRANTED;
|
||||
boolean shouldShowRequestPermissionRationale = false;
|
||||
for (String permission : requestedPermissions) {
|
||||
permissionCheck = permissionCheck + checkSelfPermission(permission);
|
||||
shouldShowRequestPermissionRationale = shouldShowRequestPermissionRationale || shouldShowRequestPermissionRationale(permission);
|
||||
}
|
||||
if (permissionCheck != PackageManager.PERMISSION_GRANTED) {
|
||||
System.out.println("Permission was not granted. Ask for permissions");
|
||||
if (shouldShowRequestPermissionRationale) {
|
||||
requestPermissions(requestedPermissions, requestCode);
|
||||
} else {
|
||||
requestPermissions(requestedPermissions, requestCode);
|
||||
}
|
||||
} else {
|
||||
System.out.println("Launching the other activity..");
|
||||
launchActivityWithPermissions();
|
||||
}
|
||||
}
|
||||
|
||||
private void launchActivityWithPermissions(){
|
||||
finish();
|
||||
Intent i = new Intent(this, InterfaceActivity.class);
|
||||
startActivity(i);
|
||||
finish();
|
||||
}
|
||||
|
||||
private void showMenu(){
|
||||
final List<String> avatarOptions = Arrays.asList("\uD83D\uDC66\uD83C\uDFFB Cody","\uD83D\uDC66\uD83C\uDFFF Will","\uD83D\uDC68\uD83C\uDFFD Albert", "\uD83D\uDC7D Being of Light");
|
||||
final String[] avatarPaths = {
|
||||
"http://mpassets.highfidelity.com/8c859fca-4cbd-4e82-aad1-5f4cb0ca5d53-v1/cody.fst",
|
||||
"http://mpassets.highfidelity.com/d029ae8d-2905-4eb7-ba46-4bd1b8cb9d73-v1/4618d52e711fbb34df442b414da767bb.fst",
|
||||
"http://mpassets.highfidelity.com/1e57c395-612e-4acd-9561-e79dbda0bc49-v1/albert.fst" };
|
||||
|
||||
final String pathForJson = "/data/data/io.highfidelity.hifiinterface/files/.config/High Fidelity - dev/";
|
||||
new AlertDialog.Builder(this)
|
||||
.setTitle("Pick an avatar")
|
||||
.setItems(avatarOptions.toArray(new CharSequence[avatarOptions.size()]),new DialogInterface.OnClickListener(){
|
||||
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
if(which < avatarPaths.length ) {
|
||||
JSONObject obj = new JSONObject();
|
||||
try {
|
||||
obj.put("firstRun",false);
|
||||
obj.put("Avatar/fullAvatarURL", avatarPaths[which]);
|
||||
File directory = new File(pathForJson);
|
||||
|
||||
if(!directory.exists()) directory.mkdirs();
|
||||
|
||||
File file = new File(pathForJson + "Interface.json");
|
||||
Writer output = new BufferedWriter(new FileWriter(file));
|
||||
output.write(obj.toString().replace("\\",""));
|
||||
output.close();
|
||||
System.out.println("I Could write config file expect to see the selected avatar"+obj.toString().replace("\\",""));
|
||||
|
||||
} catch (JSONException e) {
|
||||
System.out.println("JSONException something weired went wrong");
|
||||
} catch (IOException e) {
|
||||
System.out.println("Could not write file :(");
|
||||
}
|
||||
} else {
|
||||
System.out.println("Default avatar selected...");
|
||||
}
|
||||
launchActivityWithPermissions();
|
||||
}
|
||||
}).show();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
|
||||
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
|
||||
int permissionCheck = PackageManager.PERMISSION_GRANTED;
|
||||
for (int permission : grantResults) {
|
||||
permissionCheck = permissionCheck + permission;
|
||||
}
|
||||
if ((grantResults.length > 0) && permissionCheck == PackageManager.PERMISSION_GRANTED) {
|
||||
launchActivityWithPermissions();
|
||||
} else if (grantResults.length > 0) {
|
||||
System.out.println("User has deliberately denied Permissions. Launching anyways");
|
||||
launchActivityWithPermissions();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,242 @@
|
|||
//
|
||||
// WebViewActivity.java
|
||||
// interface/java
|
||||
//
|
||||
// Created by Cristian Duarte and Gabriel Calero on 8/17/17.
|
||||
// Copyright 2017 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
//package hifiinterface.highfidelity.io.mybrowserapplication;
|
||||
package io.highfidelity.hifiinterface;
|
||||
|
||||
import android.app.ActionBar;
|
||||
import android.app.Activity;
|
||||
import android.content.Intent;
|
||||
import android.graphics.Bitmap;
|
||||
import android.net.Uri;
|
||||
import android.net.http.SslError;
|
||||
import android.os.Bundle;
|
||||
import android.util.Log;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuInflater;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.webkit.SslErrorHandler;
|
||||
import android.webkit.WebChromeClient;
|
||||
import android.webkit.WebResourceError;
|
||||
import android.webkit.WebResourceRequest;
|
||||
import android.webkit.WebResourceResponse;
|
||||
import android.webkit.WebSettings;
|
||||
import android.webkit.WebView;
|
||||
import android.webkit.WebViewClient;
|
||||
import android.widget.ProgressBar;
|
||||
import android.widget.Toast;
|
||||
import android.widget.Toolbar;
|
||||
import android.os.Looper;
|
||||
import java.lang.Thread;
|
||||
import java.lang.Runnable;
|
||||
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
|
||||
public class WebViewActivity extends Activity {
|
||||
|
||||
public static final String WEB_VIEW_ACTIVITY_EXTRA_URL = "url";
|
||||
|
||||
private native void nativeProcessURL(String url);
|
||||
|
||||
private WebView myWebView;
|
||||
private ProgressBar mProgressBar;
|
||||
private ActionBar mActionBar;
|
||||
private String mUrl;
|
||||
|
||||
enum SafenessLevel {
|
||||
NOT_ANALYZED_YET(""),
|
||||
NOT_SECURE(""),
|
||||
SECURE("\uD83D\uDD12 "),
|
||||
BAD_SECURE("\uD83D\uDD13 ");
|
||||
|
||||
String icon;
|
||||
SafenessLevel(String icon) {
|
||||
this.icon = icon;
|
||||
}
|
||||
}
|
||||
|
||||
private SafenessLevel safenessLevel = SafenessLevel.NOT_ANALYZED_YET;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.activity_web_view);
|
||||
|
||||
setActionBar((Toolbar) findViewById(R.id.toolbar_actionbar));
|
||||
mActionBar = getActionBar();
|
||||
mActionBar.setDisplayHomeAsUpEnabled(true);
|
||||
|
||||
mProgressBar = (ProgressBar) findViewById(R.id.toolbarProgressBar);
|
||||
|
||||
mUrl = getIntent().getStringExtra(WEB_VIEW_ACTIVITY_EXTRA_URL);
|
||||
myWebView = (WebView) findViewById(R.id.web_view);
|
||||
myWebView.setWebViewClient(new HiFiWebViewClient());
|
||||
myWebView.setWebChromeClient(new HiFiWebChromeClient());
|
||||
WebSettings webSettings = myWebView.getSettings();
|
||||
webSettings.setJavaScriptEnabled(true);
|
||||
webSettings.setBuiltInZoomControls(true);
|
||||
webSettings.setDisplayZoomControls(false);
|
||||
myWebView.loadUrl(mUrl);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onKeyDown(int keyCode, KeyEvent event) {
|
||||
// Check if the key event was the Back button and if there's history
|
||||
if ((keyCode == KeyEvent.KEYCODE_BACK) && myWebView.canGoBack()) {
|
||||
myWebView.goBack();
|
||||
return true;
|
||||
}
|
||||
// If it wasn't the Back key or there's no web page history, bubble up to the default
|
||||
// system behavior (probably exit the activity)
|
||||
return super.onKeyDown(keyCode, event);
|
||||
}
|
||||
|
||||
private void showSubtitleWithUrl(String url) {
|
||||
try {
|
||||
mActionBar.setSubtitle(safenessLevel.icon + new URL(url.toString()).getHost());
|
||||
} catch (MalformedURLException e) {
|
||||
Toast.makeText(WebViewActivity.this, "Error loading page: " + "bad url", Toast.LENGTH_LONG).show();
|
||||
Log.e("openUrl", "bad url");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCreateOptionsMenu(Menu menu) {
|
||||
MenuInflater inflater = getMenuInflater();
|
||||
inflater.inflate(R.menu.web_view_menu, menu);
|
||||
return true;
|
||||
}
|
||||
|
||||
private String intentUrlOrWebUrl() {
|
||||
return myWebView==null || myWebView.getUrl()==null?mUrl:myWebView.getUrl();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item){
|
||||
switch (item.getItemId()) {
|
||||
// Respond to the action bar's Up/Home/back button
|
||||
case android.R.id.home:
|
||||
finish();
|
||||
break;
|
||||
case R.id.action_browser:
|
||||
Intent i = new Intent(Intent.ACTION_VIEW);
|
||||
i.setData(Uri.parse(intentUrlOrWebUrl()));
|
||||
startActivity(i);
|
||||
return true;
|
||||
case R.id.action_share:
|
||||
Intent is = new Intent(Intent.ACTION_SEND);
|
||||
is.setType("text/plain");
|
||||
is.putExtra(Intent.EXTRA_SUBJECT, getString(R.string.web_view_action_share_subject));
|
||||
is.putExtra(Intent.EXTRA_TEXT, intentUrlOrWebUrl());
|
||||
startActivity(Intent.createChooser(is, getString(R.string.web_view_action_share_chooser)));
|
||||
return true;
|
||||
}
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
|
||||
class HiFiWebViewClient extends WebViewClient {
|
||||
|
||||
@Override
|
||||
public void onPageFinished(WebView view, String url) {
|
||||
super.onPageFinished(view, url);
|
||||
mProgressBar.setVisibility(View.GONE);
|
||||
if (safenessLevel!=SafenessLevel.BAD_SECURE) {
|
||||
if (url.startsWith("https:")) {
|
||||
safenessLevel=SafenessLevel.SECURE;
|
||||
} else {
|
||||
safenessLevel=SafenessLevel.NOT_SECURE;
|
||||
}
|
||||
}
|
||||
showSubtitleWithUrl(url);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPageStarted(WebView view, String url, Bitmap favicon) {
|
||||
super.onPageStarted(view, url, favicon);
|
||||
safenessLevel = SafenessLevel.NOT_ANALYZED_YET;
|
||||
mProgressBar.setVisibility(View.VISIBLE);
|
||||
mProgressBar.setProgress(0);
|
||||
showSubtitleWithUrl(url);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onReceivedError(WebView view, WebResourceRequest request, WebResourceError error) {
|
||||
Toast.makeText(WebViewActivity.this, "Error loading page: " + error.getDescription(), Toast.LENGTH_LONG).show();
|
||||
if (ERROR_FAILED_SSL_HANDSHAKE == error.getErrorCode()) {
|
||||
safenessLevel = SafenessLevel.BAD_SECURE;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onReceivedHttpError(WebView view, WebResourceRequest request, WebResourceResponse errorResponse) {
|
||||
Toast.makeText(WebViewActivity.this, "Network Error loading page: " + errorResponse.getReasonPhrase(), Toast.LENGTH_LONG).show();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) {
|
||||
super.onReceivedSslError(view, handler, error);
|
||||
Toast.makeText(WebViewActivity.this, "SSL error loading page: " + error.toString(), Toast.LENGTH_LONG).show();
|
||||
safenessLevel = SafenessLevel.BAD_SECURE;
|
||||
}
|
||||
|
||||
private boolean isFst(WebResourceRequest request) {
|
||||
return isFst(request.getUrl().toString());
|
||||
}
|
||||
|
||||
private boolean isFst(String url) {
|
||||
return url.endsWith(".fst");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {
|
||||
// managing avatar selections
|
||||
if (isFst(request)) {
|
||||
final String url = request.getUrl().toString();
|
||||
new Thread(new Runnable() {
|
||||
public void run() {
|
||||
nativeProcessURL(url);
|
||||
}
|
||||
}).start(); // Avoid deadlock in Qt dialog
|
||||
WebViewActivity.this.finish();
|
||||
return true;
|
||||
}
|
||||
return super.shouldOverrideUrlLoading(view, request);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoadResource(WebView view, String url) {
|
||||
if (isFst(url)) {
|
||||
// processed separately
|
||||
} else {
|
||||
super.onLoadResource(view, url);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class HiFiWebChromeClient extends WebChromeClient {
|
||||
|
||||
@Override
|
||||
public void onProgressChanged(WebView view, int newProgress) {
|
||||
super.onProgressChanged(view, newProgress);
|
||||
mProgressBar.setProgress(newProgress);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onReceivedTitle(WebView view, String title) {
|
||||
super.onReceivedTitle(view, title);
|
||||
mActionBar.setTitle(title);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24.0"
|
||||
android:viewportHeight="24.0">
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M19,6.41L17.59,5 12,10.59 6.41,5 5,6.41 10.59,12 5,17.59 6.41,19 12,13.41 17.59,19 19,17.59 13.41,12z"/>
|
||||
</vector>
|
34
android/app/src/main/res/layout/activity_web_view.xml
Normal file
|
@ -0,0 +1,34 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<Toolbar
|
||||
android:id="@+id/toolbar_actionbar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="?android:attr/actionBarSize"
|
||||
android:layout_alignParentTop="true"
|
||||
style="@android:style/Widget.Material.ActionBar"
|
||||
android:titleTextAppearance="@style/ActionBarTitleStyle"
|
||||
android:subtitleTextAppearance="@style/ActionBarSubtitleStyle"
|
||||
android:navigationIcon="@drawable/ic_close_black_24dp"
|
||||
android:contentInsetStart="0dp"
|
||||
android:contentInsetStartWithNavigation="0dp"
|
||||
android:title="">
|
||||
</Toolbar>
|
||||
|
||||
<WebView
|
||||
android:id="@+id/web_view"
|
||||
android:layout_below="@id/toolbar_actionbar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"/>
|
||||
<ProgressBar
|
||||
android:id="@+id/toolbarProgressBar"
|
||||
android:layout_below="@id/toolbar_actionbar"
|
||||
style="?android:attr/progressBarStyleHorizontal"
|
||||
android:visibility="gone"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="3dp"
|
||||
android:indeterminate="false"
|
||||
android:padding="0dp" />
|
||||
</RelativeLayout>
|
10
android/app/src/main/res/menu/web_view_menu.xml
Normal file
|
@ -0,0 +1,10 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<menu xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item
|
||||
android:id="@+id/action_share"
|
||||
android:title="@string/web_view_action_share"
|
||||
android:showAsAction="never"/>
|
||||
<item android:id="@+id/action_browser"
|
||||
android:title="@string/web_view_action_open_in_browser"
|
||||
android:showAsAction="never"/>
|
||||
</menu>
|
Before ![]() (image error) Size: 3.3 KiB After ![]() (image error) Size: 5.1 KiB ![]() ![]() |
Before ![]() (image error) Size: 4.1 KiB After ![]() (image error) Size: 4.9 KiB ![]() ![]() |
Before ![]() (image error) Size: 2.2 KiB After ![]() (image error) Size: 4.2 KiB ![]() ![]() |
Before ![]() (image error) Size: 2.5 KiB After ![]() (image error) Size: 4.3 KiB ![]() ![]() |
Before ![]() (image error) Size: 4.7 KiB After ![]() (image error) Size: 5.8 KiB ![]() ![]() |
Before ![]() (image error) Size: 6 KiB After ![]() (image error) Size: 5.5 KiB ![]() ![]() |
Before ![]() (image error) Size: 7.5 KiB After ![]() (image error) Size: 7.3 KiB ![]() ![]() |
Before ![]() (image error) Size: 9.8 KiB After ![]() (image error) Size: 6.7 KiB ![]() ![]() |
Before ![]() (image error) Size: 10 KiB After ![]() (image error) Size: 8.9 KiB ![]() ![]() |
Before ![]() (image error) Size: 14 KiB After ![]() (image error) Size: 8.2 KiB ![]() ![]() |
12
android/app/src/main/res/values/dimens.xml
Normal file
|
@ -0,0 +1,12 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<!-- Default screen margins, per the Android Design guidelines. -->
|
||||
<dimen name="activity_horizontal_margin">16dp</dimen>
|
||||
<dimen name="activity_vertical_margin">16dp</dimen>
|
||||
|
||||
<!-- Hack to have a desired text size for both orientations (default portrait is too big) -->
|
||||
<!-- Default text size for action bar title.-->
|
||||
<dimen name="text_size_title_material_toolbar">14dp</dimen>
|
||||
<!-- Default text size for action bar subtitle.-->
|
||||
<dimen name="text_size_subtitle_material_toolbar">12dp</dimen>
|
||||
</resources>
|
|
@ -1,3 +1,8 @@
|
|||
<resources>
|
||||
<string name="app_name">TestApp</string>
|
||||
<string name="app_name" translatable="false">Interface</string>
|
||||
<string name="web_view_action_open_in_browser" translatable="false">Open in browser</string>
|
||||
<string name="web_view_action_share" translatable="false">Share link</string>
|
||||
<string name="web_view_action_share_subject" translatable="false">Shared a link</string>
|
||||
<string name="web_view_action_share_chooser" translatable="false">Share link</string>
|
||||
|
||||
</resources>
|
||||
|
|
|
@ -11,5 +11,15 @@
|
|||
<!--item name="android:background">@color/white_opaque</item-->
|
||||
</style>
|
||||
|
||||
|
||||
<!-- Overriding text size so it's not so big in portrait -->
|
||||
<style name="ActionBarTitleStyle"
|
||||
parent="@android:style/TextAppearance.Material.Widget.ActionBar.Title">
|
||||
<item name="android:textSize">@dimen/text_size_title_material_toolbar</item>
|
||||
</style>
|
||||
<style name="ActionBarSubtitleStyle"
|
||||
parent="@android:style/TextAppearance.Material.Widget.ActionBar.Subtitle">
|
||||
<item name="android:textSize">@dimen/text_size_subtitle_material_toolbar</item>
|
||||
</style>
|
||||
|
||||
|
||||
</resources>
|
||||
|
|
|
@ -40,6 +40,7 @@ ext {
|
|||
BUILD_BRANCH = project.hasProperty('BUILD_BRANCH') ? project.getProperty('BUILD_BRANCH') : ''
|
||||
EXEC_SUFFIX = Os.isFamily(Os.FAMILY_WINDOWS) ? '.exe' : ''
|
||||
QT5_DEPS = [
|
||||
'Qt5Concurrent',
|
||||
'Qt5Core',
|
||||
'Qt5Gui',
|
||||
'Qt5Multimedia',
|
||||
|
@ -47,8 +48,11 @@ ext {
|
|||
'Qt5OpenGL',
|
||||
'Qt5Qml',
|
||||
'Qt5Quick',
|
||||
'Qt5QuickControls2',
|
||||
'Qt5QuickTemplates2',
|
||||
'Qt5Script',
|
||||
'Qt5ScriptTools',
|
||||
'Qt5Svg',
|
||||
'Qt5WebChannel',
|
||||
'Qt5WebSockets',
|
||||
'Qt5Widgets',
|
||||
|
@ -93,6 +97,11 @@ def packages = [
|
|||
versionId: 'cA3tVJSmkvb1naA3l6D_Jv2Noh.4yc4m',
|
||||
checksum: '617a80d213a5ec69fbfa21a1f2f738cd',
|
||||
],
|
||||
glad: [
|
||||
file: 'glad_armv8-libcpp.zip',
|
||||
versionId: 'Q9szthzeye8fFyAA.cY26Lgn2B8kezEE',
|
||||
checksum: 'a8ee8584cf1ccd34766c7ddd9d5e5449',
|
||||
],
|
||||
glm: [
|
||||
file: 'glm-0.9.8.tgz',
|
||||
versionId: 'BlkJNwaYV2Gfy5XwMeU7K0uzPDRKFMt2',
|
||||
|
@ -145,16 +154,18 @@ def options = [
|
|||
|
||||
def qmlRoot = new File(HIFI_ANDROID_PRECOMPILED, 'qt')
|
||||
|
||||
def captureOutput = { String command ->
|
||||
def proc = command.execute()
|
||||
def sout = new StringBuilder(), serr = new StringBuilder()
|
||||
proc.consumeProcessOutput(sout, serr)
|
||||
proc.waitForOrKill(10000)
|
||||
def errorOutput = serr.toString()
|
||||
if (!errorOutput.isEmpty()) {
|
||||
throw new GradleException("Command '${command}' failed with error ${errorOutput}")
|
||||
def captureOutput = { String command, List<String> commandArgs ->
|
||||
def result
|
||||
new ByteArrayOutputStream().withStream { os ->
|
||||
def execResult = exec {
|
||||
executable = command
|
||||
args = commandArgs
|
||||
standardOutput = os
|
||||
errorOutput = new ByteArrayOutputStream()
|
||||
}
|
||||
result = os.toString()
|
||||
}
|
||||
return sout.toString()
|
||||
return result;
|
||||
}
|
||||
|
||||
def relativize = { File root, File absolute ->
|
||||
|
@ -168,11 +179,13 @@ def scanQmlImports = { File qmlRootPath ->
|
|||
throw new GradleException('Unable to find required qmlimportscanner executable at ' + qmlImportCommandFile.parent.toString())
|
||||
}
|
||||
|
||||
def command = qmlImportCommandFile.absolutePath +
|
||||
" -rootPath ${qmlRootPath.absolutePath}" +
|
||||
" -importPath ${qmlRoot.absolutePath}/qml"
|
||||
def command = qmlImportCommandFile.absolutePath
|
||||
def args = [
|
||||
'-rootPath', qmlRootPath.absolutePath,
|
||||
'-importPath', "${qmlRoot.absolutePath}/qml"
|
||||
]
|
||||
|
||||
def commandResult = captureOutput(command)
|
||||
def commandResult = captureOutput(command, args)
|
||||
new JsonSlurper().parseText(commandResult).each {
|
||||
if (!it.containsKey('path')) {
|
||||
println "Warning: QML import could not be resolved in any of the import paths: ${it.name}"
|
||||
|
@ -257,7 +270,7 @@ def parseQtDependencies = { List qtLibs ->
|
|||
def generateLibsXml = {
|
||||
def libDestinationDirectory = jniFolder
|
||||
def jarDestinationDirectory = new File(appDir, 'libs')
|
||||
def assetDestinationDirectory = new File(appDir, 'src/main/assets/bundled');
|
||||
def assetDestinationDirectory = new File(appDir, 'src/main/assets/--Added-by-androiddeployqt--');
|
||||
def libsXmlFile = new File(appDir, 'src/main/res/values/libs.xml')
|
||||
def libPrefix = 'lib' + File.separator
|
||||
def jarPrefix = 'jar' + File.separator
|
||||
|
@ -293,7 +306,7 @@ def generateLibsXml = {
|
|||
} else if (relativePath.startsWith('jar')) {
|
||||
destinationFile = new File(jarDestinationDirectory, relativePath.substring(jarPrefix.size()))
|
||||
} else {
|
||||
xmlParser.createNode(bundledAssetsNode, 'item', [:]).setValue("bundled/${relativePath}:${relativePath}".replace(File.separator, '/'))
|
||||
xmlParser.createNode(bundledAssetsNode, 'item', [:]).setValue("--Added-by-androiddeployqt--/${relativePath}:${relativePath}".replace(File.separator, '/'))
|
||||
destinationFile = new File(assetDestinationDirectory, relativePath)
|
||||
}
|
||||
|
||||
|
@ -427,9 +440,55 @@ task extractGvrBinaries(dependsOn: extractDependencies) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
def generateAssetsFileList = {
|
||||
def assetsPath = "${appDir}/src/main/assets/"
|
||||
def addedByAndroidDeployQtName = "--Added-by-androiddeployqt--/"
|
||||
|
||||
def addedByAndroidDeployQtPath = assetsPath + addedByAndroidDeployQtName
|
||||
|
||||
def addedByAndroidDeployQt = new File(addedByAndroidDeployQtPath)
|
||||
if (!addedByAndroidDeployQt.exists() && !addedByAndroidDeployQt.mkdirs()) {
|
||||
throw new GradleScriptException("Failed to create directory " + addedByAndroidDeployQtPath, null);
|
||||
}
|
||||
def outputFilename = "/qt_cache_pregenerated_file_list"
|
||||
def outputFile = new File(addedByAndroidDeployQtPath + outputFilename);
|
||||
Map<String, List<String>> directoryContents = new TreeMap<>();
|
||||
|
||||
def dir = new File(assetsPath)
|
||||
dir.eachFileRecurse (FileType.ANY) { file ->
|
||||
|
||||
def name = file.path.substring(assetsPath.length())
|
||||
int slashIndex = name.lastIndexOf('/')
|
||||
def pathName = slashIndex >= 0 ? name.substring(0, slashIndex) : "/"
|
||||
def fileName = slashIndex >= 0 ? name.substring(pathName.length() + 1) : name
|
||||
if (!fileName.isEmpty() && file.isDirectory() && !fileName.endsWith("/")) {
|
||||
fileName += "/"
|
||||
}
|
||||
|
||||
if (!directoryContents.containsKey(pathName)) {
|
||||
directoryContents[pathName] = new ArrayList<String>()
|
||||
}
|
||||
if (!fileName.isEmpty()) {
|
||||
directoryContents[pathName].add(fileName);
|
||||
}
|
||||
}
|
||||
DataOutputStream fos = new DataOutputStream(new FileOutputStream(outputFile));
|
||||
for (Map.Entry<String, List<String>> e: directoryContents.entrySet()) {
|
||||
def entryList = e.getValue()
|
||||
fos.writeInt(e.key.length()*2); // 2 bytes per char
|
||||
fos.writeChars(e.key);
|
||||
fos.writeInt(entryList.size());
|
||||
for (String entry: entryList) {
|
||||
fos.writeInt(entry.length()*2);
|
||||
fos.writeChars(entry);
|
||||
}
|
||||
}
|
||||
fos.close();
|
||||
}
|
||||
|
||||
|
||||
// Copy required Qt main libraries and required plugins based on the predefined list here
|
||||
// FIXME eventually we would like to use the readelf functionality to automatically detect dependencies
|
||||
// from our built applications and use that during the full build process. However doing so would mean
|
||||
|
@ -438,10 +497,11 @@ task extractGvrBinaries(dependsOn: extractDependencies) {
|
|||
task qtBundle {
|
||||
doLast {
|
||||
parseQtDependencies(QT5_DEPS)
|
||||
//def qmlImportFolder = new File("${appDir}/../../interface/resources/qml/")
|
||||
def qmlImportFolder = new File("${projectDir}/app/src/main/cpp")
|
||||
def qmlImportFolder = new File("${appDir}/../../interface/resources/qml/")
|
||||
//def qmlImportFolder = new File("${projectDir}/app/src/main/cpp")
|
||||
scanQmlImports(qmlImportFolder)
|
||||
generateLibsXml()
|
||||
generateAssetsFileList()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -450,10 +510,12 @@ task setupDependencies(dependsOn: [setupScribe, copyDependencies, extractGvrBina
|
|||
task cleanDependencies(type: Delete) {
|
||||
delete HIFI_ANDROID_PRECOMPILED
|
||||
delete 'app/src/main/jniLibs/arm64-v8a'
|
||||
delete 'app/src/main/assets/bundled'
|
||||
delete 'app/src/main/assets/--Added-by-androiddeployqt--'
|
||||
delete 'app/src/main/res/values/libs.xml'
|
||||
}
|
||||
|
||||
|
||||
|
||||
// FIXME this code is prototyping the desired functionality for doing build time binary dependency resolution.
|
||||
// See the comment on the qtBundle task above
|
||||
/*
|
||||
|
|
|
@ -43,15 +43,17 @@ export LDFLAGS="-pie"
|
|||
* Install Python 3.6 for Windows
|
||||
* Open a Git Bash command prompt
|
||||
* Ensure the following commands are visible in the path with `which <command>`
|
||||
* gcc
|
||||
* javac
|
||||
* python
|
||||
* gmake
|
||||
* gcc
|
||||
* javac
|
||||
* python
|
||||
* gmake
|
||||
* If any of them fail, fix your path and restart the bash prompt
|
||||
* Fetch the pre-built OpenSSL binaries for Android/iOS from here: https://github.com/leenjewel/openssl_for_ios_and_android/releases
|
||||
* Grab the latest release of the 1.0.2 series
|
||||
* Open the archive and extract the `/android/openssl-arm64-v8a` folder
|
||||
|
||||
### All platforms
|
||||
|
||||
* Download the Qt sources
|
||||
* `git clone git://code.qt.io/qt/qt5.git`
|
||||
* `cd qt5`
|
||||
|
@ -60,7 +62,11 @@ export LDFLAGS="-pie"
|
|||
* `git submodule update --recursive`
|
||||
* `cd ..`
|
||||
* Create a build directory with the command `mkdir qt5build`
|
||||
* Configure the Qt5 build with the command `../qt5/configure -xplatform android-clang -android-ndk-host windows-x86_64 -confirm-license -opensource --disable-rpath -nomake tests -nomake examples -skip qttranslations -skip qtserialport -skip qt3d -skip qtwebengine -skip qtlocation -skip qtwayland -skip qtsensors -skip qtgamepad -skip qtgamepad -skip qtspeech -skip qtcharts -skip qtx11extras -skip qtmacextras -skip qtvirtualkeyboard -skip qtpurchasing -skip qtdatavis3d -android-ndk C:/Android/NDK -android-toolchain-version 4.9 -android-arch arm64-v8a -no-warnings-are-errors -android-ndk-platform android-24 -v -platform win32-g++ -prefix C:/qt5build_debug -android-sdk C:/Android/SDK -c++std c++14 -openssl-linked -L<PATH_TO_SSL>/lib -I<PATH_TO_SSL>/include`
|
||||
* Configure the Qt5 build with the command `../qt5/configure -opensource -confirm-license -xplatform android-clang --disable-rpath -nomake tests -nomake examples -skip qttranslations -skip qtserialport -skip qt3d -skip qtwebengine -skip qtlocation -skip qtwayland -skip qtsensors -skip qtgamepad -skip qtgamepad -skip qtspeech -skip qtcharts -skip qtx11extras -skip qtmacextras -skip qtvirtualkeyboard -skip qtpurchasing -skip qtdatavis3d -android-toolchain-version 4.9 -android-ndk $HOME/Android/NDK -android-arch arm64-v8a -no-warnings-are-errors -android-ndk-platform android-24 -v -android-ndk-host windows-x86_64 -platform win32-g++ -prefix C:/qt5build_debug -android-sdk $HOME/Android/SDK -c++std c++14 -openssl-linked -L<PATH_TO_SSL>/lib -I<PATH_TO_SSL>/include`
|
||||
* Some of those entries must be customized depending on platform.
|
||||
* `-platform win32-g++`
|
||||
* `-android-ndk-host windows-x86_64`
|
||||
* `-prefix C:/qt5build_debug`
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -1,17 +0,0 @@
|
|||
# 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
|
|
@ -123,12 +123,12 @@ void ScriptableAvatar::update(float deltatime) {
|
|||
AnimPose& absPose = absPoses[i];
|
||||
if (data.rotation != absPose.rot()) {
|
||||
data.rotation = absPose.rot();
|
||||
data.rotationSet = true;
|
||||
data.rotationIsDefaultPose = false;
|
||||
}
|
||||
AnimPose& relPose = poses[i];
|
||||
if (data.translation != relPose.trans()) {
|
||||
data.translation = relPose.trans();
|
||||
data.translationSet = true;
|
||||
data.translationIsDefaultPose = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,27 +1,22 @@
|
|||
set(EXTERNAL_NAME glew)
|
||||
|
||||
if (ANDROID)
|
||||
set(ANDROID_CMAKE_ARGS "-DCMAKE_TOOLCHAIN_FILE=${CMAKE_TOOLCHAIN_FILE}" "-DANDROID_NATIVE_API_LEVEL=19")
|
||||
endif ()
|
||||
set(EXTERNAL_NAME glad32es)
|
||||
|
||||
include(ExternalProject)
|
||||
include(SelectLibraryConfigurations)
|
||||
|
||||
ExternalProject_Add(
|
||||
${EXTERNAL_NAME}
|
||||
URL http://hifi-public.s3.amazonaws.com/dependencies/glew_simple_1.13.0.zip
|
||||
URL_MD5 73f833649e904257b35bf4e84f8bdfb5
|
||||
CONFIGURE_COMMAND CMAKE_ARGS ${ANDROID_CMAKE_ARGS} -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} -DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR> -DCMAKE_POSITION_INDEPENDENT_CODE=ON
|
||||
URL https://hifi-public.s3.amazonaws.com/austin/glad/glad32es.zip
|
||||
URL_MD5 6a641d8c49dee4c895fa59315f5682a6
|
||||
CONFIGURE_COMMAND CMAKE_ARGS -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} -DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR> -DCMAKE_POSITION_INDEPENDENT_CODE=ON
|
||||
LOG_DOWNLOAD 1
|
||||
LOG_CONFIGURE 1
|
||||
LOG_BUILD 1
|
||||
)
|
||||
|
||||
# Hide this external target (for ide users)
|
||||
set_target_properties(${EXTERNAL_NAME} PROPERTIES FOLDER "hidden/externals")
|
||||
|
||||
ExternalProject_Get_Property(${EXTERNAL_NAME} INSTALL_DIR)
|
||||
|
||||
string(TOUPPER ${EXTERNAL_NAME} EXTERNAL_NAME_UPPER)
|
||||
set(${EXTERNAL_NAME_UPPER}_INCLUDE_DIRS ${INSTALL_DIR}/include CACHE PATH "List of glew include directories")
|
||||
set_target_properties(${EXTERNAL_NAME} PROPERTIES FOLDER "hidden/externals")
|
||||
ExternalProject_Get_Property(${EXTERNAL_NAME} INSTALL_DIR)
|
||||
|
||||
if (UNIX)
|
||||
set(LIB_PREFIX "lib")
|
||||
|
@ -30,5 +25,9 @@ elseif (WIN32)
|
|||
set(LIB_EXT "lib")
|
||||
endif ()
|
||||
|
||||
set(${EXTERNAL_NAME_UPPER}_LIBRARY_DEBUG ${INSTALL_DIR}/lib/${LIB_PREFIX}glew_d.${LIB_EXT} CACHE FILEPATH "Path to glew debug library")
|
||||
set(${EXTERNAL_NAME_UPPER}_LIBRARY_RELEASE ${INSTALL_DIR}/lib/${LIB_PREFIX}glew.${LIB_EXT} CACHE FILEPATH "Path to glew release library")
|
||||
set(${EXTERNAL_NAME_UPPER}_LIBRARY_DEBUG ${INSTALL_DIR}/lib/${LIB_PREFIX}glad_d.${LIB_EXT})
|
||||
set(${EXTERNAL_NAME_UPPER}_LIBRARY_RELEASE ${INSTALL_DIR}/lib/${LIB_PREFIX}glad.${LIB_EXT})
|
||||
select_library_configurations(${EXTERNAL_NAME_UPPER})
|
||||
|
||||
set(${EXTERNAL_NAME_UPPER}_INCLUDE_DIRS ${INSTALL_DIR}/include CACHE PATH "List of glad include directories")
|
||||
set(${EXTERNAL_NAME_UPPER}_LIBRARY ${${EXTERNAL_NAME_UPPER}_LIBRARY} CACHE INTERNAL "glad libraries")
|
33
cmake/externals/glad41/CMakeLists.txt
vendored
Normal file
|
@ -0,0 +1,33 @@
|
|||
set(EXTERNAL_NAME glad41)
|
||||
|
||||
include(ExternalProject)
|
||||
include(SelectLibraryConfigurations)
|
||||
|
||||
ExternalProject_Add(
|
||||
${EXTERNAL_NAME}
|
||||
URL https://hifi-public.s3.amazonaws.com/austin/glad/glad41.zip
|
||||
URL_MD5 1324eeec33abe91e67d19ae551ba624d
|
||||
CONFIGURE_COMMAND CMAKE_ARGS -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} -DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR> -DCMAKE_POSITION_INDEPENDENT_CODE=ON
|
||||
LOG_DOWNLOAD 1
|
||||
LOG_CONFIGURE 1
|
||||
LOG_BUILD 1
|
||||
)
|
||||
|
||||
# Hide this external target (for ide users)
|
||||
string(TOUPPER ${EXTERNAL_NAME} EXTERNAL_NAME_UPPER)
|
||||
set_target_properties(${EXTERNAL_NAME} PROPERTIES FOLDER "hidden/externals")
|
||||
ExternalProject_Get_Property(${EXTERNAL_NAME} INSTALL_DIR)
|
||||
|
||||
if (UNIX)
|
||||
set(LIB_PREFIX "lib")
|
||||
set(LIB_EXT "a")
|
||||
elseif (WIN32)
|
||||
set(LIB_EXT "lib")
|
||||
endif ()
|
||||
|
||||
set(${EXTERNAL_NAME_UPPER}_LIBRARY_DEBUG ${INSTALL_DIR}/lib/${LIB_PREFIX}glad_d.${LIB_EXT})
|
||||
set(${EXTERNAL_NAME_UPPER}_LIBRARY_RELEASE ${INSTALL_DIR}/lib/${LIB_PREFIX}glad.${LIB_EXT})
|
||||
select_library_configurations(${EXTERNAL_NAME_UPPER})
|
||||
|
||||
set(${EXTERNAL_NAME_UPPER}_INCLUDE_DIRS ${INSTALL_DIR}/include CACHE PATH "List of glad include directories")
|
||||
set(${EXTERNAL_NAME_UPPER}_LIBRARY ${${EXTERNAL_NAME_UPPER}_LIBRARY} CACHE INTERNAL "glad libraries")
|
33
cmake/externals/glad45/CMakeLists.txt
vendored
Normal file
|
@ -0,0 +1,33 @@
|
|||
set(EXTERNAL_NAME glad45)
|
||||
|
||||
include(ExternalProject)
|
||||
include(SelectLibraryConfigurations)
|
||||
|
||||
ExternalProject_Add(
|
||||
${EXTERNAL_NAME}
|
||||
URL https://hifi-public.s3.amazonaws.com/austin/glad/glad45.zip
|
||||
URL_MD5 cfb19b3cb5b2f8f1d1669fb3150e5f05
|
||||
CONFIGURE_COMMAND CMAKE_ARGS -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} -DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR> -DCMAKE_POSITION_INDEPENDENT_CODE=ON
|
||||
LOG_DOWNLOAD 1
|
||||
LOG_CONFIGURE 1
|
||||
LOG_BUILD 1
|
||||
)
|
||||
|
||||
# Hide this external target (for ide users)
|
||||
string(TOUPPER ${EXTERNAL_NAME} EXTERNAL_NAME_UPPER)
|
||||
set_target_properties(${EXTERNAL_NAME} PROPERTIES FOLDER "hidden/externals")
|
||||
ExternalProject_Get_Property(${EXTERNAL_NAME} INSTALL_DIR)
|
||||
|
||||
if (UNIX)
|
||||
set(LIB_PREFIX "lib")
|
||||
set(LIB_EXT "a")
|
||||
elseif (WIN32)
|
||||
set(LIB_EXT "lib")
|
||||
endif ()
|
||||
|
||||
set(${EXTERNAL_NAME_UPPER}_LIBRARY_DEBUG ${INSTALL_DIR}/lib/${LIB_PREFIX}glad_d.${LIB_EXT})
|
||||
set(${EXTERNAL_NAME_UPPER}_LIBRARY_RELEASE ${INSTALL_DIR}/lib/${LIB_PREFIX}glad.${LIB_EXT})
|
||||
select_library_configurations(${EXTERNAL_NAME_UPPER})
|
||||
|
||||
set(${EXTERNAL_NAME_UPPER}_INCLUDE_DIRS ${INSTALL_DIR}/include CACHE PATH "List of glad include directories")
|
||||
set(${EXTERNAL_NAME_UPPER}_LIBRARY ${${EXTERNAL_NAME_UPPER}_LIBRARY} CACHE INTERNAL "glad libraries")
|
|
@ -12,9 +12,14 @@ function(GENERATE_QRC)
|
|||
foreach(GLOB ${GENERATE_QRC_GLOBS})
|
||||
file(GLOB_RECURSE FOUND_FILES RELATIVE ${GENERATE_QRC_PATH} ${GLOB})
|
||||
foreach(FILENAME ${FOUND_FILES})
|
||||
if (${FILENAME} MATCHES "^\\.\\.")
|
||||
continue()
|
||||
endif()
|
||||
list(APPEND ALL_FILES "${GENERATE_QRC_PATH}/${FILENAME}")
|
||||
set(QRC_CONTENTS "${QRC_CONTENTS}<file alias=\"${FILENAME}\">${GENERATE_QRC_PATH}/${FILENAME}</file>\n")
|
||||
endforeach()
|
||||
endforeach()
|
||||
|
||||
|
||||
set(GENERATE_QRC_DEPENDS ${ALL_FILES} PARENT_SCOPE)
|
||||
configure_file("${HF_CMAKE_DIR}/templates/resources.qrc.in" ${GENERATE_QRC_OUTPUT})
|
||||
endfunction()
|
||||
|
|
38
cmake/macros/TargetGlad.cmake
Normal file
|
@ -0,0 +1,38 @@
|
|||
#
|
||||
# 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_GLAD)
|
||||
if (ANDROID)
|
||||
set(INSTALL_DIR ${HIFI_ANDROID_PRECOMPILED}/glad)
|
||||
set(GLAD_INCLUDE_DIRS "${INSTALL_DIR}/include")
|
||||
set(GLAD_LIBRARY_DEBUG ${INSTALL_DIR}/lib/libglad_d.a)
|
||||
set(GLAD_LIBRARY_RELEASE ${INSTALL_DIR}/lib/libglad.a)
|
||||
select_library_configurations(GLAD)
|
||||
find_library(EGL EGL)
|
||||
target_link_libraries(${TARGET_NAME} ${EGL})
|
||||
else()
|
||||
if (USE_GLES)
|
||||
set(GLAD_VER "32es")
|
||||
else()
|
||||
set(GLAD_VER "45")
|
||||
endif()
|
||||
find_package(OpenGL REQUIRED)
|
||||
list(APPEND GLAD_EXTRA_LIBRARIES ${OPENGL_LIBRARY})
|
||||
if (NOT WIN32)
|
||||
list(APPEND GLAD_EXTRA_LIBRARIES dl)
|
||||
endif()
|
||||
set(GLAD "glad${GLAD_VER}")
|
||||
string(TOUPPER ${GLAD} GLAD_UPPER)
|
||||
add_dependency_external_projects(${GLAD})
|
||||
set(GLAD_INCLUDE_DIRS ${${GLAD_UPPER}_INCLUDE_DIRS})
|
||||
set(GLAD_LIBRARY ${${GLAD_UPPER}_LIBRARY})
|
||||
endif()
|
||||
|
||||
target_include_directories(${TARGET_NAME} PUBLIC ${GLAD_INCLUDE_DIRS})
|
||||
target_link_libraries(${TARGET_NAME} ${GLAD_LIBRARY})
|
||||
target_link_libraries(${TARGET_NAME} ${GLAD_EXTRA_LIBRARIES})
|
||||
endmacro()
|
|
@ -1,16 +0,0 @@
|
|||
#
|
||||
# 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_GLEW)
|
||||
if (NOT ANDROID)
|
||||
add_definitions(-DGLEW_STATIC)
|
||||
add_dependency_external_projects(glew)
|
||||
find_package(GLEW REQUIRED)
|
||||
target_include_directories(${TARGET_NAME} PUBLIC ${GLEW_INCLUDE_DIRS})
|
||||
target_link_libraries(${TARGET_NAME} ${GLEW_LIBRARY})
|
||||
endif()
|
||||
endmacro()
|
|
@ -6,20 +6,6 @@
|
|||
# See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
#
|
||||
macro(TARGET_OPENGL)
|
||||
if (APPLE)
|
||||
# link in required OS X frameworks and include the right GL headers
|
||||
find_library(OpenGL OpenGL)
|
||||
target_link_libraries(${TARGET_NAME} ${OpenGL})
|
||||
elseif(ANDROID)
|
||||
target_link_libraries(${TARGET_NAME} GLESv3 EGL)
|
||||
else()
|
||||
find_package(OpenGL REQUIRED)
|
||||
if (${OPENGL_INCLUDE_DIR})
|
||||
include_directories(SYSTEM "${OPENGL_INCLUDE_DIR}")
|
||||
endif()
|
||||
target_link_libraries(${TARGET_NAME} "${OPENGL_LIBRARY}")
|
||||
target_include_directories(${TARGET_NAME} PUBLIC ${OPENGL_INCLUDE_DIR})
|
||||
endif()
|
||||
target_glad()
|
||||
target_nsight()
|
||||
target_glew()
|
||||
endmacro()
|
||||
|
|
|
@ -11,9 +11,20 @@ function(JOIN VALUES GLUE OUTPUT)
|
|||
set (${OUTPUT} "${_TMP_STR}" PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
set(RESOURCES_QRC ${CMAKE_CURRENT_BINARY_DIR}/resources.qrc)
|
||||
set(RESOURCES_RCC ${CMAKE_CURRENT_SOURCE_DIR}/compiledResources/resources.rcc)
|
||||
generate_qrc(OUTPUT ${RESOURCES_QRC} PATH ${CMAKE_CURRENT_SOURCE_DIR}/resources GLOBS *)
|
||||
|
||||
add_custom_command(
|
||||
OUTPUT ${RESOURCES_RCC}
|
||||
DEPENDS ${RESOURCES_QRC} ${GENERATE_QRC_DEPENDS}
|
||||
COMMAND "${QT_DIR}/bin/rcc"
|
||||
ARGS ${RESOURCES_QRC} -binary -o ${RESOURCES_RCC}
|
||||
)
|
||||
|
||||
list(APPEND GENERATE_QRC_DEPENDS ${RESOURCES_RCC})
|
||||
add_custom_target(resources ALL DEPENDS ${GENERATE_QRC_DEPENDS})
|
||||
|
||||
set(INTERFACE_QML_QRC ${CMAKE_CURRENT_BINARY_DIR}/qml.qrc)
|
||||
generate_qrc(OUTPUT ${INTERFACE_QML_QRC} PATH ${CMAKE_CURRENT_SOURCE_DIR}/resources GLOBS *.qml *.qss *.js *.html *.ttf *.gif *.svg *.png *.jpg)
|
||||
|
||||
# set a default root dir for each of our optional externals if it was not passed
|
||||
set(OPTIONAL_EXTERNALS "LeapMotion")
|
||||
|
@ -40,6 +51,7 @@ endif()
|
|||
# grab the implementation and header files from src dirs
|
||||
file(GLOB_RECURSE INTERFACE_SRCS "src/*.cpp" "src/*.h")
|
||||
GroupSources("src")
|
||||
list(APPEND INTERFACE_SRCS ${RESOURCES_RCC})
|
||||
|
||||
# Add SpeechRecognizer if on Windows or OS X, otherwise remove
|
||||
if (WIN32)
|
||||
|
@ -72,16 +84,6 @@ qt5_wrap_ui(QT_UI_HEADERS "${QT_UI_FILES}")
|
|||
# add them to the interface source files
|
||||
set(INTERFACE_SRCS ${INTERFACE_SRCS} "${QT_UI_HEADERS}" "${QT_RESOURCES}")
|
||||
|
||||
list(APPEND INTERFACE_SRCS ${INTERFACE_QML_QRC})
|
||||
|
||||
if (UNIX)
|
||||
install(
|
||||
DIRECTORY "${CMAKE_SOURCE_DIR}/interface/resources/qml"
|
||||
DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/resources
|
||||
COMPONENT ${CLIENT_COMPONENT}
|
||||
)
|
||||
endif()
|
||||
|
||||
# translation disabled until we strip out the line numbers
|
||||
# set(QM ${TARGET_NAME}_en.qm)
|
||||
# set(TS ${TARGET_NAME}_en.ts)
|
||||
|
@ -89,21 +91,7 @@ endif()
|
|||
|
||||
# setup the android parameters that will help us produce an APK
|
||||
if (ANDROID)
|
||||
set(ANDROID_APK_BUILD_DIR "${CMAKE_CURRENT_BINARY_DIR}/apk-build")
|
||||
set(ANDROID_APK_OUTPUT_DIR "${CMAKE_CURRENT_BINARY_DIR}/apk")
|
||||
|
||||
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${ANDROID_APK_OUTPUT_DIR}/libs/${ANDROID_ABI}")
|
||||
|
||||
set(ANDROID_SDK_ROOT $ENV{ANDROID_HOME})
|
||||
set(ANDROID_APP_DISPLAY_NAME Interface)
|
||||
set(ANDROID_API_LEVEL 19)
|
||||
set(ANDROID_APK_PACKAGE io.highfidelity.interface)
|
||||
set(ANDROID_ACTIVITY_NAME io.highfidelity.interface.InterfaceActivity)
|
||||
set(ANDROID_APK_VERSION_NAME "0.1")
|
||||
set(ANDROID_APK_VERSION_CODE 1)
|
||||
set(ANDROID_APK_FULLSCREEN TRUE)
|
||||
set(ANDROID_DEPLOY_QT_INSTALL "--install")
|
||||
|
||||
set(BUILD_SHARED_LIBS ON)
|
||||
endif ()
|
||||
|
||||
|
@ -175,6 +163,8 @@ else ()
|
|||
add_executable(${TARGET_NAME} ${INTERFACE_SRCS} ${QM})
|
||||
endif ()
|
||||
|
||||
add_dependencies(${TARGET_NAME} resources)
|
||||
|
||||
if (WIN32)
|
||||
# These are external plugins, but we need to do the 'add dependency' here so that their
|
||||
# binary directories get added to the fixup path
|
||||
|
@ -258,15 +248,20 @@ endforeach()
|
|||
# include headers for interface and InterfaceConfig.
|
||||
include_directories("${PROJECT_SOURCE_DIR}/src")
|
||||
|
||||
if (ANDROID)
|
||||
find_library(ANDROID_LOG_LIB log)
|
||||
target_link_libraries(${TARGET_NAME} ${ANDROID_LOG_LIB})
|
||||
endif ()
|
||||
|
||||
target_link_libraries(
|
||||
${TARGET_NAME}
|
||||
Qt5::Gui Qt5::Network Qt5::Multimedia Qt5::OpenGL
|
||||
Qt5::Qml Qt5::Quick Qt5::Script Qt5::Svg
|
||||
Qt5::WebChannel Qt5::WebEngine
|
||||
Qt5::WebChannel
|
||||
${PLATFORM_QT_LIBRARIES}
|
||||
)
|
||||
|
||||
if (UNIX)
|
||||
if (UNIX AND NOT ANDROID)
|
||||
if (CMAKE_SYSTEM_NAME MATCHES "Linux")
|
||||
# Linux
|
||||
target_link_libraries(${TARGET_NAME} pthread atomic)
|
||||
|
@ -274,7 +269,7 @@ if (UNIX)
|
|||
# OSX
|
||||
target_link_libraries(${TARGET_NAME} pthread)
|
||||
endif ()
|
||||
endif(UNIX)
|
||||
endif()
|
||||
|
||||
# assume we are using a Qt build without bearer management
|
||||
add_definitions(-DQT_NO_BEARERMANAGEMENT)
|
||||
|
@ -304,12 +299,20 @@ if (APPLE)
|
|||
# call the fixup_interface macro to add required bundling commands for installation
|
||||
fixup_interface()
|
||||
|
||||
else (APPLE)
|
||||
else()
|
||||
# copy the resources files beside the executable
|
||||
add_custom_command(TARGET ${TARGET_NAME} POST_BUILD
|
||||
COMMAND "${CMAKE_COMMAND}" -E copy_if_different
|
||||
"${RESOURCES_RCC}"
|
||||
"$<TARGET_FILE_DIR:interface>"
|
||||
# FIXME, the edit script code loads HTML from the scripts folder
|
||||
# which in turn relies on CSS that refers to the fonts. In theory
|
||||
# we should be able to modify the CSS to reference the QRC path to
|
||||
# the ttf files, but doing so generates a CORS policy violation,
|
||||
# so we have to retain a copy of the fonts outside of the resources binary
|
||||
COMMAND "${CMAKE_COMMAND}" -E copy_directory
|
||||
"${PROJECT_SOURCE_DIR}/resources"
|
||||
"$<TARGET_FILE_DIR:${TARGET_NAME}>/resources"
|
||||
"${PROJECT_SOURCE_DIR}/resources/fonts"
|
||||
"$<TARGET_FILE_DIR:${TARGET_NAME}>/resources/fonts"
|
||||
COMMAND "${CMAKE_COMMAND}" -E copy_directory
|
||||
"${CMAKE_SOURCE_DIR}/scripts"
|
||||
"$<TARGET_FILE_DIR:${TARGET_NAME}>/scripts"
|
||||
|
@ -335,7 +338,7 @@ else (APPLE)
|
|||
|
||||
optional_win_executable_signing()
|
||||
endif()
|
||||
endif (APPLE)
|
||||
endif()
|
||||
|
||||
if (SCRIPTS_INSTALL_DIR)
|
||||
|
||||
|
@ -359,20 +362,6 @@ if (WIN32)
|
|||
package_libraries_for_deployment()
|
||||
endif()
|
||||
|
||||
if (ANDROID)
|
||||
set(HIFI_URL_INTENT "<intent-filter>\
|
||||
\n <action android:name='android.intent.action.VIEW' />\
|
||||
\n <category android:name='android.intent.category.DEFAULT' />\
|
||||
\n <category android:name='android.intent.category.BROWSABLE' />\
|
||||
\n <data android:scheme='hifi' />\
|
||||
\n </intent-filter>"
|
||||
)
|
||||
|
||||
set(ANDROID_EXTRA_ACTIVITY_XML "${HIFI_URL_INTENT}")
|
||||
|
||||
qt_create_apk()
|
||||
endif ()
|
||||
|
||||
add_dependency_external_projects(GifCreator)
|
||||
find_package(GifCreator REQUIRED)
|
||||
target_include_directories(${TARGET_NAME} PUBLIC ${GIFCREATOR_INCLUDE_DIRS})
|
||||
|
|
0
interface/compiledResources/.placeholder
Normal file
21
interface/resources/icons/tablet-icons/EmoteAppIcon.svg
Normal file
|
@ -0,0 +1,21 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 22.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
viewBox="0 0 100 100.8" style="enable-background:new 0 0 100 100.8;" xml:space="preserve">
|
||||
<style type="text/css">
|
||||
.st0{fill:#FFFFFF;}
|
||||
</style>
|
||||
<path class="st0" d="M26.7,83.9c7.3,1.2,14.8,1.8,22.1,1.8c0.4,0,0.8,0,1.2,0c7.8-0.1,15.6-0.8,23.4-2.2l0,0
|
||||
c5.7-1.1,11.3-6.6,12.5-12.3C87.3,64.2,88,57,88,50s-0.7-14.2-2.1-21.2c-1.2-5.6-6.8-11.1-12.5-12.2c-7.7-1.4-15.6-2.2-23.4-2.2
|
||||
c-7.7-0.1-15.6,0.5-23.4,1.8c-5.7,1-11.4,6.5-12.6,12.3c-1.4,7.2-2.1,14.4-2.1,21.6s0.7,14.4,2.1,21.7
|
||||
C15.3,77.4,20.9,82.9,26.7,83.9z M20.9,29.8c0.6-2.9,4-6.3,6.9-6.8c7-1.1,14-1.7,21-1.7c0.4,0,0.8,0,1.2,0
|
||||
c7.4,0.1,14.8,0.8,22.1,2.1c2.9,0.6,6.4,3.9,6.9,6.7c1.3,6.6,1.9,13.3,1.9,19.9c0,6.6-0.6,13.3-1.9,19.8c-0.6,2.8-4,6.2-6.9,6.8
|
||||
c-7.3,1.3-14.8,2.1-22.1,2.1c-7.4,0.1-14.8-0.5-22.1-1.7c-2.9-0.5-6.3-3.9-6.9-6.7c-1.3-6.7-2-13.5-2-20.3
|
||||
C19,43.3,19.6,36.4,20.9,29.8z"/>
|
||||
<path class="st0" d="M32.3,61.4c-0.5,1.3-0.1,2.8,0.9,3.8c0.3,0.3,7.2,6.6,15.9,6.6c0.8,0,1.7-0.1,2.6-0.2
|
||||
c9.8-1.5,15.5-11.1,15.8-11.5c0.7-1.2,0.6-2.8-0.2-3.9c-0.9-1.1-2.3-1.6-3.7-1.3c-9.2,2.5-18.6,3.9-28.1,4.2
|
||||
C34,59.1,32.8,60,32.3,61.4z"/>
|
||||
<circle class="st0" cx="36.5" cy="42.8" r="9"/>
|
||||
<path class="st0" d="M61.4,44.1h6.1c1.9,0,3.3-1.5,3.3-3.3c0-1.9-1.5-3.3-3.3-3.3h-6.1c-1.9,0-3.3,1.5-3.3,3.3
|
||||
C58.1,42.7,59.6,44.1,61.4,44.1z"/>
|
||||
</svg>
|
After (image error) Size: 1.5 KiB |
BIN
interface/resources/images/+gles/Default-Sky-9-cubemap.ktx
Normal file
BIN
interface/resources/images/preview-privacy.png
Normal file
After ![]() (image error) Size: 52 KiB |
135
interface/resources/meshes/+gles/defaultAvatar_full.fst
Normal file
|
@ -0,0 +1,135 @@
|
|||
name = being_of_light
|
||||
type = body+head
|
||||
scale = 1
|
||||
filename = being_of_light/being_of_light.fbx
|
||||
texdir = being_of_light/textures
|
||||
joint = jointRoot = Hips
|
||||
joint = jointLeftHand = LeftHand
|
||||
joint = jointHead = HeadTop_End
|
||||
joint = jointLean = Spine
|
||||
joint = jointEyeLeft = LeftEye
|
||||
joint = jointRightHand = RightHand
|
||||
joint = jointNeck = Head
|
||||
joint = jointEyeRight = RightEye
|
||||
freeJoint = LeftArm
|
||||
freeJoint = LeftForeArm
|
||||
freeJoint = RightArm
|
||||
freeJoint = RightForeArm
|
||||
bs = MouthFrown_L = Frown_Left = 1
|
||||
bs = MouthLeft = Midmouth_Left = 1
|
||||
bs = BrowsU_R = BrowsUp_Right = 1
|
||||
bs = ChinUpperRaise = UpperLipUp_Right = 0.5
|
||||
bs = ChinUpperRaise = UpperLipUp_Left = 0.5
|
||||
bs = MouthSmile_R = Smile_Right = 1
|
||||
bs = MouthDimple_L = Smile_Left = 0.25
|
||||
bs = EyeBlink_L = Blink_Left = 1
|
||||
bs = BrowsD_L = BrowsDown_Left = 1
|
||||
bs = MouthFrown_R = Frown_Right = 1
|
||||
bs = MouthDimple_R = Smile_Right = 0.25
|
||||
bs = Sneer = Squint_Right = 0.5
|
||||
bs = Sneer = Squint_Left = 0.5
|
||||
bs = Sneer = NoseScrunch_Right = 0.75
|
||||
bs = Sneer = NoseScrunch_Left = 0.75
|
||||
bs = EyeSquint_L = Squint_Left = 1
|
||||
bs = EyeBlink_R = Blink_Right = 1
|
||||
bs = JawLeft = JawRotateY_Left = 0.5
|
||||
bs = BrowsD_R = BrowsDown_Right = 1
|
||||
bs = EyeSquint_R = Squint_Right = 1
|
||||
bs = Puff = CheekPuff_Right = 1
|
||||
bs = Puff = CheekPuff_Left = 1
|
||||
bs = LipsUpperClose = UpperLipIn = 1
|
||||
bs = JawOpen = MouthOpen = 0.69999999999999996
|
||||
bs = LipsUpperUp = UpperLipUp_Right = 0.69999999999999996
|
||||
bs = LipsUpperUp = UpperLipUp_Left = 0.69999999999999996
|
||||
bs = LipsLowerDown = LowerLipDown_Right = 0.69999999999999996
|
||||
bs = LipsLowerDown = LowerLipDown_Left = 0.69999999999999996
|
||||
bs = LipsLowerOpen = LowerLipOut = 1
|
||||
bs = EyeOpen_L = EyesWide_Left = 1
|
||||
bs = LipsPucker = MouthNarrow_Right = 1
|
||||
bs = LipsPucker = MouthNarrow_Left = 1
|
||||
bs = EyeOpen_R = EyesWide_Right = 1
|
||||
bs = JawRight = Jaw_Right = 1
|
||||
bs = MouthRight = Midmouth_Right = 1
|
||||
bs = ChinLowerRaise = Jaw_Up = 1
|
||||
bs = LipsUpperOpen = UpperLipOut = 1
|
||||
bs = BrowsU_C = BrowsUp_Right = 1
|
||||
bs = BrowsU_C = BrowsUp_Left = 1
|
||||
bs = JawFwd = JawForeward = 1
|
||||
bs = BrowsU_L = BrowsUp_Left = 1
|
||||
bs = MouthSmile_L = Smile_Left = 1
|
||||
bs = LipsLowerClose = LowerLipIn = 1
|
||||
bs = LipsFunnel = TongueUp = 1
|
||||
bs = LipsFunnel = MouthWhistle_NarrowAdjust_Right = 0.5
|
||||
bs = LipsFunnel = MouthWhistle_NarrowAdjust_Left = 0.5
|
||||
bs = LipsFunnel = MouthNarrow_Right = 1
|
||||
bs = LipsFunnel = MouthNarrow_Left = 1
|
||||
bs = LipsFunnel = Jaw_Down = 0.35999999999999999
|
||||
bs = LipsFunnel = JawForeward = 0.39000000000000001
|
||||
jointIndex = LeftHandIndex1 = 50
|
||||
jointIndex = LeftHandIndex2 = 51
|
||||
jointIndex = LeftHandIndex3 = 52
|
||||
jointIndex = LeftHandIndex4 = 53
|
||||
jointIndex = Spine1 = 12
|
||||
jointIndex = Spine2 = 13
|
||||
jointIndex = RightHandThumb1 = 18
|
||||
jointIndex = RightHandThumb2 = 19
|
||||
jointIndex = RightHandThumb3 = 20
|
||||
jointIndex = RightHandThumb4 = 21
|
||||
jointIndex = LeftFoot = 8
|
||||
jointIndex = LeftForeArm = 40
|
||||
jointIndex = Neck = 62
|
||||
jointIndex = Head = 63
|
||||
jointIndex = Hips = 0
|
||||
jointIndex = RightHandPinky1 = 30
|
||||
jointIndex = RightHandPinky2 = 31
|
||||
jointIndex = RightHandPinky3 = 32
|
||||
jointIndex = RightHandPinky4 = 33
|
||||
jointIndex = RightLeg = 2
|
||||
jointIndex = RightForeArm = 16
|
||||
jointIndex = LeftHandRing1 = 46
|
||||
jointIndex = LeftHandRing2 = 47
|
||||
jointIndex = LeftHandRing3 = 48
|
||||
jointIndex = LeftHandRing4 = 49
|
||||
jointIndex = LeftHandThumb1 = 54
|
||||
jointIndex = LeftHandThumb2 = 55
|
||||
jointIndex = LeftHandThumb3 = 56
|
||||
jointIndex = LeftHandThumb4 = 57
|
||||
jointIndex = HeadTop_End = 66
|
||||
jointIndex = LeftUpLeg = 6
|
||||
jointIndex = LeftToeBase = 9
|
||||
jointIndex = LeftHandPinky1 = 42
|
||||
jointIndex = LeftHandPinky2 = 43
|
||||
jointIndex = LeftHandPinky3 = 44
|
||||
jointIndex = LeftHandPinky4 = 45
|
||||
jointIndex = LeftLeg = 7
|
||||
jointIndex = RightEye = 65
|
||||
jointIndex = RightHand = 17
|
||||
jointIndex = RightToeBase = 4
|
||||
jointIndex = RightUpLeg = 1
|
||||
jointIndex = RightArm = 15
|
||||
jointIndex = RightHandRing1 = 26
|
||||
jointIndex = RightHandRing2 = 27
|
||||
jointIndex = RightHandRing3 = 28
|
||||
jointIndex = RightHandRing4 = 29
|
||||
jointIndex = RightHandIndex1 = 22
|
||||
jointIndex = RightHandIndex2 = 23
|
||||
jointIndex = RightHandIndex3 = 24
|
||||
jointIndex = RightHandIndex4 = 25
|
||||
jointIndex = LeftToe_End = 10
|
||||
jointIndex = LeftHandMiddle1 = 58
|
||||
jointIndex = LeftHandMiddle2 = 59
|
||||
jointIndex = LeftHandMiddle3 = 60
|
||||
jointIndex = LeftShoulder = 38
|
||||
jointIndex = LeftHandMiddle4 = 61
|
||||
jointIndex = RightFoot = 3
|
||||
jointIndex = LeftHand = 41
|
||||
jointIndex = RightHandMiddle1 = 34
|
||||
jointIndex = RightHandMiddle2 = 35
|
||||
jointIndex = RightHandMiddle3 = 36
|
||||
jointIndex = RightShoulder = 14
|
||||
jointIndex = LeftEye = 64
|
||||
jointIndex = RightHandMiddle4 = 37
|
||||
jointIndex = Body = 67
|
||||
jointIndex = LeftArm = 39
|
||||
jointIndex = RightToe_End = 5
|
||||
jointIndex = Spine = 11
|
BIN
interface/resources/meshes/being_of_light/being_of_light.fbx
Normal file
After ![]() (image error) Size: 2.6 MiB |
After ![]() (image error) Size: 2.9 MiB |
After ![]() (image error) Size: 645 KiB |
394
interface/resources/qml/+android/Stats.qml
Normal file
|
@ -0,0 +1,394 @@
|
|||
import Hifi 1.0 as Hifi
|
||||
import QtQuick 2.3
|
||||
import '.'
|
||||
|
||||
Item {
|
||||
id: stats
|
||||
|
||||
anchors.leftMargin: 300
|
||||
objectName: "StatsItem"
|
||||
property int modality: Qt.NonModal
|
||||
implicitHeight: row.height
|
||||
implicitWidth: row.width
|
||||
|
||||
Component.onCompleted: {
|
||||
stats.parentChanged.connect(fill);
|
||||
fill();
|
||||
}
|
||||
Component.onDestruction: {
|
||||
stats.parentChanged.disconnect(fill);
|
||||
}
|
||||
|
||||
function fill() {
|
||||
// This will cause a warning at shutdown, need to find another way to remove
|
||||
// the warning other than filling the anchors to the parent
|
||||
anchors.horizontalCenter = parent.horizontalCenter
|
||||
}
|
||||
|
||||
Hifi.Stats {
|
||||
id: root
|
||||
objectName: "Stats"
|
||||
implicitHeight: row.height
|
||||
implicitWidth: row.width
|
||||
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
readonly property string bgColor: "#AA111111"
|
||||
|
||||
Row {
|
||||
id: row
|
||||
spacing: 8
|
||||
Rectangle {
|
||||
width: generalCol.width + 8;
|
||||
height: generalCol.height + 8;
|
||||
color: root.bgColor;
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
onClicked: { root.expanded = !root.expanded; }
|
||||
hoverEnabled: true
|
||||
}
|
||||
|
||||
Column {
|
||||
id: generalCol
|
||||
spacing: 4; x: 4; y: 4;
|
||||
StatText {
|
||||
text: "Servers: " + root.serverCount
|
||||
}
|
||||
StatText {
|
||||
text: "Avatars: " + root.avatarCount
|
||||
}
|
||||
StatText {
|
||||
text: "Game Rate: " + root.gameLoopRate
|
||||
}
|
||||
StatText {
|
||||
visible: root.expanded
|
||||
text: root.gameUpdateStats
|
||||
}
|
||||
StatText {
|
||||
text: "Render Rate: " + root.renderrate.toFixed(2);
|
||||
}
|
||||
StatText {
|
||||
text: "Present Rate: " + root.presentrate.toFixed(2);
|
||||
}
|
||||
StatText {
|
||||
visible: root.expanded
|
||||
text: " Present New Rate: " + root.presentnewrate.toFixed(2);
|
||||
}
|
||||
StatText {
|
||||
visible: root.expanded
|
||||
text: " Present Drop Rate: " + root.presentdroprate.toFixed(2);
|
||||
}
|
||||
StatText {
|
||||
text: "Stutter Rate: " + root.stutterrate.toFixed(3);
|
||||
visible: root.stutterrate != -1;
|
||||
}
|
||||
StatText {
|
||||
text: "Missed Frame Count: " + root.appdropped;
|
||||
visible: root.appdropped > 0;
|
||||
}
|
||||
StatText {
|
||||
text: "Long Render Count: " + root.longrenders;
|
||||
visible: root.longrenders > 0;
|
||||
}
|
||||
StatText {
|
||||
text: "Long Submit Count: " + root.longsubmits;
|
||||
visible: root.longsubmits > 0;
|
||||
}
|
||||
StatText {
|
||||
text: "Long Frame Count: " + root.longframes;
|
||||
visible: root.longframes > 0;
|
||||
}
|
||||
StatText {
|
||||
text: "Packets In/Out: " + root.packetInCount + "/" + root.packetOutCount
|
||||
}
|
||||
StatText {
|
||||
text: "Mbps In/Out: " + root.mbpsIn.toFixed(2) + "/" + root.mbpsOut.toFixed(2)
|
||||
}
|
||||
StatText {
|
||||
visible: root.expanded
|
||||
text: "Asset Mbps In/Out: " + root.assetMbpsIn.toFixed(2) + "/" + root.assetMbpsOut.toFixed(2)
|
||||
}
|
||||
StatText {
|
||||
visible: root.expanded
|
||||
text: "Avatars Updated: " + root.updatedAvatarCount
|
||||
}
|
||||
StatText {
|
||||
visible: root.expanded
|
||||
text: "Avatars NOT Updated: " + root.notUpdatedAvatarCount
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
width: pingCol.width + 8
|
||||
height: pingCol.height + 8
|
||||
color: root.bgColor;
|
||||
visible: root.audioPing != -2
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
onClicked: { root.expanded = !root.expanded; }
|
||||
hoverEnabled: true
|
||||
}
|
||||
Column {
|
||||
id: pingCol
|
||||
spacing: 4; x: 4; y: 4;
|
||||
StatText {
|
||||
text: "Audio ping/loss: " + root.audioPing + "/" + root.audioPacketLoss + "%"
|
||||
}
|
||||
StatText {
|
||||
text: "Avatar ping: " + root.avatarPing
|
||||
}
|
||||
StatText {
|
||||
text: "Entities avg ping: " + root.entitiesPing
|
||||
}
|
||||
StatText {
|
||||
text: "Asset ping: " + root.assetPing
|
||||
}
|
||||
StatText {
|
||||
visible: root.expanded;
|
||||
text: "Messages max ping: " + root.messagePing
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
width: geoCol.width + 8
|
||||
height: geoCol.height + 8
|
||||
color: root.bgColor;
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
onClicked: { root.expanded = !root.expanded; }
|
||||
hoverEnabled: true
|
||||
}
|
||||
Column {
|
||||
id: geoCol
|
||||
spacing: 4; x: 4; y: 4;
|
||||
StatText {
|
||||
text: "Position: " + root.position.x.toFixed(1) + ", " +
|
||||
root.position.y.toFixed(1) + ", " + root.position.z.toFixed(1)
|
||||
}
|
||||
StatText {
|
||||
text: "Speed: " + root.speed.toFixed(1)
|
||||
}
|
||||
StatText {
|
||||
text: "Yaw: " + root.yaw.toFixed(1)
|
||||
}
|
||||
StatText {
|
||||
visible: root.expanded;
|
||||
text: "Avatar Mixer In: " + root.avatarMixerInKbps + " kbps, " +
|
||||
root.avatarMixerInPps + "pps";
|
||||
}
|
||||
StatText {
|
||||
visible: root.expanded;
|
||||
text: "Avatar Mixer Out: " + root.avatarMixerOutKbps + " kbps, " +
|
||||
root.avatarMixerOutPps + "pps, " +
|
||||
root.myAvatarSendRate.toFixed(2) + "hz";
|
||||
}
|
||||
StatText {
|
||||
visible: root.expanded;
|
||||
text: "Audio Mixer In: " + root.audioMixerInKbps + " kbps, " +
|
||||
root.audioMixerInPps + "pps";
|
||||
}
|
||||
StatText {
|
||||
visible: root.expanded;
|
||||
text: "Audio In Audio: " + root.audioAudioInboundPPS + " pps, " +
|
||||
"Silent: " + root.audioSilentInboundPPS + " pps";
|
||||
}
|
||||
StatText {
|
||||
visible: root.expanded;
|
||||
text: "Audio Mixer Out: " + root.audioMixerOutKbps + " kbps, " +
|
||||
root.audioMixerOutPps + "pps";
|
||||
}
|
||||
StatText {
|
||||
visible: root.expanded;
|
||||
text: "Audio Out Mic: " + root.audioOutboundPPS + " pps, " +
|
||||
"Silent: " + root.audioSilentOutboundPPS + " pps";
|
||||
}
|
||||
StatText {
|
||||
visible: root.expanded;
|
||||
text: "Audio Codec: " + root.audioCodec + " Noise Gate: " +
|
||||
root.audioNoiseGate;
|
||||
}
|
||||
StatText {
|
||||
visible: root.expanded;
|
||||
text: "Entity Servers In: " + root.entityPacketsInKbps + " kbps";
|
||||
}
|
||||
StatText {
|
||||
visible: root.expanded;
|
||||
text: "Downloads: " + root.downloads + "/" + root.downloadLimit +
|
||||
", Pending: " + root.downloadsPending;
|
||||
}
|
||||
StatText {
|
||||
visible: root.expanded;
|
||||
text: "Processing: " + root.processing +
|
||||
", Pending: " + root.processingPending;
|
||||
}
|
||||
StatText {
|
||||
visible: root.expanded && root.downloadUrls.length > 0;
|
||||
text: "Download URLs:"
|
||||
}
|
||||
ListView {
|
||||
width: geoCol.width
|
||||
height: root.downloadUrls.length * 15
|
||||
|
||||
visible: root.expanded && root.downloadUrls.length > 0;
|
||||
|
||||
model: root.downloadUrls
|
||||
delegate: StatText {
|
||||
visible: root.expanded;
|
||||
text: modelData.length > 30
|
||||
? modelData.substring(0, 5) + "..." + modelData.substring(modelData.length - 22)
|
||||
: modelData
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Rectangle {
|
||||
width: octreeCol.width + 8
|
||||
height: octreeCol.height + 8
|
||||
color: root.bgColor;
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
onClicked: { root.expanded = !root.expanded; }
|
||||
hoverEnabled: true
|
||||
}
|
||||
Column {
|
||||
id: octreeCol
|
||||
spacing: 4; x: 4; y: 4;
|
||||
StatText {
|
||||
text: "Engine: " + root.engineFrameTime.toFixed(1) + " ms"
|
||||
}
|
||||
StatText {
|
||||
text: "Batch: " + root.batchFrameTime.toFixed(1) + " ms"
|
||||
}
|
||||
StatText {
|
||||
text: "GPU: " + root.gpuFrameTime.toFixed(1) + " ms"
|
||||
}
|
||||
StatText {
|
||||
text: "Triangles: " + root.triangles +
|
||||
" / Material Switches: " + root.materialSwitches
|
||||
}
|
||||
StatText {
|
||||
text: "GPU Free Memory: " + root.gpuFreeMemory + " MB";
|
||||
}
|
||||
StatText {
|
||||
text: "GPU Textures: ";
|
||||
}
|
||||
StatText {
|
||||
text: " Count: " + root.gpuTextures;
|
||||
}
|
||||
StatText {
|
||||
text: " Pressure State: " + root.gpuTextureMemoryPressureState;
|
||||
}
|
||||
StatText {
|
||||
text: " Resource Allocated / Populated / Pending: ";
|
||||
}
|
||||
StatText {
|
||||
text: " " + root.gpuTextureResourceMemory + " / " + root.gpuTextureResourcePopulatedMemory + " / " + root.texturePendingTransfers + " MB";
|
||||
}
|
||||
StatText {
|
||||
text: " Resident Memory: " + root.gpuTextureResidentMemory + " MB";
|
||||
}
|
||||
StatText {
|
||||
text: " Framebuffer Memory: " + root.gpuTextureFramebufferMemory + " MB";
|
||||
}
|
||||
StatText {
|
||||
text: " External Memory: " + root.gpuTextureExternalMemory + " MB";
|
||||
}
|
||||
StatText {
|
||||
text: "GPU Buffers: "
|
||||
}
|
||||
StatText {
|
||||
text: " Count: " + root.gpuBuffers;
|
||||
}
|
||||
StatText {
|
||||
text: " Memory: " + root.gpuBufferMemory + " MB";
|
||||
}
|
||||
StatText {
|
||||
text: "GL Swapchain Memory: " + root.glContextSwapchainMemory + " MB";
|
||||
}
|
||||
StatText {
|
||||
text: "QML Texture Memory: " + root.qmlTextureMemory + " MB";
|
||||
}
|
||||
StatText {
|
||||
visible: root.expanded;
|
||||
text: "Items rendered / considered: " +
|
||||
root.itemRendered + " / " + root.itemConsidered;
|
||||
}
|
||||
StatText {
|
||||
visible: root.expanded;
|
||||
text: " out of view: " + root.itemOutOfView +
|
||||
" too small: " + root.itemTooSmall;
|
||||
}
|
||||
StatText {
|
||||
visible: root.expanded;
|
||||
text: "Shadows rendered / considered: " +
|
||||
root.shadowRendered + " / " + root.shadowConsidered;
|
||||
}
|
||||
StatText {
|
||||
visible: root.expanded;
|
||||
text: " out of view: " + root.shadowOutOfView +
|
||||
" too small: " + root.shadowTooSmall;
|
||||
}
|
||||
StatText {
|
||||
visible: !root.expanded
|
||||
text: "Octree Elements Server: " + root.serverElements +
|
||||
" Local: " + root.localElements;
|
||||
}
|
||||
StatText {
|
||||
visible: root.expanded
|
||||
text: "Octree Sending Mode: " + root.sendingMode;
|
||||
}
|
||||
StatText {
|
||||
visible: root.expanded
|
||||
text: "Octree Packets to Process: " + root.packetStats;
|
||||
}
|
||||
StatText {
|
||||
visible: root.expanded
|
||||
text: "Octree Elements - ";
|
||||
}
|
||||
StatText {
|
||||
visible: root.expanded
|
||||
text: "\tServer: " + root.serverElements +
|
||||
" Internal: " + root.serverInternal +
|
||||
" Leaves: " + root.serverLeaves;
|
||||
}
|
||||
StatText {
|
||||
visible: root.expanded
|
||||
text: "\tLocal: " + root.localElements +
|
||||
" Internal: " + root.localInternal +
|
||||
" Leaves: " + root.localLeaves;
|
||||
}
|
||||
StatText {
|
||||
visible: root.expanded
|
||||
text: "LOD: " + root.lodStatus;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
y: 250
|
||||
visible: root.timingExpanded
|
||||
width: perfText.width + 8
|
||||
height: perfText.height + 8
|
||||
color: root.bgColor;
|
||||
StatText {
|
||||
x: 4; y: 4
|
||||
id: perfText
|
||||
font.family: root.monospaceFont
|
||||
text: "------------------------------------------ Function " +
|
||||
"--------------------------------------- --msecs- -calls--\n" +
|
||||
root.timingStats;
|
||||
}
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: root.parent
|
||||
onWidthChanged: {
|
||||
root.x = root.parent.width - root.width;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -16,10 +16,9 @@ import "controls-uit" as HifiControls
|
|||
Item {
|
||||
id: root
|
||||
width: parent.width
|
||||
height: parent.height
|
||||
height: parent.height
|
||||
|
||||
property var hideQtMethods: true
|
||||
|
||||
property var maxUpdateValues: 20
|
||||
property var maxReloadValues: 200
|
||||
property var apiMembers: []
|
||||
|
@ -30,7 +29,7 @@ Item {
|
|||
property Component keyboard
|
||||
|
||||
Rectangle {
|
||||
color: "white"
|
||||
color: hifi.colors.baseGray
|
||||
width: parent.width
|
||||
height: parent.height
|
||||
}
|
||||
|
@ -51,32 +50,22 @@ Item {
|
|||
Row {
|
||||
id: topBar
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: 8
|
||||
anchors.leftMargin: 30
|
||||
anchors.top: parent.top
|
||||
anchors.topMargin: 30
|
||||
width: parent.width
|
||||
height: 50
|
||||
HifiControls.GlyphButton {
|
||||
id: search
|
||||
enabled: true
|
||||
glyph: hifi.glyphs.search
|
||||
color: hifi.colors.text
|
||||
size: 48
|
||||
width: 50
|
||||
height: 50
|
||||
onClicked: {
|
||||
addListElements(searchBar.text);
|
||||
focus = true;
|
||||
}
|
||||
}
|
||||
height: 40
|
||||
|
||||
HifiControls.GlyphButton {
|
||||
id: back;
|
||||
enabled: true;
|
||||
color: hifi.buttons.black
|
||||
glyph: hifi.glyphs.backward
|
||||
color: hifi.colors.text
|
||||
size: 48
|
||||
width: 30
|
||||
height: 50
|
||||
anchors.margins: 2
|
||||
size: 40
|
||||
width: 40
|
||||
height: 40
|
||||
anchors.left: search.right
|
||||
anchors.leftMargin: 12
|
||||
onClicked: {
|
||||
var text = searchBar.text;
|
||||
var chain = text.split(".");
|
||||
|
@ -99,17 +88,20 @@ Item {
|
|||
}
|
||||
}
|
||||
|
||||
TextField {
|
||||
id: searchBar
|
||||
HifiControls.TextField {
|
||||
id: searchBar
|
||||
focus: true
|
||||
font.pixelSize: 16
|
||||
width: 2*(parent.width-back.width-search.width-reload.width-update.width-evaluate.width-addMember.width-16)/3
|
||||
height: parent.height
|
||||
font.family: ralewayRegular.name
|
||||
isSearchField: true
|
||||
width: parent.width - 112
|
||||
height: 40
|
||||
colorScheme: hifi.colorSchemes.dark
|
||||
anchors.left: back.right
|
||||
anchors.leftMargin: 10
|
||||
font.family: firaSansSemiBold.name
|
||||
placeholderText: "Search"
|
||||
onAccepted: {
|
||||
console.log("Enter Pressed");
|
||||
search.clicked();
|
||||
addListElements(searchBar.text);
|
||||
}
|
||||
onActiveFocusChanged: {
|
||||
if (activeFocus && HMD.mounted) {
|
||||
|
@ -119,15 +111,27 @@ Item {
|
|||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
HifiControls.Button {
|
||||
Row {
|
||||
id: topBar2
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: 30
|
||||
anchors.top: topBar.bottom
|
||||
anchors.topMargin: 30
|
||||
width: parent.width -60
|
||||
height: 40
|
||||
|
||||
HifiControls.GlyphButton {
|
||||
id: addMember;
|
||||
enabled: true;
|
||||
text: "+"
|
||||
width: 50
|
||||
height: 50
|
||||
anchors.margins: 2
|
||||
color: hifi.buttons.black
|
||||
glyph: hifi.glyphs.maximize
|
||||
width: 40
|
||||
height: 40
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
onClicked: {
|
||||
addNewMember();
|
||||
updateList.start();
|
||||
|
@ -138,36 +142,48 @@ Item {
|
|||
HifiControls.Button {
|
||||
id: evaluate;
|
||||
enabled: true;
|
||||
color: hifi.buttons.black
|
||||
text: "Eval"
|
||||
width: 50
|
||||
height: 50
|
||||
anchors.margins: 2
|
||||
width: 40
|
||||
height: 40
|
||||
anchors.left: addMember.right
|
||||
anchors.leftMargin: 12
|
||||
onClicked: {
|
||||
evaluateMember();
|
||||
focus = true;
|
||||
}
|
||||
}
|
||||
TextField {
|
||||
id: valueBar
|
||||
focus: true
|
||||
|
||||
HifiControls.TextField {
|
||||
id: valueBar
|
||||
isSearchField: false
|
||||
font.pixelSize: 16
|
||||
width: (parent.width-back.width-search.width-reload.width-update.width-evaluate.width-addMember.width-16)/3
|
||||
height: parent.height
|
||||
font.family: ralewayRegular.name
|
||||
width: parent.width - 208
|
||||
height: 40
|
||||
colorScheme: hifi.colorSchemes.dark
|
||||
font.family: firaSansSemiBold.name
|
||||
placeholderText: "Value"
|
||||
textColor: "#4466DD"
|
||||
anchors.margins: 2
|
||||
anchors.left: evaluate.right
|
||||
anchors.leftMargin: 12
|
||||
onActiveFocusChanged: {
|
||||
if (activeFocus && HMD.mounted) {
|
||||
keyboard.raised = true;
|
||||
} else {
|
||||
keyboard.raised = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
HifiControls.GlyphButton {
|
||||
id: reload;
|
||||
enabled: false;
|
||||
color: hifi.buttons.black
|
||||
glyph: hifi.glyphs.reload
|
||||
color: hifi.colors.text
|
||||
size: 48
|
||||
width: 50
|
||||
height: 50
|
||||
anchors.margins: 2
|
||||
size: 40
|
||||
width: 40
|
||||
height: 40
|
||||
anchors.right: update.left
|
||||
anchors.rightMargin: 12
|
||||
onClicked: {
|
||||
reloadListValues();
|
||||
focus = true;
|
||||
|
@ -177,11 +193,12 @@ Item {
|
|||
HifiControls.GlyphButton {
|
||||
id: update;
|
||||
enabled: false;
|
||||
color: hifi.buttons.black
|
||||
glyph: hifi.glyphs.playback_play
|
||||
size: 48
|
||||
width: 50
|
||||
height: 50
|
||||
anchors.margins: 2
|
||||
size: 40
|
||||
width: 40
|
||||
height: 40
|
||||
anchors.right: parent.right
|
||||
onClicked: {
|
||||
if (isReloading) {
|
||||
update.glyph = hifi.glyphs.playback_play
|
||||
|
@ -196,71 +213,104 @@ Item {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
ListModel {
|
||||
id: memberModel
|
||||
}
|
||||
|
||||
Component {
|
||||
id: memberDelegate
|
||||
|
||||
Row {
|
||||
id: memberRow
|
||||
property var isMainKey: apiType === "class";
|
||||
spacing: 10
|
||||
Rectangle {
|
||||
width: isMainKey ? 20 : 40;
|
||||
height: parent.height
|
||||
}
|
||||
|
||||
RalewayRegular {
|
||||
text: apiMember
|
||||
size: !isMainKey ? 16 : 22
|
||||
MouseArea {
|
||||
width: list.width
|
||||
height: parent.height
|
||||
onClicked: {
|
||||
searchBar.text = apiType=="function()" ? apiMember + "()" : apiMember;
|
||||
valueBar.text = !apiValue ? "" : apiValue;
|
||||
list.currentIndex = index;
|
||||
evaluatingIdx = index;
|
||||
}
|
||||
onDoubleClicked: {
|
||||
if (apiType === "class") {
|
||||
addListElements(apiMember+".");
|
||||
} else {
|
||||
isolateElement(evaluatingIdx);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
RalewayRegular {
|
||||
text: apiType
|
||||
size: 14
|
||||
color: hifi.colors.baseGrayHighlight
|
||||
}
|
||||
|
||||
RalewayRegular {
|
||||
text: !apiValue ? "" : apiValue;
|
||||
size: 16
|
||||
color: "#4466DD"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Rectangle {
|
||||
id: membersBackground
|
||||
anchors {
|
||||
left: parent.left; right: parent.right; top: topBar.bottom; bottom: parent.bottom;
|
||||
margins: hifi.dimensions.contentMargin.x
|
||||
bottomMargin: hifi.dimensions.contentSpacing.y + 40
|
||||
left: parent.left; right: parent.right; top: topBar2.bottom; bottom: bottomBar.top;
|
||||
margins: 30
|
||||
}
|
||||
color: hifi.colors.tableBackgroundDark
|
||||
border.color: hifi.colors.lightGray
|
||||
border.width: 2
|
||||
radius: 5
|
||||
|
||||
ListModel {
|
||||
id: memberModel
|
||||
}
|
||||
|
||||
Component {
|
||||
id: memberDelegate
|
||||
Item {
|
||||
id: item
|
||||
width: parent.width
|
||||
anchors.left: parent.left
|
||||
height: 26
|
||||
clip: true
|
||||
|
||||
Rectangle {
|
||||
width: parent.width
|
||||
height: parent.height
|
||||
color: index % 2 == 0 ? hifi.colors.tableRowDarkEven : hifi.colors.tableRowDarkOdd
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
|
||||
Row {
|
||||
id: memberRow
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
spacing: 10
|
||||
|
||||
FiraSansSemiBold {
|
||||
property var isMainKey: apiType === "class";
|
||||
text: apiMember
|
||||
size: isMainKey ? 17 : 15
|
||||
font.bold: true
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
color: isMainKey ? hifi.colors.faintGray : hifi.colors.lightGrayText
|
||||
MouseArea {
|
||||
width: list.width
|
||||
height: parent.height
|
||||
onClicked: {
|
||||
searchBar.text = apiType=="function()" ? apiMember + "()" : apiMember;
|
||||
valueBar.text = !apiValue ? "" : apiValue;
|
||||
list.currentIndex = index;
|
||||
evaluatingIdx = index;
|
||||
}
|
||||
onDoubleClicked: {
|
||||
if (apiType === "class") {
|
||||
addListElements(apiMember+".");
|
||||
} else {
|
||||
isolateElement(evaluatingIdx);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
FiraSansRegular {
|
||||
text: apiType
|
||||
anchors.left: apiMember.right
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
size: 13
|
||||
color: hifi.colors.lightGrayText
|
||||
}
|
||||
|
||||
FiraSansRegular {
|
||||
text: !apiValue ? "" : apiValue;
|
||||
anchors.left: apiType.right
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
size: 14
|
||||
color: hifi.colors.primaryHighlight
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Component {
|
||||
id: highlight
|
||||
Rectangle {
|
||||
anchors {
|
||||
left: list.left
|
||||
right: scrollBar.left
|
||||
leftMargin: 2
|
||||
rightMargin: 2
|
||||
}
|
||||
color: hifi.colors.primaryHighlight
|
||||
radius: 4
|
||||
z: 10
|
||||
opacity: 0.5
|
||||
}
|
||||
}
|
||||
color: "white"
|
||||
radius: 4
|
||||
|
||||
ListView {
|
||||
id: list
|
||||
|
@ -269,23 +319,16 @@ Item {
|
|||
left: parent.left
|
||||
right: scrollBar.left
|
||||
bottom: parent.bottom
|
||||
margins: 4
|
||||
topMargin: 2
|
||||
leftMargin: 2
|
||||
bottomMargin: 2
|
||||
}
|
||||
clip: true
|
||||
cacheBuffer: 4000
|
||||
model: memberModel
|
||||
delegate: memberDelegate
|
||||
highlightMoveDuration: 0
|
||||
|
||||
highlight: Rectangle {
|
||||
anchors {
|
||||
left: parent ? parent.left : undefined
|
||||
right: parent ? parent.right : undefined
|
||||
leftMargin: hifi.dimensions.borderWidth
|
||||
rightMargin: hifi.dimensions.borderWidth
|
||||
}
|
||||
color: "#BBDDFF"
|
||||
}
|
||||
highlight: highlight
|
||||
onMovementStarted: {
|
||||
scrollSlider.manual = true;
|
||||
}
|
||||
|
@ -310,12 +353,11 @@ Item {
|
|||
top: parent.top
|
||||
right: parent.right
|
||||
bottom: parent.bottom
|
||||
topMargin: 4
|
||||
bottomMargin: 4
|
||||
margins: 2
|
||||
}
|
||||
width: scrolling ? 18 : 0
|
||||
radius: 4
|
||||
color: hifi.colors.baseGrayShadow
|
||||
width: 22
|
||||
height: parent.height - 4
|
||||
color: hifi.colors.tableScrollBackgroundDark
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
|
@ -344,14 +386,12 @@ Item {
|
|||
y = index*(scrollBar.height - scrollSlider.height)/(list.count - 1);
|
||||
}
|
||||
|
||||
anchors {
|
||||
right: parent.right
|
||||
rightMargin: 3
|
||||
}
|
||||
width: 12
|
||||
height: (list.height / list.contentHeight) * list.height
|
||||
radius: width / 4
|
||||
color: "white"
|
||||
anchors.right: parent.right
|
||||
anchors.margins: 2
|
||||
width: 18
|
||||
height: ((list.height / list.contentHeight) * list.height) < 15 ? 15 : (list.height / list.contentHeight) * list.height
|
||||
radius: 5
|
||||
color: hifi.colors.tableScrollHandleDark
|
||||
|
||||
visible: scrollBar.scrolling;
|
||||
|
||||
|
@ -373,66 +413,75 @@ Item {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
HifiControls.GlyphButton {
|
||||
id: clipboard;
|
||||
enabled: true;
|
||||
glyph: hifi.glyphs.scriptNew
|
||||
size: 38
|
||||
width: 50
|
||||
height: 50
|
||||
|
||||
Row {
|
||||
id: bottomBar
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: 30
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.margins: 2
|
||||
anchors.leftMargin: 8
|
||||
onClicked: {
|
||||
var buffer = "";
|
||||
for (var i = 0; i < memberModel.count; i++) {
|
||||
var datarow = memberModel.get(i);
|
||||
buffer += "\n" + datarow.apiMember + " " + datarow.apiType + " " + datarow.apiValue;
|
||||
}
|
||||
Window.copyToClipboard(buffer);
|
||||
focus = true;
|
||||
}
|
||||
}
|
||||
|
||||
HifiControls.Button {
|
||||
id: debug;
|
||||
enabled: true;
|
||||
text: "Debug Script"
|
||||
width: 120
|
||||
height: 50
|
||||
anchors.right: parent.right
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.margins: 2
|
||||
anchors.rightMargin: 8
|
||||
onClicked: {
|
||||
sendToScript({type: "selectScript"});
|
||||
}
|
||||
}
|
||||
anchors.bottomMargin: 30
|
||||
width: parent.width
|
||||
height: 40
|
||||
|
||||
HifiControls.CheckBox {
|
||||
id: hideQt
|
||||
boxSize: 25
|
||||
boxRadius: 3
|
||||
checked: true
|
||||
anchors.left: clipboard.right
|
||||
anchors.leftMargin: 8
|
||||
anchors.verticalCenter: clipboard.verticalCenter
|
||||
anchors.margins: 2
|
||||
onClicked: {
|
||||
hideQtMethods = checked;
|
||||
addListElements();
|
||||
HifiControls.GlyphButton {
|
||||
id: clipboard;
|
||||
enabled: true;
|
||||
color: hifi.buttons.black
|
||||
glyph: hifi.glyphs.scriptNew
|
||||
size: 25
|
||||
width: 40
|
||||
height: 40
|
||||
anchors.left: parent.left
|
||||
onClicked: {
|
||||
var buffer = "";
|
||||
for (var i = 0; i < memberModel.count; i++) {
|
||||
var datarow = memberModel.get(i);
|
||||
buffer += "\n" + datarow.apiMember + " " + datarow.apiType + " " + datarow.apiValue;
|
||||
}
|
||||
Window.copyToClipboard(buffer);
|
||||
focus = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
HifiControls.Label {
|
||||
id: hideLabel
|
||||
anchors.left: hideQt.right
|
||||
anchors.verticalCenter: clipboard.verticalCenter
|
||||
anchors.margins: 2
|
||||
font.pixelSize: 15
|
||||
text: "Hide Qt Methods"
|
||||
HifiControls.CheckBox {
|
||||
id: hideQt
|
||||
colorScheme: hifi.checkbox.dark
|
||||
boxSize: 25
|
||||
boxRadius: 3
|
||||
checked: true
|
||||
anchors.left: clipboard.right
|
||||
anchors.leftMargin: 10
|
||||
anchors.verticalCenter: clipboard.verticalCenter
|
||||
onClicked: {
|
||||
hideQtMethods = checked;
|
||||
addListElements();
|
||||
}
|
||||
}
|
||||
|
||||
HifiControls.Label {
|
||||
id: hideLabel
|
||||
anchors.left: hideQt.right
|
||||
anchors.verticalCenter: clipboard.verticalCenter
|
||||
anchors.margins: 2
|
||||
font.pixelSize: 15
|
||||
text: "Hide Qt Methods"
|
||||
}
|
||||
|
||||
HifiControls.Button {
|
||||
id: debug;
|
||||
enabled: true;
|
||||
color: hifi.buttons.black
|
||||
text: "Debug Script"
|
||||
width: 120
|
||||
height: 40
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: 60
|
||||
anchors.bottom: parent.bottom
|
||||
|
||||
onClicked: {
|
||||
sendToScript({type: "selectScript"});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
HifiControls.Keyboard {
|
||||
|
@ -639,4 +688,4 @@ Item {
|
|||
}
|
||||
|
||||
signal sendToScript(var message);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,10 +24,13 @@ TextField {
|
|||
property bool isSearchField: false
|
||||
property string label: ""
|
||||
property real controlHeight: height + (textFieldLabel.visible ? textFieldLabel.height + 1 : 0)
|
||||
property bool hasDefocusedBorder: true;
|
||||
property bool hasRoundedBorder: false
|
||||
property int roundedBorderRadius: 4
|
||||
property bool error: false;
|
||||
property bool hasClearButton: false;
|
||||
property string leftPlaceholderGlyph: "";
|
||||
property string leftPermanentGlyph: "";
|
||||
property string centerPlaceholderGlyph: "";
|
||||
|
||||
placeholderText: textField.placeholderText
|
||||
|
||||
|
@ -101,12 +104,12 @@ TextField {
|
|||
}
|
||||
}
|
||||
border.color: textField.error ? hifi.colors.redHighlight :
|
||||
(textField.activeFocus ? hifi.colors.primaryHighlight : (isFaintGrayColorScheme ? hifi.colors.lightGrayText : hifi.colors.lightGray))
|
||||
(textField.activeFocus ? hifi.colors.primaryHighlight : (hasDefocusedBorder ? (isFaintGrayColorScheme ? hifi.colors.lightGrayText : hifi.colors.lightGray) : color))
|
||||
border.width: textField.activeFocus || hasRoundedBorder || textField.error ? 1 : 0
|
||||
radius: isSearchField ? textField.height / 2 : (hasRoundedBorder ? 4 : 0)
|
||||
radius: isSearchField ? textField.height / 2 : (hasRoundedBorder ? roundedBorderRadius : 0)
|
||||
|
||||
HiFiGlyphs {
|
||||
text: textField.leftPlaceholderGlyph;
|
||||
text: textField.leftPermanentGlyph;
|
||||
color: textColor;
|
||||
size: hifi.fontSizes.textFieldSearchIcon;
|
||||
anchors.left: parent.left;
|
||||
|
@ -115,6 +118,15 @@ TextField {
|
|||
visible: text;
|
||||
}
|
||||
|
||||
HiFiGlyphs {
|
||||
text: textField.centerPlaceholderGlyph;
|
||||
color: textColor;
|
||||
size: parent.height;
|
||||
anchors.horizontalCenter: parent.horizontalCenter;
|
||||
anchors.verticalCenter: parent.verticalCenter;
|
||||
visible: text && !textField.focus && textField.text === "";
|
||||
}
|
||||
|
||||
HiFiGlyphs {
|
||||
text: hifi.glyphs.search
|
||||
color: textColor
|
||||
|
@ -145,7 +157,7 @@ TextField {
|
|||
placeholderTextColor: isFaintGrayColorScheme ? hifi.colors.lightGrayText : hifi.colors.lightGray
|
||||
selectedTextColor: hifi.colors.black
|
||||
selectionColor: hifi.colors.primaryHighlight
|
||||
padding.left: ((isSearchField || textField.leftPlaceholderGlyph !== "") ? textField.height - 2 : 0) + hifi.dimensions.textPadding
|
||||
padding.left: hasRoundedBorder ? textField.height / 2 : ((isSearchField || textField.leftPermanentGlyph !== "") ? textField.height - 2 : 0) + hifi.dimensions.textPadding
|
||||
padding.right: (hasClearButton ? textField.height - 2 : 0) + hifi.dimensions.textPadding
|
||||
}
|
||||
|
||||
|
|
63
interface/resources/qml/hifi/+android/Desktop.qml
Normal file
|
@ -0,0 +1,63 @@
|
|||
import QtQuick 2.5
|
||||
import QtQuick.Controls 1.4
|
||||
|
||||
import Qt.labs.settings 1.0
|
||||
|
||||
import "../desktop" as OriginalDesktop
|
||||
import ".."
|
||||
import "."
|
||||
import "./toolbars"
|
||||
|
||||
OriginalDesktop.Desktop {
|
||||
id: desktop
|
||||
|
||||
MouseArea {
|
||||
id: hoverWatch
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
propagateComposedEvents: true
|
||||
scrollGestureEnabled: false // we don't need/want these
|
||||
onEntered: ApplicationCompositor.reticleOverDesktop = true
|
||||
onExited: ApplicationCompositor.reticleOverDesktop = false
|
||||
acceptedButtons: Qt.NoButton
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
Component { id: toolbarBuilder; Toolbar { } }
|
||||
// This used to create sysToolbar dynamically with a call to getToolbar() within onCompleted.
|
||||
// Beginning with QT 5.6, this stopped working, as anything added to toolbars too early got
|
||||
// wiped during startup.
|
||||
Toolbar {
|
||||
id: sysToolbar;
|
||||
objectName: "com.highfidelity.interface.toolbar.system";
|
||||
// Magic: sysToolbar.x and y come from settings, and are bound before the properties specified here are applied.
|
||||
x: sysToolbar.x;
|
||||
y: sysToolbar.y;
|
||||
}
|
||||
property var toolbars: (function (map) { // answer dictionary preloaded with sysToolbar
|
||||
map[sysToolbar.objectName] = sysToolbar;
|
||||
return map; })({});
|
||||
|
||||
Component.onCompleted: {
|
||||
}
|
||||
|
||||
// Accept a download through the webview
|
||||
property bool webViewProfileSetup: false
|
||||
property string currentUrl: ""
|
||||
property string adaptedPath: ""
|
||||
property string tempDir: ""
|
||||
|
||||
// Create or fetch a toolbar with the given name
|
||||
function getToolbar(name) {
|
||||
var result = toolbars[name];
|
||||
if (!result) {
|
||||
result = toolbars[name] = toolbarBuilder.createObject(desktop, {});
|
||||
result.objectName = name;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -102,7 +102,7 @@ Column {
|
|||
'include_actions=' + actions,
|
||||
'restriction=' + (Account.isLoggedIn() ? 'open,hifi' : 'open'),
|
||||
'require_online=true',
|
||||
'protocol=' + encodeURIComponent(AddressManager.protocolVersion()),
|
||||
'protocol=' + encodeURIComponent(Window.protocolSignature()),
|
||||
'page=' + pageNumber
|
||||
];
|
||||
var url = metaverseBase + 'user_stories?' + options.join('&');
|
||||
|
|
|
@ -17,6 +17,7 @@ ListModel {
|
|||
id: root;
|
||||
property string sortColumnName: "";
|
||||
property bool isSortingDescending: true;
|
||||
property bool valuesAreNumerical: false;
|
||||
|
||||
function swap(a, b) {
|
||||
if (a < b) {
|
||||
|
@ -29,26 +30,51 @@ ListModel {
|
|||
}
|
||||
|
||||
function partition(begin, end, pivot) {
|
||||
var piv = get(pivot)[sortColumnName];
|
||||
swap(pivot, end - 1);
|
||||
var store = begin;
|
||||
if (valuesAreNumerical) {
|
||||
var piv = get(pivot)[sortColumnName];
|
||||
swap(pivot, end - 1);
|
||||
var store = begin;
|
||||
|
||||
for (var i = begin; i < end - 1; ++i) {
|
||||
if (isSortingDescending) {
|
||||
if (get(i)[sortColumnName] < piv) {
|
||||
swap(store, i);
|
||||
++store;
|
||||
}
|
||||
} else {
|
||||
if (get(i)[sortColumnName] > piv) {
|
||||
swap(store, i);
|
||||
++store;
|
||||
for (var i = begin; i < end - 1; ++i) {
|
||||
var currentElement = get(i)[sortColumnName];
|
||||
if (isSortingDescending) {
|
||||
if (currentElement < piv) {
|
||||
swap(store, i);
|
||||
++store;
|
||||
}
|
||||
} else {
|
||||
if (currentElement > piv) {
|
||||
swap(store, i);
|
||||
++store;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
swap(end - 1, store);
|
||||
swap(end - 1, store);
|
||||
|
||||
return store;
|
||||
return store;
|
||||
} else {
|
||||
var piv = get(pivot)[sortColumnName].toLowerCase();
|
||||
swap(pivot, end - 1);
|
||||
var store = begin;
|
||||
|
||||
for (var i = begin; i < end - 1; ++i) {
|
||||
var currentElement = get(i)[sortColumnName].toLowerCase();
|
||||
if (isSortingDescending) {
|
||||
if (currentElement < piv) {
|
||||
swap(store, i);
|
||||
++store;
|
||||
}
|
||||
} else {
|
||||
if (currentElement > piv) {
|
||||
swap(store, i);
|
||||
++store;
|
||||
}
|
||||
}
|
||||
}
|
||||
swap(end - 1, store);
|
||||
|
||||
return store;
|
||||
}
|
||||
}
|
||||
|
||||
function qsort(begin, end) {
|
||||
|
|
|
@ -677,7 +677,7 @@ Rectangle {
|
|||
}
|
||||
}
|
||||
|
||||
if (sameItemCount !== tempPurchasesModel.count) {
|
||||
if (sameItemCount !== tempPurchasesModel.count || filterBar.text !== "") {
|
||||
filteredPurchasesModel.clear();
|
||||
for (var i = 0; i < tempPurchasesModel.count; i++) {
|
||||
filteredPurchasesModel.append(tempPurchasesModel.get(i));
|
||||
|
|
|
@ -193,7 +193,7 @@ Item {
|
|||
color: hifi.colors.white;
|
||||
}
|
||||
|
||||
// "Change Passphrase" button
|
||||
// "Change Security Pic" button
|
||||
HifiControlsUit.Button {
|
||||
id: changeSecurityImageButton;
|
||||
color: hifi.buttons.blue;
|
||||
|
|
|
@ -34,13 +34,11 @@ Item {
|
|||
securityImageChangePageSecurityImage.source = "image://security/securityImage";
|
||||
if (exists) { // Success submitting new security image
|
||||
if (root.justSubmitted) {
|
||||
root.resetSubmitButton();
|
||||
sendSignalToWallet({method: "walletSecurity_changeSecurityImageSuccess"});
|
||||
root.justSubmitted = false;
|
||||
}
|
||||
} else if (root.justSubmitted) {
|
||||
// Error submitting new security image.
|
||||
root.resetSubmitButton();
|
||||
root.justSubmitted = false;
|
||||
}
|
||||
}
|
||||
|
@ -180,7 +178,8 @@ Item {
|
|||
// "Submit" button
|
||||
HifiControlsUit.Button {
|
||||
id: securityImageSubmitButton;
|
||||
enabled: securityImageSelection.currentIndex !== -1;
|
||||
text: root.justSubmitted ? "Submitting..." : "Submit";
|
||||
enabled: securityImageSelection.currentIndex !== -1 && !root.justSubmitted;
|
||||
color: hifi.buttons.blue;
|
||||
colorScheme: hifi.colorSchemes.dark;
|
||||
anchors.top: parent.top;
|
||||
|
@ -188,11 +187,8 @@ Item {
|
|||
anchors.right: parent.right;
|
||||
anchors.rightMargin: 20;
|
||||
width: 150;
|
||||
text: "Submit";
|
||||
onClicked: {
|
||||
root.justSubmitted = true;
|
||||
securityImageSubmitButton.text = "Submitting...";
|
||||
securityImageSubmitButton.enabled = false;
|
||||
var securityImagePath = securityImageSelection.getImagePathFromImageID(securityImageSelection.getSelectedImageIndex())
|
||||
Commerce.chooseSecurityImage(securityImagePath);
|
||||
}
|
||||
|
@ -205,11 +201,6 @@ Item {
|
|||
|
||||
signal sendSignalToWallet(var msg);
|
||||
|
||||
function resetSubmitButton() {
|
||||
securityImageSubmitButton.enabled = true;
|
||||
securityImageSubmitButton.text = "Submit";
|
||||
}
|
||||
|
||||
function initModel() {
|
||||
securityImageSelection.initModel();
|
||||
}
|
||||
|
|
|
@ -24,7 +24,7 @@ Item {
|
|||
HifiConstants { id: hifi; }
|
||||
|
||||
id: root;
|
||||
property int currentIndex: securityImageGrid.currentIndex;
|
||||
property alias currentIndex: securityImageGrid.currentIndex;
|
||||
|
||||
// This will cause a bug -- if you bring up security image selection in HUD mode while
|
||||
// in HMD while having HMD preview enabled, then move, then finish passphrase selection,
|
||||
|
@ -98,6 +98,11 @@ Item {
|
|||
|
||||
function initModel() {
|
||||
gridModel.initModel();
|
||||
securityImageGrid.currentIndex = -1;
|
||||
}
|
||||
|
||||
function resetSelection() {
|
||||
securityImageGrid.currentIndex = -1;
|
||||
}
|
||||
//
|
||||
// FUNCTION DEFINITIONS END
|
||||
|
|
|
@ -389,7 +389,7 @@ Rectangle {
|
|||
//
|
||||
Item {
|
||||
id: tabButtonsContainer;
|
||||
visible: !needsLogIn.visible && root.activeView !== "passphraseChange" && root.activeView !== "securityImageChange";
|
||||
visible: !needsLogIn.visible && root.activeView !== "passphraseChange" && root.activeView !== "securityImageChange" && sendMoney.currentActiveView !== "sendMoneyStep";
|
||||
property int numTabs: 5;
|
||||
// Size
|
||||
width: root.width;
|
||||
|
|
|
@ -392,7 +392,6 @@ Item {
|
|||
width: 118;
|
||||
height: paintedHeight;
|
||||
wrapMode: Text.WordWrap;
|
||||
font.bold: true;
|
||||
// Alignment
|
||||
horizontalAlignment: Text.AlignRight;
|
||||
}
|
||||
|
|
|
@ -348,6 +348,7 @@ Item {
|
|||
width: 200;
|
||||
text: "Back"
|
||||
onClicked: {
|
||||
securityImageSelection.resetSelection();
|
||||
root.activeView = "step_1";
|
||||
}
|
||||
}
|
||||
|
@ -516,6 +517,7 @@ Item {
|
|||
width: 200;
|
||||
text: "Back"
|
||||
onClicked: {
|
||||
securityImageSelection.resetSelection();
|
||||
root.lastPage = "step_3";
|
||||
root.activeView = "step_2";
|
||||
}
|
||||
|
|
|
@ -29,13 +29,13 @@ Item {
|
|||
property string userName;
|
||||
property string profilePicUrl;
|
||||
|
||||
height: 65;
|
||||
height: 75;
|
||||
width: parent.width;
|
||||
|
||||
Rectangle {
|
||||
id: mainContainer;
|
||||
// Style
|
||||
color: root.isSelected ? hifi.colors.faintGray : hifi.colors.white;
|
||||
color: root.isSelected ? hifi.colors.faintGray80 : hifi.colors.white;
|
||||
// Size
|
||||
anchors.left: parent.left;
|
||||
anchors.right: parent.right;
|
||||
|
@ -49,7 +49,7 @@ Item {
|
|||
anchors.verticalCenter: parent.verticalCenter;
|
||||
anchors.left: parent.left;
|
||||
anchors.leftMargin: 36;
|
||||
height: root.height - 15;
|
||||
height: 50;
|
||||
width: visible ? height : 0;
|
||||
clip: true;
|
||||
Image {
|
||||
|
@ -83,15 +83,15 @@ Item {
|
|||
RalewaySemiBold {
|
||||
id: userName;
|
||||
anchors.left: avatarImage.right;
|
||||
anchors.leftMargin: 16;
|
||||
anchors.leftMargin: 12;
|
||||
anchors.top: parent.top;
|
||||
anchors.bottom: parent.bottom;
|
||||
anchors.right: chooseButton.visible ? chooseButton.left : parent.right;
|
||||
anchors.rightMargin: chooseButton.visible ? 10 : 0;
|
||||
// Text size
|
||||
size: 20;
|
||||
size: 18;
|
||||
// Style
|
||||
color: hifi.colors.baseGray;
|
||||
color: hifi.colors.blueAccent;
|
||||
text: root.userName;
|
||||
elide: Text.ElideRight;
|
||||
// Alignment
|
||||
|
@ -107,9 +107,9 @@ Item {
|
|||
colorScheme: hifi.colorSchemes.dark;
|
||||
anchors.verticalCenter: parent.verticalCenter;
|
||||
anchors.right: parent.right;
|
||||
anchors.rightMargin: 24;
|
||||
height: root.height - 20;
|
||||
width: 110;
|
||||
anchors.rightMargin: 28;
|
||||
height: 35;
|
||||
width: 100;
|
||||
text: "CHOOSE";
|
||||
onClicked: {
|
||||
var msg = { method: 'chooseConnection', userName: root.userName, profilePicUrl: root.profilePicUrl };
|
||||
|
|
|
@ -29,6 +29,7 @@ Item {
|
|||
property string displayName;
|
||||
property string userName;
|
||||
property string profilePic;
|
||||
property string textColor: hifi.colors.white;
|
||||
|
||||
Item {
|
||||
visible: root.isDisplayingNearby;
|
||||
|
@ -46,7 +47,7 @@ Item {
|
|||
// Text size
|
||||
size: 18;
|
||||
// Style
|
||||
color: hifi.colors.baseGray;
|
||||
color: root.textColor;
|
||||
verticalAlignment: Text.AlignBottom;
|
||||
elide: Text.ElideRight;
|
||||
}
|
||||
|
@ -63,7 +64,7 @@ Item {
|
|||
// Text size
|
||||
size: 16;
|
||||
// Style
|
||||
color: hifi.colors.baseGray;
|
||||
color: root.textColor;
|
||||
verticalAlignment: Text.AlignTop;
|
||||
elide: Text.ElideRight;
|
||||
}
|
||||
|
@ -108,7 +109,7 @@ Item {
|
|||
// Text size
|
||||
size: 16;
|
||||
// Style
|
||||
color: hifi.colors.baseGray;
|
||||
color: root.textColor;
|
||||
verticalAlignment: Text.AlignVCenter;
|
||||
elide: Text.ElideRight;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 22.0.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
viewBox="0 0 512 512" style="enable-background:new 0 0 512 512;" xml:space="preserve">
|
||||
<style type="text/css">
|
||||
.st0{fill:#1398BB;}
|
||||
</style>
|
||||
<path class="st0" d="M256.8,42C138.5,42,42.2,138.3,42.2,256.6s96.3,214.6,214.6,214.6c118.3,0,214.6-96.3,214.6-214.6
|
||||
S375.1,42,256.8,42z M256.8,444.4C153.2,444.4,69,360.1,69,256.6C69,153,153.2,68.7,256.8,68.7c103.6,0,187.8,84.3,187.8,187.8
|
||||
C444.6,360.1,360.4,444.4,256.8,444.4z"/>
|
||||
<circle class="st0" cx="260.6" cy="189.4" r="60.6"/>
|
||||
<path class="st0" d="M306.4,282.6h-87.6c-36.5,0-66.4,30.2-66.4,66.7v33.9c29.3,22.6,65.4,36.1,105,36.1c44.4,0,84.7-17,115.2-44.7
|
||||
v-25.3C372.7,312.7,342.9,282.6,306.4,282.6z"/>
|
||||
</svg>
|
After (image error) Size: 921 B |
After ![]() (image error) Size: 58 KiB |
|
@ -0,0 +1,27 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 22.0.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
viewBox="0 0 512 512" style="enable-background:new 0 0 512 512;" xml:space="preserve">
|
||||
<style type="text/css">
|
||||
.st0{fill:#1398BB;}
|
||||
</style>
|
||||
<path class="st0" d="M144.3,155c-8.7-8.8-16.7-17.1-25.2-25.7c-22.4,25.4-36.6,53.9-43.6,86.2c-26.9,125.7,81.2,241.5,208.6,223.4
|
||||
C385.9,424.4,458,329.2,443.5,228.2c-4.4-30.6-15.4-58.9-34.1-83.9c-1.6-2.2-3.3-4.3-4.7-6.6c-4.4-7.4-3.1-14.9,3-19.5
|
||||
c6-4.5,14.2-3.6,19.2,3.5c8.2,11.7,16.6,23.4,22.9,36.1c41.9,84.9,25.7,181.7-41,248.7c-67,67.4-175.1,81.3-257.1,33.3
|
||||
c-35.3-20.7-63.1-48.6-82.7-84.5c-41-75-31.5-172.5,23.4-237.9c2.2-2.7,4.4-5.4,7.1-8.7c-8.1-8.5-16.1-16.9-24-25.3
|
||||
c-7.2-7.7-7.9-16.1-1.9-22.1c5.9-5.9,15-5.1,22.1,2.4c56.8,59.5,113.6,119,170.4,178.6c7.2,7.6,7.8,15.4,1.9,21.4
|
||||
c-6.1,6.2-14.7,5.5-22-2c-10.2-10.4-20.2-21-30.3-31.5c-17.4,24.7-3.3,62,27.2,72.5c23,7.9,48.8-2,60.7-23.1
|
||||
c1.2-2.1,2.3-4.3,3.7-6.3c4.5-6.6,11.7-8.6,18.3-5c6.6,3.5,8.9,10.5,5.9,18.1c-12.4,31.6-47.9,52.2-82.3,47.7
|
||||
c-36.1-4.8-64.3-32.6-68.4-67.7c-2.4-20.7,2.4-39.7,14.9-57.5c-10.4-10.9-20.8-21.6-31.7-33c-9.7,10.8-16.2,22.7-20.9,35.7
|
||||
c-31.3,86.4,38.9,175.1,130.1,164.3c74-8.7,122.3-80.9,103.3-154.3c-3.4-13.1-1-20.2,7.8-22.7c9.5-2.8,15.2,1.8,19.2,15.4
|
||||
c20.1,67.4-16,144.8-79.8,175.3c-67.5,32.2-147.5,9.7-188.8-49c-37.8-53.8-36.1-127.7,4.7-179.1C141.2,159.4,142.5,157.4,144.3,155z
|
||||
"/>
|
||||
<path class="st0" d="M236.2,262.2c-4.2-13.6,3.4-28.2,16.8-32.4c13.5-4.2,28.1,3.3,32.5,16.8c4.5,13.9-3.1,28.4-17.2,32.7
|
||||
C254.6,283.5,240.4,275.9,236.2,262.2z"/>
|
||||
<path class="st0" d="M319.6,101.9c-3.7-11,1.8-22.3,12.7-26c11.3-3.9,22.8,1.9,26.4,13.2c3.5,11-2.3,22.2-13.2,25.8
|
||||
C334.5,118.5,323.3,112.9,319.6,101.9z"/>
|
||||
<path class="st0" d="M214.9,66.2c3.2,10.2-2.2,20.5-12.5,23.6c-9.8,3-20-2.3-23.3-12c-3.3-9.9,2.2-20.8,12-24
|
||||
C201.1,50.5,211.8,56.2,214.9,66.2z"/>
|
||||
<path class="st0" d="M230.8,164.6c-3.7-11,1.8-22.3,12.7-26c11.3-3.9,22.8,1.9,26.4,13.2c3.5,11-2.3,22.2-13.2,25.8
|
||||
C245.7,181.2,234.5,175.6,230.8,164.6z"/>
|
||||
</svg>
|
After (image error) Size: 2.1 KiB |
|
@ -0,0 +1,27 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 22.0.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
viewBox="0 0 143.1 414.2" style="enable-background:new 0 0 143.1 414.2;" xml:space="preserve">
|
||||
<style type="text/css">
|
||||
.st0{fill:#B9B9B9;}
|
||||
.st1{fill:#EE982D;}
|
||||
.st2{fill:#FF630A;}
|
||||
</style>
|
||||
<path class="st0" d="M78.8,7.1c3.9,4.3,7.7,8.7,11.8,12.9c3.7,3.8,5.1,7.9,4.4,12.9c-1,7.1-1.8,14-7.1,20.1
|
||||
c-4.2,4.7-1.3,12,4.6,14.5c5.6,2.3,11.1,4.6,16.7,7c8.1,3.5,12.3,9.6,13.2,17.4c0.8,6.3,0.8,12.6,1.2,18.9c0.1,2.2,0.3,4.3,0.7,6.4
|
||||
c0.3,2.2,1.9,4.4-1.3,6.1c-0.6,0.3-0.6,2.2-0.3,3.3c5.4,25.1-0.3,49.7-4.9,74.3c-1.2,6.3-3.1,12-5.5,17.9
|
||||
c-2.3,5.5-0.9,12.4-0.4,18.7c0.6,7.8,2,15.5,3.2,23.7c-2.5,0.5-4.5,1.4-6.3,1.2c-6.1-0.5-6.8,2.6-6.4,6.7c0.7,6.6,1.1,13.3,2.4,19.8
|
||||
c0.6,3.3,3.5,6.1,4.5,9.4c5,15.6,1.1,30.9-1.3,46.5c-1.7,10.6-0.6,21.5-1.5,32.2c-0.5,6.5-1.5,13.3-4,19.4c-2.2,5.4-9,3.9-14.1,4
|
||||
c-2.8,0.1-5.6-0.3-8.2-1.1c-1.2-0.3-2.6-2.2-2.5-3.3c0.1-1.9,0.7-4.1,1.9-5.7c11.5-16,9.1-33.7,8.2-51.2c-0.5-9.8-1.6-19.6-2.9-29.3
|
||||
c-1.2-8.8-3.1-17.5-5-26.2c-1.2-5.5-3.4-10.9-4.4-16.5c-0.8-3.9-2.4-5.3-7.4-3.8c-0.5,8.5-3.1,17.7-0.9,25.9
|
||||
c2.7,10.1,4.5,20,3.3,30.2c-1,8.8-2.9,17.5-3.9,26.2c-0.7,6.6-1.1,13,1.7,19.8c2.4,5.9,0.6,13.1,0.3,19.7c0,0.9-2.1,2.3-3.4,2.5
|
||||
c-4.8,0.7-9.8,0.8-14.5,1.6c-5.1,0.9-9.9,3-15,3.6c-5.7,0.6-11.5,0.1-17.3,0.1c-2.4-4,0-6.2,3.2-8.4c6.9-4.5,13.7-9,20.5-13.6
|
||||
c6.4-4.4,7.5-10.2,6.6-17.1c-2.1-17.2-6.4-34.1-5.2-51.6c0.8-11.3-0.7-22.5-4.2-33.5c-1.7-5.2-3.4-9.1-10.4-7.8
|
||||
c-0.4-0.8-0.9-1.2-0.9-1.7c-0.4-17.6-1.7-35.3-0.9-52.9c0.6-12.6,3.9-25,6-37.5c0.1-0.6,0.9-1.5,0.7-1.8c-5-8,2.9-15.7,0.6-23.9
|
||||
c-2.2-8-3.5-16.4-3.7-24.6c-0.2-6.9,2.3-13.8,2.8-20.7c0.8-12.2,8.8-18.8,20.6-23c7.3-2.6,9.1-5.2,8.2-11.3c-0.1-1.1-0.6-2.7-1.4-3
|
||||
c-10-4.1-8.9-12.3-9.9-19.9c-0.9-7.2-2.7-14.2-3.6-21.4c-0.3-2.9,0.2-5.9,3.6-8.1c6.4-4,13.1-5.3,20.7-3.4
|
||||
C73.7,8.3,76.3,7.4,78.8,7.1z M107.1,130.2c-1,0-2,0.1-3.1,0.1c0,3.1-0.2,6.1,0,9.2c0.7,9.3,5.9,19-2.4,27.7
|
||||
c-0.2,0.2-0.2,0.6-0.1,0.9c1.9,7.2,3.8,14.5,5.6,21.7c0.7-0.1,1.4-0.1,2.1-0.2C108.5,169.9,107.8,150,107.1,130.2z"/>
|
||||
<circle class="st1" cx="70.9" cy="109.9" r="26"/>
|
||||
<circle class="st2" cx="70.9" cy="109.9" r="19"/>
|
||||
</svg>
|
After (image error) Size: 2.3 KiB |
|
@ -0,0 +1,30 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 22.0.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
viewBox="0 0 143.1 414.2" style="enable-background:new 0 0 143.1 414.2;" xml:space="preserve">
|
||||
<style type="text/css">
|
||||
.st0{fill:#B9B9B9;}
|
||||
.st1{fill:#009175;}
|
||||
.st2{fill:#1FC6A6;}
|
||||
.st3{fill:#FFFFFF;}
|
||||
</style>
|
||||
<path class="st0" d="M78.8,7.1c3.9,4.3,7.7,8.7,11.8,12.9c3.7,3.8,5.1,7.9,4.4,12.9c-1,7.1-1.8,14-7.1,20.1
|
||||
c-4.2,4.7-1.3,12,4.6,14.5c5.6,2.3,11.1,4.6,16.7,7c8.1,3.5,12.3,9.6,13.2,17.4c0.8,6.3,0.8,12.6,1.2,18.9c0.1,2.2,0.3,4.3,0.7,6.4
|
||||
c0.3,2.2,1.9,4.4-1.3,6.1c-0.6,0.3-0.6,2.2-0.3,3.3c5.4,25.1-0.3,49.7-4.9,74.3c-1.2,6.3-3.1,12-5.5,17.9
|
||||
c-2.3,5.5-0.9,12.4-0.4,18.7c0.6,7.8,2,15.5,3.2,23.7c-2.5,0.5-4.5,1.4-6.3,1.2c-6.1-0.5-6.8,2.6-6.4,6.7c0.7,6.6,1.1,13.3,2.4,19.8
|
||||
c0.6,3.3,3.5,6.1,4.5,9.4c5,15.6,1.1,30.9-1.3,46.5c-1.7,10.6-0.6,21.5-1.5,32.2c-0.5,6.5-1.5,13.3-4,19.4c-2.2,5.4-9,3.9-14.1,4
|
||||
c-2.8,0.1-5.6-0.3-8.2-1.1c-1.2-0.3-2.6-2.2-2.5-3.3c0.1-1.9,0.7-4.1,1.9-5.7c11.5-16,9.1-33.7,8.2-51.2c-0.5-9.8-1.6-19.6-2.9-29.3
|
||||
c-1.2-8.8-3.1-17.5-5-26.2c-1.2-5.5-3.4-10.9-4.4-16.5c-0.8-3.9-2.4-5.3-7.4-3.8c-0.5,8.5-3.1,17.7-0.9,25.9
|
||||
c2.7,10.1,4.5,20,3.3,30.2c-1,8.8-2.9,17.5-3.9,26.2c-0.7,6.6-1.1,13,1.7,19.8c2.4,5.9,0.6,13.1,0.3,19.7c0,0.9-2.1,2.3-3.4,2.5
|
||||
c-4.8,0.7-9.8,0.8-14.5,1.6c-5.1,0.9-9.9,3-15,3.6c-5.7,0.6-11.5,0.1-17.3,0.1c-2.4-4,0-6.2,3.2-8.4c6.9-4.5,13.7-9,20.5-13.6
|
||||
c6.4-4.4,7.5-10.2,6.6-17.1c-2.1-17.2-6.4-34.1-5.2-51.6c0.8-11.3-0.7-22.5-4.2-33.5c-1.7-5.2-3.4-9.1-10.4-7.8
|
||||
c-0.4-0.8-0.9-1.2-0.9-1.7c-0.4-17.6-1.7-35.3-0.9-52.9c0.6-12.6,3.9-25,6-37.5c0.1-0.6,0.9-1.5,0.7-1.8c-5-8,2.9-15.7,0.6-23.9
|
||||
c-2.2-8-3.5-16.4-3.7-24.6c-0.2-6.9,2.3-13.8,2.8-20.7c0.8-12.2,8.8-18.8,20.6-23c7.3-2.6,9.1-5.2,8.2-11.3c-0.1-1.1-0.6-2.7-1.4-3
|
||||
c-10-4.1-8.9-12.3-9.9-19.9c-0.9-7.2-2.7-14.2-3.6-21.4c-0.3-2.9,0.2-5.9,3.6-8.1c6.4-4,13.1-5.3,20.7-3.4
|
||||
C73.7,8.3,76.3,7.4,78.8,7.1z M107.1,130.2c-1,0-2,0.1-3.1,0.1c0,3.1-0.2,6.1,0,9.2c0.7,9.3,5.9,19-2.4,27.7
|
||||
c-0.2,0.2-0.2,0.6-0.1,0.9c1.9,7.2,3.8,14.5,5.6,21.7c0.7-0.1,1.4-0.1,2.1-0.2C108.5,169.9,107.8,150,107.1,130.2z"/>
|
||||
<circle class="st1" cx="70.9" cy="109.9" r="26"/>
|
||||
<circle class="st2" cx="70.9" cy="109.9" r="23"/>
|
||||
<path class="st3" d="M70.9,127.8c-9.9,0-17.9-8-17.9-17.9s8-17.9,17.9-17.9s17.9,8,17.9,17.9S80.7,127.8,70.9,127.8z M70.9,94.8
|
||||
c-8.3,0-15.1,6.8-15.1,15.1s6.8,15.1,15.1,15.1S86,118.3,86,109.9S79.2,94.8,70.9,94.8z"/>
|
||||
</svg>
|
After (image error) Size: 2.5 KiB |
|
@ -0,0 +1,29 @@
|
|||
//
|
||||
// AdvancedPreferencesDialog.qml
|
||||
//
|
||||
// Created by Brad Hefta-Gaub on 20 Jan 2018
|
||||
// Copyright 2018 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
import QtQuick 2.5
|
||||
import Qt.labs.settings 1.0
|
||||
|
||||
import "../../dialogs"
|
||||
|
||||
PreferencesDialog {
|
||||
id: root
|
||||
objectName: "AdvancedPreferencesDialog"
|
||||
title: "Advanced Settings"
|
||||
showCategories: ["Advanced UI" ]
|
||||
property var settings: Settings {
|
||||
category: root.objectName
|
||||
property alias x: root.x
|
||||
property alias y: root.y
|
||||
property alias width: root.width
|
||||
property alias height: root.height
|
||||
}
|
||||
}
|
||||
|
|
@ -17,7 +17,7 @@ PreferencesDialog {
|
|||
id: root
|
||||
objectName: "GeneralPreferencesDialog"
|
||||
title: "General Settings"
|
||||
showCategories: ["UI", "Snapshots", "Scripts", "Privacy", "Octree", "HMD", "Game Controller", "Sixense Controllers", "Perception Neuron", "Kinect", "Leap Motion"]
|
||||
showCategories: ["UI", "Snapshots", "Privacy", "HMD", "Game Controller", "Sixense Controllers", "Perception Neuron", "Kinect", "Leap Motion"]
|
||||
property var settings: Settings {
|
||||
category: root.objectName
|
||||
property alias x: root.x
|
||||
|
|
|
@ -14,17 +14,20 @@
|
|||
#include <chrono>
|
||||
#include <thread>
|
||||
|
||||
#include <gl/Config.h>
|
||||
#include <glm/glm.hpp>
|
||||
#include <glm/gtx/component_wise.hpp>
|
||||
#include <glm/gtx/quaternion.hpp>
|
||||
#include <glm/gtx/vector_angle.hpp>
|
||||
#include <glm/gtc/type_ptr.hpp>
|
||||
|
||||
#include <gl/Config.h>
|
||||
|
||||
#include <QtCore/QResource>
|
||||
#include <QtCore/QAbstractNativeEventFilter>
|
||||
#include <QtCore/QCommandLineParser>
|
||||
#include <QtCore/QMimeData>
|
||||
#include <QtCore/QThreadPool>
|
||||
#include <QtCore/QFileSelector>
|
||||
#include <QtConcurrent/QtConcurrentRun>
|
||||
|
||||
#include <QtGui/QScreen>
|
||||
|
@ -49,6 +52,7 @@
|
|||
|
||||
#include <gl/QOpenGLContextWrapper.h>
|
||||
|
||||
#include <shared/FileUtils.h>
|
||||
#include <shared/QtHelpers.h>
|
||||
#include <shared/GlobalAppProperties.h>
|
||||
#include <StatTracker.h>
|
||||
|
@ -209,9 +213,8 @@
|
|||
#include "commerce/QmlCommerce.h"
|
||||
|
||||
#include "webbrowser/WebBrowserSuggestionsEngine.h"
|
||||
#include <DesktopPreviewProvider.h>
|
||||
|
||||
// On Windows PC, NVidia Optimus laptop, we want to enable NVIDIA GPU
|
||||
// FIXME seems to be broken.
|
||||
#if defined(Q_OS_WIN)
|
||||
#include <VersionHelpers.h>
|
||||
|
||||
|
@ -226,11 +229,17 @@
|
|||
#undef QT_BOOTSTRAPPED
|
||||
#endif
|
||||
|
||||
// On Windows PC, NVidia Optimus laptop, we want to enable NVIDIA GPU
|
||||
// FIXME seems to be broken.
|
||||
extern "C" {
|
||||
_declspec(dllexport) DWORD NvOptimusEnablement = 0x00000001;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(Q_OS_ANDROID)
|
||||
#include <android/log.h>
|
||||
#endif
|
||||
|
||||
enum ApplicationEvent {
|
||||
// Execute a lambda function
|
||||
Lambda = QEvent::User + 1,
|
||||
|
@ -240,7 +249,6 @@ enum ApplicationEvent {
|
|||
Idle,
|
||||
};
|
||||
|
||||
|
||||
class RenderEventHandler : public QObject {
|
||||
using Parent = QObject;
|
||||
Q_OBJECT
|
||||
|
@ -304,9 +312,19 @@ static QTimer locationUpdateTimer;
|
|||
static QTimer identityPacketTimer;
|
||||
static QTimer pingTimer;
|
||||
|
||||
static const QString DISABLE_WATCHDOG_FLAG("HIFI_DISABLE_WATCHDOG");
|
||||
#if defined(Q_OS_ANDROID)
|
||||
static bool DISABLE_WATCHDOG = true;
|
||||
#else
|
||||
static const QString DISABLE_WATCHDOG_FLAG{ "HIFI_DISABLE_WATCHDOG" };
|
||||
static bool DISABLE_WATCHDOG = QProcessEnvironment::systemEnvironment().contains(DISABLE_WATCHDOG_FLAG);
|
||||
#endif
|
||||
|
||||
#if defined(USE_GLES)
|
||||
static bool DISABLE_DEFERRED = true;
|
||||
#else
|
||||
static const QString RENDER_FORWARD{ "HIFI_RENDER_FORWARD" };
|
||||
static bool DISABLE_DEFERRED = QProcessEnvironment::systemEnvironment().contains(RENDER_FORWARD);
|
||||
#endif
|
||||
|
||||
static const int MAX_CONCURRENT_RESOURCE_DOWNLOADS = 16;
|
||||
|
||||
|
@ -333,7 +351,7 @@ static const float MIRROR_FULLSCREEN_DISTANCE = 0.389f;
|
|||
static const quint64 TOO_LONG_SINCE_LAST_SEND_DOWNSTREAM_AUDIO_STATS = 1 * USECS_PER_SECOND;
|
||||
|
||||
static const QString INFO_EDIT_ENTITIES_PATH = "html/edit-commands.html";
|
||||
static const QString INFO_HELP_PATH = "../../../html/tabletHelp.html";
|
||||
static const QString INFO_HELP_PATH = "html/tabletHelp.html";
|
||||
|
||||
static const unsigned int THROTTLED_SIM_FRAMERATE = 15;
|
||||
static const int THROTTLED_SIM_FRAME_PERIOD_MS = MSECS_PER_SECOND / THROTTLED_SIM_FRAMERATE;
|
||||
|
@ -503,7 +521,13 @@ public:
|
|||
}
|
||||
|
||||
if (message->message == WM_DEVICECHANGE) {
|
||||
Midi::USBchanged(); // re-scan the MIDI bus
|
||||
const float MIN_DELTA_SECONDS = 2.0f; // de-bounce signal
|
||||
static float lastTriggerTime = 0.0f;
|
||||
const float deltaSeconds = secTimestampNow() - lastTriggerTime;
|
||||
lastTriggerTime = secTimestampNow();
|
||||
if (deltaSeconds > MIN_DELTA_SECONDS) {
|
||||
Midi::USBchanged(); // re-scan the MIDI bus
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
|
@ -530,6 +554,26 @@ void messageHandler(QtMsgType type, const QMessageLogContext& context, const QSt
|
|||
#ifdef Q_OS_WIN
|
||||
OutputDebugStringA(logMessage.toLocal8Bit().constData());
|
||||
OutputDebugStringA("\n");
|
||||
#elif defined Q_OS_ANDROID
|
||||
const char * local=logMessage.toStdString().c_str();
|
||||
switch (type) {
|
||||
case QtDebugMsg:
|
||||
__android_log_write(ANDROID_LOG_DEBUG,"Interface",local);
|
||||
break;
|
||||
case QtInfoMsg:
|
||||
__android_log_write(ANDROID_LOG_INFO,"Interface",local);
|
||||
break;
|
||||
case QtWarningMsg:
|
||||
__android_log_write(ANDROID_LOG_WARN,"Interface",local);
|
||||
break;
|
||||
case QtCriticalMsg:
|
||||
__android_log_write(ANDROID_LOG_ERROR,"Interface",local);
|
||||
break;
|
||||
case QtFatalMsg:
|
||||
default:
|
||||
__android_log_write(ANDROID_LOG_FATAL,"Interface",local);
|
||||
abort();
|
||||
}
|
||||
#endif
|
||||
qApp->getLogger()->addMessage(qPrintable(logMessage + "\n"));
|
||||
}
|
||||
|
@ -573,8 +617,7 @@ bool setupEssentials(int& argc, char** argv, bool runningMarkerExisted) {
|
|||
}
|
||||
};
|
||||
reportAndQuit("--protocolVersion", [&](FILE* fp) {
|
||||
DependencyManager::set<AddressManager>();
|
||||
auto version = DependencyManager::get<AddressManager>()->protocolVersion();
|
||||
auto version = protocolVersionsSignatureBase64();
|
||||
fputs(version.toLatin1().data(), fp);
|
||||
});
|
||||
reportAndQuit("--version", [&](FILE* fp) {
|
||||
|
@ -594,6 +637,24 @@ bool setupEssentials(int& argc, char** argv, bool runningMarkerExisted) {
|
|||
qApp->setProperty(hifi::properties::APP_LOCAL_DATA_PATH, cacheDir);
|
||||
}
|
||||
|
||||
// FIXME fix the OSX installer to install the resources.rcc binary instead of resource files and remove
|
||||
// this conditional exclusion
|
||||
#if !defined(Q_OS_OSX)
|
||||
{
|
||||
#if defined(Q_OS_ANDROID)
|
||||
const QString resourcesBinaryFile = QStandardPaths::writableLocation(QStandardPaths::CacheLocation) + "/resources.rcc";
|
||||
#else
|
||||
const QString resourcesBinaryFile = QCoreApplication::applicationDirPath() + "/resources.rcc";
|
||||
#endif
|
||||
if (!QFile::exists(resourcesBinaryFile)) {
|
||||
throw std::runtime_error("Unable to find primary resources");
|
||||
}
|
||||
if (!QResource::registerResource(resourcesBinaryFile)) {
|
||||
throw std::runtime_error("Unable to load primary resources");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
Setting::init();
|
||||
|
||||
// Tell the plugin manager about our statically linked plugins
|
||||
|
@ -632,15 +693,16 @@ bool setupEssentials(int& argc, char** argv, bool runningMarkerExisted) {
|
|||
DependencyManager::set<PointerScriptingInterface>();
|
||||
DependencyManager::set<PickScriptingInterface>();
|
||||
DependencyManager::set<Cursor::Manager>();
|
||||
DependencyManager::set<DesktopPreviewProvider>();
|
||||
DependencyManager::set<AccountManager>(std::bind(&Application::getUserAgent, qApp));
|
||||
DependencyManager::set<StatTracker>();
|
||||
DependencyManager::set<ScriptEngines>(ScriptEngine::CLIENT_SCRIPT);
|
||||
DependencyManager::set<Preferences>();
|
||||
DependencyManager::set<recording::ClipCache>();
|
||||
DependencyManager::set<recording::Deck>();
|
||||
DependencyManager::set<recording::Recorder>();
|
||||
DependencyManager::set<AddressManager>();
|
||||
DependencyManager::set<NodeList>(NodeType::Agent, listenPort);
|
||||
DependencyManager::set<recording::ClipCache>();
|
||||
DependencyManager::set<GeometryCache>();
|
||||
DependencyManager::set<ModelCache>();
|
||||
DependencyManager::set<ScriptCache>();
|
||||
|
@ -729,8 +791,10 @@ OverlayID _keyboardFocusHighlightID{ UNKNOWN_OVERLAY_ID };
|
|||
//
|
||||
// So instead we create a new offscreen context to share with the QGLWidget,
|
||||
// and manually set THAT to be the shared context for the Chromium helper
|
||||
#if !defined(DISABLE_QML)
|
||||
OffscreenGLCanvas* _chromiumShareContext { nullptr };
|
||||
Q_GUI_EXPORT void qt_gl_set_global_share_context(QOpenGLContext *context);
|
||||
#endif
|
||||
|
||||
Setting::Handle<int> sessionRunTime{ "sessionRunTime", 0 };
|
||||
|
||||
|
@ -776,6 +840,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
|
|||
_sampleSound(nullptr)
|
||||
|
||||
{
|
||||
|
||||
auto steamClient = PluginManager::getInstance()->getSteamClientPlugin();
|
||||
setProperty(hifi::properties::STEAM, (steamClient && steamClient->isRunning()));
|
||||
setProperty(hifi::properties::CRASHED, _previousSessionCrashed);
|
||||
|
@ -996,8 +1061,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
|
|||
DependencyManager::get<AddressManager>().data(), &AddressManager::storeCurrentAddress);
|
||||
|
||||
// Inititalize sample before registering
|
||||
QFileInfo infSample = QFileInfo(PathUtils::resourcesPath() + "sounds/sample.wav");
|
||||
_sampleSound = DependencyManager::get<SoundCache>()->getSound(QUrl::fromLocalFile(infSample.absoluteFilePath()));
|
||||
_sampleSound = DependencyManager::get<SoundCache>()->getSound(PathUtils::resourcesUrl("sounds/sample.wav"));
|
||||
|
||||
auto scriptEngines = DependencyManager::get<ScriptEngines>().data();
|
||||
scriptEngines->registerScriptInitializer([this](ScriptEnginePointer engine){
|
||||
|
@ -1082,9 +1146,6 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
|
|||
// Make sure we don't time out during slow operations at startup
|
||||
updateHeartbeat();
|
||||
|
||||
// Now that OpenGL is initialized, we are sure we have a valid context and can create the various pipeline shaders with success.
|
||||
DependencyManager::get<GeometryCache>()->initializeShapePipelines();
|
||||
|
||||
// sessionRunTime will be reset soon by loadSettings. Grab it now to get previous session value.
|
||||
// The value will be 0 if the user blew away settings this session, which is both a feature and a bug.
|
||||
static const QString TESTER = "HIFI_TESTER";
|
||||
|
@ -1375,8 +1436,9 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
|
|||
userInputMapper->registerDevice(_touchscreenDevice->getInputDevice());
|
||||
}
|
||||
|
||||
// force the model the look at the correct directory (weird order of operations issue)
|
||||
scriptEngines->setScriptsLocation(scriptEngines->getScriptsLocation());
|
||||
// this will force the model the look at the correct directory (weird order of operations issue)
|
||||
scriptEngines->reloadLocalFiles();
|
||||
|
||||
// do this as late as possible so that all required subsystems are initialized
|
||||
// If we've overridden the default scripts location, just load default scripts
|
||||
// otherwise, load 'em all
|
||||
|
@ -1730,7 +1792,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
|
|||
static int lastCountOfNearbyAvatars = -1;
|
||||
QTimer* checkNearbyAvatarsTimer = new QTimer(this);
|
||||
checkNearbyAvatarsTimer->setInterval(CHECK_NEARBY_AVATARS_INTERVAL_MS); // 10 seconds, Qt::CoarseTimer ok
|
||||
connect(checkNearbyAvatarsTimer, &QTimer::timeout, this, [this]() {
|
||||
connect(checkNearbyAvatarsTimer, &QTimer::timeout, this, []() {
|
||||
auto avatarManager = DependencyManager::get<AvatarManager>();
|
||||
int nearbyAvatars = avatarManager->numberOfAvatarsInRange(avatarManager->getMyAvatar()->getWorldPosition(),
|
||||
NEARBY_AVATAR_RADIUS_METERS) - 1;
|
||||
|
@ -1769,9 +1831,11 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
|
|||
PROFILE_RANGE(render, "Process Default Skybox");
|
||||
auto textureCache = DependencyManager::get<TextureCache>();
|
||||
|
||||
auto skyboxUrl = PathUtils::resourcesPath().toStdString() + "images/Default-Sky-9-cubemap.ktx";
|
||||
QFileSelector fileSelector;
|
||||
fileSelector.setExtraSelectors(FileUtils::getFileSelectors());
|
||||
auto skyboxUrl = fileSelector.select(PathUtils::resourcesPath() + "images/Default-Sky-9-cubemap.ktx");
|
||||
|
||||
_defaultSkyboxTexture = gpu::Texture::unserialize(skyboxUrl);
|
||||
_defaultSkyboxTexture = gpu::Texture::unserialize(skyboxUrl.toStdString());
|
||||
_defaultSkyboxAmbientTexture = _defaultSkyboxTexture;
|
||||
|
||||
_defaultSkybox->setCubemap(_defaultSkyboxTexture);
|
||||
|
@ -1782,8 +1846,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
|
|||
return entityServerNode && !isPhysicsEnabled();
|
||||
});
|
||||
|
||||
QFileInfo infSnap = QFileInfo(PathUtils::resourcesPath() + "sounds/snap.wav");
|
||||
_snapshotSound = DependencyManager::get<SoundCache>()->getSound(QUrl::fromLocalFile(infSnap.absoluteFilePath()));
|
||||
_snapshotSound = DependencyManager::get<SoundCache>()->getSound(PathUtils::resourcesUrl("sounds/snap.wav"));
|
||||
|
||||
QVariant testProperty = property(hifi::properties::TEST);
|
||||
qDebug() << testProperty;
|
||||
|
@ -2181,11 +2244,16 @@ void Application::initializeGL() {
|
|||
}
|
||||
|
||||
_glWidget->makeCurrent();
|
||||
_chromiumShareContext = new OffscreenGLCanvas();
|
||||
_chromiumShareContext->setObjectName("ChromiumShareContext");
|
||||
_chromiumShareContext->create(_glWidget->qglContext());
|
||||
_chromiumShareContext->makeCurrent();
|
||||
qt_gl_set_global_share_context(_chromiumShareContext->getContext());
|
||||
|
||||
#if !defined(DISABLE_QML)
|
||||
if (!nsightActive()) {
|
||||
_chromiumShareContext = new OffscreenGLCanvas();
|
||||
_chromiumShareContext->setObjectName("ChromiumShareContext");
|
||||
_chromiumShareContext->create(_glWidget->qglContext());
|
||||
_chromiumShareContext->makeCurrent();
|
||||
qt_gl_set_global_share_context(_chromiumShareContext->getContext());
|
||||
}
|
||||
#endif
|
||||
|
||||
_glWidget->makeCurrent();
|
||||
gpu::Context::init<gpu::gl::GLBackend>();
|
||||
|
@ -2202,13 +2270,17 @@ void Application::initializeGL() {
|
|||
// Set up the render engine
|
||||
render::CullFunctor cullFunctor = LODManager::shouldRender;
|
||||
static const QString RENDER_FORWARD = "HIFI_RENDER_FORWARD";
|
||||
bool isDeferred = !QProcessEnvironment::systemEnvironment().contains(RENDER_FORWARD);
|
||||
_renderEngine->addJob<UpdateSceneTask>("UpdateScene");
|
||||
_renderEngine->addJob<SecondaryCameraRenderTask>("SecondaryCameraJob", cullFunctor);
|
||||
_renderEngine->addJob<RenderViewTask>("RenderMainView", cullFunctor, isDeferred);
|
||||
#ifndef Q_OS_ANDROID
|
||||
_renderEngine->addJob<SecondaryCameraRenderTask>("SecondaryCameraJob", cullFunctor, !DISABLE_DEFERRED);
|
||||
#endif
|
||||
_renderEngine->addJob<RenderViewTask>("RenderMainView", cullFunctor, !DISABLE_DEFERRED);
|
||||
_renderEngine->load();
|
||||
_renderEngine->registerScene(_main3DScene);
|
||||
|
||||
// Now that OpenGL is initialized, we are sure we have a valid context and can create the various pipeline shaders with success.
|
||||
DependencyManager::get<GeometryCache>()->initializeShapePipelines();
|
||||
|
||||
_offscreenContext = new OffscreenGLCanvas();
|
||||
_offscreenContext->setObjectName("MainThreadContext");
|
||||
_offscreenContext->create(_glWidget->qglContext());
|
||||
|
@ -2313,8 +2385,7 @@ void Application::initializeUi() {
|
|||
offscreenUi->setProxyWindow(_window->windowHandle());
|
||||
// OffscreenUi is a subclass of OffscreenQmlSurface specifically designed to
|
||||
// support the window management and scripting proxies for VR use
|
||||
offscreenUi->createDesktop(QString("hifi/Desktop.qml"));
|
||||
|
||||
offscreenUi->createDesktop(PathUtils::qmlUrl("hifi/Desktop.qml"));
|
||||
// FIXME either expose so that dialogs can set this themselves or
|
||||
// do better detection in the offscreen UI of what has focus
|
||||
offscreenUi->setNavigationFocused(false);
|
||||
|
@ -2653,7 +2724,8 @@ void Application::showHelp() {
|
|||
queryString.addQueryItem("defaultTab", defaultTab);
|
||||
auto tabletScriptingInterface = DependencyManager::get<TabletScriptingInterface>();
|
||||
TabletProxy* tablet = dynamic_cast<TabletProxy*>(tabletScriptingInterface->getTablet(SYSTEM_TABLET));
|
||||
tablet->gotoWebScreen(INFO_HELP_PATH + "?" + queryString.toString());
|
||||
tablet->gotoWebScreen(PathUtils::resourcesPath() + INFO_HELP_PATH + "?" + queryString.toString());
|
||||
DependencyManager::get<HMDScriptingInterface>()->openTablet();
|
||||
//InfoView::show(INFO_HELP_PATH, false, queryString.toString());
|
||||
}
|
||||
|
||||
|
@ -3909,12 +3981,18 @@ void Application::idle() {
|
|||
PROFILE_COUNTER_IF_CHANGED(app, "pendingProcessing", int, DependencyManager::get<StatTracker>()->getStat("PendingProcessing").toInt());
|
||||
auto renderConfig = _renderEngine->getConfiguration();
|
||||
PROFILE_COUNTER_IF_CHANGED(render, "gpuTime", float, (float)_gpuContext->getFrameTimerGPUAverage());
|
||||
auto opaqueRangeTimer = renderConfig->getConfig("OpaqueRangeTimer");
|
||||
auto linearDepth = renderConfig->getConfig("LinearDepth");
|
||||
auto surfaceGeometry = renderConfig->getConfig("SurfaceGeometry");
|
||||
auto renderDeferred = renderConfig->getConfig("RenderDeferred");
|
||||
auto toneAndPostRangeTimer = renderConfig->getConfig("ToneAndPostRangeTimer");
|
||||
|
||||
PROFILE_COUNTER(render_detail, "gpuTimes", {
|
||||
{ "OpaqueRangeTimer", renderConfig->getConfig("OpaqueRangeTimer")->property("gpuRunTime") },
|
||||
{ "LinearDepth", renderConfig->getConfig("LinearDepth")->property("gpuRunTime") },
|
||||
{ "SurfaceGeometry", renderConfig->getConfig("SurfaceGeometry")->property("gpuRunTime") },
|
||||
{ "RenderDeferred", renderConfig->getConfig("RenderDeferred")->property("gpuRunTime") },
|
||||
{ "ToneAndPostRangeTimer", renderConfig->getConfig("ToneAndPostRangeTimer")->property("gpuRunTime") }
|
||||
{ "OpaqueRangeTimer", opaqueRangeTimer ? opaqueRangeTimer->property("gpuRunTime") : 0 },
|
||||
{ "LinearDepth", linearDepth ? linearDepth->property("gpuRunTime") : 0 },
|
||||
{ "SurfaceGeometry", surfaceGeometry ? surfaceGeometry->property("gpuRunTime") : 0 },
|
||||
{ "RenderDeferred", renderDeferred ? renderDeferred->property("gpuRunTime") : 0 },
|
||||
{ "ToneAndPostRangeTimer", toneAndPostRangeTimer ? toneAndPostRangeTimer->property("gpuRunTime") : 0 }
|
||||
});
|
||||
|
||||
PROFILE_RANGE(app, __FUNCTION__);
|
||||
|
@ -4279,9 +4357,9 @@ void Application::init() {
|
|||
|
||||
// Make sure Login state is up to date
|
||||
DependencyManager::get<DialogsManager>()->toggleLoginDialog();
|
||||
|
||||
DependencyManager::get<DeferredLightingEffect>()->init();
|
||||
|
||||
if (!DISABLE_DEFERRED) {
|
||||
DependencyManager::get<DeferredLightingEffect>()->init();
|
||||
}
|
||||
DependencyManager::get<AvatarManager>()->init();
|
||||
|
||||
_timerStart.start();
|
||||
|
@ -5760,10 +5838,13 @@ void Application::registerScriptEngineWithApplicationServices(ScriptEnginePointe
|
|||
scriptEngine->registerGetterSetter("location", LocationScriptingInterface::locationGetter,
|
||||
LocationScriptingInterface::locationSetter);
|
||||
|
||||
#if !defined(Q_OS_ANDROID)
|
||||
scriptEngine->registerFunction("OverlayWebWindow", QmlWebWindowClass::constructor);
|
||||
#endif
|
||||
scriptEngine->registerFunction("OverlayWindow", QmlWindowClass::constructor);
|
||||
|
||||
scriptEngine->registerGlobalObject("Menu", MenuScriptingInterface::getInstance());
|
||||
scriptEngine->registerGlobalObject("DesktopPreviewProvider", DependencyManager::get<DesktopPreviewProvider>().data());
|
||||
scriptEngine->registerGlobalObject("Stats", Stats::getInstance());
|
||||
scriptEngine->registerGlobalObject("Settings", SettingsScriptingInterface::getInstance());
|
||||
scriptEngine->registerGlobalObject("Snapshot", DependencyManager::get<Snapshot>().data());
|
||||
|
|
|
@ -756,6 +756,13 @@ Menu::Menu() {
|
|||
// Developer > Stats
|
||||
addCheckableActionToQMenuAndActionHash(developerMenu, MenuOption::Stats);
|
||||
|
||||
// Developer > Advanced Settings...
|
||||
action = addActionToQMenuAndActionHash(developerMenu, "Advanced Preferences...");
|
||||
connect(action, &QAction::triggered, [] {
|
||||
qApp->showDialog(QString("hifi/dialogs/AdvancedPreferencesDialog.qml"),
|
||||
QString("hifi/tablet/AdvancedPreferencesDialog.qml"), "AdvancedPreferencesDialog");
|
||||
});
|
||||
|
||||
// Developer > API Debugger
|
||||
action = addActionToQMenuAndActionHash(developerMenu, "API Debugger");
|
||||
connect(action, &QAction::triggered, [] {
|
||||
|
|
|
@ -203,10 +203,14 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
void SecondaryCameraRenderTask::build(JobModel& task, const render::Varying& inputs, render::Varying& outputs, render::CullFunctor cullFunctor) {
|
||||
void SecondaryCameraRenderTask::build(JobModel& task, const render::Varying& inputs, render::Varying& outputs, render::CullFunctor cullFunctor, bool isDeferred) {
|
||||
const auto cachedArg = task.addJob<SecondaryCameraJob>("SecondaryCamera");
|
||||
const auto items = task.addJob<RenderFetchCullSortTask>("FetchCullSort", cullFunctor);
|
||||
assert(items.canCast<RenderFetchCullSortTask::Output>());
|
||||
task.addJob<RenderDeferredTask>("RenderDeferredTask", items);
|
||||
if (!isDeferred) {
|
||||
task.addJob<RenderForwardTask>("Forward", items);
|
||||
} else {
|
||||
task.addJob<RenderDeferredTask>("RenderDeferredTask", items);
|
||||
}
|
||||
task.addJob<EndSecondaryCameraFrame>("EndSecondaryCamera", cachedArg);
|
||||
}
|
|
@ -71,7 +71,7 @@ public:
|
|||
using JobModel = render::Task::Model<SecondaryCameraRenderTask, Config>;
|
||||
SecondaryCameraRenderTask() {}
|
||||
void configure(const Config& config) {}
|
||||
void build(JobModel& task, const render::Varying& inputs, render::Varying& outputs, render::CullFunctor cullFunctor);
|
||||
void build(JobModel& task, const render::Varying& inputs, render::Varying& outputs, render::CullFunctor cullFunctor, bool isDeferred = true);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1797,7 +1797,7 @@ void MyAvatar::initAnimGraph() {
|
|||
} else if (!_fstAnimGraphOverrideUrl.isEmpty()) {
|
||||
graphUrl = _fstAnimGraphOverrideUrl;
|
||||
} else {
|
||||
graphUrl = QUrl::fromLocalFile(PathUtils::resourcesPath() + "avatar/avatar-animation.json");
|
||||
graphUrl = PathUtils::resourcesUrl("avatar/avatar-animation.json");
|
||||
}
|
||||
|
||||
_skeletonModel->getRig().initAnimGraph(graphUrl);
|
||||
|
@ -2019,8 +2019,7 @@ void MyAvatar::updateOrientation(float deltaTime) {
|
|||
_smoothOrientationTimer = 0.0f;
|
||||
}
|
||||
|
||||
getHead()->setBasePitch(getHead()->getBasePitch() + getDriveKey(PITCH) * _pitchSpeed * deltaTime);
|
||||
|
||||
Head* head = getHead();
|
||||
auto headPose = getControllerPoseInAvatarFrame(controller::Action::HEAD);
|
||||
if (headPose.isValid()) {
|
||||
glm::quat localOrientation = headPose.rotation * Quaternions::Y_180;
|
||||
|
@ -2032,6 +2031,10 @@ void MyAvatar::updateOrientation(float deltaTime) {
|
|||
head->setBaseYaw(YAW(euler));
|
||||
head->setBasePitch(PITCH(euler));
|
||||
head->setBaseRoll(ROLL(euler));
|
||||
} else {
|
||||
head->setBaseYaw(0.0f);
|
||||
head->setBasePitch(getHead()->getBasePitch() + getDriveKey(PITCH) * _pitchSpeed * deltaTime);
|
||||
head->setBaseRoll(0.0f);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
#include "Ledger.h"
|
||||
#include "CommerceLogging.h"
|
||||
#include <NetworkingConstants.h>
|
||||
#include <AddressManager.h>
|
||||
|
||||
// inventory answers {status: 'success', data: {assets: [{id: "guid", title: "name", preview: "url"}....]}}
|
||||
// balance answers {status: 'success', data: {balance: integer}}
|
||||
|
@ -122,25 +123,30 @@ QString hfcString(const QJsonValue& sentValue, const QJsonValue& receivedValue)
|
|||
int sent = sentValue.toInt();
|
||||
int received = receivedValue.toInt();
|
||||
if (sent <= 0 && received <= 0) {
|
||||
return QString("-");
|
||||
return QString("0 HFC");
|
||||
}
|
||||
QString result;
|
||||
if (sent > 0) {
|
||||
result += QString("<font color='#B70A37'>-%1 HFC</font>").arg(sent);
|
||||
result += QString("<font color='#B70A37'><b>-%1 HFC</b></font>").arg(sent);
|
||||
if (received > 0) {
|
||||
result += QString("<br>");
|
||||
}
|
||||
}
|
||||
if (received > 0) {
|
||||
result += QString("<font color='#3AA38F'>%1 HFC</font>").arg(received);
|
||||
result += QString("<font color='#3AA38F'><b>%1 HFC</b></font>").arg(received);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
static const QString USER_PAGE_BASE_URL = NetworkingConstants::METAVERSE_SERVER_URL().toString() + "/users/";
|
||||
static const QString PLACE_PAGE_BASE_URL = NetworkingConstants::METAVERSE_SERVER_URL().toString() + "/places/";
|
||||
static const QStringList KNOWN_USERS(QStringList() << "highfidelity" << "marketplace");
|
||||
QString userLink(const QString& username) {
|
||||
QString userLink(const QString& username, const QString& placename) {
|
||||
if (username.isEmpty()) {
|
||||
return QString("someone");
|
||||
if (placename.isEmpty()) {
|
||||
return QString("someone");
|
||||
} else {
|
||||
return QString("someone <a href=\"%1%2\">nearby</a>").arg(PLACE_PAGE_BASE_URL, placename);
|
||||
}
|
||||
}
|
||||
if (KNOWN_USERS.contains(username)) {
|
||||
return username;
|
||||
|
@ -157,13 +163,13 @@ QString transactionString(const QJsonObject& valueObject) {
|
|||
QDateTime createdAt(QDateTime::fromSecsSinceEpoch(dateInteger, Qt::UTC));
|
||||
QString result;
|
||||
|
||||
if (sentCerts <= 0 && receivedCerts <= 0) {
|
||||
if (sentCerts <= 0 && receivedCerts <= 0 && !KNOWN_USERS.contains(valueObject["sender_name"].toString())) {
|
||||
// this is an hfc transfer.
|
||||
if (sent > 0) {
|
||||
QString recipient = userLink(valueObject["recipient_name"].toString());
|
||||
QString recipient = userLink(valueObject["recipient_name"].toString(), valueObject["place_name"].toString());
|
||||
result += QString("Money sent to %1").arg(recipient);
|
||||
} else {
|
||||
QString sender = userLink(valueObject["sender_name"].toString());
|
||||
QString sender = userLink(valueObject["sender_name"].toString(), valueObject["place_name"].toString());
|
||||
result += QString("Money from %1").arg(sender);
|
||||
}
|
||||
if (!message.isEmpty()) {
|
||||
|
@ -172,8 +178,8 @@ QString transactionString(const QJsonObject& valueObject) {
|
|||
} else {
|
||||
result += valueObject["message"].toString();
|
||||
}
|
||||
|
||||
// no matter what we append a smaller date to the bottom of this...
|
||||
|
||||
result += QString("<br><font size='-2' color='#1080B8'>%1").arg(createdAt.toLocalTime().toString(Qt::DefaultLocaleShortDate));
|
||||
return result;
|
||||
}
|
||||
|
@ -314,6 +320,7 @@ void Ledger::transferHfcToNode(const QString& hfc_key, const QString& nodeID, co
|
|||
transaction["node_id"] = nodeID;
|
||||
transaction["quantity"] = amount;
|
||||
transaction["message"] = optionalMessage;
|
||||
transaction["place_name"] = DependencyManager::get<AddressManager>()->getPlaceName();
|
||||
QJsonDocument transactionDoc{ transaction };
|
||||
auto transactionString = transactionDoc.toJson(QJsonDocument::Compact);
|
||||
signedSend("transaction", transactionString, hfc_key, "transfer_hfc_to_node", "transferHfcToNodeSuccess", "transferHfcToNodeFailure");
|
||||
|
|
|
@ -591,8 +591,8 @@ void Wallet::chooseSecurityImage(const QString& filename) {
|
|||
if (_securityImage) {
|
||||
delete _securityImage;
|
||||
}
|
||||
QString path = qApp->applicationDirPath();
|
||||
path.append("/resources/qml/hifi/commerce/wallet/");
|
||||
QString path = PathUtils::resourcesPath();
|
||||
path.append("/qml/hifi/commerce/wallet/");
|
||||
path.append(filename);
|
||||
|
||||
// now create a new security image pixmap
|
||||
|
|
|
@ -20,7 +20,6 @@
|
|||
#include <QTranslator>
|
||||
|
||||
#include <BuildInfo.h>
|
||||
#include <gl/OpenGLVersionChecker.h>
|
||||
#include <SandboxUtils.h>
|
||||
#include <SharedUtil.h>
|
||||
#include <NetworkAccessManager.h>
|
||||
|
@ -53,6 +52,14 @@ int main(int argc, const char* argv[]) {
|
|||
QApplication::setAttribute(Qt::AA_DontUseNativeMenuBar);
|
||||
#endif
|
||||
|
||||
#if defined(USE_GLES) && defined(Q_OS_WIN)
|
||||
// When using GLES on Windows, we can't create normal GL context in Qt, so
|
||||
// we force Qt to use angle. This will cause the QML to be unable to be used
|
||||
// in the output window, so QML should be disabled.
|
||||
qputenv("QT_ANGLE_PLATFORM", "d3d11");
|
||||
QCoreApplication::setAttribute(Qt::AA_UseOpenGLES);
|
||||
#endif
|
||||
|
||||
disableQtBearerPoll(); // Fixes wifi ping spikes
|
||||
|
||||
QElapsedTimer startupTime;
|
||||
|
|
|
@ -44,7 +44,7 @@ OverlayID StylusPointer::buildStylusOverlay(const QVariantMap& properties) {
|
|||
QVariantMap overlayProperties;
|
||||
// TODO: make these configurable per pointer
|
||||
overlayProperties["name"] = "stylus";
|
||||
overlayProperties["url"] = PathUtils::resourcesPath() + "/meshes/tablet-stylus-fat.fbx";
|
||||
overlayProperties["url"] = PathUtils::resourcesUrl() + "/meshes/tablet-stylus-fat.fbx";
|
||||
overlayProperties["loadPriority"] = 10.0f;
|
||||
overlayProperties["solid"] = true;
|
||||
overlayProperties["visible"] = false;
|
||||
|
|
|
@ -39,8 +39,7 @@ AssetMappingsScriptingInterface::AssetMappingsScriptingInterface() {
|
|||
void AssetMappingsScriptingInterface::setMapping(QString path, QString hash, QJSValue callback) {
|
||||
auto assetClient = DependencyManager::get<AssetClient>();
|
||||
auto request = assetClient->createSetMappingRequest(path, hash);
|
||||
|
||||
connect(request, &SetMappingRequest::finished, this, [this, callback](SetMappingRequest* request) mutable {
|
||||
connect(request, &SetMappingRequest::finished, this, [callback](SetMappingRequest* request) mutable {
|
||||
if (callback.isCallable()) {
|
||||
QJSValueList args { request->getErrorString(), request->getPath() };
|
||||
callback.call(args);
|
||||
|
@ -48,15 +47,13 @@ void AssetMappingsScriptingInterface::setMapping(QString path, QString hash, QJS
|
|||
|
||||
request->deleteLater();
|
||||
});
|
||||
|
||||
request->start();
|
||||
}
|
||||
|
||||
void AssetMappingsScriptingInterface::getMapping(QString path, QJSValue callback) {
|
||||
auto assetClient = DependencyManager::get<AssetClient>();
|
||||
auto request = assetClient->createGetMappingRequest(path);
|
||||
|
||||
connect(request, &GetMappingRequest::finished, this, [this, callback](GetMappingRequest* request) mutable {
|
||||
connect(request, &GetMappingRequest::finished, this, [callback](GetMappingRequest* request) mutable {
|
||||
auto hash = request->getHash();
|
||||
|
||||
if (callback.isCallable()) {
|
||||
|
|
|
@ -12,9 +12,11 @@
|
|||
#ifndef hifi_LimitlessConnection_h
|
||||
#define hifi_LimitlessConnection_h
|
||||
|
||||
#include <QtCore/QObject>
|
||||
#include <QtCore/QFuture>
|
||||
#include <QtNetwork/QTcpSocket>
|
||||
|
||||
#include <AudioClient.h>
|
||||
#include <QObject>
|
||||
#include <QFuture>
|
||||
|
||||
class LimitlessConnection : public QObject {
|
||||
Q_OBJECT
|
||||
|
|
|
@ -277,7 +277,8 @@ void WindowScriptingInterface::browseAsync(const QString& title, const QString&
|
|||
if (!result.isEmpty()) {
|
||||
setPreviousBrowseLocation(QFileInfo(result).absolutePath());
|
||||
}
|
||||
emit openFileChanged(result);
|
||||
emit browseChanged(result);
|
||||
emit openFileChanged(result); // Deprecated signal; to be removed in due course.
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -390,6 +391,10 @@ QString WindowScriptingInterface::checkVersion() {
|
|||
return QCoreApplication::applicationVersion();
|
||||
}
|
||||
|
||||
QString WindowScriptingInterface::protocolSignature() {
|
||||
return protocolVersionsSignatureBase64();
|
||||
}
|
||||
|
||||
int WindowScriptingInterface::getInnerWidth() {
|
||||
return qApp->getDeviceSize().x;
|
||||
}
|
||||
|
|
|
@ -197,18 +197,19 @@ public slots:
|
|||
|
||||
/**jsdoc
|
||||
* Prompt the user to choose a file. Displays a non-modal dialog that navigates the directory tree. A
|
||||
* {@link Window.openFileChanged|openFileChanged} signal is emitted when a file is chosen; no signal is emitted if the user
|
||||
* {@link Window.browseChanged|browseChanged} signal is emitted when a file is chosen; no signal is emitted if the user
|
||||
* cancels the dialog.
|
||||
* @deprecated A deprecated {@link Window.openFileChanged|openFileChanged} signal is also emitted when a file is chosen.
|
||||
* @function Window.browseAsync
|
||||
* @param {string} title="" - The title to display at the top of the dialog.
|
||||
* @param {string} directory="" - The initial directory to start browsing at.
|
||||
* @param {string} nameFilter="" - The types of files to display. Examples: <code>"*.json"</code> and
|
||||
* <code>"Images (*.png *.jpg *.svg)"</code>. All files are displayed if a filter isn't specified.
|
||||
* @example <caption>Ask the user to choose an image file without waiting for the answer.</caption>
|
||||
* function onOpenFileChanged(filename) {
|
||||
* function onBrowseChanged(filename) {
|
||||
* print("File: " + filename);
|
||||
* }
|
||||
* Window.openFileChanged.connect(onOpenFileChanged);
|
||||
* Window.browseChanged.connect(onBrowseChanged);
|
||||
*
|
||||
* Window.browseAsync("Select Image File", Paths.resources, "Images (*.png *.jpg *.svg)");
|
||||
* print("Script continues without waiting");
|
||||
|
@ -305,6 +306,13 @@ public slots:
|
|||
*/
|
||||
QString checkVersion();
|
||||
|
||||
/**jsdoc
|
||||
* Get the signature for Interface's protocol version.
|
||||
* @function Window.protocolSignature
|
||||
* @returns {string} A string uniquely identifying the version of the metaverse protocol that Interface is using.
|
||||
*/
|
||||
QString protocolSignature();
|
||||
|
||||
/**jsdoc
|
||||
* Copies text to the operating system's clipboard.
|
||||
* @function Window.copyToClipboard
|
||||
|
@ -652,9 +660,18 @@ signals:
|
|||
*/
|
||||
void saveFileChanged(QString filename);
|
||||
|
||||
/**jsdoc
|
||||
* Triggered when the user chooses a file in a {@link Window.browseAsync|browseAsync} dialog.
|
||||
* @function Window.browseChanged
|
||||
* @param {string} filename - The path and name of the file the user chose in the dialog.
|
||||
* @returns {Signal}
|
||||
*/
|
||||
void browseChanged(QString filename);
|
||||
|
||||
/**jsdoc
|
||||
* Triggered when the user chooses a file in a {@link Window.browseAsync|browseAsync} dialog.
|
||||
* @function Window.openFileChanged
|
||||
* @deprecated This signal is being replaced with {@link Window.browseChanged|browseChanged} and will be removed.
|
||||
* @param {string} filename - The path and name of the file the user chose in the dialog.
|
||||
* @returns {Signal}
|
||||
*/
|
||||
|
|
|
@ -9,6 +9,8 @@
|
|||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include "ApplicationOverlay.h"
|
||||
|
||||
#include <glm/gtc/type_ptr.hpp>
|
||||
|
||||
#include <avatar/AvatarManager.h>
|
||||
|
@ -17,12 +19,10 @@
|
|||
#include <OffscreenUi.h>
|
||||
#include <CursorManager.h>
|
||||
#include <PerfStat.h>
|
||||
#include <gl/Config.h>
|
||||
|
||||
#include "AudioClient.h"
|
||||
#include "audio/AudioScope.h"
|
||||
#include "Application.h"
|
||||
#include "ApplicationOverlay.h"
|
||||
|
||||
#include "Util.h"
|
||||
#include "ui/Stats.h"
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#define hifi_ApplicationOverlay_h
|
||||
|
||||
#include <gpu/Texture.h>
|
||||
#include <render/Args.h>
|
||||
|
||||
|
||||
// Handles the drawing of the overlays to the screen
|
||||
|
|
|
@ -82,19 +82,42 @@ void setupPreferences() {
|
|||
preference->setMax(500);
|
||||
preferences->addPreference(preference);
|
||||
}
|
||||
{
|
||||
auto getter = []()->float { return qApp->getDesktopTabletScale(); };
|
||||
auto setter = [](float value) { qApp->setDesktopTabletScale(value); };
|
||||
auto preference = new SpinnerPreference(UI_CATEGORY, "Desktop Tablet Scale %", getter, setter);
|
||||
preference->setMin(20);
|
||||
preference->setMax(500);
|
||||
preferences->addPreference(preference);
|
||||
}
|
||||
|
||||
|
||||
{
|
||||
auto getter = []()->bool { return qApp->getPreferStylusOverLaser(); };
|
||||
auto setter = [](bool value) { qApp->setPreferStylusOverLaser(value); };
|
||||
preferences->addPreference(new CheckPreference(UI_CATEGORY, "Prefer Stylus Over Laser", getter, setter));
|
||||
}
|
||||
|
||||
static const QString ADVANCED_UI_CATEGORY { "Advanced UI" };
|
||||
{
|
||||
auto getter = []()->float { return qApp->getDesktopTabletScale(); };
|
||||
auto setter = [](float value) { qApp->setDesktopTabletScale(value); };
|
||||
auto preference = new SpinnerPreference(ADVANCED_UI_CATEGORY, "Desktop Tablet Scale %", getter, setter);
|
||||
preference->setMin(20);
|
||||
preference->setMax(500);
|
||||
preferences->addPreference(preference);
|
||||
}
|
||||
{
|
||||
auto getter = [=]()->float { return myAvatar->getRealWorldFieldOfView(); };
|
||||
auto setter = [=](float value) { myAvatar->setRealWorldFieldOfView(value); };
|
||||
auto preference = new SpinnerPreference(ADVANCED_UI_CATEGORY, "Real world vertical field of view (angular size of monitor)", getter, setter);
|
||||
preference->setMin(1);
|
||||
preference->setMax(180);
|
||||
preferences->addPreference(preference);
|
||||
}
|
||||
{
|
||||
auto getter = []()->float { return qApp->getFieldOfView(); };
|
||||
auto setter = [](float value) { qApp->setFieldOfView(value); };
|
||||
auto preference = new SpinnerPreference(ADVANCED_UI_CATEGORY, "Vertical field of view", getter, setter);
|
||||
preference->setMin(1);
|
||||
preference->setMax(180);
|
||||
preference->setStep(1);
|
||||
preferences->addPreference(preference);
|
||||
}
|
||||
|
||||
|
||||
// FIXME: Remove setting completely or make available through JavaScript API?
|
||||
/*
|
||||
{
|
||||
|
@ -128,21 +151,13 @@ void setupPreferences() {
|
|||
preferences->addPreference(preference);
|
||||
}
|
||||
|
||||
// Scripts
|
||||
{
|
||||
auto getter = []()->QString { return DependencyManager::get<ScriptEngines>()->getScriptsLocation(); };
|
||||
auto setter = [](const QString& value) { DependencyManager::get<ScriptEngines>()->setScriptsLocation(value); };
|
||||
preferences->addPreference(new BrowsePreference("Scripts", "Load scripts from this directory", getter, setter));
|
||||
}
|
||||
|
||||
preferences->addPreference(new ButtonPreference("Scripts", "Load Default Scripts", [] {
|
||||
DependencyManager::get<ScriptEngines>()->loadDefaultScripts();
|
||||
}));
|
||||
|
||||
{
|
||||
auto getter = []()->bool { return !Menu::getInstance()->isOptionChecked(MenuOption::DisableActivityLogger); };
|
||||
auto setter = [](bool value) { Menu::getInstance()->setIsOptionChecked(MenuOption::DisableActivityLogger, !value); };
|
||||
preferences->addPreference(new CheckPreference("Privacy", "Send data", getter, setter));
|
||||
preferences->addPreference(new CheckPreference("Privacy", "Send data - High Fidelity uses information provided by your "
|
||||
"client to improve the product through the logging of errors, tracking of usage patterns, "
|
||||
"installation and system details, and crash events. By allowing High Fidelity to collect "
|
||||
"this information you are helping to improve the product. ", getter, setter));
|
||||
}
|
||||
|
||||
static const QString LOD_TUNING("Level of Detail Tuning");
|
||||
|
@ -167,23 +182,6 @@ void setupPreferences() {
|
|||
}
|
||||
|
||||
static const QString AVATAR_TUNING { "Avatar Tuning" };
|
||||
{
|
||||
auto getter = [=]()->float { return myAvatar->getRealWorldFieldOfView(); };
|
||||
auto setter = [=](float value) { myAvatar->setRealWorldFieldOfView(value); };
|
||||
auto preference = new SpinnerPreference(AVATAR_TUNING, "Real world vertical field of view (angular size of monitor)", getter, setter);
|
||||
preference->setMin(1);
|
||||
preference->setMax(180);
|
||||
preferences->addPreference(preference);
|
||||
}
|
||||
{
|
||||
auto getter = []()->float { return qApp->getFieldOfView(); };
|
||||
auto setter = [](float value) { qApp->setFieldOfView(value); };
|
||||
auto preference = new SpinnerPreference(AVATAR_TUNING, "Vertical field of view", getter, setter);
|
||||
preference->setMin(1);
|
||||
preference->setMax(180);
|
||||
preference->setStep(1);
|
||||
preferences->addPreference(preference);
|
||||
}
|
||||
{
|
||||
auto getter = [=]()->QString { return myAvatar->getDominantHand(); };
|
||||
auto setter = [=](const QString& value) { myAvatar->setDominantHand(value); };
|
||||
|
@ -297,26 +295,6 @@ void setupPreferences() {
|
|||
}
|
||||
#endif
|
||||
|
||||
{
|
||||
auto getter = []()->float { return qApp->getMaxOctreePacketsPerSecond(); };
|
||||
auto setter = [](float value) { qApp->setMaxOctreePacketsPerSecond(value); };
|
||||
auto preference = new SpinnerPreference("Octree", "Max packets sent each second", getter, setter);
|
||||
preference->setMin(60);
|
||||
preference->setMax(6000);
|
||||
preference->setStep(10);
|
||||
preferences->addPreference(preference);
|
||||
}
|
||||
|
||||
|
||||
{
|
||||
auto getter = []()->float { return qApp->getApplicationCompositor().getHmdUIAngularSize(); };
|
||||
auto setter = [](float value) { qApp->getApplicationCompositor().setHmdUIAngularSize(value); };
|
||||
auto preference = new SpinnerPreference("HMD", "UI horizontal angular size (degrees)", getter, setter);
|
||||
preference->setMin(30);
|
||||
preference->setMax(160);
|
||||
preference->setStep(1);
|
||||
preferences->addPreference(preference);
|
||||
}
|
||||
|
||||
{
|
||||
static const QString RENDER("Graphics");
|
||||
|
@ -342,7 +320,7 @@ void setupPreferences() {
|
|||
}
|
||||
}
|
||||
{
|
||||
static const QString RENDER("Networking");
|
||||
static const QString NETWORKING("Networking");
|
||||
|
||||
auto nodelist = DependencyManager::get<NodeList>();
|
||||
{
|
||||
|
@ -350,10 +328,21 @@ void setupPreferences() {
|
|||
static const int MAX_PORT_NUMBER { 65535 };
|
||||
auto getter = [nodelist] { return static_cast<int>(nodelist->getSocketLocalPort()); };
|
||||
auto setter = [nodelist](int preset) { nodelist->setSocketLocalPort(static_cast<quint16>(preset)); };
|
||||
auto preference = new IntSpinnerPreference(RENDER, "Listening Port", getter, setter);
|
||||
auto preference = new IntSpinnerPreference(NETWORKING, "Listening Port", getter, setter);
|
||||
preference->setMin(MIN_PORT_NUMBER);
|
||||
preference->setMax(MAX_PORT_NUMBER);
|
||||
preferences->addPreference(preference);
|
||||
}
|
||||
|
||||
{
|
||||
auto getter = []()->float { return qApp->getMaxOctreePacketsPerSecond(); };
|
||||
auto setter = [](float value) { qApp->setMaxOctreePacketsPerSecond(value); };
|
||||
auto preference = new SpinnerPreference(NETWORKING, "Max entities packets sent each second", getter, setter);
|
||||
preference->setMin(60);
|
||||
preference->setMax(6000);
|
||||
preference->setStep(10);
|
||||
preferences->addPreference(preference);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,10 +10,9 @@
|
|||
|
||||
#include "ResourceImageItem.h"
|
||||
|
||||
#include <gl/Config.h>
|
||||
|
||||
#include <QOpenGLFramebufferObjectFormat>
|
||||
#include <QOpenGLFunctions>
|
||||
#include <QOpenGLExtraFunctions>
|
||||
#include <QOpenGLContext>
|
||||
|
||||
#include <plugins/DisplayPlugin.h>
|
||||
|
||||
|
@ -89,11 +88,9 @@ QOpenGLFramebufferObject* ResourceImageItemRenderer::createFramebufferObject(con
|
|||
}
|
||||
|
||||
void ResourceImageItemRenderer::render() {
|
||||
auto f = QOpenGLContext::currentContext()->extraFunctions();
|
||||
|
||||
if (_fenceSync) {
|
||||
f->glWaitSync(_fenceSync, 0, GL_TIMEOUT_IGNORED);
|
||||
f->glDeleteSync(_fenceSync);
|
||||
glWaitSync(_fenceSync, 0, GL_TIMEOUT_IGNORED);
|
||||
glDeleteSync(_fenceSync);
|
||||
_fenceSync = 0;
|
||||
}
|
||||
if (_ready) {
|
||||
|
|
|
@ -14,6 +14,8 @@
|
|||
|
||||
#include "Application.h"
|
||||
|
||||
#include <gl/Config.h>
|
||||
|
||||
#include <QQuickFramebufferObject>
|
||||
#include <QQuickWindow>
|
||||
#include <QTimer>
|
||||
|
|
|
@ -42,8 +42,9 @@ using namespace std;
|
|||
|
||||
static Stats* INSTANCE{ nullptr };
|
||||
|
||||
#if !defined (Q_OS_ANDROID)
|
||||
QString getTextureMemoryPressureModeString();
|
||||
|
||||
#endif
|
||||
Stats* Stats::getInstance() {
|
||||
if (!INSTANCE) {
|
||||
Stats::registerType();
|
||||
|
@ -359,7 +360,9 @@ void Stats::updateStats(bool force) {
|
|||
STAT_UPDATE(gpuTextureResourceMemory, (int)BYTES_TO_MB(gpu::Context::getTextureResourceGPUMemSize()));
|
||||
STAT_UPDATE(gpuTextureResourcePopulatedMemory, (int)BYTES_TO_MB(gpu::Context::getTextureResourcePopulatedGPUMemSize()));
|
||||
STAT_UPDATE(gpuTextureExternalMemory, (int)BYTES_TO_MB(gpu::Context::getTextureExternalGPUMemSize()));
|
||||
#if !defined(Q_OS_ANDROID)
|
||||
STAT_UPDATE(gpuTextureMemoryPressureState, getTextureMemoryPressureModeString());
|
||||
#endif
|
||||
STAT_UPDATE(gpuFreeMemory, (int)BYTES_TO_MB(gpu::Context::getFreeGPUMemSize()));
|
||||
STAT_UPDATE(rectifiedTextureCount, (int)RECTIFIED_TEXTURE_COUNT.load());
|
||||
STAT_UPDATE(decimatedTextureCount, (int)DECIMATED_TEXTURE_COUNT.load());
|
||||
|
|
|
@ -564,9 +564,9 @@ void ModelOverlay::animate() {
|
|||
rotationMat * fbxJoints[index].postTransform);
|
||||
auto& jointData = jointsData[j];
|
||||
jointData.translation = extractTranslation(finalMat);
|
||||
jointData.translationSet = true;
|
||||
jointData.translationIsDefaultPose = false;
|
||||
jointData.rotation = glmExtractRotation(finalMat);
|
||||
jointData.rotationSet = true;
|
||||
jointData.rotationIsDefaultPose = false;
|
||||
}
|
||||
}
|
||||
// Set the data in the model
|
||||
|
|
|
@ -1705,16 +1705,16 @@ void Rig::copyJointsIntoJointData(QVector<JointData>& jointDataVec) const {
|
|||
// rotations are in absolute rig frame.
|
||||
glm::quat defaultAbsRot = geometryToRigPose.rot() * _animSkeleton->getAbsoluteDefaultPose(i).rot();
|
||||
data.rotation = _internalPoseSet._absolutePoses[i].rot();
|
||||
data.rotationSet = !isEqual(data.rotation, defaultAbsRot);
|
||||
data.rotationIsDefaultPose = isEqual(data.rotation, defaultAbsRot);
|
||||
|
||||
// translations are in relative frame but scaled so that they are in meters,
|
||||
// instead of geometry units.
|
||||
glm::vec3 defaultRelTrans = _geometryOffset.scale() * _animSkeleton->getRelativeDefaultPose(i).trans();
|
||||
data.translation = _geometryOffset.scale() * _internalPoseSet._relativePoses[i].trans();
|
||||
data.translationSet = !isEqual(data.translation, defaultRelTrans);
|
||||
data.translationIsDefaultPose = isEqual(data.translation, defaultRelTrans);
|
||||
} else {
|
||||
data.translationSet = false;
|
||||
data.rotationSet = false;
|
||||
data.translationIsDefaultPose = true;
|
||||
data.rotationIsDefaultPose = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1739,11 +1739,11 @@ void Rig::copyJointsFromJointData(const QVector<JointData>& jointDataVec) {
|
|||
const glm::quat rigToGeometryRot(glmExtractRotation(_rigToGeometryTransform));
|
||||
for (int i = 0; i < numJoints; i++) {
|
||||
const JointData& data = jointDataVec.at(i);
|
||||
if (data.rotationSet) {
|
||||
if (data.rotationIsDefaultPose) {
|
||||
rotations.push_back(absoluteDefaultPoses[i].rot());
|
||||
} else {
|
||||
// JointData rotations are in absolute rig-frame so we rotate them to absolute geometry-frame
|
||||
rotations.push_back(rigToGeometryRot * data.rotation);
|
||||
} else {
|
||||
rotations.push_back(absoluteDefaultPoses[i].rot());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1759,11 +1759,11 @@ void Rig::copyJointsFromJointData(const QVector<JointData>& jointDataVec) {
|
|||
const JointData& data = jointDataVec.at(i);
|
||||
_internalPoseSet._relativePoses[i].scale() = Vectors::ONE;
|
||||
_internalPoseSet._relativePoses[i].rot() = rotations[i];
|
||||
if (data.translationSet) {
|
||||
if (data.translationIsDefaultPose) {
|
||||
_internalPoseSet._relativePoses[i].trans() = relativeDefaultPoses[i].trans();
|
||||
} else {
|
||||
// JointData translations are in scaled relative-frame so we scale back to regular relative-frame
|
||||
_internalPoseSet._relativePoses[i].trans() = _invGeometryOffset.scale() * data.translation;
|
||||
} else {
|
||||
_internalPoseSet._relativePoses[i].trans() = relativeDefaultPoses[i].trans();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -427,28 +427,11 @@ AudioInjectorPointer AudioInjector::playSound(SharedSoundPointer sound, const fl
|
|||
options.stereo = sound->isStereo();
|
||||
options.position = position;
|
||||
options.volume = volume;
|
||||
options.pitch = 1.0f / stretchFactor;
|
||||
|
||||
QByteArray samples = sound->getByteArray();
|
||||
if (stretchFactor == 1.0f) {
|
||||
return playSoundAndDelete(samples, options);
|
||||
}
|
||||
|
||||
const int standardRate = AudioConstants::SAMPLE_RATE;
|
||||
const int resampledRate = standardRate * stretchFactor;
|
||||
const int channelCount = sound->isStereo() ? 2 : 1;
|
||||
|
||||
AudioSRC resampler(standardRate, resampledRate, channelCount);
|
||||
|
||||
const int nInputFrames = samples.size() / (channelCount * sizeof(int16_t));
|
||||
const int maxOutputFrames = resampler.getMaxOutput(nInputFrames);
|
||||
QByteArray resampled(maxOutputFrames * channelCount * sizeof(int16_t), '\0');
|
||||
|
||||
int nOutputFrames = resampler.render(reinterpret_cast<const int16_t*>(samples.data()),
|
||||
reinterpret_cast<int16_t*>(resampled.data()),
|
||||
nInputFrames);
|
||||
|
||||
Q_UNUSED(nOutputFrames);
|
||||
return playSoundAndDelete(resampled, options);
|
||||
return playSoundAndDelete(samples, options);
|
||||
}
|
||||
|
||||
AudioInjectorPointer AudioInjector::playSoundAndDelete(const QByteArray& buffer, const AudioInjectorOptions options) {
|
||||
|
@ -461,12 +444,40 @@ AudioInjectorPointer AudioInjector::playSoundAndDelete(const QByteArray& buffer,
|
|||
return sound;
|
||||
}
|
||||
|
||||
|
||||
AudioInjectorPointer AudioInjector::playSound(const QByteArray& buffer, const AudioInjectorOptions options) {
|
||||
AudioInjectorPointer injector = AudioInjectorPointer::create(buffer, options);
|
||||
|
||||
if (!injector->inject(&AudioInjectorManager::threadInjector)) {
|
||||
qWarning() << "AudioInjector::playSound failed to thread injector";
|
||||
if (options.pitch == 1.0f) {
|
||||
|
||||
AudioInjectorPointer injector = AudioInjectorPointer::create(buffer, options);
|
||||
|
||||
if (!injector->inject(&AudioInjectorManager::threadInjector)) {
|
||||
qWarning() << "AudioInjector::playSound failed to thread injector";
|
||||
}
|
||||
return injector;
|
||||
|
||||
} else {
|
||||
|
||||
const int standardRate = AudioConstants::SAMPLE_RATE;
|
||||
const int resampledRate = AudioConstants::SAMPLE_RATE / glm::clamp(options.pitch, 1/16.0f, 16.0f); // limit to 4 octaves
|
||||
const int numChannels = options.ambisonic ? AudioConstants::AMBISONIC :
|
||||
(options.stereo ? AudioConstants::STEREO : AudioConstants::MONO);
|
||||
|
||||
AudioSRC resampler(standardRate, resampledRate, numChannels);
|
||||
|
||||
// create a resampled buffer that is guaranteed to be large enough
|
||||
const int nInputFrames = buffer.size() / (numChannels * sizeof(int16_t));
|
||||
const int maxOutputFrames = resampler.getMaxOutput(nInputFrames);
|
||||
QByteArray resampledBuffer(maxOutputFrames * numChannels * sizeof(int16_t), '\0');
|
||||
|
||||
resampler.render(reinterpret_cast<const int16_t*>(buffer.data()),
|
||||
reinterpret_cast<int16_t*>(resampledBuffer.data()),
|
||||
nInputFrames);
|
||||
|
||||
AudioInjectorPointer injector = AudioInjectorPointer::create(resampledBuffer, options);
|
||||
|
||||
if (!injector->inject(&AudioInjectorManager::threadInjector)) {
|
||||
qWarning() << "AudioInjector::playSound failed to thread pitch-shifted injector";
|
||||
}
|
||||
return injector;
|
||||
}
|
||||
return injector;
|
||||
}
|
||||
|
|
|
@ -26,7 +26,8 @@ AudioInjectorOptions::AudioInjectorOptions() :
|
|||
ambisonic(false),
|
||||
ignorePenumbra(false),
|
||||
localOnly(false),
|
||||
secondOffset(0.0f)
|
||||
secondOffset(0.0f),
|
||||
pitch(1.0f)
|
||||
{
|
||||
|
||||
}
|
||||
|
@ -40,6 +41,7 @@ QScriptValue injectorOptionsToScriptValue(QScriptEngine* engine, const AudioInje
|
|||
obj.setProperty("ignorePenumbra", injectorOptions.ignorePenumbra);
|
||||
obj.setProperty("localOnly", injectorOptions.localOnly);
|
||||
obj.setProperty("secondOffset", injectorOptions.secondOffset);
|
||||
obj.setProperty("pitch", injectorOptions.pitch);
|
||||
return obj;
|
||||
}
|
||||
|
||||
|
@ -87,6 +89,12 @@ void injectorOptionsFromScriptValue(const QScriptValue& object, AudioInjectorOpt
|
|||
} else {
|
||||
qCWarning(audio) << "Audio injector options: secondOffset is not a number";
|
||||
}
|
||||
} else if (it.name() == "pitch") {
|
||||
if (it.value().isNumber()) {
|
||||
injectorOptions.pitch = it.value().toNumber();
|
||||
} else {
|
||||
qCWarning(audio) << "Audio injector options: pitch is not a number";
|
||||
}
|
||||
} else {
|
||||
qCWarning(audio) << "Unknown audio injector option:" << it.name();
|
||||
}
|
||||
|
|
|
@ -29,6 +29,7 @@ public:
|
|||
bool ignorePenumbra;
|
||||
bool localOnly;
|
||||
float secondOffset;
|
||||
float pitch; // multiplier, where 2.0f shifts up one octave
|
||||
};
|
||||
|
||||
Q_DECLARE_METATYPE(AudioInjectorOptions);
|
||||
|
|
|
@ -791,10 +791,19 @@ bool Avatar::shouldRenderHead(const RenderArgs* renderArgs) const {
|
|||
|
||||
// virtual
|
||||
void Avatar::simulateAttachments(float deltaTime) {
|
||||
assert(_attachmentModels.size() == _attachmentModelsTexturesLoaded.size());
|
||||
PerformanceTimer perfTimer("attachments");
|
||||
for (int i = 0; i < (int)_attachmentModels.size(); i++) {
|
||||
const AttachmentData& attachment = _attachmentData.at(i);
|
||||
auto& model = _attachmentModels.at(i);
|
||||
bool texturesLoaded = _attachmentModelsTexturesLoaded.at(i);
|
||||
|
||||
// Watch for texture loading
|
||||
if (!texturesLoaded && model->getGeometry() && model->getGeometry()->areTexturesLoaded()) {
|
||||
_attachmentModelsTexturesLoaded[i] = true;
|
||||
model->updateRenderItems();
|
||||
}
|
||||
|
||||
int jointIndex = getJointIndex(attachment.jointName);
|
||||
glm::vec3 jointPosition;
|
||||
glm::quat jointRotation;
|
||||
|
@ -1319,6 +1328,7 @@ void Avatar::setAttachmentData(const QVector<AttachmentData>& attachmentData) {
|
|||
while ((int)_attachmentModels.size() > attachmentData.size()) {
|
||||
auto attachmentModel = _attachmentModels.back();
|
||||
_attachmentModels.pop_back();
|
||||
_attachmentModelsTexturesLoaded.pop_back();
|
||||
_attachmentsToRemove.push_back(attachmentModel);
|
||||
}
|
||||
|
||||
|
@ -1326,11 +1336,16 @@ void Avatar::setAttachmentData(const QVector<AttachmentData>& attachmentData) {
|
|||
if (i == (int)_attachmentModels.size()) {
|
||||
// if number of attachments has been increased, we need to allocate a new model
|
||||
_attachmentModels.push_back(allocateAttachmentModel(attachmentData[i].isSoft, _skeletonModel->getRig(), isMyAvatar()));
|
||||
}
|
||||
else if (i < oldAttachmentData.size() && oldAttachmentData[i].isSoft != attachmentData[i].isSoft) {
|
||||
_attachmentModelsTexturesLoaded.push_back(false);
|
||||
} else if (i < oldAttachmentData.size() && oldAttachmentData[i].isSoft != attachmentData[i].isSoft) {
|
||||
// if the attachment has changed type, we need to re-allocate a new one.
|
||||
_attachmentsToRemove.push_back(_attachmentModels[i]);
|
||||
_attachmentModels[i] = allocateAttachmentModel(attachmentData[i].isSoft, _skeletonModel->getRig(), isMyAvatar());
|
||||
_attachmentModelsTexturesLoaded[i] = false;
|
||||
}
|
||||
// If the model URL has changd, we need to wait for the textures to load
|
||||
if (_attachmentModels[i]->getURL() != attachmentData[i].modelURL) {
|
||||
_attachmentModelsTexturesLoaded[i] = false;
|
||||
}
|
||||
_attachmentModels[i]->setURL(attachmentData[i].modelURL);
|
||||
}
|
||||
|
|
|
@ -306,6 +306,7 @@ protected:
|
|||
|
||||
glm::vec3 _skeletonOffset;
|
||||
std::vector<std::shared_ptr<Model>> _attachmentModels;
|
||||
std::vector<bool> _attachmentModelsTexturesLoaded;
|
||||
std::vector<std::shared_ptr<Model>> _attachmentsToRemove;
|
||||
std::vector<std::shared_ptr<Model>> _attachmentsToDelete;
|
||||
|
||||
|
|