Merge remote-tracking branch 'upstream/master' into bias

This commit is contained in:
SamGondelman 2019-07-09 15:38:13 -07:00
commit 29dbbc49ad
175 changed files with 8749 additions and 801 deletions

View file

@ -453,6 +453,13 @@ void AvatarMixerSlave::broadcastAvatarDataToAgent(const SharedNodePointer& node)
// or that somehow we haven't sent
if (lastSeqToReceiver == lastSeqFromSender && lastSeqToReceiver != 0) {
++numAvatarsHeldBack;
// BUGZ-781 verbose debugging:
auto usecLastTimeSent = destinationNodeData->getLastOtherAvatarEncodeTime(sourceAvatarNodeData->getNodeLocalID());
if (usecLastTimeSent != 0 && startIgnoreCalculation - usecLastTimeSent > 10 * USECS_PER_SECOND) {
qCDebug(avatars) << "Not sent avatar" << *sourceAvatarNode << "to Node" << *destinationNode << "in > 10 s";
}
sendAvatar = false;
} else if (lastSeqFromSender == 0) {
// We have have not yet received any data about this avatar. Ignore it for now

View file

@ -66,6 +66,9 @@ macro(AUTOSCRIBE_PLATFORM_SHADER)
list(APPEND SHADER_GEN_LINE ${TEMP_PATH})
file(RELATIVE_PATH TEMP_PATH ${CMAKE_SOURCE_DIR} ${AUTOSCRIBE_OUTPUT_FILE})
list(APPEND SHADER_GEN_LINE ${TEMP_PATH})
if (NOT("${DEFINES}" STREQUAL ""))
list(APPEND SHADER_GEN_LINE "defines:${DEFINES}")
endif()
list(APPEND SHADER_GEN_LINE ${AUTOSCRIBE_SHADER_SEEN_LIBS})
string(CONCAT AUTOSCRIBE_SHADERGEN_COMMANDS "${AUTOSCRIBE_SHADERGEN_COMMANDS}" "${SHADER_GEN_LINE}\n")
endmacro()
@ -108,6 +111,10 @@ macro(AUTOSCRIBE_SHADER)
set(SHADER_TYPE geom)
endif()
if (NOT("${DEFINES}" STREQUAL ""))
string(CONCAT SHADER_NAME "${SHADER_NAME}" "_${DEFINES}")
endif()
set(SCRIBE_ARGS -D GLPROFILE ${GLPROFILE} -T ${SHADER_TYPE} ${SCRIBE_INCLUDES} )
# SHADER_SCRIBED -> the output of scribe
@ -135,11 +142,78 @@ macro(AUTOSCRIBE_SHADER)
endif()
endif()
string(CONCAT SHADER_ENUMS "${SHADER_ENUMS}" "${SHADER_NAME} = ${SHADER_COUNT},\n")
string(CONCAT SHADER_LIST "${SHADER_LIST}" "${SHADER_NAME} = ${SHADER_COUNT},\n")
string(CONCAT SHADER_SHADERS_ARRAY "${SHADER_SHADERS_ARRAY}" "${SHADER_COUNT},\n")
MATH(EXPR SHADER_COUNT "${SHADER_COUNT}+1")
endmacro()
# This function takes in the list of defines, which would look like:
# (normalmap;translucent:f)/shadow;deformed:v
# and handles parentheses and slashes, producing the semicolon-separated final list of all combinations, which in that case will look like:
# normalmap;translucent:f;normalmap_translucent:f;shadow;normalmap_deformed:v;translucent:f_deformed:v;normalmap_translucent:f_deformed:v;shadow_deformed:v
function(GENERATE_DEFINES_LIST_HELPER INPUT_LIST RETURN_LIST)
# This while loop handles parentheses, looking for matching ( and ) and then calling GENERATE_DEFINES_LIST_HELPER recursively on the text in between
string(LENGTH "${INPUT_LIST}" STR_LENGTH)
set(OPEN_INDEX -1)
set(STR_INDEX 0)
set(NESTED_DEPTH 0)
while ("${STR_INDEX}" LESS "${STR_LENGTH}")
string(SUBSTRING "${INPUT_LIST}" ${STR_INDEX} 1 CURRENT_CHAR)
if (("${CURRENT_CHAR}" STREQUAL "(") AND (OPEN_INDEX EQUAL -1))
set(OPEN_INDEX ${STR_INDEX})
MATH(EXPR STR_INDEX "${STR_INDEX}+1")
continue()
elseif (("${CURRENT_CHAR}" STREQUAL "(") AND NOT(OPEN_INDEX EQUAL -1))
MATH(EXPR NESTED_DEPTH "${NESTED_DEPTH}+1")
MATH(EXPR STR_INDEX "${STR_INDEX}+1")
continue()
elseif (("${CURRENT_CHAR}" STREQUAL ")") AND NOT(OPEN_INDEX EQUAL -1) AND (NESTED_DEPTH GREATER 0))
MATH(EXPR NESTED_DEPTH "${NESTED_DEPTH}-1")
MATH(EXPR STR_INDEX "${STR_INDEX}+1")
continue()
elseif (("${CURRENT_CHAR}" STREQUAL ")") AND NOT(OPEN_INDEX EQUAL -1) AND (NESTED_DEPTH EQUAL 0))
MATH(EXPR OPEN_INDEX "${OPEN_INDEX}+1")
MATH(EXPR SUBSTR_LENGTH "${STR_INDEX}-${OPEN_INDEX}")
string(SUBSTRING "${INPUT_LIST}" ${OPEN_INDEX} ${SUBSTR_LENGTH} GROUP_STR)
GENERATE_DEFINES_LIST_HELPER("${GROUP_STR}" EXPANDED_GROUP_LIST)
string(REPLACE ";" "/" EXPANDED_GROUP_LIST "${EXPANDED_GROUP_LIST}")
string(REPLACE "(${GROUP_STR})" "${EXPANDED_GROUP_LIST}" INPUT_LIST "${INPUT_LIST}")
MATH(EXPR STR_INDEX "${OPEN_INDEX}-1")
set(OPEN_INDEX -1)
string(LENGTH "${INPUT_LIST}" STR_LENGTH)
continue()
endif()
MATH(EXPR STR_INDEX "${STR_INDEX}+1")
endwhile()
# Here we handle the base case, the recursive case, and slashes
list(LENGTH INPUT_LIST NUM_DEFINES)
if (NUM_DEFINES EQUAL 1)
string(REPLACE "/" ";" INPUT_LIST "${INPUT_LIST}")
set(${RETURN_LIST} ${INPUT_LIST} PARENT_SCOPE)
elseif (NUM_DEFINES GREATER 1)
list(GET INPUT_LIST 0 CURRENT_DEFINES)
string(REPLACE "/" ";" CURRENT_DEFINES "${CURRENT_DEFINES}")
list(REMOVE_AT INPUT_LIST 0)
GENERATE_DEFINES_LIST_HELPER("${INPUT_LIST}" REMAINING_DEFINES_LIST)
set(TO_RETURN_LIST "${CURRENT_DEFINES}")
foreach(REMAINING_DEFINES ${REMAINING_DEFINES_LIST})
list(APPEND TO_RETURN_LIST "${REMAINING_DEFINES}")
foreach(CURRENT_DEFINE ${CURRENT_DEFINES})
list(APPEND TO_RETURN_LIST "${CURRENT_DEFINE}_${REMAINING_DEFINES}")
endforeach()
endforeach()
set(${RETURN_LIST} ${TO_RETURN_LIST} PARENT_SCOPE)
endif()
endfunction()
macro(GENERATE_DEFINES_LIST)
set(DEFINES_LIST "")
GENERATE_DEFINES_LIST_HELPER("${ARGV0}" DEFINES_LIST)
endmacro()
macro(AUTOSCRIBE_SHADER_LIB)
if (NOT ("${TARGET_NAME}" STREQUAL "shaders"))
message(FATAL_ERROR "AUTOSCRIBE_SHADER_LIB can only be used by the shaders library")
@ -164,24 +238,24 @@ macro(AUTOSCRIBE_SHADER_LIB)
if (SHADER_VERTEX_FILES)
source_group("${SHADER_LIB}/Vertex" FILES ${SHADER_VERTEX_FILES})
list(APPEND ALL_SCRIBE_SHADERS ${SHADER_VERTEX_FILES})
string(CONCAT SHADER_ENUMS "${SHADER_ENUMS}" "namespace vertex { enum {\n")
foreach(SHADER_FILE ${SHADER_VERTEX_FILES})
set(SHADER_LIST "namespace vertex { enum {\n")
foreach(SHADER_FILE ${SHADER_VERTEX_FILES})
AUTOSCRIBE_SHADER(${ALL_SHADER_HEADERS})
endforeach()
string(CONCAT SHADER_ENUMS "${SHADER_ENUMS}" "}; } // vertex \n")
set(VERTEX_ENUMS "${SHADER_LIST}")
endif()
file(GLOB_RECURSE SHADER_FRAGMENT_FILES ${SRC_FOLDER}/*.slf)
if (SHADER_FRAGMENT_FILES)
source_group("${SHADER_LIB}/Fragment" FILES ${SHADER_FRAGMENT_FILES})
list(APPEND ALL_SCRIBE_SHADERS ${SHADER_FRAGMENT_FILES})
string(CONCAT SHADER_ENUMS "${SHADER_ENUMS}" "namespace fragment { enum {\n")
foreach(SHADER_FILE ${SHADER_FRAGMENT_FILES})
set(SHADER_LIST "namespace fragment { enum {\n")
foreach(SHADER_FILE ${SHADER_FRAGMENT_FILES})
AUTOSCRIBE_SHADER(${ALL_SHADER_HEADERS})
endforeach()
string(CONCAT SHADER_ENUMS "${SHADER_ENUMS}" "}; } // fragment \n")
set(FRAGMENT_ENUMS "${SHADER_LIST}")
endif()
# FIXME add support for geometry, compute and tesselation shaders
#file(GLOB_RECURSE SHADER_GEOMETRY_FILES ${SRC_FOLDER}/*.slg)
#file(GLOB_RECURSE SHADER_COMPUTE_FILES ${SRC_FOLDER}/*.slc)
@ -191,13 +265,13 @@ macro(AUTOSCRIBE_SHADER_LIB)
if (SHADER_PROGRAM_FILES)
source_group("${SHADER_LIB}/Program" FILES ${SHADER_PROGRAM_FILES})
list(APPEND ALL_SCRIBE_SHADERS ${SHADER_PROGRAM_FILES})
string(CONCAT SHADER_ENUMS "${SHADER_ENUMS}" "namespace program { enum {\n")
set(PROGRAM_ENUMS "namespace program { enum {\n")
foreach(PROGRAM_FILE ${SHADER_PROGRAM_FILES})
get_filename_component(PROGRAM_NAME ${PROGRAM_FILE} NAME_WE)
set(AUTOSCRIBE_PROGRAM_FRAGMENT ${PROGRAM_NAME})
file(READ ${PROGRAM_FILE} PROGRAM_CONFIG)
set(AUTOSCRIBE_PROGRAM_VERTEX ${PROGRAM_NAME})
set(AUTOSCRIBE_PROGRAM_FRAGMENT ${PROGRAM_NAME})
set(AUTOSCRIBE_PROGRAM_DEFINES "")
if (NOT("${PROGRAM_CONFIG}" STREQUAL ""))
string(REGEX MATCH ".*VERTEX +([_\\:A-Z0-9a-z]+)" MVERT ${PROGRAM_CONFIG})
@ -208,6 +282,12 @@ macro(AUTOSCRIBE_SHADER_LIB)
if (CMAKE_MATCH_1)
set(AUTOSCRIBE_PROGRAM_FRAGMENT ${CMAKE_MATCH_1})
endif()
string(REGEX MATCH ".*DEFINES +([a-zA-Z\(\)/: ]+)" MDEF ${PROGRAM_CONFIG})
if (CMAKE_MATCH_1)
set(AUTOSCRIBE_PROGRAM_DEFINES ${CMAKE_MATCH_1})
string(TOLOWER AUTOSCRIBE_PROGRAM_DEFINES "${AUTOSCRIBE_PROGRAM_DEFINES}")
string(REGEX REPLACE " +" ";" AUTOSCRIBE_PROGRAM_DEFINES "${AUTOSCRIBE_PROGRAM_DEFINES}")
endif()
endif()
if (NOT (${AUTOSCRIBE_PROGRAM_VERTEX} MATCHES ".*::.*"))
@ -216,12 +296,75 @@ macro(AUTOSCRIBE_SHADER_LIB)
if (NOT (${AUTOSCRIBE_PROGRAM_FRAGMENT} MATCHES ".*::.*"))
set(AUTOSCRIBE_PROGRAM_FRAGMENT "fragment::${AUTOSCRIBE_PROGRAM_FRAGMENT}")
endif()
string(REGEX REPLACE ".*::" "" VERTEX_NAME "${AUTOSCRIBE_PROGRAM_VERTEX}")
string(REGEX REPLACE ".*::" "" FRAGMENT_NAME "${AUTOSCRIBE_PROGRAM_FRAGMENT}")
set(PROGRAM_ENTRY "${PROGRAM_NAME} = (${AUTOSCRIBE_PROGRAM_VERTEX} << 16) | ${AUTOSCRIBE_PROGRAM_FRAGMENT},\n")
string(CONCAT SHADER_ENUMS "${SHADER_ENUMS}" "${PROGRAM_ENTRY}")
GENERATE_DEFINES_LIST("${AUTOSCRIBE_PROGRAM_DEFINES}")
string(CONCAT PROGRAM_ENUMS "${PROGRAM_ENUMS}" "${PROGRAM_NAME} = (${AUTOSCRIBE_PROGRAM_VERTEX} << 16) | ${AUTOSCRIBE_PROGRAM_FRAGMENT},\n")
string(CONCAT SHADER_PROGRAMS_ARRAY "${SHADER_PROGRAMS_ARRAY} ${SHADER_NAMESPACE}::program::${PROGRAM_NAME},\n")
foreach(DEFINES ${DEFINES_LIST})
set(ORIG_DEFINES "${DEFINES}")
# Below here we handle :v and :f. The program name includes both, but the vertex and fragment names
# remove the elements with :f and :v respectively, and only have to call AUTOSCRIBE_SHADER if they don't have those
# (because the shaders without them will have already been generated)
string(REPLACE ":v" "" VERTEX_DEFINES "${ORIG_DEFINES}")
string(FIND "${ORIG_DEFINES}" ":f" HAS_FRAGMENT)
if (HAS_FRAGMENT EQUAL -1)
set(DEFINES "${VERTEX_DEFINES}")
set(SHADER_LIST "")
set(SHADER_FILE "${SRC_FOLDER}/${VERTEX_NAME}.slv")
AUTOSCRIBE_SHADER(${ALL_SHADER_HEADERS})
string(CONCAT VERTEX_ENUMS "${VERTEX_ENUMS}" "${SHADER_LIST}")
else()
string(REGEX REPLACE "_*[^_]*:f" "" VERTEX_DEFINES "${VERTEX_DEFINES}")
endif()
if (NOT("${VERTEX_DEFINES}" STREQUAL "") AND NOT("${VERTEX_DEFINES}" MATCHES "^_.*"))
set(VERTEX_DEFINES "_${VERTEX_DEFINES}")
endif()
string(REPLACE ":f" "" FRAGMENT_DEFINES "${ORIG_DEFINES}")
string(FIND "${ORIG_DEFINES}" ":v" HAS_VERTEX)
if (HAS_VERTEX EQUAL -1)
set(DEFINES "${FRAGMENT_DEFINES}")
set(SHADER_LIST "")
set(SHADER_FILE "${SRC_FOLDER}/${FRAGMENT_NAME}.slf")
AUTOSCRIBE_SHADER(${ALL_SHADER_HEADERS})
string(CONCAT FRAGMENT_ENUMS "${FRAGMENT_ENUMS}" "${SHADER_LIST}")
else()
string(REGEX REPLACE "_*[^_]*:v" "" FRAGMENT_DEFINES "${FRAGMENT_DEFINES}")
endif()
if (NOT("${FRAGMENT_DEFINES}" STREQUAL "") AND NOT("${FRAGMENT_DEFINES}" MATCHES "^_.*"))
set(FRAGMENT_DEFINES "_${FRAGMENT_DEFINES}")
endif()
string(REGEX REPLACE ":(f|v)" "" PROGRAM_DEFINES "${ORIG_DEFINES}")
if (NOT("${PROGRAM_DEFINES}" STREQUAL ""))
string(CONCAT PROGRAM_ENUMS "${PROGRAM_ENUMS}" "${PROGRAM_NAME}_${PROGRAM_DEFINES} = (${AUTOSCRIBE_PROGRAM_VERTEX}${VERTEX_DEFINES} << 16) | ${AUTOSCRIBE_PROGRAM_FRAGMENT}${FRAGMENT_DEFINES},\n")
string(CONCAT SHADER_PROGRAMS_ARRAY "${SHADER_PROGRAMS_ARRAY} ${SHADER_NAMESPACE}::program::${PROGRAM_NAME}_${PROGRAM_DEFINES},\n")
endif()
endforeach()
endforeach()
string(CONCAT SHADER_ENUMS "${SHADER_ENUMS}" "}; } // program \n")
endif()
if (SHADER_VERTEX_FILES)
string(CONCAT VERTEX_ENUMS "${VERTEX_ENUMS}" "}; } // vertex \n")
string(CONCAT SHADER_ENUMS "${SHADER_ENUMS}" "${VERTEX_ENUMS}")
endif()
if (SHADER_FRAGMENT_FILES)
string(CONCAT FRAGMENT_ENUMS "${FRAGMENT_ENUMS}" "}; } // fragment \n")
string(CONCAT SHADER_ENUMS "${SHADER_ENUMS}" "${FRAGMENT_ENUMS}")
endif()
if (SHADER_PROGRAM_FILES)
string(CONCAT PROGRAM_ENUMS "${PROGRAM_ENUMS}" "}; } // program \n")
string(CONCAT SHADER_ENUMS "${SHADER_ENUMS}" "${PROGRAM_ENUMS}")
endif()
# Finish the shader enums

View file

@ -121,12 +121,13 @@ void DomainGatekeeper::processConnectRequestPacket(QSharedPointer<ReceivedMessag
nodeData->setNodeInterestSet(safeInterestSet);
nodeData->setPlaceName(nodeConnection.placeName);
QMetaEnum metaEnum = QMetaEnum::fromType<LimitedNodeList::ConnectReason>();
qDebug() << "Allowed connection from node" << uuidStringWithoutCurlyBraces(node->getUUID())
<< "on" << message->getSenderSockAddr()
<< "with MAC" << nodeConnection.hardwareAddress
<< "and machine fingerprint" << nodeConnection.machineFingerprint
<< "user" << username
<< "reason" << QString(nodeConnection.connectReason ? "SilentDomainDisconnect" : "Connect")
<< "reason" << QString(metaEnum.valueToKey(nodeConnection.connectReason))
<< "previous connection uptime" << nodeConnection.previousConnectionUpTime/USECS_PER_MSEC << "msec"
<< "sysinfo" << nodeConnection.SystemInfo;

View file

@ -2498,7 +2498,7 @@ bool DomainServer::handleHTTPRequest(HTTPConnection* connection, const QUrl& url
return true;
} else if (allNodesDeleteRegex.indexIn(url.path()) != -1) {
qDebug() << "Received request to kill all nodes.";
nodeList->eraseAllNodes();
nodeList->eraseAllNodes(url.path());
return true;
}

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

File diff suppressed because it is too large Load diff

View file

@ -400,7 +400,8 @@ Item {
size: 24;
x: 120
anchors.verticalCenter: nameCardConnectionInfoImage.verticalCenter
anchors.left: has3DHTML ? nameCardConnectionInfoText.right + 10 : avatarImage.right
anchors.left: has3DHTML ? nameCardConnectionInfoText.right : avatarImage.right
anchors.leftMargin: has3DHTML ? 10 : 0
}
MouseArea {
anchors.fill:nameCardRemoveConnectionImage

View file

@ -25,6 +25,14 @@ Flickable {
if (visible) {
root.contentX = 0;
root.contentY = 0;
// When the user clicks the About tab, refresh the audio I/O model so that
// the delegate Component.onCompleted handlers fire, which will update
// the text that appears in the About screen.
audioOutputDevices.model = undefined;
audioOutputDevices.model = AudioScriptingInterface.devices.output;
audioInputDevices.model = undefined;
audioInputDevices.model = AudioScriptingInterface.devices.input;
}
}
@ -47,8 +55,8 @@ Flickable {
source: "images/logo.png"
Layout.alignment: Qt.AlignHCenter
Layout.topMargin: 16
Layout.preferredWidth: 200
Layout.preferredHeight: 150
Layout.preferredWidth: 160
Layout.preferredHeight: 120
fillMode: Image.PreserveAspectFit
mipmap: true
}
@ -195,6 +203,71 @@ Flickable {
wrapMode: Text.Wrap
}
// This is a bit of a hack to get the name of the currently-selected audio input device
// in the current mode (Desktop or VR). The reason this is necessary is because it seems to me like
// the only way one can get a human-readable list of the audio I/O devices is by using a ListView
// and grabbing the names from the AudioScriptingInterface; you can't do it using a ListModel.
// See `AudioDevices.h`, specifically the comment above the declaration of `QVariant data()`.
ListView {
id: audioInputDevices
visible: false
property string selectedInputDeviceName
Layout.preferredWidth: parent.width
Layout.preferredHeight: contentItem.height
interactive: false
delegate: Item {
Component.onCompleted: {
if (HMD.active && selectedHMD) {
audioInputDevices.selectedInputDeviceName = model.devicename
} else if (!HMD.active && selectedDesktop) {
audioInputDevices.selectedInputDeviceName = model.devicename
}
}
}
}
HifiStylesUit.GraphikRegular {
text: "<b>Audio Input:</b> " + audioInputDevices.selectedInputDeviceName
Layout.maximumWidth: parent.width
height: paintedHeight
size: 16
color: simplifiedUI.colors.text.white
wrapMode: Text.Wrap
}
// This is a bit of a hack to get the name of the currently-selected audio output device
// in the current mode (Desktop or VR). The reason this is necessary is because it seems to me like
// the only way one can get a human-readable list of the audio I/O devices is by using a ListView
// and grabbing the names from the AudioScriptingInterface; you can't do it using a ListModel.
// See `AudioDevices.h`, specifically the comment above the declaration of `QVariant data()`.
ListView {
id: audioOutputDevices
visible: false
property string selectedOutputDeviceName
Layout.preferredWidth: parent.width
Layout.preferredHeight: contentItem.height
interactive: false
delegate: Item {
Component.onCompleted: {
if (HMD.active && selectedHMD) {
audioOutputDevices.selectedOutputDeviceName = model.devicename
} else if (!HMD.active && selectedDesktop) {
audioOutputDevices.selectedOutputDeviceName = model.devicename
}
}
}
}
HifiStylesUit.GraphikRegular {
text: "<b>Audio Output:</b> " + audioOutputDevices.selectedOutputDeviceName
Layout.maximumWidth: parent.width
height: paintedHeight
size: 16
color: simplifiedUI.colors.text.white
wrapMode: Text.Wrap
}
SimplifiedControls.Button {
Layout.topMargin: 8
width: 200
@ -248,6 +321,8 @@ Flickable {
textToCopy += "GPU: " + gpuModel + "\n";
textToCopy += "VR Hand Controllers: " + (PlatformInfo.hasRiftControllers() ? "Rift" : (PlatformInfo.hasViveControllers() ? "Vive" : "None")) + "\n";
textToCopy += "Audio Input: " + audioInputDevices.selectedInputDeviceName + "\n";
textToCopy += "Audio Output: " + audioOutputDevices.selectedOutputDeviceName + "\n";
textToCopy += "\n**All Platform Info**\n";
textToCopy += JSON.stringify(JSON.parse(PlatformInfo.getPlatform()), null, 4);

View file

@ -548,6 +548,13 @@ public:
return true;
}
if (message->message == WM_POWERBROADCAST) {
if (message->wParam == PBT_APMRESUMEAUTOMATIC) {
qCInfo(interfaceapp) << "Waking up from sleep or hybernation.";
QMetaObject::invokeMethod(DependencyManager::get<NodeList>().data(), "noteAwakening", Qt::QueuedConnection);
}
}
if (message->message == WM_COPYDATA) {
COPYDATASTRUCT* pcds = (COPYDATASTRUCT*)(message->lParam);
QUrl url = QUrl((const char*)(pcds->lpData));
@ -1465,6 +1472,9 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
_saveAvatarOverrideUrl = true;
}
// setDefaultFormat has no effect after the platform window has been created, so call it here.
QSurfaceFormat::setDefaultFormat(getDefaultOpenGLSurfaceFormat());
_glWidget = new GLCanvas();
getApplicationCompositor().setRenderingWidget(_glWidget);
_window->setCentralWidget(_glWidget);
@ -4161,6 +4171,13 @@ bool Application::event(QEvent* event) {
case QEvent::FocusOut:
focusOutEvent(static_cast<QFocusEvent*>(event));
return true;
case QEvent::FocusIn:
{ //testing to see if we can set focus when focus is not set to root window.
_glWidget->activateWindow();
_glWidget->setFocus();
return true;
}
case QEvent::TouchBegin:
touchBeginEvent(static_cast<QTouchEvent*>(event));
event->accept();
@ -5122,7 +5139,7 @@ void Application::idle() {
// If the offscreen Ui has something active that is NOT the root, then assume it has keyboard focus.
if (offscreenUi && offscreenUi->getWindow()) {
auto activeFocusItem = offscreenUi->getWindow()->activeFocusItem();
if (_keyboardDeviceHasFocus && activeFocusItem != offscreenUi->getRootItem()) {
if (_keyboardDeviceHasFocus && (activeFocusItem != NULL && activeFocusItem != offscreenUi->getRootItem())) {
_keyboardMouseDevice->pluginFocusOutEvent();
_keyboardDeviceHasFocus = false;
synthesizeKeyReleasEvents();
@ -7877,7 +7894,7 @@ void Application::showAssetServerWidget(QString filePath) {
if (!hmd->getShouldShowTablet() && !isHMDMode()) {
getOffscreenUI()->show(url, "AssetServer", startUpload);
} else {
static const QUrl url("hifi/dialogs/TabletAssetServer.qml");
static const QUrl url("qrc:///qml/hifi/dialogs/TabletAssetServer.qml");
if (!tablet->isPathLoaded(url)) {
tablet->pushOntoStack(url);
}
@ -8769,6 +8786,8 @@ bool Application::isThrottleRendering() const {
bool Application::hasFocus() const {
bool result = (QApplication::activeWindow() != nullptr);
#if defined(Q_OS_WIN)
// On Windows, QWidget::activateWindow() - as called in setFocus() - makes the application's taskbar icon flash but doesn't
// take user focus away from their current window. So also check whether the application is the user's current foreground

View file

@ -10,6 +10,8 @@
//
#include "PerformanceManager.h"
#include <platform/Platform.h>
#include <platform/PlatformKeys.h>
#include <platform/Profiler.h>
#include "scripting/RenderScriptingInterface.h"
@ -65,6 +67,19 @@ void PerformanceManager::applyPerformancePreset(PerformanceManager::PerformanceP
// Ugly case that prevent us to run deferred everywhere...
bool isDeferredCapable = platform::Profiler::isRenderMethodDeferredCapable();
auto masterDisplay = platform::getDisplay(platform::getMasterDisplay());
// eval recommanded PPI and Scale
float recommandedPpiScale = 1.0f;
const float RECOMMANDED_PPI[] = { 200.0f, 120.f, 160.f, 250.f};
if (!masterDisplay.empty() && masterDisplay.count(platform::keys::display::ppi)) {
float ppi = masterDisplay[platform::keys::display::ppi];
// only scale if the actual ppi is higher than the recommended ppi
if (ppi > RECOMMANDED_PPI[preset]) {
// make sure the scale is no less than a quarter
recommandedPpiScale = std::max(0.25f, RECOMMANDED_PPI[preset] / (float) ppi);
}
}
switch (preset) {
case PerformancePreset::HIGH:
@ -72,17 +87,21 @@ void PerformanceManager::applyPerformancePreset(PerformanceManager::PerformanceP
RenderScriptingInterface::RenderMethod::DEFERRED :
RenderScriptingInterface::RenderMethod::FORWARD ) );
RenderScriptingInterface::getInstance()->setViewportResolutionScale(recommandedPpiScale);
RenderScriptingInterface::getInstance()->setShadowsEnabled(true);
qApp->getRefreshRateManager().setRefreshRateProfile(RefreshRateManager::RefreshRateProfile::REALTIME);
DependencyManager::get<LODManager>()->setWorldDetailQuality(0.5f);
break;
case PerformancePreset::MID:
RenderScriptingInterface::getInstance()->setRenderMethod((isDeferredCapable ?
RenderScriptingInterface::RenderMethod::DEFERRED :
RenderScriptingInterface::RenderMethod::FORWARD));
RenderScriptingInterface::getInstance()->setViewportResolutionScale(recommandedPpiScale);
RenderScriptingInterface::getInstance()->setShadowsEnabled(false);
qApp->getRefreshRateManager().setRefreshRateProfile(RefreshRateManager::RefreshRateProfile::INTERACTIVE);
DependencyManager::get<LODManager>()->setWorldDetailQuality(0.5f);
@ -93,6 +112,8 @@ void PerformanceManager::applyPerformancePreset(PerformanceManager::PerformanceP
RenderScriptingInterface::getInstance()->setShadowsEnabled(false);
qApp->getRefreshRateManager().setRefreshRateProfile(RefreshRateManager::RefreshRateProfile::ECO);
RenderScriptingInterface::getInstance()->setViewportResolutionScale(recommandedPpiScale);
DependencyManager::get<LODManager>()->setWorldDetailQuality(0.75f);
break;

View file

@ -19,6 +19,11 @@
const int SafeLanding::SEQUENCE_MODULO = std::numeric_limits<OCTREE_PACKET_SEQUENCE>::max() + 1;
CalculateEntityLoadingPriority SafeLanding::entityLoadingOperatorElevateCollidables = [](const EntityItem& entityItem) {
const int COLLIDABLE_ENTITY_PRIORITY = 10.0f;
return entityItem.getCollisionless() * COLLIDABLE_ENTITY_PRIORITY;
};
namespace {
template<typename T> bool lessThanWraparound(int a, int b) {
constexpr int MAX_T_VALUE = std::numeric_limits<T>::max();
@ -52,7 +57,8 @@ void SafeLanding::startTracking(QSharedPointer<EntityTreeRenderer> entityTreeRen
connect(std::const_pointer_cast<EntityTree>(entityTree).get(),
&EntityTree::deletingEntity, this, &SafeLanding::deleteTrackedEntity);
EntityTreeRenderer::setEntityLoadingPriorityFunction(&ElevatedPriority);
_prevEntityLoadingPriorityOperator = EntityTreeRenderer::getEntityLoadingPriorityOperator();
EntityTreeRenderer::setEntityLoadingPriorityFunction(entityLoadingOperatorElevateCollidables);
}
}
}
@ -162,7 +168,7 @@ void SafeLanding::stopTracking() {
&EntityTree::deletingEntity, this, &SafeLanding::deleteTrackedEntity);
_entityTreeRenderer.reset();
}
EntityTreeRenderer::setEntityLoadingPriorityFunction(StandardPriority);
EntityTreeRenderer::setEntityLoadingPriorityFunction(_prevEntityLoadingPriorityOperator);
}
bool SafeLanding::trackingIsComplete() const {
@ -205,10 +211,6 @@ bool SafeLanding::isEntityPhysicsReady(const EntityItemPointer& entity) {
return true;
}
float SafeLanding::ElevatedPriority(const EntityItem& entityItem) {
return entityItem.getCollisionless() ? 0.0f : 10.0f;
}
void SafeLanding::debugDumpSequenceIDs() const {
int p = -1;
qCDebug(interfaceapp) << "Sequence set size:" << _sequenceNumbers.size();

View file

@ -20,6 +20,8 @@
#include "EntityItem.h"
#include "EntityDynamicInterface.h"
#include "EntityTreeRenderer.h"
class EntityTreeRenderer;
class EntityItemID;
@ -64,8 +66,8 @@ private:
std::set<int, SequenceLessThan> _sequenceNumbers;
static float ElevatedPriority(const EntityItem& entityItem);
static float StandardPriority(const EntityItem&) { return 0.0f; }
static CalculateEntityLoadingPriority entityLoadingOperatorElevateCollidables;
CalculateEntityLoadingPriority _prevEntityLoadingPriorityOperator { nullptr };
static const int SEQUENCE_MODULO;
};

View file

@ -21,121 +21,146 @@ class LaserPointerScriptingInterface : public QObject, public Dependency {
SINGLETON_DEPENDENCY
/**jsdoc
* Synonym for {@link Pointers} as used for laser pointers. Deprecated.
* The <code>LaserPointers</code> API is a subset of the {@link Pointers} API. It lets you create, manage, and visually
* represent objects for repeatedly calculating ray intersections with avatars, entities, and overlays. Ray pointers can also
* be configured to generate events on entities and overlays intersected.
*
* <p class="important">Deprecated: This API is deprecated. Use {@link Pointers} instead.
*
* @namespace LaserPointers
*
* @hifi-interface
* @hifi-client-entity
* @hifi-avatar
*
* @borrows Pointers.enablePointer as enableLaserPointer
* @borrows Pointers.disablePointer as disableLaserPointer
* @borrows Pointers.removePointer as removeLaserPointer
* @borrows Pointers.setPrecisionPicking as setPrecisionPicking
*/
public:
/**jsdoc
* Creates a new ray pointer. The pointer can have a wide range of behaviors depending on the properties specified. For
* example, it may be a static ray pointer, a mouse ray pointer, or joint ray pointer.
* <p><strong>Warning:</strong> Pointers created using this method currently always intersect at least visible and
* collidable things but this may not always be the case.</p>
* @function LaserPointers.createLaserPointer
* @param {Pointers.LaserPointerProperties} properties
* @returns {number}
* @param {Pointers.RayPointerProperties} properties - The properties of the pointer, including the properties of the
* underlying pick that the pointer uses to do its picking.
* @returns {number} The ID of the pointer if successfully created, otherwise <code>0</code>.
*/
Q_INVOKABLE unsigned int createLaserPointer(const QVariant& properties) const;
/**jsdoc
* @function LaserPointers.enableLaserPointer
* @param {number} id
*/
// jsdoc @borrows from Pointers
Q_INVOKABLE void enableLaserPointer(unsigned int uid) const { DependencyManager::get<PointerManager>()->enablePointer(uid); }
/**jsdoc
* @function LaserPointers.disableLaserPointer
* @param {number} id
*/
// jsdoc @borrows from Pointers
Q_INVOKABLE void disableLaserPointer(unsigned int uid) const { DependencyManager::get<PointerManager>()->disablePointer(uid); }
/**jsdoc
* @function LaserPointers.removeLaserPointer
* @param {number} id
*/
// jsdoc @borrows from Pointers
Q_INVOKABLE void removeLaserPointer(unsigned int uid) const { DependencyManager::get<PointerManager>()->removePointer(uid); }
/**jsdoc
* Edits a render state of a pointer, to change its visual appearance for the state when the pointer is intersecting
* something.
* <p><strong>Note:</strong> You can only edit the properties of the existing parts of the pointer; you cannot change the
* type of any part.</p>
* <p><strong>Note:</strong> You cannot use this method to change the appearance of a default render state.</p>
* @function LaserPointers.editRenderState
* @param {number} id
* @param {string} renderState
* @param {Pointers.RayPointerRenderState} properties
* @param {number} id - The ID of the pointer.
* @param {string} renderState - The name of the render state to edit.
* @param {Pointers.RayPointerRenderState} properties - The new properties for the render state. Only the overlay
* properties to change need be specified.
*/
Q_INVOKABLE void editRenderState(unsigned int uid, const QString& renderState, const QVariant& properties) const;
/**jsdoc
* Sets the render state of a pointer, to change its visual appearance and possibly disable or enable it.
* @function LaserPointers.setRenderState
* @param {string} renderState
* @param {number} id
* @param {string} renderState - <p>The name of the render state to set the pointer to. This may be:</p>
* <ul>
* <li>The name of one of the render states set in the pointer's properties.</li>
* <li><code>""</code>, to hide the pointer and disable emitting of events.</li>
* </ul>
* @param {number} id - The ID of the pointer.
*/
Q_INVOKABLE void setRenderState(unsigned int uid, const QString& renderState) const { DependencyManager::get<PointerManager>()->setRenderState(uid, renderState.toStdString()); }
/**jsdoc
* Gets the most recent intersection of a pointer. A pointer continues to be updated ready to return a result, as long as
* it is enabled, regardless of the render state.
* @function LaserPointers.getPrevRayPickResult
* @param {number} id
* @returns {RayPickResult}
* @param {number} id - The ID of the pointer.
* @returns {RayPickResult} The most recent intersection of the pointer.
*/
Q_INVOKABLE QVariantMap getPrevRayPickResult(unsigned int uid) const;
/**jsdoc
* @function LaserPointers.setPrecisionPicking
* @param {number} id
* @param {boolean} precisionPicking
*/
// jsdoc @borrows from Pointers
Q_INVOKABLE void setPrecisionPicking(unsigned int uid, bool precisionPicking) const { DependencyManager::get<PointerManager>()->setPrecisionPicking(uid, precisionPicking); }
/**jsdoc
* Sets the length of a pointer.
* @function LaserPointers.setLaserLength
* @param {number} id
* @param {number} laserLength
* @param {number} id - The ID of the pointer.
* @param {number} laserLength - The desired length of the pointer.
*/
Q_INVOKABLE void setLaserLength(unsigned int uid, float laserLength) const { DependencyManager::get<PointerManager>()->setLength(uid, laserLength); }
/**jsdoc
* Sets a list of entity and avatar IDs that a pointer should ignore during intersection.
* @function LaserPointers.setIgnoreItems
* @param {number} id
* @param {Uuid[]} ignoreItems
* @param {number} id - The ID of the pointer.
* @param {Uuid[]} ignoreItems - A list of IDs to ignore.
*/
Q_INVOKABLE void setIgnoreItems(unsigned int uid, const QScriptValue& ignoreEntities) const;
/**jsdoc
* Sets a list of entity and avatar IDs that a pointer should include during intersection, instead of intersecting with
* everything.
* @function LaserPointers.setIncludeItems
* @param {number} id
* @param {Uuid[]} includeItems
* @param {number} id - The ID of the pointer.
* @param {Uuid[]} includeItems - A list of IDs to include.
*/
Q_INVOKABLE void setIncludeItems(unsigned int uid, const QScriptValue& includeEntities) const;
/**jsdoc
* Locks a pointer onto a specific entity or avatar.
* @function LaserPointers.setLockEndUUID
* @param {number} id
* @param {Uuid} itemID
* @param {boolean} isAvatar
* @param {Mat4} [offsetMat]
* @param {number} id - The ID of the pointer.
* @param {Uuid} targetID - The ID of the entity or avatar to lock the pointer on to.
* @param {boolean} isAvatar - <code>true</code> if the target is an avatar, <code>false</code> if it is an entity.
* @param {Mat4} [offset] - The offset of the target point from the center of the target item. If not specified, the
* pointer locks on to the center of the target item.
*/
Q_INVOKABLE void setLockEndUUID(unsigned int uid, const QUuid& objectID, bool isAvatar, const glm::mat4& offsetMat = glm::mat4()) const { DependencyManager::get<PointerManager>()->setLockEndUUID(uid, objectID, isAvatar, offsetMat); }
/**jsdoc
* Checks if a pointer is associated with the left hand: a pointer with <code>joint</code> property set to
* <code>"_CONTROLLER_LEFTHAND"</code> or <code>"_CAMERA_RELATIVE_CONTROLLER_LEFTHAND"</code>.
* @function LaserPointers.isLeftHand
* @param {number} id
* @returns {boolean}
* @param {number} id - The ID of the pointer.
* @returns {boolean} <code>true</code> if the pointer is associated with the left hand, <code>false</code> if it isn't.
*/
Q_INVOKABLE bool isLeftHand(unsigned int uid) { return DependencyManager::get<PointerManager>()->isLeftHand(uid); }
/**jsdoc
* Checks if a pointer is associated with the right hand: a pointer with <code>joint</code> property set to
* <code>"_CONTROLLER_RIGHTHAND"</code> or <code>"_CAMERA_RELATIVE_CONTROLLER_RIGHTHAND"</code>.
* @function LaserPointers.isRightHand
* @param {number} id
* @returns {boolean}
* @param {number} id - The ID of the pointer.
* @returns {boolean} <code>true</code> if the pointer is associated with the right hand, <code>false</code> if it isn't.
*/
Q_INVOKABLE bool isRightHand(unsigned int uid) { return DependencyManager::get<PointerManager>()->isRightHand(uid); }
/**jsdoc
* Checks if a pointer is associated with the system mouse: a pointer with <code>joint</code> property set to
* <code>"Mouse"</code>.
* @function LaserPointers.isMouse
* @param {number} id
* @returns {boolean}
* @param {number} id - The ID of the pointer.
* @returns {boolean} <code>true</code> if the pointer is associated with the system mouse, <code>false</code> if it isn't.
*/
Q_INVOKABLE bool isMouse(unsigned int uid) { return DependencyManager::get<PointerManager>()->isMouse(uid); }
};

View file

@ -55,7 +55,7 @@ PickFilter getPickFilter(unsigned int filter) {
}
/**jsdoc
* A set of properties that can be passed to {@link Picks.createPick} when creating a new ray pick.
* The properties of a ray pick.
*
* @typedef {object} Picks.RayPickProperties
* @property {boolean} [enabled=false] - <code>true</code> if this pick should start enabled, <code>false</code> if it should
@ -138,7 +138,7 @@ unsigned int PickScriptingInterface::createRayPick(const QVariant& properties) {
}
/**jsdoc
* A set of properties that can be passed to {@link Picks.createPick} when creating a new stylus pick.
* The properties of a stylus pick.
*
* @typedef {object} Picks.StylusPickProperties
* @property {number} [hand=-1] <code>0</code> for the left hand, <code>1</code> for the right hand, invalid (<code>-1</code>)
@ -189,7 +189,7 @@ unsigned int PickScriptingInterface::createStylusPick(const QVariant& properties
// NOTE: Laser pointer still uses scaleWithAvatar. Until scaleWithAvatar is also deprecated for pointers, scaleWithAvatar should not be removed from the pick API.
/**jsdoc
* A set of properties that can be passed to {@link Picks.createPick} when creating a new parabola pick.
* The properties of a parabola pick.
*
* @typedef {object} Picks.ParabolaPickProperties
* @property {boolean} [enabled=false] - <code>true</code> if this pick should start enabled, <code>false</code> if it should
@ -297,7 +297,7 @@ unsigned int PickScriptingInterface::createParabolaPick(const QVariant& properti
/**jsdoc
* A set of properties that can be passed to {@link Picks.createPick} when creating a new collision pick.
* The properties of a collision pick.
*
* @typedef {object} Picks.CollisionPickProperties
* @property {boolean} [enabled=false] - <code>true</code> if this pick should start enabled, <code>false</code> if it should

View file

@ -194,7 +194,8 @@ public:
Q_INVOKABLE QVariantMap getPrevPickResult(unsigned int uid);
/**jsdoc
* Sets whether or not to use precision picking, i.e., whether to pick against precise meshes or coarse meshes.
* Sets whether or not a pick should use precision picking, i.e., whether it should pick against precise meshes or coarse
* meshes.
* This has the same effect as using the <code>PICK_PRECISE</code> or <code>PICK_COARSE</code> filter flags.
* @function Picks.setPrecisionPicking
* @param {number} id - The ID of the pick.
@ -203,7 +204,7 @@ public:
Q_INVOKABLE void setPrecisionPicking(unsigned int uid, bool precisionPicking);
/**jsdoc
* Sets a list of entity and avatar IDs to ignore during intersection.
* Sets a list of entity and avatar IDs that a pick should ignore during intersection.
* <p><strong>Note:</strong> Not used by stylus picks.</p>
* @function Picks.setIgnoreItems
* @param {number} id - The ID of the pick.
@ -212,8 +213,9 @@ public:
Q_INVOKABLE void setIgnoreItems(unsigned int uid, const QScriptValue& ignoreItems);
/**jsdoc
* Sets a list of entity IDs and/or avatar IDs to include during intersection, instead of intersecting with everything.
* <p><strong>Note:</strong> Stylus picks only intersect with objects in their include list.</p>
* Sets a list of entity and avatar IDs that a pick should include during intersection, instead of intersecting with
* everything.
* <p><strong>Note:</strong> Stylus picks only intersect with items in their include list.</p>
* @function Picks.setIncludeItems
* @param {number} id - The ID of the pick.
* @param {Uuid[]} includeItems - The list of IDs to include.
@ -221,9 +223,9 @@ public:
Q_INVOKABLE void setIncludeItems(unsigned int uid, const QScriptValue& includeItems);
/**jsdoc
* Checks if a pick is associated with the left hand: a ray or parabola pick with joint set to
* <code>"_CONTROLLER_LEFTHAND"</code> or <code>"_CAMERA_RELATIVE_CONTROLLER_LEFTHAND"</code>, or a stylus pick with hand
* set to <code>0</code>.
* Checks if a pick is associated with the left hand: a ray or parabola pick with <code>joint</code> property set to
* <code>"_CONTROLLER_LEFTHAND"</code> or <code>"_CAMERA_RELATIVE_CONTROLLER_LEFTHAND"</code>, or a stylus pick with
* <code>hand</code> property set to <code>0</code>.
* @function Picks.isLeftHand
* @param {number} id - The ID of the pick.
* @returns {boolean} <code>true</code> if the pick is associated with the left hand, <code>false</code> if it isn't.
@ -231,9 +233,9 @@ public:
Q_INVOKABLE bool isLeftHand(unsigned int uid);
/**jsdoc
* Checks if a pick is associated with the right hand: a ray or parabola pick with joint set to
* <code>"_CONTROLLER_RIGHTHAND"</code> or <code>"_CAMERA_RELATIVE_CONTROLLER_RIGHTHAND"</code>, or a stylus pick with hand
* set to <code>1</code>.
* Checks if a pick is associated with the right hand: a ray or parabola pick with <code>joint</code> property set to
* <code>"_CONTROLLER_RIGHTHAND"</code> or <code>"_CAMERA_RELATIVE_CONTROLLER_RIGHTHAND"</code>, or a stylus pick with
* <code>hand</code> property set to <code>1</code>.
* @function Picks.isRightHand
* @param {number} id - The ID of the pick.
* @returns {boolean} <code>true</code> if the pick is associated with the right hand, <code>false</code> if it isn't.
@ -241,7 +243,8 @@ public:
Q_INVOKABLE bool isRightHand(unsigned int uid);
/**jsdoc
* Checks if a pick is associated with the system mouse: a ray or parabola pick with joint set to <code>"Mouse"</code>.
* Checks if a pick is associated with the system mouse: a ray or parabola pick with <code>joint</code> property set to
* <code>"Mouse"</code>.
* @function Picks.isMouse
* @param {number} id - The ID of the pick.
* @returns {boolean} <code>true</code> if the pick is associated with the system mouse, <code>false</code> if it isn't.

View file

@ -51,21 +51,22 @@ unsigned int PointerScriptingInterface::createPointer(const PickQuery::PickType&
}
/**jsdoc
* A set of properties that can be passed to {@link Pointers.createPointer} to create a new Pointer. Contains the relevant {@link Picks.PickProperties} to define the underlying Pick.
* The properties of a stylus pointer. These include the properties from the underlying stylus pick that the pointer uses.
* @typedef {object} Pointers.StylusPointerProperties
* @property {boolean} [hover=false] If this pointer should generate hover events.
* @property {boolean} [enabled=false]
* @property {Vec3} [tipOffset] The specified offset of the from the joint index.
* @property {Pointers.StylusPointerProperties.model} [model] Data to replace the default model url, positionOffset and rotationOffset.
* @property {Pointers.StylusPointerModel} [model] - Override some or all of the default stylus model properties.
* @property {boolean} [hover=false] - <code>true</code> if the pointer generates {@link Entities} hover events,
* <code>false</code> if it doesn't.
* @see {@link Picks.StylusPickProperties} for additional properties from the underlying stylus pick.
*/
/**jsdoc
* The properties of a stylus pointer model.
* @typedef {object} Pointers.StylusPointerModel
* @property {string} [url] - The url of a model to use for the stylus, to override the default stylus mode.
* @property {Vec3} [dimensions] - The dimensions of the stylus, to override the default stylus dimensions.
* @property {Vec3} [positionOffset] - The position offset of the model from the stylus tip, to override the default position
* offset.
* @property {Quat} [rotationOffset] - The rotation offset of the model from the hand, to override the default rotation offset.
*/
/**jsdoc
* properties defining stylus pick model that can be included to {@link Pointers.StylusPointerProperties}
* @typedef {object} Pointers.StylusPointerProperties.model
* @property {string} [url] url to the model
* @property {Vec3} [dimensions] the dimensions of the model
* @property {Vec3} [positionOffset] the position offset of the model from the stylus tip.
* @property {Vec3} [rotationOffset] the rotation offset of the model from the parent joint index
*/
unsigned int PointerScriptingInterface::createStylus(const QVariant& properties) const {
QVariantMap propertyMap = properties.toMap();
@ -104,48 +105,76 @@ unsigned int PointerScriptingInterface::createStylus(const QVariant& properties)
}
/**jsdoc
* A set of properties used to define the visual aspect of a Ray Pointer in the case that the Pointer is not intersecting something. Same as a {@link Pointers.RayPointerRenderState},
* but with an additional distance field.
*
* Properties that define the visual appearance of a ray pointer when the pointer is not intersecting something. These are the
* properties of {@link Pointers.RayPointerRenderState} but with an additional property.
* @typedef {object} Pointers.DefaultRayPointerRenderState
* @augments Pointers.RayPointerRenderState
* @property {number} distance The distance at which to render the end of this Ray Pointer, if one is defined.
* @property {number} distance - The distance at which to render the end of the ray pointer.
* @see {@link Pointers.RayPointerRenderState} for the remainder of the properties.
*/
/**jsdoc
* A set of properties which define the visual aspect of a Ray Pointer in the case that the Pointer is intersecting something.
*
* Properties that define the visual appearance of a ray pointer when the pointer is intersecting something.
* @typedef {object} Pointers.RayPointerRenderState
* @property {string} name When using {@link Pointers.createPointer}, the name of this render state, used by {@link Pointers.setRenderState} and {@link Pointers.editRenderState}
* @property {Overlays.OverlayProperties|QUuid} [start] When using {@link Pointers.createPointer}, an optionally defined object to represent the beginning of the Ray Pointer,
* using the properties you would normally pass to {@link Overlays.addOverlay}, plus the type (as a <code>type</code> field).
* When returned from {@link Pointers.getPointerProperties}, the ID of the created object if it exists, or a null ID otherwise.
* @property {Overlays.OverlayProperties|QUuid} [path] When using {@link Pointers.createPointer}, an optionally defined object to represent the path of the Ray Pointer,
* using the properties you would normally pass to {@link Overlays.addOverlay}, plus the type (as a <code>type</code> field), which <b>must</b> be <code>"line3d"</code>.
* When returned from {@link Pointers.getPointerProperties}, the ID of the created object if it exists, or a null ID otherwise.
* @property {Overlays.OverlayProperties|QUuid} [end] When using {@link Pointers.createPointer}, an optionally defined object to represent the end of the Ray Pointer,
* using the properties you would normally pass to {@link Overlays.addOverlay}, plus the type (as a <code>type</code> field).
* When returned from {@link Pointers.getPointerProperties}, the ID of the created object if it exists, or a null ID otherwise.
* @property {string} name - When creating using {@link Pointers.createPointer}, the name of the render state.
* @property {Overlays.OverlayProperties|Uuid} [start]
* <p>When creating or editing using {@link Pointers.createPointer} or {@link Pointers.editRenderState}, the properties of
* an overlay to render at the start of the ray pointer. The <code>type</code> property must be specified.</p>
* <p>When getting using {@link Pointers.getPointerProperties}, the ID of the overlay rendered at the start of the ray;
* <code>null</code> if there is no overlay.
*
* @property {Overlays.OverlayProperties|Uuid} [path]
* <p>When creating or editing using {@link Pointers.createPointer} or {@link Pointers.editRenderState}, the properties of
* the overlay rendered for the path of the ray pointer. The <code>type</code> property must be specified and be
* <code>"line3d"</code>.</p>
* <p>When getting using {@link Pointers.getPointerProperties}, the ID of the overlay rendered for the path of the ray;
* <code>null</code> if there is no overlay.
*
* @property {Overlays.OverlayProperties|Uuid} [end]
* <p>When creating or editing using {@link Pointers.createPointer} or {@link Pointers.editRenderState}, the properties of
* an overlay to render at the end of the ray pointer. The <code>type</code> property must be specified.</p>
* <p>When getting using {@link Pointers.getPointerProperties}, the ID of the overlay rendered at the end of the ray;
* <code>null</code> if there is no overlay.
*/
/**jsdoc
* A set of properties that can be passed to {@link Pointers.createPointer} to create a new Pointer. Contains the relevant {@link Picks.PickProperties} to define the underlying Pick.
* @typedef {object} Pointers.LaserPointerProperties
* @property {boolean} [faceAvatar=false] If true, the end of the Pointer will always rotate to face the avatar.
* @property {boolean} [centerEndY=true] If false, the end of the Pointer will be moved up by half of its height.
* @property {boolean} [lockEnd=false] If true, the end of the Pointer will lock on to the center of the object at which the pointer is pointing.
* @property {boolean} [distanceScaleEnd=false] If true, the dimensions of the end of the Pointer will scale linearly with distance.
* @property {boolean} [scaleWithParent=false] If true, the width of the Pointer's path will scale linearly with the pick parent's scale. scaleWithAvatar is an alias but is deprecated.
* @property {boolean} [followNormal=false] If true, the end of the Pointer will rotate to follow the normal of the intersected surface.
* @property {number} [followNormalStrength=0.0] The strength of the interpolation between the real normal and the visual normal if followNormal is true. <code>0-1</code>. If 0 or 1,
* the normal will follow exactly.
* @property {boolean} [enabled=false]
* @property {Pointers.RayPointerRenderState[]|Object.<string, Pointers.RayPointerRenderState>} [renderStates] A collection of different visual states to switch between.
* When using {@link Pointers.createPointer}, a list of RayPointerRenderStates.
* When returned from {@link Pointers.getPointerProperties}, a map between render state names and RayPointRenderStates.
* @property {Pointers.DefaultRayPointerRenderState[]|Object.<string, Pointers.DefaultRayPointerRenderState>} [defaultRenderStates] A collection of different visual states to use if there is no intersection.
* When using {@link Pointers.createPointer}, a list of DefaultRayPointerRenderStates.
* When returned from {@link Pointers.getPointerProperties}, a map between render state names and DefaultRayPointRenderStates.
* @property {boolean} [hover=false] If this Pointer should generate hover events.
* @property {Pointers.Trigger[]} [triggers] A list of different triggers mechanisms that control this Pointer's click event generation.
* The properties of a ray pointer. These include the properties from the underlying ray pick that the pointer uses.
* @typedef {object} Pointers.RayPointerProperties
* @property {boolean} [faceAvatar=false] - <code>true</code> if the overlay rendered at the end of the ray rotates about the
* world y-axis to always face the avatar; <code>false</code> if it maintains its world orientation.
* @property {boolean} [centerEndY=true] - <code>true</code> if the overlay rendered at the end of the ray is centered on
* the ray end; <code>false</code> if the overlay is positioned against the surface if <code>followNormal</code> is
* <code>true</code>, or above the ray end if <code>followNormal</code> is <code>false</code>.
* @property {boolean} [lockEnd=false] - <code>true</code> if the end of the ray is locked to the center of the object at
* which the ray is pointing; <code>false</code> if the end of the ray is at the intersected surface.
* @property {boolean} [distanceScaleEnd=false] - <code>true</code> if the dimensions of the overlay at the end of the ray
* scale linearly with distance; <code>false</code> if they aren't.
* @property {boolean} [scaleWithParent=false] - <code>true</code> if the width of the ray's path and the size of the
* start and end overlays scale linearly with the pointer parent's scale; <code>false</code> if they don't scale.
* @property {boolean} [scaleWithAvatar=false] - A synonym for <code>scalewithParent</code>.
* <p class="important">Deprecated: This property is deprecated and will be removed.</p>
* @property {boolean} [followNormal=false] - <code>true</code> if the overlay rendered at the end of the ray rotates to
* follow the normal of the surface if one is intersected; <code>false</code> if it doesn't.
* @property {number} [followNormalStrength=0.0] - How quickly the overlay rendered at the end of the ray rotates to follow
* the normal of an intersected surface. If <code>0</code> or <code>1</code>, the overlay rotation follows instantaneously;
* for other values, the larger the value the more quickly the rotation follows.
* @property {Pointers.RayPointerRenderState[]|Object.<string, Pointers.RayPointerRenderState>} [renderStates]
* <p>A set of visual states that can be switched among using {@link Pointers.setRenderState}. These define the visual
* appearance of the pointer when it is intersecting something.</p>
* <p>When setting using {@link Pointers.createPointer}, an array of
* {@link Pointers.RayPointerRenderState|RayPointerRenderState} values.</p>
* <p>When getting using {@link Pointers.getPointerProperties}, an object mapping render state names to
* {@link Pointers.RayPointerRenderState|RayPointerRenderState} values.</p>
* @property {Pointers.DefaultRayPointerRenderState[]|Object.<string, Pointers.DefaultRayPointerRenderState>}
* [defaultRenderStates]
* <p>A set of visual states that can be switched among using {@link Pointers.setRenderState}. These define the visual
* appearance of the pointer when it is not intersecting something.</p>
* <p>When setting using {@link Pointers.createPointer}, an array of
* {@link Pointers.DefaultRayPointerRenderState|DefaultRayPointerRenderState} values.</p>
* <p>When getting using {@link Pointers.getPointerProperties}, an object mapping render state names to
* {@link Pointers.DefaultRayPointerRenderState|DefaultRayPointerRenderState} values.</p>
* @property {boolean} [hover=false] - <code>true</code> if the pointer generates {@link Entities} hover events,
* <code>false</code> if it doesn't.
* @property {Pointers.Trigger[]} [triggers=[]] - A list of ways that a {@link Controller} action or function should trigger
* events on the entity or overlay currently intersected.
* @see {@link Picks.RayPickProperties} for additional properties from the underlying ray pick.
*/
unsigned int PointerScriptingInterface::createLaserPointer(const QVariant& properties) const {
QVariantMap propertyMap = properties.toMap();
@ -260,58 +289,84 @@ unsigned int PointerScriptingInterface::createLaserPointer(const QVariant& prope
}
/**jsdoc
* The rendering properties of the parabolic path
*
* @typedef {object} Pointers.ParabolaProperties
* @property {Color} color=255,255,255 The color of the parabola.
* @property {number} alpha=1.0 The alpha of the parabola.
* @property {number} width=0.01 The width of the parabola, in meters.
* @property {boolean} isVisibleInSecondaryCamera=false The width of the parabola, in meters.
* @property {boolean} drawInFront=false If <code>true</code>, the parabola is rendered in front of other items in the scene.
*/
* The visual appearance of the parabolic path.
* @typedef {object} Pointers.ParabolaPointerPath
* @property {Color} [color=255,255,255] - The color of the parabola.
* @property {number} [alpha=1.0] - The opacity of the parabola, range <code>0.0</code> &ndash; <code>1.0</code>.
* @property {number} [width=0.01] - The width of the parabola, in meters.
* @property {boolean} [isVisibleInSecondaryCamera=false] - <code>true</code> if the parabola is rendered in the secondary
* camera, <code>false</code> if it isn't.
* @property {boolean} [drawInFront=false] - <code>true</code> if the parabola is rendered in front of objects in the world,
* but behind the HUD, <code>false</code> if it is occluded by objects in front of it.
*/
/**jsdoc
* A set of properties used to define the visual aspect of a Parabola Pointer in the case that the Pointer is not intersecting something. Same as a {@link Pointers.ParabolaPointerRenderState},
* but with an additional distance field.
*
* @typedef {object} Pointers.DefaultParabolaPointerRenderState
* @augments Pointers.ParabolaPointerRenderState
* @property {number} distance The distance along the parabola at which to render the end of this Parabola Pointer, if one is defined.
*/
* Properties that define the visual appearance of a parabola pointer when the pointer is not intersecting something. These are
* properties of {@link Pointers.ParabolaPointerRenderState} but with an additional property.
* @typedef {object} Pointers.DefaultParabolaPointerRenderState
* @property {number} distance - The distance along the parabola at which to render the end of the parabola pointer.
* @see {@link Pointers.ParabolaPointerRenderState} for the remainder of the properties.
*/
/**jsdoc
* A set of properties used to define the visual aspect of a Parabola Pointer in the case that the Pointer is intersecting something.
*
* @typedef {object} Pointers.ParabolaPointerRenderState
* @property {string} name When using {@link Pointers.createPointer}, the name of this render state, used by {@link Pointers.setRenderState} and {@link Pointers.editRenderState}
* @property {Overlays.OverlayProperties|QUuid} [start] When using {@link Pointers.createPointer}, an optionally defined object to represent the beginning of the Parabola Pointer,
* using the properties you would normally pass to {@link Overlays.addOverlay}, plus the type (as a <code>type</code> field).
* When returned from {@link Pointers.getPointerProperties}, the ID of the created object if it exists, or a null ID otherwise.
* @property {Pointers.ParabolaProperties} [path] When using {@link Pointers.createPointer}, the optionally defined rendering properties of the parabolic path defined by the Parabola Pointer.
* Not defined in {@link Pointers.getPointerProperties}.
* @property {Overlays.OverlayProperties|QUuid} [end] When using {@link Pointers.createPointer}, an optionally defined object to represent the end of the Parabola Pointer,
* using the properties you would normally pass to {@link Overlays.addOverlay}, plus the type (as a <code>type</code> field).
* When returned from {@link Pointers.getPointerProperties}, the ID of the created object if it exists, or a null ID otherwise.
*/
* Properties that define the visual appearance of a parabola pointer when the pointer is intersecting something.
* @typedef {object} Pointers.ParabolaPointerRenderState
* @property {string} name - When creating using {@link Pointers.createPointer}, the name of the render state.
* @property {Overlays.OverlayProperties|Uuid} [start]
* <p>When creating or editing using {@link Pointers.createPointer} or {@link Pointers.editRenderState}, the properties of
* an overlay to render at the start of the parabola pointer. The <code>type</code> property must be specified.</p>
* <p>When getting using {@link Pointers.getPointerProperties}, the ID of the overlay rendered at the start of the
* parabola; <code>null</code> if there is no overlay.
* @property {Pointers.ParabolaPointerPath|Uuid} [path]
* <p>When creating or editing using {@link Pointers.createPointer} or {@link Pointers.editRenderState}, the properties of
* the rendered path of the parabola pointer.</p>
* <p>This property is not provided when getting using {@link Pointers.getPointerProperties}.
* @property {Overlays.OverlayProperties|Uuid} [end]
* <p>When creating or editing using {@link Pointers.createPointer} or {@link Pointers.editRenderState}, the properties of
* an overlay to render at the end of the ray pointer. The <code>type</code> property must be specified.</p>
* <p>When getting using {@link Pointers.getPointerProperties}, the ID of the overlay rendered at the end of the parabola;
* <code>null</code> if there is no overlay.
*/
/**jsdoc
* A set of properties that can be passed to {@link Pointers.createPointer} to create a new Pointer. Contains the relevant {@link Picks.PickProperties} to define the underlying Pick.
* @typedef {object} Pointers.ParabolaPointerProperties
* @property {boolean} [faceAvatar=false] If true, the end of the Pointer will always rotate to face the avatar.
* @property {boolean} [centerEndY=true] If false, the end of the Pointer will be moved up by half of its height.
* @property {boolean} [lockEnd=false] If true, the end of the Pointer will lock on to the center of the object at which the pointer is pointing.
* @property {boolean} [distanceScaleEnd=false] If true, the dimensions of the end of the Pointer will scale linearly with distance.
* @property {boolean} [scaleWithParent=true] If true, the width of the Pointer's path will scale linearly with the pick parent's scale. scaleWithAvatar is an alias but is deprecated.
* @property {boolean} [followNormal=false] If true, the end of the Pointer will rotate to follow the normal of the intersected surface.
* @property {number} [followNormalStrength=0.0] The strength of the interpolation between the real normal and the visual normal if followNormal is true. <code>0-1</code>. If 0 or 1,
* the normal will follow exactly.
* @property {boolean} [enabled=false]
* @property {Pointers.ParabolaPointerRenderState[]|Object.<string, Pointers.ParabolaPointerRenderState>} [renderStates] A collection of different visual states to switch between.
* When using {@link Pointers.createPointer}, a list of ParabolaPointerRenderStates.
* When returned from {@link Pointers.getPointerProperties}, a map between render state names and ParabolaPointerRenderStates.
* @property {Pointers.DefaultParabolaPointerRenderState[]|Object.<string, Pointers.DefaultParabolaPointerRenderState>} [defaultRenderStates] A collection of different visual states to use if there is no intersection.
* When using {@link Pointers.createPointer}, a list of DefaultParabolaPointerRenderStates.
* When returned from {@link Pointers.getPointerProperties}, a map between render state names and DefaultParabolaPointerRenderStates.
* @property {boolean} [hover=false] If this Pointer should generate hover events.
* @property {Pointers.Trigger[]} [triggers] A list of different triggers mechanisms that control this Pointer's click event generation.
*/
* The properties of a parabola pointer. These include the properties from the underlying parabola pick that the pointer uses.
* @typedef {object} Pointers.ParabolaPointerProperties
* @property {boolean} [faceAvatar=false] - <code>true</code> if the overlay rendered at the end of the ray rotates about the
* world y-axis to always face the avatar; <code>false</code> if it maintains its world orientation.
* @property {boolean} [centerEndY=true] - <code>true</code> if the overlay rendered at the end of the ray is centered on
* the ray end; <code>false</code> if the overlay is positioned against the surface if <code>followNormal</code> is
* <code>true</code>, or above the ray end if <code>followNormal</code> is <code>false</code>.
* @property {boolean} [lockEnd=false] - <code>true</code> if the end of the ray is locked to the center of the object at
* which the ray is pointing; <code>false</code> if the end of the ray is at the intersected surface.
* @property {boolean} [distanceScaleEnd=false] - <code>true</code> if the dimensions of the overlay at the end of the ray
* scale linearly with distance; <code>false</code> if they aren't.
* @property {boolean} [scaleWithParent=false] - <code>true</code> if the width of the ray's path and the size of the
* start and end overlays scale linearly with the pointer parent's scale; <code>false</code> if they don't scale.
* @property {boolean} [scaleWithAvatar=false] - A synonym for <code>scalewithParent</code>.
* <p class="important">Deprecated: This property is deprecated and will be removed.</p>
* @property {boolean} [followNormal=false] - <code>true</code> if the overlay rendered at the end of the ray rotates to
* follow the normal of the surface if one is intersected; <code>false</code> if it doesn't.
* @property {number} [followNormalStrength=0.0] - How quickly the overlay rendered at the end of the ray rotates to follow
* the normal of an intersected surface. If <code>0</code> or <code>1</code>, the overlay rotation follows instantaneously;
* for other values, the larger the value the more quickly the rotation follows.
* @property {Pointers.ParabolaPointerRenderState[]|Object.<string, Pointers.ParabolaPointerRenderState>} [renderStates]
* <p>A set of visual states that can be switched among using {@link Pointers.setRenderState}. These define the visual
* appearance of the pointer when it is intersecting something.</p>
* <p>When setting using {@link Pointers.createPointer}, an array of
* {@link Pointers.ParabolaPointerRenderState|ParabolaPointerRenderState} values.</p>
* <p>When getting using {@link Pointers.getPointerProperties}, an object mapping render state names to
* {@link Pointers.ParabolaPointerRenderState|ParabolaPointerRenderState} values.</p>
* @property {Pointers.DefaultParabolaPointerRenderState[]|Object.<string, Pointers.DefaultParabolaPointerRenderState>}
* [defaultRenderStates]
* <p>A set of visual states that can be switched among using {@link Pointers.setRenderState}. These define the visual
* appearance of the pointer when it is not intersecting something.</p>
* <p>When setting using {@link Pointers.createPointer}, an array of
* {@link Pointers.DefaultParabolaPointerRenderState|DefaultParabolaPointerRenderState} values.</p>
* <p>When getting using {@link Pointers.getPointerProperties}, an object mapping render state names to
* {@link Pointers.DefaultParabolaPointerRenderState|DefaultParabolaPointerRenderState} values.</p>
* @property {boolean} [hover=false] - <code>true</code> if the pointer generates {@link Entities} hover events,
* <code>false</code> if it doesn't.
* @property {Pointers.Trigger[]} [triggers=[]] - A list of ways that a {@link Controller} action or function should trigger
* events on the entity or overlay currently intersected.
* @see {@link Picks.ParabolaPickProperties} for additional properties from the underlying parabola pick.
*/
unsigned int PointerScriptingInterface::createParabolaPointer(const QVariant& properties) const {
QVariantMap propertyMap = properties.toMap();

View file

@ -15,8 +15,9 @@
#include <Pick.h>
/**jsdoc
* The Pointers API lets you create and manage objects for repeatedly calculating intersections in different ways, as well as the visual representation of those objects.
* Pointers can also be configured to automatically generate {@link PointerEvent}s on {@link Entities}.
* The <code>Pointers</code> API lets you create, manage, and visually represent objects for repeatedly calculating
* intersections with avatars, entities, and overlays. Pointers can also be configured to generate events on entities and
* overlays intersected.
*
* @namespace Pointers
*
@ -35,184 +36,416 @@ public:
unsigned int createParabolaPointer(const QVariant& properties) const;
/**jsdoc
* A trigger mechanism for Ray and Parabola Pointers.
*
* @typedef {object} Pointers.Trigger
* @property {Controller.Standard|Controller.Actions|function} action This can be a built-in Controller action, like Controller.Standard.LTClick, or a function that evaluates to >= 1.0 when you want to trigger <code>button</code>.
* @property {string} button Which button to trigger. "Primary", "Secondary", "Tertiary", and "Focus" are currently supported. Only "Primary" will trigger clicks on web surfaces. If "Focus" is triggered,
* it will try to set the entity focus to the object at which the Pointer is aimed. Buttons besides the first three will still trigger events, but event.button will be "None".
*/
* Specifies that a {@link Controller} action or function should trigger events on the entity or overlay currently
* intersected by a {@link Pointers.RayPointerProperties|Ray} or {@link Pointers.ParabolaPointerProperties|Parabola}
* pointer.
* @typedef {object} Pointers.Trigger
* @property {Controller.Standard|Controller.Actions|function} action - The controller output or function that triggers the
* events on the entity or overlay. If a function, it must return a number <code>&gt;= 1.0</code> to start the action
* and <code>&lt; 1.0</code> to terminate the action.
* @property {string} button - Which button to trigger.
* <ul>
* <li><code>"Primary"</code>, <code>"Secondary"</code>, and <code>"Tertiary"</code> cause {@link Entities} and
* {@link Overlays} mouse pointer events. Other button names also cause mouse events but the <code>button</code>
* property in the event will be <code>"None"</code>.</li>
* <li><code>"Focus"</code> will try to give focus to the entity or overlay which the pointer is intersecting.</li>
* </ul>
*/
/**jsdoc
* Adds a new Pointer
* Different {@link PickType}s use different properties, and within one PickType, the properties you choose can lead to a wide range of behaviors. For example,
* with PickType.Ray, depending on which optional parameters you pass, you could create a Static Ray Pointer, a Mouse Ray Pointer, or a Joint Ray Pointer.
* Pointers created with this method always intersect at least visible and collidable things
* Creates a new ray, parabola, or stylus pointer. The pointer can have a wide range of behaviors depending on the
* properties specified. For example, a ray pointer may be a static ray pointer, a mouse ray pointer, or joint ray
* pointer.
* <p><strong>Warning:</strong> Pointers created using this method currently always intersect at least visible and
* collidable things but this may not always be the case.</p>
* @function Pointers.createPointer
* @param {PickType} type A PickType that specifies the method of picking to use. Cannot be {@link PickType|PickType.Collision}.
* @param {Pointers.LaserPointerProperties|Pointers.StylusPointerProperties|Pointers.ParabolaPointerProperties} properties A PointerProperties object, containing all the properties for initializing this Pointer <b>and</b> the {@link Picks.PickProperties} for the Pick that
* this Pointer will use to do its picking.
* @returns {number} The ID of the created Pointer. Used for managing the Pointer. 0 if invalid.
* @param {PickType} type - The type of pointer to create. Cannot be {@link PickType|PickType.Collision}.
* @param {Pointers.RayPointerProperties|Pointers.ParabolaPointerProperties|Pointers.StylusPointerProperties} properties -
* The properties of the pointer, per the pointer <code>type</code>, including the properties of the underlying pick
* that the pointer uses to do its picking.
* @returns {number} The ID of the pointer if successfully created, otherwise <code>0</code>.
*
* @example <caption>Create a left hand Ray Pointer that triggers events on left controller trigger click and changes color when it's intersecting something.</caption>
*
* var end = {
* @example <caption>Create a ray pointer on the left hand that changes color when it's intersecting and that triggers
* events.<br />
* Note: Stop controllerScripts.js from running to disable similar behavior from it.</caption>
* var intersectEnd = {
* type: "sphere",
* dimensions: {x:0.5, y:0.5, z:0.5},
* dimensions: { x: 0.2, y: 0.2, z: 0.2 },
* solid: true,
* color: {red:0, green:255, blue:0},
* color: { red: 0, green: 255, blue: 0 },
* ignorePickIntersection: true
* };
* var end2 = {
* var intersectedPath = {
* type: "line3d",
* color: { red: 0, green: 255, blue: 0 },
* };
* var searchEnd = {
* type: "sphere",
* dimensions: {x:0.5, y:0.5, z:0.5},
* dimensions: { x: 0.2, y: 0.2, z: 0.2 },
* solid: true,
* color: {red:255, green:0, blue:0},
* color: { red: 255, green: 0, blue: 0 },
* ignorePickIntersection: true
* };
*
* var renderStates = [ {name: "test", end: end} ];
* var defaultRenderStates = [ {name: "test", distance: 10.0, end: end2} ];
* var pointer = Pointers.createPointer(PickType.Ray, {
* var searchPath = {
* type: "line3d",
* color: { red: 255, green: 0, blue: 0 },
* };
*
* var renderStates = [{ name: "example", path: intersectedPath, end: intersectEnd }];
* var defaultRenderStates = [{ name: "example", distance: 20.0, path: searchPath, end: searchEnd }];
*
* // Create the pointer.
* var rayPointer = Pointers.createPointer(PickType.Ray, {
* joint: "_CAMERA_RELATIVE_CONTROLLER_LEFTHAND",
* filter: Picks.PICK_LOCAL_ENTITIES | Picks.PICK_DOMAIN_ENTITIES | Picks.PICK_INCLUDE_NONCOLLIDABLE,
* renderStates: renderStates,
* defaultRenderStates: defaultRenderStates,
* distanceScaleEnd: true,
* triggers: [ {action: Controller.Standard.LTClick, button: "Focus"}, {action: Controller.Standard.LTClick, button: "Primary"} ],
* hover: true,
* hover: true, // Generate hover events.
* triggers: [
* { action: Controller.Standard.LTClick, button: "Primary" }, // Generate mouse events.
* { action: Controller.Standard.LTClick, button: "Focus" } // Focus on web entities.
* ],
* enabled: true
* });
* Pointers.setRenderState(pointer, "test");
* Pointers.setRenderState(rayPointer, "example");
*
* // Hover events.
* Entities.hoverEnterEntity.connect(function (entityID, event) {
* print("hoverEnterEntity() : " + entityID);
* });
* Entities.hoverLeaveEntity.connect(function (entityID, event) {
* print("hoverLeaveEntity() : " + entityID);
* });
*
* // Mouse events.
* Entities.mousePressOnEntity.connect(function (entityID, event) {
* print("mousePressOnEntity() : " + entityID + " , " + event.button);
* });
* Entities.mouseReleaseOnEntity.connect(function (entityID, event) {
* print("mouseReleaseOnEntity() : " + entityID + " , " + event.button);
* });
*
* // Tidy up.
* Script.scriptEnding.connect(function () {
* Pointers.removePointer(rayPointer);
* });
*/
// TODO: expand Pointers to be able to be fully configurable with PickFilters
Q_INVOKABLE unsigned int createPointer(const PickQuery::PickType& type, const QVariant& properties);
/**jsdoc
* Enables a Pointer.
* Enables and shows a pointer. Enabled pointers update their pick results and generate events.
* @function Pointers.enablePointer
* @param {number} uid The ID of the Pointer, as returned by {@link Pointers.createPointer}.
* @param {number} id - The ID of the pointer.
*/
Q_INVOKABLE void enablePointer(unsigned int uid) const { DependencyManager::get<PointerManager>()->enablePointer(uid); }
/**jsdoc
* Disables a Pointer.
* Disables and hides a pointer. Disabled pointers do not update their pick results or generate events.
* @function Pointers.disablePointer
* @param {number} uid The ID of the Pointer, as returned by {@link Pointers.createPointer}.
* @param {number} id - The ID of the pointer.
*/
Q_INVOKABLE void disablePointer(unsigned int uid) const { DependencyManager::get<PointerManager>()->disablePointer(uid); }
/**jsdoc
* Removes a Pointer.
* Removes (deletes) a pointer.
* @function Pointers.removePointer
* @param {number} uid The ID of the Pointer, as returned by {@link Pointers.createPointer}.
* @param {number} id - The ID of the pointer.
*/
Q_INVOKABLE void removePointer(unsigned int uid) const { DependencyManager::get<PointerManager>()->removePointer(uid); }
/**jsdoc
* Edit some visual aspect of a Pointer. Currently only supported for Ray Pointers.
* Edits a render state of a {@link Pointers.RayPointerProperties|ray} or
* {@link Pointers.ParabolaPointerProperties|parabola} pointer, to change its visual appearance for the state when the
* pointer is intersecting something.
* <p><strong>Note:</strong> You can only edit the properties of the existing parts of the pointer; you cannot change the
* type of any part.</p>
* <p><strong>Note:</strong> You cannot use this method to change the appearance of a default render state.</p>
* <p><strong>Note:</strong> Not able to be used with stylus pointers.</p>
* @function Pointers.editRenderState
* @param {number} uid The ID of the Pointer, as returned by {@link Pointers.createPointer}.
* @param {string} renderState The name of the render state you want to edit.
* @param {Pointers.RayPointerRenderState} properties The new properties for <code>renderStates</code> item.
* @param {number} id - The ID of the pointer.
* @param {string} renderState - The name of the render state to edit.
* @param {Pointers.RayPointerRenderState|Pointers.ParabolaPointerRenderState} properties - The new properties for the
* render state. Only the overlay properties to change need be specified.
* @example <caption>Change the dimensions of a ray pointer's intersecting end overlay.</caption>
* var intersectEnd = {
* type: "sphere",
* dimensions: { x: 0.2, y: 0.2, z: 0.2 },
* solid: true,
* color: { red: 0, green: 255, blue: 0 },
* ignorePickIntersection: true
* };
* var intersectedPath = {
* type: "line3d",
* color: { red: 0, green: 255, blue: 0 },
* };
* var searchEnd = {
* type: "sphere",
* dimensions: { x: 0.2, y: 0.2, z: 0.2 },
* solid: true,
* color: { red: 255, green: 0, blue: 0 },
* ignorePickIntersection: true
* };
* var searchPath = {
* type: "line3d",
* color: { red: 255, green: 0, blue: 0 },
* };
*
* var renderStates = [ { name: "example", path: intersectedPath, end: intersectEnd } ];
* var defaultRenderStates = [ { name: "example", distance: 20.0, path: searchPath, end: searchEnd } ];
*
* // Create the pointer.
* var rayPointer = Pointers.createPointer(PickType.Ray, {
* joint: "_CAMERA_RELATIVE_CONTROLLER_LEFTHAND",
* filter: Picks.PICK_LOCAL_ENTITIES | Picks.PICK_DOMAIN_ENTITIES | Picks.PICK_INCLUDE_NONCOLLIDABLE,
* renderStates: renderStates,
* defaultRenderStates: defaultRenderStates,
* enabled: true
* });
* Pointers.setRenderState(rayPointer, "example");
*
* // Edit the intersecting render state.
* Script.setTimeout(function () {
* print("Edit render state");
* Pointers.editRenderState(rayPointer, "example", {
* end: { dimensions: { x: 0.5, y: 0.5, z: 0.5 } }
* });
* }, 10000);
*
* Script.setTimeout(function () {
* print("Edit render state");
* Pointers.editRenderState(rayPointer, "example", {
* end: { dimensions: { x: 0.2, y: 0.2, z: 0.2 } }
* });
* }, 15000);
*
* // Tidy up.
* Script.scriptEnding.connect(function () {
* Pointers.removePointer(rayPointer);
* });
*/
Q_INVOKABLE void editRenderState(unsigned int uid, const QString& renderState, const QVariant& properties) const;
/**jsdoc
* Set the render state of a Pointer. For Ray Pointers, this means switching between their {@link Pointers.RayPointerRenderState}s, or "" to turn off rendering and hover/trigger events.
* For Stylus Pointers, there are three built-in options: "events on" (render and send events, the default), "events off" (render but don't send events), and "disabled" (don't render, don't send events).
* Sets the render state of a pointer, to change its visual appearance and possibly disable or enable it.
* @function Pointers.setRenderState
* @param {number} uid The ID of the Pointer, as returned by {@link Pointers.createPointer}.
* @param {string} renderState The name of the render state to which you want to switch.
* @param {number} id - The ID of the pointer.
* @param {string} renderState - <p>The name of the render state to set the pointer to.</p>
* <p>For {@link Pointers.RayPointerProperties|ray} and {@link Pointers.ParabolaPointerProperties|parabola} pointers,
* this may be:</p>
* <ul>
* <li>The name of one of the render states set in the pointer's properties.</li>
* <li><code>""</code>, to hide the pointer and disable emitting of events.</li>
* </ul>
* <p>For {@link Pointers.StylusPointerProperties|stylus} pointers, the values may be:</p>
* <ul>
* <li><code>"events on"</code>, to render and emit events (the default).</li>
* <li><code>"events off"</code>, to render but don't emit events.</li>
* <li><code>"disabled"</code>, to not render and not emit events.</li>
* </ul>
* @example <caption>Switch a ray pointer between having a path and not having a path.</caption>
* var intersectEnd = {
* type: "sphere",
* dimensions: { x: 0.2, y: 0.2, z: 0.2 },
* solid: true,
* color: { red: 0, green: 255, blue: 0 },
* ignorePickIntersection: true
* };
* var intersectedPath = {
* type: "line3d",
* color: { red: 0, green: 255, blue: 0 },
* };
* var searchEnd = {
* type: "sphere",
* dimensions: { x: 0.2, y: 0.2, z: 0.2 },
* solid: true,
* color: { red: 255, green: 0, blue: 0 },
* ignorePickIntersection: true
* };
* var searchPath = {
* type: "line3d",
* color: { red: 255, green: 0, blue: 0 },
* };
*
* var renderStates = [
* { name: "examplePath", path: intersectedPath, end: intersectEnd },
* { name: "exampleNoPath", end: intersectEnd }
* ];
* var defaultRenderStates = [
* { name: "examplePath", distance: 20.0, path: searchPath, end: searchEnd },
* { name: "exampleNoPath", distance: 20.0, end: searchEnd }
* ];
*
* // Create the pointer.
* var rayPointer = Pointers.createPointer(PickType.Ray, {
* joint: "_CAMERA_RELATIVE_CONTROLLER_LEFTHAND",
* filter: Picks.PICK_LOCAL_ENTITIES | Picks.PICK_DOMAIN_ENTITIES | Picks.PICK_INCLUDE_NONCOLLIDABLE,
* renderStates: renderStates,
* defaultRenderStates: defaultRenderStates,
* enabled: true
* });
* Pointers.setRenderState(rayPointer, "examplePath");
*
* // Change states.
* Script.setTimeout(function () {
* print("Without path");
* Pointers.setRenderState(rayPointer, "exampleNoPath");
* }, 10000);
*
* Script.setTimeout(function () {
* print("With path");
* Pointers.setRenderState(rayPointer, "examplePath");
* }, 15000);
*
* // Tidy up.
* Script.scriptEnding.connect(function () {
* Pointers.removePointer(rayPointer);
* });
*/
Q_INVOKABLE void setRenderState(unsigned int uid, const QString& renderState) const { DependencyManager::get<PointerManager>()->setRenderState(uid, renderState.toStdString()); }
/**jsdoc
* Get the most recent pick result from this Pointer. This will be updated as long as the Pointer is enabled, regardless of the render state.
* Gets the most recent intersection of a pointer. A pointer continues to be updated ready to return a result, as long as
* it is enabled, regardless of the render state.
* @function Pointers.getPrevPickResult
* @param {number} uid The ID of the Pointer, as returned by {@link Pointers.createPointer}.
* @returns {RayPickResult|StylusPickResult} The most recent intersection result. This will be slightly different for different PickTypes.
* @param {number} id - The ID of the pointer.
* @returns {RayPickResult|ParabolaPickResult|StylusPickResult} The most recent intersection of the pointer.
*/
Q_INVOKABLE QVariantMap getPrevPickResult(unsigned int uid) const;
/**jsdoc
* Sets whether or not to use precision picking.
* Sets whether or not a pointer should use precision picking, i.e., whether it should pick against precise meshes or
* coarse meshes. This has the same effect as using the <code>PICK_PRECISE</code> or <code>PICK_COARSE</code> filter flags.
* @function Pointers.setPrecisionPicking
* @param {number} uid The ID of the Pointer, as returned by {@link Pointers.createPointer}.
* @param {boolean} precisionPicking Whether or not to use precision picking
* @param {number} id - The ID of the pointer.
* @param {boolean} precisionPicking - <code>true</code> to use precision picking, <code>false</code> to use coarse picking.
*/
Q_INVOKABLE void setPrecisionPicking(unsigned int uid, bool precisionPicking) const { DependencyManager::get<PointerManager>()->setPrecisionPicking(uid, precisionPicking); }
/**jsdoc
* Sets the length of this Pointer. No effect on Stylus Pointers.
* Sets the length of a pointer.
* <p><strong>Note:</strong> Not used by stylus pointers.</p>
* @function Pointers.setLength
* @param {number} uid The ID of the Pointer, as returned by {@link Pointers.createPointer}.
* @param {number} length The desired length of the Pointer.
* @param {number} id - The ID of the pointer.
* @param {number} length - The desired length of the pointer.
*/
Q_INVOKABLE void setLength(unsigned int uid, float length) const { DependencyManager::get<PointerManager>()->setLength(uid, length); }
/**jsdoc
* Sets a list of Entity IDs and/or Avatar IDs to ignore during intersection. Not used by Stylus Pointers.
* Sets a list of entity and avatar IDs that a pointer should ignore during intersection.
* <p><strong>Note:</strong> Not used by stylus pointers.</p>
* @function Pointers.setIgnoreItems
* @param {number} uid The ID of the Pointer, as returned by {@link Pointers.createPointer}.
* @param {Uuid[]} ignoreItems A list of IDs to ignore.
* @param {number} id - The ID of the pointer.
* @param {Uuid[]} ignoreItems - A list of IDs to ignore.
*/
Q_INVOKABLE void setIgnoreItems(unsigned int uid, const QScriptValue& ignoreEntities) const;
/**jsdoc
* Sets a list of Entity IDs and/or Avatar IDs to include during intersection, instead of intersecting with everything. Stylus
* Pointers <b>only</b> intersect with objects in their include list.
* Sets a list of entity and avatar IDs that a pointer should include during intersection, instead of intersecting with
* everything.
* <p><strong>Note:</strong> Stylus pointers only intersect with items in their include list.</p>
* @function Pointers.setIncludeItems
* @param {number} uid The ID of the Pointer, as returned by {@link Pointers.createPointer}.
* @param {Uuid[]} includeItems A list of IDs to include.
* @param {number} id - The ID of the pointer.
* @param {Uuid[]} includeItems - A list of IDs to include.
*/
Q_INVOKABLE void setIncludeItems(unsigned int uid, const QScriptValue& includeEntities) const;
/**jsdoc
* Lock a Pointer onto a specific object (entity or avatar). Optionally, provide an offset in object-space, otherwise the Pointer will lock on to the center of the object.
* Not used by Stylus Pointers.
* Locks a pointer onto a specific entity or avatar.
* <p><strong>Note:</strong> Not used by stylus pointers.</p>
* @function Pointers.setLockEndUUID
* @param {number} uid The ID of the Pointer, as returned by {@link Pointers.createPointer}.
* @param {Uuid} objectID The ID of the object to which to lock on.
* @param {boolean} isAvatar False for entities, true for avatars
* @param {Mat4} [offsetMat] The offset matrix to use if you do not want to lock on to the center of the object.
* @param {number} id - The ID of the pointer.
* @param {Uuid} targetID - The ID of the entity or avatar to lock the pointer on to.
* @param {boolean} isAvatar - <code>true</code> if the target is an avatar, <code>false</code> if it is an entity.
* @param {Mat4} [offset] - The offset of the target point from the center of the target item. If not specified, the
* pointer locks on to the center of the target item.
*/
Q_INVOKABLE void setLockEndUUID(unsigned int uid, const QUuid& objectID, bool isAvatar, const glm::mat4& offsetMat = glm::mat4()) const { DependencyManager::get<PointerManager>()->setLockEndUUID(uid, objectID, isAvatar, offsetMat); }
/**jsdoc
* Check if a Pointer is associated with the left hand.
* Checks if a pointer is associated with the left hand: a ray or parabola pointer with <code>joint</code> property set to
* <code>"_CONTROLLER_LEFTHAND"</code> or <code>"_CAMERA_RELATIVE_CONTROLLER_LEFTHAND"</code>, or a stylus pointer with
* <code>hand</code> property set to <code>0</code>.
* @function Pointers.isLeftHand
* @param {number} uid The ID of the Pointer, as returned by {@link Pointers.createPointer}.
* @returns {boolean} True if the Pointer is a Joint Ray Pointer with joint == "_CONTROLLER_LEFTHAND" or "_CAMERA_RELATIVE_CONTROLLER_LEFTHAND", or a Stylus Pointer with hand == 0
* @param {number} id - The ID of the pointer.
* @returns {boolean} <code>true</code> if the pointer is associated with the left hand, <code>false</code> if it isn't.
*/
Q_INVOKABLE bool isLeftHand(unsigned int uid) { return DependencyManager::get<PointerManager>()->isLeftHand(uid); }
/**jsdoc
* Check if a Pointer is associated with the right hand.
* Checks if a pointer is associated with the right hand: a ray or parabola pointer with <code>joint</code> property set to
* <code>"_CONTROLLER_RIGHTHAND"</code> or <code>"_CAMERA_RELATIVE_CONTROLLER_RIGHTHAND"</code>, or a stylus pointer with
* <code>hand</code> property set to <code>1</code>.
* @function Pointers.isRightHand
* @param {number} uid The ID of the Pointer, as returned by {@link Pointers.createPointer}.
* @returns {boolean} True if the Pointer is a Joint Ray Pointer with joint == "_CONTROLLER_RIGHTHAND" or "_CAMERA_RELATIVE_CONTROLLER_RIGHTHAND", or a Stylus Pointer with hand == 1
* @param {number} id - The ID of the pointer.
* @returns {boolean} <code>true</code> if the pointer is associated with the right hand, <code>false</code> if it isn't.
*/
Q_INVOKABLE bool isRightHand(unsigned int uid) { return DependencyManager::get<PointerManager>()->isRightHand(uid); }
/**jsdoc
* Check if a Pointer is associated with the system mouse.
* Checks if a pointer is associated with the system mouse: a ray or parabola pointer with <code>joint</code> property set
* to <code>"Mouse"</code>.
* @function Pointers.isMouse
* @param {number} uid The ID of the Pointer, as returned by {@link Pointers.createPointer}.
* @returns {boolean} True if the Pointer is a Mouse Ray Pointer, false otherwise.
* @param {number} id - The ID of the pointer.
* @returns {boolean} <code>true</code> if the pointer is associated with the system mouse, <code>false</code> if it isn't.
*/
Q_INVOKABLE bool isMouse(unsigned int uid) { return DependencyManager::get<PointerManager>()->isMouse(uid); }
/**jsdoc
* Returns information about an existing Pointer
* Gets information about a pointer.
* @function Pointers.getPointerProperties
* @param {number} uid The ID of the Pointer, as returned by {@link Pointers.createPointer}.
* @returns {Pointers.LaserPointerProperties|Pointers.StylusPointerProperties|Pointers.ParabolaPointerProperties} The information about the Pointer.
* Currently only includes renderStates and defaultRenderStates with associated entity IDs.
* @param {number} id - The ID of the pointer.
* @returns {Pointers.RayPointerProperties|Pointers.ParabolaPointerProperties|object} The <code>renderStates</code> and
* <code>defaultRenderStates</code> for ray and parabola pointers, <code>{}</code> for stylus pointers.
* @example <caption>Report the properties of a parabola pointer.</caption>
* var intersectEnd = {
* type: "sphere",
* dimensions: { x: 0.2, y: 0.2, z: 0.2 },
* solid: true,
* color: { red: 0, green: 255, blue: 0 },
* ignorePickIntersection: true
* };
* var intersectedPath = {
* color: { red: 0, green: 255, blue: 0 },
* };
* var searchEnd = {
* type: "sphere",
* dimensions: { x: 0.2, y: 0.2, z: 0.2 },
* solid: true,
* color: { red: 255, green: 0, blue: 0 },
* ignorePickIntersection: true
* };
* var searchPath = {
* color: { red: 255, green: 0, blue: 0 },
* };
*
* var renderStates = [{ name: "example", path: intersectedPath, end: intersectEnd }];
* var defaultRenderStates = [{ name: "example", distance: 20.0, path: searchPath, end: searchEnd }];
*
* // Create the pointer.
* var parabolaPointer = Pointers.createPointer(PickType.Parabola, {
* joint: "_CAMERA_RELATIVE_CONTROLLER_LEFTHAND",
* filter: Picks.PICK_LOCAL_ENTITIES | Picks.PICK_DOMAIN_ENTITIES | Picks.PICK_INCLUDE_NONCOLLIDABLE,
* renderStates: renderStates,
* defaultRenderStates: defaultRenderStates,
* enabled: true
* });
* Pointers.setRenderState(parabolaPointer, "example");
*
* // Report the pointer properties.
* Script.setTimeout(function () {
* var properties = Pointers.getPointerProperties(parabolaPointer);
* print("Pointer properties:" + JSON.stringify(properties));
* }, 500);
*
* // Tidy up.
* Script.scriptEnding.connect(function () {
* Pointers.removePointer(parabolaPointer);
* });
*/
Q_INVOKABLE QVariantMap getPointerProperties(unsigned int uid) const;
};

View file

@ -107,7 +107,8 @@ public:
/**jsdoc
* Sets whether or not to use precision picking, i.e., whether to pick against precise meshes or coarse meshes.
* Sets whether or not a ray pick should use precision picking, i.e., whether it should pick against precise meshes or
* coarse meshes.
* @function RayPick.setPrecisionPicking
* @param {number} id - The ID of the ray pick.
* @param {boolean} precisionPicking - <code>true</code> to use precision picking, <code>false</code> to use coarse picking.
@ -115,7 +116,7 @@ public:
Q_INVOKABLE void setPrecisionPicking(unsigned int uid, bool precisionPicking);
/**jsdoc
* Sets a list of entity and avatar IDs to ignore during intersection.
* Sets a list of entity and avatar IDs that a ray pick should ignore during intersection.
* @function RayPick.setIgnoreItems
* @param {number} id - The ID of the ray pick.
* @param {Uuid[]} ignoreItems - The list of IDs to ignore.
@ -123,7 +124,8 @@ public:
Q_INVOKABLE void setIgnoreItems(unsigned int uid, const QScriptValue& ignoreEntities);
/**jsdoc
* Sets a list of entity IDs and/or avatar IDs to include during intersection, instead of intersecting with everything.
* Sets a list of entity and avatar IDs that a ray pick should include during intersection, instead of intersecting with
* everything.
* @function RayPick.setIncludeItems
* @param {number} id - The ID of the ray pick.
* @param {Uuid[]} includeItems - The list of IDs to include.
@ -132,9 +134,9 @@ public:
/**jsdoc
* Checks if a pick is associated with the left hand: a ray or parabola pick with joint set to
* <code>"_CONTROLLER_LEFTHAND"</code> or <code>"_CAMERA_RELATIVE_CONTROLLER_LEFTHAND"</code>, or a stylus pick with hand
* set to <code>0</code>.
* Checks if a pick is associated with the left hand: a ray or parabola pick with <code>joint</code> property set to
* <code>"_CONTROLLER_LEFTHAND"</code> or <code>"_CAMERA_RELATIVE_CONTROLLER_LEFTHAND"</code>, or a stylus pick with
* <code>hand</code> property set to <code>0</code>.
* @function RayPick.isLeftHand
* @param {number} id - The ID of the ray pick.
* @returns {boolean} <code>true</code> if the pick is associated with the left hand, <code>false</code> if it isn't.
@ -142,9 +144,9 @@ public:
Q_INVOKABLE bool isLeftHand(unsigned int uid);
/**jsdoc
* Checks if a pick is associated with the right hand: a ray or parabola pick with joint set to
* <code>"_CONTROLLER_RIGHTHAND"</code> or <code>"_CAMERA_RELATIVE_CONTROLLER_RIGHTHAND"</code>, or a stylus pick with hand
* set to <code>1</code>.
* Checks if a pick is associated with the right hand: a ray or parabola pick with <code>joint</code> property set to
* <code>"_CONTROLLER_RIGHTHAND"</code> or <code>"_CAMERA_RELATIVE_CONTROLLER_RIGHTHAND"</code>, or a stylus pick with
* <code>hand</code> property set to <code>1</code>.
* @function RayPick.isRightHand
* @param {number} id - The ID of the ray pick.
* @returns {boolean} <code>true</code> if the pick is associated with the right hand, <code>false</code> if it isn't.
@ -152,7 +154,8 @@ public:
Q_INVOKABLE bool isRightHand(unsigned int uid);
/**jsdoc
* Checks if a pick is associated with the system mouse: a ray or parabola pick with joint set to <code>"Mouse"</code>.
* Checks if a pick is associated with the system mouse: a ray or parabola pick with <code>joint</code> property set to
* <code>"Mouse"</code>.
* @function RayPick.isMouse
* @param {number} id - The ID of the ray pick.
* @returns {boolean} <code>true</code> if the pick is associated with the system mouse, <code>false</code> if it isn't.

View file

@ -167,7 +167,9 @@ bool PlatformInfoScriptingInterface::isStandalone() {
int PlatformInfoScriptingInterface::getNumCPUs() {
return platform::getNumCPUs();
}
int PlatformInfoScriptingInterface::getMasterCPU() {
return platform::getMasterCPU();
}
QString PlatformInfoScriptingInterface::getCPU(int index) {
auto desc = platform::getCPU(index);
return QString(desc.dump().c_str());
@ -176,7 +178,9 @@ QString PlatformInfoScriptingInterface::getCPU(int index) {
int PlatformInfoScriptingInterface::getNumGPUs() {
return platform::getNumGPUs();
}
int PlatformInfoScriptingInterface::getMasterGPU() {
return platform::getMasterGPU();
}
QString PlatformInfoScriptingInterface::getGPU(int index) {
auto desc = platform::getGPU(index);
return QString(desc.dump().c_str());
@ -185,7 +189,9 @@ QString PlatformInfoScriptingInterface::getGPU(int index) {
int PlatformInfoScriptingInterface::getNumDisplays() {
return platform::getNumDisplays();
}
int PlatformInfoScriptingInterface::getMasterDisplay() {
return platform::getMasterDisplay();
}
QString PlatformInfoScriptingInterface::getDisplay(int index) {
auto desc = platform::getDisplay(index);
return QString(desc.dump().c_str());

View file

@ -94,8 +94,8 @@ public slots:
* @returns {string} The graphics card type.
* @deprecated This function is deprecated and will be removed.
* use getNumGPUs() to know the number of GPUs in the hardware, at least one is expected
* use getGPU(0)["vendor"] to get the brand of the vendor
* use getGPU(0)["model"] to get the model name of the gpu
* use getGPU(getMasterGPU())["vendor"] to get the brand of the vendor
* use getGPU(getMasterGPU())["model"] to get the model name of the gpu
*/
QString getGraphicsCardType();
@ -135,6 +135,13 @@ public slots:
*/
int getNumCPUs();
/**jsdoc
* Get the index of the master CPU.
* @function PlatformInfo.getMasterCPU
* @returns {number} The index of the master CPU detected on the hardware platform.
*/
int getMasterCPU();
/**jsdoc
* Get the description of the CPU at the index parameter
* expected fields are:
@ -152,6 +159,13 @@ public slots:
*/
int getNumGPUs();
/**jsdoc
* Get the index of the master GPU.
* @function PlatformInfo.getMasterGPU
* @returns {number} The index of the master GPU detected on the hardware platform.
*/
int getMasterGPU();
/**jsdoc
* Get the description of the GPU at the index parameter
* expected fields are:
@ -169,6 +183,13 @@ public slots:
*/
int getNumDisplays();
/**jsdoc
* Get the index of the master Display.
* @function PlatformInfo.getMasterDisplay
* @returns {number} The index of the master Display detected on the hardware platform.
*/
int getMasterDisplay();
/**jsdoc
* Get the description of the Display at the index parameter
* expected fields are:

View file

@ -132,7 +132,7 @@ void AnimStats::updateStats(bool force) {
if (type == AnimNodeType::Clip) {
// figure out the grayScale color of this line.
const float LIT_TIME = 2.0f;
const float LIT_TIME = 20.0f;
const float FADE_OUT_TIME = 1.0f;
float grayScale = 0.0f;
float secondsElapsed = (float)(now - _animAlphaValueChangedTimers[key]) / (float)USECS_PER_SECOND;
@ -176,7 +176,7 @@ void AnimStats::updateStats(bool force) {
}
// figure out the grayScale color of this line.
const float LIT_TIME = 2.0f;
const float LIT_TIME = 20.0f;
const float FADE_OUT_TIME = 0.5f;
float grayScale = 0.0f;
float secondsElapsed = (float)(now - _animVarChangedTimers[key]) / (float)USECS_PER_SECOND;

View file

@ -32,6 +32,11 @@ CLauncherApp theApp;
// CLauncherApp initialization
BOOL CLauncherApp::InitInstance() {
// Close interface if is running
int interfacePID = -1;
if (LauncherUtils::isProcessRunning(L"interface.exe", interfacePID)) {
LauncherUtils::shutdownProcess(interfacePID, 0);
}
int iNumOfArgs;
LPWSTR* pArgs = CommandLineToArgvW(GetCommandLine(), &iNumOfArgs);
bool isUninstalling = false;

View file

@ -119,15 +119,22 @@ BOOL CLauncherDlg::OnInitDialog() {
return TRUE;
}
POINT CLauncherDlg::getMouseCoords(MSG* pMsg) {
POINT pos;
pos.x = (int)(short)LOWORD(pMsg->lParam);
pos.y = (int)(short)HIWORD(pMsg->lParam);
return pos;
}
BOOL CLauncherDlg::PreTranslateMessage(MSG* pMsg) {
if ((pMsg->message == WM_KEYDOWN))
{
switch (pMsg->message) {
case WM_KEYDOWN:
if (pMsg->wParam == 'A' && GetKeyState(VK_CONTROL) < 0) {
CWnd* wnd = GetFocus();
CWnd* myWnd = this->GetDlgItem(IDC_ORGNAME);
if (wnd && (wnd == this->GetDlgItem(IDC_ORGNAME) ||
wnd == this->GetDlgItem(IDC_USERNAME) ||
wnd == this->GetDlgItem(IDC_PASSWORD))) {
wnd == this->GetDlgItem(IDC_USERNAME) ||
wnd == this->GetDlgItem(IDC_PASSWORD))) {
((CEdit*)wnd)->SetSel(0, -1);
}
return TRUE;
@ -135,6 +142,33 @@ BOOL CLauncherDlg::PreTranslateMessage(MSG* pMsg) {
OnNextClicked();
return TRUE;
}
break;
case WM_LBUTTONDOWN:
if (pMsg->hwnd == GetSafeHwnd()) {
_draggingWindow = true;
_dragOffset = getMouseCoords(pMsg);
SetCapture();
}
break;
case WM_LBUTTONUP:
if (_draggingWindow) {
ReleaseCapture();
_draggingWindow = false;
}
break;
case WM_MOUSEMOVE:
if (_draggingWindow) {
POINT pos = getMouseCoords(pMsg);
RECT windowRect;
GetWindowRect(&windowRect);
int width = windowRect.right - windowRect.left;
int height = windowRect.bottom - windowRect.top;
ClientToScreen(&pos);
MoveWindow(pos.x - _dragOffset.x, pos.y - _dragOffset.y, width, height, FALSE);
}
break;
default:
break;
}
return CDialog::PreTranslateMessage(pMsg);
}
@ -174,19 +208,11 @@ void CLauncherDlg::startProcess() {
theApp._manager.addToLog(_T("Starting Process Setup"));
setDrawDialog(DrawStep::DrawProcessSetup);
}
theApp._manager.addToLog(_T("Deleting directories before install"));
CString installDir;
theApp._manager.getAndCreatePaths(LauncherManager::PathType::Interface_Directory, installDir);
theApp._manager.addToLog(_T("Deleting download directory"));
CString downloadDir;
theApp._manager.getAndCreatePaths(LauncherManager::PathType::Download_Directory, downloadDir);
LauncherUtils::deleteDirectoriesOnThread(installDir, downloadDir, [&](int error) {
LauncherUtils::DeleteDirError deleteError = (LauncherUtils::DeleteDirError)error;
switch(error) {
case LauncherUtils::DeleteDirError::NoErrorDeleting:
theApp._manager.addToLog(_T("Install directory deleted."));
theApp._manager.addToLog(_T("Downloads directory deleted."));
LauncherUtils::deleteDirectoryOnThread(downloadDir, [&](bool error) {
if (!error) {
if (!theApp._manager.isLoggedIn()) {
theApp._manager.addToLog(_T("Downloading Content"));
theApp._manager.downloadContent();
@ -194,23 +220,12 @@ void CLauncherDlg::startProcess() {
theApp._manager.addToLog(_T("Downloading App"));
theApp._manager.downloadApplication();
}
break;
case LauncherUtils::DeleteDirError::ErrorDeletingBothDirs:
theApp._manager.addToLog(_T("Error deleting directories."));
break;
case LauncherUtils::DeleteDirError::ErrorDeletingApplicationDir:
theApp._manager.addToLog(_T("Error deleting application directory."));
break;
case LauncherUtils::DeleteDirError::ErrorDeletingDownloadsDir:
theApp._manager.addToLog(_T("Error deleting downloads directory."));
break;
default:
break;
}
if (error != LauncherUtils::DeleteDirError::NoErrorDeleting) {
} else {
theApp._manager.addToLog(_T("Error deleting download directory."));
theApp._manager.setFailed(true);
}
});
}
BOOL CLauncherDlg::getHQInfo(const CString& orgname) {
@ -629,7 +644,7 @@ void CLauncherDlg::OnTimer(UINT_PTR nIDEvent) {
::SetForegroundWindow(_applicationWND);
::SetActiveWindow(_applicationWND);
}
if (LauncherUtils::IsProcessRunning(L"interface.exe")) {
if (LauncherUtils::isProcessWindowOpened(L"interface.exe")) {
exit(0);
}
}
@ -653,7 +668,7 @@ void CLauncherDlg::OnTimer(UINT_PTR nIDEvent) {
}
_splashStep++;
} else if (theApp._manager.shouldShutDown()) {
if (LauncherUtils::IsProcessRunning(L"interface.exe")) {
if (LauncherUtils::isProcessWindowOpened(L"interface.exe")) {
exit(0);
}
}

View file

@ -60,12 +60,18 @@ protected:
DrawStep _drawStep { DrawStep::DrawLogo };
BOOL getTextFormat(int ResID, TextFormat& formatOut);
void showWindows(std::vector<CStatic*> windows, bool show);
POINT getMouseCoords(MSG* pMsg);
bool _isConsoleRunning{ false };
bool _isInstalling{ false };
bool _isFirstDraw{ false };
bool _showSplash{ true };
int _splashStep{ 0 };
bool _isConsoleRunning { false };
bool _isInstalling { false };
bool _isFirstDraw { false };
bool _showSplash { true };
bool _draggingWindow { false };
POINT _dragOffset;
int _splashStep { 0 };
float _logoRotation { 0.0f };
HICON m_hIcon;

View file

@ -15,13 +15,10 @@
#include "LauncherManager.h"
LauncherManager::LauncherManager()
{
LauncherManager::LauncherManager() {
}
LauncherManager::~LauncherManager()
{
LauncherManager::~LauncherManager() {
}
void LauncherManager::init() {
@ -41,6 +38,9 @@ void LauncherManager::init() {
addToLog(_T("New build found. Updating"));
_shouldUpdate = TRUE;
}
} else if (_loggedIn) {
addToLog(_T("Interface not found but logged in. Reinstalling"));
_shouldUpdate = TRUE;
}
} else {
_hasFailed = true;
@ -113,8 +113,11 @@ BOOL LauncherManager::installLauncher() {
// The installer is not running on the desired location and has to be installed
// Kill of running before self-copy
addToLog(_T("Installing Launcher."));
if (LauncherUtils::IsProcessRunning(LAUNCHER_EXE_FILENAME)) {
ShellExecute(NULL, NULL, L"taskkill", L"/F /T /IM " + LAUNCHER_EXE_FILENAME, NULL, SW_HIDE);
int launcherPID = -1;
if (LauncherUtils::isProcessRunning(LAUNCHER_EXE_FILENAME, launcherPID)) {
if (!LauncherUtils::shutdownProcess(launcherPID, 0)) {
addToLog(_T("Error shutting down the Launcher"));
}
}
CopyFile(appPath, instalationPath, FALSE);
}
@ -151,7 +154,7 @@ BOOL LauncherManager::createShortcuts() {
CString installDir;
getAndCreatePaths(PathType::Launcher_Directory, installDir);
CString installPath = installDir + LAUNCHER_EXE_FILENAME;
if (!LauncherUtils::CreateLink(installPath, (LPCSTR)CStringA(desktopLnkPath), _T("CLick to Setup and Launch HQ."))) {
if (!LauncherUtils::createLink(installPath, (LPCSTR)CStringA(desktopLnkPath), _T("CLick to Setup and Launch HQ."))) {
return FALSE;
}
CString startLinkPath;
@ -159,13 +162,13 @@ BOOL LauncherManager::createShortcuts() {
CString appStartLinkPath = startLinkPath + _T("HQ Launcher.lnk");
CString uniStartLinkPath = startLinkPath + _T("Uninstall HQ.lnk");
CString uniLinkPath = installDir + _T("Uninstall HQ.lnk");
if (!LauncherUtils::CreateLink(installPath, (LPCSTR)CStringA(appStartLinkPath), _T("CLick to Setup and Launch HQ."))) {
if (!LauncherUtils::createLink(installPath, (LPCSTR)CStringA(appStartLinkPath), _T("CLick to Setup and Launch HQ."))) {
return FALSE;
}
if (!LauncherUtils::CreateLink(installPath, (LPCSTR)CStringA(uniStartLinkPath), _T("CLick to Uninstall HQ."), _T("--uninstall"))) {
if (!LauncherUtils::createLink(installPath, (LPCSTR)CStringA(uniStartLinkPath), _T("CLick to Uninstall HQ."), _T("--uninstall"))) {
return FALSE;
}
if (!LauncherUtils::CreateLink(installPath, (LPCSTR)CStringA(uniLinkPath), _T("CLick to Uninstall HQ."), _T("--uninstall"))) {
if (!LauncherUtils::createLink(installPath, (LPCSTR)CStringA(uniLinkPath), _T("CLick to Uninstall HQ."), _T("--uninstall"))) {
return FALSE;
}
return TRUE;
@ -189,9 +192,9 @@ BOOL LauncherManager::isApplicationInstalled(CString& version, CString& domain,
CString applicationPath = applicationDir + "interface\\interface.exe";
BOOL isApplicationInstalled = PathFileExistsW(applicationPath);
BOOL configFileExist = PathFileExistsW(applicationDir + _T("interface\\config.json"));
if (isApplicationInstalled && configFileExist) {
if (configFileExist) {
LauncherUtils::ResponseError status = readConfigJSON(version, domain, content, loggedIn);
return status == LauncherUtils::ResponseError::NoError;
return isApplicationInstalled && status == LauncherUtils::ResponseError::NoError;
}
return FALSE;
}
@ -308,7 +311,8 @@ LauncherUtils::ResponseError LauncherManager::readConfigJSON(CString& version, C
}
Json::Value config;
configFile >> config;
if (config["version"].isString() && config["domain"].isString() &&
if (config["version"].isString() &&
config["domain"].isString() &&
config["content"].isString()) {
loggedIn = config["loggedIn"].asBool();
version = config["version"].asCString();
@ -440,10 +444,6 @@ void LauncherManager::onZipExtracted(ZipType type, int size) {
downloadApplication();
} else if (type == ZipType::ZipApplication) {
createShortcuts();
CString versionPath;
getAndCreatePaths(LauncherManager::PathType::Launcher_Directory, versionPath);
addToLog(_T("Creating config.json"));
createConfigJSON();
addToLog(_T("Launching application."));
_shouldLaunch = TRUE;
if (!_shouldUpdate) {
@ -457,6 +457,8 @@ void LauncherManager::onZipExtracted(ZipType type, int size) {
BOOL LauncherManager::extractApplication() {
CString installPath;
getAndCreatePaths(LauncherManager::PathType::Interface_Directory, installPath);
addToLog(_T("Creating config.json"));
createConfigJSON();
BOOL success = LauncherUtils::unzipFileOnThread(ZipType::ZipApplication, LauncherUtils::cStringToStd(_applicationZipPath),
LauncherUtils::cStringToStd(installPath), [&](int type, int size) {
if (size > 0) {
@ -476,11 +478,31 @@ BOOL LauncherManager::extractApplication() {
void LauncherManager::onFileDownloaded(DownloadType type) {
if (type == DownloadType::DownloadContent) {
addToLog(_T("Installing content."));
installContent();
addToLog(_T("Deleting content directory before install"));
CString contentDir;
getAndCreatePaths(PathType::Content_Directory, contentDir);
LauncherUtils::deleteDirectoryOnThread(contentDir, [&](bool error) {
if (!error) {
addToLog(_T("Installing content."));
installContent();
} else {
addToLog(_T("Error deleting content directory."));
setFailed(true);
}
});
} else if (type == DownloadType::DownloadApplication) {
addToLog(_T("Installing application."));
extractApplication();
addToLog(_T("Deleting application directory before install"));
CString applicationDir;
getAndCreatePaths(PathType::Interface_Directory, applicationDir);
LauncherUtils::deleteDirectoryOnThread(applicationDir, [&](bool error) {
if (!error) {
addToLog(_T("Installing application."));
extractApplication();
} else {
addToLog(_T("Error deleting install directory."));
setFailed(true);
}
});
}
}

View file

@ -37,17 +37,53 @@ CString LauncherUtils::urlEncodeString(const CString& url) {
return stringOut;
}
BOOL LauncherUtils::IsProcessRunning(const wchar_t *processName) {
BOOL LauncherUtils::shutdownProcess(DWORD dwProcessId, UINT uExitCode) {
DWORD dwDesiredAccess = PROCESS_TERMINATE;
BOOL bInheritHandle = FALSE;
HANDLE hProcess = OpenProcess(dwDesiredAccess, bInheritHandle, dwProcessId);
if (hProcess == NULL) {
return FALSE;
}
BOOL result = TerminateProcess(hProcess, uExitCode);
CloseHandle(hProcess);
return result;
}
BOOL CALLBACK LauncherUtils::isWindowOpenedCallback(HWND hWnd, LPARAM lparam) {
ProcessData* processData = reinterpret_cast<ProcessData*>(lparam);
if (processData) {
DWORD idptr;
GetWindowThreadProcessId(hWnd, &idptr);
if (idptr && (int)(idptr) == processData->processID) {
processData->isOpened = IsWindowVisible(hWnd);
return FALSE;
}
}
return TRUE;
}
BOOL LauncherUtils::isProcessWindowOpened(const wchar_t *processName) {
ProcessData processData;
BOOL result = isProcessRunning(processName, processData.processID);
if (result) {
EnumWindows(LauncherUtils::isWindowOpenedCallback, reinterpret_cast<LPARAM>(&processData));
return processData.isOpened;
}
return result;
}
BOOL LauncherUtils::isProcessRunning(const wchar_t *processName, int& processID) {
bool exists = false;
PROCESSENTRY32 entry;
entry.dwSize = sizeof(PROCESSENTRY32);
HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, NULL);
if (Process32First(snapshot, &entry)) {
while (Process32Next(snapshot, &entry)) {
if (!_wcsicmp(entry.szExeFile, processName)) {
exists = true;
processID = entry.th32ProcessID;
break;
}
}
@ -56,7 +92,7 @@ BOOL LauncherUtils::IsProcessRunning(const wchar_t *processName) {
return exists;
}
HRESULT LauncherUtils::CreateLink(LPCWSTR lpszPathObj, LPCSTR lpszPathLink, LPCWSTR lpszDesc, LPCWSTR lpszArgs) {
HRESULT LauncherUtils::createLink(LPCWSTR lpszPathObj, LPCSTR lpszPathLink, LPCWSTR lpszDesc, LPCWSTR lpszArgs) {
IShellLink* psl;
// Get a pointer to the IShellLink interface. It is assumed that CoInitialize
@ -444,16 +480,10 @@ DWORD WINAPI LauncherUtils::downloadThread(LPVOID lpParameter) {
return 0;
}
DWORD WINAPI LauncherUtils::deleteDirectoriesThread(LPVOID lpParameter) {
DWORD WINAPI LauncherUtils::deleteDirectoryThread(LPVOID lpParameter) {
DeleteThreadData& data = *((DeleteThreadData*)lpParameter);
DeleteDirError error = DeleteDirError::NoErrorDeleting;
if (!LauncherUtils::deleteFileOrDirectory(data._applicationDir)) {
error = DeleteDirError::ErrorDeletingApplicationDir;
}
if (!LauncherUtils::deleteFileOrDirectory(data._downloadsDir)) {
error = error == NoError ? DeleteDirError::ErrorDeletingDownloadsDir : DeleteDirError::ErrorDeletingBothDirs;
}
data.callback(error);
BOOL success = LauncherUtils::deleteFileOrDirectory(data._dirPath);
data.callback(!success);
return 0;
}
@ -487,15 +517,12 @@ BOOL LauncherUtils::downloadFileOnThread(int type, const CString& url, const CSt
return FALSE;
}
BOOL LauncherUtils::deleteDirectoriesOnThread(const CString& applicationDir,
const CString& downloadsDir,
std::function<void(int)> callback) {
BOOL LauncherUtils::deleteDirectoryOnThread(const CString& dirPath, std::function<void(bool)> callback) {
DWORD myThreadID;
DeleteThreadData* deleteThreadData = new DeleteThreadData();
deleteThreadData->_applicationDir = applicationDir;
deleteThreadData->_downloadsDir = downloadsDir;
deleteThreadData->_dirPath = dirPath;
deleteThreadData->setCallback(callback);
HANDLE myHandle = CreateThread(0, 0, deleteDirectoriesThread, deleteThreadData, 0, &myThreadID);
HANDLE myHandle = CreateThread(0, 0, deleteDirectoryThread, deleteThreadData, 0, &myThreadID);
if (myHandle) {
CloseHandle(myHandle);
return TRUE;

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