merging from upstream

This commit is contained in:
amer cerkic 2019-02-14 16:31:04 -08:00
commit 7037e14d09
290 changed files with 4369 additions and 2980 deletions

View file

@ -81,7 +81,11 @@ if (ANDROID)
set(GLES_OPTION ON)
set(PLATFORM_QT_COMPONENTS AndroidExtras WebView)
add_definitions(-DHIFI_ANDROID_APP=\"${HIFI_ANDROID_APP}\")
if (${HIFI_ANDROID_APP} STREQUAL "questInterface")
if (
(${HIFI_ANDROID_APP} STREQUAL "questInterface") OR
(${HIFI_ANDROID_APP} STREQUAL "questFramePlayer") OR
(${HIFI_ANDROID_APP} STREQUAL "framePlayer")
)
# We know the quest hardware has this extension, so we can force the use of instanced stereo
add_definitions(-DHAVE_EXT_clip_cull_distance)
# We can also use multiview stereo techniques
@ -89,9 +93,15 @@ if (ANDROID)
add_definitions(-DHAVE_OVR_multiview)
# We can also use our own foveated textures
add_definitions(-DHAVE_QCOM_texture_foveated)
# if set, the application itself or some library it depends on MUST implement
# `DisplayPluginList getDisplayPlugins()` and `InputPluginList getInputPlugins()`
add_definitions(-DCUSTOM_INPUT_PLUGINS)
add_definitions(-DCUSTOM_DISPLAY_PLUGINS)
set(PLATFORM_PLUGIN_LIBRARIES oculusMobile oculusMobilePlugin)
endif()
else ()
set(PLATFORM_QT_COMPONENTS WebEngine)
set(PLATFORM_QT_COMPONENTS WebEngine Xml)
endif ()
if (USE_GLES AND (NOT ANDROID))

View file

@ -24,6 +24,7 @@ import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.Vibrator;
import android.text.TextUtils;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
@ -54,6 +55,7 @@ public class InterfaceActivity extends QtActivity implements WebViewFragment.OnW
public static final String DOMAIN_URL = "url";
public static final String EXTRA_GOTO_USERNAME = "gotousername";
private static final String TAG = "Interface";
public static final String EXTRA_ARGS = "args";
private static final int WEB_DRAWER_RIGHT_MARGIN = 262;
private static final int WEB_DRAWER_BOTTOM_MARGIN = 150;
private static final int NORMAL_DPI = 160;
@ -78,6 +80,7 @@ public class InterfaceActivity extends QtActivity implements WebViewFragment.OnW
private boolean nativeEnterBackgroundCallEnqueued = false;
private SlidingDrawer mWebSlidingDrawer;
private boolean mStartInDomain;
// 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.
@ -93,8 +96,14 @@ public class InterfaceActivity extends QtActivity implements WebViewFragment.OnW
public void onCreate(Bundle savedInstanceState) {
super.isLoading = true;
Intent intent = getIntent();
if (intent.hasExtra(DOMAIN_URL) && !intent.getStringExtra(DOMAIN_URL).isEmpty()) {
if (intent.hasExtra(DOMAIN_URL) && !TextUtils.isEmpty(intent.getStringExtra(DOMAIN_URL))) {
intent.putExtra("applicationArguments", "--url " + intent.getStringExtra(DOMAIN_URL));
} else if (intent.hasExtra(EXTRA_ARGS)) {
String args = intent.getStringExtra(EXTRA_ARGS);
if (!TextUtils.isEmpty(args)) {
mStartInDomain = true;
intent.putExtra("applicationArguments", args);
}
}
super.onCreate(savedInstanceState);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
@ -125,7 +134,10 @@ public class InterfaceActivity extends QtActivity implements WebViewFragment.OnW
getActionBar().hide();
}
});
startActivity(new Intent(this, SplashActivity.class));
Intent splashIntent = new Intent(this, SplashActivity.class);
splashIntent.putExtra(SplashActivity.EXTRA_START_IN_DOMAIN, mStartInDomain);
startActivity(splashIntent);
mVibrator = (Vibrator) this.getSystemService(VIBRATOR_SERVICE);
headsetStateReceiver = new HeadsetStateReceiver();
}

View file

@ -1,4 +1,3 @@
package io.highfidelity.hifiinterface;
import android.app.Activity;

View file

