Merged with master
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 Width: | Height: | Size: 3.3 KiB After Width: | Height: | Size: 5.1 KiB |
Before Width: | Height: | Size: 4.1 KiB After Width: | Height: | Size: 4.9 KiB |
Before Width: | Height: | Size: 2.2 KiB After Width: | Height: | Size: 4.2 KiB |
Before Width: | Height: | Size: 2.5 KiB After Width: | Height: | Size: 4.3 KiB |
Before Width: | Height: | Size: 4.7 KiB After Width: | Height: | Size: 5.8 KiB |
Before Width: | Height: | Size: 6 KiB After Width: | Height: | Size: 5.5 KiB |
Before Width: | Height: | Size: 7.5 KiB After Width: | Height: | Size: 7.3 KiB |
Before Width: | Height: | Size: 9.8 KiB After Width: | Height: | Size: 6.7 KiB |
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 8.9 KiB |
Before Width: | Height: | Size: 14 KiB After Width: | Height: | 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
|
|
@ -343,7 +343,6 @@ void Agent::scriptRequestFinished() {
|
|||
|
||||
void Agent::executeScript() {
|
||||
_scriptEngine = scriptEngineFactory(ScriptEngine::AGENT_SCRIPT, _scriptContents, _payload);
|
||||
_scriptEngine->setParent(this); // be the parent of the script engine so it gets moved when we do
|
||||
|
||||
DependencyManager::get<RecordingScriptingInterface>()->setScriptEngine(_scriptEngine);
|
||||
|
||||
|
|
|
@ -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 Width: | Height: | 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 Width: | Height: | 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 Width: | Height: | Size: 2.6 MiB |
After Width: | Height: | Size: 2.9 MiB |
After Width: | Height: | 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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,256 +0,0 @@
|
|||
//
|
||||
// ToolWindow.qml
|
||||
//
|
||||
// Created by Bradley Austin Davis on 12 Jan 2016
|
||||
// Copyright 2016 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 QtQuick.Controls 1.4
|
||||
import QtQuick.Controls.Styles 1.4
|
||||
import QtWebEngine 1.1
|
||||
import QtWebChannel 1.0
|
||||
import Qt.labs.settings 1.0
|
||||
|
||||
import "windows"
|
||||
import "controls-uit"
|
||||
import "styles-uit"
|
||||
|
||||
|
||||
ScrollingWindow {
|
||||
id: toolWindow
|
||||
resizable: true
|
||||
objectName: "ToolWindow"
|
||||
destroyOnCloseButton: false
|
||||
destroyOnHidden: false
|
||||
closable: true
|
||||
shown: false
|
||||
title: "Edit"
|
||||
property alias tabView: tabView
|
||||
implicitWidth: 520; implicitHeight: 695
|
||||
minSize: Qt.vector2d(456, 500)
|
||||
|
||||
HifiConstants { id: hifi }
|
||||
|
||||
onParentChanged: {
|
||||
if (parent) {
|
||||
x = 120;
|
||||
y = 120;
|
||||
}
|
||||
}
|
||||
|
||||
onShownChanged: {
|
||||
keyboardEnabled = HMD.active;
|
||||
}
|
||||
|
||||
Settings {
|
||||
category: "ToolWindow.Position"
|
||||
property alias x: toolWindow.x
|
||||
property alias y: toolWindow.y
|
||||
}
|
||||
|
||||
Item {
|
||||
id: toolWindowTabViewItem
|
||||
height: pane.scrollHeight
|
||||
width: pane.contentWidth
|
||||
anchors.left: parent.left
|
||||
anchors.top: parent.top
|
||||
|
||||
TabView {
|
||||
id: tabView
|
||||
width: pane.contentWidth
|
||||
// Pane height so that don't use Window's scrollbars otherwise tabs may be scrolled out of view.
|
||||
height: pane.scrollHeight
|
||||
property int tabCount: 0
|
||||
|
||||
Repeater {
|
||||
model: 4
|
||||
Tab {
|
||||
// Force loading of the content even if the tab is not visible
|
||||
// (required for letting the C++ code access the webview)
|
||||
active: true
|
||||
enabled: false
|
||||
property string originalUrl: ""
|
||||
|
||||
WebView {
|
||||
id: webView
|
||||
anchors.fill: parent
|
||||
enabled: false
|
||||
Component.onCompleted: {
|
||||
webChannel.registerObject("eventBridge", eventBridge);
|
||||
webChannel.registerObject("eventBridgeWrapper", eventBridgeWrapper);
|
||||
}
|
||||
|
||||
onEnabledChanged: toolWindow.updateVisiblity()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
style: TabViewStyle {
|
||||
|
||||
frame: Rectangle { // Background shown before content loads.
|
||||
anchors.fill: parent
|
||||
color: hifi.colors.baseGray
|
||||
}
|
||||
|
||||
frameOverlap: 0
|
||||
|
||||
tab: Rectangle {
|
||||
implicitWidth: text.width
|
||||
implicitHeight: 3 * text.height
|
||||
color: styleData.selected ? hifi.colors.black : hifi.colors.tabBackgroundDark
|
||||
|
||||
RalewayRegular {
|
||||
id: text
|
||||
text: styleData.title
|
||||
font.capitalization: Font.AllUppercase
|
||||
size: hifi.fontSizes.tabName
|
||||
width: tabView.tabCount > 1 ? styleData.availableWidth / tabView.tabCount : implicitWidth + 2 * hifi.dimensions.contentSpacing.x
|
||||
elide: Text.ElideRight
|
||||
color: styleData.selected ? hifi.colors.primaryHighlight : hifi.colors.lightGrayText
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
anchors.centerIn: parent
|
||||
}
|
||||
|
||||
Rectangle { // Separator.
|
||||
width: 1
|
||||
height: parent.height
|
||||
color: hifi.colors.black
|
||||
anchors.left: parent.left
|
||||
anchors.top: parent.top
|
||||
visible: styleData.index > 0
|
||||
|
||||
Rectangle {
|
||||
width: 1
|
||||
height: 1
|
||||
color: hifi.colors.baseGray
|
||||
anchors.left: parent.left
|
||||
anchors.bottom: parent.bottom
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle { // Active underline.
|
||||
width: parent.width - (styleData.index > 0 ? 1 : 0)
|
||||
height: 1
|
||||
anchors.right: parent.right
|
||||
anchors.bottom: parent.bottom
|
||||
color: styleData.selected ? hifi.colors.primaryHighlight : hifi.colors.baseGray
|
||||
}
|
||||
}
|
||||
|
||||
tabOverlap: 0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function updateVisiblity() {
|
||||
if (visible) {
|
||||
for (var i = 0; i < tabView.count; ++i) {
|
||||
if (tabView.getTab(i).enabled) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
shown = false;
|
||||
}
|
||||
}
|
||||
|
||||
function findIndexForUrl(source) {
|
||||
for (var i = 0; i < tabView.count; ++i) {
|
||||
var tab = tabView.getTab(i);
|
||||
if (tab.originalUrl === source) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
function findTabForUrl(source) {
|
||||
var index = findIndexForUrl(source);
|
||||
if (index < 0) {
|
||||
return;
|
||||
}
|
||||
return tabView.getTab(index);
|
||||
}
|
||||
|
||||
function showTabForUrl(source, newVisible) {
|
||||
var index = findIndexForUrl(source);
|
||||
if (index < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
var tab = tabView.getTab(index);
|
||||
if (newVisible) {
|
||||
toolWindow.shown = true
|
||||
tab.enabled = true
|
||||
} else {
|
||||
tab.enabled = false;
|
||||
updateVisiblity();
|
||||
}
|
||||
}
|
||||
|
||||
function findFreeTab() {
|
||||
for (var i = 0; i < tabView.count; ++i) {
|
||||
var tab = tabView.getTab(i);
|
||||
if (tab && (!tab.originalUrl || tab.originalUrl === "")) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
function removeTabForUrl(source) {
|
||||
var index = findIndexForUrl(source);
|
||||
if (index < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
var tab = tabView.getTab(index);
|
||||
tab.title = "";
|
||||
tab.enabled = false;
|
||||
tab.originalUrl = "";
|
||||
tab.item.url = "about:blank";
|
||||
tab.item.enabled = false;
|
||||
tabView.tabCount--;
|
||||
}
|
||||
|
||||
function addWebTab(properties) {
|
||||
if (!properties.source) {
|
||||
console.warn("Attempted to open Web Tool Pane without URL");
|
||||
return;
|
||||
}
|
||||
|
||||
var existingTabIndex = findIndexForUrl(properties.source);
|
||||
if (existingTabIndex >= 0) {
|
||||
var tab = tabView.getTab(existingTabIndex);
|
||||
return tab.item;
|
||||
}
|
||||
|
||||
var freeTabIndex = findFreeTab();
|
||||
if (freeTabIndex === -1) {
|
||||
console.warn("Unable to add new tab");
|
||||
return;
|
||||
}
|
||||
|
||||
if (properties.width) {
|
||||
tabView.width = Math.min(Math.max(tabView.width, properties.width), toolWindow.maxSize.x);
|
||||
}
|
||||
|
||||
if (properties.height) {
|
||||
tabView.height = Math.min(Math.max(tabView.height, properties.height), toolWindow.maxSize.y);
|
||||
}
|
||||
|
||||
var tab = tabView.getTab(freeTabIndex);
|
||||
tab.title = properties.title || "Unknown";
|
||||
tab.enabled = true;
|
||||
tab.originalUrl = properties.source;
|
||||
|
||||
var result = tab.item;
|
||||
result.enabled = true;
|
||||
tabView.tabCount++;
|
||||
result.url = properties.source;
|
||||
return result;
|
||||
}
|
||||
}
|
|
@ -24,13 +24,18 @@ 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 leftPermanentGlyph: "";
|
||||
property string centerPlaceholderGlyph: "";
|
||||
|
||||
placeholderText: textField.placeholderText
|
||||
|
||||
FontLoader { id: firaSansSemiBold; source: "../../fonts/FiraSans-SemiBold.ttf"; }
|
||||
FontLoader { id: hifiGlyphs; source: "../../fonts/hifi-glyphs.ttf"; }
|
||||
font.family: firaSansSemiBold.name
|
||||
font.pixelSize: hifi.fontSizes.textFieldInput
|
||||
font.italic: textField.text == ""
|
||||
|
@ -54,6 +59,7 @@ TextField {
|
|||
}
|
||||
|
||||
style: TextFieldStyle {
|
||||
id: style;
|
||||
textColor: {
|
||||
if (isLightColorScheme) {
|
||||
if (textField.activeFocus) {
|
||||
|
@ -98,9 +104,28 @@ 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.leftPermanentGlyph;
|
||||
color: textColor;
|
||||
size: hifi.fontSizes.textFieldSearchIcon;
|
||||
anchors.left: parent.left;
|
||||
anchors.verticalCenter: parent.verticalCenter;
|
||||
anchors.leftMargin: hifi.dimensions.textPadding - 2;
|
||||
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
|
||||
|
@ -132,7 +157,7 @@ TextField {
|
|||
placeholderTextColor: isFaintGrayColorScheme ? hifi.colors.lightGrayText : hifi.colors.lightGray
|
||||
selectedTextColor: hifi.colors.black
|
||||
selectionColor: hifi.colors.primaryHighlight
|
||||
padding.left: (isSearchField ? 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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -22,10 +22,6 @@ OriginalDesktop.Desktop {
|
|||
acceptedButtons: Qt.NoButton
|
||||
}
|
||||
|
||||
// The tool window, one instance
|
||||
property alias toolWindow: toolWindow
|
||||
ToolWindow { id: toolWindow }
|
||||
|
||||
Action {
|
||||
text: "Open Browser"
|
||||
shortcut: "Ctrl+B"
|
||||
|
|
|
@ -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('&');
|
||||
|
|
|
@ -1,73 +0,0 @@
|
|||
//
|
||||
// SendMoney.qml
|
||||
// qml/hifi/commerce/wallet
|
||||
//
|
||||
// SendMoney
|
||||
//
|
||||
// Created by Zach Fox on 2017-08-18
|
||||
// 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
|
||||
//
|
||||
|
||||
import Hifi 1.0 as Hifi
|
||||
import QtQuick 2.5
|
||||
import QtQuick.Controls 1.4
|
||||
import "../../../styles-uit"
|
||||
import "../../../controls-uit" as HifiControlsUit
|
||||
import "../../../controls" as HifiControls
|
||||
|
||||
// references XXX from root context
|
||||
|
||||
Item {
|
||||
HifiConstants { id: hifi; }
|
||||
|
||||
id: root;
|
||||
|
||||
Connections {
|
||||
target: Commerce;
|
||||
}
|
||||
|
||||
// "Unavailable"
|
||||
RalewayRegular {
|
||||
text: "You currently cannot send money to other High Fidelity users.";
|
||||
// Anchors
|
||||
anchors.fill: parent;
|
||||
// Text size
|
||||
size: 24;
|
||||
// Style
|
||||
color: hifi.colors.faintGray;
|
||||
wrapMode: Text.WordWrap;
|
||||
// Alignment
|
||||
horizontalAlignment: Text.AlignHCenter;
|
||||
verticalAlignment: Text.AlignVCenter;
|
||||
}
|
||||
|
||||
//
|
||||
// FUNCTION DEFINITIONS START
|
||||
//
|
||||
//
|
||||
// Function Name: fromScript()
|
||||
//
|
||||
// Relevant Variables:
|
||||
// None
|
||||
//
|
||||
// Arguments:
|
||||
// message: The message sent from the JavaScript.
|
||||
// Messages are in format "{method, params}", like json-rpc.
|
||||
//
|
||||
// Description:
|
||||
// Called when a message is received from a script.
|
||||
//
|
||||
function fromScript(message) {
|
||||
switch (message.method) {
|
||||
default:
|
||||
console.log('Unrecognized message from wallet.js:', JSON.stringify(message));
|
||||
}
|
||||
}
|
||||
signal sendSignalToWallet(var msg);
|
||||
//
|
||||
// FUNCTION DEFINITIONS END
|
||||
//
|
||||
}
|
|
@ -19,8 +19,7 @@ import "../../../styles-uit"
|
|||
import "../../../controls-uit" as HifiControlsUit
|
||||
import "../../../controls" as HifiControls
|
||||
import "../common" as HifiCommerceCommon
|
||||
|
||||
// references XXX from root context
|
||||
import "./sendMoney"
|
||||
|
||||
Rectangle {
|
||||
HifiConstants { id: hifi; }
|
||||
|
@ -316,18 +315,29 @@ Rectangle {
|
|||
|
||||
Connections {
|
||||
onSendSignalToWallet: {
|
||||
sendToScript(msg);
|
||||
if (msg.method === 'transactionHistory_usernameLinkClicked') {
|
||||
userInfoViewer.url = msg.usernameLink;
|
||||
userInfoViewer.visible = true;
|
||||
} else {
|
||||
sendToScript(msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SendMoney {
|
||||
id: sendMoney;
|
||||
z: 997;
|
||||
visible: root.activeView === "sendMoney";
|
||||
anchors.top: titleBarContainer.bottom;
|
||||
anchors.bottom: tabButtonsContainer.top;
|
||||
anchors.left: parent.left;
|
||||
anchors.right: parent.right;
|
||||
anchors.fill: parent;
|
||||
parentAppTitleBarHeight: titleBarContainer.height;
|
||||
parentAppNavBarHeight: tabButtonsContainer.height;
|
||||
|
||||
Connections {
|
||||
onSendSignalToWallet: {
|
||||
sendToScript(msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Security {
|
||||
|
@ -379,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;
|
||||
|
@ -497,7 +507,7 @@ Rectangle {
|
|||
Rectangle {
|
||||
id: sendMoneyButtonContainer;
|
||||
visible: !walletSetup.visible;
|
||||
color: hifi.colors.black;
|
||||
color: root.activeView === "sendMoney" ? hifi.colors.blueAccent : hifi.colors.black;
|
||||
anchors.top: parent.top;
|
||||
anchors.left: exchangeMoneyButtonContainer.right;
|
||||
anchors.bottom: parent.bottom;
|
||||
|
@ -513,7 +523,7 @@ Rectangle {
|
|||
anchors.top: parent.top;
|
||||
anchors.topMargin: -2;
|
||||
// Style
|
||||
color: hifi.colors.lightGray50;
|
||||
color: root.activeView === "sendMoney" || sendMoneyTabMouseArea.containsMouse ? hifi.colors.white : hifi.colors.blueHighlight;
|
||||
}
|
||||
|
||||
RalewaySemiBold {
|
||||
|
@ -528,12 +538,24 @@ Rectangle {
|
|||
anchors.right: parent.right;
|
||||
anchors.rightMargin: 4;
|
||||
// Style
|
||||
color: hifi.colors.lightGray50;
|
||||
color: root.activeView === "sendMoney" || sendMoneyTabMouseArea.containsMouse ? hifi.colors.white : hifi.colors.blueHighlight;
|
||||
wrapMode: Text.WordWrap;
|
||||
// Alignment
|
||||
horizontalAlignment: Text.AlignHCenter;
|
||||
verticalAlignment: Text.AlignTop;
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: sendMoneyTabMouseArea;
|
||||
anchors.fill: parent;
|
||||
hoverEnabled: enabled;
|
||||
onClicked: {
|
||||
root.activeView = "sendMoney";
|
||||
tabButtonsContainer.resetTabButtonColors();
|
||||
}
|
||||
onEntered: parent.color = hifi.colors.blueHighlight;
|
||||
onExited: parent.color = root.activeView === "sendMoney" ? hifi.colors.blueAccent : hifi.colors.black;
|
||||
}
|
||||
}
|
||||
|
||||
// "SECURITY" tab button
|
||||
|
@ -665,9 +687,16 @@ Rectangle {
|
|||
// TAB BUTTONS END
|
||||
//
|
||||
|
||||
HifiControls.TabletWebView {
|
||||
id: userInfoViewer;
|
||||
z: 998;
|
||||
anchors.fill: parent;
|
||||
visible: false;
|
||||
}
|
||||
|
||||
Item {
|
||||
id: keyboardContainer;
|
||||
z: 998;
|
||||
z: 999;
|
||||
visible: keyboard.raised;
|
||||
property bool punctuationMode: false;
|
||||
anchors {
|
||||
|
@ -713,6 +742,13 @@ Rectangle {
|
|||
case 'inspectionCertificate_resetCert':
|
||||
// NOP
|
||||
break;
|
||||
case 'updateConnections':
|
||||
sendMoney.updateConnections(message.connections);
|
||||
break;
|
||||
case 'selectRecipient':
|
||||
case 'updateSelectedRecipientUsername':
|
||||
sendMoney.fromScript(message);
|
||||
break;
|
||||
default:
|
||||
console.log('Unrecognized message from wallet.js:', JSON.stringify(message));
|
||||
}
|
||||
|
|
|
@ -19,8 +19,6 @@ import "../../../styles-uit"
|
|||
import "../../../controls-uit" as HifiControlsUit
|
||||
import "../../../controls" as HifiControls
|
||||
|
||||
// references XXX from root context
|
||||
|
||||
Item {
|
||||
HifiConstants { id: hifi; }
|
||||
|
||||
|
@ -32,6 +30,20 @@ Item {
|
|||
property int currentHistoryPage: 1;
|
||||
property var pagesAlreadyAdded: new Array();
|
||||
|
||||
onVisibleChanged: {
|
||||
if (visible) {
|
||||
transactionHistoryModel.clear();
|
||||
Commerce.balance();
|
||||
initialHistoryReceived = false;
|
||||
root.currentHistoryPage = 1;
|
||||
root.noMoreHistoryData = false;
|
||||
root.historyRequestPending = true;
|
||||
Commerce.history(root.currentHistoryPage);
|
||||
} else {
|
||||
refreshTimer.stop();
|
||||
}
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: Commerce;
|
||||
|
||||
|
@ -189,20 +201,6 @@ Item {
|
|||
color: hifi.colors.white;
|
||||
// Alignment
|
||||
verticalAlignment: Text.AlignVCenter;
|
||||
|
||||
onVisibleChanged: {
|
||||
if (visible) {
|
||||
transactionHistoryModel.clear();
|
||||
Commerce.balance();
|
||||
initialHistoryReceived = false;
|
||||
root.currentHistoryPage = 1;
|
||||
root.noMoreHistoryData = false;
|
||||
root.historyRequestPending = true;
|
||||
Commerce.history(root.currentHistoryPage);
|
||||
} else {
|
||||
refreshTimer.stop();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// "balance" text below field
|
||||
|
@ -384,8 +382,8 @@ Item {
|
|||
height: visible ? parent.height : 0;
|
||||
|
||||
AnonymousProRegular {
|
||||
id: dateText;
|
||||
text: model.created_at ? getFormattedDate(model.created_at * 1000) : "";
|
||||
id: hfcText;
|
||||
text: model.hfc_text || '';
|
||||
// Style
|
||||
size: 18;
|
||||
anchors.left: parent.left;
|
||||
|
@ -393,7 +391,6 @@ Item {
|
|||
anchors.topMargin: 15;
|
||||
width: 118;
|
||||
height: paintedHeight;
|
||||
color: hifi.colors.blueAccent;
|
||||
wrapMode: Text.WordWrap;
|
||||
// Alignment
|
||||
horizontalAlignment: Text.AlignRight;
|
||||
|
@ -401,20 +398,25 @@ Item {
|
|||
|
||||
AnonymousProRegular {
|
||||
id: transactionText;
|
||||
text: model.text ? (model.status === "invalidated" ? ("INVALIDATED: " + model.text) : model.text) : "";
|
||||
text: model.transaction_text ? (model.status === "invalidated" ? ("INVALIDATED: " + model.transaction_text) : model.transaction_text) : "";
|
||||
size: 18;
|
||||
anchors.top: parent.top;
|
||||
anchors.topMargin: 15;
|
||||
anchors.left: dateText.right;
|
||||
anchors.left: hfcText.right;
|
||||
anchors.leftMargin: 20;
|
||||
anchors.right: parent.right;
|
||||
height: paintedHeight;
|
||||
color: model.status === "invalidated" ? hifi.colors.redAccent : hifi.colors.baseGrayHighlight;
|
||||
linkColor: hifi.colors.blueAccent;
|
||||
wrapMode: Text.WordWrap;
|
||||
font.strikeout: model.status === "invalidated";
|
||||
|
||||
onLinkActivated: {
|
||||
sendSignalToWallet({method: 'transactionHistory_linkClicked', marketplaceLink: link});
|
||||
if (link.indexOf("users/") !== -1) {
|
||||
sendSignalToWallet({method: 'transactionHistory_usernameLinkClicked', usernameLink: link});
|
||||
} else {
|
||||
sendSignalToWallet({method: 'transactionHistory_linkClicked', marketplaceLink: link});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,128 @@
|
|||
//
|
||||
// ConnectionItem.qml
|
||||
// qml/hifi/commerce/wallet/sendMoney
|
||||
//
|
||||
// ConnectionItem
|
||||
//
|
||||
// Created by Zach Fox on 2018-01-09
|
||||
// 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 Hifi 1.0 as Hifi
|
||||
import QtQuick 2.5
|
||||
import QtGraphicalEffects 1.0
|
||||
import QtQuick.Controls 1.4
|
||||
import QtQuick.Controls.Styles 1.4
|
||||
import "../../../../styles-uit"
|
||||
import "../../../../controls-uit" as HifiControlsUit
|
||||
import "../../../../controls" as HifiControls
|
||||
import "../../wallet" as HifiWallet
|
||||
|
||||
Item {
|
||||
HifiConstants { id: hifi; }
|
||||
|
||||
id: root;
|
||||
property bool isSelected: false;
|
||||
property string userName;
|
||||
property string profilePicUrl;
|
||||
|
||||
height: 75;
|
||||
width: parent.width;
|
||||
|
||||
Rectangle {
|
||||
id: mainContainer;
|
||||
// Style
|
||||
color: root.isSelected ? hifi.colors.faintGray80 : hifi.colors.white;
|
||||
// Size
|
||||
anchors.left: parent.left;
|
||||
anchors.right: parent.right;
|
||||
anchors.top: parent.top;
|
||||
height: root.height;
|
||||
|
||||
Item {
|
||||
id: avatarImage;
|
||||
visible: profileUrl !== "" && userName !== "";
|
||||
// Size
|
||||
anchors.verticalCenter: parent.verticalCenter;
|
||||
anchors.left: parent.left;
|
||||
anchors.leftMargin: 36;
|
||||
height: 50;
|
||||
width: visible ? height : 0;
|
||||
clip: true;
|
||||
Image {
|
||||
id: userImage;
|
||||
source: root.profilePicUrl !== "" ? ((0 === root.profilePicUrl.indexOf("http")) ?
|
||||
root.profilePicUrl : (Account.metaverseServerURL + root.profilePicUrl)) : "";
|
||||
mipmap: true;
|
||||
// Anchors
|
||||
anchors.fill: parent
|
||||
layer.enabled: true
|
||||
layer.effect: OpacityMask {
|
||||
maskSource: Item {
|
||||
width: userImage.width;
|
||||
height: userImage.height;
|
||||
Rectangle {
|
||||
anchors.centerIn: parent;
|
||||
width: userImage.width; // This works because userImage is square
|
||||
height: width;
|
||||
radius: width;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
AnimatedImage {
|
||||
source: "../../../../../icons/profilePicLoading.gif"
|
||||
anchors.fill: parent;
|
||||
visible: userImage.status != Image.Ready;
|
||||
}
|
||||
}
|
||||
|
||||
RalewaySemiBold {
|
||||
id: userName;
|
||||
anchors.left: avatarImage.right;
|
||||
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: 18;
|
||||
// Style
|
||||
color: hifi.colors.blueAccent;
|
||||
text: root.userName;
|
||||
elide: Text.ElideRight;
|
||||
// Alignment
|
||||
horizontalAlignment: Text.AlignLeft;
|
||||
verticalAlignment: Text.AlignVCenter;
|
||||
}
|
||||
|
||||
// "Choose" button
|
||||
HifiControlsUit.Button {
|
||||
id: chooseButton;
|
||||
visible: root.isSelected;
|
||||
color: hifi.buttons.blue;
|
||||
colorScheme: hifi.colorSchemes.dark;
|
||||
anchors.verticalCenter: parent.verticalCenter;
|
||||
anchors.right: parent.right;
|
||||
anchors.rightMargin: 28;
|
||||
height: 35;
|
||||
width: 100;
|
||||
text: "CHOOSE";
|
||||
onClicked: {
|
||||
var msg = { method: 'chooseConnection', userName: root.userName, profilePicUrl: root.profilePicUrl };
|
||||
sendToSendMoney(msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// FUNCTION DEFINITIONS START
|
||||
//
|
||||
signal sendToSendMoney(var msg);
|
||||
//
|
||||
// FUNCTION DEFINITIONS END
|
||||
//
|
||||
}
|
|
@ -0,0 +1,117 @@
|
|||
//
|
||||
// RecipientDisplay.qml
|
||||
// qml/hifi/commerce/wallet/sendMoney
|
||||
//
|
||||
// RecipientDisplay
|
||||
//
|
||||
// Created by Zach Fox on 2018-01-11
|
||||
// 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 Hifi 1.0 as Hifi
|
||||
import QtQuick 2.6
|
||||
import QtQuick.Controls 2.2
|
||||
import QtGraphicalEffects 1.0
|
||||
import "../../../../styles-uit"
|
||||
import "../../../../controls-uit" as HifiControlsUit
|
||||
import "../../../../controls" as HifiControls
|
||||
import "../../common" as HifiCommerceCommon
|
||||
|
||||
Item {
|
||||
HifiConstants { id: hifi; }
|
||||
|
||||
id: root;
|
||||
|
||||
property bool isDisplayingNearby; // as opposed to 'connections'
|
||||
property string displayName;
|
||||
property string userName;
|
||||
property string profilePic;
|
||||
property string textColor: hifi.colors.white;
|
||||
|
||||
Item {
|
||||
visible: root.isDisplayingNearby;
|
||||
anchors.fill: parent;
|
||||
|
||||
RalewaySemiBold {
|
||||
id: recipientDisplayName;
|
||||
text: root.displayName;
|
||||
// Anchors
|
||||
anchors.top: parent.top;
|
||||
anchors.left: parent.left;
|
||||
anchors.right: parent.right;
|
||||
anchors.rightMargin: 12;
|
||||
height: parent.height/2;
|
||||
// Text size
|
||||
size: 18;
|
||||
// Style
|
||||
color: root.textColor;
|
||||
verticalAlignment: Text.AlignBottom;
|
||||
elide: Text.ElideRight;
|
||||
}
|
||||
|
||||
RalewaySemiBold {
|
||||
text: root.userName;
|
||||
// Anchors
|
||||
anchors.bottom: parent.bottom;
|
||||
anchors.left: recipientDisplayName.anchors.left;
|
||||
anchors.leftMargin: recipientDisplayName.anchors.leftMargin;
|
||||
anchors.right: recipientDisplayName.anchors.right;
|
||||
anchors.rightMargin: recipientDisplayName.anchors.rightMargin;
|
||||
height: parent.height/2;
|
||||
// Text size
|
||||
size: 16;
|
||||
// Style
|
||||
color: root.textColor;
|
||||
verticalAlignment: Text.AlignTop;
|
||||
elide: Text.ElideRight;
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
visible: !root.isDisplayingNearby;
|
||||
anchors.fill: parent;
|
||||
|
||||
Image {
|
||||
id: userImage;
|
||||
source: root.profilePic;
|
||||
mipmap: true;
|
||||
// Anchors
|
||||
anchors.left: parent.left;
|
||||
anchors.verticalCenter: parent.verticalCenter;
|
||||
height: parent.height - 36;
|
||||
width: height;
|
||||
layer.enabled: true;
|
||||
layer.effect: OpacityMask {
|
||||
maskSource: Item {
|
||||
width: userImage.width;
|
||||
height: userImage.height;
|
||||
Rectangle {
|
||||
anchors.centerIn: parent;
|
||||
width: userImage.width; // This works because userImage is square
|
||||
height: width;
|
||||
radius: width;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
RalewaySemiBold {
|
||||
text: root.userName;
|
||||
// Anchors
|
||||
anchors.left: userImage.right;
|
||||
anchors.leftMargin: 8;
|
||||
anchors.right: parent.right;
|
||||
anchors.verticalCenter: parent.verticalCenter;
|
||||
height: parent.height - 4;
|
||||
// Text size
|
||||
size: 16;
|
||||
// Style
|
||||
color: root.textColor;
|
||||
verticalAlignment: Text.AlignVCenter;
|
||||
elide: Text.ElideRight;
|
||||
}
|
||||
}
|
||||
}
|
1575
interface/resources/qml/hifi/commerce/wallet/sendMoney/SendMoney.qml
Normal file
|
@ -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 Width: | Height: | Size: 921 B |
After Width: | Height: | 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 Width: | Height: | 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 Width: | Height: | 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 Width: | Height: | Size: 2.5 KiB |
|
@ -7,7 +7,7 @@ import "."
|
|||
Overlay {
|
||||
id: root
|
||||
|
||||
Image {
|
||||
AnimatedImage {
|
||||
id: image
|
||||
property bool scaleFix: true
|
||||
property real xStart: 0
|
||||
|
|
|
@ -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>
|
||||
|
@ -157,7 +161,7 @@
|
|||
#include "scripting/AssetMappingsScriptingInterface.h"
|
||||
#include "scripting/ClipboardScriptingInterface.h"
|
||||
#include "scripting/DesktopScriptingInterface.h"
|
||||
#include "scripting/GlobalServicesScriptingInterface.h"
|
||||
#include "scripting/AccountServicesScriptingInterface.h"
|
||||
#include "scripting/HMDScriptingInterface.h"
|
||||
#include "scripting/MenuScriptingInterface.h"
|
||||
#include "scripting/SettingsScriptingInterface.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;
|
||||
|
||||
|
@ -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";
|
||||
|
@ -1730,7 +1791,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 +1830,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 +1845,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;
|
||||
|
@ -2093,6 +2155,11 @@ void Application::cleanupBeforeQuit() {
|
|||
DependencyManager::destroy<AudioInjectorManager>();
|
||||
DependencyManager::destroy<AudioScriptingInterface>();
|
||||
|
||||
// The PointerManager must be destroyed before the PickManager because when a Pointer is deleted,
|
||||
// it accesses the PickManager to delete its associated Pick
|
||||
DependencyManager::destroy<PointerManager>();
|
||||
DependencyManager::destroy<PickManager>();
|
||||
|
||||
qCDebug(interfaceapp) << "Application::cleanupBeforeQuit() complete";
|
||||
}
|
||||
|
||||
|
@ -2176,11 +2243,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>();
|
||||
|
@ -2197,13 +2269,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());
|
||||
|
@ -2287,7 +2363,7 @@ void Application::initializeUi() {
|
|||
QUrl{ "hifi/commerce/wallet/SecurityImageChange.qml" },
|
||||
QUrl{ "hifi/commerce/wallet/SecurityImageModel.qml" },
|
||||
QUrl{ "hifi/commerce/wallet/SecurityImageSelection.qml" },
|
||||
QUrl{ "hifi/commerce/wallet/SendMoney.qml" },
|
||||
QUrl{ "hifi/commerce/wallet/sendMoney/SendMoney.qml" },
|
||||
QUrl{ "hifi/commerce/wallet/Wallet.qml" },
|
||||
QUrl{ "hifi/commerce/wallet/WalletHome.qml" },
|
||||
QUrl{ "hifi/commerce/wallet/WalletSetup.qml" },
|
||||
|
@ -2308,8 +2384,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);
|
||||
|
@ -2376,9 +2451,11 @@ void Application::initializeUi() {
|
|||
surfaceContext->setContextProperty("SoundCache", DependencyManager::get<SoundCache>().data());
|
||||
surfaceContext->setContextProperty("InputConfiguration", DependencyManager::get<InputConfiguration>().data());
|
||||
|
||||
surfaceContext->setContextProperty("Account", GlobalServicesScriptingInterface::getInstance());
|
||||
surfaceContext->setContextProperty("Account", AccountServicesScriptingInterface::getInstance()); // DEPRECATED - TO BE REMOVED
|
||||
surfaceContext->setContextProperty("GlobalServices", AccountServicesScriptingInterface::getInstance()); // DEPRECATED - TO BE REMOVED
|
||||
surfaceContext->setContextProperty("AccountServices", AccountServicesScriptingInterface::getInstance());
|
||||
|
||||
surfaceContext->setContextProperty("DialogsManager", _dialogsManagerScriptingInterface);
|
||||
surfaceContext->setContextProperty("GlobalServices", GlobalServicesScriptingInterface::getInstance());
|
||||
surfaceContext->setContextProperty("FaceTracker", DependencyManager::get<DdeFaceTracker>().data());
|
||||
surfaceContext->setContextProperty("AvatarManager", DependencyManager::get<AvatarManager>().data());
|
||||
surfaceContext->setContextProperty("UndoStack", &_undoStackScriptingInterface);
|
||||
|
@ -3902,12 +3979,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__);
|
||||
|
@ -4272,9 +4355,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();
|
||||
|
@ -4349,8 +4432,9 @@ void Application::updateLOD(float deltaTime) const {
|
|||
float presentTime = getActiveDisplayPlugin()->getAveragePresentTime();
|
||||
float engineRunTime = (float)(_renderEngine->getConfiguration().get()->getCPURunTime());
|
||||
float gpuTime = getGPUContext()->getFrameTimerGPUAverage();
|
||||
float maxRenderTime = glm::max(gpuTime, glm::max(presentTime, engineRunTime));
|
||||
DependencyManager::get<LODManager>()->autoAdjustLOD(maxRenderTime, deltaTime);
|
||||
auto lodManager = DependencyManager::get<LODManager>();
|
||||
lodManager->setRenderTimes(presentTime, engineRunTime, gpuTime);
|
||||
lodManager->autoAdjustLOD(deltaTime);
|
||||
} else {
|
||||
DependencyManager::get<LODManager>()->resetLODAdjust();
|
||||
}
|
||||
|
@ -5752,10 +5836,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());
|
||||
|
@ -5775,10 +5862,11 @@ void Application::registerScriptEngineWithApplicationServices(ScriptEnginePointe
|
|||
scriptEngine->registerGlobalObject("ModelCache", DependencyManager::get<ModelCache>().data());
|
||||
scriptEngine->registerGlobalObject("SoundCache", DependencyManager::get<SoundCache>().data());
|
||||
|
||||
scriptEngine->registerGlobalObject("Account", GlobalServicesScriptingInterface::getInstance());
|
||||
scriptEngine->registerGlobalObject("DialogsManager", _dialogsManagerScriptingInterface);
|
||||
|
||||
scriptEngine->registerGlobalObject("GlobalServices", GlobalServicesScriptingInterface::getInstance());
|
||||
scriptEngine->registerGlobalObject("Account", AccountServicesScriptingInterface::getInstance()); // DEPRECATED - TO BE REMOVED
|
||||
scriptEngine->registerGlobalObject("GlobalServices", AccountServicesScriptingInterface::getInstance()); // DEPRECATED - TO BE REMOVED
|
||||
scriptEngine->registerGlobalObject("AccountServices", AccountServicesScriptingInterface::getInstance());
|
||||
qScriptRegisterMetaType(scriptEngine.data(), DownloadInfoResultToScriptValue, DownloadInfoResultFromScriptValue);
|
||||
|
||||
scriptEngine->registerGlobalObject("FaceTracker", DependencyManager::get<DdeFaceTracker>().data());
|
||||
|
|
|
@ -26,43 +26,50 @@ Setting::Handle<float> hmdLODDecreaseFPS("hmdLODDecreaseFPS", DEFAULT_HMD_LOD_DO
|
|||
LODManager::LODManager() {
|
||||
}
|
||||
|
||||
float LODManager::getLODDecreaseFPS() {
|
||||
float LODManager::getLODDecreaseFPS() const {
|
||||
if (qApp->isHMDMode()) {
|
||||
return getHMDLODDecreaseFPS();
|
||||
}
|
||||
return getDesktopLODDecreaseFPS();
|
||||
}
|
||||
|
||||
float LODManager::getLODIncreaseFPS() {
|
||||
float LODManager::getLODIncreaseFPS() const {
|
||||
if (qApp->isHMDMode()) {
|
||||
return getHMDLODIncreaseFPS();
|
||||
}
|
||||
return getDesktopLODIncreaseFPS();
|
||||
}
|
||||
|
||||
// We use a "time-weighted running average" of the renderTime and compare it against min/max thresholds
|
||||
// We use a "time-weighted running average" of the maxRenderTime and compare it against min/max thresholds
|
||||
// to determine if we should adjust the level of detail (LOD).
|
||||
//
|
||||
// A time-weighted running average has a timescale which determines how fast the average tracks the measured
|
||||
// value in real-time. Given a step-function in the mesured value, and assuming measurements happen
|
||||
// faster than the runningAverage is computed, the error between the value and its runningAverage will be
|
||||
// reduced by 1/e every timescale of real-time that passes.
|
||||
const float LOD_ADJUST_RUNNING_AVG_TIMESCALE = 0.1f; // sec
|
||||
const float LOD_ADJUST_RUNNING_AVG_TIMESCALE = 0.08f; // sec
|
||||
//
|
||||
// Assuming the measured value is affected by logic invoked by the runningAverage bumping up against its
|
||||
// thresholds, we expect the adjustment to introduce a step-function. We want the runningAverage to settle
|
||||
// to the new value BEFORE we test it aginst its thresholds again. Hence we test on a period that is a few
|
||||
// multiples of the running average timescale:
|
||||
const uint64_t LOD_AUTO_ADJUST_PERIOD = 5 * (uint64_t)(LOD_ADJUST_RUNNING_AVG_TIMESCALE * (float)USECS_PER_MSEC); // usec
|
||||
const uint64_t LOD_AUTO_ADJUST_PERIOD = 4 * (uint64_t)(LOD_ADJUST_RUNNING_AVG_TIMESCALE * (float)USECS_PER_MSEC); // usec
|
||||
|
||||
const float LOD_AUTO_ADJUST_DECREMENT_FACTOR = 0.8f;
|
||||
const float LOD_AUTO_ADJUST_INCREMENT_FACTOR = 1.2f;
|
||||
|
||||
void LODManager::autoAdjustLOD(float renderTime, float realTimeDelta) {
|
||||
// compute time-weighted running average renderTime
|
||||
void LODManager::setRenderTimes(float presentTime, float engineRunTime, float gpuTime) {
|
||||
_presentTime = presentTime;
|
||||
_engineRunTime = engineRunTime;
|
||||
_gpuTime = gpuTime;
|
||||
}
|
||||
|
||||
void LODManager::autoAdjustLOD(float realTimeDelta) {
|
||||
float maxRenderTime = glm::max(glm::max(_presentTime, _engineRunTime), _gpuTime);
|
||||
// compute time-weighted running average maxRenderTime
|
||||
// Note: we MUST clamp the blend to 1.0 for stability
|
||||
float blend = (realTimeDelta < LOD_ADJUST_RUNNING_AVG_TIMESCALE) ? realTimeDelta / LOD_ADJUST_RUNNING_AVG_TIMESCALE : 1.0f;
|
||||
_avgRenderTime = (1.0f - blend) * _avgRenderTime + blend * renderTime; // msec
|
||||
_avgRenderTime = (1.0f - blend) * _avgRenderTime + blend * maxRenderTime; // msec
|
||||
if (!_automaticLODAdjust) {
|
||||
// early exit
|
||||
return;
|
||||
|
@ -84,6 +91,10 @@ void LODManager::autoAdjustLOD(float renderTime, float realTimeDelta) {
|
|||
<< "targetFPS =" << getLODDecreaseFPS()
|
||||
<< "octreeSizeScale =" << _octreeSizeScale;
|
||||
emit LODDecreased();
|
||||
// Assuming the LOD adjustment will work: we optimistically reset _avgRenderTime
|
||||
// to provide an FPS just above the decrease threshold. It will drift close to its
|
||||
// true value after a few LOD_ADJUST_TIMESCALEs and we'll adjust again as necessary.
|
||||
_avgRenderTime = (float)MSECS_PER_SECOND / (getLODDecreaseFPS() + 1.0f);
|
||||
}
|
||||
_decreaseFPSExpiry = now + LOD_AUTO_ADJUST_PERIOD;
|
||||
}
|
||||
|
@ -105,6 +116,10 @@ void LODManager::autoAdjustLOD(float renderTime, float realTimeDelta) {
|
|||
<< "targetFPS =" << getLODDecreaseFPS()
|
||||
<< "octreeSizeScale =" << _octreeSizeScale;
|
||||
emit LODIncreased();
|
||||
// Assuming the LOD adjustment will work: we optimistically reset _avgRenderTime
|
||||
// to provide an FPS just below the increase threshold. It will drift close to its
|
||||
// true value after a few LOD_ADJUST_TIMESCALEs and we'll adjust again as necessary.
|
||||
_avgRenderTime = (float)MSECS_PER_SECOND / (getLODIncreaseFPS() - 1.0f);
|
||||
}
|
||||
_increaseFPSExpiry = now + LOD_AUTO_ADJUST_PERIOD;
|
||||
}
|
||||
|
@ -119,11 +134,6 @@ void LODManager::autoAdjustLOD(float renderTime, float realTimeDelta) {
|
|||
if (lodToolsDialog) {
|
||||
lodToolsDialog->reloadSliders();
|
||||
}
|
||||
// Assuming the LOD adjustment will work: we optimistically reset _avgRenderTime
|
||||
// to be at middle of target zone. It will drift close to its true value within
|
||||
// about three few LOD_ADJUST_TIMESCALEs and we'll adjust again as necessary.
|
||||
float expectedFPS = 0.5f * (getLODIncreaseFPS() + getLODDecreaseFPS());
|
||||
_avgRenderTime = MSECS_PER_SECOND / expectedFPS;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -131,6 +141,18 @@ void LODManager::resetLODAdjust() {
|
|||
_decreaseFPSExpiry = _increaseFPSExpiry = usecTimestampNow() + LOD_AUTO_ADJUST_PERIOD;
|
||||
}
|
||||
|
||||
float LODManager::getLODLevel() const {
|
||||
// simpleLOD is a linearized and normalized number that represents how much LOD is being applied.
|
||||
// It ranges from:
|
||||
// 1.0 = normal (max) level of detail
|
||||
// 0.0 = min level of detail
|
||||
// In other words: as LOD "drops" the value of simpleLOD will also "drop", and it cannot go lower than 0.0.
|
||||
const float LOG_MIN_LOD_RATIO = logf(ADJUST_LOD_MIN_SIZE_SCALE / ADJUST_LOD_MAX_SIZE_SCALE);
|
||||
float power = logf(_octreeSizeScale / ADJUST_LOD_MAX_SIZE_SCALE);
|
||||
float simpleLOD = (LOG_MIN_LOD_RATIO - power) / LOG_MIN_LOD_RATIO;
|
||||
return simpleLOD;
|
||||
}
|
||||
|
||||
const float MIN_DECREASE_FPS = 0.5f;
|
||||
|
||||
void LODManager::setDesktopLODDecreaseFPS(float fps) {
|
||||
|
|
|
@ -37,7 +37,7 @@ class AABox;
|
|||
class LODManager : public QObject, public Dependency {
|
||||
Q_OBJECT
|
||||
SINGLETON_DEPENDENCY
|
||||
|
||||
|
||||
public:
|
||||
Q_INVOKABLE void setAutomaticLODAdjust(bool value) { _automaticLODAdjust = value; }
|
||||
Q_INVOKABLE bool getAutomaticLODAdjust() const { return _automaticLODAdjust; }
|
||||
|
@ -49,34 +49,56 @@ public:
|
|||
Q_INVOKABLE void setHMDLODDecreaseFPS(float value);
|
||||
Q_INVOKABLE float getHMDLODDecreaseFPS() const;
|
||||
Q_INVOKABLE float getHMDLODIncreaseFPS() const;
|
||||
|
||||
|
||||
// User Tweakable LOD Items
|
||||
Q_INVOKABLE QString getLODFeedbackText();
|
||||
Q_INVOKABLE void setOctreeSizeScale(float sizeScale);
|
||||
Q_INVOKABLE float getOctreeSizeScale() const { return _octreeSizeScale; }
|
||||
|
||||
|
||||
Q_INVOKABLE void setBoundaryLevelAdjust(int boundaryLevelAdjust);
|
||||
Q_INVOKABLE int getBoundaryLevelAdjust() const { return _boundaryLevelAdjust; }
|
||||
|
||||
Q_INVOKABLE float getLODDecreaseFPS();
|
||||
Q_INVOKABLE float getLODIncreaseFPS();
|
||||
|
||||
|
||||
Q_INVOKABLE float getLODDecreaseFPS() const;
|
||||
Q_INVOKABLE float getLODIncreaseFPS() const;
|
||||
|
||||
Q_PROPERTY(float presentTime READ getPresentTime)
|
||||
Q_PROPERTY(float engineRunTime READ getEngineRunTime)
|
||||
Q_PROPERTY(float gpuTime READ getGPUTime)
|
||||
Q_PROPERTY(float avgRenderTime READ getAverageRenderTime)
|
||||
Q_PROPERTY(float fps READ getMaxTheoreticalFPS)
|
||||
Q_PROPERTY(float lodLevel READ getLODLevel)
|
||||
|
||||
Q_PROPERTY(float lodDecreaseFPS READ getLODDecreaseFPS)
|
||||
Q_PROPERTY(float lodIncreaseFPS READ getLODIncreaseFPS)
|
||||
|
||||
float getPresentTime() const { return _presentTime; }
|
||||
float getEngineRunTime() const { return _engineRunTime; }
|
||||
float getGPUTime() const { return _gpuTime; }
|
||||
|
||||
static bool shouldRender(const RenderArgs* args, const AABox& bounds);
|
||||
void autoAdjustLOD(float renderTime, float realTimeDelta);
|
||||
|
||||
void setRenderTimes(float presentTime, float engineRunTime, float gpuTime);
|
||||
void autoAdjustLOD(float realTimeDelta);
|
||||
|
||||
void loadSettings();
|
||||
void saveSettings();
|
||||
void resetLODAdjust();
|
||||
|
||||
|
||||
float getAverageRenderTime() const { return _avgRenderTime; };
|
||||
float getMaxTheoreticalFPS() const { return (float)MSECS_PER_SECOND / _avgRenderTime; };
|
||||
float getLODLevel() const;
|
||||
|
||||
signals:
|
||||
void LODIncreased();
|
||||
void LODDecreased();
|
||||
|
||||
|
||||
private:
|
||||
LODManager();
|
||||
|
||||
|
||||
bool _automaticLODAdjust = true;
|
||||
float _avgRenderTime { 0.0f };
|
||||
float _presentTime { 0.0f }; // msec
|
||||
float _engineRunTime { 0.0f }; // msec
|
||||
float _gpuTime { 0.0f }; // msec
|
||||
float _avgRenderTime { 0.0f }; // msec
|
||||
float _desktopMaxRenderTime { DEFAULT_DESKTOP_MAX_RENDER_TIME };
|
||||
float _hmdMaxRenderTime { DEFAULT_HMD_MAX_RENDER_TIME };
|
||||
|
||||
|
|
|
@ -574,8 +574,6 @@ Menu::Menu() {
|
|||
avatar.get(), SLOT(setEnableMeshVisible(bool)));
|
||||
addCheckableActionToQMenuAndActionHash(avatarDebugMenu, MenuOption::DisableEyelidAdjustment, 0, false);
|
||||
addCheckableActionToQMenuAndActionHash(avatarDebugMenu, MenuOption::TurnWithHead, 0, false);
|
||||
addCheckableActionToQMenuAndActionHash(avatarDebugMenu, MenuOption::UseAnimPreAndPostRotations, 0, true,
|
||||
avatar.get(), SLOT(setUseAnimPreAndPostRotations(bool)));
|
||||
addCheckableActionToQMenuAndActionHash(avatarDebugMenu, MenuOption::EnableInverseKinematics, 0, true,
|
||||
avatar.get(), SLOT(setEnableInverseKinematics(bool)));
|
||||
addCheckableActionToQMenuAndActionHash(avatarDebugMenu, MenuOption::RenderSensorToWorldMatrix, 0, false,
|
||||
|
|
|
@ -194,7 +194,6 @@ namespace MenuOption {
|
|||
const QString TurnWithHead = "Turn using Head";
|
||||
const QString UseAudioForMouth = "Use Audio for Mouth";
|
||||
const QString UseCamera = "Use Camera";
|
||||
const QString UseAnimPreAndPostRotations = "Use Anim Pre and Post Rotations";
|
||||
const QString VelocityFilter = "Velocity Filter";
|
||||
const QString VisibleToEveryone = "Everyone";
|
||||
const QString VisibleToFriends = "Friends";
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -537,6 +537,7 @@ void MyAvatar::simulate(float deltaTime) {
|
|||
// we've achived our final adjusted position and rotation for the avatar
|
||||
// and all of its joints, now update our attachements.
|
||||
Avatar::simulateAttachments(deltaTime);
|
||||
relayJointDataToChildren();
|
||||
|
||||
if (!_skeletonModel->hasSkeleton()) {
|
||||
// All the simulation that can be done has been done
|
||||
|
@ -1061,11 +1062,6 @@ void MyAvatar::setEnableMeshVisible(bool isEnabled) {
|
|||
_skeletonModel->setVisibleInScene(isEnabled, qApp->getMain3DScene());
|
||||
}
|
||||
|
||||
void MyAvatar::setUseAnimPreAndPostRotations(bool isEnabled) {
|
||||
AnimClip::usePreAndPostPoseFromAnim = isEnabled;
|
||||
reset(true);
|
||||
}
|
||||
|
||||
void MyAvatar::setEnableInverseKinematics(bool isEnabled) {
|
||||
_skeletonModel->getRig().setEnableInverseKinematics(isEnabled);
|
||||
}
|
||||
|
@ -1801,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);
|
||||
|
@ -1929,7 +1925,7 @@ void MyAvatar::preDisplaySide(RenderArgs* renderArgs) {
|
|||
_prevShouldDrawHead = shouldDrawHead;
|
||||
}
|
||||
|
||||
const float RENDER_HEAD_CUTOFF_DISTANCE = 0.3f;
|
||||
const float RENDER_HEAD_CUTOFF_DISTANCE = 0.47f;
|
||||
|
||||
bool MyAvatar::cameraInsideHead(const glm::vec3& cameraPosition) const {
|
||||
return glm::length(cameraPosition - getHeadPosition()) < (RENDER_HEAD_CUTOFF_DISTANCE * getModelScale());
|
||||
|
@ -2023,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;
|
||||
|
@ -2036,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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2100,7 +2099,7 @@ void MyAvatar::updateActionMotor(float deltaTime) {
|
|||
_actionMotorVelocity = motorSpeed * direction;
|
||||
} else {
|
||||
// we're interacting with a floor --> simple horizontal speed and exponential decay
|
||||
_actionMotorVelocity = getSensorToWorldScale() * DEFAULT_AVATAR_MAX_WALKING_SPEED * direction;
|
||||
_actionMotorVelocity = getSensorToWorldScale() * _walkSpeed.get() * direction;
|
||||
}
|
||||
|
||||
float boomChange = getDriveKey(ZOOM);
|
||||
|
@ -2692,6 +2691,14 @@ float MyAvatar::getUserEyeHeight() const {
|
|||
return userHeight - userHeight * ratio;
|
||||
}
|
||||
|
||||
float MyAvatar::getWalkSpeed() const {
|
||||
return _walkSpeed.get();
|
||||
}
|
||||
|
||||
void MyAvatar::setWalkSpeed(float value) {
|
||||
_walkSpeed.set(value);
|
||||
}
|
||||
|
||||
glm::vec3 MyAvatar::getPositionForAudio() {
|
||||
switch (_audioListenerMode) {
|
||||
case AudioListenerMode::FROM_HEAD:
|
||||
|
|
|
@ -163,6 +163,8 @@ class MyAvatar : public Avatar {
|
|||
|
||||
Q_PROPERTY(QUuid SELF_ID READ getSelfID CONSTANT)
|
||||
|
||||
Q_PROPERTY(float walkSpeed READ getWalkSpeed WRITE setWalkSpeed);
|
||||
|
||||
const QString DOMINANT_LEFT_HAND = "left";
|
||||
const QString DOMINANT_RIGHT_HAND = "right";
|
||||
|
||||
|
@ -557,6 +559,9 @@ public:
|
|||
|
||||
const QUuid& getSelfID() const { return AVATAR_SELF_ID; }
|
||||
|
||||
void setWalkSpeed(float value);
|
||||
float getWalkSpeed() const;
|
||||
|
||||
public slots:
|
||||
void increaseSize();
|
||||
void decreaseSize();
|
||||
|
@ -594,7 +599,6 @@ public slots:
|
|||
|
||||
bool getEnableMeshVisible() const { return _skeletonModel->isVisible(); }
|
||||
void setEnableMeshVisible(bool isEnabled);
|
||||
void setUseAnimPreAndPostRotations(bool isEnabled);
|
||||
void setEnableInverseKinematics(bool isEnabled);
|
||||
|
||||
QUrl getAnimGraphOverrideUrl() const; // thread-safe
|
||||
|
@ -841,6 +845,9 @@ private:
|
|||
|
||||
// height of user in sensor space, when standing erect.
|
||||
ThreadSafeValueCache<float> _userHeight { DEFAULT_AVATAR_HEIGHT };
|
||||
|
||||
// max unscaled forward movement speed
|
||||
ThreadSafeValueCache<float> _walkSpeed { DEFAULT_AVATAR_MAX_WALKING_SPEED };
|
||||
};
|
||||
|
||||
QScriptValue audioListenModeToScriptValue(QScriptEngine* engine, const AudioListenerMode& audioListenerMode);
|
||||
|
|
|
@ -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}}
|
||||
|
@ -46,6 +47,8 @@ Handler(buy)
|
|||
Handler(receiveAt)
|
||||
Handler(balance)
|
||||
Handler(inventory)
|
||||
Handler(transferHfcToNode)
|
||||
Handler(transferHfcToUsername)
|
||||
|
||||
void Ledger::send(const QString& endpoint, const QString& success, const QString& fail, QNetworkAccessManager::Operation method, AccountManagerAuth::Type authType, QJsonObject request) {
|
||||
auto accountManager = DependencyManager::get<AccountManager>();
|
||||
|
@ -116,23 +119,69 @@ void Ledger::inventory(const QStringList& keys) {
|
|||
keysQuery("inventory", "inventorySuccess", "inventoryFailure");
|
||||
}
|
||||
|
||||
QString amountString(const QString& label, const QString&color, const QJsonValue& moneyValue, const QJsonValue& certsValue) {
|
||||
int money = moneyValue.toInt();
|
||||
int certs = certsValue.toInt();
|
||||
if (money <= 0 && certs <= 0) {
|
||||
return QString();
|
||||
QString hfcString(const QJsonValue& sentValue, const QJsonValue& receivedValue) {
|
||||
int sent = sentValue.toInt();
|
||||
int received = receivedValue.toInt();
|
||||
if (sent <= 0 && received <= 0) {
|
||||
return QString("0 HFC");
|
||||
}
|
||||
QString result(QString("<font color='#%1'> %2").arg(color, label));
|
||||
if (money > 0) {
|
||||
result += QString(" %1 HFC").arg(money);
|
||||
}
|
||||
if (certs > 0) {
|
||||
if (money > 0) {
|
||||
result += QString(",");
|
||||
QString result;
|
||||
if (sent > 0) {
|
||||
result += QString("<font color='#B70A37'><b>-%1 HFC</b></font>").arg(sent);
|
||||
if (received > 0) {
|
||||
result += QString("<br>");
|
||||
}
|
||||
result += QString((certs == 1) ? " %1 certificate" : " %1 certificates").arg(certs);
|
||||
}
|
||||
return result + QString("</font>");
|
||||
if (received > 0) {
|
||||
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, const QString& placename) {
|
||||
if (username.isEmpty()) {
|
||||
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;
|
||||
}
|
||||
return QString("<a href=\"%1%2\">%2</a>").arg(USER_PAGE_BASE_URL, username);
|
||||
}
|
||||
|
||||
QString transactionString(const QJsonObject& valueObject) {
|
||||
int sentCerts = valueObject["sent_certs"].toInt();
|
||||
int receivedCerts = valueObject["received_certs"].toInt();
|
||||
int sent = valueObject["sent_money"].toInt();
|
||||
int dateInteger = valueObject["created_at"].toInt();
|
||||
QString message = valueObject["message"].toString();
|
||||
QDateTime createdAt(QDateTime::fromSecsSinceEpoch(dateInteger, Qt::UTC));
|
||||
QString result;
|
||||
|
||||
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(), valueObject["place_name"].toString());
|
||||
result += QString("Money sent to %1").arg(recipient);
|
||||
} else {
|
||||
QString sender = userLink(valueObject["sender_name"].toString(), valueObject["place_name"].toString());
|
||||
result += QString("Money from %1").arg(sender);
|
||||
}
|
||||
if (!message.isEmpty()) {
|
||||
result += QString("<br>with memo: <i>\"%1\"</i>").arg(message);
|
||||
}
|
||||
} 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;
|
||||
}
|
||||
|
||||
static const QString MARKETPLACE_ITEMS_BASE_URL = NetworkingConstants::METAVERSE_SERVER_URL().toString() + "/marketplace/items/";
|
||||
|
@ -155,16 +204,13 @@ void Ledger::historySuccess(QNetworkReply& reply) {
|
|||
|
||||
// TODO: do this with 0 copies if possible
|
||||
for (auto it = historyArray.begin(); it != historyArray.end(); it++) {
|
||||
// We have 2 text fields to synthesize, the one on the left is a listing
|
||||
// of the HFC in/out of your wallet. The one on the right contains an explaination
|
||||
// of the transaction. That could be just the memo (if it is a regular purchase), or
|
||||
// more text (plus the optional memo) if an hfc transfer
|
||||
auto valueObject = (*it).toObject();
|
||||
QString sent = amountString("sent", "EA4C5F", valueObject["sent_money"], valueObject["sent_certs"]);
|
||||
QString received = amountString("received", "1FC6A6", valueObject["received_money"], valueObject["received_certs"]);
|
||||
|
||||
// turns out on my machine, toLocalTime convert to some weird timezone, yet the
|
||||
// systemTimeZone is correct. To avoid a strange bug with other's systems too, lets
|
||||
// be explicit
|
||||
QDateTime createdAt = QDateTime::fromSecsSinceEpoch(valueObject["created_at"].toInt(), Qt::UTC);
|
||||
QDateTime localCreatedAt = createdAt.toTimeZone(QTimeZone::systemTimeZone());
|
||||
valueObject["text"] = QString("%1%2%3").arg(valueObject["message"].toString(), sent, received);
|
||||
valueObject["hfc_text"] = hfcString(valueObject["sent_money"], valueObject["received_money"]);
|
||||
valueObject["transaction_text"] = transactionString(valueObject);
|
||||
newHistoryArray.push_back(valueObject);
|
||||
}
|
||||
// now copy the rest of the json -- this is inefficient
|
||||
|
@ -198,11 +244,17 @@ void Ledger::accountSuccess(QNetworkReply& reply) {
|
|||
auto salt = QByteArray::fromBase64(data["salt"].toString().toUtf8());
|
||||
auto iv = QByteArray::fromBase64(data["iv"].toString().toUtf8());
|
||||
auto ckey = QByteArray::fromBase64(data["ckey"].toString().toUtf8());
|
||||
QString remotePublicKey = data["public_key"].toString();
|
||||
|
||||
wallet->setSalt(salt);
|
||||
wallet->setIv(iv);
|
||||
wallet->setCKey(ckey);
|
||||
|
||||
QStringList localPublicKeys = wallet->listPublicKeys();
|
||||
if (remotePublicKey.isEmpty() && !localPublicKeys.isEmpty()) {
|
||||
receiveAt(localPublicKeys.first(), "");
|
||||
}
|
||||
|
||||
// none of the hfc account info should be emitted
|
||||
emit accountResult(QJsonObject{ {"status", "success"} });
|
||||
}
|
||||
|
@ -261,3 +313,26 @@ void Ledger::certificateInfo(const QString& certificateId) {
|
|||
request["certificate_id"] = certificateId;
|
||||
send(endpoint, "certificateInfoSuccess", "certificateInfoFailure", QNetworkAccessManager::PutOperation, AccountManagerAuth::None, request);
|
||||
}
|
||||
|
||||
void Ledger::transferHfcToNode(const QString& hfc_key, const QString& nodeID, const int& amount, const QString& optionalMessage) {
|
||||
QJsonObject transaction;
|
||||
transaction["public_key"] = hfc_key;
|
||||
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");
|
||||
}
|
||||
|
||||
void Ledger::transferHfcToUsername(const QString& hfc_key, const QString& username, const int& amount, const QString& optionalMessage) {
|
||||
QJsonObject transaction;
|
||||
transaction["public_key"] = hfc_key;
|
||||
transaction["username"] = username;
|
||||
transaction["quantity"] = amount;
|
||||
transaction["message"] = optionalMessage;
|
||||
QJsonDocument transactionDoc{ transaction };
|
||||
auto transactionString = transactionDoc.toJson(QJsonDocument::Compact);
|
||||
signedSend("transaction", transactionString, hfc_key, "transfer_hfc_to_user", "transferHfcToUsernameSuccess", "transferHfcToUsernameFailure");
|
||||
}
|
||||
|
|
|
@ -33,6 +33,8 @@ public:
|
|||
void account();
|
||||
void updateLocation(const QString& asset_id, const QString location, const bool controlledFailure = false);
|
||||
void certificateInfo(const QString& certificateId);
|
||||
void transferHfcToNode(const QString& hfc_key, const QString& nodeID, const int& amount, const QString& optionalMessage);
|
||||
void transferHfcToUsername(const QString& hfc_key, const QString& username, const int& amount, const QString& optionalMessage);
|
||||
|
||||
enum CertificateStatus {
|
||||
CERTIFICATE_STATUS_UNKNOWN = 0,
|
||||
|
@ -51,6 +53,8 @@ signals:
|
|||
void accountResult(QJsonObject result);
|
||||
void locationUpdateResult(QJsonObject result);
|
||||
void certificateInfoResult(QJsonObject result);
|
||||
void transferHfcToNodeResult(QJsonObject result);
|
||||
void transferHfcToUsernameResult(QJsonObject result);
|
||||
|
||||
void updateCertificateStatus(const QString& certID, uint certStatus);
|
||||
|
||||
|
@ -71,6 +75,10 @@ public slots:
|
|||
void updateLocationFailure(QNetworkReply& reply);
|
||||
void certificateInfoSuccess(QNetworkReply& reply);
|
||||
void certificateInfoFailure(QNetworkReply& reply);
|
||||
void transferHfcToNodeSuccess(QNetworkReply& reply);
|
||||
void transferHfcToNodeFailure(QNetworkReply& reply);
|
||||
void transferHfcToUsernameSuccess(QNetworkReply& reply);
|
||||
void transferHfcToUsernameFailure(QNetworkReply& reply);
|
||||
|
||||
private:
|
||||
QJsonObject apiResponse(const QString& label, QNetworkReply& reply);
|
||||
|
|
|
@ -29,6 +29,8 @@ QmlCommerce::QmlCommerce() {
|
|||
connect(wallet.data(), &Wallet::walletStatusResult, this, &QmlCommerce::walletStatusResult);
|
||||
connect(ledger.data(), &Ledger::certificateInfoResult, this, &QmlCommerce::certificateInfoResult);
|
||||
connect(ledger.data(), &Ledger::updateCertificateStatus, this, &QmlCommerce::updateCertificateStatus);
|
||||
connect(ledger.data(), &Ledger::transferHfcToNodeResult, this, &QmlCommerce::transferHfcToNodeResult);
|
||||
connect(ledger.data(), &Ledger::transferHfcToUsernameResult, this, &QmlCommerce::transferHfcToUsernameResult);
|
||||
|
||||
auto accountManager = DependencyManager::get<AccountManager>();
|
||||
connect(accountManager.data(), &AccountManager::usernameChanged, this, [&]() {
|
||||
|
@ -137,3 +139,27 @@ void QmlCommerce::certificateInfo(const QString& certificateId) {
|
|||
auto ledger = DependencyManager::get<Ledger>();
|
||||
ledger->certificateInfo(certificateId);
|
||||
}
|
||||
|
||||
void QmlCommerce::transferHfcToNode(const QString& nodeID, const int& amount, const QString& optionalMessage) {
|
||||
auto ledger = DependencyManager::get<Ledger>();
|
||||
auto wallet = DependencyManager::get<Wallet>();
|
||||
QStringList keys = wallet->listPublicKeys();
|
||||
if (keys.count() == 0) {
|
||||
QJsonObject result{ { "status", "fail" },{ "message", "Uninitialized Wallet." } };
|
||||
return emit buyResult(result);
|
||||
}
|
||||
QString key = keys[0];
|
||||
ledger->transferHfcToNode(key, nodeID, amount, optionalMessage);
|
||||
}
|
||||
|
||||
void QmlCommerce::transferHfcToUsername(const QString& username, const int& amount, const QString& optionalMessage) {
|
||||
auto ledger = DependencyManager::get<Ledger>();
|
||||
auto wallet = DependencyManager::get<Wallet>();
|
||||
QStringList keys = wallet->listPublicKeys();
|
||||
if (keys.count() == 0) {
|
||||
QJsonObject result{ { "status", "fail" },{ "message", "Uninitialized Wallet." } };
|
||||
return emit buyResult(result);
|
||||
}
|
||||
QString key = keys[0];
|
||||
ledger->transferHfcToUsername(key, username, amount, optionalMessage);
|
||||
}
|
||||
|
|
|
@ -45,6 +45,9 @@ signals:
|
|||
|
||||
void updateCertificateStatus(const QString& certID, uint certStatus);
|
||||
|
||||
void transferHfcToNodeResult(QJsonObject result);
|
||||
void transferHfcToUsernameResult(QJsonObject result);
|
||||
|
||||
protected:
|
||||
Q_INVOKABLE void getWalletStatus();
|
||||
|
||||
|
@ -65,6 +68,9 @@ protected:
|
|||
Q_INVOKABLE void account();
|
||||
|
||||
Q_INVOKABLE void certificateInfo(const QString& certificateId);
|
||||
|
||||
Q_INVOKABLE void transferHfcToNode(const QString& nodeID, const int& amount, const QString& optionalMessage);
|
||||
Q_INVOKABLE void transferHfcToUsername(const QString& username, const int& amount, const QString& optionalMessage);
|
||||
};
|
||||
|
||||
#endif // hifi_QmlCommerce_h
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -1,36 +0,0 @@
|
|||
//
|
||||
// AccountScriptingInterface.cpp
|
||||
// interface/src/scripting
|
||||
//
|
||||
// Created by Stojce Slavkovski on 6/07/14.
|
||||
// Copyright 2014 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include "AccountManager.h"
|
||||
|
||||
#include "AccountScriptingInterface.h"
|
||||
#include "GlobalServicesScriptingInterface.h"
|
||||
|
||||
AccountScriptingInterface* AccountScriptingInterface::getInstance() {
|
||||
static AccountScriptingInterface sharedInstance;
|
||||
return &sharedInstance;
|
||||
}
|
||||
|
||||
bool AccountScriptingInterface::isLoggedIn() {
|
||||
return GlobalServicesScriptingInterface::getInstance()->isLoggedIn();
|
||||
}
|
||||
|
||||
void AccountScriptingInterface::logOut() {
|
||||
GlobalServicesScriptingInterface::getInstance()->logOut();
|
||||
}
|
||||
|
||||
bool AccountScriptingInterface::loggedIn() const {
|
||||
return GlobalServicesScriptingInterface::getInstance()->loggedIn();
|
||||
}
|
||||
|
||||
QString AccountScriptingInterface::getUsername() {
|
||||
return GlobalServicesScriptingInterface::getInstance()->getUsername();
|
||||
}
|
|
@ -1,60 +0,0 @@
|
|||
//
|
||||
// AccountScriptingInterface.h
|
||||
// interface/src/scripting
|
||||
//
|
||||
// Created by Stojce Slavkovski on 6/07/14.
|
||||
// Copyright 2014 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#ifndef hifi_AccountScriptingInterface_h
|
||||
#define hifi_AccountScriptingInterface_h
|
||||
|
||||
#include <QObject>
|
||||
|
||||
class AccountScriptingInterface : public QObject {
|
||||
Q_OBJECT
|
||||
|
||||
/**jsdoc
|
||||
* @namespace Account
|
||||
* @property username {String} username if user is logged in, otherwise it returns "Unknown user"
|
||||
*/
|
||||
Q_PROPERTY(QString username READ getUsername)
|
||||
Q_PROPERTY(bool loggedIn READ loggedIn)
|
||||
|
||||
signals:
|
||||
|
||||
/**jsdoc
|
||||
* Triggered when username has changed.
|
||||
* @function Account.usernameChanged
|
||||
* @return {Signal}
|
||||
*/
|
||||
void usernameChanged();
|
||||
void loggedInChanged(bool loggedIn);
|
||||
|
||||
public slots:
|
||||
static AccountScriptingInterface* getInstance();
|
||||
|
||||
/**jsdoc
|
||||
* Returns the username for the currently logged in High Fidelity metaverse account.
|
||||
* @function Account.getUsername
|
||||
* @return {string} username if user is logged in, otherwise it returns "Unknown user"
|
||||
*/
|
||||
QString getUsername();
|
||||
|
||||
/**jsdoc
|
||||
* Determine if the user is logged into the High Fidleity metaverse.
|
||||
* @function Account.isLoggedIn
|
||||
* @return {bool} true when user is logged into the High Fidelity metaverse.
|
||||
*/
|
||||
bool isLoggedIn();
|
||||
void logOut();
|
||||
|
||||
public:
|
||||
AccountScriptingInterface(QObject* parent = nullptr) {}
|
||||
bool loggedIn() const;
|
||||
};
|
||||
|
||||
#endif // hifi_AccountScriptingInterface_h
|
|
@ -1,5 +1,5 @@
|
|||
//
|
||||
// GlobalServicesScriptingInterface.cpp
|
||||
// AccountServicesScriptingInterface.cpp
|
||||
// interface/src/scripting
|
||||
//
|
||||
// Created by Thijs Wenker on 9/10/14.
|
||||
|
@ -14,41 +14,41 @@
|
|||
#include "DiscoverabilityManager.h"
|
||||
#include "ResourceCache.h"
|
||||
|
||||
#include "GlobalServicesScriptingInterface.h"
|
||||
#include "AccountServicesScriptingInterface.h"
|
||||
|
||||
GlobalServicesScriptingInterface::GlobalServicesScriptingInterface() {
|
||||
AccountServicesScriptingInterface::AccountServicesScriptingInterface() {
|
||||
auto accountManager = DependencyManager::get<AccountManager>();
|
||||
connect(accountManager.data(), &AccountManager::usernameChanged, this, &GlobalServicesScriptingInterface::onUsernameChanged);
|
||||
connect(accountManager.data(), &AccountManager::logoutComplete, this, &GlobalServicesScriptingInterface::loggedOut);
|
||||
connect(accountManager.data(), &AccountManager::loginComplete, this, &GlobalServicesScriptingInterface::connected);
|
||||
connect(accountManager.data(), &AccountManager::usernameChanged, this, &AccountServicesScriptingInterface::onUsernameChanged);
|
||||
connect(accountManager.data(), &AccountManager::logoutComplete, this, &AccountServicesScriptingInterface::loggedOut);
|
||||
connect(accountManager.data(), &AccountManager::loginComplete, this, &AccountServicesScriptingInterface::connected);
|
||||
|
||||
_downloading = false;
|
||||
QTimer* checkDownloadTimer = new QTimer(this);
|
||||
connect(checkDownloadTimer, &QTimer::timeout, this, &GlobalServicesScriptingInterface::checkDownloadInfo);
|
||||
connect(checkDownloadTimer, &QTimer::timeout, this, &AccountServicesScriptingInterface::checkDownloadInfo);
|
||||
const int CHECK_DOWNLOAD_INTERVAL = MSECS_PER_SECOND / 2;
|
||||
checkDownloadTimer->start(CHECK_DOWNLOAD_INTERVAL);
|
||||
|
||||
auto discoverabilityManager = DependencyManager::get<DiscoverabilityManager>();
|
||||
connect(discoverabilityManager.data(), &DiscoverabilityManager::discoverabilityModeChanged,
|
||||
this, &GlobalServicesScriptingInterface::discoverabilityModeChanged);
|
||||
this, &AccountServicesScriptingInterface::discoverabilityModeChanged);
|
||||
|
||||
_loggedIn = isLoggedIn();
|
||||
emit loggedInChanged(_loggedIn);
|
||||
}
|
||||
|
||||
GlobalServicesScriptingInterface::~GlobalServicesScriptingInterface() {
|
||||
AccountServicesScriptingInterface::~AccountServicesScriptingInterface() {
|
||||
auto accountManager = DependencyManager::get<AccountManager>();
|
||||
disconnect(accountManager.data(), &AccountManager::usernameChanged, this, &GlobalServicesScriptingInterface::onUsernameChanged);
|
||||
disconnect(accountManager.data(), &AccountManager::logoutComplete, this, &GlobalServicesScriptingInterface::loggedOut);
|
||||
disconnect(accountManager.data(), &AccountManager::loginComplete, this, &GlobalServicesScriptingInterface::connected);
|
||||
disconnect(accountManager.data(), &AccountManager::usernameChanged, this, &AccountServicesScriptingInterface::onUsernameChanged);
|
||||
disconnect(accountManager.data(), &AccountManager::logoutComplete, this, &AccountServicesScriptingInterface::loggedOut);
|
||||
disconnect(accountManager.data(), &AccountManager::loginComplete, this, &AccountServicesScriptingInterface::connected);
|
||||
}
|
||||
|
||||
GlobalServicesScriptingInterface* GlobalServicesScriptingInterface::getInstance() {
|
||||
static GlobalServicesScriptingInterface sharedInstance;
|
||||
AccountServicesScriptingInterface* AccountServicesScriptingInterface::getInstance() {
|
||||
static AccountServicesScriptingInterface sharedInstance;
|
||||
return &sharedInstance;
|
||||
}
|
||||
|
||||
const QString GlobalServicesScriptingInterface::getUsername() const {
|
||||
const QString AccountServicesScriptingInterface::getUsername() const {
|
||||
auto accountManager = DependencyManager::get<AccountManager>();
|
||||
if (accountManager->isLoggedIn()) {
|
||||
return accountManager->getAccountInfo().getUsername();
|
||||
|
@ -57,31 +57,31 @@ const QString GlobalServicesScriptingInterface::getUsername() const {
|
|||
}
|
||||
}
|
||||
|
||||
bool GlobalServicesScriptingInterface::isLoggedIn() {
|
||||
bool AccountServicesScriptingInterface::isLoggedIn() {
|
||||
auto accountManager = DependencyManager::get<AccountManager>();
|
||||
return accountManager->isLoggedIn();
|
||||
}
|
||||
|
||||
bool GlobalServicesScriptingInterface::checkAndSignalForAccessToken() {
|
||||
bool AccountServicesScriptingInterface::checkAndSignalForAccessToken() {
|
||||
auto accountManager = DependencyManager::get<AccountManager>();
|
||||
return accountManager->checkAndSignalForAccessToken();
|
||||
}
|
||||
|
||||
void GlobalServicesScriptingInterface::logOut() {
|
||||
void AccountServicesScriptingInterface::logOut() {
|
||||
auto accountManager = DependencyManager::get<AccountManager>();
|
||||
return accountManager->logout();
|
||||
}
|
||||
|
||||
void GlobalServicesScriptingInterface::loggedOut() {
|
||||
emit GlobalServicesScriptingInterface::disconnected(QString("logout"));
|
||||
void AccountServicesScriptingInterface::loggedOut() {
|
||||
emit AccountServicesScriptingInterface::disconnected(QString("logout"));
|
||||
}
|
||||
|
||||
QString GlobalServicesScriptingInterface::getFindableBy() const {
|
||||
QString AccountServicesScriptingInterface::getFindableBy() const {
|
||||
auto discoverabilityManager = DependencyManager::get<DiscoverabilityManager>();
|
||||
return DiscoverabilityManager::findableByString(discoverabilityManager->getDiscoverabilityMode());
|
||||
}
|
||||
|
||||
void GlobalServicesScriptingInterface::setFindableBy(const QString& discoverabilityMode) {
|
||||
void AccountServicesScriptingInterface::setFindableBy(const QString& discoverabilityMode) {
|
||||
auto discoverabilityManager = DependencyManager::get<DiscoverabilityManager>();
|
||||
if (discoverabilityMode.toLower() == "none") {
|
||||
discoverabilityManager->setDiscoverabilityMode(Discoverability::None);
|
||||
|
@ -96,11 +96,11 @@ void GlobalServicesScriptingInterface::setFindableBy(const QString& discoverabil
|
|||
}
|
||||
}
|
||||
|
||||
void GlobalServicesScriptingInterface::discoverabilityModeChanged(Discoverability::Mode discoverabilityMode) {
|
||||
void AccountServicesScriptingInterface::discoverabilityModeChanged(Discoverability::Mode discoverabilityMode) {
|
||||
emit findableByChanged(DiscoverabilityManager::findableByString(discoverabilityMode));
|
||||
}
|
||||
|
||||
void GlobalServicesScriptingInterface::onUsernameChanged(const QString& username) {
|
||||
void AccountServicesScriptingInterface::onUsernameChanged(const QString& username) {
|
||||
_loggedIn = (username != QString());
|
||||
emit myUsernameChanged(username);
|
||||
emit loggedInChanged(_loggedIn);
|
||||
|
@ -135,7 +135,7 @@ void DownloadInfoResultFromScriptValue(const QScriptValue& object, DownloadInfoR
|
|||
result.pending = object.property("pending").toVariant().toFloat();
|
||||
}
|
||||
|
||||
DownloadInfoResult GlobalServicesScriptingInterface::getDownloadInfo() {
|
||||
DownloadInfoResult AccountServicesScriptingInterface::getDownloadInfo() {
|
||||
DownloadInfoResult result;
|
||||
foreach(const auto& resource, ResourceCache::getLoadingRequests()) {
|
||||
result.downloading.append(resource->getProgress() * 100.0f);
|
||||
|
@ -144,7 +144,7 @@ DownloadInfoResult GlobalServicesScriptingInterface::getDownloadInfo() {
|
|||
return result;
|
||||
}
|
||||
|
||||
void GlobalServicesScriptingInterface::checkDownloadInfo() {
|
||||
void AccountServicesScriptingInterface::checkDownloadInfo() {
|
||||
DownloadInfoResult downloadInfo = getDownloadInfo();
|
||||
bool downloading = downloadInfo.downloading.count() > 0 || downloadInfo.pending > 0;
|
||||
|
||||
|
@ -155,7 +155,7 @@ void GlobalServicesScriptingInterface::checkDownloadInfo() {
|
|||
}
|
||||
}
|
||||
|
||||
void GlobalServicesScriptingInterface::updateDownloadInfo() {
|
||||
void AccountServicesScriptingInterface::updateDownloadInfo() {
|
||||
emit downloadInfoChanged(getDownloadInfo());
|
||||
}
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
//
|
||||
// GlobalServicesScriptingInterface.h
|
||||
// AccountServicesScriptingInterface.h
|
||||
// interface/src/scripting
|
||||
//
|
||||
// Created by Thijs Wenker on 9/10/14.
|
||||
|
@ -9,8 +9,8 @@
|
|||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#ifndef hifi_GlobalServicesScriptingInterface_h
|
||||
#define hifi_GlobalServicesScriptingInterface_h
|
||||
#ifndef hifi_AccountServicesScriptingInterface_h
|
||||
#define hifi_AccountServicesScriptingInterface_h
|
||||
|
||||
#include <QObject>
|
||||
#include <QScriptContext>
|
||||
|
@ -32,7 +32,7 @@ Q_DECLARE_METATYPE(DownloadInfoResult)
|
|||
QScriptValue DownloadInfoResultToScriptValue(QScriptEngine* engine, const DownloadInfoResult& result);
|
||||
void DownloadInfoResultFromScriptValue(const QScriptValue& object, DownloadInfoResult& result);
|
||||
|
||||
class GlobalServicesScriptingInterface : public QObject {
|
||||
class AccountServicesScriptingInterface : public QObject {
|
||||
Q_OBJECT
|
||||
|
||||
Q_PROPERTY(QString username READ getUsername NOTIFY myUsernameChanged)
|
||||
|
@ -41,7 +41,7 @@ class GlobalServicesScriptingInterface : public QObject {
|
|||
Q_PROPERTY(QUrl metaverseServerURL READ getMetaverseServerURL)
|
||||
|
||||
public:
|
||||
static GlobalServicesScriptingInterface* getInstance();
|
||||
static AccountServicesScriptingInterface* getInstance();
|
||||
|
||||
const QString getUsername() const;
|
||||
bool loggedIn() const { return _loggedIn; }
|
||||
|
@ -74,11 +74,11 @@ signals:
|
|||
void loggedInChanged(bool loggedIn);
|
||||
|
||||
private:
|
||||
GlobalServicesScriptingInterface();
|
||||
~GlobalServicesScriptingInterface();
|
||||
AccountServicesScriptingInterface();
|
||||
~AccountServicesScriptingInterface();
|
||||
|
||||
bool _downloading;
|
||||
bool _loggedIn{ false };
|
||||
};
|
||||
|
||||
#endif // hifi_GlobalServicesScriptingInterface_h
|
||||
#endif // hifi_AccountServicesScriptingInterface_h
|
|
@ -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;
|
||||
}
|
||||
|
@ -411,6 +416,11 @@ int WindowScriptingInterface::getY() {
|
|||
}
|
||||
|
||||
void WindowScriptingInterface::copyToClipboard(const QString& text) {
|
||||
if (QThread::currentThread() != qApp->thread()) {
|
||||
QMetaObject::invokeMethod(this, "copyToClipboard", Q_ARG(QString, text));
|
||||
return;
|
||||
}
|
||||
|
||||
qDebug() << "Copying";
|
||||
QApplication::clipboard()->setText(text);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -386,8 +386,6 @@ void Circle3DOverlay::setProperties(const QVariantMap& properties) {
|
|||
* the pulse multiplier is applied out of phase with the pulse period. (The magnitude of the property isn't otherwise
|
||||
* used.)
|
||||
* @property {boolean} visible=true - If <code>true</code>, the overlay is rendered, otherwise it is not rendered.
|
||||
* @property {string} anchor="" - If set to <code>"MyAvatar"</code> then the overlay is attached to your avatar, moving and
|
||||
* rotating as you move your avatar.
|
||||
*
|
||||
* @property {string} name="" - A friendly name for the overlay.
|
||||
* @property {Vec3} position - The position of the overlay center. Synonyms: <code>p1</code>, <code>point</code>, and
|
||||
|
|