3
0
Fork 0
mirror of https://github.com/lubosz/overte.git synced 2025-04-26 18:15:49 +02:00

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

This commit is contained in:
ZappoMan 2018-01-25 11:39:56 -08:00
commit 4497302a2b
296 changed files with 8872 additions and 4971 deletions
.gitignoreBUILD_LINUX_CHEATSHEET.mdCMakeLists.txt
android
assignment-client/src/avatars
cmake
interface
libraries
animation/src
audio/src
avatars-renderer/src/avatars-renderer

9
.gitignore vendored
View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -1,6 +0,0 @@
<RCC>
<qresource prefix="/">
<file>simple.qml</file>
<file>+android/simple.qml</file>
</qresource>
</RCC>

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

View file

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

View file

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

View file

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

View file

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

View file

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

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

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

Binary file not shown.

Before

(image error) Size: 3.3 KiB

After

(image error) Size: 5.1 KiB

Binary file not shown.

Before

(image error) Size: 4.1 KiB

After

(image error) Size: 4.9 KiB

Binary file not shown.

Before

(image error) Size: 2.2 KiB

After

(image error) Size: 4.2 KiB

Binary file not shown.

Before

(image error) Size: 2.5 KiB

After

(image error) Size: 4.3 KiB

Binary file not shown.

Before

(image error) Size: 4.7 KiB

After

(image error) Size: 5.8 KiB

Binary file not shown.

Before

(image error) Size: 6 KiB

After

(image error) Size: 5.5 KiB

Binary file not shown.

Before

(image error) Size: 7.5 KiB

After

(image error) Size: 7.3 KiB

Binary file not shown.

Before

(image error) Size: 9.8 KiB

After

(image error) Size: 6.7 KiB

Binary file not shown.

Before

(image error) Size: 10 KiB

After

(image error) Size: 8.9 KiB

Binary file not shown.

Before

(image error) Size: 14 KiB

After

(image error) Size: 8.2 KiB

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

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

View file

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

View file

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

View file

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

View file

View file

