Merge branch 'master' into bugz-690

This commit is contained in:
amer cerkic 2019-07-08 09:28:28 -07:00
commit 386d945eeb
45 changed files with 1685 additions and 492 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

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

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

@ -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);
}
@ -629,7 +663,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 +687,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() {
@ -113,8 +110,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 +151,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 +159,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;
@ -308,7 +308,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();

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

View file

@ -66,6 +66,11 @@ public:
void setCallback(std::function<void(int)> fn) { callback = std::bind(fn, std::placeholders::_1); }
};
struct ProcessData {
int processID = -1;
BOOL isOpened = FALSE;
};
static BOOL parseJSON(const CString& jsonTxt, Json::Value& jsonObject);
static ResponseError makeHTTPCall(const CString& callerName, const CString& mainUrl,
const CString& dirUrl, const CString& contentType,
@ -73,11 +78,14 @@ public:
static std::string cStringToStd(CString cstring);
static BOOL getFont(const CString& fontName, int fontSize, bool isBold, CFont& fontOut);
static BOOL launchApplication(LPCWSTR lpApplicationName, LPTSTR cmdArgs = _T(""));
static BOOL IsProcessRunning(const wchar_t *processName);
static BOOL CALLBACK isWindowOpenedCallback(HWND hWnd, LPARAM lparam);
static BOOL isProcessRunning(const wchar_t *processName, int& processID);
static BOOL isProcessWindowOpened(const wchar_t *processName);
static BOOL shutdownProcess(DWORD dwProcessId, UINT uExitCode);
static BOOL insertRegistryKey(const std::string& regPath, const std::string& name, const std::string& value);
static BOOL insertRegistryKey(const std::string& regPath, const std::string& name, DWORD value);
static BOOL deleteFileOrDirectory(const CString& dirPath, bool noRecycleBin = true);
static HRESULT CreateLink(LPCWSTR lpszPathObj, LPCSTR lpszPathLink, LPCWSTR lpszDesc, LPCWSTR lpszArgs = _T(""));
static HRESULT createLink(LPCWSTR lpszPathObj, LPCSTR lpszPathLink, LPCWSTR lpszDesc, LPCWSTR lpszArgs = _T(""));
static BOOL hMac256(const CString& message, const char* key, CString& hashOut);
static uint64_t extractZip(const std::string& zipFile, const std::string& path, std::vector<std::string>& files);
static BOOL deleteRegistryKey(const CString& registryPath);

View file

@ -280,6 +280,10 @@ AvatarSharedPointer AvatarHashMap::parseAvatarData(QSharedPointer<ReceivedMessag
return avatar;
} else {
// Shouldn't happen if mixer functioning correctly - debugging for BUGZ-781:
qCDebug(avatars) << "Discarding received avatar data" << sessionUUID << (sessionUUID == _lastOwnerSessionUUID ? "(is self)" : "")
<< "isIgnoringNode = " << nodeList->isIgnoringNode(sessionUUID);
// create a dummy AvatarData class to throw this data on the ground
AvatarData dummyData;
int bytesRead = dummyData.parseDataFromBuffer(byteArray);

View file

@ -69,6 +69,7 @@ public:
virtual PacketType getExpectedPacketType() const override { return PacketType::EntityData; }
// Returns the priority at which an entity should be loaded. Higher values indicate higher priority.
static CalculateEntityLoadingPriority getEntityLoadingPriorityOperator() { return _calculateEntityLoadingPriorityFunc; }
static float getEntityLoadingPriority(const EntityItem& item) { return _calculateEntityLoadingPriorityFunc(item); }
static void setEntityLoadingPriorityFunction(CalculateEntityLoadingPriority fn) { _calculateEntityLoadingPriorityFunc = fn; }

View file

@ -199,9 +199,8 @@ void ImageEntityRenderer::doRender(RenderArgs* args) {
float x = _keepAspectRatio ? fromImage.width() / (2.0f * maxSize) : 0.5f;
float y = _keepAspectRatio ? fromImage.height() / (2.0f * maxSize) : 0.5f;
glm::vec2 texCoordBottomLeft((fromImage.x() + 0.5f) / imageWidth, -(fromImage.y() + 0.5f) / imageHeight);
glm::vec2 texCoordTopRight((fromImage.x() + fromImage.width() - 0.5f) / imageWidth,
-(fromImage.y() + fromImage.height() - 0.5f) / imageHeight);
glm::vec2 texCoordBottomLeft((fromImage.x() + 0.5f) / imageWidth, (fromImage.y() + fromImage.height() - 0.5f) / imageHeight);
glm::vec2 texCoordTopRight((fromImage.x() + fromImage.width() - 0.5f) / imageWidth, (fromImage.y() + 0.5f) / imageHeight);
DependencyManager::get<GeometryCache>()->renderQuad(
*batch, glm::vec2(-x, -y), glm::vec2(x, y), texCoordBottomLeft, texCoordTopRight,

View file

@ -277,51 +277,60 @@ entities::TextPayload::~TextPayload() {
}
ItemKey entities::TextPayload::getKey() const {
auto renderable = DependencyManager::get<EntityTreeRenderer>()->renderableForEntityId(_entityID);
if (renderable) {
auto textRenderable = std::static_pointer_cast<TextEntityRenderer>(renderable);
ItemKey::Builder key;
// Similar to EntityRenderer::getKey()
if (textRenderable->isTextTransparent()) {
key = ItemKey::Builder::transparentShape().withSubMetaCulled().withTagBits(textRenderable->getTagMask()).withLayer(textRenderable->getHifiRenderLayer());
} else if (textRenderable->_canCastShadow) {
key = ItemKey::Builder::opaqueShape().withSubMetaCulled().withTagBits(textRenderable->getTagMask()).withShadowCaster().withLayer(textRenderable->getHifiRenderLayer());
} else {
key = ItemKey::Builder::opaqueShape().withSubMetaCulled().withTagBits(textRenderable->getTagMask()).withLayer(textRenderable->getHifiRenderLayer());
}
auto entityTreeRenderer = DependencyManager::get<EntityTreeRenderer>();
if (entityTreeRenderer) {
auto renderable = entityTreeRenderer->renderableForEntityId(_entityID);
if (renderable) {
auto textRenderable = std::static_pointer_cast<TextEntityRenderer>(renderable);
ItemKey::Builder key;
// Similar to EntityRenderer::getKey()
if (textRenderable->isTextTransparent()) {
key = ItemKey::Builder::transparentShape().withSubMetaCulled().withTagBits(textRenderable->getTagMask()).withLayer(textRenderable->getHifiRenderLayer());
} else if (textRenderable->_canCastShadow) {
key = ItemKey::Builder::opaqueShape().withSubMetaCulled().withTagBits(textRenderable->getTagMask()).withShadowCaster().withLayer(textRenderable->getHifiRenderLayer());
} else {
key = ItemKey::Builder::opaqueShape().withSubMetaCulled().withTagBits(textRenderable->getTagMask()).withLayer(textRenderable->getHifiRenderLayer());
}
if (!textRenderable->_visible) {
key.withInvisible();
if (!textRenderable->_visible) {
key.withInvisible();
}
return key;
}
return key;
}
return ItemKey::Builder::opaqueShape();
}
Item::Bound entities::TextPayload::getBound() const {
auto renderable = DependencyManager::get<EntityTreeRenderer>()->renderableForEntityId(_entityID);
if (renderable) {
return std::static_pointer_cast<TextEntityRenderer>(renderable)->getBound();
auto entityTreeRenderer = DependencyManager::get<EntityTreeRenderer>();
if (entityTreeRenderer) {
auto renderable = entityTreeRenderer->renderableForEntityId(_entityID);
if (renderable) {
return std::static_pointer_cast<TextEntityRenderer>(renderable)->getBound();
}
}
return Item::Bound();
}
ShapeKey entities::TextPayload::getShapeKey() const {
auto renderable = DependencyManager::get<EntityTreeRenderer>()->renderableForEntityId(_entityID);
if (renderable) {
auto textRenderable = std::static_pointer_cast<TextEntityRenderer>(renderable);
auto entityTreeRenderer = DependencyManager::get<EntityTreeRenderer>();
if (entityTreeRenderer) {
auto renderable = entityTreeRenderer->renderableForEntityId(_entityID);
if (renderable) {
auto textRenderable = std::static_pointer_cast<TextEntityRenderer>(renderable);
auto builder = render::ShapeKey::Builder().withOwnPipeline();
if (textRenderable->isTextTransparent()) {
builder.withTranslucent();
auto builder = render::ShapeKey::Builder().withOwnPipeline();
if (textRenderable->isTextTransparent()) {
builder.withTranslucent();
}
if (textRenderable->_unlit) {
builder.withUnlit();
}
if (textRenderable->_primitiveMode == PrimitiveMode::LINES) {
builder.withWireframe();
}
return builder.build();
}
if (textRenderable->_unlit) {
builder.withUnlit();
}
if (textRenderable->_primitiveMode == PrimitiveMode::LINES) {
builder.withWireframe();
}
return builder.build();
}
return ShapeKey::Builder::invalid();
}
@ -336,7 +345,11 @@ void entities::TextPayload::render(RenderArgs* args) {
return;
}
auto renderable = DependencyManager::get<EntityTreeRenderer>()->renderableForEntityId(_entityID);
auto entityTreeRenderer = DependencyManager::get<EntityTreeRenderer>();
if (!entityTreeRenderer) {
return;
}
auto renderable = entityTreeRenderer->renderableForEntityId(_entityID);
if (!renderable) {
return;
}

View file

@ -21,12 +21,15 @@ bool enumeratePlatform();
int getNumCPUs();
json getCPU(int index);
int getMasterCPU();
int getNumGPUs();
json getGPU(int index);
int getMasterGPU();
int getNumDisplays();
json getDisplay(int index);
int getMasterDisplay();
json getMemory();

View file

@ -20,6 +20,7 @@ namespace platform { namespace keys{
extern const char* model;
extern const char* clockSpeed;
extern const char* numCores;
extern const char* isMaster;
}
namespace gpu {
extern const char* vendor;
@ -30,6 +31,8 @@ namespace platform { namespace keys{
extern const char* model;
extern const char* videoMemory;
extern const char* driver;
extern const char* displays;
extern const char* isMaster;
}
namespace nic {
extern const char* mac;
@ -38,10 +41,19 @@ namespace platform { namespace keys{
namespace display {
extern const char* description;
extern const char* name;
extern const char* coordsLeft;
extern const char* coordsRight;
extern const char* coordsTop;
extern const char* coordsBottom;
extern const char* boundsLeft;
extern const char* boundsRight;
extern const char* boundsTop;
extern const char* boundsBottom;
extern const char* gpu;
extern const char* ppi;
extern const char* ppiDesktop;
extern const char* physicalWidth;
extern const char* physicalHeight;
extern const char* modeRefreshrate;
extern const char* modeWidth;
extern const char* modeHeight;
extern const char* isMaster;
}
namespace memory {
extern const char* memTotal;

View file

@ -32,9 +32,9 @@ Profiler::Tier Profiler::profilePlatform() {
return platformTier;
}
// Not filtered yet, let s try to make sense of the cpu and gpu info
auto cpuInfo = platform::getCPU(0);
auto gpuInfo = platform::getGPU(0);
// Not filtered yet, let s try to make sense of the master cpu and master gpu info
auto cpuInfo = platform::getCPU(platform::getMasterCPU());
auto gpuInfo = platform::getGPU(platform::getMasterGPU());
if (filterOnProcessors(computerInfo, cpuInfo, gpuInfo, platformTier)) {
return platformTier;
}
@ -133,10 +133,12 @@ bool filterOnProcessors(const platform::json& computer, const platform::json& cp
// YES on macos EXCEPT for macbookair with gpu intel iris or intel HD 6000
bool Profiler::isRenderMethodDeferredCapable() {
#if defined(Q_OS_MAC)
// Deferred works correctly on every supported macos platform at the moment, let s enable it
/*
auto computer = platform::getComputer();
const auto computerModel = (computer.count(keys::computer::model) ? computer[keys::computer::model].get<std::string>() : "");
auto gpuInfo = platform::getGPU(0);
auto gpuInfo = platform::getGPU(getMasterGPU());
const auto gpuModel = (gpuInfo.count(keys::gpu::model) ? gpuInfo[keys::gpu::model].get<std::string>() : "");
@ -154,7 +156,7 @@ bool Profiler::isRenderMethodDeferredCapable() {
if ((gpuModel.find("Intel ") != std::string::npos)) {
return false;
}
*/
return true;
#elif defined(Q_OS_ANDROID)
return false;

View file

@ -10,6 +10,7 @@
#include "../PlatformKeys.h"
#include <GPUIdent.h>
#include <QSysInfo>
#include <QtCore/QtGlobal>
using namespace platform;
@ -23,7 +24,7 @@ void AndroidInstance::enumerateCpus() {
_cpus.push_back(cpu);
}
void AndroidInstance::enumerateGpus() {
void AndroidInstance::enumerateGpusAndDisplays() {
GPUIdent* ident = GPUIdent::getInstance();
json gpu = {};
gpu[keys::gpu::model] = ident->getName().toUtf8().constData();

View file

@ -16,7 +16,7 @@ namespace platform {
public:
void enumerateCpus() override;
void enumerateGpus() override;
void enumerateGpusAndDisplays() override;
void enumerateMemory() override;
void enumerateComputer() override;
};

View file

@ -12,6 +12,9 @@
#include <thread>
#include <string>
#include <CPUIdent.h>
#include <QtCore/QtGlobal>
#include <GPUIdent.h>
#include <QSysInfo>
@ -27,7 +30,7 @@ void LinuxInstance::enumerateCpus() {
_cpus.push_back(cpu);
}
void LinuxInstance::enumerateGpus() {
void LinuxInstance::enumerateGpusAndDisplays() {
GPUIdent* ident = GPUIdent::getInstance();
json gpu = {};
gpu[keys::gpu::model] = ident->getName().toUtf8().constData();

View file

@ -16,7 +16,7 @@ namespace platform {
public:
void enumerateCpus() override;
void enumerateGpus() override;
void enumerateGpusAndDisplays() override;
void enumerateMemory() override;
void enumerateComputer() override;
};

View file

@ -12,16 +12,22 @@
#include <thread>
#include <string>
#include <CPUIdent.h>
#include <GPUIdent.h>
#include <QtCore/QtGlobal>
#ifdef Q_OS_MAC
#include <unistd.h>
#include <cpuid.h>
#include <sys/sysctl.h>
#include <sstream>
#include <regex>
#include <CoreFoundation/CoreFoundation.h>
#include <ApplicationServices/ApplicationServices.h>
#include <QSysInfo>
#include <QString>
#include <OpenGL/OpenGL.h>
#endif
using namespace platform;
@ -36,73 +42,249 @@ void MACOSInstance::enumerateCpus() {
_cpus.push_back(cpu);
}
void MACOSInstance::enumerateGpus() {
void MACOSInstance::enumerateGpusAndDisplays() {
#ifdef Q_OS_MAC
// ennumerate the displays first
std::vector<GLuint> displayMasks;
{
uint32_t numDisplays = 0;
CGError error = CGGetOnlineDisplayList(0, nullptr, &numDisplays);
if (numDisplays <= 0 || error != kCGErrorSuccess) {
return;
}
GPUIdent* ident = GPUIdent::getInstance();
json gpu = {};
std::vector<CGDirectDisplayID> onlineDisplayIDs(numDisplays, 0);
error = CGGetOnlineDisplayList(onlineDisplayIDs.size(), onlineDisplayIDs.data(), &numDisplays);
if (error != kCGErrorSuccess) {
return;
}
gpu[keys::gpu::model] = ident->getName().toUtf8().constData();
gpu[keys::gpu::vendor] = findGPUVendorInDescription(gpu[keys::gpu::model].get<std::string>());
gpu[keys::gpu::videoMemory] = ident->getMemory();
gpu[keys::gpu::driver] = ident->getDriver().toUtf8().constData();
_gpus.push_back(gpu);
for (auto displayID : onlineDisplayIDs) {
auto displaySize = CGDisplayScreenSize(displayID);
const auto MM_TO_IN = 0.0393701f;
auto displaySizeWidthInches = displaySize.width * MM_TO_IN;
auto displaySizeHeightInches = displaySize.height * MM_TO_IN;
auto displayBounds = CGDisplayBounds(displayID);
auto displayMaster =CGDisplayIsMain(displayID);
auto displayUnit =CGDisplayUnitNumber(displayID);
auto displayModel =CGDisplayModelNumber(displayID);
auto displayVendor = CGDisplayVendorNumber(displayID);
auto displaySerial = CGDisplaySerialNumber(displayID);
auto displayMode = CGDisplayCopyDisplayMode(displayID);
auto displayModeWidth = CGDisplayModeGetPixelWidth(displayMode);
auto displayModeHeight = CGDisplayModeGetPixelHeight(displayMode);
auto displayRefreshrate = CGDisplayModeGetRefreshRate(displayMode);
auto ppiH = displayModeWidth / displaySizeWidthInches;
auto ppiV = displayModeHeight / displaySizeHeightInches;
auto ppiHScaled = displayBounds.size.width / displaySizeWidthInches;
auto ppiVScaled = displayBounds.size.height / displaySizeHeightInches;
auto glmask = CGDisplayIDToOpenGLDisplayMask(displayID);
// Metal device ID is the recommended new way but requires objective c
// auto displayDevice = CGDirectDisplayCopyCurrentMetalDevice(displayID);
CGDisplayModeRelease(displayMode);
json display = {};
// Rect region of the desktop in desktop units
display[keys::display::boundsLeft] = displayBounds.origin.x;
display[keys::display::boundsRight] = displayBounds.origin.x + displayBounds.size.width;
display[keys::display::boundsTop] = displayBounds.origin.y;
display[keys::display::boundsBottom] = displayBounds.origin.y + displayBounds.size.height;
// PPI & resolution
display[keys::display::physicalWidth] = displaySizeWidthInches;
display[keys::display::physicalHeight] = displaySizeHeightInches;
display[keys::display::modeWidth] = displayModeWidth;
display[keys::display::modeHeight] = displayModeHeight;
//Average the ppiH and V for the simple ppi
display[keys::display::ppi] = std::round(0.5f * (ppiH + ppiV));
display[keys::display::ppiDesktop] = std::round(0.5f * (ppiHScaled + ppiVScaled));
// refreshrate
display[keys::display::modeRefreshrate] = displayRefreshrate;
// Master display ?
display[keys::display::isMaster] = (displayMaster ? true : false);
// Macos specific
display["macos_unit"] = displayUnit;
display["macos_vendor"] = displayVendor;
display["macos_model"] = displayModel;
display["macos_serial"] = displaySerial;
display["macos_glmask"] = glmask;
displayMasks.push_back(glmask);
_displays.push_back(display);
}
}
#endif
// Collect Renderer info as exposed by the CGL layers
GLuint cglDisplayMask = -1; // Iterate over all of them.
CGLRendererInfoObj rendererInfo;
GLint rendererInfoCount;
CGLError error = CGLQueryRendererInfo(cglDisplayMask, &rendererInfo, &rendererInfoCount);
if (rendererInfoCount <= 0 || 0 != error) {
return;
}
// Iterate over all of the renderers and use the figure for the one with the most VRAM,
// on the assumption that this is the one that will actually be used.
for (GLint i = 0; i < rendererInfoCount; i++) {
struct CGLRendererDesc {
int rendererID{0};
int deviceVRAM{0};
int accelerated{0};
int displayMask{0};
} desc;
CGLDescribeRenderer(rendererInfo, i, kCGLRPRendererID, &desc.rendererID);
CGLDescribeRenderer(rendererInfo, i, kCGLRPVideoMemoryMegabytes, &desc.deviceVRAM);
CGLDescribeRenderer(rendererInfo, i, kCGLRPDisplayMask, &desc.displayMask);
CGLDescribeRenderer(rendererInfo, i, kCGLRPAccelerated, &desc.accelerated);
// If this renderer is not hw accelerated then just skip it in the enumeration
if (!desc.accelerated) {
continue;
}
// From the rendererID identify the vendorID
// https://github.com/apitrace/apitrace/blob/master/retrace/glws_cocoa.mm
GLint vendorID = desc.rendererID & kCGLRendererIDMatchingMask & ~0xfff;
const GLint VENDOR_ID_SOFTWARE { 0x00020000 };
const GLint VENDOR_ID_AMD { 0x00021000 };
const GLint VENDOR_ID_NVIDIA { 0x00022000 };
const GLint VENDOR_ID_INTEL { 0x00024000 };
const char* vendorName;
switch (vendorID) {
case VENDOR_ID_SOFTWARE:
// Software renderer then skip it (should already have been caught by hwaccelerated test abve
continue;
break;
case VENDOR_ID_AMD:
vendorName = keys::gpu::vendor_AMD;
break;
case VENDOR_ID_NVIDIA:
vendorName = keys::gpu::vendor_NVIDIA;
break;
case VENDOR_ID_INTEL:
vendorName = keys::gpu::vendor_Intel;
break;
default:
vendorName = keys::UNKNOWN;
break;
}
//once we reach this point, the renderer is legit
// Start defining the gpu json
json gpu = {};
gpu[keys::gpu::vendor] = vendorName;
gpu[keys::gpu::videoMemory] = desc.deviceVRAM;
gpu["macos_rendererID"] = desc.rendererID;
gpu["macos_displayMask"] = desc.displayMask;
std::vector<int> displayIndices;
for (int d = 0; d < (int) displayMasks.size(); d++) {
if (desc.displayMask & displayMasks[d]) {
displayIndices.push_back(d);
_displays[d][keys::display::gpu] = _gpus.size();
}
}
gpu[keys::gpu::displays] = displayIndices;
_gpus.push_back(gpu);
}
CGLDestroyRendererInfo(rendererInfo);
{ //get gpu information from the system profiler that we don't know how to retreive otherwise
struct ChipsetModelDesc {
std::string model;
std::string vendor;
int deviceID{0};
int videoMemory{0};
};
std::vector<ChipsetModelDesc> chipsetDescs;
FILE* stream = popen("system_profiler SPDisplaysDataType | grep -e Chipset -e VRAM -e Vendor -e \"Device ID\"", "r");
std::ostringstream hostStream;
while (!feof(stream) && !ferror(stream)) {
char buf[128];
int bytesRead = fread(buf, 1, 128, stream);
hostStream.write(buf, bytesRead);
}
std::string gpuArrayDesc = hostStream.str();
// Find the Chipset model first
const std::regex chipsetModelToken("(Chipset Model: )(.*)");
std::smatch found;
while (std::regex_search(gpuArrayDesc, found, chipsetModelToken)) {
ChipsetModelDesc desc;
}
void MACOSInstance::enumerateDisplays() {
#ifdef Q_OS_MAC
auto displayID = CGMainDisplayID();
auto displaySize = CGDisplayScreenSize(displayID);
const auto MM_TO_IN = 0.0393701;
auto displaySizeWidthInches = displaySize.width * MM_TO_IN;
auto displaySizeHeightInches = displaySize.height * MM_TO_IN;
auto displaySizeDiagonalInches = sqrt(displaySizeWidthInches * displaySizeWidthInches + displaySizeHeightInches * displaySizeHeightInches);
desc.model = found.str(2);
// Find the end of the gpu block
gpuArrayDesc = found.suffix();
std::string gpuDesc = gpuArrayDesc;
const std::regex endGpuToken("Chipset Model: ");
if (std::regex_search(gpuArrayDesc, found, endGpuToken)) {
gpuDesc = found.prefix();
}
// Find the vendor
desc.vendor = findGPUVendorInDescription(desc.model);
// Find the memory amount in MB
const std::regex memoryToken("(VRAM .*: )(.*)");
if (std::regex_search(gpuDesc, found, memoryToken)) {
auto memAmountUnit = found.str(2);
std::smatch amount;
const std::regex memAmountGBToken("(\\d*) GB");
const std::regex memAmountMBToken("(\\d*) MB");
const int GB_TO_MB { 1024 };
if (std::regex_search(memAmountUnit, amount, memAmountGBToken)) {
desc.videoMemory = std::stoi(amount.str(1)) * GB_TO_MB;
} else if (std::regex_search(memAmountUnit, amount, memAmountMBToken)) {
desc.videoMemory = std::stoi(amount.str(1));
} else {
desc.videoMemory = std::stoi(memAmountUnit);
}
}
// Find the Device ID
const std::regex deviceIDToken("(Device ID: )(.*)");
if (std::regex_search(gpuDesc, found, deviceIDToken)) {
desc.deviceID = std::stoi(found.str(2), 0, 16);
}
chipsetDescs.push_back(desc);
}
// GO through the detected gpus in order and complete missing information from ChipsetModelDescs
// assuming the order is the same and checking that the vendor and memory amount match as a simple check
auto numDescs = (int) std::min(chipsetDescs.size(),_gpus.size());
for (int i = 0; i < numDescs; ++i) {
const auto& chipset = chipsetDescs[i];
auto& gpu = _gpus[i];
if ( (chipset.vendor.find( gpu[keys::gpu::vendor]) != std::string::npos)
&& (chipset.videoMemory == gpu[keys::gpu::videoMemory]) ) {
gpu[keys::gpu::model] = chipset.model;
gpu["macos_deviceID"] = chipset.deviceID;
}
}
}
auto displayBounds = CGDisplayBounds(displayID);
auto displayMaster =CGDisplayIsMain(displayID);
auto displayUnit =CGDisplayUnitNumber(displayID);
auto displayModel =CGDisplayModelNumber(displayID);
auto displayVendor = CGDisplayVendorNumber(displayID);
auto displaySerial = CGDisplaySerialNumber(displayID);
auto displayMode = CGDisplayCopyDisplayMode(displayID);
auto displayModeWidth = CGDisplayModeGetPixelWidth(displayMode);
auto displayModeHeight = CGDisplayModeGetPixelHeight(displayMode);
auto displayRefreshrate = CGDisplayModeGetRefreshRate(displayMode);
CGDisplayModeRelease(displayMode);
json display = {};
display["physicalWidth"] = displaySizeWidthInches;
display["physicalHeight"] = displaySizeHeightInches;
display["physicalDiagonal"] = displaySizeDiagonalInches;
display["ppi"] = sqrt(displayModeHeight * displayModeHeight + displayModeWidth * displayModeWidth) / displaySizeDiagonalInches;
display["coordLeft"] = displayBounds.origin.x;
display["coordRight"] = displayBounds.origin.x + displayBounds.size.width;
display["coordTop"] = displayBounds.origin.y;
display["coordBottom"] = displayBounds.origin.y + displayBounds.size.height;
display["isMaster"] = displayMaster;
display["unit"] = displayUnit;
display["vendor"] = displayVendor;
display["model"] = displayModel;
display["serial"] = displaySerial;
display["refreshrate"] =displayRefreshrate;
display["modeWidth"] = displayModeWidth;
display["modeHeight"] = displayModeHeight;
_displays.push_back(display);
#endif
}
@ -132,11 +314,11 @@ void MACOSInstance::enumerateComputer(){
_computer[keys::computer::model]=std::string(model);
free(model);
#endif
auto sysInfo = QSysInfo();
_computer[keys::computer::OSVersion] = sysInfo.kernelVersion().toStdString();
#endif
}

View file

@ -16,8 +16,7 @@ namespace platform {
public:
void enumerateCpus() override;
void enumerateGpus() override;
void enumerateDisplays() override;
void enumerateGpusAndDisplays() override;
void enumerateMemory() override;
void enumerateComputer() override;
};

View file

@ -21,7 +21,8 @@ namespace platform { namespace keys {
const char* model = "model";
const char* clockSpeed = "clockSpeed";
const char* numCores = "numCores";
}
const char* isMaster = "isMaster";
}
namespace gpu {
const char* vendor = "vendor";
const char* vendor_NVIDIA = "NVIDIA";
@ -31,6 +32,8 @@ namespace platform { namespace keys {
const char* model = "model";
const char* videoMemory = "videoMemory";
const char* driver = "driver";
const char* displays = "displays";
const char* isMaster = "isMaster";
}
namespace nic {
const char* mac = "mac";
@ -39,10 +42,19 @@ namespace platform { namespace keys {
namespace display {
const char* description = "description";
const char* name = "deviceName";
const char* coordsLeft = "coordinatesleft";
const char* coordsRight = "coordinatesright";
const char* coordsTop = "coordinatestop";
const char* coordsBottom = "coordinatesbottom";
const char* boundsLeft = "boundsLeft";
const char* boundsRight = "boundsRight";
const char* boundsTop = "boundsTop";
const char* boundsBottom = "boundsBottom";
const char* gpu = "gpu";
const char* ppi = "ppi";
const char* ppiDesktop = "ppiDesktop";
const char* physicalWidth = "physicalWidth";
const char* physicalHeight = "physicalHeight";
const char* modeRefreshrate = "modeRefreshrate";
const char* modeWidth = "modeWidth";
const char* modeHeight = "modeHeight";
const char* isMaster = "isMaster";
}
namespace memory {
const char* memTotal = "memTotal";
@ -117,6 +129,10 @@ json platform::getCPU(int index) {
return _instance->getCPU(index);
}
int platform::getMasterCPU() {
return _instance->getMasterCPU();
}
int platform::getNumGPUs() {
return _instance->getNumGPUs();
}
@ -125,6 +141,10 @@ json platform::getGPU(int index) {
return _instance->getGPU(index);
}
int platform::getMasterGPU() {
return _instance->getMasterGPU();
}
int platform::getNumDisplays() {
return _instance->getNumDisplays();
}
@ -133,6 +153,10 @@ json platform::getDisplay(int index) {
return _instance->getDisplay(index);
}
int platform::getMasterDisplay() {
return _instance->getMasterDisplay();
}
json platform::getMemory() {
return _instance->getMemory();
}

View file

@ -16,18 +16,83 @@
using namespace platform;
bool Instance::enumeratePlatform() {
//clear all knowledge
_computer.clear();
_memory.clear();
_cpus.clear();
_gpus.clear();
_displays.clear();
_nics.clear();
// enumerate platform components
enumerateComputer();
enumerateMemory();
enumerateCpus();
enumerateGpus();
enumerateDisplays();
enumerateGpusAndDisplays();
enumerateNics();
// eval the master index for each platform scopes
updateMasterIndices();
// And profile the platform and put the tier in "computer"
_computer[keys::computer::profileTier] = Profiler::TierNames[Profiler::profilePlatform()];
return true;
}
void Instance::updateMasterIndices() {
// We assume a single CPU at the moment:
{
if (!_cpus.empty()) {
_masterCPU = 0;
_cpus[0][keys::cpu::isMaster] = true;
} else {
_masterCPU = NOT_FOUND;
}
}
// Go through the displays list
{
_masterDisplay = NOT_FOUND;
for (int i = 0; i < (int) _displays.size(); ++i) {
const auto& display = _displays[i];
if (display.count(keys::display::isMaster)) {
if (display[keys::display::isMaster].get<bool>()) {
_masterDisplay = i;
break;
}
}
}
// NO master display found, return the first one or NOT_FOUND if no display
if (_masterDisplay == NOT_FOUND) {
if (!_displays.empty()) {
_masterDisplay = 0;
_displays[0][keys::display::isMaster] = true;
}
}
}
// From the master display decide the master gpu
{
_masterGPU = NOT_FOUND;
if (_masterDisplay != NOT_FOUND) {
const auto& display = _displays[_masterDisplay];
// FInd the GPU index of the master display
if (display.count(keys::display::gpu)) {
_masterGPU = display[keys::display::gpu];
_gpus[_masterGPU][keys::gpu::isMaster] = true;
}
}
// NO master GPU found from master display, bummer, return the first one or NOT_FOUND if no display
if (_masterGPU == NOT_FOUND) {
if (!_gpus.empty()) {
_masterGPU = 0;
_gpus[0][keys::gpu::isMaster] = true;
}
}
}
}
void Instance::enumerateNics() {
QNetworkInterface interface;
foreach(interface, interface.allInterfaces()) {
@ -57,6 +122,7 @@ json Instance::getGPU(int index) {
return _gpus.at(index);
}
json Instance::getDisplay(int index) {
assert(index <(int) _displays.size());
@ -98,13 +164,13 @@ json Instance::listAllKeys() {
keys::gpu::model,
keys::gpu::videoMemory,
keys::gpu::driver,
keys::gpu::displays,
keys::display::description,
keys::display::name,
keys::display::coordsLeft,
keys::display::coordsRight,
keys::display::coordsTop,
keys::display::coordsBottom,
keys::display::boundsLeft,
keys::display::boundsRight,
keys::display::boundsTop,
keys::display::boundsBottom,
keys::display::gpu,
keys::memory::memTotal,

View file

@ -17,16 +17,21 @@ namespace platform {
class Instance {
public:
const int NOT_FOUND { -1 };
bool virtual enumeratePlatform();
int getNumCPUs() { return (int)_cpus.size(); }
json getCPU(int index);
int getMasterCPU() const { return _masterCPU; }
int getNumGPUs() { return (int)_gpus.size(); }
json getGPU(int index);
int getMasterGPU() const { return _masterGPU; }
int getNumDisplays() { return (int)_displays.size(); }
json getDisplay(int index);
int getMasterDisplay() const { return _masterDisplay; }
json getMemory() { return _memory; }
@ -35,8 +40,7 @@ public:
json getAll();
void virtual enumerateCpus()=0;
void virtual enumerateGpus()=0;
void virtual enumerateDisplays() {}
void virtual enumerateGpusAndDisplays()=0;
void virtual enumerateNics();
void virtual enumerateMemory() = 0;
void virtual enumerateComputer()=0;
@ -55,6 +59,14 @@ protected:
std::vector<json> _nics;
json _memory;
json _computer;
int _masterCPU{ -1 };
int _masterGPU{ -1 };
int _masterDisplay{ -1 };
// Traverse the cpus, gpus and displays to update the "master" index in each domain
void updateMasterIndices();
};
} // namespace platform

View file

@ -11,21 +11,31 @@
#include <thread>
#include <string>
#include <CPUIdent.h>
#include <GPUIdent.h>
#include <QtCore/QtGlobal>
#ifdef Q_OS_WIN
#include <sstream>
#include <qstring>
#include <qsysinfo>
#include <Windows.h>
#include <iphlpapi.h>
#include <stdio.h>
#include <QSysInfo>
#include <dxgi1_3.h>
#pragma comment(lib, "dxgi.lib")
#include <shellscalingapi.h>
#pragma comment(lib, "Shcore.lib")
#endif
using namespace platform;
void WINInstance::enumerateCpus() {
json cpu = {};
cpu[keys::cpu::vendor] = CPUIdent::Vendor();
cpu[keys::cpu::model] = CPUIdent::Brand();
cpu[keys::cpu::numCores] = std::thread::hardware_concurrency();
@ -33,23 +43,153 @@ void WINInstance::enumerateCpus() {
_cpus.push_back(cpu);
}
void WINInstance::enumerateGpus() {
void WINInstance::enumerateGpusAndDisplays() {
#ifdef Q_OS_WIN
struct ConvertLargeIntegerToString {
std::string convert(const LARGE_INTEGER& version) {
std::ostringstream value;
value << uint32_t(((version.HighPart & 0xFFFF0000) >> 16) & 0x0000FFFF);
value << ".";
value << uint32_t((version.HighPart) & 0x0000FFFF);
value << ".";
value << uint32_t(((version.LowPart & 0xFFFF0000) >> 16) & 0x0000FFFF);
value << ".";
value << uint32_t((version.LowPart) & 0x0000FFFF);
return value.str();
}
} convertDriverVersionToString;
GPUIdent* ident = GPUIdent::getInstance();
json gpu = {};
gpu[keys::gpu::model] = ident->getName().toUtf8().constData();
gpu[keys::gpu::vendor] = findGPUVendorInDescription(gpu[keys::gpu::model].get<std::string>());
gpu[keys::gpu::videoMemory] = ident->getMemory();
gpu[keys::gpu::driver] = ident->getDriver().toUtf8().constData();
// Create the DXGI factory
// Let s get into DXGI land:
HRESULT hr = S_OK;
_gpus.push_back(gpu);
_displays = ident->getOutput();
IDXGIFactory1* pFactory = nullptr;
hr = CreateDXGIFactory1(__uuidof(IDXGIFactory1), (void**)(&pFactory));
if (hr != S_OK || pFactory == nullptr) {
return;
}
std::vector<int> validAdapterList;
using AdapterEntry = std::pair<std::pair<DXGI_ADAPTER_DESC1, LARGE_INTEGER>, std::vector<DXGI_OUTPUT_DESC>>;
std::vector<AdapterEntry> adapterToOutputs;
// Enumerate adapters and outputs
{
UINT adapterNum = 0;
IDXGIAdapter1* pAdapter = nullptr;
while (pFactory->EnumAdapters1(adapterNum, &pAdapter) != DXGI_ERROR_NOT_FOUND) {
// Found an adapter, get descriptor
DXGI_ADAPTER_DESC1 adapterDesc;
pAdapter->GetDesc1(&adapterDesc);
// Only describe gpu if it is a hardware adapter
if (!(adapterDesc.Flags & DXGI_ADAPTER_FLAG_SOFTWARE)) {
LARGE_INTEGER version;
hr = pAdapter->CheckInterfaceSupport(__uuidof(IDXGIDevice), &version);
std::wstring wDescription(adapterDesc.Description);
std::string description(wDescription.begin(), wDescription.end());
json gpu = {};
gpu[keys::gpu::model] = description;
gpu[keys::gpu::vendor] = findGPUVendorInDescription(gpu[keys::gpu::model].get<std::string>());
const SIZE_T BYTES_PER_MEGABYTE = 1024 * 1024;
gpu[keys::gpu::videoMemory] = (uint32_t)(adapterDesc.DedicatedVideoMemory / BYTES_PER_MEGABYTE);
gpu[keys::gpu::driver] = convertDriverVersionToString.convert(version);
std::vector<int> displayIndices;
UINT outputNum = 0;
IDXGIOutput* pOutput;
bool hasOutputConnectedToDesktop = false;
while (pAdapter->EnumOutputs(outputNum, &pOutput) != DXGI_ERROR_NOT_FOUND) {
// FOund an output attached to the adapter, get descriptor
DXGI_OUTPUT_DESC outputDesc;
pOutput->GetDesc(&outputDesc);
pOutput->Release();
outputNum++;
// Grab the monitor info
MONITORINFO monitorInfo;
monitorInfo.cbSize = sizeof(MONITORINFO);
GetMonitorInfo(outputDesc.Monitor, &monitorInfo);
// Grab the dpi info for the monitor
UINT dpiX{ 0 };
UINT dpiY{ 0 };
GetDpiForMonitor(outputDesc.Monitor, MDT_RAW_DPI, &dpiX, &dpiY);
UINT dpiXScaled{ 0 };
UINT dpiYScaled{ 0 };
GetDpiForMonitor(outputDesc.Monitor, MDT_EFFECTIVE_DPI, &dpiXScaled, &dpiYScaled);
// Current display mode
DEVMODEW devMode;
devMode.dmSize = sizeof(DEVMODEW);
EnumDisplaySettingsW(outputDesc.DeviceName, ENUM_CURRENT_SETTINGS, &devMode);
auto physicalWidth = devMode.dmPelsWidth / (float)dpiX;
auto physicalHeight = devMode.dmPelsHeight / (float)dpiY;
json display = {};
// Display name
std::wstring wDeviceName(outputDesc.DeviceName);
std::string deviceName(wDeviceName.begin(), wDeviceName.end());
display[keys::display::name] = deviceName;
display[keys::display::description] = "";
// Rect region of the desktop in desktop units
//display["desktopRect"] = (outputDesc.AttachedToDesktop ? true : false);
display[keys::display::boundsLeft] = outputDesc.DesktopCoordinates.left;
display[keys::display::boundsRight] = outputDesc.DesktopCoordinates.right;
display[keys::display::boundsBottom] = outputDesc.DesktopCoordinates.bottom;
display[keys::display::boundsTop] = outputDesc.DesktopCoordinates.top;
// PPI & resolution
display[keys::display::physicalWidth] = physicalWidth;
display[keys::display::physicalHeight] = physicalHeight;
display[keys::display::modeWidth] = devMode.dmPelsWidth;
display[keys::display::modeHeight] = devMode.dmPelsHeight;
//Average the ppiH and V for the simple ppi
display[keys::display::ppi] = std::round(0.5f * (dpiX + dpiY));
display[keys::display::ppiDesktop] = std::round(0.5f * (dpiXScaled + dpiYScaled));
// refreshrate
display[keys::display::modeRefreshrate] = devMode.dmDisplayFrequency;;
// Master display ?
display[keys::display::isMaster] = (bool) (monitorInfo.dwFlags & MONITORINFOF_PRIMARY);
// Add the display index to the list of displays of the gpu
displayIndices.push_back((int) _displays.size());
// And set the gpu index to the display description
display[keys::display::gpu] = (int) _gpus.size();
// WIN specific
// One more display desc
_displays.push_back(display);
}
gpu[keys::gpu::displays] = displayIndices;
_gpus.push_back(gpu);
}
pAdapter->Release();
adapterNum++;
}
}
pFactory->Release();
#endif
}
void WINInstance::enumerateMemory() {
json ram = {};
#ifdef Q_OS_WIN
MEMORYSTATUSEX statex;
statex.dwLength = sizeof(statex);
@ -60,16 +200,18 @@ void WINInstance::enumerateMemory() {
_memory = ram;
}
void WINInstance::enumerateComputer(){
void WINInstance::enumerateComputer() {
_computer[keys::computer::OS] = keys::computer::OS_WINDOWS;
_computer[keys::computer::vendor] = "";
_computer[keys::computer::model] = "";
auto sysInfo = QSysInfo();
#ifdef Q_OS_WIN
auto sysInfo = QSysInfo();
_computer[keys::computer::OSVersion] = sysInfo.kernelVersion().toStdString();
#endif
}
void WINInstance::enumerateNics() {
// Start with the default from QT, getting the result into _nics:
Instance::enumerateNics();
@ -78,23 +220,23 @@ void WINInstance::enumerateNics() {
// We can usually do better than the QNetworkInterface::humanReadableName() by
// matching up Iphlpapi.lib IP_ADAPTER_INFO by mac id.
ULONG buflen = sizeof(IP_ADAPTER_INFO);
IP_ADAPTER_INFO* pAdapterInfo = (IP_ADAPTER_INFO*) malloc(buflen);
IP_ADAPTER_INFO* pAdapterInfo = (IP_ADAPTER_INFO*)malloc(buflen);
// Size the buffer:
if (GetAdaptersInfo(pAdapterInfo, &buflen) == ERROR_BUFFER_OVERFLOW) {
free(pAdapterInfo);
pAdapterInfo = (IP_ADAPTER_INFO *) malloc(buflen);
pAdapterInfo = (IP_ADAPTER_INFO*)malloc(buflen);
}
// Now get the data...
if (GetAdaptersInfo(pAdapterInfo, &buflen) == NO_ERROR) {
for (json& nic : _nics) { // ... loop through the nics from above...
for (json& nic : _nics) { // ... loop through the nics from above...
// ...convert the json to a string without the colons...
QString qtmac = nic[keys::nic::mac].get<std::string>().c_str();
QString qtraw = qtmac.remove(QChar(':'), Qt::CaseInsensitive).toLower();
// ... and find the matching one in pAdapter:
for (IP_ADAPTER_INFO* pAdapter = pAdapterInfo; pAdapter; pAdapter = pAdapter->Next) {
QByteArray wmac = QByteArray((const char*) (pAdapter->Address), pAdapter->AddressLength);
QByteArray wmac = QByteArray((const char*)(pAdapter->Address), pAdapter->AddressLength);
QString wraw = wmac.toHex();
if (qtraw == wraw) {
nic[keys::nic::name] = pAdapter->Description;
@ -108,4 +250,4 @@ void WINInstance::enumerateNics() {
free(pAdapterInfo);
}
#endif
}
}

View file

@ -16,7 +16,7 @@ namespace platform {
public:
void enumerateCpus() override;
void enumerateGpus() override;
void enumerateGpusAndDisplays() override;
void enumerateMemory() override;
void enumerateComputer () override;
void enumerateNics() override;

View file

@ -86,19 +86,30 @@ PropFolderPanel {
var itemLabel = proItem.property;
var itemDepth = root.indentDepth + 1;
if (Array.isArray(itemRootObject)) {
if (objectItem.length > 1) {
itemLabel = itemLabel + " " + objectItem.length
itemLabel = proItem.property + "[] / " + itemRootObject.length
if (itemRootObject.length == 0) {
var component = Qt.createComponent("PropItem.qml");
component.createObject(propItemsContainer, {
"label": itemLabel
})
} else {
itemLabel = itemLabel + " " + objectItem.length
itemRootObject = itemRootObject[0];
var component = Qt.createComponent("PropGroup.qml");
component.createObject(propItemsContainer, {
"label": itemLabel,
"rootObject":itemRootObject,
"indentDepth": itemDepth,
"isUnfold": true,
})
}
} else {
var component = Qt.createComponent("PropGroup.qml");
component.createObject(propItemsContainer, {
"label": itemLabel,
"rootObject":itemRootObject,
"indentDepth": itemDepth,
"isUnfold": true,
})
}
var component = Qt.createComponent("PropGroup.qml");
component.createObject(propItemsContainer, {
"label": itemLabel,
"rootObject":itemRootObject,
"indentDepth": itemDepth,
})
} break;
case 'printLabel': {
var component = Qt.createComponent("PropItem.qml");
@ -125,12 +136,6 @@ PropFolderPanel {
function populateFromObjectProps(object) {
var propsModel = []
if (Array.isArray(object)) {
if (object.length <= 1) {
object = object[0];
}
}
var props = Object.keys(object);
for (var p in props) {
var o = {};

View file

@ -51,6 +51,7 @@ Rectangle {
}
Prop.PropFolderPanel {
label: "Platform"
isUnfold: true
panelFrameData: Component {
Platform {
}

View file

@ -483,6 +483,25 @@ function maybeUpdateOutputDeviceMutedOverlay() {
}
var oldAutomaticLODAdjust;
var oldLODLevel;
var DEFAULT_AUTO_LOD_ADJUST = false;
var DEFAULT_LOD_LEVEL = 0.5;
function modifyLODSettings() {
oldAutomaticLODAdjust = LODManager.automaticLODAdjust;
oldLODLevel = LODManager.lodQualityLevel;
LODManager.automaticLODAdjust = DEFAULT_AUTO_LOD_ADJUST;
LODManager.lodQualityLevel = DEFAULT_LOD_LEVEL;
}
function restoreLODSettings() {
LODManager.automaticLODAdjust = oldAutomaticLODAdjust;
LODManager.lodQualityLevel = oldLODLevel;
}
var simplifiedNametag = Script.require("./simplifiedNametag/simplifiedNametag.js?" + Date.now());
var SimplifiedStatusIndicator = Script.require("./simplifiedStatusIndicator/simplifiedStatusIndicator.js?" + Date.now());
var si;
@ -491,6 +510,7 @@ var oldShowBubbleTools;
var keepExistingUIAndScriptsSetting = Settings.getValue("simplifiedUI/keepExistingUIAndScripts", false);
function startup() {
maybeRemoveDesktopMenu();
modifyLODSettings();
if (!keepExistingUIAndScriptsSetting) {
pauseCurrentScripts();
@ -541,6 +561,7 @@ function restoreScripts() {
function shutdown() {
restoreScripts();
restoreLODSettings();
if (!keepExistingUIAndScriptsSetting) {
console.log("The Simplified UI script has been shut down. If you notice any strangeness with user interface, please restart this application.");

View file

@ -1,6 +1,6 @@
WebView {
id: entityListToolWebView
url: QT.resolvedURL("../html/entityList.html")
url: Qt.resolvedUrl("../html/entityList.html")
enabled: true
blurOnCtrlShift: false
}

View file

@ -247,7 +247,7 @@ TabBar {
property Component visualItem: Component {
WebView {
id: entityPropertiesWebView
url: Qt.resolvedURL("../entityProperties/html/entityProperties.html")
url: Qt.resolvedUrl("../entityProperties/html/entityProperties.html")
enabled: true
blurOnCtrlShift: false
}
@ -263,7 +263,7 @@ TabBar {
property Component visualItem: Component {
WebView {
id: gridControlsWebView
url: Qt.resolvedURL("../../html/gridControls.html")
url: Qt.resolvedUrl("../../html/gridControls.html")
enabled: true
blurOnCtrlShift: false
}

View file

@ -66,7 +66,6 @@ def getExtensionsHeader(dialect, variant, extensions):
extensionsHeaderMutex.release()
return extensionHeader
def getDialectAndVariantHeaders(dialect, variant, extensions=None):
result = []
headerPath = args.source_dir + '/libraries/shaders/headers/'
@ -80,6 +79,14 @@ def getDialectAndVariantHeaders(dialect, variant, extensions=None):
result.append(variantHeader)
return result
def getDefines(defines):
definesList = []
if defines:
definesSplit = defines.split("_")
for define in definesSplit:
definesList.append('HIFI_USE_{} 1'.format(define.upper()))
return definesList
class ScribeDependenciesCache:
cache = {}
lock = Lock()
@ -99,9 +106,9 @@ class ScribeDependenciesCache:
with open(self.filename, "w") as f:
f.write(json.dumps(self.cache))
def get(self, scribefile, dialect, variant):
def get(self, scribefile, dialect, variant, defines):
self.lock.acquire()
key = self.key(scribefile, dialect, variant)
key = self.key(scribefile, dialect, variant, defines)
try:
if key in self.cache:
return self.cache[key].copy()
@ -109,25 +116,26 @@ class ScribeDependenciesCache:
self.lock.release()
return None
def key(self, scribeFile, dialect, variant):
return ':'.join([scribeFile, dialect, variant])
def key(self, scribeFile, dialect, variant, defines):
return ':'.join([scribeFile, dialect, variant, defines])
def getOrGen(self, scribefile, includeLibs, dialect, variant):
result = self.get(scribefile, dialect, variant)
if (None == result):
result = self.gen(scribefile, includeLibs, dialect, variant)
def getOrGen(self, scribefile, includeLibs, dialect, variant, defines):
result = self.get(scribefile, dialect, variant, defines)
if result is None:
result = self.gen(scribefile, includeLibs, dialect, variant, defines)
return result
def gen(self, scribefile, includeLibs, dialect, variant):
def gen(self, scribefile, includeLibs, dialect, variant, defines):
scribeArgs = getCommonScribeArgs(scribefile, includeLibs)
scribeArgs.extend(['-M'])
processResult = subprocess.run(scribeArgs, stdout=subprocess.PIPE)
if (0 != processResult.returncode):
raise RuntimeError("Unable to parse scribe dependencies")
raise RuntimeError("Unable to parse scribe dependencies for file {} with defines: {}".format(scribefile, defines))
result = processResult.stdout.decode("utf-8").splitlines(False)
result.append(scribefile)
result.extend(getDialectAndVariantHeaders(dialect, variant))
key = self.key(scribefile, dialect, variant)
result.extend(getDefines(defines))
key = self.key(scribefile, dialect, variant, defines)
self.lock.acquire()
self.cache[key] = result.copy()
self.lock.release()
@ -166,6 +174,10 @@ def processCommand(line):
variant = params.pop(0)
scribeFile = args.source_dir + '/' + params.pop(0)
unoptGlslFile = args.source_dir + '/' + params.pop(0)
defines = ""
if len(params) > 1 and params[0].startswith("defines:"):
defines = params.pop(0)
defines = defines[len("defines:"):]
libs = params
upoptSpirvFile = unoptGlslFile + '.spv'
@ -184,19 +196,23 @@ def processCommand(line):
os.makedirs(scribeOutputDir)
folderMutex.release()
scribeDeps = scribeDepCache.getOrGen(scribeFile, libs, dialect, variant)
scribeDeps = scribeDepCache.getOrGen(scribeFile, libs, dialect, variant, defines)
# if the scribe sources (slv, slf, slh, etc), or the dialect/ variant headers are out of date
# regenerate the scribe GLSL output
if args.force or outOfDate(scribeDeps, outputFiles):
print('Processing file {} dialect {} variant {}'.format(scribeFile, dialect, variant))
print('Processing file {} dialect {} variant {} defines {}'.format(scribeFile, dialect, variant, defines))
if args.dry_run:
return True
scribeDepCache.gen(scribeFile, libs, dialect, variant)
scribeDepCache.gen(scribeFile, libs, dialect, variant, defines)
scribeArgs = getCommonScribeArgs(scribeFile, libs)
for header in getDialectAndVariantHeaders(dialect, variant, args.extensions):
scribeArgs.extend(['-H', header])
for define in getDefines(defines):
defineArgs = ['-D']
defineArgs.extend(define.split(' '))
scribeArgs.extend(defineArgs)
scribeArgs.extend(['-o', unoptGlslFile])
executeSubprocess(scribeArgs)