@ -9,6 +9,7 @@ import android.content.pm.PackageManager;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.text.TextUtils;
import org.json.JSONException;
import org.json.JSONObject;
@ -27,9 +28,14 @@ public class PermissionChecker extends Activity {
private static final boolean CHOOSE_AVATAR_ON_STARTUP = false;
private static final String TAG = "Interface";
private static final String EXTRA_ARGS = "args";
private String mArgs;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mArgs =(getIntent().getStringExtra(EXTRA_ARGS));
Intent myIntent = new Intent(this, BreakpadUploaderService.class);
startService(myIntent);
if (CHOOSE_AVATAR_ON_STARTUP) {
@ -76,6 +82,11 @@ public class PermissionChecker extends Activity {
private void launchActivityWithPermissions(){
Intent i = new Intent(this, InterfaceActivity.class);
if (!TextUtils.isEmpty(mArgs)) {
i.putExtra(EXTRA_ARGS, mArgs);
}
startActivity(i);
finish();
}

View file

@ -7,6 +7,9 @@ import android.view.View;
public class SplashActivity extends Activity {
public static final String EXTRA_START_IN_DOMAIN = "start-in-domain";
private boolean mStartInDomain;
private native void registerLoadCompleteListener();
@Override
@ -36,13 +39,27 @@ public class SplashActivity extends Activity {
}
public void onAppLoadedComplete() {
if (HifiUtils.getInstance().isUserLoggedIn()) {
startActivity(new Intent(this, MainActivity.class));
} else {
Intent menuIntent = new Intent(this, LoginMenuActivity.class);
menuIntent.putExtra(LoginMenuActivity.EXTRA_FINISH_ON_BACK, true);
startActivity(menuIntent);
if (!mStartInDomain) {
if (HifiUtils.getInstance().isUserLoggedIn()) {
startActivity(new Intent(this, MainActivity.class));
} else {
Intent menuIntent = new Intent(this, LoginMenuActivity.class);
menuIntent.putExtra(LoginMenuActivity.EXTRA_FINISH_ON_BACK, true);
startActivity(menuIntent);
}
}
SplashActivity.this.finish();
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putBoolean(EXTRA_START_IN_DOMAIN, mStartInDomain);
}
@Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
mStartInDomain = savedInstanceState.getBoolean(EXTRA_START_IN_DOMAIN, false);
}
}

View file

@ -15,6 +15,7 @@ android {
'-DHIFI_ANDROID_APP=questFramePlayer',
'-DANDROID_TOOLCHAIN=clang',
'-DANDROID_STL=c++_shared',
'-DCMAKE_VERBOSE_MAKEFILE=ON'
targets = ['questFramePlayer']
}

View file

@ -1,15 +1,29 @@
import de.undercouch.gradle.tasks.download.Download
import de.undercouch.gradle.tasks.download.Verify
import groovy.io.FileType
import groovy.json.JsonSlurper
import groovy.xml.XmlUtil
import org.apache.tools.ant.taskdefs.condition.Os
import java.util.regex.Matcher
import java.util.regex.Pattern
buildscript {
repositories {
google()
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:3.3.0'
classpath 'com.android.tools.build:gradle:3.2.1'
}
}
plugins {
id 'de.undercouch.download' version '3.3.0'
id "cz.malohlava" version "1.0.3"
id "io.github.http-builder-ng.http-plugin" version "0.1.1"
}
allprojects {
repositories {
google()
@ -18,6 +32,10 @@ allprojects {
}
}
task clean(type: Delete) {
delete rootProject.buildDir
}
ext {
RELEASE_NUMBER = project.hasProperty('RELEASE_NUMBER') ? project.getProperty('RELEASE_NUMBER') : '0'
VERSION_CODE = project.hasProperty('VERSION_CODE') ? project.getProperty('VERSION_CODE') : '0'
@ -126,6 +144,108 @@ task setupDependencies() {
task cleanDependencies(type: Delete) {
}
def runBreakpadDumpSyms = { buildType ->
gradle.startParameter.showStacktrace = ShowStacktrace.ALWAYS
def objDir = new File("${appDir}/build/intermediates/cmake/${buildType}/obj/arm64-v8a")
def stripDebugSymbol = "${appDir}/build/intermediates/transforms/stripDebugSymbol/${buildType}/0/lib/arm64-v8a/"
def outputDir = new File(breakpadDumpSymsDir, buildType)
if (!outputDir.exists()) {
outputDir.mkdirs()
}
objDir.eachFileRecurse (FileType.FILES) { file ->
if (file.name.endsWith('.so')) {
def output = file.name + ".sym"
def cmdArgs = [
file.toString(),
stripDebugSymbol
]
def result = exec {
workingDir HIFI_ANDROID_PRECOMPILED + '/breakpad/bin'
commandLine './dump_syms'
args cmdArgs
ignoreExitValue true
standardOutput = new BufferedOutputStream(new FileOutputStream(new File(outputDir, output)))
}
}
}
}
task runBreakpadDumpSymsDebug() {
doLast {
runBreakpadDumpSyms("debug");
}
}
task runBreakpadDumpSymsRelease() {
doLast {
runBreakpadDumpSyms("release");
}
}
task zipDumpSymsDebug(type: Zip, dependsOn: runBreakpadDumpSymsDebug) {
from (new File(breakpadDumpSymsDir, "debug").absolutePath)
archiveName "symbols-${RELEASE_NUMBER}-debug.zip"
destinationDir(new File("${appDir}/build/tmp/"))
}
task zipDumpSymsRelease(type: Zip, dependsOn: runBreakpadDumpSymsRelease) {
from (new File(breakpadDumpSymsDir, "release").absolutePath)
archiveName "symbols-${RELEASE_NUMBER}-release.zip"
destinationDir(new File("${appDir}/build/tmp/"))
}
task uploadBreakpadDumpSymsDebug(type:io.github.httpbuilderng.http.HttpTask, dependsOn: zipDumpSymsDebug) {
onlyIf {
System.getenv("CMAKE_BACKTRACE_URL") && System.getenv("CMAKE_BACKTRACE_SYMBOLS_TOKEN")
}
config {
request.uri = System.getenv("CMAKE_BACKTRACE_URL")
}
post {
request.uri.path = '/post'
request.uri.query = [format: 'symbols', token: System.getenv("CMAKE_BACKTRACE_SYMBOLS_TOKEN")]
request.body = new File("${appDir}/build/tmp/", "symbols-${RELEASE_NUMBER}-debug.zip").bytes
request.contentType = 'application/octet-stream'
response.success {
println ("${appDir}/build/tmp/symbols-${RELEASE_NUMBER}-debug.zip uploaded")
}
}
}
task uploadBreakpadDumpSymsRelease(type:io.github.httpbuilderng.http.HttpTask, dependsOn: zipDumpSymsRelease) {
onlyIf {
System.getenv("CMAKE_BACKTRACE_URL") && System.getenv("CMAKE_BACKTRACE_SYMBOLS_TOKEN")
}
config {
request.uri = System.getenv("CMAKE_BACKTRACE_URL")
}
post {
request.uri.path = '/post'
request.uri.query = [format: 'symbols', token: System.getenv("CMAKE_BACKTRACE_SYMBOLS_TOKEN")]
request.body = new File("${appDir}/build/tmp/", "symbols-${RELEASE_NUMBER}-release.zip").bytes
request.contentType = 'application/octet-stream'
response.success {
println ("${appDir}/build/tmp/symbols-${RELEASE_NUMBER}-release.zip uploaded")
}
}
}
task renameHifiACTaskDebug() {
doLast {
def sourceFile = new File("${appDir}/build/intermediates/cmake/debug/obj/arm64-v8a/","libhifiCodec.so")
def destinationFile = new File("${appDir}/src/main/jniLibs/arm64-v8a", "libplugins_libhifiCodec.so")
copy { from sourceFile; into destinationFile.parent; rename(sourceFile.name, destinationFile.name) }
}
}
task renameHifiACTaskRelease(type: Copy) {
doLast {
def sourceFile = new File("${appDir}/build/intermediates/cmake/release/obj/arm64-v8a/","libhifiCodec.so")
def destinationFile = new File("${appDir}/src/main/jniLibs/arm64-v8a", "libplugins_libhifiCodec.so")
copy { from sourceFile; into destinationFile.parent; rename(sourceFile.name, destinationFile.name) }
}
}
// 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

@ -12,8 +12,8 @@ project(':qt').projectDir = new File(settingsDir, 'libraries/qt')
// Applications
//
//include ':interface'
//project(':interface').projectDir = new File(settingsDir, 'apps/interface')
include ':interface'
project(':interface').projectDir = new File(settingsDir, 'apps/interface')
include ':questInterface'
project(':questInterface').projectDir = new File(settingsDir, 'apps/questInterface')
@ -22,8 +22,8 @@ project(':questInterface').projectDir = new File(settingsDir, 'apps/questInterfa
// Test projects
//
//include ':framePlayer'
//project(':framePlayer').projectDir = new File(settingsDir, 'apps/framePlayer')
include ':framePlayer'
project(':framePlayer').projectDir = new File(settingsDir, 'apps/framePlayer')
//include ':questFramePlayer'
//project(':questFramePlayer').projectDir = new File(settingsDir, 'apps/questFramePlayer')
include ':questFramePlayer'
project(':questFramePlayer').projectDir = new File(settingsDir, 'apps/questFramePlayer')

View file

@ -38,6 +38,19 @@ const QString AVATAR_MIXER_LOGGING_NAME = "avatar-mixer";
// FIXME - what we'd actually like to do is send to users at ~50% of their present rate down to 30hz. Assume 90 for now.
const int AVATAR_MIXER_BROADCAST_FRAMES_PER_SECOND = 45;
const QRegularExpression AvatarMixer::suffixedNamePattern { R"(^\s*(.+)\s*_(\d)+\s*$)" };
// Lexicographic comparison:
bool AvatarMixer::SessionDisplayName::operator<(const SessionDisplayName& rhs) const {
if (_baseName < rhs._baseName) {
return true;
} else if (rhs._baseName < _baseName) {
return false;
} else {
return _suffix < rhs._suffix;
}
}
AvatarMixer::AvatarMixer(ReceivedMessage& message) :
ThreadedAssignment(message),
_slavePool(&_slaveSharedData)
@ -313,27 +326,40 @@ void AvatarMixer::manageIdentityData(const SharedNodePointer& node) {
bool sendIdentity = false;
if (nodeData && nodeData->getAvatarSessionDisplayNameMustChange()) {
AvatarData& avatar = nodeData->getAvatar();
const QString& existingBaseDisplayName = nodeData->getBaseDisplayName();
if (--_sessionDisplayNames[existingBaseDisplayName].second <= 0) {
_sessionDisplayNames.remove(existingBaseDisplayName);
const QString& existingBaseDisplayName = nodeData->getAvatar().getSessionDisplayName();
if (!existingBaseDisplayName.isEmpty()) {
SessionDisplayName existingDisplayName { existingBaseDisplayName };
auto suffixMatch = suffixedNamePattern.match(existingBaseDisplayName);
if (suffixMatch.hasMatch()) {
existingDisplayName._baseName = suffixMatch.captured(1);
existingDisplayName._suffix = suffixMatch.captured(2).toInt();
}
_sessionDisplayNames.erase(existingDisplayName);
}
QString baseName = avatar.getDisplayName().trimmed();
const QRegularExpression curses { "fuck|shit|damn|cock|cunt" }; // POC. We may eventually want something much more elaborate (subscription?).
baseName = baseName.replace(curses, "*"); // Replace rather than remove, so that people have a clue that the person's a jerk.
const QRegularExpression trailingDigits { "\\s*(_\\d+\\s*)?(\\s*\\n[^$]*)?$" }; // trailing whitespace "_123" and any subsequent lines
static const QRegularExpression trailingDigits { R"(\s*(_\d+\s*)?(\s*\n[^$]*)?$)" }; // trailing whitespace "_123" and any subsequent lines
baseName = baseName.remove(trailingDigits);
if (baseName.isEmpty()) {
baseName = "anonymous";
}
QPair<int, int>& soFar = _sessionDisplayNames[baseName]; // Inserts and answers 0, 0 if not already present, which is what we want.
int& highWater = soFar.first;
nodeData->setBaseDisplayName(baseName);
QString sessionDisplayName = (highWater > 0) ? baseName + "_" + QString::number(highWater) : baseName;
SessionDisplayName newDisplayName { baseName };
auto nameIter = _sessionDisplayNames.lower_bound(newDisplayName);
if (nameIter != _sessionDisplayNames.end() && nameIter->_baseName == baseName) {
// Existing instance(s) of name; find first free suffix
while (*nameIter == newDisplayName && ++newDisplayName._suffix && ++nameIter != _sessionDisplayNames.end())
;
}
_sessionDisplayNames.insert(newDisplayName);
QString sessionDisplayName = (newDisplayName._suffix > 0) ? baseName + "_" + QString::number(newDisplayName._suffix) : baseName;
avatar.setSessionDisplayName(sessionDisplayName);
highWater++;
soFar.second++; // refcount
nodeData->setBaseDisplayName(baseName);
nodeData->flagIdentityChange();
nodeData->setAvatarSessionDisplayNameMustChange(false);
sendIdentity = true;
@ -409,10 +435,19 @@ void AvatarMixer::handleAvatarKilled(SharedNodePointer avatarNode) {
{ // decrement sessionDisplayNames table and possibly remove
QMutexLocker nodeDataLocker(&avatarNode->getLinkedData()->getMutex());
AvatarMixerClientData* nodeData = dynamic_cast<AvatarMixerClientData*>(avatarNode->getLinkedData());
const QString& baseDisplayName = nodeData->getBaseDisplayName();
// No sense guarding against very rare case of a node with no entry, as this will work without the guard and do one less lookup in the common case.
if (--_sessionDisplayNames[baseDisplayName].second <= 0) {
_sessionDisplayNames.remove(baseDisplayName);
const QString& displayName = nodeData->getAvatar().getSessionDisplayName();
SessionDisplayName exitingDisplayName { displayName };
auto suffixMatch = suffixedNamePattern.match(displayName);
if (suffixMatch.hasMatch()) {
exitingDisplayName._baseName = suffixMatch.captured(1);
exitingDisplayName._suffix = suffixMatch.captured(2).toInt();
}
auto displayNameIter = _sessionDisplayNames.find(exitingDisplayName);
if (displayNameIter == _sessionDisplayNames.end()) {
qCDebug(avatars) << "Exiting avatar displayname" << displayName << "not found";
} else {
_sessionDisplayNames.erase(displayNameIter);
}
}

View file

@ -15,6 +15,7 @@
#ifndef hifi_AvatarMixer_h
#define hifi_AvatarMixer_h
#include <set>
#include <shared/RateCounter.h>
#include <PortableHighResolutionClock.h>
@ -88,7 +89,24 @@ private:
RateCounter<> _broadcastRate;
p_high_resolution_clock::time_point _lastDebugMessage;
QHash<QString, QPair<int, int>> _sessionDisplayNames;
// Pair of basename + uniquifying integer suffix.
struct SessionDisplayName {
explicit SessionDisplayName(QString baseName = QString(), int suffix = 0) :
_baseName(baseName),
_suffix(suffix) { }
// Does lexicographic ordering:
bool operator<(const SessionDisplayName& rhs) const;
bool operator==(const SessionDisplayName& rhs) const {
return _baseName == rhs._baseName && _suffix == rhs._suffix;
}
QString _baseName;
int _suffix;
};
static const QRegularExpression suffixedNamePattern;
std::set<SessionDisplayName> _sessionDisplayNames;
quint64 _displayNameManagementElapsedTime { 0 }; // total time spent in broadcastAvatarData/display name management... since last stats window
quint64 _ignoreCalculationElapsedTime { 0 };

View file

@ -111,7 +111,7 @@ bool EntityTreeSendThread::traverseTreeAndSendContents(SharedNodePointer node, O
int32_t lodLevelOffset = nodeData->getBoundaryLevelAdjust() + (viewFrustumChanged ? LOW_RES_MOVING_ADJUST : NO_BOUNDARY_ADJUST);
newView.lodScaleFactor = powf(2.0f, lodLevelOffset);
startNewTraversal(newView, root);
startNewTraversal(newView, root, isFullScene);
// When the viewFrustum changed the sort order may be incorrect, so we re-sort
// and also use the opportunity to cull anything no longer in view
@ -220,9 +220,10 @@ bool EntityTreeSendThread::addDescendantsToExtraFlaggedEntities(const QUuid& fil
return hasNewChild || hasNewDescendants;
}
void EntityTreeSendThread::startNewTraversal(const DiffTraversal::View& view, EntityTreeElementPointer root) {
void EntityTreeSendThread::startNewTraversal(const DiffTraversal::View& view, EntityTreeElementPointer root,
bool forceFirstPass) {
DiffTraversal::Type type = _traversal.prepareNewTraversal(view, root);
DiffTraversal::Type type = _traversal.prepareNewTraversal(view, root, forceFirstPass);
// there are three types of traversal:
//
// (1) FirstTime = at login --> find everything in view

View file

@ -42,7 +42,7 @@ private:
bool addAncestorsToExtraFlaggedEntities(const QUuid& filteredEntityID, EntityItem& entityItem, EntityNodeData& nodeData);
bool addDescendantsToExtraFlaggedEntities(const QUuid& filteredEntityID, EntityItem& entityItem, EntityNodeData& nodeData);
void startNewTraversal(const DiffTraversal::View& viewFrustum, EntityTreeElementPointer root);
void startNewTraversal(const DiffTraversal::View& viewFrustum, EntityTreeElementPointer root, bool forceFirstPass = false);
bool traverseTreeAndBuildNextPacketPayload(EncodeBitstreamParams& params, const QJsonObject& jsonFilters) override;
void preDistributionProcessing() override;

View file

@ -0,0 +1,36 @@
#
# FixupNitpick.cmake
# cmake/macros
#
# Copyright 2019 High Fidelity, Inc.
# Created by Nissim Hadar on January 14th, 2016
#
# Distributed under the Apache License, Version 2.0.
# See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
#
macro(fixup_nitpick)
if (APPLE)
string(REPLACE " " "\\ " ESCAPED_BUNDLE_NAME ${NITPICK_BUNDLE_NAME})
string(REPLACE " " "\\ " ESCAPED_INSTALL_PATH ${NITPICK_INSTALL_DIR})
set(_NITPICK_INSTALL_PATH "${ESCAPED_INSTALL_PATH}/${ESCAPED_BUNDLE_NAME}.app")
find_program(MACDEPLOYQT_COMMAND macdeployqt PATHS "${QT_DIR}/bin" NO_DEFAULT_PATH)
if (NOT MACDEPLOYQT_COMMAND AND (PRODUCTION_BUILD OR PR_BUILD))
message(FATAL_ERROR "Could not find macdeployqt at ${QT_DIR}/bin.\
It is required to produce a relocatable nitpick application.\
Check that the environment variable QT_DIR points to your Qt installation.\
")
endif ()
install(CODE "
execute_process(COMMAND ${MACDEPLOYQT_COMMAND}\
\${CMAKE_INSTALL_PREFIX}/${_NITPICK_INSTALL_PATH}/\
-verbose=2 -qmldir=${CMAKE_SOURCE_DIR}/interface/resources/qml/\
)"
COMPONENT ${CLIENT_COMPONENT}
)
endif ()
endmacro()

View file

@ -77,6 +77,9 @@ macro(SET_PACKAGING_PARAMETERS)
add_definitions(-DDEV_BUILD)
endif ()
set(NITPICK_BUNDLE_NAME "nitpick")
set(NITPICK_ICON_PREFIX "nitpick")
string(TIMESTAMP BUILD_TIME "%d/%m/%Y")
# if STABLE_BUILD is 1, PRODUCTION_BUILD must be 1 and
@ -140,8 +143,9 @@ macro(SET_PACKAGING_PARAMETERS)
set(DMG_SUBFOLDER_ICON "${HF_CMAKE_DIR}/installer/install-folder.rsrc")
set(CONSOLE_INSTALL_DIR ${DMG_SUBFOLDER_NAME})
set(CONSOLE_INSTALL_DIR ${DMG_SUBFOLDER_NAME})
set(INTERFACE_INSTALL_DIR ${DMG_SUBFOLDER_NAME})
set(NITPICK_INSTALL_DIR ${DMG_SUBFOLDER_NAME})
if (CLIENT_ONLY)
set(CONSOLE_EXEC_NAME "Console.app")
@ -159,11 +163,14 @@ macro(SET_PACKAGING_PARAMETERS)
set(INTERFACE_INSTALL_APP_PATH "${CONSOLE_INSTALL_DIR}/${INTERFACE_BUNDLE_NAME}.app")
set(INTERFACE_ICON_FILENAME "${INTERFACE_ICON_PREFIX}.icns")
set(NITPICK_ICON_FILENAME "${NITPICK_ICON_PREFIX}.icns")
else ()
if (WIN32)
set(CONSOLE_INSTALL_DIR "server-console")
set(NITPICK_INSTALL_DIR "nitpick")
else ()
set(CONSOLE_INSTALL_DIR ".")
set(NITPICK_INSTALL_DIR ".")
endif ()
set(COMPONENT_INSTALL_DIR ".")
@ -173,6 +180,7 @@ macro(SET_PACKAGING_PARAMETERS)
if (WIN32)
set(INTERFACE_EXEC_PREFIX "interface")
set(INTERFACE_ICON_FILENAME "${INTERFACE_ICON_PREFIX}.ico")
set(NITPICK_ICON_FILENAME "${NITPICK_ICON_PREFIX}.ico")
set(CONSOLE_EXEC_NAME "server-console.exe")

View file

@ -202,10 +202,6 @@ if (WIN32)
set_property(TARGET ${TARGET_NAME} APPEND_STRING PROPERTY LINK_FLAGS_DEBUG "/OPT:NOREF /OPT:NOICF")
endif()
if (ANDROID)
set(PLATFORM_DISPLAY_PLUGINS oculusMobile oculusMobilePlugin)
endif()
# link required hifi libraries
link_hifi_libraries(
shared workload task octree ktx gpu gl procedural graphics graphics-scripting render
@ -217,8 +213,8 @@ link_hifi_libraries(
ui-plugins display-plugins input-plugins
# Platform specific GL libraries
${PLATFORM_GL_BACKEND}
# Plaform specific display plugins libraries
${PLATFORM_DISPLAY_PLUGINS}
# Plaform specific input & display plugin libraries
${PLATFORM_PLUGIN_LIBRARIES}
shaders
)
@ -283,7 +279,7 @@ target_link_libraries(
${TARGET_NAME}
Qt5::Gui Qt5::Network Qt5::Multimedia Qt5::Widgets
Qt5::Qml Qt5::Quick Qt5::Script Qt5::Svg
Qt5::WebChannel
Qt5::WebChannel
${PLATFORM_QT_LIBRARIES}
)
@ -337,7 +333,11 @@ if (APPLE)
COMMAND "${CMAKE_COMMAND}" -E copy_directory
"${PROJECT_SOURCE_DIR}/resources/fonts"
"${RESOURCES_DEV_DIR}/fonts"
# add redirect json to macOS builds.
#copy serverless for android
COMMAND "${CMAKE_COMMAND}" -E copy_directory
"${PROJECT_SOURCE_DIR}/resources/serverless"
"${RESOURCES_DEV_DIR}/serverless"
# add redirect json to macOS builds.
COMMAND "${CMAKE_COMMAND}" -E copy_if_different
"${PROJECT_SOURCE_DIR}/resources/serverless/redirect.json"
"${RESOURCES_DEV_DIR}/serverless/redirect.json"

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

View file

@ -10,10 +10,6 @@ joint = jointRoot = Hips
joint = jointLeftHand = LeftHand
joint = jointRightHand = RightHand
joint = jointHead = Head
freeJoint = LeftArm
freeJoint = LeftForeArm
freeJoint = RightArm
freeJoint = RightForeArm
bs = JawOpen = mouth_Open = 1
bs = LipsFunnel = Oo = 1
bs = BrowsU_L = brow_Up = 1

View file

@ -1,275 +0,0 @@
import QtQuick 2.5
import QtWebChannel 1.0
import QtWebEngine 1.5
import controlsUit 1.0
import stylesUit 1.0
import "qrc:////qml//windows"
ScrollingWindow {
id: root
HifiConstants { id: hifi }
//HifiStyles.HifiConstants { id: hifistyles }
title: "Browser"
resizable: true
destroyOnHidden: true
width: 800
height: 600
property variant permissionsBar: {'securityOrigin':'none','feature':'none'}
property alias url: webview.url
property alias webView: webview
signal loadingChanged(int status)
x: 100
y: 100
Component.onCompleted: {
focus = true
shown = true
addressBar.text = webview.url
}
function setProfile(profile) {
webview.profile = profile;
}
function showPermissionsBar(){
permissionsContainer.visible=true;
}
function hidePermissionsBar(){
permissionsContainer.visible=false;
}
function allowPermissions(){
webview.grantFeaturePermission(permissionsBar.securityOrigin, permissionsBar.feature, true);
hidePermissionsBar();
}
function setAutoAdd(auto) {
desktop.setAutoAdd(auto);
}
Item {
id:item
width: pane.contentWidth
implicitHeight: pane.scrollHeight
Row {
id: buttons
spacing: 4
anchors.top: parent.top
anchors.topMargin: 8
anchors.left: parent.left
anchors.leftMargin: 8
HiFiGlyphs {
id: back;
enabled: webview.canGoBack;
text: hifi.glyphs.backward
color: enabled ? hifi.colors.text : hifi.colors.disabledText
size: 48
MouseArea { anchors.fill: parent; onClicked: webview.goBack() }
}
HiFiGlyphs {
id: forward;
enabled: webview.canGoForward;
text: hifi.glyphs.forward
color: enabled ? hifi.colors.text : hifi.colors.disabledText
size: 48
MouseArea { anchors.fill: parent; onClicked: webview.goForward() }
}
HiFiGlyphs {
id: reload;
enabled: webview.canGoForward;
text: webview.loading ? hifi.glyphs.close : hifi.glyphs.reload
color: enabled ? hifi.colors.text : hifi.colors.disabledText
size: 48
MouseArea { anchors.fill: parent; onClicked: webview.goForward() }
}
}
Item {
id: border
height: 48
anchors.top: parent.top
anchors.topMargin: 8
anchors.right: parent.right
anchors.rightMargin: 8
anchors.left: buttons.right
anchors.leftMargin: 8
Item {
id: barIcon
width: parent.height
height: parent.height
Image {
source: webview.icon;
x: (parent.height - height) / 2
y: (parent.width - width) / 2
sourceSize: Qt.size(width, height);
verticalAlignment: Image.AlignVCenter;
horizontalAlignment: Image.AlignHCenter
}
}
TextField {
id: addressBar
anchors.right: parent.right
anchors.rightMargin: 8
anchors.left: barIcon.right
anchors.leftMargin: 0
anchors.verticalCenter: parent.verticalCenter
focus: true
colorScheme: hifi.colorSchemes.dark
placeholderText: "Enter URL"
Component.onCompleted: ScriptDiscoveryService.scriptsModelFilter.filterRegExp = new RegExp("^.*$", "i")
Keys.onPressed: {
switch(event.key) {
case Qt.Key_Enter:
case Qt.Key_Return:
event.accepted = true
if (text.indexOf("http") != 0) {
text = "http://" + text;
}
root.hidePermissionsBar();
root.keyboardRaised = false;
webview.url = text;
break;
}
}
}
}
Rectangle {
id:permissionsContainer
visible:false
color: "#000000"
width: parent.width
anchors.top: buttons.bottom
height:40
z:100
gradient: Gradient {
GradientStop { position: 0.0; color: "black" }
GradientStop { position: 1.0; color: "grey" }
}
RalewayLight {
id: permissionsInfo
anchors.right:permissionsRow.left
anchors.rightMargin: 32
anchors.topMargin:8
anchors.top:parent.top
text: "This site wants to use your microphone/camera"
size: 18
color: hifi.colors.white
}
Row {
id: permissionsRow
spacing: 4
anchors.top:parent.top
anchors.topMargin: 8
anchors.right: parent.right
visible: true
z:101
Button {
id:allow
text: "Allow"
color: hifi.buttons.blue
colorScheme: root.colorScheme
width: 120
enabled: true
onClicked: root.allowPermissions();
z:101
}
Button {
id:block
text: "Block"
color: hifi.buttons.red
colorScheme: root.colorScheme
width: 120
enabled: true
onClicked: root.hidePermissionsBar();
z:101
}
}
}
WebView {
id: webview
url: "https://highfidelity.com/"
profile: FileTypeProfile;
// Create a global EventBridge object for raiseAndLowerKeyboard.
WebEngineScript {
id: createGlobalEventBridge
sourceCode: eventBridgeJavaScriptToInject
injectionPoint: WebEngineScript.Deferred
worldId: WebEngineScript.MainWorld
}
// Detect when may want to raise and lower keyboard.
WebEngineScript {
id: raiseAndLowerKeyboard
injectionPoint: WebEngineScript.Deferred
sourceUrl: resourceDirectoryUrl + "/html/raiseAndLowerKeyboard.js"
worldId: WebEngineScript.MainWorld
}
userScripts: [ createGlobalEventBridge, raiseAndLowerKeyboard ]
anchors.top: buttons.bottom
anchors.topMargin: 8
anchors.bottom: parent.bottom
anchors.left: parent.left
anchors.right: parent.right
onFeaturePermissionRequested: {
if (feature == 2) { // QWebEnginePage::MediaAudioCapture
grantFeaturePermission(securityOrigin, feature, true);
} else {
permissionsBar.securityOrigin = securityOrigin;
permissionsBar.feature = feature;
root.showPermissionsBar();
}
}
onLoadingChanged: {
if (loadRequest.status === WebEngineView.LoadSucceededStatus) {
addressBar.text = loadRequest.url
}
root.loadingChanged(loadRequest.status);
}
onWindowCloseRequested: {
root.destroy();
}
Component.onCompleted: {
webChannel.registerObject("eventBridge", eventBridge);
webChannel.registerObject("eventBridgeWrapper", eventBridgeWrapper);
desktop.initWebviewProfileHandlers(webview.profile);
}
}
} // item
Keys.onPressed: {
switch(event.key) {
case Qt.Key_L:
if (event.modifiers == Qt.ControlModifier) {
event.accepted = true
addressBar.selectAll()
addressBar.forceActiveFocus()
}
break;
}
}
} // dialog

View file

@ -0,0 +1,58 @@
import QtQuick 2.5
import QtWebChannel 1.0
import QtWebEngine 1.5
import controlsUit 1.0
WebView {
id: webview
url: "https://highfidelity.com/"
profile: FileTypeProfile;
property var parentRoot: null
// Create a global EventBridge object for raiseAndLowerKeyboard.
WebEngineScript {
id: createGlobalEventBridge
sourceCode: eventBridgeJavaScriptToInject
injectionPoint: WebEngineScript.Deferred
worldId: WebEngineScript.MainWorld
}
// Detect when may want to raise and lower keyboard.
WebEngineScript {
id: raiseAndLowerKeyboard
injectionPoint: WebEngineScript.Deferred
sourceUrl: resourceDirectoryUrl + "/html/raiseAndLowerKeyboard.js"
worldId: WebEngineScript.MainWorld
}
userScripts: [ createGlobalEventBridge, raiseAndLowerKeyboard ]
onFeaturePermissionRequested: {
if (feature == 2) { // QWebEnginePage::MediaAudioCapture
grantFeaturePermission(securityOrigin, feature, true);
} else {
permissionsBar.securityOrigin = securityOrigin;
permissionsBar.feature = feature;
parentRoot.showPermissionsBar();
}
}
onLoadingChanged: {
if (loadRequest.status === WebEngineView.LoadSucceededStatus) {
addressBar.text = loadRequest.url
}
parentRoot.loadingChanged(loadRequest.status);
}
onWindowCloseRequested: {
parentRoot.destroy();
}
Component.onCompleted: {
webChannel.registerObject("eventBridge", eventBridge);
webChannel.registerObject("eventBridgeWrapper", eventBridgeWrapper);
desktop.initWebviewProfileHandlers(webview.profile);
}
}

View file

@ -1,50 +0,0 @@
//
// InfoView.qml
//
// Created by Bradley Austin Davis on 27 Apr 2015
// 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
//
import QtQuick 2.5
import Hifi 1.0 as Hifi
import controlsUit 1.0
import "qrc:////qml//windows" as Windows
Windows.ScrollingWindow {
id: root
width: 800
height: 800
resizable: true
Hifi.InfoView {
id: infoView
width: pane.contentWidth
implicitHeight: pane.scrollHeight
WebView {
id: webview
objectName: "WebView"
anchors.fill: parent
url: infoView.url
}
}
Component.onCompleted: {
centerWindow(root);
}
onVisibleChanged: {
if (visible) {
centerWindow(root);
}
}
function centerWindow() {
desktop.centerOnVisible(root);
}
}

View file

@ -0,0 +1,53 @@
import QtQuick 2.5
import QtWebEngine 1.1
import QtWebChannel 1.0
import controlsUit 1.0 as Controls
import stylesUit 1.0
Controls.WebView {
id: webview
url: "about:blank"
anchors.fill: parent
focus: true
profile: HFWebEngineProfile;
property string userScriptUrl: ""
// Create a global EventBridge object for raiseAndLowerKeyboard.
WebEngineScript {
id: createGlobalEventBridge
sourceCode: eventBridgeJavaScriptToInject
injectionPoint: WebEngineScript.DocumentCreation
worldId: WebEngineScript.MainWorld
}
// Detect when may want to raise and lower keyboard.
WebEngineScript {
id: raiseAndLowerKeyboard
injectionPoint: WebEngineScript.Deferred
sourceUrl: resourceDirectoryUrl + "/html/raiseAndLowerKeyboard.js"
worldId: WebEngineScript.MainWorld
}
// User script.
WebEngineScript {
id: userScript
sourceUrl: webview.userScriptUrl
injectionPoint: WebEngineScript.DocumentReady // DOM ready but page load may not be finished.
worldId: WebEngineScript.MainWorld
}
userScripts: [ createGlobalEventBridge, raiseAndLowerKeyboard, userScript ]
function onWebEventReceived(event) {
if (event.slice(0, 17) === "CLARA.IO DOWNLOAD") {
ApplicationInterface.addAssetToWorldFromURL(event.slice(18));
}
}
Component.onCompleted: {
webChannel.registerObject("eventBridge", eventBridge);
webChannel.registerObject("eventBridgeWrapper", eventBridgeWrapper);
eventBridge.webEventReceived.connect(onWebEventReceived);
}
}

View file

@ -1,14 +1,13 @@
import QtQuick 2.5
import controlsUit 1.0
import stylesUit 1.0
import "windows"
import "."
ScrollingWindow {
id: root
HifiConstants { id: hifi }
//HifiStyles.HifiConstants { id: hifistyles }
title: "Browser"
resizable: true
destroyOnHidden: true
@ -30,6 +29,7 @@ ScrollingWindow {
}
function setProfile(profile) {
webview.profile = profile;
}
function showPermissionsBar(){
@ -41,6 +41,7 @@ ScrollingWindow {
}
function allowPermissions(){
webview.grantFeaturePermission(permissionsBar.securityOrigin, permissionsBar.feature, true);
hidePermissionsBar();
}
@ -198,10 +199,15 @@ ScrollingWindow {
}
}
ProxyWebView {
BrowserWebView {
id: webview
anchors.centerIn: parent
url: "https://highfidelity.com/"
parentRoot: root
anchors.top: buttons.bottom
anchors.topMargin: 8
anchors.bottom: parent.bottom
anchors.left: parent.left
anchors.right: parent.right
}
} // item

View file

@ -0,0 +1,8 @@
import QtQuick 2.5
import controlsUit 1.0
ProxyWebView {
property var parentRoot: null
function grantFeaturePermission(origin, feature) {}
}

View file

@ -24,7 +24,7 @@ Windows.ScrollingWindow {
width: pane.contentWidth
implicitHeight: pane.scrollHeight
ProxyWebView {
BaseWebView {
id: webview
objectName: "WebView"
anchors.fill: parent

View file

@ -9,10 +9,9 @@
//
import QtQuick 2.5
import QtWebView 1.1
import QtWebChannel 1.0
import "windows" as Windows
import "."
import controlsUit 1.0 as Controls
import stylesUit 1.0
@ -57,25 +56,8 @@ Windows.ScrollingWindow {
width: pane.contentWidth
implicitHeight: pane.scrollHeight
Controls.WebView {
QmlWebWindowView {
id: webview
url: "about:blank"
anchors.fill: parent
focus: true
property string userScriptUrl: ""
function onWebEventReceived(event) {
if (event.slice(0, 17) === "CLARA.IO DOWNLOAD") {
ApplicationInterface.addAssetToWorldFromURL(event.slice(18));
}
}
Component.onCompleted: {
webChannel.registerObject("eventBridge", eventBridge);
webChannel.registerObject("eventBridgeWrapper", eventBridgeWrapper);
eventBridge.webEventReceived.connect(onWebEventReceived);
}
}
}
}

View file

@ -0,0 +1,5 @@
import QtQuick 2.5
import controlsUit 1.0
BaseWebView {
}

View file

@ -1,7 +1,7 @@
//
// Web3DOverlay.qml
//
// Created by Gabriel Calero & Cristian Duarte on Jun 22, 2018
// Created by David Rowe on 16 Dec 2016.
// Copyright 2016 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
@ -9,68 +9,23 @@
//
import QtQuick 2.5
import QtGraphicalEffects 1.0
Item {
import "controls" as Controls
property string url
RadialGradient {
anchors.fill: parent
gradient: Gradient {
GradientStop { position: 0.0; color: "#262626" }
GradientStop { position: 1.0; color: "#000000" }
Controls.WebView {
// This is for JS/QML communication, which is unused in a Web3DOverlay,
// but not having this here results in spurious warnings about a
// missing signal
signal sendToScript(var message);
function onWebEventReceived(event) {
if (event.slice(0, 17) === "CLARA.IO DOWNLOAD") {
ApplicationInterface.addAssetToWorldFromURL(event.slice(18));
}
}
function shortUrl(url) {
var hostBegin = url.indexOf("://");
if (hostBegin > -1) {
url = url.substring(hostBegin + 3);
}
var portBegin = url.indexOf(":");
if (portBegin > -1) {
url = url.substring(0, portBegin);
}
var pathBegin = url.indexOf("/");
if (pathBegin > -1) {
url = url.substring(0, pathBegin);
}
if (url.length > 45) {
url = url.substring(0, 45);
}
return url;
Component.onCompleted: {
eventBridge.webEventReceived.connect(onWebEventReceived);
}
Text {
id: urlText
text: shortUrl(url)
verticalAlignment: Text.AlignVCenter
horizontalAlignment: Text.AlignHCenter
anchors.fill: parent
anchors.rightMargin: 10
anchors.leftMargin: 10
font.family: "Cairo"
font.weight: Font.DemiBold
font.pointSize: 48
fontSizeMode: Text.Fit
color: "#FFFFFF"
minimumPixelSize: 5
}
Image {
id: hand
source: "../../icons/hand.svg"
width: 300
height: 300
anchors.bottom: parent.bottom
anchors.right: parent.right
anchors.bottomMargin: 100
anchors.rightMargin: 100
}
}
}

View file

@ -0,0 +1,24 @@
//
// WebSpinner.qml
//
// Created by David Rowe on 23 May 2017
// Copyright 2017 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
import QtQuick 2.5
import QtWebEngine 1.5
AnimatedImage {
property WebEngineView webview: parent
source: "qrc:////icons//loader-snake-64-w.gif"
visible: webview.loading && /^(http.*|)$/i.test(webview.url.toString())
playing: visible
z: 10000
anchors {
horizontalCenter: parent.horizontalCenter
verticalCenter: parent.verticalCenter
}
}

View file

@ -18,6 +18,7 @@ Rectangle {
property bool safeLoading: false
property bool loadingLatched: false
property bool loading: false
property var loadingRequest: null

View file

@ -9,11 +9,15 @@
//
import QtQuick 2.5
import QtWebView 1.1
AnimatedImage {
property WebView webview: parent
source: "../../icons/loader-snake-64-w.gif"
Image {
Item {
id: webView
property bool loading: false
property string url: ""
}
source: "qrc:////images//unsupportedImage.png"
visible: webview.loading && /^(http.*|)$/i.test(webview.url.toString())
playing: visible
z: 10000

View file

@ -0,0 +1,44 @@
import QtQuick 2.7
import QtWebEngine 1.5
Item {
id: root
property bool webViewProfileSetup: false
property string currentUrl: ""
property string downloadUrl: ""
property string adaptedPath: ""
property string tempDir: ""
function setupWebEngineSettings() {
WebEngine.settings.javascriptCanOpenWindows = true;
WebEngine.settings.javascriptCanAccessClipboard = false;
WebEngine.settings.spatialNavigationEnabled = false;
WebEngine.settings.localContentCanAccessRemoteUrls = true;
}
function initWebviewProfileHandlers(profile) {
downloadUrl = currentUrl;
if (webViewProfileSetup) return;
webViewProfileSetup = true;
profile.downloadRequested.connect(function(download){
adaptedPath = File.convertUrlToPath(downloadUrl);
tempDir = File.getTempDir();
download.path = tempDir + "/" + adaptedPath;
download.accept();
if (download.state === WebEngineDownloadItem.DownloadInterrupted) {
console.log("download failed to complete");
}
})
profile.downloadFinished.connect(function(download){
if (download.state === WebEngineDownloadItem.DownloadCompleted) {
File.runUnzip(download.path, downloadUrl, autoAdd);
} else {
console.log("The download was corrupted, state: " + download.state);
}
autoAdd = false;
})
}
}

View file

@ -1,5 +1,4 @@
import QtQuick 2.7
import QtWebView 1.1
import Qt.labs.settings 1.0 as QtSettings
import QtQuick.Controls 2.3
@ -87,15 +86,21 @@ OriginalDesktop.Desktop {
return map;
})({});
Component.onCompleted: {
webEngineConfig.setupWebEngineSettings();
}
// Accept a download through the webview
property bool webViewProfileSetup: false
property string currentUrl: ""
property string downloadUrl: ""
property string adaptedPath: ""
property string tempDir: ""
property alias webViewProfileSetup: webEngineConfig.webViewProfileSetup
property alias currentUrl: webEngineConfig.currentUrl
property alias downloadUrl: webEngineConfig.downloadUrl
property alias adaptedPath: webEngineConfig.adaptedPath
property alias tempDir: webEngineConfig.tempDir
property var initWebviewProfileHandlers: webEngineConfig.initWebviewProfileHandlers
property bool autoAdd: false
function initWebviewProfileHandlers(profile) {
DesktopWebEngine {
id: webEngineConfig
}
function setAutoAdd(auto) {

View file

@ -0,0 +1,17 @@
import QtQuick 2.7
Item {
id: root
property bool webViewProfileSetup: false
property string currentUrl: ""
property string downloadUrl: ""
property string adaptedPath: ""
property string tempDir: ""
function setupWebEngineSettings() {
}
function initWebviewProfileHandlers(profile) {
}
}

View file

@ -1,358 +0,0 @@
//
// WebBrowser.qml
//
//
// Created by Vlad Stelmahovsky on 06/22/2017
// Copyright 2017 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
import QtQuick 2.7
import QtQuick.Controls 2.2 as QQControls
import QtQuick.Layouts 1.3
import QtGraphicalEffects 1.0
import QtWebView 1.1
import QtWebChannel 1.0
import stylesUit 1.0
import controlsUit 1.0 as HifiControls
import "../windows"
import "../controls"
import HifiWeb 1.0
Rectangle {
id: root;
HifiConstants { id: hifi; }
property string title: "";
signal sendToScript(var message);
property bool keyboardEnabled: true // FIXME - Keyboard HMD only: Default to false
property bool keyboardRaised: false
property bool punctuationMode: false
property var suggestionsList: []
readonly property string searchUrlTemplate: "https://www.google.com/search?client=hifibrowser&q=";
WebBrowserSuggestionsEngine {
id: searchEngine
onSuggestions: {
if (suggestions.length > 0) {
suggestionsList = []
suggestionsList.push(addressBarInput.text); //do not overwrite edit text
for(var i = 0; i < suggestions.length; i++) {
suggestionsList.push(suggestions[i]);
}
addressBar.model = suggestionsList
if (!addressBar.popup.visible) {
addressBar.popup.open();
}
}
}
}
Timer {
id: suggestionRequestTimer
interval: 200
repeat: false
onTriggered: {
if (addressBar.editText !== "") {
searchEngine.querySuggestions(addressBarInput.text);
}
}
}
color: hifi.colors.baseGray;
function goTo(url) {
//must be valid attempt to open an site with dot
var urlNew = url
if (url.indexOf(".") > 0) {
if (url.indexOf("http") < 0) {
urlNew = "http://" + url;
}
} else {
urlNew = searchUrlTemplate + url
}
addressBar.model = []
//need to rebind if binfing was broken by selecting from suggestions
addressBar.editText = Qt.binding( function() { return webStack.currentItem.webEngineView.url; });
webStack.currentItem.webEngineView.url = urlNew
suggestionRequestTimer.stop();
addressBar.popup.close();
}
Column {
spacing: 2
width: parent.width;
RowLayout {
id: addressBarRow
width: parent.width;
height: 48
HifiControls.WebGlyphButton {
enabled: webStack.currentItem.webEngineView.canGoBack || webStack.depth > 1
glyph: hifi.glyphs.backward;
anchors.verticalCenter: parent.verticalCenter;
size: 38;
onClicked: {
if (webStack.currentItem.webEngineView.canGoBack) {
webStack.currentItem.webEngineView.goBack();
} else if (webStack.depth > 1) {
webStack.pop();
}
}
}
HifiControls.WebGlyphButton {
enabled: webStack.currentItem.webEngineView.canGoForward
glyph: hifi.glyphs.forward;
anchors.verticalCenter: parent.verticalCenter;
size: 38;
onClicked: {
webStack.currentItem.webEngineView.goForward();
}
}
QQControls.ComboBox {
id: addressBar
//selectByMouse: true
focus: true
editable: true
//flat: true
indicator: Item {}
background: Item {}
onActivated: {
goTo(textAt(index));
}
onHighlightedIndexChanged: {
if (highlightedIndex >= 0) {
addressBar.editText = textAt(highlightedIndex)
}
}
popup.height: webStack.height
onFocusChanged: {
if (focus) {
addressBarInput.selectAll();
}
}
contentItem: QQControls.TextField {
id: addressBarInput
leftPadding: 26
rightPadding: hifi.dimensions.controlLineHeight + 5
text: addressBar.editText
placeholderText: qsTr("Enter URL")
font: addressBar.font
selectByMouse: true
horizontalAlignment: Text.AlignLeft
verticalAlignment: Text.AlignVCenter
onFocusChanged: {
if (focus) {
selectAll();
}
}
Keys.onDeletePressed: {
addressBarInput.text = ""
}
Keys.onPressed: {
if (event.key === Qt.Key_Return) {
goTo(addressBarInput.text);
event.accepted = true;
}
}
Image {
anchors.verticalCenter: parent.verticalCenter;
x: 5
z: 2
id: faviconImage
width: 16; height: 16
sourceSize: Qt.size(width, height)
source: webStack.currentItem.webEngineView.icon
}
HifiControls.WebGlyphButton {
glyph: webStack.currentItem.WebView.Loading ? hifi.glyphs.closeSmall : hifi.glyphs.reloadSmall;
anchors.verticalCenter: parent.verticalCenter;
width: hifi.dimensions.controlLineHeight
z: 2
x: addressBarInput.width - implicitWidth
onClicked: {
if (webStack.currentItem.WebView.Loading) {
webStack.currentItem.webEngineView.stop();
} else {
webStack.currentItem.reloadTimer.start();
}
}
}
}
Component.onCompleted: ScriptDiscoveryService.scriptsModelFilter.filterRegExp = new RegExp("^.*$", "i");
Keys.onPressed: {
if (event.key === Qt.Key_Return) {
goTo(addressBarInput.text);
event.accepted = true;
}
}
onEditTextChanged: {
if (addressBar.editText !== "" && addressBar.editText !== webStack.currentItem.webEngineView.url.toString()) {
suggestionRequestTimer.restart();
} else {
addressBar.model = []
addressBar.popup.close();
}
}
Layout.fillWidth: true
editText: webStack.currentItem.webEngineView.url
onAccepted: goTo(addressBarInput.text);
}
HifiControls.WebGlyphButton {
checkable: true
checked: webStack.currentItem.webEngineView.audioMuted
glyph: checked ? hifi.glyphs.unmuted : hifi.glyphs.muted
anchors.verticalCenter: parent.verticalCenter;
width: hifi.dimensions.controlLineHeight
onClicked: {
webStack.currentItem.webEngineView.audioMuted = !webStack.currentItem.webEngineView.audioMuted
}
}
}
QQControls.ProgressBar {
id: loadProgressBar
background: Rectangle {
implicitHeight: 2
color: "#6A6A6A"
}
contentItem: Item {
implicitHeight: 2
Rectangle {
width: loadProgressBar.visualPosition * parent.width
height: parent.height
color: "#00B4EF"
}
}
width: parent.width;
from: 0
to: 100
value: webStack.currentItem.WebView.LoadProgress
height: 2
}
Component {
id: webViewComponent
Rectangle {
property alias webEngineView: webEngineView
property alias reloadTimer: reloadTimer
property var request: null
property bool isDialog: QQControls.StackView.index > 0
property real margins: isDialog ? 10 : 0
color: "#d1d1d1"
QQControls.StackView.onActivated: {
addressBar.editText = Qt.binding( function() { return webStack.currentItem.webEngineView.url; });
}
onRequestChanged: {
if (isDialog && request !== null && request !== undefined) {//is Dialog ?
request.openIn(webEngineView);
}
}
HifiControls.BaseWebView {
id: webEngineView
anchors.fill: parent
anchors.margins: parent.margins
layer.enabled: parent.isDialog
layer.effect: DropShadow {
verticalOffset: 8
horizontalOffset: 8
color: "#330066ff"
samples: 10
spread: 0.5
}
focus: true
objectName: "tabletWebEngineView"
profile.httpUserAgent: "Mozilla/5.0 (Android; Mobile; rv:13.0) Gecko/13.0 Firefox/13.0"
property string userScriptUrl: ""
onLoadingChanged: {
if (!loading) {
addressBarInput.cursorPosition = 0 //set input field cursot to beginning
suggestionRequestTimer.stop();
addressBar.popup.close();
}
}
onLinkHovered: {
//TODO: change cursor shape?
}
Component.onCompleted: {
webChannel.registerObject("eventBridge", eventBridge);
webChannel.registerObject("eventBridgeWrapper", eventBridgeWrapper);
}
}
Timer {
id: reloadTimer
interval: 0
running: false
repeat: false
onTriggered: webEngineView.reload()
}
}
}
QQControls.StackView {
id: webStack
width: parent.width;
property real webViewHeight: root.height - loadProgressBar.height - 48 - 4
height: keyboardEnabled && keyboardRaised ? webViewHeight - keyboard.height : webViewHeight
Component.onCompleted: webStack.push(webViewComponent, {"webEngineView.url": "https://www.highfidelity.com"});
}
}
HifiControls.Keyboard {
id: keyboard
raised: parent.keyboardEnabled && parent.keyboardRaised
numeric: parent.punctuationMode
anchors {
left: parent.left
right: parent.right
bottom: parent.bottom
}
}
}

View file

@ -16,7 +16,13 @@ import TabletScriptingInterface 1.0
Rectangle {
readonly property var level: AudioScriptingInterface.inputLevel;
property bool gated: false;
Component.onCompleted: {
AudioScriptingInterface.noiseGateOpened.connect(function() { gated = false; });
AudioScriptingInterface.noiseGateClosed.connect(function() { gated = true; });
}
property bool standalone: false;
property var dragTarget: null;
@ -77,6 +83,7 @@ Rectangle {
readonly property string gutter: "#575757";
readonly property string greenStart: "#39A38F";
readonly property string greenEnd: "#1FC6A6";
readonly property string yellow: "#C0C000";
readonly property string red: colors.muted;
readonly property string fill: "#55000000";
readonly property string border: standalone ? "#80FFFFFF" : "#55FFFFFF";
@ -189,7 +196,7 @@ Rectangle {
Rectangle { // mask
id: mask;
width: parent.width * level;
width: gated ? 0 : parent.width * level;
radius: 5;
anchors {
bottom: parent.bottom;
@ -212,18 +219,42 @@ Rectangle {
color: colors.greenStart;
}
GradientStop {
position: 0.8;
position: 0.5;
color: colors.greenEnd;
}
GradientStop {
position: 0.81;
color: colors.red;
}
GradientStop {
position: 1;
color: colors.red;
color: colors.yellow;
}
}
}
Rectangle {
id: gatedIndicator;
visible: gated && !AudioScriptingInterface.clipping
radius: 4;
width: 2 * radius;
height: 2 * radius;
color: "#0080FF";
anchors {
right: parent.left;
verticalCenter: parent.verticalCenter;
}
}
Rectangle {
id: clippingIndicator;
visible: AudioScriptingInterface.clipping
radius: 4;
width: 2 * radius;
height: 2 * radius;
color: colors.red;
anchors {
left: parent.right;
verticalCenter: parent.verticalCenter;
}
}
}
}

View file

@ -21,7 +21,7 @@ Rectangle {
HifiControlsUit.Keyboard {
id: keyboard
z: 1000
raised: parent.keyboardEnabled && parent.keyboardRaised
raised: parent.keyboardEnabled && parent.keyboardRaised && HMD.active
numeric: parent.punctuationMode
anchors {
left: parent.left

View file

@ -38,8 +38,8 @@ Rectangle {
property bool keyboardEnabled: HMD.active
property bool keyboardRaised: false
property string searchScopeString: "Featured"
property bool isLoggedIn: false;
property bool supports3DHTML: true;
property bool isLoggedIn: false
property bool supports3DHTML: true
anchors.fill: (typeof parent === undefined) ? undefined : parent
@ -49,7 +49,7 @@ Rectangle {
licenseInfo.visible = false;
marketBrowseModel.getFirstPage();
{
if(root.searchString !== undefined && root.searchString !== "") {
if(root.searchString !== undefined && root.searchString !== "") {
root.searchScopeString = "Search Results: \"" + root.searchString + "\"";
} else if (root.categoryString !== "") {
root.searchScopeString = root.categoryString;
@ -498,7 +498,7 @@ Rectangle {
"",
"",
root.sortString,
false,
WalletScriptingInterface.limitedCommerce,
marketBrowseModel.currentPageToRetrieve,
marketBrowseModel.itemsPerPage
);

View file

@ -14,8 +14,6 @@
import Hifi 1.0 as Hifi
import QtQuick 2.9
import QtQuick.Controls 2.2
import QtGraphicalEffects 1.0
import QtWebEngine 1.5
import stylesUit 1.0
import controlsUit 1.0 as HifiControlsUit
import "../../../controls" as HifiControls
@ -424,13 +422,13 @@ Rectangle {
elide: Text.ElideRight
size: 14
color: model.link ? hifi.colors.blueHighlight : hifi.colors.baseGray
color: (model.link && root.supports3DHTML)? hifi.colors.blueHighlight : hifi.colors.baseGray
verticalAlignment: Text.AlignVCenter
MouseArea {
anchors.fill: parent
onClicked: {
if (model.link) {
if (model.link && root.supports3DHTML) {
sendToScript({method: 'marketplace_open_link', link: model.link});
}
}
@ -571,12 +569,14 @@ Rectangle {
text: root.description
size: 14
color: hifi.colors.lightGray
linkColor: hifi.colors.blueHighlight
linkColor: root.supports3DHTML ? hifi.colors.blueHighlight : hifi.colors.lightGray
verticalAlignment: Text.AlignVCenter
textFormat: Text.RichText
wrapMode: Text.Wrap
onLinkActivated: {
sendToScript({method: 'marketplace_open_link', link: link});
if (root.supports3DHTML) {
sendToScript({method: 'marketplace_open_link', link: link});
}
}
onHeightChanged: { footer.evalHeight(); }

View file

@ -607,7 +607,7 @@ Rectangle {
} else if (msg.method === "showTrashLightbox") {
lightboxPopup.titleText = "Send \"" + msg.itemName + "\" to Trash";
lightboxPopup.bodyText = "Sending this item to the Trash means you will no longer own this item " +
"and it will be inaccessible to you from Purchases.\n\nThis action cannot be undone.";
"and it will be inaccessible to you from Inventory.\n\nThis action cannot be undone.";
lightboxPopup.button1text = "CANCEL";
lightboxPopup.button1method = function() {
lightboxPopup.visible = false;

View file

@ -0,0 +1,7 @@
import QtQuick 2.0
import QtWebEngine 1.5
import "../../controls" as Controls
Controls.TabletWebView {
profile: WebEngineProfile { httpUserAgent: "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.90 Safari/537.36"}
}

View file

@ -1,6 +1,4 @@
import QtQuick 2.0
import QtWebView 1.1
import "../../controls" as Controls
Controls.TabletWebView {

View file

@ -2,7 +2,7 @@ import QtQuick 2.5
import QtGraphicalEffects 1.0
import QtQuick.Controls 1.4
import QtQml 2.2
import QtWebChannel 1.0
import "."
import stylesUit 1.0

View file

@ -1,5 +1,4 @@
import QtQuick 2.0
import "../../controls" as Controls
Controls.TabletWebScreen {

View file

@ -1,5 +1,4 @@
import QtQuick 2.0
import "../../controls" as Controls
Controls.WebView {

View file

@ -20,7 +20,8 @@
*
* @hifi-interface
* @hifi-client-entity
*
* @hifi-avatar
*
* @property {string} buildDate
* @property {string} buildVersion
* @property {string} qtVersion

View file

@ -2428,7 +2428,6 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
connect(&AndroidHelper::instance(), &AndroidHelper::enterForeground, this, &Application::enterForeground);
AndroidHelper::instance().notifyLoadComplete();
#endif
AndroidHelper::instance().notifyLoadComplete();
pauseUntilLoginDetermined();
}
@ -3641,14 +3640,14 @@ void Application::handleSandboxStatus(QNetworkReply* reply) {
}
// Get controller availability
#ifdef Q_OS_ANDROID
#ifdef Q_OS_ANDROID
bool hasHandControllers = true;
#else
#else
bool hasHandControllers = false;
if (PluginUtils::isViveControllerAvailable() || PluginUtils::isOculusTouchControllerAvailable()) {
hasHandControllers = true;
}
#endif
#endif
// Check HMD use (may be technically available without being in use)
bool hasHMD = PluginUtils::isHMDAvailable();
@ -4981,10 +4980,10 @@ void Application::idle() {
// Normally we check PipelineWarnings, but since idle will often take more than 10ms we only show these idle timing
// details if we're in ExtraDebugging mode. However, the ::update() and its subcomponents will show their timing
// details normally.
#ifndef Q_OS_ANDROID
bool showWarnings = getLogger()->extraDebugging();
#else
#ifdef Q_OS_ANDROID
bool showWarnings = false;
#else
bool showWarnings = getLogger()->extraDebugging();
#endif
PerformanceWarning warn(showWarnings, "idle()");
@ -8329,7 +8328,7 @@ void Application::toggleLogDialog() {
bool keepOnTop =_keepLogWindowOnTop.get();
#ifdef Q_OS_WIN
_logDialog = new LogDialog(keepOnTop ? qApp->getWindow() : nullptr, getLogger());
#else
#elif !defined(Q_OS_ANDROID)
_logDialog = new LogDialog(nullptr, getLogger());
if (keepOnTop) {

View file

@ -21,6 +21,7 @@
*
* @hifi-interface
* @hifi-client-entity
* @hifi-avatar
*
*/

View file

@ -36,6 +36,7 @@ class AABox;
*
* @hifi-interface
* @hifi-client-entity
* @hifi-avatar
*
* @property {number} presentTime <em>Read-only.</em>
* @property {number} engineRunTime <em>Read-only.</em>

View file

@ -21,6 +21,7 @@
*
* @hifi-client-entity
* @hifi-interface
* @hifi-avatar
*/
class LocationBookmarks : public Bookmarks, public Dependency {

View file

@ -294,13 +294,6 @@ void ModelPackager::populateBasicMapping(QVariantHash& mapping, QString filename
}
mapping.insert(JOINT_FIELD, joints);
if (!mapping.contains(FREE_JOINT_FIELD)) {
mapping.insertMulti(FREE_JOINT_FIELD, "LeftArm");
mapping.insertMulti(FREE_JOINT_FIELD, "LeftForeArm");
mapping.insertMulti(FREE_JOINT_FIELD, "RightArm");
mapping.insertMulti(FREE_JOINT_FIELD, "RightForeArm");
}
// If there are no blendshape mappings, and we detect that this is likely a mixamo file,
// then we can add the default mixamo to "faceshift" mappings

View file

@ -58,11 +58,6 @@ _hfmModel(hfmModel)
form->addRow("Left Hand Joint:", _leftHandJoint = createJointBox());
form->addRow("Right Hand Joint:", _rightHandJoint = createJointBox());
form->addRow("Free Joints:", _freeJoints = new QVBoxLayout());
QPushButton* newFreeJoint = new QPushButton("New Free Joint");
_freeJoints->addWidget(newFreeJoint);
connect(newFreeJoint, SIGNAL(clicked(bool)), SLOT(createNewFreeJoint()));
QDialogButtonBox* buttons = new QDialogButtonBox(QDialogButtonBox::Ok |
QDialogButtonBox::Cancel | QDialogButtonBox::Reset);
connect(buttons, SIGNAL(accepted()), SLOT(accept()));
@ -102,11 +97,6 @@ QVariantHash ModelPropertiesDialog::getMapping() const {
insertJointMapping(joints, "jointLeftHand", _leftHandJoint->currentText());
insertJointMapping(joints, "jointRightHand", _rightHandJoint->currentText());
mapping.remove(FREE_JOINT_FIELD);
for (int i = 0; i < _freeJoints->count() - 1; i++) {
QComboBox* box = static_cast<QComboBox*>(_freeJoints->itemAt(i)->widget()->layout()->itemAt(0)->widget());
mapping.insertMulti(FREE_JOINT_FIELD, box->currentText());
}
mapping.insert(JOINT_FIELD, joints);
return mapping;
@ -133,16 +123,6 @@ void ModelPropertiesDialog::reset() {
setJointText(_headJoint, jointHash.value("jointHead").toString());
setJointText(_leftHandJoint, jointHash.value("jointLeftHand").toString());
setJointText(_rightHandJoint, jointHash.value("jointRightHand").toString());
while (_freeJoints->count() > 1) {
delete _freeJoints->itemAt(0)->widget();
}
foreach (const QVariant& joint, _originalMapping.values(FREE_JOINT_FIELD)) {
QString jointName = joint.toString();
if (_hfmModel.jointIndices.contains(jointName)) {
createNewFreeJoint(jointName);
}
}
}
void ModelPropertiesDialog::chooseTextureDirectory() {
@ -176,20 +156,6 @@ void ModelPropertiesDialog::updatePivotJoint() {
_pivotJoint->setEnabled(!_pivotAboutCenter->isChecked());
}
void ModelPropertiesDialog::createNewFreeJoint(const QString& joint) {
QWidget* freeJoint = new QWidget();
QHBoxLayout* freeJointLayout = new QHBoxLayout();
freeJointLayout->setContentsMargins(QMargins());
freeJoint->setLayout(freeJointLayout);
QComboBox* jointBox = createJointBox(false);
jointBox->setCurrentText(joint);
freeJointLayout->addWidget(jointBox, 1);
QPushButton* deleteJoint = new QPushButton("Delete");
freeJointLayout->addWidget(deleteJoint);
freeJoint->connect(deleteJoint, SIGNAL(clicked(bool)), SLOT(deleteLater()));
_freeJoints->insertWidget(_freeJoints->count() - 1, freeJoint);
}
QComboBox* ModelPropertiesDialog::createJointBox(bool withNone) const {
QComboBox* box = new QComboBox();
if (withNone) {

View file

@ -39,7 +39,6 @@ private slots:
void chooseTextureDirectory();
void chooseScriptDirectory();
void updatePivotJoint();
void createNewFreeJoint(const QString& joint = QString());
private:
QComboBox* createJointBox(bool withNone = true) const;
@ -66,7 +65,6 @@ private:
QComboBox* _headJoint = nullptr;
QComboBox* _leftHandJoint = nullptr;
QComboBox* _rightHandJoint = nullptr;
QVBoxLayout* _freeJoints = nullptr;
};
#endif // hifi_ModelPropertiesDialog_h

View file

@ -27,6 +27,7 @@
*
* @hifi-interface
* @hifi-client-entity
* @hifi-avatar
*/
class SpeechRecognizer : public QObject, public Dependency {
Q_OBJECT

View file

@ -31,6 +31,7 @@ class AudioScope : public QObject, public Dependency {
*
* @hifi-interface
* @hifi-client-entity
* @hifi-avatar
*
* @property {number} scopeInput <em>Read-only.</em>
* @property {number} scopeOutputLeft <em>Read-only.</em>

View file

@ -569,7 +569,7 @@ void AvatarActionHold::lateAvatarUpdate(const AnimPose& prePhysicsRoomPose, cons
}
btTransform worldTrans = rigidBody->getWorldTransform();
AnimPose worldBodyPose(glm::vec3(1), bulletToGLM(worldTrans.getRotation()), bulletToGLM(worldTrans.getOrigin()));
AnimPose worldBodyPose(1.0f, bulletToGLM(worldTrans.getRotation()), bulletToGLM(worldTrans.getOrigin()));
// transform the body transform into sensor space with the prePhysics sensor-to-world matrix.
// then transform it back into world uisng the postAvatarUpdate sensor-to-world matrix.

View file

@ -652,28 +652,25 @@ RayToAvatarIntersectionResult AvatarManager::findRayIntersectionVector(const Pic
PROFILE_RANGE(simulation_physics, __FUNCTION__);
float distance = (float)INT_MAX; // with FLT_MAX bullet rayTest does not return results
float bulletDistance = (float)INT_MAX; // with FLT_MAX bullet rayTest does not return results
glm::vec3 rayDirection = glm::normalize(ray.direction);
std::vector<MyCharacterController::RayAvatarResult> physicsResults = _myAvatar->getCharacterController()->rayTest(glmToBullet(ray.origin), glmToBullet(rayDirection), distance, QVector<uint>());
std::vector<MyCharacterController::RayAvatarResult> physicsResults = _myAvatar->getCharacterController()->rayTest(glmToBullet(ray.origin), glmToBullet(rayDirection), bulletDistance, QVector<uint>());
if (physicsResults.size() > 0) {
glm::vec3 rayDirectionInv = { rayDirection.x != 0.0f ? 1.0f / rayDirection.x : INFINITY,
rayDirection.y != 0.0f ? 1.0f / rayDirection.y : INFINITY,
rayDirection.z != 0.0f ? 1.0f / rayDirection.z : INFINITY };
MyCharacterController::RayAvatarResult rayAvatarResult;
AvatarPointer avatar = nullptr;
BoxFace face = BoxFace::UNKNOWN_FACE;
glm::vec3 surfaceNormal;
QVariantMap extraInfo;
for (auto &hit : physicsResults) {
auto avatarID = hit._intersectWithAvatar;
if ((avatarsToInclude.size() > 0 && !avatarsToInclude.contains(avatarID)) ||
(avatarsToDiscard.size() > 0 && avatarsToDiscard.contains(avatarID))) {
continue;
}
MyCharacterController::RayAvatarResult rayAvatarResult;
BoxFace face = BoxFace::UNKNOWN_FACE;
QVariantMap extraInfo;
AvatarPointer avatar = nullptr;
if (_myAvatar->getSessionUUID() != avatarID) {
auto avatarMap = getHashCopy();
AvatarHash::iterator itr = avatarMap.find(avatarID);
@ -683,46 +680,45 @@ RayToAvatarIntersectionResult AvatarManager::findRayIntersectionVector(const Pic
} else {
avatar = _myAvatar;
}
if (!hit._isBound) {
rayAvatarResult = hit;
} else if (avatar) {
auto &multiSpheres = avatar->getMultiSphereShapes();
if (multiSpheres.size() > 0) {
std::vector<MyCharacterController::RayAvatarResult> boxHits;
MyCharacterController::RayAvatarResult boxHit;
boxHit._distance = FLT_MAX;
for (size_t i = 0; i < hit._boundJoints.size(); i++) {
assert(hit._boundJoints[i] < multiSpheres.size());
auto &mSphere = multiSpheres[hit._boundJoints[i]];
if (mSphere.isValid()) {
float boundDistance = FLT_MAX;
BoxFace face;
glm::vec3 surfaceNormal;
BoxFace boundFace = BoxFace::UNKNOWN_FACE;
glm::vec3 boundSurfaceNormal;
auto &bbox = mSphere.getBoundingBox();
if (bbox.findRayIntersection(ray.origin, rayDirection, rayDirectionInv, boundDistance, face, surfaceNormal)) {
MyCharacterController::RayAvatarResult boxHit;
boxHit._distance = boundDistance;
boxHit._intersect = true;
boxHit._intersectionNormal = surfaceNormal;
boxHit._intersectionPoint = ray.origin + boundDistance * rayDirection;
boxHit._intersectWithAvatar = avatarID;
boxHit._intersectWithJoint = mSphere.getJointIndex();
boxHits.push_back(boxHit);
if (bbox.findRayIntersection(ray.origin, rayDirection, rayDirectionInv, boundDistance, boundFace, boundSurfaceNormal)) {
if (boundDistance < boxHit._distance) {
boxHit._intersect = true;
boxHit._intersectWithAvatar = avatarID;
boxHit._intersectWithJoint = mSphere.getJointIndex();
boxHit._distance = boundDistance;
boxHit._intersectionPoint = ray.origin + boundDistance * rayDirection;
boxHit._intersectionNormal = boundSurfaceNormal;
face = boundFace;
}
}
}
}
if (boxHits.size() > 0) {
if (boxHits.size() > 1) {
std::sort(boxHits.begin(), boxHits.end(), [](const MyCharacterController::RayAvatarResult& hitA,
const MyCharacterController::RayAvatarResult& hitB) {
return hitA._distance < hitB._distance;
});
}
rayAvatarResult = boxHits[0];
if (boxHit._distance < FLT_MAX) {
rayAvatarResult = boxHit;
}
}
}
if (pickAgainstMesh) {
if (rayAvatarResult._intersect && pickAgainstMesh) {
glm::vec3 localRayOrigin = avatar->worldToJointPoint(ray.origin, rayAvatarResult._intersectWithJoint);
glm::vec3 localRayPoint = avatar->worldToJointPoint(ray.origin + rayDirection, rayAvatarResult._intersectWithJoint);
glm::vec3 localRayPoint = avatar->worldToJointPoint(ray.origin + rayAvatarResult._distance * rayDirection, rayAvatarResult._intersectWithJoint);
auto avatarOrientation = avatar->getWorldOrientation();
auto avatarPosition = avatar->getWorldPosition();
@ -732,31 +728,37 @@ RayToAvatarIntersectionResult AvatarManager::findRayIntersectionVector(const Pic
auto defaultFrameRayOrigin = jointPosition + jointOrientation * localRayOrigin;
auto defaultFrameRayPoint = jointPosition + jointOrientation * localRayPoint;
auto defaultFrameRayDirection = defaultFrameRayPoint - defaultFrameRayOrigin;
auto defaultFrameRayDirection = glm::normalize(defaultFrameRayPoint - defaultFrameRayOrigin);
if (avatar->getSkeletonModel()->findRayIntersectionAgainstSubMeshes(defaultFrameRayOrigin, defaultFrameRayDirection, distance, face, surfaceNormal, extraInfo, true, false)) {
auto newDistance = glm::length(vec3FromVariant(extraInfo["worldIntersectionPoint"]) - defaultFrameRayOrigin);
rayAvatarResult._distance = newDistance;
rayAvatarResult._intersectionPoint = ray.origin + newDistance * rayDirection;
rayAvatarResult._intersectionNormal = surfaceNormal;
extraInfo["worldIntersectionPoint"] = vec3toVariant(rayAvatarResult._intersectionPoint);
break;
float subMeshDistance = FLT_MAX;
BoxFace subMeshFace = BoxFace::UNKNOWN_FACE;
glm::vec3 subMeshSurfaceNormal;
QVariantMap subMeshExtraInfo;
if (avatar->getSkeletonModel()->findRayIntersectionAgainstSubMeshes(defaultFrameRayOrigin, defaultFrameRayDirection, subMeshDistance, subMeshFace, subMeshSurfaceNormal, subMeshExtraInfo, true, false)) {
rayAvatarResult._distance = subMeshDistance;
rayAvatarResult._intersectionPoint = ray.origin + subMeshDistance * rayDirection;
rayAvatarResult._intersectionNormal = subMeshSurfaceNormal;
face = subMeshFace;
extraInfo = subMeshExtraInfo;
} else {
rayAvatarResult._intersect = false;
}
} else if (rayAvatarResult._intersect){
}
if (rayAvatarResult._intersect) {
result.intersects = true;
result.avatarID = rayAvatarResult._intersectWithAvatar;
result.distance = rayAvatarResult._distance;
result.face = face;
result.intersection = ray.origin + rayAvatarResult._distance * rayDirection;
result.surfaceNormal = rayAvatarResult._intersectionNormal;
result.jointIndex = rayAvatarResult._intersectWithJoint;
result.extraInfo = extraInfo;
break;
}
}
if (rayAvatarResult._intersect) {
result.intersects = true;
result.avatarID = rayAvatarResult._intersectWithAvatar;
result.distance = rayAvatarResult._distance;
result.surfaceNormal = rayAvatarResult._intersectionNormal;
result.jointIndex = rayAvatarResult._intersectWithJoint;
result.intersection = ray.origin + rayAvatarResult._distance * rayDirection;
result.extraInfo = extraInfo;
result.face = face;
}
}
return result;
}

View file

@ -46,6 +46,7 @@ using SortedAvatar = std::pair<float, std::shared_ptr<Avatar>>;
*
* @hifi-interface
* @hifi-client-entity
* @hifi-avatar
*
* @borrows AvatarList.getAvatarIdentifiers as getAvatarIdentifiers
* @borrows AvatarList.getAvatarsInRange as getAvatarsInRange

View file

@ -915,14 +915,9 @@ void MyAvatar::simulate(float deltaTime, bool inView) {
auto entityTreeRenderer = qApp->getEntities();
EntityTreePointer entityTree = entityTreeRenderer ? entityTreeRenderer->getTree() : nullptr;
if (entityTree) {
bool zoneAllowsFlying = true;
bool collisionlessAllowed = true;
std::pair<bool, bool> zoneInteractionProperties;
entityTree->withWriteLock([&] {
std::shared_ptr<ZoneEntityItem> zone = entityTreeRenderer->myAvatarZone();
if (zone) {
zoneAllowsFlying = zone->getFlyingAllowed();
collisionlessAllowed = zone->getGhostingAllowed();
}
zoneInteractionProperties = entityTreeRenderer->getZoneInteractionProperties();
EntityEditPacketSender* packetSender = qApp->getEntityEditPacketSender();
forEachDescendant([&](SpatiallyNestablePointer object) {
// we need to update attached queryAACubes in our own local tree so point-select always works
@ -935,6 +930,8 @@ void MyAvatar::simulate(float deltaTime, bool inView) {
});
});
bool isPhysicsEnabled = qApp->isPhysicsEnabled();
bool zoneAllowsFlying = zoneInteractionProperties.first;
bool collisionlessAllowed = zoneInteractionProperties.second;
_characterController.setFlyingAllowed((zoneAllowsFlying && _enableFlying) || !isPhysicsEnabled);
_characterController.setCollisionlessAllowed(collisionlessAllowed);
}
@ -2983,7 +2980,7 @@ void MyAvatar::postUpdate(float deltaTime, const render::ScenePointer& scene) {
auto animSkeleton = _skeletonModel->getRig().getAnimSkeleton();
// the rig is in the skeletonModel frame
AnimPose xform(glm::vec3(1), _skeletonModel->getRotation(), _skeletonModel->getTranslation());
AnimPose xform(1.0f, _skeletonModel->getRotation(), _skeletonModel->getTranslation());
if (_enableDebugDrawDefaultPose && animSkeleton) {
glm::vec4 gray(0.2f, 0.2f, 0.2f, 0.2f);
@ -3028,7 +3025,7 @@ void MyAvatar::postUpdate(float deltaTime, const render::ScenePointer& scene) {
updateHoldActions(_prePhysicsRoomPose, postUpdateRoomPose);
if (_enableDebugDrawDetailedCollision) {
AnimPose rigToWorldPose(glm::vec3(1.0f), getWorldOrientation() * Quaternions::Y_180, getWorldPosition());
AnimPose rigToWorldPose(1.0f, getWorldOrientation() * Quaternions::Y_180, getWorldPosition());
const int NUM_DEBUG_COLORS = 8;
const glm::vec4 DEBUG_COLORS[NUM_DEBUG_COLORS] = {
glm::vec4(1.0f, 1.0f, 1.0f, 1.0f),
@ -4824,7 +4821,7 @@ void MyAvatar::FollowHelper::prePhysicsUpdate(MyAvatar& myAvatar, const glm::mat
swingTwistDecomposition(hipsinWorldSpace, avatarUpWorld, resultingSwingInWorld, resultingTwistInWorld);
// remove scale present from sensorToWorldMatrix
followWorldPose.scale() = glm::vec3(1.0f);
followWorldPose.scale() = 1.0f;
if (isActive(Rotation)) {
//use the hmd reading for the hips follow

View file

@ -66,6 +66,7 @@ class MyAvatar : public Avatar {
*
* @hifi-interface
* @hifi-client-entity
* @hifi-avatar
*
* @property {Vec3} qmlPosition - A synonym for <code>position</code> for use by QML.
* @property {boolean} shouldRenderLocally=true - If <code>true</code> then your avatar is rendered for you in Interface,

View file

@ -41,7 +41,7 @@ static AnimPose computeHipsInSensorFrame(MyAvatar* myAvatar, bool isFlying) {
if (myAvatar->isJointPinned(hipsIndex)) {
Transform avatarTransform = myAvatar->getTransform();
AnimPose result = AnimPose(worldToSensorMat * avatarTransform.getMatrix() * Matrices::Y_180);
result.scale() = glm::vec3(1.0f, 1.0f, 1.0f);
result.scale() = 1.0f;
return result;
}
@ -108,7 +108,7 @@ void MySkeletonModel::updateRig(float deltaTime, glm::mat4 parentTransform) {
Rig::ControllerParameters params;
AnimPose avatarToRigPose(glm::vec3(1.0f), Quaternions::Y_180, glm::vec3(0.0f));
AnimPose avatarToRigPose(1.0f, Quaternions::Y_180, glm::vec3(0.0f));
glm::mat4 rigToAvatarMatrix = Matrices::Y_180;
glm::mat4 avatarToWorldMatrix = createMatFromQuatAndPos(myAvatar->getWorldOrientation(), myAvatar->getWorldPosition());
@ -127,7 +127,7 @@ void MySkeletonModel::updateRig(float deltaTime, glm::mat4 parentTransform) {
// preMult 180 is necessary to convert from avatar to rig coordinates.
// postMult 180 is necessary to convert head from -z forward to z forward.
glm::quat headRot = Quaternions::Y_180 * head->getFinalOrientationInLocalFrame() * Quaternions::Y_180;
params.primaryControllerPoses[Rig::PrimaryControllerType_Head] = AnimPose(glm::vec3(1.0f), headRot, glm::vec3(0.0f));
params.primaryControllerPoses[Rig::PrimaryControllerType_Head] = AnimPose(1.0f, headRot, glm::vec3(0.0f));
params.primaryControllerFlags[Rig::PrimaryControllerType_Head] = 0;
}

View file

@ -447,6 +447,10 @@ void OtherAvatar::handleChangedAvatarEntityData() {
EntityItemProperties properties;
int32_t bytesLeftToRead = data.size();
unsigned char* dataAt = (unsigned char*)(data.data());
// FIXME: This function will cause unintented changes in SpaillyNestable
// E.g overriding the ID index of an exisiting entity to temporary entity
// in the following map QHash<QUuid, SpatiallyNestableWeakPointer> _children;
// Andrew Meadows will address this issue
if (!properties.constructFromBuffer(dataAt, bytesLeftToRead)) {
// properties are corrupt
continue;
@ -489,6 +493,17 @@ void OtherAvatar::handleChangedAvatarEntityData() {
bool success = true;
if (entity) {
QUuid oldParentID = entity->getParentID();
// Since has overwrtiiten the back pointer
// from the parent children map (see comment for function call above),
// we need to for reset the back pointer in the map correctly by setting the parentID, but
// since the parentID of the entity has not changed we first need to set it some ither ID,
// then set the the original ID for the changes to take effect
// TODO: This is a horrible hack and once properties.constructFromBuffer no longer causes
// side effects...remove the following three lines
const QUuid NULL_ID = QUuid("{00000000-0000-0000-0000-000000000005}");
entity->setParentID(NULL_ID);
entity->setParentID(oldParentID);
if (entityTree->updateEntity(entityID, properties)) {
entity->updateLastEditedFromRemote();
} else {

View file

@ -72,20 +72,17 @@ void QmlMarketplace::getMarketplaceItems(
void QmlMarketplace::getMarketplaceItem(const QString& marketplaceItemId) {
QString endpoint = QString("items/") + marketplaceItemId;
QUrlQuery request;
send(endpoint, "getMarketplaceItemSuccess", "getMarketplaceItemFailure", QNetworkAccessManager::GetOperation, AccountManagerAuth::Optional, request);
send(endpoint, "getMarketplaceItemSuccess", "getMarketplaceItemFailure", QNetworkAccessManager::GetOperation, AccountManagerAuth::Optional);
}
void QmlMarketplace::marketplaceItemLike(const QString& marketplaceItemId, const bool like) {
QString endpoint = QString("items/") + marketplaceItemId + "/like";
QUrlQuery request;
send(endpoint, "marketplaceItemLikeSuccess", "marketplaceItemLikeFailure", like ? QNetworkAccessManager::PostOperation : QNetworkAccessManager::DeleteOperation, AccountManagerAuth::Required, request);
send(endpoint, "marketplaceItemLikeSuccess", "marketplaceItemLikeFailure", like ? QNetworkAccessManager::PostOperation : QNetworkAccessManager::DeleteOperation, AccountManagerAuth::Required);
}
void QmlMarketplace::getMarketplaceCategories() {
QString endpoint = "categories";
QUrlQuery request;
send(endpoint, "getMarketplaceCategoriesSuccess", "getMarketplaceCategoriesFailure", QNetworkAccessManager::GetOperation, AccountManagerAuth::None, request);
send(endpoint, "getMarketplaceCategoriesSuccess", "getMarketplaceCategoriesFailure", QNetworkAccessManager::GetOperation, AccountManagerAuth::None);
}
@ -94,14 +91,13 @@ void QmlMarketplace::send(const QString& endpoint, const QString& success, const
const QString URL = "/api/v1/marketplace/";
JSONCallbackParameters callbackParams(this, success, fail);
accountManager->sendRequest(URL + endpoint,
accountManager->sendRequest(URL + endpoint + "?" + request.toString(),
authType,
method,
callbackParams,
QByteArray(),
NULL,
QVariantMap(),
request);
QVariantMap());
}

View file

@ -60,7 +60,12 @@ signals:
void marketplaceItemLikeResult(QJsonObject result);
private:
void send(const QString& endpoint, const QString& success, const QString& fail, QNetworkAccessManager::Operation method, AccountManagerAuth::Type authType, const QUrlQuery & request);
void send(const QString& endpoint,
const QString& success,
const QString& fail,
QNetworkAccessManager::Operation method,
AccountManagerAuth::Type authType,
const QUrlQuery& request = QUrlQuery());
QJsonObject apiResponse(const QString& label, QNetworkReply* reply);
QJsonObject failResponse(const QString& label, QNetworkReply* reply);
};

View file

@ -32,6 +32,7 @@
*
* @hifi-interface
* @hifi-client-entity
* @hifi-avatar
*/
class DdeFaceTracker : public FaceTracker, public Dependency {

View file

@ -40,11 +40,12 @@ void OctreePacketProcessor::processPacket(QSharedPointer<ReceivedMessage> messag
#ifndef Q_OS_ANDROID
const int WAY_BEHIND = 300;
if (packetsToProcessCount() > WAY_BEHIND && qApp->getLogger()->extraDebugging()) {
qDebug("OctreePacketProcessor::processPacket() packets to process=%d", packetsToProcessCount());
}
#endif
bool wasStatsPacket = false;
PacketType octreePacketType = message->getType();

View file

@ -27,6 +27,7 @@ class LaserPointerScriptingInterface : public QObject, public Dependency {
*
* @hifi-interface
* @hifi-client-entity
* @hifi-avatar
*/
public:

View file

@ -23,6 +23,7 @@
*
* @hifi-interface
* @hifi-client-entity
* @hifi-avatar
*
* @property {number} PICK_ENTITIES A filter flag. Include domain and avatar entities when intersecting. <em>Read-only.</em>. Deprecated.
* @property {number} PICK_OVERLAYS A filter flag. Include local entities when intersecting. <em>Read-only.</em>. Deprecated.

View file

@ -22,6 +22,7 @@
*
* @hifi-interface
* @hifi-client-entity
* @hifi-avatar
*/
class PointerScriptingInterface : public QObject, public Dependency {

View file

@ -56,7 +56,8 @@ PickResultPointer RayPick::getOverlayIntersection(const PickRay& pick) {
}
PickResultPointer RayPick::getAvatarIntersection(const PickRay& pick) {
RayToAvatarIntersectionResult avatarRes = DependencyManager::get<AvatarManager>()->findRayIntersectionVector(pick, getIncludeItemsAs<EntityItemID>(), getIgnoreItemsAs<EntityItemID>(), true);
bool precisionPicking = !(getFilter().isCoarse() || DependencyManager::get<PickManager>()->getForceCoarsePicking());
RayToAvatarIntersectionResult avatarRes = DependencyManager::get<AvatarManager>()->findRayIntersectionVector(pick, getIncludeItemsAs<EntityItemID>(), getIgnoreItemsAs<EntityItemID>(), precisionPicking);
if (avatarRes.intersects) {
return std::make_shared<RayPickResult>(IntersectionType::AVATAR, avatarRes.avatarID, avatarRes.distance, avatarRes.intersection, pick, avatarRes.surfaceNormal, avatarRes.extraInfo);
} else {

View file

@ -25,6 +25,7 @@
*
* @hifi-interface
* @hifi-client-entity
* @hifi-avatar
*
* @property {number} PICK_ENTITIES <em>Read-only.</em>
* @property {number} PICK_OVERLAYS <em>Read-only.</em>

View file

@ -42,6 +42,7 @@ class AccountServicesScriptingInterface : public QObject {
*
* @hifi-interface
* @hifi-client-entity
* @hifi-avatar
*
* @namespace AccountServices
* @property {string} username <em>Read-only.</em>

View file

@ -15,6 +15,7 @@
#include "Application.h"
#include "AudioClient.h"
#include "AudioHelpers.h"
#include "ui/AvatarInputs.h"
using namespace scripting;
@ -26,26 +27,9 @@ QString Audio::HMD { "VR" };
Setting::Handle<bool> enableNoiseReductionSetting { QStringList { Audio::AUDIO, "NoiseReduction" }, true };
float Audio::loudnessToLevel(float loudness) {
const float LOG2 = log(2.0f);
const float METER_LOUDNESS_SCALE = 2.8f / 5.0f;
const float LOG2_LOUDNESS_FLOOR = 11.0f;
float level = 0.0f;
loudness += 1.0f;
float log2loudness = logf(loudness) / LOG2;
if (log2loudness <= LOG2_LOUDNESS_FLOOR) {
level = (log2loudness / LOG2_LOUDNESS_FLOOR) * METER_LOUDNESS_SCALE;
} else {
level = (log2loudness - (LOG2_LOUDNESS_FLOOR - 1.0f)) * METER_LOUDNESS_SCALE;
}
if (level > 1.0f) {
level = 1.0;
}
return level;
float level = 6.02059991f * fastLog2f(loudness); // level in dBFS
level = (level + 48.0f) * (1/39.0f); // map [-48, -9] dBFS to [0, 1]
return glm::clamp(level, 0.0f, 1.0f);
}
Audio::Audio() : _devices(_contextIsHMD) {
@ -150,18 +134,33 @@ float Audio::getInputLevel() const {
});
}
void Audio::onInputLoudnessChanged(float loudness) {
bool Audio::isClipping() const {
return resultWithReadLock<bool>([&] {
return _isClipping;
});
}
void Audio::onInputLoudnessChanged(float loudness, bool isClipping) {
float level = loudnessToLevel(loudness);
bool changed = false;
bool levelChanged = false;
bool isClippingChanged = false;
withWriteLock([&] {
if (_inputLevel != level) {
_inputLevel = level;
changed = true;
levelChanged = true;
}
if (_isClipping != isClipping) {
_isClipping = isClipping;
isClippingChanged = true;
}
});
if (changed) {
if (levelChanged) {
emit inputLevelChanged(level);
}
if (isClippingChanged) {
emit clippingChanged(isClipping);
}
}
QString Audio::getContext() const {

View file

@ -32,6 +32,7 @@ class Audio : public AudioScriptingInterface, protected ReadWriteLockable {
*
* @hifi-interface
* @hifi-client-entity
* @hifi-avatar
* @hifi-server-entity
* @hifi-assignment-client
*
@ -41,6 +42,7 @@ class Audio : public AudioScriptingInterface, protected ReadWriteLockable {
* above the noise floor.
* @property {number} inputLevel - The loudness of the audio input, range <code>0.0</code> (no sound) &ndash;
* <code>1.0</code> (the onset of clipping). <em>Read-only.</em>
* @property {boolean} clipping - <code>true</code> if the audio input is clipping, otherwise <code>false</code>.
* @property {number} inputVolume - Adjusts the volume of the input audio; range <code>0.0</code> &ndash; <code>1.0</code>.
* If set to a value, the resulting value depends on the input device: for example, the volume can't be changed on some
* devices, and others might only support values of <code>0.0</code> and <code>1.0</code>.
@ -58,6 +60,7 @@ class Audio : public AudioScriptingInterface, protected ReadWriteLockable {
Q_PROPERTY(bool noiseReduction READ noiseReductionEnabled WRITE enableNoiseReduction NOTIFY noiseReductionChanged)
Q_PROPERTY(float inputVolume READ getInputVolume WRITE setInputVolume NOTIFY inputVolumeChanged)
Q_PROPERTY(float inputLevel READ getInputLevel NOTIFY inputLevelChanged)
Q_PROPERTY(bool clipping READ isClipping NOTIFY clippingChanged)
Q_PROPERTY(QString context READ getContext NOTIFY contextChanged)
Q_PROPERTY(AudioDevices* devices READ getDevices NOTIFY nop)
@ -74,6 +77,7 @@ public:
bool noiseReductionEnabled() const;
float getInputVolume() const;
float getInputLevel() const;
bool isClipping() const;
QString getContext() const;
void showMicMeter(bool show);
@ -217,6 +221,14 @@ signals:
*/
void inputLevelChanged(float level);
/**jsdoc
* Triggered when the clipping state of the input audio changes.
* @function Audio.clippingChanged
* @param {boolean} isClipping - <code>true</code> if the audio input is clipping, otherwise <code>false</code>.
* @returns {Signal}
*/
void clippingChanged(bool isClipping);
/**jsdoc
* Triggered when the current context of the audio changes.
* @function Audio.contextChanged
@ -237,7 +249,7 @@ private slots:
void setMuted(bool muted);
void enableNoiseReduction(bool enable);
void setInputVolume(float volume);
void onInputLoudnessChanged(float loudness);
void onInputLoudnessChanged(float loudness, bool isClipping);
protected:
// Audio must live on a separate thread from AudioClient to avoid deadlocks
@ -247,6 +259,7 @@ private:
float _inputVolume { 1.0f };
float _inputLevel { 0.0f };
bool _isClipping { false };
bool _isMuted { false };
bool _enableNoiseReduction { true }; // Match default value of AudioClient::_isNoiseGateEnabled.
bool _contextIsHMD { false };

View file

@ -24,6 +24,7 @@
*
* @hifi-interface
* @hifi-client-entity
* @hifi-avatar
*/
class ClipboardScriptingInterface : public QObject {
Q_OBJECT

View file

@ -199,6 +199,7 @@ class ScriptEngine;
*
* @hifi-interface
* @hifi-client-entity
* @hifi-avatar
*
* @property {Controller.Actions} Actions - Predefined actions on Interface and the user's avatar. These can be used as end
* points in a {@link RouteObject} mapping. A synonym for <code>Controller.Hardware.Actions</code>.

View file

@ -24,7 +24,8 @@
*
* @hifi-interface
* @hifi-client-entity
*
* @hifi-avatar
*
* @property {number} width
* @property {number} height
* @property {number} ALWAYS_ON_TOP - InteractiveWindow flag for always showing a window on top

View file

@ -21,6 +21,7 @@
*
* @hifi-interface
* @hifi-client-entity
* @hifi-avatar
*/
class GooglePolyScriptingInterface : public QObject, public Dependency {

View file

@ -31,6 +31,7 @@ class QScriptEngine;
*
* @hifi-interface
* @hifi-client-entity
* @hifi-avatar
*
* @property {Vec3} position - The position of the HMD if currently in VR display mode, otherwise
* {@link Vec3(0)|Vec3.ZERO}. <em>Read-only.</em>

View file

@ -24,6 +24,7 @@
*
* @hifi-interface
* @hifi-client-entity
* @hifi-avatar
*
* @property {bool} raised - <code>true</code> If the keyboard is visible <code>false</code> otherwise
* @property {bool} password - <code>true</code> Will show * instead of characters in the text display <code>false</code> otherwise

View file

@ -35,6 +35,7 @@ class MenuItemProperties;
*
* @hifi-interface
* @hifi-client-entity
* @hifi-avatar
*/
/**

View file

@ -88,6 +88,7 @@ protected:
*
* @hifi-interface
* @hifi-client-entity
* @hifi-avatar
*
* @example <caption>Outline an entity when it is grabbed by a controller.</caption>
* // Create a box and copy the following text into the entity's "Script URL" field.

View file

@ -21,6 +21,7 @@
*
* @hifi-interface
* @hifi-client-entity
* @hifi-avatar
*/
class SettingsScriptingInterface : public QObject {

View file

@ -34,6 +34,7 @@ public:
*
* @hifi-interface
* @hifi-client-entity
* @hifi-avatar
*
* @property {number} walletStatus
* @property {bool} limitedCommerce

View file

@ -31,6 +31,7 @@
*
* @hifi-interface
* @hifi-client-entity
* @hifi-avatar
*
* @property {number} innerWidth - The width of the drawable area of the Interface window (i.e., without borders or other
* chrome), in pixels. <em>Read-only.</em>

View file

@ -17,7 +17,7 @@ HIFI_QML_DEF(AnimStats)
static AnimStats* INSTANCE{ nullptr };
AnimStats* AnimStats::getInstance() {
//Q_ASSERT(INSTANCE);
Q_ASSERT(INSTANCE);
return INSTANCE;
}

View file

@ -29,6 +29,7 @@ class AvatarInputs : public QObject {
*
* @hifi-interface
* @hifi-client-entity
* @hifi-avatar
*
* @property {boolean} cameraEnabled <em>Read-only.</em>
* @property {boolean} cameraMuted <em>Read-only.</em>

View file

@ -734,7 +734,6 @@ void Keyboard::setLayerIndex(int layerIndex) {
}
void Keyboard::loadKeyboardFile(const QString& keyboardFile) {
return;
if (keyboardFile.isEmpty()) {
return;
}
@ -782,7 +781,7 @@ void Keyboard::loadKeyboardFile(const QString& keyboardFile) {
{ "isSolid", true },
{ "visible", false },
{ "grabbable", true },
{ "ignoreRayIntersection", false },
{ "ignorePickIntersection", false },
{ "dimensions", anchorObject["dimensions"].toVariant() },
{ "position", anchorObject["position"].toVariant() },
{ "orientation", anchorObject["rotation"].toVariant() }

View file

@ -42,6 +42,7 @@ private:
*
* @hifi-interface
* @hifi-client-entity
* @hifi-avatar
*/
class Snapshot : public QObject, public Dependency {

View file

@ -46,7 +46,7 @@ static Stats* INSTANCE{ nullptr };
QString getTextureMemoryPressureModeString();
#endif
Stats* Stats::getInstance() {
//Q_ASSERT(INSTANCE);
Q_ASSERT(INSTANCE);
return INSTANCE;
}

View file

@ -27,6 +27,7 @@ private: \
*
* @hifi-interface
* @hifi-client-entity
* @hifi-avatar
* @hifi-server-entity
* @hifi-assignment-client
*

View file

@ -87,6 +87,7 @@ public:
*
* @hifi-interface
* @hifi-client-entity
* @hifi-avatar
*
* @property {Uuid} keyboardFocusOverlay - Get or set the {@link Overlays.OverlayType|web3d} overlay that has keyboard focus.
* If no overlay has keyboard focus, get returns <code>null</code>; set to <code>null</code> or {@link Uuid|Uuid.NULL} to

View file

@ -4,5 +4,6 @@ link_hifi_libraries(shared graphics fbx)
include_hifi_library_headers(networking)
include_hifi_library_headers(gpu)
include_hifi_library_headers(hfm)
include_hifi_library_headers(image)
target_nsight()

View file

@ -140,10 +140,10 @@ void AnimClip::copyFromNetworkAnim() {
postRot = animSkeleton.getPostRotationPose(animJoint);
// cancel out scale
preRot.scale() = glm::vec3(1.0f);
postRot.scale() = glm::vec3(1.0f);
preRot.scale() = 1.0f;
postRot.scale() = 1.0f;
AnimPose rot(glm::vec3(1.0f), hfmAnimRot, glm::vec3());
AnimPose rot(1.0f, hfmAnimRot, glm::vec3());
// adjust translation offsets, so large translation animatons on the reference skeleton
// will be adjusted when played on a skeleton with short limbs.
@ -155,7 +155,7 @@ void AnimClip::copyFromNetworkAnim() {
boneLengthScale = glm::length(relDefaultPose.trans()) / glm::length(hfmZeroTrans);
}
AnimPose trans = AnimPose(glm::vec3(1.0f), glm::quat(), relDefaultPose.trans() + boneLengthScale * (hfmAnimTrans - hfmZeroTrans));
AnimPose trans = AnimPose(1.0f, glm::quat(), relDefaultPose.trans() + boneLengthScale * (hfmAnimTrans - hfmZeroTrans));
_anim[frame][skeletonJoint] = trans * preRot * rot * postRot;
}

View file

@ -552,7 +552,7 @@ void AnimInverseKinematics::solveTargetWithCCD(const AnimContext& context, const
AnimPose accum = absolutePoses[_hipsIndex];
AnimPose baseParentPose = absolutePoses[_hipsIndex];
for (int i = (int)chainDepth - 1; i >= 0; i--) {
accum = accum * AnimPose(glm::vec3(1.0f), jointChainInfoOut.jointInfoVec[i].rot, jointChainInfoOut.jointInfoVec[i].trans);
accum = accum * AnimPose(1.0f, jointChainInfoOut.jointInfoVec[i].rot, jointChainInfoOut.jointInfoVec[i].trans);
postAbsPoses[i] = accum;
if (jointChainInfoOut.jointInfoVec[i].jointIndex == topJointIndex) {
topChainIndex = i;
@ -734,7 +734,7 @@ void AnimInverseKinematics::computeAndCacheSplineJointInfosForIKTarget(const Ani
glm::mat3 m(u, v, glm::cross(u, v));
glm::quat rot = glm::normalize(glm::quat_cast(m));
AnimPose pose(glm::vec3(1.0f), rot, spline(t));
AnimPose pose(1.0f, rot, spline(t));
AnimPose offsetPose = pose.inverse() * defaultPose;
SplineJointInfo splineJointInfo = { index, ratio, offsetPose };
@ -767,7 +767,7 @@ void AnimInverseKinematics::solveTargetWithSpline(const AnimContext& context, co
const int baseIndex = _hipsIndex;
// build spline from tip to base
AnimPose tipPose = AnimPose(glm::vec3(1.0f), target.getRotation(), target.getTranslation());
AnimPose tipPose = AnimPose(1.0f, target.getRotation(), target.getTranslation());
AnimPose basePose = absolutePoses[baseIndex];
CubicHermiteSplineFunctorWithArcLength spline;
if (target.getIndex() == _headIndex) {
@ -815,7 +815,7 @@ void AnimInverseKinematics::solveTargetWithSpline(const AnimContext& context, co
glm::mat3 m(u, v, glm::cross(u, v));
glm::quat rot = glm::normalize(glm::quat_cast(m));
AnimPose desiredAbsPose = AnimPose(glm::vec3(1.0f), rot, trans) * splineJointInfo.offsetPose;
AnimPose desiredAbsPose = AnimPose(1.0f, rot, trans) * splineJointInfo.offsetPose;
// apply flex coefficent
AnimPose flexedAbsPose;
@ -960,7 +960,7 @@ const AnimPoseVec& AnimInverseKinematics::overlay(const AnimVariantMap& animVars
}
_relativePoses[_hipsIndex] = parentAbsPose.inverse() * absPose;
_relativePoses[_hipsIndex].scale() = glm::vec3(1.0f);
_relativePoses[_hipsIndex].scale() = 1.0f;
}
// if there is an active jointChainInfo for the hips store the post shifted hips into it.
@ -1748,7 +1748,7 @@ void AnimInverseKinematics::setSecondaryTargets(const AnimContext& context) {
AnimPose rigToGeometryPose = AnimPose(glm::inverse(context.getGeometryToRigMatrix()));
for (auto& iter : _secondaryTargetsInRigFrame) {
AnimPose absPose = rigToGeometryPose * iter.second;
absPose.scale() = glm::vec3(1.0f);
absPose.scale() = 1.0f;
AnimPose parentAbsPose;
int parentIndex = _skeleton->getParentIndex(iter.first);
@ -1820,7 +1820,7 @@ void AnimInverseKinematics::debugDrawSpineSplines(const AnimContext& context, co
const int baseIndex = _hipsIndex;
// build spline
AnimPose tipPose = AnimPose(glm::vec3(1.0f), target.getRotation(), target.getTranslation());
AnimPose tipPose = AnimPose(1.0f, target.getRotation(), target.getTranslation());
AnimPose basePose = _skeleton->getAbsolutePose(baseIndex, _relativePoses);
CubicHermiteSplineFunctorWithArcLength spline;

View file

@ -172,5 +172,5 @@ AnimPose AnimManipulator::computeRelativePoseFromJointVar(const AnimVariantMap&
break;
}
return AnimPose(glm::vec3(1), relRot, relTrans);
return AnimPose(1.0f, relRot, relTrans);
}

View file

@ -95,7 +95,7 @@ const AnimPoseVec& AnimPoleVectorConstraint::evaluate(const AnimVariantMap& anim
AnimPose tipPose = ikChain.getAbsolutePoseFromJointIndex(_tipJointIndex);
// Look up refVector from animVars, make sure to convert into geom space.
glm::vec3 refVector = midPose.xformVectorFast(_referenceVector);
glm::vec3 refVector = midPose.xformVector(_referenceVector);
float refVectorLength = glm::length(refVector);
glm::vec3 axis = basePose.trans() - tipPose.trans();

View file

@ -14,15 +14,14 @@
#include <glm/gtc/matrix_transform.hpp>
#include "AnimUtil.h"
const AnimPose AnimPose::identity = AnimPose(glm::vec3(1.0f),
glm::quat(),
glm::vec3(0.0f));
const AnimPose AnimPose::identity = AnimPose(1.0f, glm::quat(), glm::vec3(0.0f));
AnimPose::AnimPose(const glm::mat4& mat) {
static const float EPSILON = 0.0001f;
_scale = extractScale(mat);
glm::vec3 scale = extractScale(mat);
// quat_cast doesn't work so well with scaled matrices, so cancel it out.
glm::mat4 tmp = glm::scale(mat, 1.0f / _scale);
glm::mat4 tmp = glm::scale(mat, 1.0f / scale);
_scale = extractUniformScale(scale);
_rot = glm::quat_cast(tmp);
float lengthSquared = glm::length2(_rot);
if (glm::abs(lengthSquared - 1.0f) > EPSILON) {
@ -40,29 +39,22 @@ glm::vec3 AnimPose::xformPoint(const glm::vec3& rhs) const {
return *this * rhs;
}
// really slow, but accurate for transforms with non-uniform scale
glm::vec3 AnimPose::xformVector(const glm::vec3& rhs) const {
glm::vec3 xAxis = _rot * glm::vec3(_scale.x, 0.0f, 0.0f);
glm::vec3 yAxis = _rot * glm::vec3(0.0f, _scale.y, 0.0f);
glm::vec3 zAxis = _rot * glm::vec3(0.0f, 0.0f, _scale.z);
glm::mat3 mat(xAxis, yAxis, zAxis);
glm::mat3 transInvMat = glm::inverse(glm::transpose(mat));
return transInvMat * rhs;
}
// faster, but does not handle non-uniform scale correctly.
glm::vec3 AnimPose::xformVectorFast(const glm::vec3& rhs) const {
return _rot * (_scale * rhs);
}
AnimPose AnimPose::operator*(const AnimPose& rhs) const {
glm::mat4 result;
glm_mat4u_mul(*this, rhs, result);
return AnimPose(result);
float scale = _scale * rhs._scale;
glm::quat rot = _rot * rhs._rot;
glm::vec3 trans = _trans + (_rot * (_scale * rhs._trans));
return AnimPose(scale, rot, trans);
}
AnimPose AnimPose::inverse() const {
return AnimPose(glm::inverse(static_cast<glm::mat4>(*this)));
float invScale = 1.0f / _scale;
glm::quat invRot = glm::inverse(_rot);
glm::vec3 invTrans = invScale * (invRot * -_trans);
return AnimPose(invScale, invRot, invTrans);
}
// mirror about x-axis without applying negative scale.
@ -71,11 +63,10 @@ AnimPose AnimPose::mirror() const {
}
AnimPose::operator glm::mat4() const {
glm::vec3 xAxis = _rot * glm::vec3(_scale.x, 0.0f, 0.0f);
glm::vec3 yAxis = _rot * glm::vec3(0.0f, _scale.y, 0.0f);
glm::vec3 zAxis = _rot * glm::vec3(0.0f, 0.0f, _scale.z);
return glm::mat4(glm::vec4(xAxis, 0.0f), glm::vec4(yAxis, 0.0f),
glm::vec4(zAxis, 0.0f), glm::vec4(_trans, 1.0f));
glm::vec3 xAxis = _rot * glm::vec3(_scale, 0.0f, 0.0f);
glm::vec3 yAxis = _rot * glm::vec3(0.0f, _scale, 0.0f);
glm::vec3 zAxis = _rot * glm::vec3(0.0f, 0.0f, _scale);
return glm::mat4(glm::vec4(xAxis, 0.0f), glm::vec4(yAxis, 0.0f), glm::vec4(zAxis, 0.0f), glm::vec4(_trans, 1.0f));
}
void AnimPose::blend(const AnimPose& srcPose, float alpha) {

View file

@ -21,14 +21,13 @@ class AnimPose {
public:
AnimPose() {}
explicit AnimPose(const glm::mat4& mat);
explicit AnimPose(const glm::quat& rotIn) : _scale(1.0f), _rot(rotIn), _trans(0.0f) {}
AnimPose(const glm::quat& rotIn, const glm::vec3& transIn) : _scale(1.0f), _rot(rotIn), _trans(transIn) {}
AnimPose(const glm::vec3& scaleIn, const glm::quat& rotIn, const glm::vec3& transIn) : _scale(scaleIn), _rot(rotIn), _trans(transIn) {}
explicit AnimPose(const glm::quat& rotIn) : _rot(rotIn), _trans(0.0f), _scale(1.0f) {}
AnimPose(const glm::quat& rotIn, const glm::vec3& transIn) : _rot(rotIn), _trans(transIn), _scale(1.0f) {}
AnimPose(float scaleIn, const glm::quat& rotIn, const glm::vec3& transIn) : _rot(rotIn), _trans(transIn), _scale(scaleIn) {}
static const AnimPose identity;
glm::vec3 xformPoint(const glm::vec3& rhs) const;
glm::vec3 xformVector(const glm::vec3& rhs) const; // really slow, but accurate for transforms with non-uniform scale
glm::vec3 xformVectorFast(const glm::vec3& rhs) const; // faster, but does not handle non-uniform scale correctly.
glm::vec3 operator*(const glm::vec3& rhs) const; // same as xformPoint
AnimPose operator*(const AnimPose& rhs) const;
@ -37,8 +36,8 @@ public:
AnimPose mirror() const;
operator glm::mat4() const;
const glm::vec3& scale() const { return _scale; }
glm::vec3& scale() { return _scale; }
float scale() const { return _scale; }
float& scale() { return _scale; }
const glm::quat& rot() const { return _rot; }
glm::quat& rot() { return _rot; }
@ -50,13 +49,13 @@ public:
private:
friend QDebug operator<<(QDebug debug, const AnimPose& pose);
glm::vec3 _scale { 1.0f };
glm::quat _rot;
glm::vec3 _trans;
float _scale { 1.0f }; // uniform scale only.
};
inline QDebug operator<<(QDebug debug, const AnimPose& pose) {
debug << "AnimPose, trans = (" << pose.trans().x << pose.trans().y << pose.trans().z << "), rot = (" << pose.rot().x << pose.rot().y << pose.rot().z << pose.rot().w << "), scale = (" << pose.scale().x << pose.scale().y << pose.scale().z << ")";
debug << "AnimPose, trans = (" << pose.trans().x << pose.trans().y << pose.trans().z << "), rot = (" << pose.rot().x << pose.rot().y << pose.rot().z << pose.rot().w << "), scale =" << pose.scale();
return debug;
}

View file

@ -76,7 +76,7 @@ int AnimSkeleton::getChainDepth(int jointIndex) const {
int index = jointIndex;
do {
chainDepth++;
index = _joints[index].parentIndex;
index = _parentIndices[index];
} while (index != -1);
return chainDepth;
} else {
@ -102,17 +102,12 @@ const AnimPose& AnimSkeleton::getPostRotationPose(int jointIndex) const {
return _relativePostRotationPoses[jointIndex];
}
int AnimSkeleton::getParentIndex(int jointIndex) const {
return _joints[jointIndex].parentIndex;
}
std::vector<int> AnimSkeleton::getChildrenOfJoint(int jointIndex) const {
// Children and grandchildren, etc.
std::vector<int> result;
if (jointIndex != -1) {
for (int i = jointIndex + 1; i < (int)_joints.size(); i++) {
if (_joints[i].parentIndex == jointIndex
|| (std::find(result.begin(), result.end(), _joints[i].parentIndex) != result.end())) {
for (int i = jointIndex + 1; i < (int)_parentIndices.size(); i++) {
if (_parentIndices[i] == jointIndex || (std::find(result.begin(), result.end(), _parentIndices[i]) != result.end())) {
result.push_back(i);
}
}
@ -128,7 +123,7 @@ AnimPose AnimSkeleton::getAbsolutePose(int jointIndex, const AnimPoseVec& relati
if (jointIndex < 0 || jointIndex >= (int)relativePoses.size() || jointIndex >= _jointsSize) {
return AnimPose::identity;
} else {
return getAbsolutePose(_joints[jointIndex].parentIndex, relativePoses) * relativePoses[jointIndex];
return getAbsolutePose(_parentIndices[jointIndex], relativePoses) * relativePoses[jointIndex];
}
}
@ -136,7 +131,7 @@ void AnimSkeleton::convertRelativePosesToAbsolute(AnimPoseVec& poses) const {
// poses start off relative and leave in absolute frame
int lastIndex = std::min((int)poses.size(), _jointsSize);
for (int i = 0; i < lastIndex; ++i) {
int parentIndex = _joints[i].parentIndex;
int parentIndex = _parentIndices[i];
if (parentIndex != -1) {
poses[i] = poses[parentIndex] * poses[i];
}
@ -147,7 +142,7 @@ void AnimSkeleton::convertAbsolutePosesToRelative(AnimPoseVec& poses) const {
// poses start off absolute and leave in relative frame
int lastIndex = std::min((int)poses.size(), _jointsSize);
for (int i = lastIndex - 1; i >= 0; --i) {
int parentIndex = _joints[i].parentIndex;
int parentIndex = _parentIndices[i];
if (parentIndex != -1) {
poses[i] = poses[parentIndex].inverse() * poses[i];
}
@ -158,7 +153,7 @@ void AnimSkeleton::convertAbsoluteRotationsToRelative(std::vector<glm::quat>& ro
// poses start off absolute and leave in relative frame
int lastIndex = std::min((int)rotations.size(), _jointsSize);
for (int i = lastIndex - 1; i >= 0; --i) {
int parentIndex = _joints[i].parentIndex;
int parentIndex = _parentIndices[i];
if (parentIndex != -1) {
rotations[i] = glm::inverse(rotations[parentIndex]) * rotations[i];
}
@ -197,6 +192,14 @@ void AnimSkeleton::mirrorAbsolutePoses(AnimPoseVec& poses) const {
void AnimSkeleton::buildSkeletonFromJoints(const std::vector<HFMJoint>& joints, const QMap<int, glm::quat> jointOffsets) {
_joints = joints;
// build a seperate vector of parentIndices for cache coherency
// AnimSkeleton::getParentIndex is called very frequently in tight loops.
_parentIndices.reserve(_joints.size());
for (auto& joint : _joints) {
_parentIndices.push_back(joint.parentIndex);
}
_jointsSize = (int)joints.size();
// build a cache of bind poses
@ -289,8 +292,6 @@ void AnimSkeleton::dump(bool verbose) const {
qCDebug(animation) << " relDefaultPose =" << getRelativeDefaultPose(i);
if (verbose) {
qCDebug(animation) << " hfmJoint =";
qCDebug(animation) << " isFree =" << _joints[i].isFree;
qCDebug(animation) << " freeLineage =" << _joints[i].freeLineage;
qCDebug(animation) << " parentIndex =" << _joints[i].parentIndex;
qCDebug(animation) << " translation =" << _joints[i].translation;
qCDebug(animation) << " preTransform =" << _joints[i].preTransform;

View file

@ -43,7 +43,10 @@ public:
// get post transform which might include FBX offset transformations
const AnimPose& getPostRotationPose(int jointIndex) const;
int getParentIndex(int jointIndex) const;
int getParentIndex(int jointIndex) const {
return _parentIndices[jointIndex];
}
std::vector<int> getChildrenOfJoint(int jointIndex) const;
AnimPose getAbsolutePose(int jointIndex, const AnimPoseVec& relativePoses) const;
@ -69,6 +72,7 @@ protected:
void buildSkeletonFromJoints(const std::vector<HFMJoint>& joints, const QMap<int, glm::quat> jointOffsets);
std::vector<HFMJoint> _joints;
std::vector<int> _parentIndices;
int _jointsSize { 0 };
AnimPoseVec _relativeDefaultPoses;
AnimPoseVec _absoluteDefaultPoses;

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