@ -0,0 +1,21 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 22.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 100 100.8" style="enable-background:new 0 0 100 100.8;" xml:space="preserve">
<style type="text/css">
.st0{fill:#FFFFFF;}
</style>
<path class="st0" d="M26.7,83.9c7.3,1.2,14.8,1.8,22.1,1.8c0.4,0,0.8,0,1.2,0c7.8-0.1,15.6-0.8,23.4-2.2l0,0
c5.7-1.1,11.3-6.6,12.5-12.3C87.3,64.2,88,57,88,50s-0.7-14.2-2.1-21.2c-1.2-5.6-6.8-11.1-12.5-12.2c-7.7-1.4-15.6-2.2-23.4-2.2
c-7.7-0.1-15.6,0.5-23.4,1.8c-5.7,1-11.4,6.5-12.6,12.3c-1.4,7.2-2.1,14.4-2.1,21.6s0.7,14.4,2.1,21.7
C15.3,77.4,20.9,82.9,26.7,83.9z M20.9,29.8c0.6-2.9,4-6.3,6.9-6.8c7-1.1,14-1.7,21-1.7c0.4,0,0.8,0,1.2,0
c7.4,0.1,14.8,0.8,22.1,2.1c2.9,0.6,6.4,3.9,6.9,6.7c1.3,6.6,1.9,13.3,1.9,19.9c0,6.6-0.6,13.3-1.9,19.8c-0.6,2.8-4,6.2-6.9,6.8
c-7.3,1.3-14.8,2.1-22.1,2.1c-7.4,0.1-14.8-0.5-22.1-1.7c-2.9-0.5-6.3-3.9-6.9-6.7c-1.3-6.7-2-13.5-2-20.3
C19,43.3,19.6,36.4,20.9,29.8z"/>
<path class="st0" d="M32.3,61.4c-0.5,1.3-0.1,2.8,0.9,3.8c0.3,0.3,7.2,6.6,15.9,6.6c0.8,0,1.7-0.1,2.6-0.2
c9.8-1.5,15.5-11.1,15.8-11.5c0.7-1.2,0.6-2.8-0.2-3.9c-0.9-1.1-2.3-1.6-3.7-1.3c-9.2,2.5-18.6,3.9-28.1,4.2
C34,59.1,32.8,60,32.3,61.4z"/>
<circle class="st0" cx="36.5" cy="42.8" r="9"/>
<path class="st0" d="M61.4,44.1h6.1c1.9,0,3.3-1.5,3.3-3.3c0-1.9-1.5-3.3-3.3-3.3h-6.1c-1.9,0-3.3,1.5-3.3,3.3
C58.1,42.7,59.6,44.1,61.4,44.1z"/>
</svg>

After

(image error) Size: 1.5 KiB

Binary file not shown.

After

(image error) Size: 52 KiB

View 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

Binary file not shown.

After

(image error) Size: 2.6 MiB

Binary file not shown.

After

(image error) Size: 2.9 MiB

Binary file not shown.

After

(image error) Size: 645 KiB

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

View file

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

View file

@ -24,10 +24,13 @@ TextField {
property bool isSearchField: false
property string label: ""
property real controlHeight: height + (textFieldLabel.visible ? textFieldLabel.height + 1 : 0)
property bool hasDefocusedBorder: true;
property bool hasRoundedBorder: false
property int roundedBorderRadius: 4
property bool error: false;
property bool hasClearButton: false;
property string leftPlaceholderGlyph: "";
property string leftPermanentGlyph: "";
property string centerPlaceholderGlyph: "";
placeholderText: textField.placeholderText
@ -101,12 +104,12 @@ TextField {
}
}
border.color: textField.error ? hifi.colors.redHighlight :
(textField.activeFocus ? hifi.colors.primaryHighlight : (isFaintGrayColorScheme ? hifi.colors.lightGrayText : hifi.colors.lightGray))
(textField.activeFocus ? hifi.colors.primaryHighlight : (hasDefocusedBorder ? (isFaintGrayColorScheme ? hifi.colors.lightGrayText : hifi.colors.lightGray) : color))
border.width: textField.activeFocus || hasRoundedBorder || textField.error ? 1 : 0
radius: isSearchField ? textField.height / 2 : (hasRoundedBorder ? 4 : 0)
radius: isSearchField ? textField.height / 2 : (hasRoundedBorder ? roundedBorderRadius : 0)
HiFiGlyphs {
text: textField.leftPlaceholderGlyph;
text: textField.leftPermanentGlyph;
color: textColor;
size: hifi.fontSizes.textFieldSearchIcon;
anchors.left: parent.left;
@ -115,6 +118,15 @@ TextField {
visible: text;
}
HiFiGlyphs {
text: textField.centerPlaceholderGlyph;
color: textColor;
size: parent.height;
anchors.horizontalCenter: parent.horizontalCenter;
anchors.verticalCenter: parent.verticalCenter;
visible: text && !textField.focus && textField.text === "";
}
HiFiGlyphs {
text: hifi.glyphs.search
color: textColor
@ -145,7 +157,7 @@ TextField {
placeholderTextColor: isFaintGrayColorScheme ? hifi.colors.lightGrayText : hifi.colors.lightGray
selectedTextColor: hifi.colors.black
selectionColor: hifi.colors.primaryHighlight
padding.left: ((isSearchField || textField.leftPlaceholderGlyph !== "") ? textField.height - 2 : 0) + hifi.dimensions.textPadding
padding.left: hasRoundedBorder ? textField.height / 2 : ((isSearchField || textField.leftPermanentGlyph !== "") ? textField.height - 2 : 0) + hifi.dimensions.textPadding
padding.right: (hasClearButton ? textField.height - 2 : 0) + hifi.dimensions.textPadding
}

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

View file

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

View file

@ -17,6 +17,7 @@ ListModel {
id: root;
property string sortColumnName: "";
property bool isSortingDescending: true;
property bool valuesAreNumerical: false;
function swap(a, b) {
if (a < b) {
@ -29,26 +30,51 @@ ListModel {
}
function partition(begin, end, pivot) {
var piv = get(pivot)[sortColumnName];
swap(pivot, end - 1);
var store = begin;
if (valuesAreNumerical) {
var piv = get(pivot)[sortColumnName];
swap(pivot, end - 1);
var store = begin;
for (var i = begin; i < end - 1; ++i) {
if (isSortingDescending) {
if (get(i)[sortColumnName] < piv) {
swap(store, i);
++store;
}
} else {
if (get(i)[sortColumnName] > piv) {
swap(store, i);
++store;
for (var i = begin; i < end - 1; ++i) {
var currentElement = get(i)[sortColumnName];
if (isSortingDescending) {
if (currentElement < piv) {
swap(store, i);
++store;
}
} else {
if (currentElement > piv) {
swap(store, i);
++store;
}
}
}
}
swap(end - 1, store);
swap(end - 1, store);
return store;
return store;
} else {
var piv = get(pivot)[sortColumnName].toLowerCase();
swap(pivot, end - 1);
var store = begin;
for (var i = begin; i < end - 1; ++i) {
var currentElement = get(i)[sortColumnName].toLowerCase();
if (isSortingDescending) {
if (currentElement < piv) {
swap(store, i);
++store;
}
} else {
if (currentElement > piv) {
swap(store, i);
++store;
}
}
}
swap(end - 1, store);
return store;
}
}
function qsort(begin, end) {

View file

@ -677,7 +677,7 @@ Rectangle {
}
}
if (sameItemCount !== tempPurchasesModel.count) {
if (sameItemCount !== tempPurchasesModel.count || filterBar.text !== "") {
filteredPurchasesModel.clear();
for (var i = 0; i < tempPurchasesModel.count; i++) {
filteredPurchasesModel.append(tempPurchasesModel.get(i));

View file

@ -193,7 +193,7 @@ Item {
color: hifi.colors.white;
}
// "Change Passphrase" button
// "Change Security Pic" button
HifiControlsUit.Button {
id: changeSecurityImageButton;
color: hifi.buttons.blue;

View file

@ -34,13 +34,11 @@ Item {
securityImageChangePageSecurityImage.source = "image://security/securityImage";
if (exists) { // Success submitting new security image
if (root.justSubmitted) {
root.resetSubmitButton();
sendSignalToWallet({method: "walletSecurity_changeSecurityImageSuccess"});
root.justSubmitted = false;
}
} else if (root.justSubmitted) {
// Error submitting new security image.
root.resetSubmitButton();
root.justSubmitted = false;
}
}
@ -180,7 +178,8 @@ Item {
// "Submit" button
HifiControlsUit.Button {
id: securityImageSubmitButton;
enabled: securityImageSelection.currentIndex !== -1;
text: root.justSubmitted ? "Submitting..." : "Submit";
enabled: securityImageSelection.currentIndex !== -1 && !root.justSubmitted;
color: hifi.buttons.blue;
colorScheme: hifi.colorSchemes.dark;
anchors.top: parent.top;
@ -188,11 +187,8 @@ Item {
anchors.right: parent.right;
anchors.rightMargin: 20;
width: 150;
text: "Submit";
onClicked: {
root.justSubmitted = true;
securityImageSubmitButton.text = "Submitting...";
securityImageSubmitButton.enabled = false;
var securityImagePath = securityImageSelection.getImagePathFromImageID(securityImageSelection.getSelectedImageIndex())
Commerce.chooseSecurityImage(securityImagePath);
}
@ -205,11 +201,6 @@ Item {
signal sendSignalToWallet(var msg);
function resetSubmitButton() {
securityImageSubmitButton.enabled = true;
securityImageSubmitButton.text = "Submit";
}
function initModel() {
securityImageSelection.initModel();
}

View file

@ -24,7 +24,7 @@ Item {
HifiConstants { id: hifi; }
id: root;
property int currentIndex: securityImageGrid.currentIndex;
property alias currentIndex: securityImageGrid.currentIndex;
// This will cause a bug -- if you bring up security image selection in HUD mode while
// in HMD while having HMD preview enabled, then move, then finish passphrase selection,
@ -98,6 +98,11 @@ Item {
function initModel() {
gridModel.initModel();
securityImageGrid.currentIndex = -1;
}
function resetSelection() {
securityImageGrid.currentIndex = -1;
}
//
// FUNCTION DEFINITIONS END

View file

@ -389,7 +389,7 @@ Rectangle {
//
Item {
id: tabButtonsContainer;
visible: !needsLogIn.visible && root.activeView !== "passphraseChange" && root.activeView !== "securityImageChange";
visible: !needsLogIn.visible && root.activeView !== "passphraseChange" && root.activeView !== "securityImageChange" && sendMoney.currentActiveView !== "sendMoneyStep";
property int numTabs: 5;
// Size
width: root.width;

View file

@ -392,7 +392,6 @@ Item {
width: 118;
height: paintedHeight;
wrapMode: Text.WordWrap;
font.bold: true;
// Alignment
horizontalAlignment: Text.AlignRight;
}

View file

@ -348,6 +348,7 @@ Item {
width: 200;
text: "Back"
onClicked: {
securityImageSelection.resetSelection();
root.activeView = "step_1";
}
}
@ -516,6 +517,7 @@ Item {
width: 200;
text: "Back"
onClicked: {
securityImageSelection.resetSelection();
root.lastPage = "step_3";
root.activeView = "step_2";
}

View file

@ -29,13 +29,13 @@ Item {
property string userName;
property string profilePicUrl;
height: 65;
height: 75;
width: parent.width;
Rectangle {
id: mainContainer;
// Style
color: root.isSelected ? hifi.colors.faintGray : hifi.colors.white;
color: root.isSelected ? hifi.colors.faintGray80 : hifi.colors.white;
// Size
anchors.left: parent.left;
anchors.right: parent.right;
@ -49,7 +49,7 @@ Item {
anchors.verticalCenter: parent.verticalCenter;
anchors.left: parent.left;
anchors.leftMargin: 36;
height: root.height - 15;
height: 50;
width: visible ? height : 0;
clip: true;
Image {
@ -83,15 +83,15 @@ Item {
RalewaySemiBold {
id: userName;
anchors.left: avatarImage.right;
anchors.leftMargin: 16;
anchors.leftMargin: 12;
anchors.top: parent.top;
anchors.bottom: parent.bottom;
anchors.right: chooseButton.visible ? chooseButton.left : parent.right;
anchors.rightMargin: chooseButton.visible ? 10 : 0;
// Text size
size: 20;
size: 18;
// Style
color: hifi.colors.baseGray;
color: hifi.colors.blueAccent;
text: root.userName;
elide: Text.ElideRight;
// Alignment
@ -107,9 +107,9 @@ Item {
colorScheme: hifi.colorSchemes.dark;
anchors.verticalCenter: parent.verticalCenter;
anchors.right: parent.right;
anchors.rightMargin: 24;
height: root.height - 20;
width: 110;
anchors.rightMargin: 28;
height: 35;
width: 100;
text: "CHOOSE";
onClicked: {
var msg = { method: 'chooseConnection', userName: root.userName, profilePicUrl: root.profilePicUrl };

View file

@ -29,6 +29,7 @@ Item {
property string displayName;
property string userName;
property string profilePic;
property string textColor: hifi.colors.white;
Item {
visible: root.isDisplayingNearby;
@ -46,7 +47,7 @@ Item {
// Text size
size: 18;
// Style
color: hifi.colors.baseGray;
color: root.textColor;
verticalAlignment: Text.AlignBottom;
elide: Text.ElideRight;
}
@ -63,7 +64,7 @@ Item {
// Text size
size: 16;
// Style
color: hifi.colors.baseGray;
color: root.textColor;
verticalAlignment: Text.AlignTop;
elide: Text.ElideRight;
}
@ -108,7 +109,7 @@ Item {
// Text size
size: 16;
// Style
color: hifi.colors.baseGray;
color: root.textColor;
verticalAlignment: Text.AlignVCenter;
elide: Text.ElideRight;
}

View 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

(image error) Size: 921 B

Binary file not shown.

After

(image error) Size: 58 KiB

View file

@ -0,0 +1,27 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 22.0.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 512 512" style="enable-background:new 0 0 512 512;" xml:space="preserve">
<style type="text/css">
.st0{fill:#1398BB;}
</style>
<path class="st0" d="M144.3,155c-8.7-8.8-16.7-17.1-25.2-25.7c-22.4,25.4-36.6,53.9-43.6,86.2c-26.9,125.7,81.2,241.5,208.6,223.4
C385.9,424.4,458,329.2,443.5,228.2c-4.4-30.6-15.4-58.9-34.1-83.9c-1.6-2.2-3.3-4.3-4.7-6.6c-4.4-7.4-3.1-14.9,3-19.5
c6-4.5,14.2-3.6,19.2,3.5c8.2,11.7,16.6,23.4,22.9,36.1c41.9,84.9,25.7,181.7-41,248.7c-67,67.4-175.1,81.3-257.1,33.3
c-35.3-20.7-63.1-48.6-82.7-84.5c-41-75-31.5-172.5,23.4-237.9c2.2-2.7,4.4-5.4,7.1-8.7c-8.1-8.5-16.1-16.9-24-25.3
c-7.2-7.7-7.9-16.1-1.9-22.1c5.9-5.9,15-5.1,22.1,2.4c56.8,59.5,113.6,119,170.4,178.6c7.2,7.6,7.8,15.4,1.9,21.4
c-6.1,6.2-14.7,5.5-22-2c-10.2-10.4-20.2-21-30.3-31.5c-17.4,24.7-3.3,62,27.2,72.5c23,7.9,48.8-2,60.7-23.1
c1.2-2.1,2.3-4.3,3.7-6.3c4.5-6.6,11.7-8.6,18.3-5c6.6,3.5,8.9,10.5,5.9,18.1c-12.4,31.6-47.9,52.2-82.3,47.7
c-36.1-4.8-64.3-32.6-68.4-67.7c-2.4-20.7,2.4-39.7,14.9-57.5c-10.4-10.9-20.8-21.6-31.7-33c-9.7,10.8-16.2,22.7-20.9,35.7
c-31.3,86.4,38.9,175.1,130.1,164.3c74-8.7,122.3-80.9,103.3-154.3c-3.4-13.1-1-20.2,7.8-22.7c9.5-2.8,15.2,1.8,19.2,15.4
c20.1,67.4-16,144.8-79.8,175.3c-67.5,32.2-147.5,9.7-188.8-49c-37.8-53.8-36.1-127.7,4.7-179.1C141.2,159.4,142.5,157.4,144.3,155z
"/>
<path class="st0" d="M236.2,262.2c-4.2-13.6,3.4-28.2,16.8-32.4c13.5-4.2,28.1,3.3,32.5,16.8c4.5,13.9-3.1,28.4-17.2,32.7
C254.6,283.5,240.4,275.9,236.2,262.2z"/>
<path class="st0" d="M319.6,101.9c-3.7-11,1.8-22.3,12.7-26c11.3-3.9,22.8,1.9,26.4,13.2c3.5,11-2.3,22.2-13.2,25.8
C334.5,118.5,323.3,112.9,319.6,101.9z"/>
<path class="st0" d="M214.9,66.2c3.2,10.2-2.2,20.5-12.5,23.6c-9.8,3-20-2.3-23.3-12c-3.3-9.9,2.2-20.8,12-24
C201.1,50.5,211.8,56.2,214.9,66.2z"/>
<path class="st0" d="M230.8,164.6c-3.7-11,1.8-22.3,12.7-26c11.3-3.9,22.8,1.9,26.4,13.2c3.5,11-2.3,22.2-13.2,25.8
C245.7,181.2,234.5,175.6,230.8,164.6z"/>
</svg>

After

(image error) Size: 2.1 KiB

View file

@ -0,0 +1,27 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 22.0.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 143.1 414.2" style="enable-background:new 0 0 143.1 414.2;" xml:space="preserve">
<style type="text/css">
.st0{fill:#B9B9B9;}
.st1{fill:#EE982D;}
.st2{fill:#FF630A;}
</style>
<path class="st0" d="M78.8,7.1c3.9,4.3,7.7,8.7,11.8,12.9c3.7,3.8,5.1,7.9,4.4,12.9c-1,7.1-1.8,14-7.1,20.1
c-4.2,4.7-1.3,12,4.6,14.5c5.6,2.3,11.1,4.6,16.7,7c8.1,3.5,12.3,9.6,13.2,17.4c0.8,6.3,0.8,12.6,1.2,18.9c0.1,2.2,0.3,4.3,0.7,6.4
c0.3,2.2,1.9,4.4-1.3,6.1c-0.6,0.3-0.6,2.2-0.3,3.3c5.4,25.1-0.3,49.7-4.9,74.3c-1.2,6.3-3.1,12-5.5,17.9
c-2.3,5.5-0.9,12.4-0.4,18.7c0.6,7.8,2,15.5,3.2,23.7c-2.5,0.5-4.5,1.4-6.3,1.2c-6.1-0.5-6.8,2.6-6.4,6.7c0.7,6.6,1.1,13.3,2.4,19.8
c0.6,3.3,3.5,6.1,4.5,9.4c5,15.6,1.1,30.9-1.3,46.5c-1.7,10.6-0.6,21.5-1.5,32.2c-0.5,6.5-1.5,13.3-4,19.4c-2.2,5.4-9,3.9-14.1,4
c-2.8,0.1-5.6-0.3-8.2-1.1c-1.2-0.3-2.6-2.2-2.5-3.3c0.1-1.9,0.7-4.1,1.9-5.7c11.5-16,9.1-33.7,8.2-51.2c-0.5-9.8-1.6-19.6-2.9-29.3
c-1.2-8.8-3.1-17.5-5-26.2c-1.2-5.5-3.4-10.9-4.4-16.5c-0.8-3.9-2.4-5.3-7.4-3.8c-0.5,8.5-3.1,17.7-0.9,25.9
c2.7,10.1,4.5,20,3.3,30.2c-1,8.8-2.9,17.5-3.9,26.2c-0.7,6.6-1.1,13,1.7,19.8c2.4,5.9,0.6,13.1,0.3,19.7c0,0.9-2.1,2.3-3.4,2.5
c-4.8,0.7-9.8,0.8-14.5,1.6c-5.1,0.9-9.9,3-15,3.6c-5.7,0.6-11.5,0.1-17.3,0.1c-2.4-4,0-6.2,3.2-8.4c6.9-4.5,13.7-9,20.5-13.6
c6.4-4.4,7.5-10.2,6.6-17.1c-2.1-17.2-6.4-34.1-5.2-51.6c0.8-11.3-0.7-22.5-4.2-33.5c-1.7-5.2-3.4-9.1-10.4-7.8
c-0.4-0.8-0.9-1.2-0.9-1.7c-0.4-17.6-1.7-35.3-0.9-52.9c0.6-12.6,3.9-25,6-37.5c0.1-0.6,0.9-1.5,0.7-1.8c-5-8,2.9-15.7,0.6-23.9
c-2.2-8-3.5-16.4-3.7-24.6c-0.2-6.9,2.3-13.8,2.8-20.7c0.8-12.2,8.8-18.8,20.6-23c7.3-2.6,9.1-5.2,8.2-11.3c-0.1-1.1-0.6-2.7-1.4-3
c-10-4.1-8.9-12.3-9.9-19.9c-0.9-7.2-2.7-14.2-3.6-21.4c-0.3-2.9,0.2-5.9,3.6-8.1c6.4-4,13.1-5.3,20.7-3.4
C73.7,8.3,76.3,7.4,78.8,7.1z M107.1,130.2c-1,0-2,0.1-3.1,0.1c0,3.1-0.2,6.1,0,9.2c0.7,9.3,5.9,19-2.4,27.7
c-0.2,0.2-0.2,0.6-0.1,0.9c1.9,7.2,3.8,14.5,5.6,21.7c0.7-0.1,1.4-0.1,2.1-0.2C108.5,169.9,107.8,150,107.1,130.2z"/>
<circle class="st1" cx="70.9" cy="109.9" r="26"/>
<circle class="st2" cx="70.9" cy="109.9" r="19"/>
</svg>

After

(image error) Size: 2.3 KiB

View file

@ -0,0 +1,30 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 22.0.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 143.1 414.2" style="enable-background:new 0 0 143.1 414.2;" xml:space="preserve">
<style type="text/css">
.st0{fill:#B9B9B9;}
.st1{fill:#009175;}
.st2{fill:#1FC6A6;}
.st3{fill:#FFFFFF;}
</style>
<path class="st0" d="M78.8,7.1c3.9,4.3,7.7,8.7,11.8,12.9c3.7,3.8,5.1,7.9,4.4,12.9c-1,7.1-1.8,14-7.1,20.1
c-4.2,4.7-1.3,12,4.6,14.5c5.6,2.3,11.1,4.6,16.7,7c8.1,3.5,12.3,9.6,13.2,17.4c0.8,6.3,0.8,12.6,1.2,18.9c0.1,2.2,0.3,4.3,0.7,6.4
c0.3,2.2,1.9,4.4-1.3,6.1c-0.6,0.3-0.6,2.2-0.3,3.3c5.4,25.1-0.3,49.7-4.9,74.3c-1.2,6.3-3.1,12-5.5,17.9
c-2.3,5.5-0.9,12.4-0.4,18.7c0.6,7.8,2,15.5,3.2,23.7c-2.5,0.5-4.5,1.4-6.3,1.2c-6.1-0.5-6.8,2.6-6.4,6.7c0.7,6.6,1.1,13.3,2.4,19.8
c0.6,3.3,3.5,6.1,4.5,9.4c5,15.6,1.1,30.9-1.3,46.5c-1.7,10.6-0.6,21.5-1.5,32.2c-0.5,6.5-1.5,13.3-4,19.4c-2.2,5.4-9,3.9-14.1,4
c-2.8,0.1-5.6-0.3-8.2-1.1c-1.2-0.3-2.6-2.2-2.5-3.3c0.1-1.9,0.7-4.1,1.9-5.7c11.5-16,9.1-33.7,8.2-51.2c-0.5-9.8-1.6-19.6-2.9-29.3
c-1.2-8.8-3.1-17.5-5-26.2c-1.2-5.5-3.4-10.9-4.4-16.5c-0.8-3.9-2.4-5.3-7.4-3.8c-0.5,8.5-3.1,17.7-0.9,25.9
c2.7,10.1,4.5,20,3.3,30.2c-1,8.8-2.9,17.5-3.9,26.2c-0.7,6.6-1.1,13,1.7,19.8c2.4,5.9,0.6,13.1,0.3,19.7c0,0.9-2.1,2.3-3.4,2.5
c-4.8,0.7-9.8,0.8-14.5,1.6c-5.1,0.9-9.9,3-15,3.6c-5.7,0.6-11.5,0.1-17.3,0.1c-2.4-4,0-6.2,3.2-8.4c6.9-4.5,13.7-9,20.5-13.6
c6.4-4.4,7.5-10.2,6.6-17.1c-2.1-17.2-6.4-34.1-5.2-51.6c0.8-11.3-0.7-22.5-4.2-33.5c-1.7-5.2-3.4-9.1-10.4-7.8
c-0.4-0.8-0.9-1.2-0.9-1.7c-0.4-17.6-1.7-35.3-0.9-52.9c0.6-12.6,3.9-25,6-37.5c0.1-0.6,0.9-1.5,0.7-1.8c-5-8,2.9-15.7,0.6-23.9
c-2.2-8-3.5-16.4-3.7-24.6c-0.2-6.9,2.3-13.8,2.8-20.7c0.8-12.2,8.8-18.8,20.6-23c7.3-2.6,9.1-5.2,8.2-11.3c-0.1-1.1-0.6-2.7-1.4-3
c-10-4.1-8.9-12.3-9.9-19.9c-0.9-7.2-2.7-14.2-3.6-21.4c-0.3-2.9,0.2-5.9,3.6-8.1c6.4-4,13.1-5.3,20.7-3.4
C73.7,8.3,76.3,7.4,78.8,7.1z M107.1,130.2c-1,0-2,0.1-3.1,0.1c0,3.1-0.2,6.1,0,9.2c0.7,9.3,5.9,19-2.4,27.7
c-0.2,0.2-0.2,0.6-0.1,0.9c1.9,7.2,3.8,14.5,5.6,21.7c0.7-0.1,1.4-0.1,2.1-0.2C108.5,169.9,107.8,150,107.1,130.2z"/>
<circle class="st1" cx="70.9" cy="109.9" r="26"/>
<circle class="st2" cx="70.9" cy="109.9" r="23"/>
<path class="st3" d="M70.9,127.8c-9.9,0-17.9-8-17.9-17.9s8-17.9,17.9-17.9s17.9,8,17.9,17.9S80.7,127.8,70.9,127.8z M70.9,94.8
c-8.3,0-15.1,6.8-15.1,15.1s6.8,15.1,15.1,15.1S86,118.3,86,109.9S79.2,94.8,70.9,94.8z"/>
</svg>

After

(image error) Size: 2.5 KiB

View file

@ -0,0 +1,29 @@
//
// AdvancedPreferencesDialog.qml
//
// Created by Brad Hefta-Gaub on 20 Jan 2018
// Copyright 2018 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
import QtQuick 2.5
import Qt.labs.settings 1.0
import "../../dialogs"
PreferencesDialog {
id: root
objectName: "AdvancedPreferencesDialog"
title: "Advanced Settings"
showCategories: ["Advanced UI" ]
property var settings: Settings {
category: root.objectName
property alias x: root.x
property alias y: root.y
property alias width: root.width
property alias height: root.height
}
}

View file

@ -17,7 +17,7 @@ PreferencesDialog {
id: root
objectName: "GeneralPreferencesDialog"
title: "General Settings"
showCategories: ["UI", "Snapshots", "Scripts", "Privacy", "Octree", "HMD", "Game Controller", "Sixense Controllers", "Perception Neuron", "Kinect", "Leap Motion"]
showCategories: ["UI", "Snapshots", "Privacy", "HMD", "Game Controller", "Sixense Controllers", "Perception Neuron", "Kinect", "Leap Motion"]
property var settings: Settings {
category: root.objectName
property alias x: root.x

View file

@ -14,17 +14,20 @@
#include <chrono>
#include <thread>
#include <gl/Config.h>
#include <glm/glm.hpp>
#include <glm/gtx/component_wise.hpp>
#include <glm/gtx/quaternion.hpp>
#include <glm/gtx/vector_angle.hpp>
#include <glm/gtc/type_ptr.hpp>
#include <gl/Config.h>
#include <QtCore/QResource>
#include <QtCore/QAbstractNativeEventFilter>
#include <QtCore/QCommandLineParser>
#include <QtCore/QMimeData>
#include <QtCore/QThreadPool>
#include <QtCore/QFileSelector>
#include <QtConcurrent/QtConcurrentRun>
#include <QtGui/QScreen>
@ -49,6 +52,7 @@
#include <gl/QOpenGLContextWrapper.h>
#include <shared/FileUtils.h>
#include <shared/QtHelpers.h>
#include <shared/GlobalAppProperties.h>
#include <StatTracker.h>
@ -209,9 +213,8 @@
#include "commerce/QmlCommerce.h"
#include "webbrowser/WebBrowserSuggestionsEngine.h"
#include <DesktopPreviewProvider.h>
// On Windows PC, NVidia Optimus laptop, we want to enable NVIDIA GPU
// FIXME seems to be broken.
#if defined(Q_OS_WIN)
#include <VersionHelpers.h>
@ -226,11 +229,17 @@
#undef QT_BOOTSTRAPPED
#endif
// On Windows PC, NVidia Optimus laptop, we want to enable NVIDIA GPU
// FIXME seems to be broken.
extern "C" {
_declspec(dllexport) DWORD NvOptimusEnablement = 0x00000001;
}
#endif
#if defined(Q_OS_ANDROID)
#include <android/log.h>
#endif
enum ApplicationEvent {
// Execute a lambda function
Lambda = QEvent::User + 1,
@ -240,7 +249,6 @@ enum ApplicationEvent {
Idle,
};
class RenderEventHandler : public QObject {
using Parent = QObject;
Q_OBJECT
@ -304,9 +312,19 @@ static QTimer locationUpdateTimer;
static QTimer identityPacketTimer;
static QTimer pingTimer;
static const QString DISABLE_WATCHDOG_FLAG("HIFI_DISABLE_WATCHDOG");
#if defined(Q_OS_ANDROID)
static bool DISABLE_WATCHDOG = true;
#else
static const QString DISABLE_WATCHDOG_FLAG{ "HIFI_DISABLE_WATCHDOG" };
static bool DISABLE_WATCHDOG = QProcessEnvironment::systemEnvironment().contains(DISABLE_WATCHDOG_FLAG);
#endif
#if defined(USE_GLES)
static bool DISABLE_DEFERRED = true;
#else
static const QString RENDER_FORWARD{ "HIFI_RENDER_FORWARD" };
static bool DISABLE_DEFERRED = QProcessEnvironment::systemEnvironment().contains(RENDER_FORWARD);
#endif
static const int MAX_CONCURRENT_RESOURCE_DOWNLOADS = 16;
@ -333,7 +351,7 @@ static const float MIRROR_FULLSCREEN_DISTANCE = 0.389f;
static const quint64 TOO_LONG_SINCE_LAST_SEND_DOWNSTREAM_AUDIO_STATS = 1 * USECS_PER_SECOND;
static const QString INFO_EDIT_ENTITIES_PATH = "html/edit-commands.html";
static const QString INFO_HELP_PATH = "../../../html/tabletHelp.html";
static const QString INFO_HELP_PATH = "html/tabletHelp.html";
static const unsigned int THROTTLED_SIM_FRAMERATE = 15;
static const int THROTTLED_SIM_FRAME_PERIOD_MS = MSECS_PER_SECOND / THROTTLED_SIM_FRAMERATE;
@ -503,7 +521,13 @@ public:
}
if (message->message == WM_DEVICECHANGE) {
Midi::USBchanged(); // re-scan the MIDI bus
const float MIN_DELTA_SECONDS = 2.0f; // de-bounce signal
static float lastTriggerTime = 0.0f;
const float deltaSeconds = secTimestampNow() - lastTriggerTime;
lastTriggerTime = secTimestampNow();
if (deltaSeconds > MIN_DELTA_SECONDS) {
Midi::USBchanged(); // re-scan the MIDI bus
}
}
}
return false;
@ -530,6 +554,26 @@ void messageHandler(QtMsgType type, const QMessageLogContext& context, const QSt
#ifdef Q_OS_WIN
OutputDebugStringA(logMessage.toLocal8Bit().constData());
OutputDebugStringA("\n");
#elif defined Q_OS_ANDROID
const char * local=logMessage.toStdString().c_str();
switch (type) {
case QtDebugMsg:
__android_log_write(ANDROID_LOG_DEBUG,"Interface",local);
break;
case QtInfoMsg:
__android_log_write(ANDROID_LOG_INFO,"Interface",local);
break;
case QtWarningMsg:
__android_log_write(ANDROID_LOG_WARN,"Interface",local);
break;
case QtCriticalMsg:
__android_log_write(ANDROID_LOG_ERROR,"Interface",local);
break;
case QtFatalMsg:
default:
__android_log_write(ANDROID_LOG_FATAL,"Interface",local);
abort();
}
#endif
qApp->getLogger()->addMessage(qPrintable(logMessage + "\n"));
}
@ -573,8 +617,7 @@ bool setupEssentials(int& argc, char** argv, bool runningMarkerExisted) {
}
};
reportAndQuit("--protocolVersion", [&](FILE* fp) {
DependencyManager::set<AddressManager>();
auto version = DependencyManager::get<AddressManager>()->protocolVersion();
auto version = protocolVersionsSignatureBase64();
fputs(version.toLatin1().data(), fp);
});
reportAndQuit("--version", [&](FILE* fp) {
@ -594,6 +637,24 @@ bool setupEssentials(int& argc, char** argv, bool runningMarkerExisted) {
qApp->setProperty(hifi::properties::APP_LOCAL_DATA_PATH, cacheDir);
}
// FIXME fix the OSX installer to install the resources.rcc binary instead of resource files and remove
// this conditional exclusion
#if !defined(Q_OS_OSX)
{
#if defined(Q_OS_ANDROID)
const QString resourcesBinaryFile = QStandardPaths::writableLocation(QStandardPaths::CacheLocation) + "/resources.rcc";
#else
const QString resourcesBinaryFile = QCoreApplication::applicationDirPath() + "/resources.rcc";
#endif
if (!QFile::exists(resourcesBinaryFile)) {
throw std::runtime_error("Unable to find primary resources");
}
if (!QResource::registerResource(resourcesBinaryFile)) {
throw std::runtime_error("Unable to load primary resources");
}
}
#endif
Setting::init();
// Tell the plugin manager about our statically linked plugins
@ -632,15 +693,16 @@ bool setupEssentials(int& argc, char** argv, bool runningMarkerExisted) {
DependencyManager::set<PointerScriptingInterface>();
DependencyManager::set<PickScriptingInterface>();
DependencyManager::set<Cursor::Manager>();
DependencyManager::set<DesktopPreviewProvider>();
DependencyManager::set<AccountManager>(std::bind(&Application::getUserAgent, qApp));
DependencyManager::set<StatTracker>();
DependencyManager::set<ScriptEngines>(ScriptEngine::CLIENT_SCRIPT);
DependencyManager::set<Preferences>();
DependencyManager::set<recording::ClipCache>();
DependencyManager::set<recording::Deck>();
DependencyManager::set<recording::Recorder>();
DependencyManager::set<AddressManager>();
DependencyManager::set<NodeList>(NodeType::Agent, listenPort);
DependencyManager::set<recording::ClipCache>();
DependencyManager::set<GeometryCache>();
DependencyManager::set<ModelCache>();
DependencyManager::set<ScriptCache>();
@ -729,8 +791,10 @@ OverlayID _keyboardFocusHighlightID{ UNKNOWN_OVERLAY_ID };
//
// So instead we create a new offscreen context to share with the QGLWidget,
// and manually set THAT to be the shared context for the Chromium helper
#if !defined(DISABLE_QML)
OffscreenGLCanvas* _chromiumShareContext { nullptr };
Q_GUI_EXPORT void qt_gl_set_global_share_context(QOpenGLContext *context);
#endif
Setting::Handle<int> sessionRunTime{ "sessionRunTime", 0 };
@ -776,6 +840,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
_sampleSound(nullptr)
{
auto steamClient = PluginManager::getInstance()->getSteamClientPlugin();
setProperty(hifi::properties::STEAM, (steamClient && steamClient->isRunning()));
setProperty(hifi::properties::CRASHED, _previousSessionCrashed);
@ -996,8 +1061,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
DependencyManager::get<AddressManager>().data(), &AddressManager::storeCurrentAddress);
// Inititalize sample before registering
QFileInfo infSample = QFileInfo(PathUtils::resourcesPath() + "sounds/sample.wav");
_sampleSound = DependencyManager::get<SoundCache>()->getSound(QUrl::fromLocalFile(infSample.absoluteFilePath()));
_sampleSound = DependencyManager::get<SoundCache>()->getSound(PathUtils::resourcesUrl("sounds/sample.wav"));
auto scriptEngines = DependencyManager::get<ScriptEngines>().data();
scriptEngines->registerScriptInitializer([this](ScriptEnginePointer engine){
@ -1082,9 +1146,6 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
// Make sure we don't time out during slow operations at startup
updateHeartbeat();
// Now that OpenGL is initialized, we are sure we have a valid context and can create the various pipeline shaders with success.
DependencyManager::get<GeometryCache>()->initializeShapePipelines();
// sessionRunTime will be reset soon by loadSettings. Grab it now to get previous session value.
// The value will be 0 if the user blew away settings this session, which is both a feature and a bug.
static const QString TESTER = "HIFI_TESTER";
@ -1375,8 +1436,9 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
userInputMapper->registerDevice(_touchscreenDevice->getInputDevice());
}
// force the model the look at the correct directory (weird order of operations issue)
scriptEngines->setScriptsLocation(scriptEngines->getScriptsLocation());
// this will force the model the look at the correct directory (weird order of operations issue)
scriptEngines->reloadLocalFiles();
// do this as late as possible so that all required subsystems are initialized
// If we've overridden the default scripts location, just load default scripts
// otherwise, load 'em all
@ -1730,7 +1792,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
static int lastCountOfNearbyAvatars = -1;
QTimer* checkNearbyAvatarsTimer = new QTimer(this);
checkNearbyAvatarsTimer->setInterval(CHECK_NEARBY_AVATARS_INTERVAL_MS); // 10 seconds, Qt::CoarseTimer ok
connect(checkNearbyAvatarsTimer, &QTimer::timeout, this, [this]() {
connect(checkNearbyAvatarsTimer, &QTimer::timeout, this, []() {
auto avatarManager = DependencyManager::get<AvatarManager>();
int nearbyAvatars = avatarManager->numberOfAvatarsInRange(avatarManager->getMyAvatar()->getWorldPosition(),
NEARBY_AVATAR_RADIUS_METERS) - 1;
@ -1769,9 +1831,11 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
PROFILE_RANGE(render, "Process Default Skybox");
auto textureCache = DependencyManager::get<TextureCache>();
auto skyboxUrl = PathUtils::resourcesPath().toStdString() + "images/Default-Sky-9-cubemap.ktx";
QFileSelector fileSelector;
fileSelector.setExtraSelectors(FileUtils::getFileSelectors());
auto skyboxUrl = fileSelector.select(PathUtils::resourcesPath() + "images/Default-Sky-9-cubemap.ktx");
_defaultSkyboxTexture = gpu::Texture::unserialize(skyboxUrl);
_defaultSkyboxTexture = gpu::Texture::unserialize(skyboxUrl.toStdString());
_defaultSkyboxAmbientTexture = _defaultSkyboxTexture;
_defaultSkybox->setCubemap(_defaultSkyboxTexture);
@ -1782,8 +1846,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
return entityServerNode && !isPhysicsEnabled();
});
QFileInfo infSnap = QFileInfo(PathUtils::resourcesPath() + "sounds/snap.wav");
_snapshotSound = DependencyManager::get<SoundCache>()->getSound(QUrl::fromLocalFile(infSnap.absoluteFilePath()));
_snapshotSound = DependencyManager::get<SoundCache>()->getSound(PathUtils::resourcesUrl("sounds/snap.wav"));
QVariant testProperty = property(hifi::properties::TEST);
qDebug() << testProperty;
@ -2181,11 +2244,16 @@ void Application::initializeGL() {
}
_glWidget->makeCurrent();
_chromiumShareContext = new OffscreenGLCanvas();
_chromiumShareContext->setObjectName("ChromiumShareContext");
_chromiumShareContext->create(_glWidget->qglContext());
_chromiumShareContext->makeCurrent();
qt_gl_set_global_share_context(_chromiumShareContext->getContext());
#if !defined(DISABLE_QML)
if (!nsightActive()) {
_chromiumShareContext = new OffscreenGLCanvas();
_chromiumShareContext->setObjectName("ChromiumShareContext");
_chromiumShareContext->create(_glWidget->qglContext());
_chromiumShareContext->makeCurrent();
qt_gl_set_global_share_context(_chromiumShareContext->getContext());
}
#endif
_glWidget->makeCurrent();
gpu::Context::init<gpu::gl::GLBackend>();
@ -2202,13 +2270,17 @@ void Application::initializeGL() {
// Set up the render engine
render::CullFunctor cullFunctor = LODManager::shouldRender;
static const QString RENDER_FORWARD = "HIFI_RENDER_FORWARD";
bool isDeferred = !QProcessEnvironment::systemEnvironment().contains(RENDER_FORWARD);
_renderEngine->addJob<UpdateSceneTask>("UpdateScene");
_renderEngine->addJob<SecondaryCameraRenderTask>("SecondaryCameraJob", cullFunctor);
_renderEngine->addJob<RenderViewTask>("RenderMainView", cullFunctor, isDeferred);
#ifndef Q_OS_ANDROID
_renderEngine->addJob<SecondaryCameraRenderTask>("SecondaryCameraJob", cullFunctor, !DISABLE_DEFERRED);
#endif
_renderEngine->addJob<RenderViewTask>("RenderMainView", cullFunctor, !DISABLE_DEFERRED);
_renderEngine->load();
_renderEngine->registerScene(_main3DScene);
// Now that OpenGL is initialized, we are sure we have a valid context and can create the various pipeline shaders with success.
DependencyManager::get<GeometryCache>()->initializeShapePipelines();
_offscreenContext = new OffscreenGLCanvas();
_offscreenContext->setObjectName("MainThreadContext");
_offscreenContext->create(_glWidget->qglContext());
@ -2313,8 +2385,7 @@ void Application::initializeUi() {
offscreenUi->setProxyWindow(_window->windowHandle());
// OffscreenUi is a subclass of OffscreenQmlSurface specifically designed to
// support the window management and scripting proxies for VR use
offscreenUi->createDesktop(QString("hifi/Desktop.qml"));
offscreenUi->createDesktop(PathUtils::qmlUrl("hifi/Desktop.qml"));
// FIXME either expose so that dialogs can set this themselves or
// do better detection in the offscreen UI of what has focus
offscreenUi->setNavigationFocused(false);
@ -2653,7 +2724,8 @@ void Application::showHelp() {
queryString.addQueryItem("defaultTab", defaultTab);
auto tabletScriptingInterface = DependencyManager::get<TabletScriptingInterface>();
TabletProxy* tablet = dynamic_cast<TabletProxy*>(tabletScriptingInterface->getTablet(SYSTEM_TABLET));
tablet->gotoWebScreen(INFO_HELP_PATH + "?" + queryString.toString());
tablet->gotoWebScreen(PathUtils::resourcesPath() + INFO_HELP_PATH + "?" + queryString.toString());
DependencyManager::get<HMDScriptingInterface>()->openTablet();
//InfoView::show(INFO_HELP_PATH, false, queryString.toString());
}
@ -3909,12 +3981,18 @@ void Application::idle() {
PROFILE_COUNTER_IF_CHANGED(app, "pendingProcessing", int, DependencyManager::get<StatTracker>()->getStat("PendingProcessing").toInt());
auto renderConfig = _renderEngine->getConfiguration();
PROFILE_COUNTER_IF_CHANGED(render, "gpuTime", float, (float)_gpuContext->getFrameTimerGPUAverage());
auto opaqueRangeTimer = renderConfig->getConfig("OpaqueRangeTimer");
auto linearDepth = renderConfig->getConfig("LinearDepth");
auto surfaceGeometry = renderConfig->getConfig("SurfaceGeometry");
auto renderDeferred = renderConfig->getConfig("RenderDeferred");
auto toneAndPostRangeTimer = renderConfig->getConfig("ToneAndPostRangeTimer");
PROFILE_COUNTER(render_detail, "gpuTimes", {
{ "OpaqueRangeTimer", renderConfig->getConfig("OpaqueRangeTimer")->property("gpuRunTime") },
{ "LinearDepth", renderConfig->getConfig("LinearDepth")->property("gpuRunTime") },
{ "SurfaceGeometry", renderConfig->getConfig("SurfaceGeometry")->property("gpuRunTime") },
{ "RenderDeferred", renderConfig->getConfig("RenderDeferred")->property("gpuRunTime") },
{ "ToneAndPostRangeTimer", renderConfig->getConfig("ToneAndPostRangeTimer")->property("gpuRunTime") }
{ "OpaqueRangeTimer", opaqueRangeTimer ? opaqueRangeTimer->property("gpuRunTime") : 0 },
{ "LinearDepth", linearDepth ? linearDepth->property("gpuRunTime") : 0 },
{ "SurfaceGeometry", surfaceGeometry ? surfaceGeometry->property("gpuRunTime") : 0 },
{ "RenderDeferred", renderDeferred ? renderDeferred->property("gpuRunTime") : 0 },
{ "ToneAndPostRangeTimer", toneAndPostRangeTimer ? toneAndPostRangeTimer->property("gpuRunTime") : 0 }
});
PROFILE_RANGE(app, __FUNCTION__);
@ -4279,9 +4357,9 @@ void Application::init() {
// Make sure Login state is up to date
DependencyManager::get<DialogsManager>()->toggleLoginDialog();
DependencyManager::get<DeferredLightingEffect>()->init();
if (!DISABLE_DEFERRED) {
DependencyManager::get<DeferredLightingEffect>()->init();
}
DependencyManager::get<AvatarManager>()->init();
_timerStart.start();
@ -5760,10 +5838,13 @@ void Application::registerScriptEngineWithApplicationServices(ScriptEnginePointe
scriptEngine->registerGetterSetter("location", LocationScriptingInterface::locationGetter,
LocationScriptingInterface::locationSetter);
#if !defined(Q_OS_ANDROID)
scriptEngine->registerFunction("OverlayWebWindow", QmlWebWindowClass::constructor);
#endif
scriptEngine->registerFunction("OverlayWindow", QmlWindowClass::constructor);
scriptEngine->registerGlobalObject("Menu", MenuScriptingInterface::getInstance());
scriptEngine->registerGlobalObject("DesktopPreviewProvider", DependencyManager::get<DesktopPreviewProvider>().data());
scriptEngine->registerGlobalObject("Stats", Stats::getInstance());
scriptEngine->registerGlobalObject("Settings", SettingsScriptingInterface::getInstance());
scriptEngine->registerGlobalObject("Snapshot", DependencyManager::get<Snapshot>().data());

View file

@ -756,6 +756,13 @@ Menu::Menu() {
// Developer > Stats
addCheckableActionToQMenuAndActionHash(developerMenu, MenuOption::Stats);
// Developer > Advanced Settings...
action = addActionToQMenuAndActionHash(developerMenu, "Advanced Preferences...");
connect(action, &QAction::triggered, [] {
qApp->showDialog(QString("hifi/dialogs/AdvancedPreferencesDialog.qml"),
QString("hifi/tablet/AdvancedPreferencesDialog.qml"), "AdvancedPreferencesDialog");
});
// Developer > API Debugger
action = addActionToQMenuAndActionHash(developerMenu, "API Debugger");
connect(action, &QAction::triggered, [] {

View file

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

View file

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

View file

@ -1797,7 +1797,7 @@ void MyAvatar::initAnimGraph() {
} else if (!_fstAnimGraphOverrideUrl.isEmpty()) {
graphUrl = _fstAnimGraphOverrideUrl;
} else {
graphUrl = QUrl::fromLocalFile(PathUtils::resourcesPath() + "avatar/avatar-animation.json");
graphUrl = PathUtils::resourcesUrl("avatar/avatar-animation.json");
}
_skeletonModel->getRig().initAnimGraph(graphUrl);
@ -2019,8 +2019,7 @@ void MyAvatar::updateOrientation(float deltaTime) {
_smoothOrientationTimer = 0.0f;
}
getHead()->setBasePitch(getHead()->getBasePitch() + getDriveKey(PITCH) * _pitchSpeed * deltaTime);
Head* head = getHead();
auto headPose = getControllerPoseInAvatarFrame(controller::Action::HEAD);
if (headPose.isValid()) {
glm::quat localOrientation = headPose.rotation * Quaternions::Y_180;
@ -2032,6 +2031,10 @@ void MyAvatar::updateOrientation(float deltaTime) {
head->setBaseYaw(YAW(euler));
head->setBasePitch(PITCH(euler));
head->setBaseRoll(ROLL(euler));
} else {
head->setBaseYaw(0.0f);
head->setBasePitch(getHead()->getBasePitch() + getDriveKey(PITCH) * _pitchSpeed * deltaTime);
head->setBaseRoll(0.0f);
}
}

View file

@ -17,6 +17,7 @@
#include "Ledger.h"
#include "CommerceLogging.h"
#include <NetworkingConstants.h>
#include <AddressManager.h>
// inventory answers {status: 'success', data: {assets: [{id: "guid", title: "name", preview: "url"}....]}}
// balance answers {status: 'success', data: {balance: integer}}
@ -122,25 +123,30 @@ QString hfcString(const QJsonValue& sentValue, const QJsonValue& receivedValue)
int sent = sentValue.toInt();
int received = receivedValue.toInt();
if (sent <= 0 && received <= 0) {
return QString("-");
return QString("0 HFC");
}
QString result;
if (sent > 0) {
result += QString("<font color='#B70A37'>-%1 HFC</font>").arg(sent);
result += QString("<font color='#B70A37'><b>-%1 HFC</b></font>").arg(sent);
if (received > 0) {
result += QString("<br>");
}
}
if (received > 0) {
result += QString("<font color='#3AA38F'>%1 HFC</font>").arg(received);
result += QString("<font color='#3AA38F'><b>%1 HFC</b></font>").arg(received);
}
return result;
}
static const QString USER_PAGE_BASE_URL = NetworkingConstants::METAVERSE_SERVER_URL().toString() + "/users/";
static const QString PLACE_PAGE_BASE_URL = NetworkingConstants::METAVERSE_SERVER_URL().toString() + "/places/";
static const QStringList KNOWN_USERS(QStringList() << "highfidelity" << "marketplace");
QString userLink(const QString& username) {
QString userLink(const QString& username, const QString& placename) {
if (username.isEmpty()) {
return QString("someone");
if (placename.isEmpty()) {
return QString("someone");
} else {
return QString("someone <a href=\"%1%2\">nearby</a>").arg(PLACE_PAGE_BASE_URL, placename);
}
}
if (KNOWN_USERS.contains(username)) {
return username;
@ -157,13 +163,13 @@ QString transactionString(const QJsonObject& valueObject) {
QDateTime createdAt(QDateTime::fromSecsSinceEpoch(dateInteger, Qt::UTC));
QString result;
if (sentCerts <= 0 && receivedCerts <= 0) {
if (sentCerts <= 0 && receivedCerts <= 0 && !KNOWN_USERS.contains(valueObject["sender_name"].toString())) {
// this is an hfc transfer.
if (sent > 0) {
QString recipient = userLink(valueObject["recipient_name"].toString());
QString recipient = userLink(valueObject["recipient_name"].toString(), valueObject["place_name"].toString());
result += QString("Money sent to %1").arg(recipient);
} else {
QString sender = userLink(valueObject["sender_name"].toString());
QString sender = userLink(valueObject["sender_name"].toString(), valueObject["place_name"].toString());
result += QString("Money from %1").arg(sender);
}
if (!message.isEmpty()) {
@ -172,8 +178,8 @@ QString transactionString(const QJsonObject& valueObject) {
} else {
result += valueObject["message"].toString();
}
// no matter what we append a smaller date to the bottom of this...
result += QString("<br><font size='-2' color='#1080B8'>%1").arg(createdAt.toLocalTime().toString(Qt::DefaultLocaleShortDate));
return result;
}
@ -314,6 +320,7 @@ void Ledger::transferHfcToNode(const QString& hfc_key, const QString& nodeID, co
transaction["node_id"] = nodeID;
transaction["quantity"] = amount;
transaction["message"] = optionalMessage;
transaction["place_name"] = DependencyManager::get<AddressManager>()->getPlaceName();
QJsonDocument transactionDoc{ transaction };
auto transactionString = transactionDoc.toJson(QJsonDocument::Compact);
signedSend("transaction", transactionString, hfc_key, "transfer_hfc_to_node", "transferHfcToNodeSuccess", "transferHfcToNodeFailure");

View file

@ -591,8 +591,8 @@ void Wallet::chooseSecurityImage(const QString& filename) {
if (_securityImage) {
delete _securityImage;
}
QString path = qApp->applicationDirPath();
path.append("/resources/qml/hifi/commerce/wallet/");
QString path = PathUtils::resourcesPath();
path.append("/qml/hifi/commerce/wallet/");
path.append(filename);
// now create a new security image pixmap

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -82,19 +82,42 @@ void setupPreferences() {
preference->setMax(500);
preferences->addPreference(preference);
}
{
auto getter = []()->float { return qApp->getDesktopTabletScale(); };
auto setter = [](float value) { qApp->setDesktopTabletScale(value); };
auto preference = new SpinnerPreference(UI_CATEGORY, "Desktop Tablet Scale %", getter, setter);
preference->setMin(20);
preference->setMax(500);
preferences->addPreference(preference);
}
{
auto getter = []()->bool { return qApp->getPreferStylusOverLaser(); };
auto setter = [](bool value) { qApp->setPreferStylusOverLaser(value); };
preferences->addPreference(new CheckPreference(UI_CATEGORY, "Prefer Stylus Over Laser", getter, setter));
}
static const QString ADVANCED_UI_CATEGORY { "Advanced UI" };
{
auto getter = []()->float { return qApp->getDesktopTabletScale(); };
auto setter = [](float value) { qApp->setDesktopTabletScale(value); };
auto preference = new SpinnerPreference(ADVANCED_UI_CATEGORY, "Desktop Tablet Scale %", getter, setter);
preference->setMin(20);
preference->setMax(500);
preferences->addPreference(preference);
}
{
auto getter = [=]()->float { return myAvatar->getRealWorldFieldOfView(); };
auto setter = [=](float value) { myAvatar->setRealWorldFieldOfView(value); };
auto preference = new SpinnerPreference(ADVANCED_UI_CATEGORY, "Real world vertical field of view (angular size of monitor)", getter, setter);
preference->setMin(1);
preference->setMax(180);
preferences->addPreference(preference);
}
{
auto getter = []()->float { return qApp->getFieldOfView(); };
auto setter = [](float value) { qApp->setFieldOfView(value); };
auto preference = new SpinnerPreference(ADVANCED_UI_CATEGORY, "Vertical field of view", getter, setter);
preference->setMin(1);
preference->setMax(180);
preference->setStep(1);
preferences->addPreference(preference);
}
// FIXME: Remove setting completely or make available through JavaScript API?
/*
{
@ -128,21 +151,13 @@ void setupPreferences() {
preferences->addPreference(preference);
}
// Scripts
{
auto getter = []()->QString { return DependencyManager::get<ScriptEngines>()->getScriptsLocation(); };
auto setter = [](const QString& value) { DependencyManager::get<ScriptEngines>()->setScriptsLocation(value); };
preferences->addPreference(new BrowsePreference("Scripts", "Load scripts from this directory", getter, setter));
}
preferences->addPreference(new ButtonPreference("Scripts", "Load Default Scripts", [] {
DependencyManager::get<ScriptEngines>()->loadDefaultScripts();
}));
{
auto getter = []()->bool { return !Menu::getInstance()->isOptionChecked(MenuOption::DisableActivityLogger); };
auto setter = [](bool value) { Menu::getInstance()->setIsOptionChecked(MenuOption::DisableActivityLogger, !value); };
preferences->addPreference(new CheckPreference("Privacy", "Send data", getter, setter));
preferences->addPreference(new CheckPreference("Privacy", "Send data - High Fidelity uses information provided by your "
"client to improve the product through the logging of errors, tracking of usage patterns, "
"installation and system details, and crash events. By allowing High Fidelity to collect "
"this information you are helping to improve the product. ", getter, setter));
}
static const QString LOD_TUNING("Level of Detail Tuning");
@ -167,23 +182,6 @@ void setupPreferences() {
}
static const QString AVATAR_TUNING { "Avatar Tuning" };
{
auto getter = [=]()->float { return myAvatar->getRealWorldFieldOfView(); };
auto setter = [=](float value) { myAvatar->setRealWorldFieldOfView(value); };
auto preference = new SpinnerPreference(AVATAR_TUNING, "Real world vertical field of view (angular size of monitor)", getter, setter);
preference->setMin(1);
preference->setMax(180);
preferences->addPreference(preference);
}
{
auto getter = []()->float { return qApp->getFieldOfView(); };
auto setter = [](float value) { qApp->setFieldOfView(value); };
auto preference = new SpinnerPreference(AVATAR_TUNING, "Vertical field of view", getter, setter);
preference->setMin(1);
preference->setMax(180);
preference->setStep(1);
preferences->addPreference(preference);
}
{
auto getter = [=]()->QString { return myAvatar->getDominantHand(); };
auto setter = [=](const QString& value) { myAvatar->setDominantHand(value); };
@ -297,26 +295,6 @@ void setupPreferences() {
}
#endif
{
auto getter = []()->float { return qApp->getMaxOctreePacketsPerSecond(); };
auto setter = [](float value) { qApp->setMaxOctreePacketsPerSecond(value); };
auto preference = new SpinnerPreference("Octree", "Max packets sent each second", getter, setter);
preference->setMin(60);
preference->setMax(6000);
preference->setStep(10);
preferences->addPreference(preference);
}
{
auto getter = []()->float { return qApp->getApplicationCompositor().getHmdUIAngularSize(); };
auto setter = [](float value) { qApp->getApplicationCompositor().setHmdUIAngularSize(value); };
auto preference = new SpinnerPreference("HMD", "UI horizontal angular size (degrees)", getter, setter);
preference->setMin(30);
preference->setMax(160);
preference->setStep(1);
preferences->addPreference(preference);
}
{
static const QString RENDER("Graphics");
@ -342,7 +320,7 @@ void setupPreferences() {
}
}
{
static const QString RENDER("Networking");
static const QString NETWORKING("Networking");
auto nodelist = DependencyManager::get<NodeList>();
{
@ -350,10 +328,21 @@ void setupPreferences() {
static const int MAX_PORT_NUMBER { 65535 };
auto getter = [nodelist] { return static_cast<int>(nodelist->getSocketLocalPort()); };
auto setter = [nodelist](int preset) { nodelist->setSocketLocalPort(static_cast<quint16>(preset)); };
auto preference = new IntSpinnerPreference(RENDER, "Listening Port", getter, setter);
auto preference = new IntSpinnerPreference(NETWORKING, "Listening Port", getter, setter);
preference->setMin(MIN_PORT_NUMBER);
preference->setMax(MAX_PORT_NUMBER);
preferences->addPreference(preference);
}
{
auto getter = []()->float { return qApp->getMaxOctreePacketsPerSecond(); };
auto setter = [](float value) { qApp->setMaxOctreePacketsPerSecond(value); };
auto preference = new SpinnerPreference(NETWORKING, "Max entities packets sent each second", getter, setter);
preference->setMin(60);
preference->setMax(6000);
preference->setStep(10);
preferences->addPreference(preference);
}
}
}

View file

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

View file

@ -14,6 +14,8 @@
#include "Application.h"
#include <gl/Config.h>
#include <QQuickFramebufferObject>
#include <QQuickWindow>
#include <QTimer>

View file

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

View file

@ -564,9 +564,9 @@ void ModelOverlay::animate() {
rotationMat * fbxJoints[index].postTransform);
auto& jointData = jointsData[j];
jointData.translation = extractTranslation(finalMat);
jointData.translationSet = true;
jointData.translationIsDefaultPose = false;
jointData.rotation = glmExtractRotation(finalMat);
jointData.rotationSet = true;
jointData.rotationIsDefaultPose = false;
}
}
// Set the data in the model

View file

@ -1705,16 +1705,16 @@ void Rig::copyJointsIntoJointData(QVector<JointData>& jointDataVec) const {
// rotations are in absolute rig frame.
glm::quat defaultAbsRot = geometryToRigPose.rot() * _animSkeleton->getAbsoluteDefaultPose(i).rot();
data.rotation = _internalPoseSet._absolutePoses[i].rot();
data.rotationSet = !isEqual(data.rotation, defaultAbsRot);
data.rotationIsDefaultPose = isEqual(data.rotation, defaultAbsRot);
// translations are in relative frame but scaled so that they are in meters,
// instead of geometry units.
glm::vec3 defaultRelTrans = _geometryOffset.scale() * _animSkeleton->getRelativeDefaultPose(i).trans();
data.translation = _geometryOffset.scale() * _internalPoseSet._relativePoses[i].trans();
data.translationSet = !isEqual(data.translation, defaultRelTrans);
data.translationIsDefaultPose = isEqual(data.translation, defaultRelTrans);
} else {
data.translationSet = false;
data.rotationSet = false;
data.translationIsDefaultPose = true;
data.rotationIsDefaultPose = true;
}
}
}
@ -1739,11 +1739,11 @@ void Rig::copyJointsFromJointData(const QVector<JointData>& jointDataVec) {
const glm::quat rigToGeometryRot(glmExtractRotation(_rigToGeometryTransform));
for (int i = 0; i < numJoints; i++) {
const JointData& data = jointDataVec.at(i);
if (data.rotationSet) {
if (data.rotationIsDefaultPose) {
rotations.push_back(absoluteDefaultPoses[i].rot());
} else {
// JointData rotations are in absolute rig-frame so we rotate them to absolute geometry-frame
rotations.push_back(rigToGeometryRot * data.rotation);
} else {
rotations.push_back(absoluteDefaultPoses[i].rot());
}
}
@ -1759,11 +1759,11 @@ void Rig::copyJointsFromJointData(const QVector<JointData>& jointDataVec) {
const JointData& data = jointDataVec.at(i);
_internalPoseSet._relativePoses[i].scale() = Vectors::ONE;
_internalPoseSet._relativePoses[i].rot() = rotations[i];
if (data.translationSet) {
if (data.translationIsDefaultPose) {
_internalPoseSet._relativePoses[i].trans() = relativeDefaultPoses[i].trans();
} else {
// JointData translations are in scaled relative-frame so we scale back to regular relative-frame
_internalPoseSet._relativePoses[i].trans() = _invGeometryOffset.scale() * data.translation;
} else {
_internalPoseSet._relativePoses[i].trans() = relativeDefaultPoses[i].trans();
}
}
}

View file

@ -427,28 +427,11 @@ AudioInjectorPointer AudioInjector::playSound(SharedSoundPointer sound, const fl
options.stereo = sound->isStereo();
options.position = position;
options.volume = volume;
options.pitch = 1.0f / stretchFactor;
QByteArray samples = sound->getByteArray();
if (stretchFactor == 1.0f) {
return playSoundAndDelete(samples, options);
}
const int standardRate = AudioConstants::SAMPLE_RATE;
const int resampledRate = standardRate * stretchFactor;
const int channelCount = sound->isStereo() ? 2 : 1;
AudioSRC resampler(standardRate, resampledRate, channelCount);
const int nInputFrames = samples.size() / (channelCount * sizeof(int16_t));
const int maxOutputFrames = resampler.getMaxOutput(nInputFrames);
QByteArray resampled(maxOutputFrames * channelCount * sizeof(int16_t), '\0');
int nOutputFrames = resampler.render(reinterpret_cast<const int16_t*>(samples.data()),
reinterpret_cast<int16_t*>(resampled.data()),
nInputFrames);
Q_UNUSED(nOutputFrames);
return playSoundAndDelete(resampled, options);
return playSoundAndDelete(samples, options);
}
AudioInjectorPointer AudioInjector::playSoundAndDelete(const QByteArray& buffer, const AudioInjectorOptions options) {
@ -461,12 +444,40 @@ AudioInjectorPointer AudioInjector::playSoundAndDelete(const QByteArray& buffer,
return sound;
}
AudioInjectorPointer AudioInjector::playSound(const QByteArray& buffer, const AudioInjectorOptions options) {
AudioInjectorPointer injector = AudioInjectorPointer::create(buffer, options);
if (!injector->inject(&AudioInjectorManager::threadInjector)) {
qWarning() << "AudioInjector::playSound failed to thread injector";
if (options.pitch == 1.0f) {
AudioInjectorPointer injector = AudioInjectorPointer::create(buffer, options);
if (!injector->inject(&AudioInjectorManager::threadInjector)) {
qWarning() << "AudioInjector::playSound failed to thread injector";
}
return injector;
} else {
const int standardRate = AudioConstants::SAMPLE_RATE;
const int resampledRate = AudioConstants::SAMPLE_RATE / glm::clamp(options.pitch, 1/16.0f, 16.0f); // limit to 4 octaves
const int numChannels = options.ambisonic ? AudioConstants::AMBISONIC :
(options.stereo ? AudioConstants::STEREO : AudioConstants::MONO);
AudioSRC resampler(standardRate, resampledRate, numChannels);
// create a resampled buffer that is guaranteed to be large enough
const int nInputFrames = buffer.size() / (numChannels * sizeof(int16_t));
const int maxOutputFrames = resampler.getMaxOutput(nInputFrames);
QByteArray resampledBuffer(maxOutputFrames * numChannels * sizeof(int16_t), '\0');
resampler.render(reinterpret_cast<const int16_t*>(buffer.data()),
reinterpret_cast<int16_t*>(resampledBuffer.data()),
nInputFrames);
AudioInjectorPointer injector = AudioInjectorPointer::create(resampledBuffer, options);
if (!injector->inject(&AudioInjectorManager::threadInjector)) {
qWarning() << "AudioInjector::playSound failed to thread pitch-shifted injector";
}
return injector;
}
return injector;
}

View file

@ -26,7 +26,8 @@ AudioInjectorOptions::AudioInjectorOptions() :
ambisonic(false),
ignorePenumbra(false),
localOnly(false),
secondOffset(0.0f)
secondOffset(0.0f),
pitch(1.0f)
{
}
@ -40,6 +41,7 @@ QScriptValue injectorOptionsToScriptValue(QScriptEngine* engine, const AudioInje
obj.setProperty("ignorePenumbra", injectorOptions.ignorePenumbra);
obj.setProperty("localOnly", injectorOptions.localOnly);
obj.setProperty("secondOffset", injectorOptions.secondOffset);
obj.setProperty("pitch", injectorOptions.pitch);
return obj;
}
@ -87,6 +89,12 @@ void injectorOptionsFromScriptValue(const QScriptValue& object, AudioInjectorOpt
} else {
qCWarning(audio) << "Audio injector options: secondOffset is not a number";
}
} else if (it.name() == "pitch") {
if (it.value().isNumber()) {
injectorOptions.pitch = it.value().toNumber();
} else {
qCWarning(audio) << "Audio injector options: pitch is not a number";
}
} else {
qCWarning(audio) << "Unknown audio injector option:" << it.name();
}

View file

@ -29,6 +29,7 @@ public:
bool ignorePenumbra;
bool localOnly;
float secondOffset;
float pitch; // multiplier, where 2.0f shifts up one octave
};
Q_DECLARE_METATYPE(AudioInjectorOptions);

View file

@ -791,10 +791,19 @@ bool Avatar::shouldRenderHead(const RenderArgs* renderArgs) const {
// virtual
void Avatar::simulateAttachments(float deltaTime) {
assert(_attachmentModels.size() == _attachmentModelsTexturesLoaded.size());
PerformanceTimer perfTimer("attachments");
for (int i = 0; i < (int)_attachmentModels.size(); i++) {
const AttachmentData& attachment = _attachmentData.at(i);
auto& model = _attachmentModels.at(i);
bool texturesLoaded = _attachmentModelsTexturesLoaded.at(i);
// Watch for texture loading
if (!texturesLoaded && model->getGeometry() && model->getGeometry()->areTexturesLoaded()) {
_attachmentModelsTexturesLoaded[i] = true;
model->updateRenderItems();
}
int jointIndex = getJointIndex(attachment.jointName);
glm::vec3 jointPosition;
glm::quat jointRotation;
@ -1319,6 +1328,7 @@ void Avatar::setAttachmentData(const QVector<AttachmentData>& attachmentData) {
while ((int)_attachmentModels.size() > attachmentData.size()) {
auto attachmentModel = _attachmentModels.back();
_attachmentModels.pop_back();
_attachmentModelsTexturesLoaded.pop_back();
_attachmentsToRemove.push_back(attachmentModel);
}
@ -1326,11 +1336,16 @@ void Avatar::setAttachmentData(const QVector<AttachmentData>& attachmentData) {
if (i == (int)_attachmentModels.size()) {
// if number of attachments has been increased, we need to allocate a new model
_attachmentModels.push_back(allocateAttachmentModel(attachmentData[i].isSoft, _skeletonModel->getRig(), isMyAvatar()));
}
else if (i < oldAttachmentData.size() && oldAttachmentData[i].isSoft != attachmentData[i].isSoft) {
_attachmentModelsTexturesLoaded.push_back(false);
} else if (i < oldAttachmentData.size() && oldAttachmentData[i].isSoft != attachmentData[i].isSoft) {
// if the attachment has changed type, we need to re-allocate a new one.
_attachmentsToRemove.push_back(_attachmentModels[i]);
_attachmentModels[i] = allocateAttachmentModel(attachmentData[i].isSoft, _skeletonModel->getRig(), isMyAvatar());
_attachmentModelsTexturesLoaded[i] = false;
}
// If the model URL has changd, we need to wait for the textures to load
if (_attachmentModels[i]->getURL() != attachmentData[i].modelURL) {
_attachmentModelsTexturesLoaded[i] = false;
}
_attachmentModels[i]->setURL(attachmentData[i].modelURL);
}

View file

@ -306,6 +306,7 @@ protected:
glm::vec3 _skeletonOffset;
std::vector<std::shared_ptr<Model>> _attachmentModels;
std::vector<bool> _attachmentModelsTexturesLoaded;
std::vector<std::shared_ptr<Model>> _attachmentsToRemove;
std::vector<std::shared_ptr<Model>> _attachmentsToDelete;

Some files were not shown because too many files have changed in this diff Show more