diff --git a/assignment-client/src/avatars/AvatarMixerSlave.cpp b/assignment-client/src/avatars/AvatarMixerSlave.cpp index 64f4aa6821..d874100ca2 100644 --- a/assignment-client/src/avatars/AvatarMixerSlave.cpp +++ b/assignment-client/src/avatars/AvatarMixerSlave.cpp @@ -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 diff --git a/cmake/macros/AutoScribeShader.cmake b/cmake/macros/AutoScribeShader.cmake index c5bb2b4054..f5a497962c 100755 --- a/cmake/macros/AutoScribeShader.cmake +++ b/cmake/macros/AutoScribeShader.cmake @@ -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 diff --git a/domain-server/src/DomainGatekeeper.cpp b/domain-server/src/DomainGatekeeper.cpp index 6aaa348f6c..09a0446468 100644 --- a/domain-server/src/DomainGatekeeper.cpp +++ b/domain-server/src/DomainGatekeeper.cpp @@ -121,12 +121,13 @@ void DomainGatekeeper::processConnectRequestPacket(QSharedPointersetNodeInterestSet(safeInterestSet); nodeData->setPlaceName(nodeConnection.placeName); + QMetaEnum metaEnum = QMetaEnum::fromType(); qDebug() << "Allowed connection from node" << uuidStringWithoutCurlyBraces(node->getUUID()) << "on" << message->getSenderSockAddr() << "with MAC" << nodeConnection.hardwareAddress << "and machine fingerprint" << nodeConnection.machineFingerprint << "user" << username - << "reason" << QString(nodeConnection.connectReason ? "SilentDomainDisconnect" : "Connect") + << "reason" << QString(metaEnum.valueToKey(nodeConnection.connectReason)) << "previous connection uptime" << nodeConnection.previousConnectionUpTime/USECS_PER_MSEC << "msec" << "sysinfo" << nodeConnection.SystemInfo; diff --git a/domain-server/src/DomainServer.cpp b/domain-server/src/DomainServer.cpp index c3a4a94c7c..b7c723ab48 100644 --- a/domain-server/src/DomainServer.cpp +++ b/domain-server/src/DomainServer.cpp @@ -2498,7 +2498,7 @@ bool DomainServer::handleHTTPRequest(HTTPConnection* connection, const QUrl& url return true; } else if (allNodesDeleteRegex.indexIn(url.path()) != -1) { qDebug() << "Received request to kill all nodes."; - nodeList->eraseAllNodes(); + nodeList->eraseAllNodes(url.path()); return true; } diff --git a/interface/resources/avatar/animations/fly.fbx b/interface/resources/avatar/animations/fly.fbx index 4a855032f9..5d8fcce23b 100644 Binary files a/interface/resources/avatar/animations/fly.fbx and b/interface/resources/avatar/animations/fly.fbx differ diff --git a/interface/resources/avatar/animations/idle.fbx b/interface/resources/avatar/animations/idle.fbx index 88c79185a1..a2cbb9b43b 100644 Binary files a/interface/resources/avatar/animations/idle.fbx and b/interface/resources/avatar/animations/idle.fbx differ diff --git a/interface/resources/avatar/animations/idle02.fbx b/interface/resources/avatar/animations/idle02.fbx new file mode 100644 index 0000000000..c18162dda1 Binary files /dev/null and b/interface/resources/avatar/animations/idle02.fbx differ diff --git a/interface/resources/avatar/animations/idle03.fbx b/interface/resources/avatar/animations/idle03.fbx new file mode 100644 index 0000000000..5349c49a31 Binary files /dev/null and b/interface/resources/avatar/animations/idle03.fbx differ diff --git a/interface/resources/avatar/animations/idle_lookaround01.fbx b/interface/resources/avatar/animations/idle04.fbx similarity index 59% rename from interface/resources/avatar/animations/idle_lookaround01.fbx rename to interface/resources/avatar/animations/idle04.fbx index fbea065713..c0676a7980 100644 Binary files a/interface/resources/avatar/animations/idle_lookaround01.fbx and b/interface/resources/avatar/animations/idle04.fbx differ diff --git a/interface/resources/avatar/animations/idleWS.fbx b/interface/resources/avatar/animations/idleWS.fbx deleted file mode 100644 index e730165012..0000000000 Binary files a/interface/resources/avatar/animations/idleWS.fbx and /dev/null differ diff --git a/interface/resources/avatar/animations/idleWS_all.fbx b/interface/resources/avatar/animations/idleWS_all.fbx index f9ac3dacfb..3605ecfcf4 100644 Binary files a/interface/resources/avatar/animations/idleWS_all.fbx and b/interface/resources/avatar/animations/idleWS_all.fbx differ diff --git a/interface/resources/avatar/animations/idle_LFF_all.fbx b/interface/resources/avatar/animations/idle_LFF_all.fbx index 6904773cd5..0344a270a7 100644 Binary files a/interface/resources/avatar/animations/idle_LFF_all.fbx and b/interface/resources/avatar/animations/idle_LFF_all.fbx differ diff --git a/interface/resources/avatar/animations/idle_RFF_all.fbx b/interface/resources/avatar/animations/idle_RFF_all.fbx index 77ea06dc70..8aec6a33c0 100644 Binary files a/interface/resources/avatar/animations/idle_RFF_all.fbx and b/interface/resources/avatar/animations/idle_RFF_all.fbx differ diff --git a/interface/resources/avatar/animations/idle_once_armstretch.fbx b/interface/resources/avatar/animations/idle_once_armstretch.fbx deleted file mode 100644 index 23eeed3b26..0000000000 Binary files a/interface/resources/avatar/animations/idle_once_armstretch.fbx and /dev/null differ diff --git a/interface/resources/avatar/animations/idle_once_bigstretch.fbx b/interface/resources/avatar/animations/idle_once_bigstretch.fbx deleted file mode 100644 index 5e4731279f..0000000000 Binary files a/interface/resources/avatar/animations/idle_once_bigstretch.fbx and /dev/null differ diff --git a/interface/resources/avatar/animations/idle_once_checkwatch.fbx b/interface/resources/avatar/animations/idle_once_checkwatch.fbx deleted file mode 100644 index 888d0bcbfc..0000000000 Binary files a/interface/resources/avatar/animations/idle_once_checkwatch.fbx and /dev/null differ diff --git a/interface/resources/avatar/animations/idle_once_fidget.fbx b/interface/resources/avatar/animations/idle_once_fidget.fbx new file mode 100644 index 0000000000..2270614901 Binary files /dev/null and b/interface/resources/avatar/animations/idle_once_fidget.fbx differ diff --git a/interface/resources/avatar/animations/idle_once_headtilt.fbx b/interface/resources/avatar/animations/idle_once_headtilt.fbx index 21d1bc43c8..eeae4604aa 100644 Binary files a/interface/resources/avatar/animations/idle_once_headtilt.fbx and b/interface/resources/avatar/animations/idle_once_headtilt.fbx differ diff --git a/interface/resources/avatar/animations/idle_once_lookaround.fbx b/interface/resources/avatar/animations/idle_once_lookaround.fbx index 15be33092c..b638191654 100644 Binary files a/interface/resources/avatar/animations/idle_once_lookaround.fbx and b/interface/resources/avatar/animations/idle_once_lookaround.fbx differ diff --git a/interface/resources/avatar/animations/idle_once_lookleftright.fbx b/interface/resources/avatar/animations/idle_once_lookleftright.fbx new file mode 100644 index 0000000000..72aee7931e Binary files /dev/null and b/interface/resources/avatar/animations/idle_once_lookleftright.fbx differ diff --git a/interface/resources/avatar/animations/idle_once_neckstretch.fbx b/interface/resources/avatar/animations/idle_once_neckstretch.fbx index 3968b96615..5ee4a99d65 100644 Binary files a/interface/resources/avatar/animations/idle_once_neckstretch.fbx and b/interface/resources/avatar/animations/idle_once_neckstretch.fbx differ diff --git a/interface/resources/avatar/animations/idle_once_shiftheelpivot.fbx b/interface/resources/avatar/animations/idle_once_shiftheelpivot.fbx new file mode 100644 index 0000000000..073b4343aa Binary files /dev/null and b/interface/resources/avatar/animations/idle_once_shiftheelpivot.fbx differ diff --git a/interface/resources/avatar/animations/idle_once_slownod.fbx b/interface/resources/avatar/animations/idle_once_slownod.fbx index ad4f4e17bf..7a27add7bf 100644 Binary files a/interface/resources/avatar/animations/idle_once_slownod.fbx and b/interface/resources/avatar/animations/idle_once_slownod.fbx differ diff --git a/interface/resources/avatar/animations/jog_bwd.fbx b/interface/resources/avatar/animations/jog_bwd.fbx index 479392d44c..b3eb8c919d 100644 Binary files a/interface/resources/avatar/animations/jog_bwd.fbx and b/interface/resources/avatar/animations/jog_bwd.fbx differ diff --git a/interface/resources/avatar/animations/jog_fwd.fbx b/interface/resources/avatar/animations/jog_fwd.fbx index f389fea364..9d38caacab 100644 Binary files a/interface/resources/avatar/animations/jog_fwd.fbx and b/interface/resources/avatar/animations/jog_fwd.fbx differ diff --git a/interface/resources/avatar/animations/jog_left.fbx b/interface/resources/avatar/animations/jog_left.fbx index 88600005b9..7732050201 100644 Binary files a/interface/resources/avatar/animations/jog_left.fbx and b/interface/resources/avatar/animations/jog_left.fbx differ diff --git a/interface/resources/avatar/animations/jog_right.fbx b/interface/resources/avatar/animations/jog_right.fbx new file mode 100644 index 0000000000..9b419b6eec Binary files /dev/null and b/interface/resources/avatar/animations/jog_right.fbx differ diff --git a/interface/resources/avatar/animations/jump_in_air.fbx b/interface/resources/avatar/animations/jump_in_air.fbx deleted file mode 100644 index 2e6ad32f4f..0000000000 Binary files a/interface/resources/avatar/animations/jump_in_air.fbx and /dev/null differ diff --git a/interface/resources/avatar/animations/jump_land.fbx b/interface/resources/avatar/animations/jump_land.fbx deleted file mode 100644 index f057c80085..0000000000 Binary files a/interface/resources/avatar/animations/jump_land.fbx and /dev/null differ diff --git a/interface/resources/avatar/animations/jump_running_launch_land.fbx b/interface/resources/avatar/animations/jump_running_launch_land.fbx deleted file mode 100644 index ad922d948e..0000000000 Binary files a/interface/resources/avatar/animations/jump_running_launch_land.fbx and /dev/null differ diff --git a/interface/resources/avatar/animations/jump_running_launch_land_all.fbx b/interface/resources/avatar/animations/jump_running_launch_land_all.fbx new file mode 100644 index 0000000000..71dae6bcc5 Binary files /dev/null and b/interface/resources/avatar/animations/jump_running_launch_land_all.fbx differ diff --git a/interface/resources/avatar/animations/jump_standing_apex.fbx b/interface/resources/avatar/animations/jump_standing_apex.fbx deleted file mode 100644 index 53b79758aa..0000000000 Binary files a/interface/resources/avatar/animations/jump_standing_apex.fbx and /dev/null differ diff --git a/interface/resources/avatar/animations/jump_standing_apex_all.fbx b/interface/resources/avatar/animations/jump_standing_apex_all.fbx new file mode 100644 index 0000000000..5d5873c39a Binary files /dev/null and b/interface/resources/avatar/animations/jump_standing_apex_all.fbx differ diff --git a/interface/resources/avatar/animations/jump_standing_land.fbx b/interface/resources/avatar/animations/jump_standing_land.fbx deleted file mode 100644 index aaeeb186fc..0000000000 Binary files a/interface/resources/avatar/animations/jump_standing_land.fbx and /dev/null differ diff --git a/interface/resources/avatar/animations/jump_standing_land_settle.fbx b/interface/resources/avatar/animations/jump_standing_land_settle.fbx deleted file mode 100644 index 1a11781e22..0000000000 Binary files a/interface/resources/avatar/animations/jump_standing_land_settle.fbx and /dev/null differ diff --git a/interface/resources/avatar/animations/jump_standing_land_settle_all.fbx b/interface/resources/avatar/animations/jump_standing_land_settle_all.fbx new file mode 100644 index 0000000000..ef8e83be34 Binary files /dev/null and b/interface/resources/avatar/animations/jump_standing_land_settle_all.fbx differ diff --git a/interface/resources/avatar/animations/jump_standing_launch.fbx b/interface/resources/avatar/animations/jump_standing_launch.fbx deleted file mode 100644 index 06479c8885..0000000000 Binary files a/interface/resources/avatar/animations/jump_standing_launch.fbx and /dev/null differ diff --git a/interface/resources/avatar/animations/jump_standing_launch_all.fbx b/interface/resources/avatar/animations/jump_standing_launch_all.fbx new file mode 100644 index 0000000000..e10e428579 Binary files /dev/null and b/interface/resources/avatar/animations/jump_standing_launch_all.fbx differ diff --git a/interface/resources/avatar/animations/jump_standing_takeoff.fbx b/interface/resources/avatar/animations/jump_standing_takeoff.fbx deleted file mode 100644 index 5fc6befdd0..0000000000 Binary files a/interface/resources/avatar/animations/jump_standing_takeoff.fbx and /dev/null differ diff --git a/interface/resources/avatar/animations/jump_takeoff.fbx b/interface/resources/avatar/animations/jump_takeoff.fbx deleted file mode 100644 index 3976725676..0000000000 Binary files a/interface/resources/avatar/animations/jump_takeoff.fbx and /dev/null differ diff --git a/interface/resources/avatar/animations/run_bwd.fbx b/interface/resources/avatar/animations/run_bwd.fbx index 62f49c9729..60ade1f2ac 100644 Binary files a/interface/resources/avatar/animations/run_bwd.fbx and b/interface/resources/avatar/animations/run_bwd.fbx differ diff --git a/interface/resources/avatar/animations/run_fast_fwd.fbx b/interface/resources/avatar/animations/run_fast_fwd.fbx new file mode 100644 index 0000000000..cb964d57d8 Binary files /dev/null and b/interface/resources/avatar/animations/run_fast_fwd.fbx differ diff --git a/interface/resources/avatar/animations/run_fast_left.fbx b/interface/resources/avatar/animations/run_fast_left.fbx new file mode 100644 index 0000000000..5078d0cb22 Binary files /dev/null and b/interface/resources/avatar/animations/run_fast_left.fbx differ diff --git a/interface/resources/avatar/animations/run_fast_right.fbx b/interface/resources/avatar/animations/run_fast_right.fbx new file mode 100644 index 0000000000..ddf081bef6 Binary files /dev/null and b/interface/resources/avatar/animations/run_fast_right.fbx differ diff --git a/interface/resources/avatar/animations/run_fwd.fbx b/interface/resources/avatar/animations/run_fwd.fbx deleted file mode 100644 index f28f9e0569..0000000000 Binary files a/interface/resources/avatar/animations/run_fwd.fbx and /dev/null differ diff --git a/interface/resources/avatar/animations/settle_to_idle.fbx b/interface/resources/avatar/animations/settle_to_idle.fbx deleted file mode 100644 index fba4305e9a..0000000000 Binary files a/interface/resources/avatar/animations/settle_to_idle.fbx and /dev/null differ diff --git a/interface/resources/avatar/animations/settle_to_idle_small.fbx b/interface/resources/avatar/animations/settle_to_idle_small.fbx new file mode 100644 index 0000000000..3d79d1930c Binary files /dev/null and b/interface/resources/avatar/animations/settle_to_idle_small.fbx differ diff --git a/interface/resources/avatar/animations/side_step_left.fbx b/interface/resources/avatar/animations/side_step_left.fbx index ef8cbe0a5c..b74fe9074a 100644 Binary files a/interface/resources/avatar/animations/side_step_left.fbx and b/interface/resources/avatar/animations/side_step_left.fbx differ diff --git a/interface/resources/avatar/animations/side_step_left_fast.fbx b/interface/resources/avatar/animations/side_step_left_fast.fbx index af71a46bb5..f4c997345f 100644 Binary files a/interface/resources/avatar/animations/side_step_left_fast.fbx and b/interface/resources/avatar/animations/side_step_left_fast.fbx differ diff --git a/interface/resources/avatar/animations/side_step_left_fast02.fbx b/interface/resources/avatar/animations/side_step_left_fast02.fbx deleted file mode 100644 index 9064b35d37..0000000000 Binary files a/interface/resources/avatar/animations/side_step_left_fast02.fbx and /dev/null differ diff --git a/interface/resources/avatar/animations/side_step_right.fbx b/interface/resources/avatar/animations/side_step_right.fbx deleted file mode 100644 index 6404657741..0000000000 Binary files a/interface/resources/avatar/animations/side_step_right.fbx and /dev/null differ diff --git a/interface/resources/avatar/animations/side_step_short_left.fbx b/interface/resources/avatar/animations/side_step_short_left.fbx index f236f30c31..8f55364b17 100644 Binary files a/interface/resources/avatar/animations/side_step_short_left.fbx and b/interface/resources/avatar/animations/side_step_short_left.fbx differ diff --git a/interface/resources/avatar/animations/side_step_short_right.fbx b/interface/resources/avatar/animations/side_step_short_right.fbx deleted file mode 100644 index df074c17e0..0000000000 Binary files a/interface/resources/avatar/animations/side_step_short_right.fbx and /dev/null differ diff --git a/interface/resources/avatar/animations/side_strafe_left.fbx b/interface/resources/avatar/animations/side_strafe_left.fbx deleted file mode 100644 index 61c3ba7b32..0000000000 Binary files a/interface/resources/avatar/animations/side_strafe_left.fbx and /dev/null differ diff --git a/interface/resources/avatar/animations/side_strafe_left02.fbx b/interface/resources/avatar/animations/side_strafe_left02.fbx deleted file mode 100644 index e9bc801997..0000000000 Binary files a/interface/resources/avatar/animations/side_strafe_left02.fbx and /dev/null differ diff --git a/interface/resources/avatar/animations/sitting.fbx b/interface/resources/avatar/animations/sitting.fbx deleted file mode 100644 index dfb51afb66..0000000000 Binary files a/interface/resources/avatar/animations/sitting.fbx and /dev/null differ diff --git a/interface/resources/avatar/animations/sitting_idle.fbx b/interface/resources/avatar/animations/sitting_idle.fbx deleted file mode 100644 index ee03d942cd..0000000000 Binary files a/interface/resources/avatar/animations/sitting_idle.fbx and /dev/null differ diff --git a/interface/resources/avatar/animations/talk.fbx b/interface/resources/avatar/animations/talk.fbx index c29bf1e9bf..6cc34049be 100644 Binary files a/interface/resources/avatar/animations/talk.fbx and b/interface/resources/avatar/animations/talk.fbx differ diff --git a/interface/resources/avatar/animations/talk02.fbx b/interface/resources/avatar/animations/talk02.fbx new file mode 100644 index 0000000000..a502ff261b Binary files /dev/null and b/interface/resources/avatar/animations/talk02.fbx differ diff --git a/interface/resources/avatar/animations/talk03.fbx b/interface/resources/avatar/animations/talk03.fbx new file mode 100644 index 0000000000..da95717540 Binary files /dev/null and b/interface/resources/avatar/animations/talk03.fbx differ diff --git a/interface/resources/avatar/animations/talk04.fbx b/interface/resources/avatar/animations/talk04.fbx index be2ba0a11f..9e5505b969 100644 Binary files a/interface/resources/avatar/animations/talk04.fbx and b/interface/resources/avatar/animations/talk04.fbx differ diff --git a/interface/resources/avatar/animations/talk_armsdown.fbx b/interface/resources/avatar/animations/talk_armsdown.fbx new file mode 100644 index 0000000000..e069811f7c Binary files /dev/null and b/interface/resources/avatar/animations/talk_armsdown.fbx differ diff --git a/interface/resources/avatar/animations/talk_lefthand.fbx b/interface/resources/avatar/animations/talk_lefthand.fbx new file mode 100644 index 0000000000..d7fd1d5e07 Binary files /dev/null and b/interface/resources/avatar/animations/talk_lefthand.fbx differ diff --git a/interface/resources/avatar/animations/talk_righthand.fbx b/interface/resources/avatar/animations/talk_righthand.fbx index df8849b4b4..332afcc1e7 100644 Binary files a/interface/resources/avatar/animations/talk_righthand.fbx and b/interface/resources/avatar/animations/talk_righthand.fbx differ diff --git a/interface/resources/avatar/animations/teleport.fbx b/interface/resources/avatar/animations/teleport.fbx deleted file mode 100644 index 99c950ced6..0000000000 Binary files a/interface/resources/avatar/animations/teleport.fbx and /dev/null differ diff --git a/interface/resources/avatar/animations/turn_left.fbx b/interface/resources/avatar/animations/turn_left.fbx index 3d32d832e6..b7cadf7a66 100644 Binary files a/interface/resources/avatar/animations/turn_left.fbx and b/interface/resources/avatar/animations/turn_left.fbx differ diff --git a/interface/resources/avatar/animations/turn_right.fbx b/interface/resources/avatar/animations/turn_right.fbx new file mode 100644 index 0000000000..4ee3d52daf Binary files /dev/null and b/interface/resources/avatar/animations/turn_right.fbx differ diff --git a/interface/resources/avatar/animations/walk_bwd.fbx b/interface/resources/avatar/animations/walk_bwd.fbx index 158ba52840..9daa769885 100644 Binary files a/interface/resources/avatar/animations/walk_bwd.fbx and b/interface/resources/avatar/animations/walk_bwd.fbx differ diff --git a/interface/resources/avatar/animations/walk_bwd_fast.fbx b/interface/resources/avatar/animations/walk_bwd_fast.fbx index f9a9ba0e26..af22d0d0b0 100644 Binary files a/interface/resources/avatar/animations/walk_bwd_fast.fbx and b/interface/resources/avatar/animations/walk_bwd_fast.fbx differ diff --git a/interface/resources/avatar/animations/walk_fwd.fbx b/interface/resources/avatar/animations/walk_fwd.fbx index 8ad461f62e..f86a8744c9 100644 Binary files a/interface/resources/avatar/animations/walk_fwd.fbx and b/interface/resources/avatar/animations/walk_fwd.fbx differ diff --git a/interface/resources/avatar/animations/walk_fwd_fast.fbx b/interface/resources/avatar/animations/walk_fwd_fast.fbx index db440fc9c4..8d2becf4b8 100644 Binary files a/interface/resources/avatar/animations/walk_fwd_fast.fbx and b/interface/resources/avatar/animations/walk_fwd_fast.fbx differ diff --git a/interface/resources/avatar/animations/walk_fwd_fast02.fbx b/interface/resources/avatar/animations/walk_fwd_fast02.fbx deleted file mode 100644 index 470b1d57f3..0000000000 Binary files a/interface/resources/avatar/animations/walk_fwd_fast02.fbx and /dev/null differ diff --git a/interface/resources/avatar/animations/walk_fwd_fast_armout.fbx b/interface/resources/avatar/animations/walk_fwd_fast_armout.fbx deleted file mode 100644 index 6aa07d0a45..0000000000 Binary files a/interface/resources/avatar/animations/walk_fwd_fast_armout.fbx and /dev/null differ diff --git a/interface/resources/avatar/animations/walk_left.fbx b/interface/resources/avatar/animations/walk_left.fbx index bfe10aa18f..f35d4f6a77 100644 Binary files a/interface/resources/avatar/animations/walk_left.fbx and b/interface/resources/avatar/animations/walk_left.fbx differ diff --git a/interface/resources/avatar/animations/walk_left_fast.fbx b/interface/resources/avatar/animations/walk_left_fast.fbx index ced6c08bac..8414ee6805 100644 Binary files a/interface/resources/avatar/animations/walk_left_fast.fbx and b/interface/resources/avatar/animations/walk_left_fast.fbx differ diff --git a/interface/resources/avatar/animations/walk_right.fbx b/interface/resources/avatar/animations/walk_right.fbx new file mode 100644 index 0000000000..5fe005f96c Binary files /dev/null and b/interface/resources/avatar/animations/walk_right.fbx differ diff --git a/interface/resources/avatar/animations/walk_right_fast.fbx b/interface/resources/avatar/animations/walk_right_fast.fbx new file mode 100644 index 0000000000..37b7bbbb62 Binary files /dev/null and b/interface/resources/avatar/animations/walk_right_fast.fbx differ diff --git a/interface/resources/avatar/animations/walk_short_bwd.fbx b/interface/resources/avatar/animations/walk_short_bwd.fbx deleted file mode 100644 index d7e4bedf53..0000000000 Binary files a/interface/resources/avatar/animations/walk_short_bwd.fbx and /dev/null differ diff --git a/interface/resources/avatar/animations/walk_short_fwd.fbx b/interface/resources/avatar/animations/walk_short_fwd.fbx index 51f0794ac1..b52371869b 100644 Binary files a/interface/resources/avatar/animations/walk_short_fwd.fbx and b/interface/resources/avatar/animations/walk_short_fwd.fbx differ diff --git a/interface/resources/avatar/avatar-animation.json b/interface/resources/avatar/avatar-animation.json index fd206ce475..b1277a26f5 100644 --- a/interface/resources/avatar/avatar-animation.json +++ b/interface/resources/avatar/avatar-animation.json @@ -733,7 +733,7 @@ }, { "id": "turnRight", - "interpTarget": 6, + "interpTarget": 8, "interpDuration": 8, "transitions": [ { "var": "isNotTurning", "state": "idle" }, @@ -753,7 +753,7 @@ }, { "id": "turnLeft", - "interpTarget": 6, + "interpTarget": 8, "interpDuration": 8, "transitions": [ { "var": "isNotTurning", "state": "idle" }, @@ -773,7 +773,7 @@ }, { "id": "strafeRightHmd", - "interpTarget": 5, + "interpTarget": 8, "interpDuration": 8, "interpType": "snapshotPrev", "transitions": [ @@ -794,7 +794,7 @@ }, { "id": "strafeLeftHmd", - "interpTarget": 5, + "interpTarget": 8, "interpDuration": 8, "interpType": "snapshotPrev", "transitions": [ @@ -905,40 +905,72 @@ "id": "idle", "type": "overlay", "data": { - "alpha": 1.0, + "alpha": 1.0, "alphaVar": "idleOverlayAlpha", "boneSet": "upperBody" }, "children": [ - { - "id": "idleTalk", + { + "id": "idleTalk", "type": "randomSwitchStateMachine", "data": { - "currentState": "idleTalk1", - "triggerRandomSwitch": "idleTalkSwitch", - "randomSwitchTimeMin": 5.0, - "randomSwitchTimeMax": 10.0, + "currentState": "talk", + "triggerRandomSwitch": "idleTalkSwitch", + "randomSwitchTimeMin": 7.0, + "randomSwitchTimeMax": 12.0, "states": [ { - "id": "idleTalk1", - "interpTarget": 6, - "interpDuration": 15, + "id": "talk", + "interpTarget": 20, + "interpDuration": 20, "priority": 0.33, "resume": true, "transitions": [] }, { - "id": "idleTalk2", - "interpTarget": 6, - "interpDuration": 15, + "id": "talk02", + "interpTarget": 20, + "interpDuration": 20, "priority": 0.33, "resume": true, "transitions": [] }, { - "id": "idleTalk3", - "interpTarget": 6, - "interpDuration": 15, + "id": "talk03", + "interpTarget": 20, + "interpDuration": 20, + "priority": 0.33, + "resume": true, + "transitions": [] + }, + { + "id": "talk04", + "interpTarget": 20, + "interpDuration": 20, + "priority": 0.33, + "resume": true, + "transitions": [] + }, + { + "id": "talk_armsdown", + "interpTarget": 20, + "interpDuration": 20, + "priority": 0.33, + "resume": true, + "transitions": [] + }, + { + "id": "talk_lefthand", + "interpTarget": 20, + "interpDuration": 20, + "priority": 0.33, + "resume": true, + "transitions": [] + }, + { + "id": "talk_righthand", + "interpTarget": 20, + "interpDuration": 20, "priority": 0.33, "resume": true, "transitions": [] @@ -947,57 +979,105 @@ }, "children": [ { - "id": "idleTalk1", + "id": "talk", "type": "clip", "data": { "url": "qrc:///avatar/animations/talk.fbx", "startFrame": 1.0, - "endFrame": 800.0, + "endFrame": 500.0, "timeScale": 1.0, "loopFlag": true }, "children": [] }, { - "id": "idleTalk2", + "id": "talk02", "type": "clip", "data": { - "url": "qrc:///avatar/animations/talk_righthand.fbx", + "url": "qrc:///avatar/animations/talk02.fbx", "startFrame": 1.0, - "endFrame": 501.0, + "endFrame": 325.0, "timeScale": 1.0, "loopFlag": true }, "children": [] }, { - "id": "idleTalk3", + "id": "talk03", + "type": "clip", + "data": { + "url": "qrc:///avatar/animations/talk03.fbx", + "startFrame": 1.0, + "endFrame": 300.0, + "timeScale": 1.0, + "loopFlag": true + }, + "children": [] + }, + { + "id": "talk04", "type": "clip", "data": { "url": "qrc:///avatar/animations/talk04.fbx", "startFrame": 1.0, - "endFrame": 499.0, + "endFrame": 500.0, + "timeScale": 1.0, + "loopFlag": true + }, + "children": [] + }, + { + "id": "talk_armsdown", + "type": "clip", + "data": { + "url": "qrc:///avatar/animations/talk_armsdown.fbx", + "startFrame": 1.0, + "endFrame": 215.0, + "timeScale": 1.0, + "loopFlag": true + }, + "children": [] + }, + { + "id": "talk_lefthand", + "type": "clip", + "data": { + "url": "qrc:///avatar/animations/talk_lefthand.fbx", + "startFrame": 1.0, + "endFrame": 500.0, + "timeScale": 1.0, + "loopFlag": true + }, + "children": [] + }, + { + "id": "talk_righthand", + "type": "clip", + "data": { + "url": "qrc:///avatar/animations/talk_righthand.fbx", + "startFrame": 1.0, + "endFrame": 502.0, "timeScale": 1.0, "loopFlag": true }, "children": [] } ] - }, + }, { "id": "idleStand", "type": "randomSwitchStateMachine", "data": { "currentState": "masterIdle", - "triggerTimeMin": 10.0, - "triggerTimeMax": 60.0, - "transitionVar": "timeToFidget", + "triggerTimeMin": 10.0, + "triggerTimeMax": 50.0, + "transitionVar": "timeToFidget", "states": [ { "id": "masterIdle", "interpTarget": 21, "interpDuration": 20, - "priority": 1.0, + "priority": 1.0, "resume": false, "transitions": [ { "var": "timeToFidget", "randomSwitchState": "fidget" } @@ -1007,17 +1087,17 @@ "id": "fidget", "interpTarget": 21, "interpDuration": 20, - "priority": -1.0, + "priority": -1.0, "resume": false, "transitions": [ - { "var": "movement1OnDone", "randomSwitchState": "masterIdle" }, - { "var": "movement2OnDone", "randomSwitchState": "masterIdle" }, - { "var": "movement3OnDone", "randomSwitchState": "masterIdle" }, - { "var": "movement4OnDone", "randomSwitchState": "masterIdle" }, - { "var": "movement5OnDone", "randomSwitchState": "masterIdle" }, - { "var": "movement6OnDone", "randomSwitchState": "masterIdle" }, - { "var": "movement7OnDone", "randomSwitchState": "masterIdle" }, - { "var": "movement8OnDone", "randomSwitchState": "masterIdle" }, + { "var": "idle_once_slownodOnDone", "randomSwitchState": "masterIdle" }, + { "var": "idle_once_headtiltOnDone", "randomSwitchState": "masterIdle" }, + { "var": "idle_once_shiftheelpivotOnDone", "randomSwitchState": "masterIdle" }, + { "var": "idleWS_allOnDone", "randomSwitchState": "masterIdle" }, + { "var": "idle_once_lookaroundOnDone", "randomSwitchState": "masterIdle" }, + { "var": "idle_once_neckstretchOnDone", "randomSwitchState": "masterIdle" }, + { "var": "idle_once_lookleftrightOnDone", "randomSwitchState": "masterIdle" }, + { "var": "idle_once_fidgetOnDone", "randomSwitchState": "masterIdle" }, { "var": "alt1ToMasterIdleOnDone", "randomSwitchState": "masterIdle" }, { "var": "alt2ToMasterIdleOnDone", "randomSwitchState": "masterIdle" } ] @@ -1032,13 +1112,13 @@ "currentState": "masterIdle1", "triggerRandomSwitch": "masterIdleSwitch", "randomSwitchTimeMin": 10.0, - "randomSwitchTimeMax": 60.0, + "randomSwitchTimeMax": 30.0, "states": [ { "id": "masterIdle1", "interpTarget": 21, "interpDuration": 20, - "priority": 0.33, + "priority": 0.25, "resume": true, "transitions": [] }, @@ -1046,7 +1126,7 @@ "id": "masterIdle2", "interpTarget": 21, "interpDuration": 20, - "priority": 0.33, + "priority": 0.25, "resume": true, "transitions": [] }, @@ -1054,7 +1134,15 @@ "id": "masterIdle3", "interpTarget": 21, "interpDuration": 20, - "priority": 0.33, + "priority": 0.25, + "resume": true, + "transitions": [] + }, + { + "id": "masterIdle4", + "interpTarget": 21, + "interpDuration": 20, + "priority": 0.25, "resume": true, "transitions": [] } @@ -1077,10 +1165,10 @@ "id": "masterIdle2", "type": "clip", "data": { - "url": "qrc:///avatar/animations/idleWS_all.fbx", + "url": "qrc:///avatar/animations/idle02.fbx", "startFrame": 1.0, - "endFrame": 1620.0, - "timeScale": 1.0, + "endFrame": 400.0, + "timeScale": 0.75, "loopFlag": true }, "children": [] @@ -1089,9 +1177,21 @@ "id": "masterIdle3", "type": "clip", "data": { - "url": "qrc:///avatar/animations/idle_lookaround01.fbx", + "url": "qrc:///avatar/animations/idle03.fbx", "startFrame": 1.0, - "endFrame": 901.0, + "endFrame": 800.0, + "timeScale": 1.0, + "loopFlag": true + }, + "children": [] + }, + { + "id": "masterIdle4", + "type": "clip", + "data": { + "url": "qrc:///avatar/animations/idle04.fbx", + "startFrame": 1.0, + "endFrame": 902.0, "timeScale": 1.0, "loopFlag": true }, @@ -1109,7 +1209,7 @@ "id": "movement", "interpTarget": 17, "interpDuration": 15, - "priority": 0.8, + "priority": 0.6, "resume": false, "transitions": [] }, @@ -1117,7 +1217,7 @@ "id": "alternateIdle", "interpTarget": 17, "interpDuration": 15, - "priority": 0.2, + "priority": 0.4, "resume": false, "transitions": [] } @@ -1128,10 +1228,10 @@ "id": "movement", "type": "randomSwitchStateMachine", "data": { - "currentState": "movement1", + "currentState": "idle_once_slownod", "states": [ { - "id": "movement1", + "id": "idle_once_slownod", "interpTarget": 21, "interpDuration": 20, "priority": 0.2, @@ -1139,7 +1239,7 @@ "transitions": [] }, { - "id": "movement2", + "id": "idle_once_headtilt", "interpTarget": 21, "interpDuration": 20, "priority": 0.2, @@ -1147,7 +1247,7 @@ "transitions": [] }, { - "id": "movement3", + "id": "idle_once_shiftheelpivot", "interpTarget": 21, "interpDuration": 20, "priority": 0.2, @@ -1155,7 +1255,7 @@ "transitions": [] }, { - "id": "movement4", + "id": "idleWS_all", "interpTarget": 21, "interpDuration": 20, "priority": 0.2, @@ -1163,7 +1263,7 @@ "transitions": [] }, { - "id": "movement5", + "id": "idle_once_lookaround", "interpTarget": 21, "interpDuration": 20, "priority": 0.2, @@ -1171,7 +1271,7 @@ "transitions": [] }, { - "id": "movement6", + "id": "idle_once_neckstretch", "interpTarget": 21, "interpDuration": 20, "priority": 0.2, @@ -1179,7 +1279,7 @@ "transitions": [] }, { - "id": "movement7", + "id": "idle_once_lookleftright", "interpTarget": 21, "interpDuration": 20, "priority": 0.2, @@ -1187,7 +1287,7 @@ "transitions": [] }, { - "id": "movement8", + "id": "idle_once_fidget", "interpTarget": 21, "interpDuration": 20, "priority": 0.2, @@ -1198,11 +1298,11 @@ }, "children": [ { - "id": "movement1", + "id": "idle_once_slownod", "type": "clip", "data": { "url": "qrc:///avatar/animations/idle_once_slownod.fbx", - "startFrame": 1, + "startFrame": 1.0, "endFrame": 91.0, "timeScale": 1.0, "loopFlag": false @@ -1210,84 +1310,84 @@ "children": [] }, { - "id": "movement2", + "id": "idle_once_headtilt", "type": "clip", "data": { "url": "qrc:///avatar/animations/idle_once_headtilt.fbx", - "startFrame": 1, - "endFrame": 154, + "startFrame": 1.0, + "endFrame": 154.0, "timeScale": 1.0, "loopFlag": false }, "children": [] }, { - "id": "movement3", + "id": "idle_once_shiftheelpivot", "type": "clip", "data": { - "url": "qrc:///avatar/animations/idle_once_headtilt.fbx", - "startFrame": 1, - "endFrame": 154, + "url": "qrc:///avatar/animations/idle_once_shiftheelpivot.fbx", + "startFrame": 1.0, + "endFrame": 491.0, "timeScale": 1.0, "loopFlag": false }, "children": [] }, { - "id": "movement4", + "id": "idleWS_all", "type": "clip", "data": { "url": "qrc:///avatar/animations/idleWS_all.fbx", - "startFrame": 1, - "endFrame": 1620, - "timeScale": 1.0, + "startFrame": 1.0, + "endFrame": 1620.0, + "timeScale": 0.7, "loopFlag": false }, "children": [] }, { - "id": "movement5", + "id": "idle_once_lookaround", "type": "clip", "data": { "url": "qrc:///avatar/animations/idle_once_lookaround.fbx", - "startFrame": 1, - "endFrame": 324, + "startFrame": 1.0, + "endFrame": 324.0, "timeScale": 1.0, "loopFlag": false }, "children": [] }, { - "id": "movement6", + "id": "idle_once_neckstretch", "type": "clip", "data": { "url": "qrc:///avatar/animations/idle_once_neckstretch.fbx", - "startFrame": 1, - "endFrame": 169, + "startFrame": 1.0, + "endFrame": 169.0, "timeScale": 1.0, "loopFlag": false }, "children": [] }, { - "id": "movement7", + "id": "idle_once_lookleftright", "type": "clip", "data": { - "url": "qrc:///avatar/animations/idleWS_all.fbx", - "startFrame": 1, - "endFrame": 1620, - "timeScale": 1.0, + "url": "qrc:///avatar/animations/idle_once_lookleftright.fbx", + "startFrame": 1.0, + "endFrame": 375.0, + "timeScale": 0.7, "loopFlag": false }, "children": [] }, { - "id": "movement8", + "id": "idle_once_fidget", "type": "clip", "data": { - "url": "qrc:///avatar/animations/idle_once_lookaround.fbx", - "startFrame": 1, - "endFrame": 324, + "url": "qrc:///avatar/animations/idle_once_fidget.fbx", + "startFrame": 1.0, + "endFrame": 429.0, "timeScale": 1.0, "loopFlag": false }, @@ -1381,7 +1481,7 @@ "data": { "url": "qrc:///avatar/animations/idle_LFF_all.fbx", "startFrame": 1, - "endFrame": 55, + "endFrame": 80, "timeScale": 1.0, "loopFlag": false }, @@ -1392,8 +1492,8 @@ "type": "clip", "data": { "url": "qrc:///avatar/animations/idle_RFF_all.fbx", - "startFrame": 1, - "endFrame": 56, + "startFrame": 1.0, + "endFrame": 80.0, "timeScale": 1.0, "loopFlag": false }, @@ -1404,7 +1504,7 @@ "type": "clip", "data": { "url": "qrc:///avatar/animations/idle_LFF_all.fbx", - "startFrame": 55, + "startFrame": 80, "endFrame": 389, "timeScale": 1.0, "loopFlag": true @@ -1416,8 +1516,8 @@ "type": "clip", "data": { "url": "qrc:///avatar/animations/idle_RFF_all.fbx", - "startFrame": 56, - "endFrame": 390, + "startFrame": 80.0, + "endFrame": 390.0, "timeScale": 1.0, "loopFlag": true }, @@ -1440,8 +1540,8 @@ "type": "clip", "data": { "url": "qrc:///avatar/animations/idle_RFF_all.fbx", - "startFrame": 390, - "endFrame": 453, + "startFrame": 390.0, + "endFrame": 453.0, "timeScale": 1.0, "loopFlag": false }, @@ -1463,7 +1563,7 @@ "data": { "alpha": 0.0, "desiredSpeed": 1.4, - "characteristicSpeeds": [0.5, 1.8, 2.3, 3.0, 5.0], + "characteristicSpeeds": [0.5, 1.8, 2.5, 3.55, 5.675], "alphaVar": "moveForwardAlpha", "desiredSpeedVar": "moveForwardSpeed" }, @@ -1473,8 +1573,8 @@ "type": "clip", "data": { "url": "qrc:///avatar/animations/walk_short_fwd.fbx", - "startFrame": 0.0, - "endFrame": 39.0, + "startFrame": 1.0, + "endFrame": 40.0, "timeScale": 1.0, "loopFlag": true }, @@ -1485,7 +1585,7 @@ "type": "clip", "data": { "url": "qrc:///avatar/animations/walk_fwd.fbx", - "startFrame": 0.0, + "startFrame": 1.0, "endFrame": 30.0, "timeScale": 1.0, "loopFlag": true @@ -1497,8 +1597,8 @@ "type": "clip", "data": { "url": "qrc:///avatar/animations/walk_fwd_fast.fbx", - "startFrame": 0.0, - "endFrame": 25.0, + "startFrame": 1.0, + "endFrame": 26.0, "timeScale": 1.0, "loopFlag": true }, @@ -1510,7 +1610,7 @@ "data": { "url": "qrc:///avatar/animations/jog_fwd.fbx", "startFrame": 1.0, - "endFrame": 22.0, + "endFrame": 18.0, "timeScale": 1.0, "loopFlag": true }, @@ -1520,9 +1620,9 @@ "id": "walkFwdRun_c", "type": "clip", "data": { - "url": "qrc:///avatar/animations/run_fwd.fbx", + "url": "qrc:///avatar/animations/run_fast_fwd.fbx", "startFrame": 1.0, - "endFrame": 23.0, + "endFrame": 19.0, "timeScale": 1.0, "loopFlag": true }, @@ -1546,7 +1646,7 @@ "id": "idleSettle", "type": "clip", "data": { - "url": "qrc:///avatar/animations/settle_to_idle.fbx", + "url": "qrc:///avatar/animations/settle_to_idle_small.fbx", "startFrame": 1.0, "endFrame": 59.0, "timeScale": 1.0, @@ -1560,7 +1660,7 @@ "data": { "alpha": 0.0, "desiredSpeed": 1.4, - "characteristicSpeeds": [0.6, 1.6, 2.3, 3.1], + "characteristicSpeeds": [0.6, 1.6, 2.8, 4.5], "alphaVar": "moveBackwardAlpha", "desiredSpeedVar": "moveBackwardSpeed" }, @@ -1569,9 +1669,9 @@ "id": "walkBwdShort_c", "type": "clip", "data": { - "url": "qrc:///avatar/animations/walk_short_bwd.fbx", - "startFrame": 0.0, - "endFrame": 38.0, + "url": "qrc:///avatar/animations/walk_bwd.fbx", + "startFrame": 1.0, + "endFrame": 37.0, "timeScale": 1.0, "loopFlag": true }, @@ -1582,8 +1682,8 @@ "type": "clip", "data": { "url": "qrc:///avatar/animations/walk_bwd_fast.fbx", - "startFrame": 0.0, - "endFrame": 27.0, + "startFrame": 1.0, + "endFrame": 28.0, "timeScale": 1.0, "loopFlag": true }, @@ -1594,8 +1694,8 @@ "type": "clip", "data": { "url": "qrc:///avatar/animations/jog_bwd.fbx", - "startFrame": 0.0, - "endFrame": 24.0, + "startFrame": 1.0, + "endFrame": 20.0, "timeScale": 1.0, "loopFlag": true }, @@ -1606,8 +1706,8 @@ "type": "clip", "data": { "url": "qrc:///avatar/animations/run_bwd.fbx", - "startFrame": 0.0, - "endFrame": 16.0, + "startFrame": 1.0, + "endFrame": 14.0, "timeScale": 1.0, "loopFlag": true }, @@ -1620,8 +1720,8 @@ "type": "clip", "data": { "url": "qrc:///avatar/animations/turn_left.fbx", - "startFrame": 0.0, - "endFrame": 32.0, + "startFrame": 1.0, + "endFrame": 33.0, "timeScale": 1.0, "loopFlag": true }, @@ -1631,12 +1731,12 @@ "id": "turnRight", "type": "clip", "data": { - "url": "qrc:///avatar/animations/turn_left.fbx", - "startFrame": 0.0, - "endFrame": 32.0, + "url": "qrc:///avatar/animations/turn_right.fbx", + "startFrame": 1.0, + "endFrame": 31.0, "timeScale": 1.0, "loopFlag": true, - "mirrorFlag": true + "mirrorFlag": false }, "children": [] }, @@ -1646,7 +1746,7 @@ "data": { "alpha": 0.0, "desiredSpeed": 1.4, - "characteristicSpeeds": [0.1, 0.5, 1.0, 2.6, 3.0], + "characteristicSpeeds": [0.1, 0.5, 1.0, 2.55, 3.35, 5.25], "alphaVar": "moveLateralAlpha", "desiredSpeedVar": "moveLateralSpeed" }, @@ -1656,8 +1756,8 @@ "type": "clip", "data": { "url": "qrc:///avatar/animations/side_step_short_left.fbx", - "startFrame": 0.0, - "endFrame": 29.0, + "startFrame": 1.0, + "endFrame": 30.0, "timeScale": 1.0, "loopFlag": true }, @@ -1668,7 +1768,7 @@ "type": "clip", "data": { "url": "qrc:///avatar/animations/side_step_left.fbx", - "startFrame": 0.0, + "startFrame": 1.0, "endFrame": 20.0, "timeScale": 1.0, "loopFlag": true @@ -1680,7 +1780,7 @@ "type": "clip", "data": { "url": "qrc:///avatar/animations/walk_left.fbx", - "startFrame": 0.0, + "startFrame": 1.0, "endFrame": 35.0, "timeScale": 1.0, "loopFlag": true @@ -1692,7 +1792,7 @@ "type": "clip", "data": { "url": "qrc:///avatar/animations/walk_left_fast.fbx", - "startFrame": 0.0, + "startFrame": 1.0, "endFrame": 21.0, "timeScale": 1.0, "loopFlag": true @@ -1704,8 +1804,20 @@ "type": "clip", "data": { "url": "qrc:///avatar/animations/jog_left.fbx", - "startFrame": 0.0, - "endFrame": 24.0, + "startFrame": 1.0, + "endFrame": 20.0, + "timeScale": 1.0, + "loopFlag": true + }, + "children": [] + }, + { + "id": "strafeLeftRun_c", + "type": "clip", + "data": { + "url": "qrc:///avatar/animations/run_fast_left.fbx", + "startFrame": 1.0, + "endFrame": 19.0, "timeScale": 1.0, "loopFlag": true }, @@ -1719,7 +1831,7 @@ "data": { "alpha": 0.0, "desiredSpeed": 1.4, - "characteristicSpeeds": [0.1, 0.5, 1.0, 2.6, 3.0], + "characteristicSpeeds": [0.1, 0.5, 1.0, 2.55, 3.4, 5.25], "alphaVar": "moveLateralAlpha", "desiredSpeedVar": "moveLateralSpeed" }, @@ -1728,8 +1840,8 @@ "type": "clip", "data": { "url": "qrc:///avatar/animations/side_step_short_left.fbx", - "startFrame": 0.0, - "endFrame": 29.0, + "startFrame": 1.0, + "endFrame": 30.0, "timeScale": 1.0, "loopFlag": true, "mirrorFlag": true @@ -1741,7 +1853,7 @@ "type": "clip", "data": { "url": "qrc:///avatar/animations/side_step_left.fbx", - "startFrame": 0.0, + "startFrame": 1.0, "endFrame": 20.0, "timeScale": 1.0, "loopFlag": true, @@ -1753,12 +1865,12 @@ "id": "strafeRightWalk_c", "type": "clip", "data": { - "url": "qrc:///avatar/animations/walk_left.fbx", - "startFrame": 0.0, + "url": "qrc:///avatar/animations/walk_right.fbx", + "startFrame": 1.0, "endFrame": 35.0, "timeScale": 1.0, "loopFlag": true, - "mirrorFlag": true + "mirrorFlag": false }, "children": [] }, @@ -1766,12 +1878,12 @@ "id": "strafeRightFast_c", "type": "clip", "data": { - "url": "qrc:///avatar/animations/walk_left_fast.fbx", - "startFrame": 0.0, + "url": "qrc:///avatar/animations/walk_right_fast.fbx", + "startFrame": 1.0, "endFrame": 21.0, "timeScale": 1.0, "loopFlag": true, - "mirrorFlag": true + "mirrorFlag": false }, "children": [] }, @@ -1779,12 +1891,25 @@ "id": "strafeRightJog_c", "type": "clip", "data": { - "url": "qrc:///avatar/animations/jog_left.fbx", - "startFrame": 0.0, - "endFrame": 24.0, + "url": "qrc:///avatar/animations/jog_right.fbx", + "startFrame": 1.0, + "endFrame": 20.0, "timeScale": 1.0, "loopFlag": true, - "mirrorFlag": true + "mirrorFlag": false + }, + "children": [] + }, + { + "id": "strafeRightRun_c", + "type": "clip", + "data": { + "url": "qrc:///avatar/animations/run_fast_right.fbx", + "startFrame": 1.0, + "endFrame": 19.0, + "timeScale": 1.0, + "loopFlag": true, + "mirrorFlag": false }, "children": [] } @@ -1806,8 +1931,8 @@ "type": "clip", "data": { "url": "qrc:///avatar/animations/side_step_short_left.fbx", - "startFrame": 0.0, - "endFrame": 29.0, + "startFrame": 1.0, + "endFrame": 30.0, "timeScale": 1.0, "loopFlag": true }, @@ -1818,7 +1943,7 @@ "type": "clip", "data": { "url": "qrc:///avatar/animations/side_step_left.fbx", - "startFrame": 0.0, + "startFrame": 1.0, "endFrame": 20.0, "timeScale": 1.0, "loopFlag": true @@ -1830,7 +1955,7 @@ "type": "clip", "data": { "url": "qrc:///avatar/animations/side_step_left_fast.fbx", - "startFrame": 0.0, + "startFrame": 1.0, "endFrame": 16.0, "timeScale": 1.0, "loopFlag": true @@ -1855,8 +1980,8 @@ "type": "clip", "data": { "url": "qrc:///avatar/animations/side_step_short_left.fbx", - "startFrame": 0.0, - "endFrame": 29.0, + "startFrame": 1.0, + "endFrame": 30.0, "timeScale": 1.0, "loopFlag": true, "mirrorFlag": true @@ -1868,7 +1993,7 @@ "type": "clip", "data": { "url": "qrc:///avatar/animations/side_step_left.fbx", - "startFrame": 0.0, + "startFrame": 1.0, "endFrame": 20.0, "timeScale": 1.0, "loopFlag": true, @@ -1881,7 +2006,7 @@ "type": "clip", "data": { "url": "qrc:///avatar/animations/side_step_left_fast.fbx", - "startFrame": 0.0, + "startFrame": 1.0, "endFrame": 16.0, "timeScale": 1.0, "loopFlag": true, @@ -1897,7 +2022,7 @@ "data": { "url": "qrc:///avatar/animations/fly.fbx", "startFrame": 1.0, - "endFrame": 80.0, + "endFrame": 79.0, "timeScale": 1.0, "loopFlag": true }, @@ -1907,8 +2032,8 @@ "id": "takeoffStand", "type": "clip", "data": { - "url": "qrc:///avatar/animations/jump_standing_launch.fbx", - "startFrame": 2.0, + "url": "qrc:///avatar/animations/jump_standing_launch_all.fbx", + "startFrame": 1.0, "endFrame": 16.0, "timeScale": 1.0, "loopFlag": false @@ -1919,7 +2044,7 @@ "id": "TAKEOFFRUN", "type": "clip", "data": { - "url": "qrc:///avatar/animations/jump_running_launch_land.fbx", + "url": "qrc:///avatar/animations/jump_running_launch_land_all.fbx", "startFrame": 4.0, "endFrame": 15.0, "timeScale": 1.0, @@ -1939,9 +2064,9 @@ "id": "inAirStandPreApex", "type": "clip", "data": { - "url": "qrc:///avatar/animations/jump_standing_apex.fbx", - "startFrame": 0.0, - "endFrame": 0.0, + "url": "qrc:///avatar/animations/jump_standing_apex_all.fbx", + "startFrame": 1.0, + "endFrame": 1.0, "timeScale": 1.0, "loopFlag": false }, @@ -1951,9 +2076,9 @@ "id": "inAirStandApex", "type": "clip", "data": { - "url": "qrc:///avatar/animations/jump_standing_apex.fbx", - "startFrame": 1.0, - "endFrame": 1.0, + "url": "qrc:///avatar/animations/jump_standing_apex_all.fbx", + "startFrame": 2.0, + "endFrame": 2.0, "timeScale": 1.0, "loopFlag": false }, @@ -1963,9 +2088,9 @@ "id": "inAirStandPostApex", "type": "clip", "data": { - "url": "qrc:///avatar/animations/jump_standing_apex.fbx", - "startFrame": 2.0, - "endFrame": 2.0, + "url": "qrc:///avatar/animations/jump_standing_apex_all.fbx", + "startFrame": 3.0, + "endFrame": 3.0, "timeScale": 1.0, "loopFlag": false }, @@ -1985,7 +2110,7 @@ "id": "inAirRunPreApex", "type": "clip", "data": { - "url": "qrc:///avatar/animations/jump_running_launch_land.fbx", + "url": "qrc:///avatar/animations/jump_running_launch_land_all.fbx", "startFrame": 16.0, "endFrame": 16.0, "timeScale": 1.0, @@ -1997,7 +2122,7 @@ "id": "inAirRunApex", "type": "clip", "data": { - "url": "qrc:///avatar/animations/jump_running_launch_land.fbx", + "url": "qrc:///avatar/animations/jump_running_launch_land_all.fbx", "startFrame": 22.0, "endFrame": 22.0, "timeScale": 1.0, @@ -2009,7 +2134,7 @@ "id": "inAirRunPostApex", "type": "clip", "data": { - "url": "qrc:///avatar/animations/jump_running_launch_land.fbx", + "url": "qrc:///avatar/animations/jump_running_launch_land_all.fbx", "startFrame": 33.0, "endFrame": 33.0, "timeScale": 1.0, @@ -2023,7 +2148,7 @@ "id": "landStandImpact", "type": "clip", "data": { - "url": "qrc:///avatar/animations/jump_standing_land_settle.fbx", + "url": "qrc:///avatar/animations/jump_standing_land_settle_all.fbx", "startFrame": 1.0, "endFrame": 6.0, "timeScale": 1.0, @@ -2035,7 +2160,7 @@ "id": "landStand", "type": "clip", "data": { - "url": "qrc:///avatar/animations/jump_standing_land_settle.fbx", + "url": "qrc:///avatar/animations/jump_standing_land_settle_all.fbx", "startFrame": 6.0, "endFrame": 68.0, "timeScale": 1.0, @@ -2047,7 +2172,7 @@ "id": "LANDRUN", "type": "clip", "data": { - "url": "qrc:///avatar/animations/jump_running_launch_land.fbx", + "url": "qrc:///avatar/animations/jump_running_launch_land_all.fbx", "startFrame": 29.0, "endFrame": 40.0, "timeScale": 1.0, @@ -2078,8 +2203,8 @@ "type": "clip", "data": { "url": "qrc:///avatar/animations/idle.fbx", - "startFrame": 0.0, - "endFrame": 90.0, + "startFrame": 1.0, + "endFrame": 300.0, "timeScale": 1.0, "loopFlag": true }, @@ -2090,8 +2215,8 @@ "type": "clip", "data": { "url": "qrc:///avatar/animations/idle.fbx", - "startFrame": 0.0, - "endFrame": 90.0, + "startFrame": 1.0, + "endFrame": 300.0, "timeScale": 1.0, "loopFlag": true }, @@ -2099,4 +2224,4 @@ } ] } -} +} \ No newline at end of file diff --git a/interface/resources/qml/InteractiveWindow.qml b/interface/resources/qml/InteractiveWindow.qml index df3475ea7b..9136de9dcf 100644 --- a/interface/resources/qml/InteractiveWindow.qml +++ b/interface/resources/qml/InteractiveWindow.qml @@ -31,6 +31,8 @@ Windows.Window { signal selfDestruct(); property var flags: 0; + property var additionalFlags: 0; + property var overrideFlags: 0; property var source; property var dynamicContent; @@ -153,10 +155,11 @@ Windows.Window { Qt.WindowMaximizeButtonHint | Qt.WindowMinimizeButtonHint; // only use the always on top feature for non Windows OS - if (Qt.platform.os !== "windows" && (flags & Desktop.ALWAYS_ON_TOP)) { + if (Qt.platform.os !== "windows" && (root.additionalFlags & Desktop.ALWAYS_ON_TOP)) { nativeWindowFlags |= Qt.WindowStaysOnTopHint; } - nativeWindow.flags = nativeWindowFlags; + root.flags = root.overrideFlags || nativeWindowFlags; + nativeWindow.flags = root.flags; nativeWindow.x = interactiveWindowPosition.x; nativeWindow.y = interactiveWindowPosition.y; @@ -225,10 +228,41 @@ Windows.Window { // Handle message traffic from our loaded QML to the script that launched us signal sendToScript(var message); + // Children of this InteractiveWindow Item are able to request a new width and height + // for the parent Item (this one) and its associated C++ InteractiveWindow using these methods. + function onRequestNewWidth(newWidth) { + interactiveWindowSize.width = newWidth; + updateInteractiveWindowSizeForMode(); + } + function onRequestNewHeight(newWidth) { + interactiveWindowSize.width = newWidth; + updateInteractiveWindowSizeForMode(); + } + + // These signals are used to forward key-related events from the QML to the C++. + signal keyPressEvent(int key, int modifiers); + signal keyReleaseEvent(int key, int modifiers); + onDynamicContentChanged: { if (dynamicContent && dynamicContent.sendToScript) { dynamicContent.sendToScript.connect(sendToScript); } + + if (dynamicContent && dynamicContent.requestNewWidth) { + dynamicContent.requestNewWidth.connect(onRequestNewWidth); + } + + if (dynamicContent && dynamicContent.requestNewHeight) { + dynamicContent.requestNewHeight.connect(onRequestNewHeight); + } + + if (dynamicContent && dynamicContent.keyPressEvent) { + dynamicContent.keyPressEvent.connect(keyPressEvent); + } + + if (dynamicContent && dynamicContent.keyReleaseEvent) { + dynamicContent.keyReleaseEvent.connect(keyReleaseEvent); + } } onInteractiveWindowVisibleChanged: { @@ -283,7 +317,7 @@ Windows.Window { // set invisible on close, to make it not re-appear unintended after switching PresentationMode interactiveWindowVisible = false; - if ((flags & Desktop.CLOSE_BUTTON_HIDES) !== Desktop.CLOSE_BUTTON_HIDES) { + if ((root.flags & Desktop.CLOSE_BUTTON_HIDES) !== Desktop.CLOSE_BUTTON_HIDES) { selfDestruct(); } } diff --git a/interface/resources/qml/hifi/NameCard.qml b/interface/resources/qml/hifi/NameCard.qml index 7e8218b7df..2cf07e32bf 100644 --- a/interface/resources/qml/hifi/NameCard.qml +++ b/interface/resources/qml/hifi/NameCard.qml @@ -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 diff --git a/interface/resources/qml/hifi/simplifiedUI/emoteApp/bar/EmoteAppBar.qml b/interface/resources/qml/hifi/simplifiedUI/emoteApp/bar/EmoteAppBar.qml new file mode 100644 index 0000000000..fd1d245033 --- /dev/null +++ b/interface/resources/qml/hifi/simplifiedUI/emoteApp/bar/EmoteAppBar.qml @@ -0,0 +1,101 @@ +// +// EmoteAppBar.qml +// +// Created by Zach Fox on 2019-07-08 +// Copyright 2019 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +import QtQuick 2.10 +import QtQuick.Controls 2.3 +import "../../simplifiedConstants" as SimplifiedConstants +import "../../simplifiedControls" as SimplifiedControls +import stylesUit 1.0 as HifiStylesUit +import TabletScriptingInterface 1.0 + +Rectangle { + id: root + color: simplifiedUI.colors.white + anchors.fill: parent + + property int originalWidth: 48 + property int hoveredWidth: 480 + property int requestedWidth + + onRequestedWidthChanged: { + root.requestNewWidth(root.requestedWidth); + } + + Behavior on requestedWidth { + enabled: true + SmoothedAnimation { duration: 220 } + } + + SimplifiedConstants.SimplifiedConstants { + id: simplifiedUI + } + + MouseArea { + anchors.fill: parent + hoverEnabled: enabled + onEntered: { + Tablet.playSound(TabletEnums.ButtonHover); + root.requestedWidth = root.hoveredWidth; + } + onExited: { + Tablet.playSound(TabletEnums.ButtonClick); + root.requestedWidth = root.originalWidth; + } + } + + Rectangle { + id: mainEmojiContainer + z: 2 + color: simplifiedUI.colors.darkBackground + anchors.top: parent.top + anchors.left: parent.left + height: parent.height + width: root.originalWidth + + HifiStylesUit.GraphikRegular { + text: "😊" + anchors.horizontalCenter: parent.horizontalCenter + anchors.verticalCenter: parent.verticalCenter + anchors.horizontalCenterOffset: -2 + anchors.verticalCenterOffset: -2 + horizontalAlignment: Text.AlignHCenter + size: 26 + color: simplifiedUI.colors.text.almostWhite + } + } + + Rectangle { + id: drawerContainer + z: 1 + color: simplifiedUI.colors.white + anchors.top: parent.top + anchors.right: parent.right + height: parent.height + width: root.hoveredWidth + + HifiStylesUit.GraphikRegular { + text: "Emotes go here." + anchors.fill: parent + horizontalAlignment: Text.AlignHCenter + size: 20 + color: simplifiedUI.colors.text.black + } + } + + function fromScript(message) { + switch (message.method) { + default: + console.log('EmoteAppBar.qml: Unrecognized message from JS'); + break; + } + } + signal sendToScript(var message); + signal requestNewWidth(int newWidth); +} diff --git a/interface/resources/qml/hifi/simplifiedUI/settingsApp/about/About.qml b/interface/resources/qml/hifi/simplifiedUI/settingsApp/about/About.qml index 3e3758e7a8..d562aae70d 100644 --- a/interface/resources/qml/hifi/simplifiedUI/settingsApp/about/About.qml +++ b/interface/resources/qml/hifi/simplifiedUI/settingsApp/about/About.qml @@ -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: "Audio Input: " + 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: "Audio Output: " + 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); diff --git a/interface/resources/qml/hifi/simplifiedUI/simplifiedConstants/SimplifiedConstants.qml b/interface/resources/qml/hifi/simplifiedUI/simplifiedConstants/SimplifiedConstants.qml index 30b2c5a111..bc27dbad5f 100644 --- a/interface/resources/qml/hifi/simplifiedUI/simplifiedConstants/SimplifiedConstants.qml +++ b/interface/resources/qml/hifi/simplifiedUI/simplifiedConstants/SimplifiedConstants.qml @@ -18,6 +18,7 @@ QtObject { readonly property color white: "#FFFFFF" readonly property color lightBlue: "#00B4EF" readonly property color lightBlueHover: "#3dcfff" + readonly property color black: "#000000" } readonly property QtObject controls: QtObject { diff --git a/interface/resources/qml/hifi/simplifiedUI/topBar/SimplifiedTopBar.qml b/interface/resources/qml/hifi/simplifiedUI/topBar/SimplifiedTopBar.qml index 61d2fd6634..822e485940 100644 --- a/interface/resources/qml/hifi/simplifiedUI/topBar/SimplifiedTopBar.qml +++ b/interface/resources/qml/hifi/simplifiedUI/topBar/SimplifiedTopBar.qml @@ -76,10 +76,20 @@ Rectangle { return; } - if (walletStatus === 5) { - topBarInventoryModel.getFirstPage(); - } else { - // Show some error to the user + switch (walletStatus) { + case 1: + var randomNumber = Math.floor(Math.random() * 34) + 1; + var securityImagePath = "images/" + randomNumber.toString().padStart(2, '0') + ".jpg"; + Commerce.getWalletAuthenticatedStatus(); // before writing security image, ensures that salt/account password is set. + Commerce.chooseSecurityImage(securityImagePath); + Commerce.generateKeyPair() + Commerce.getWalletStatus(); + break; + case 5: + topBarInventoryModel.getFirstPage(); + break; + default: + console.log('WARNING: SimplifiedTopBar.qml walletStatusResult:', walletStatus); } } diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 8ecb16b65f..b59fd223ba 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -548,6 +548,13 @@ public: return true; } + if (message->message == WM_POWERBROADCAST) { + if (message->wParam == PBT_APMRESUMEAUTOMATIC) { + qCInfo(interfaceapp) << "Waking up from sleep or hybernation."; + QMetaObject::invokeMethod(DependencyManager::get().data(), "noteAwakening", Qt::QueuedConnection); + } + } + if (message->message == WM_COPYDATA) { COPYDATASTRUCT* pcds = (COPYDATASTRUCT*)(message->lParam); QUrl url = QUrl((const char*)(pcds->lpData)); @@ -832,6 +839,8 @@ bool setupEssentials(int& argc, char** argv, bool runningMarkerExisted) { QCoreApplication::addLibraryPath(audioDLLPath); #endif + QString defaultScriptsOverrideOption = getCmdOption(argc, constArgv, "--defaultScriptsOverride"); + DependencyManager::registerInheritance(); DependencyManager::registerInheritance(); DependencyManager::registerInheritance(); @@ -853,7 +862,7 @@ bool setupEssentials(int& argc, char** argv, bool runningMarkerExisted) { DependencyManager::set(std::bind(&Application::getUserAgent, qApp)); #endif DependencyManager::set(); - DependencyManager::set(ScriptEngine::CLIENT_SCRIPT); + DependencyManager::set(ScriptEngine::CLIENT_SCRIPT, defaultScriptsOverrideOption); DependencyManager::set(); DependencyManager::set(); DependencyManager::set(); @@ -1345,9 +1354,22 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo connect(this, &QCoreApplication::aboutToQuit, addressManager.data(), &AddressManager::storeCurrentAddress); connect(this, &Application::activeDisplayPluginChanged, this, &Application::updateThreadPoolCount); - connect(this, &Application::activeDisplayPluginChanged, this, [](){ + connect(this, &Application::activeDisplayPluginChanged, this, [=](){ qApp->setProperty(hifi::properties::HMD, qApp->isHMDMode()); auto displayPlugin = qApp->getActiveDisplayPlugin(); + + if (displayPlugin->isHmd()) { + if (_preferredCursor.get() == Cursor::Manager::getIconName(Cursor::Icon::RETICLE)) { + setPreferredCursor(Cursor::Manager::getIconName(Cursor::Icon::RETICLE)); + } + else { + setPreferredCursor(Cursor::Manager::getIconName(Cursor::Icon::ARROW)); + } + } + else { + setPreferredCursor(Cursor::Manager::getIconName(Cursor::Icon::SYSTEM)); + } + setCrashAnnotation("display_plugin", displayPlugin->getName().toStdString()); setCrashAnnotation("hmd", displayPlugin->isHmd() ? "1" : "0"); }); @@ -1452,6 +1474,9 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo _saveAvatarOverrideUrl = true; } + // setDefaultFormat has no effect after the platform window has been created, so call it here. + QSurfaceFormat::setDefaultFormat(getDefaultOpenGLSurfaceFormat()); + _glWidget = new GLCanvas(); getApplicationCompositor().setRenderingWidget(_glWidget); _window->setCentralWidget(_glWidget); @@ -4148,6 +4173,13 @@ bool Application::event(QEvent* event) { case QEvent::FocusOut: focusOutEvent(static_cast(event)); return true; + case QEvent::FocusIn: + { //testing to see if we can set focus when focus is not set to root window. + _glWidget->activateWindow(); + _glWidget->setFocus(); + return true; + } + case QEvent::TouchBegin: touchBeginEvent(static_cast(event)); event->accept(); @@ -5109,7 +5141,7 @@ void Application::idle() { // If the offscreen Ui has something active that is NOT the root, then assume it has keyboard focus. if (offscreenUi && offscreenUi->getWindow()) { auto activeFocusItem = offscreenUi->getWindow()->activeFocusItem(); - if (_keyboardDeviceHasFocus && activeFocusItem != offscreenUi->getRootItem()) { + if (_keyboardDeviceHasFocus && (activeFocusItem != NULL && activeFocusItem != offscreenUi->getRootItem())) { _keyboardMouseDevice->pluginFocusOutEvent(); _keyboardDeviceHasFocus = false; synthesizeKeyReleasEvents(); @@ -5393,12 +5425,10 @@ void Application::loadSettings() { } bool isFirstPerson = false; - if (_firstRun.get()) { - // If this is our first run, and no preferred devices were set, default to - // an HMD device if available. + if (arguments().contains("--no-launcher")) { auto displayPlugins = pluginManager->getDisplayPlugins(); for (auto& plugin : displayPlugins) { - if (plugin->isHmd()) { + if (!plugin->isHmd()) { if (auto action = menu->getActionForOption(plugin->getName())) { action->setChecked(true); action->trigger(); @@ -5406,18 +5436,31 @@ void Application::loadSettings() { } } } - isFirstPerson = (qApp->isHMDMode()); - } else { - // if this is not the first run, the camera will be initialized differently depending on user settings - - if (qApp->isHMDMode()) { - // if the HMD is active, use first-person camera, unless the appropriate setting is checked - isFirstPerson = menu->isOptionChecked(MenuOption::FirstPersonHMD); + if (_firstRun.get()) { + // If this is our first run, and no preferred devices were set, default to + // an HMD device if available. + auto displayPlugins = pluginManager->getDisplayPlugins(); + for (auto& plugin : displayPlugins) { + if (plugin->isHmd()) { + if (auto action = menu->getActionForOption(plugin->getName())) { + action->setChecked(true); + action->trigger(); + break; + } + } + } + isFirstPerson = (qApp->isHMDMode()); } else { - // if HMD is not active, only use first person if the menu option is checked - isFirstPerson = menu->isOptionChecked(MenuOption::FirstPerson); + // if this is not the first run, the camera will be initialized differently depending on user settings + if (qApp->isHMDMode()) { + // if the HMD is active, use first-person camera, unless the appropriate setting is checked + isFirstPerson = menu->isOptionChecked(MenuOption::FirstPersonHMD); + } else { + // if HMD is not active, only use first person if the menu option is checked + isFirstPerson = menu->isOptionChecked(MenuOption::FirstPerson); + } } } @@ -7864,7 +7907,7 @@ void Application::showAssetServerWidget(QString filePath) { if (!hmd->getShouldShowTablet() && !isHMDMode()) { getOffscreenUI()->show(url, "AssetServer", startUpload); } else { - static const QUrl url("hifi/dialogs/TabletAssetServer.qml"); + static const QUrl url("qrc:///qml/hifi/dialogs/TabletAssetServer.qml"); if (!tablet->isPathLoaded(url)) { tablet->pushOntoStack(url); } @@ -8756,6 +8799,8 @@ bool Application::isThrottleRendering() const { bool Application::hasFocus() const { bool result = (QApplication::activeWindow() != nullptr); + + #if defined(Q_OS_WIN) // On Windows, QWidget::activateWindow() - as called in setFocus() - makes the application's taskbar icon flash but doesn't // take user focus away from their current window. So also check whether the application is the user's current foreground diff --git a/interface/src/PerformanceManager.cpp b/interface/src/PerformanceManager.cpp index 0a028f95cc..ec12ab0404 100644 --- a/interface/src/PerformanceManager.cpp +++ b/interface/src/PerformanceManager.cpp @@ -10,6 +10,8 @@ // #include "PerformanceManager.h" +#include +#include #include #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()->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()->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()->setWorldDetailQuality(0.75f); break; diff --git a/interface/src/graphics/WorldBox.cpp b/interface/src/graphics/WorldBox.cpp index a28850207f..648d6d3177 100644 --- a/interface/src/graphics/WorldBox.cpp +++ b/interface/src/graphics/WorldBox.cpp @@ -108,8 +108,8 @@ void WorldBoxRenderData::renderWorldBox(RenderArgs* args, gpu::Batch& batch) { glm::vec3(HALF_TREE_SCALE, 0.0f, HALF_TREE_SCALE), GREY, geometryIds[17]); - - geometryCache->renderWireCubeInstance(args, batch, GREY4); + auto pipeline = geometryCache->getShapePipelinePointer(false, false, args->_renderMethod == render::Args::RenderMethod::FORWARD); + geometryCache->renderWireCubeInstance(args, batch, GREY4, pipeline); // Draw meter markers along the 3 axis to help with measuring things const float MARKER_DISTANCE = 1.0f; @@ -117,22 +117,22 @@ void WorldBoxRenderData::renderWorldBox(RenderArgs* args, gpu::Batch& batch) { transform = Transform().setScale(MARKER_RADIUS); batch.setModelTransform(transform); - geometryCache->renderSolidSphereInstance(args, batch, RED); + geometryCache->renderSolidSphereInstance(args, batch, RED, pipeline); transform = Transform().setTranslation(glm::vec3(MARKER_DISTANCE, 0.0f, 0.0f)).setScale(MARKER_RADIUS); batch.setModelTransform(transform); - geometryCache->renderSolidSphereInstance(args, batch, RED); + geometryCache->renderSolidSphereInstance(args, batch, RED, pipeline); transform = Transform().setTranslation(glm::vec3(0.0f, MARKER_DISTANCE, 0.0f)).setScale(MARKER_RADIUS); batch.setModelTransform(transform); - geometryCache->renderSolidSphereInstance(args, batch, GREEN); + geometryCache->renderSolidSphereInstance(args, batch, GREEN, pipeline); transform = Transform().setTranslation(glm::vec3(0.0f, 0.0f, MARKER_DISTANCE)).setScale(MARKER_RADIUS); batch.setModelTransform(transform); - geometryCache->renderSolidSphereInstance(args, batch, BLUE); + geometryCache->renderSolidSphereInstance(args, batch, BLUE, pipeline); transform = Transform().setTranslation(glm::vec3(MARKER_DISTANCE, 0.0f, MARKER_DISTANCE)).setScale(MARKER_RADIUS); batch.setModelTransform(transform); - geometryCache->renderSolidSphereInstance(args, batch, GREY); + geometryCache->renderSolidSphereInstance(args, batch, GREY, pipeline); } diff --git a/interface/src/main.cpp b/interface/src/main.cpp index 3fd65f452c..f6ce1ec8ad 100644 --- a/interface/src/main.cpp +++ b/interface/src/main.cpp @@ -86,6 +86,7 @@ int main(int argc, const char* argv[]) { QCommandLineOption responseTokensOption("tokens", "set response tokens ", "json"); QCommandLineOption displayNameOption("displayName", "set user display name ", "string"); QCommandLineOption setBookmarkOption("setBookmark", "set bookmark key=value pair", "string"); + QCommandLineOption defaultScriptOverrideOption("defaultScriptsOverride", "override defaultsScripts.js", "string"); parser.addOption(urlOption); parser.addOption(noLauncherOption); @@ -99,6 +100,7 @@ int main(int argc, const char* argv[]) { parser.addOption(responseTokensOption); parser.addOption(displayNameOption); parser.addOption(setBookmarkOption); + parser.addOption(defaultScriptOverrideOption); if (!parser.parse(arguments)) { std::cout << parser.errorText().toStdString() << std::endl; // Avoid Qt log spam diff --git a/interface/src/octree/SafeLanding.cpp b/interface/src/octree/SafeLanding.cpp index c358df746b..75e512232b 100644 --- a/interface/src/octree/SafeLanding.cpp +++ b/interface/src/octree/SafeLanding.cpp @@ -19,6 +19,11 @@ const int SafeLanding::SEQUENCE_MODULO = std::numeric_limits::max() + 1; +CalculateEntityLoadingPriority SafeLanding::entityLoadingOperatorElevateCollidables = [](const EntityItem& entityItem) { + const int COLLIDABLE_ENTITY_PRIORITY = 10.0f; + return entityItem.getCollisionless() * COLLIDABLE_ENTITY_PRIORITY; +}; + namespace { template bool lessThanWraparound(int a, int b) { constexpr int MAX_T_VALUE = std::numeric_limits::max(); @@ -52,7 +57,8 @@ void SafeLanding::startTracking(QSharedPointer entityTreeRen connect(std::const_pointer_cast(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(); diff --git a/interface/src/octree/SafeLanding.h b/interface/src/octree/SafeLanding.h index 2f1db2366f..87dac16ba3 100644 --- a/interface/src/octree/SafeLanding.h +++ b/interface/src/octree/SafeLanding.h @@ -20,6 +20,8 @@ #include "EntityItem.h" #include "EntityDynamicInterface.h" +#include "EntityTreeRenderer.h" + class EntityTreeRenderer; class EntityItemID; @@ -64,8 +66,8 @@ private: std::set _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; }; diff --git a/interface/src/raypick/LaserPointerScriptingInterface.h b/interface/src/raypick/LaserPointerScriptingInterface.h index 425ffd7de4..6c5ce0dbaf 100644 --- a/interface/src/raypick/LaserPointerScriptingInterface.h +++ b/interface/src/raypick/LaserPointerScriptingInterface.h @@ -21,121 +21,146 @@ class LaserPointerScriptingInterface : public QObject, public Dependency { SINGLETON_DEPENDENCY /**jsdoc - * Synonym for {@link Pointers} as used for laser pointers. Deprecated. + * The LaserPointers 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. + * + *

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. + *

Warning: Pointers created using this method currently always intersect at least visible and + * collidable things but this may not always be the case.

* @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 0. */ 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()->enablePointer(uid); } - /**jsdoc - * @function LaserPointers.disableLaserPointer - * @param {number} id - */ + // jsdoc @borrows from Pointers Q_INVOKABLE void disableLaserPointer(unsigned int uid) const { DependencyManager::get()->disablePointer(uid); } - /**jsdoc - * @function LaserPointers.removeLaserPointer - * @param {number} id - */ + // jsdoc @borrows from Pointers Q_INVOKABLE void removeLaserPointer(unsigned int uid) const { DependencyManager::get()->removePointer(uid); } /**jsdoc + * Edits a render state of a pointer, to change its visual appearance for the state when the pointer is intersecting + * something. + *

Note: You can only edit the properties of the existing parts of the pointer; you cannot change the + * type of any part.

+ *

Note: You cannot use this method to change the appearance of a default render state.

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

The name of the render state to set the pointer to. This may be:

+ *
    + *
  • The name of one of the render states set in the pointer's properties.
  • + *
  • "", to hide the pointer and disable emitting of events.
  • + *
+ * @param {number} id - The ID of the pointer. */ Q_INVOKABLE void setRenderState(unsigned int uid, const QString& renderState) const { DependencyManager::get()->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()->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()->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 - true if the target is an avatar, false 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()->setLockEndUUID(uid, objectID, isAvatar, offsetMat); } /**jsdoc + * Checks if a pointer is associated with the left hand: a pointer with joint property set to + * "_CONTROLLER_LEFTHAND" or "_CAMERA_RELATIVE_CONTROLLER_LEFTHAND". * @function LaserPointers.isLeftHand - * @param {number} id - * @returns {boolean} + * @param {number} id - The ID of the pointer. + * @returns {boolean} true if the pointer is associated with the left hand, false if it isn't. */ Q_INVOKABLE bool isLeftHand(unsigned int uid) { return DependencyManager::get()->isLeftHand(uid); } /**jsdoc + * Checks if a pointer is associated with the right hand: a pointer with joint property set to + * "_CONTROLLER_RIGHTHAND" or "_CAMERA_RELATIVE_CONTROLLER_RIGHTHAND". * @function LaserPointers.isRightHand - * @param {number} id - * @returns {boolean} + * @param {number} id - The ID of the pointer. + * @returns {boolean} true if the pointer is associated with the right hand, false if it isn't. */ Q_INVOKABLE bool isRightHand(unsigned int uid) { return DependencyManager::get()->isRightHand(uid); } /**jsdoc + * Checks if a pointer is associated with the system mouse: a pointer with joint property set to + * "Mouse". * @function LaserPointers.isMouse - * @param {number} id - * @returns {boolean} + * @param {number} id - The ID of the pointer. + * @returns {boolean} true if the pointer is associated with the system mouse, false if it isn't. */ Q_INVOKABLE bool isMouse(unsigned int uid) { return DependencyManager::get()->isMouse(uid); } }; diff --git a/interface/src/raypick/PickScriptingInterface.cpp b/interface/src/raypick/PickScriptingInterface.cpp index 82d00d803f..12f68c1430 100644 --- a/interface/src/raypick/PickScriptingInterface.cpp +++ b/interface/src/raypick/PickScriptingInterface.cpp @@ -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] - true if this pick should start enabled, false 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] 0 for the left hand, 1 for the right hand, invalid (-1) @@ -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] - true if this pick should start enabled, false 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] - true if this pick should start enabled, false if it should diff --git a/interface/src/raypick/PickScriptingInterface.h b/interface/src/raypick/PickScriptingInterface.h index d8654e2a13..473413ca58 100644 --- a/interface/src/raypick/PickScriptingInterface.h +++ b/interface/src/raypick/PickScriptingInterface.h @@ -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 PICK_PRECISE or PICK_COARSE 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. *

Note: Not used by stylus picks.

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

Note: Stylus picks only intersect with objects in their include list.

+ * Sets a list of entity and avatar IDs that a pick should include during intersection, instead of intersecting with + * everything. + *

Note: Stylus picks only intersect with items in their include list.

* @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 - * "_CONTROLLER_LEFTHAND" or "_CAMERA_RELATIVE_CONTROLLER_LEFTHAND", or a stylus pick with hand - * set to 0. + * Checks if a pick is associated with the left hand: a ray or parabola pick with joint property set to + * "_CONTROLLER_LEFTHAND" or "_CAMERA_RELATIVE_CONTROLLER_LEFTHAND", or a stylus pick with + * hand property set to 0. * @function Picks.isLeftHand * @param {number} id - The ID of the pick. * @returns {boolean} true if the pick is associated with the left hand, false 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 - * "_CONTROLLER_RIGHTHAND" or "_CAMERA_RELATIVE_CONTROLLER_RIGHTHAND", or a stylus pick with hand - * set to 1. + * Checks if a pick is associated with the right hand: a ray or parabola pick with joint property set to + * "_CONTROLLER_RIGHTHAND" or "_CAMERA_RELATIVE_CONTROLLER_RIGHTHAND", or a stylus pick with + * hand property set to 1. * @function Picks.isRightHand * @param {number} id - The ID of the pick. * @returns {boolean} true if the pick is associated with the right hand, false 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 "Mouse". + * Checks if a pick is associated with the system mouse: a ray or parabola pick with joint property set to + * "Mouse". * @function Picks.isMouse * @param {number} id - The ID of the pick. * @returns {boolean} true if the pick is associated with the system mouse, false if it isn't. diff --git a/interface/src/raypick/PointerScriptingInterface.cpp b/interface/src/raypick/PointerScriptingInterface.cpp index 1c80caff88..f1dcf7bd5d 100644 --- a/interface/src/raypick/PointerScriptingInterface.cpp +++ b/interface/src/raypick/PointerScriptingInterface.cpp @@ -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] - true if the pointer generates {@link Entities} hover events, + * false 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 type 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 type field), which must be "line3d". - * 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 type 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] + *

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 type property must be specified.

+ *

When getting using {@link Pointers.getPointerProperties}, the ID of the overlay rendered at the start of the ray; + * null if there is no overlay. + * + * @property {Overlays.OverlayProperties|Uuid} [path] + *

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 type property must be specified and be + * "line3d".

+ *

When getting using {@link Pointers.getPointerProperties}, the ID of the overlay rendered for the path of the ray; + * null if there is no overlay. + * + * @property {Overlays.OverlayProperties|Uuid} [end] + *

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 type property must be specified.

+ *

When getting using {@link Pointers.getPointerProperties}, the ID of the overlay rendered at the end of the ray; + * null 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. 0-1. If 0 or 1, - * the normal will follow exactly. - * @property {boolean} [enabled=false] - * @property {Pointers.RayPointerRenderState[]|Object.} [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.} [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] - true if the overlay rendered at the end of the ray rotates about the + * world y-axis to always face the avatar; false if it maintains its world orientation. + * @property {boolean} [centerEndY=true] - true if the overlay rendered at the end of the ray is centered on + * the ray end; false if the overlay is positioned against the surface if followNormal is + * true, or above the ray end if followNormal is false. +* @property {boolean} [lockEnd=false] - true if the end of the ray is locked to the center of the object at + * which the ray is pointing; false if the end of the ray is at the intersected surface. + * @property {boolean} [distanceScaleEnd=false] - true if the dimensions of the overlay at the end of the ray + * scale linearly with distance; false if they aren't. + * @property {boolean} [scaleWithParent=false] - true 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; false if they don't scale. + * @property {boolean} [scaleWithAvatar=false] - A synonym for scalewithParent. + *

Deprecated: This property is deprecated and will be removed.

+ * @property {boolean} [followNormal=false] - true if the overlay rendered at the end of the ray rotates to + * follow the normal of the surface if one is intersected; false 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 0 or 1, the overlay rotation follows instantaneously; + * for other values, the larger the value the more quickly the rotation follows. + * @property {Pointers.RayPointerRenderState[]|Object.} [renderStates] + *

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.

+ *

When setting using {@link Pointers.createPointer}, an array of + * {@link Pointers.RayPointerRenderState|RayPointerRenderState} values.

+ *

When getting using {@link Pointers.getPointerProperties}, an object mapping render state names to + * {@link Pointers.RayPointerRenderState|RayPointerRenderState} values.

+ * @property {Pointers.DefaultRayPointerRenderState[]|Object.} + * [defaultRenderStates] + *

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.

+ *

When setting using {@link Pointers.createPointer}, an array of + * {@link Pointers.DefaultRayPointerRenderState|DefaultRayPointerRenderState} values.

+ *

When getting using {@link Pointers.getPointerProperties}, an object mapping render state names to + * {@link Pointers.DefaultRayPointerRenderState|DefaultRayPointerRenderState} values.

+ * @property {boolean} [hover=false] - true if the pointer generates {@link Entities} hover events, + * false 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 true, 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 0.01.0. + * @property {number} [width=0.01] - The width of the parabola, in meters. + * @property {boolean} [isVisibleInSecondaryCamera=false] - true if the parabola is rendered in the secondary + * camera, false if it isn't. + * @property {boolean} [drawInFront=false] - true if the parabola is rendered in front of objects in the world, + * but behind the HUD, false 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 type 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 type 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] + *

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 type property must be specified.

+ *

When getting using {@link Pointers.getPointerProperties}, the ID of the overlay rendered at the start of the + * parabola; null if there is no overlay. + * @property {Pointers.ParabolaPointerPath|Uuid} [path] + *

When creating or editing using {@link Pointers.createPointer} or {@link Pointers.editRenderState}, the properties of + * the rendered path of the parabola pointer.

+ *

This property is not provided when getting using {@link Pointers.getPointerProperties}. + * @property {Overlays.OverlayProperties|Uuid} [end] + *

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 type property must be specified.

+ *

When getting using {@link Pointers.getPointerProperties}, the ID of the overlay rendered at the end of the parabola; + * null 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. 0-1. If 0 or 1, -* the normal will follow exactly. -* @property {boolean} [enabled=false] -* @property {Pointers.ParabolaPointerRenderState[]|Object.} [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.} [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] - true if the overlay rendered at the end of the ray rotates about the + * world y-axis to always face the avatar; false if it maintains its world orientation. + * @property {boolean} [centerEndY=true] - true if the overlay rendered at the end of the ray is centered on + * the ray end; false if the overlay is positioned against the surface if followNormal is + * true, or above the ray end if followNormal is false. +* @property {boolean} [lockEnd=false] - true if the end of the ray is locked to the center of the object at + * which the ray is pointing; false if the end of the ray is at the intersected surface. + * @property {boolean} [distanceScaleEnd=false] - true if the dimensions of the overlay at the end of the ray + * scale linearly with distance; false if they aren't. + * @property {boolean} [scaleWithParent=false] - true 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; false if they don't scale. + * @property {boolean} [scaleWithAvatar=false] - A synonym for scalewithParent. + *

Deprecated: This property is deprecated and will be removed.

+ * @property {boolean} [followNormal=false] - true if the overlay rendered at the end of the ray rotates to + * follow the normal of the surface if one is intersected; false 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 0 or 1, the overlay rotation follows instantaneously; + * for other values, the larger the value the more quickly the rotation follows. + * @property {Pointers.ParabolaPointerRenderState[]|Object.} [renderStates] + *

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.

+ *

When setting using {@link Pointers.createPointer}, an array of + * {@link Pointers.ParabolaPointerRenderState|ParabolaPointerRenderState} values.

+ *

When getting using {@link Pointers.getPointerProperties}, an object mapping render state names to + * {@link Pointers.ParabolaPointerRenderState|ParabolaPointerRenderState} values.

+ * @property {Pointers.DefaultParabolaPointerRenderState[]|Object.} + * [defaultRenderStates] + *

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.

+ *

When setting using {@link Pointers.createPointer}, an array of + * {@link Pointers.DefaultParabolaPointerRenderState|DefaultParabolaPointerRenderState} values.

+ *

When getting using {@link Pointers.getPointerProperties}, an object mapping render state names to + * {@link Pointers.DefaultParabolaPointerRenderState|DefaultParabolaPointerRenderState} values.

+ * @property {boolean} [hover=false] - true if the pointer generates {@link Entities} hover events, + * false 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(); diff --git a/interface/src/raypick/PointerScriptingInterface.h b/interface/src/raypick/PointerScriptingInterface.h index 268b178fb6..e6efaae09f 100644 --- a/interface/src/raypick/PointerScriptingInterface.h +++ b/interface/src/raypick/PointerScriptingInterface.h @@ -15,8 +15,9 @@ #include /**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 Pointers 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 button. - * @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 >= 1.0 to start the action + * and < 1.0 to terminate the action. + * @property {string} button - Which button to trigger. + *
    + *
  • "Primary", "Secondary", and "Tertiary" cause {@link Entities} and + * {@link Overlays} mouse pointer events. Other button names also cause mouse events but the button + * property in the event will be "None".
  • + *
  • "Focus" will try to give focus to the entity or overlay which the pointer is intersecting.
  • + *
+ */ /**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. + *

Warning: Pointers created using this method currently always intersect at least visible and + * collidable things but this may not always be the case.

* @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 and 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 type, 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 0. * - * @example Create a left hand Ray Pointer that triggers events on left controller trigger click and changes color when it's intersecting something. - * - * var end = { + * @example Create a ray pointer on the left hand that changes color when it's intersecting and that triggers + * events.
+ * Note: Stop controllerScripts.js from running to disable similar behavior from it. + * 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()->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()->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()->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. + *

Note: You can only edit the properties of the existing parts of the pointer; you cannot change the + * type of any part.

+ *

Note: You cannot use this method to change the appearance of a default render state.

+ *

Note: Not able to be used with stylus pointers.

* @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 renderStates 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 Change the dimensions of a ray pointer's intersecting end overlay. + * 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 -

The name of the render state to set the pointer to.

+ *

For {@link Pointers.RayPointerProperties|ray} and {@link Pointers.ParabolaPointerProperties|parabola} pointers, + * this may be:

+ *
    + *
  • The name of one of the render states set in the pointer's properties.
  • + *
  • "", to hide the pointer and disable emitting of events.
  • + *
+ *

For {@link Pointers.StylusPointerProperties|stylus} pointers, the values may be:

+ *
    + *
  • "events on", to render and emit events (the default).
  • + *
  • "events off", to render but don't emit events.
  • + *
  • "disabled", to not render and not emit events.
  • + *
+ * @example Switch a ray pointer between having a path and not having a path. + * 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()->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 PICK_PRECISE or PICK_COARSE 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 - true to use precision picking, false to use coarse picking. */ Q_INVOKABLE void setPrecisionPicking(unsigned int uid, bool precisionPicking) const { DependencyManager::get()->setPrecisionPicking(uid, precisionPicking); } /**jsdoc - * Sets the length of this Pointer. No effect on Stylus Pointers. + * Sets the length of a pointer. + *

Note: Not used by stylus pointers.

* @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()->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. + *

Note: Not used by stylus pointers.

* @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 only 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. + *

Note: Stylus pointers only intersect with items in their include list.

* @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. + *

Note: Not used by stylus pointers.

* @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 - true if the target is an avatar, false 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()->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 joint property set to + * "_CONTROLLER_LEFTHAND" or "_CAMERA_RELATIVE_CONTROLLER_LEFTHAND", or a stylus pointer with + * hand property set to 0. * @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} true if the pointer is associated with the left hand, false if it isn't. */ Q_INVOKABLE bool isLeftHand(unsigned int uid) { return DependencyManager::get()->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 joint property set to + * "_CONTROLLER_RIGHTHAND" or "_CAMERA_RELATIVE_CONTROLLER_RIGHTHAND", or a stylus pointer with + * hand property set to 1. * @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} true if the pointer is associated with the right hand, false if it isn't. */ Q_INVOKABLE bool isRightHand(unsigned int uid) { return DependencyManager::get()->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 joint property set + * to "Mouse". * @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} true if the pointer is associated with the system mouse, false if it isn't. */ Q_INVOKABLE bool isMouse(unsigned int uid) { return DependencyManager::get()->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 renderStates and + * defaultRenderStates for ray and parabola pointers, {} for stylus pointers. + * @example Report the properties of a parabola pointer. + * 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; }; diff --git a/interface/src/raypick/RayPickScriptingInterface.h b/interface/src/raypick/RayPickScriptingInterface.h index 41972ca52d..204407e92d 100644 --- a/interface/src/raypick/RayPickScriptingInterface.h +++ b/interface/src/raypick/RayPickScriptingInterface.h @@ -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 - true to use precision picking, false 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 - * "_CONTROLLER_LEFTHAND" or "_CAMERA_RELATIVE_CONTROLLER_LEFTHAND", or a stylus pick with hand - * set to 0. + * Checks if a pick is associated with the left hand: a ray or parabola pick with joint property set to + * "_CONTROLLER_LEFTHAND" or "_CAMERA_RELATIVE_CONTROLLER_LEFTHAND", or a stylus pick with + * hand property set to 0. * @function RayPick.isLeftHand * @param {number} id - The ID of the ray pick. * @returns {boolean} true if the pick is associated with the left hand, false 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 - * "_CONTROLLER_RIGHTHAND" or "_CAMERA_RELATIVE_CONTROLLER_RIGHTHAND", or a stylus pick with hand - * set to 1. + * Checks if a pick is associated with the right hand: a ray or parabola pick with joint property set to + * "_CONTROLLER_RIGHTHAND" or "_CAMERA_RELATIVE_CONTROLLER_RIGHTHAND", or a stylus pick with + * hand property set to 1. * @function RayPick.isRightHand * @param {number} id - The ID of the ray pick. * @returns {boolean} true if the pick is associated with the right hand, false 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 "Mouse". + * Checks if a pick is associated with the system mouse: a ray or parabola pick with joint property set to + * "Mouse". * @function RayPick.isMouse * @param {number} id - The ID of the ray pick. * @returns {boolean} true if the pick is associated with the system mouse, false if it isn't. diff --git a/interface/src/scripting/PlatformInfoScriptingInterface.cpp b/interface/src/scripting/PlatformInfoScriptingInterface.cpp index 84c4d923d0..cbd94b3dd5 100644 --- a/interface/src/scripting/PlatformInfoScriptingInterface.cpp +++ b/interface/src/scripting/PlatformInfoScriptingInterface.cpp @@ -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()); diff --git a/interface/src/scripting/PlatformInfoScriptingInterface.h b/interface/src/scripting/PlatformInfoScriptingInterface.h index 113509d6d9..9ac67ec0bd 100644 --- a/interface/src/scripting/PlatformInfoScriptingInterface.h +++ b/interface/src/scripting/PlatformInfoScriptingInterface.h @@ -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: diff --git a/interface/src/ui/AnimStats.cpp b/interface/src/ui/AnimStats.cpp index d4696a8c04..47116ea281 100644 --- a/interface/src/ui/AnimStats.cpp +++ b/interface/src/ui/AnimStats.cpp @@ -132,7 +132,7 @@ void AnimStats::updateStats(bool force) { if (type == AnimNodeType::Clip) { // figure out the grayScale color of this line. - const float LIT_TIME = 2.0f; + const float LIT_TIME = 20.0f; const float FADE_OUT_TIME = 1.0f; float grayScale = 0.0f; float secondsElapsed = (float)(now - _animAlphaValueChangedTimers[key]) / (float)USECS_PER_SECOND; @@ -176,7 +176,7 @@ void AnimStats::updateStats(bool force) { } // figure out the grayScale color of this line. - const float LIT_TIME = 2.0f; + const float LIT_TIME = 20.0f; const float FADE_OUT_TIME = 0.5f; float grayScale = 0.0f; float secondsElapsed = (float)(now - _animVarChangedTimers[key]) / (float)USECS_PER_SECOND; diff --git a/interface/src/ui/InteractiveWindow.cpp b/interface/src/ui/InteractiveWindow.cpp index 84d24ddeae..dfef16b536 100644 --- a/interface/src/ui/InteractiveWindow.cpp +++ b/interface/src/ui/InteractiveWindow.cpp @@ -32,7 +32,8 @@ static auto CONTENT_WINDOW_QML = QUrl("InteractiveWindow.qml"); -static const char* const FLAGS_PROPERTY = "flags"; +static const char* const ADDITIONAL_FLAGS_PROPERTY = "additionalFlags"; +static const char* const OVERRIDE_FLAGS_PROPERTY = "overrideFlags"; static const char* const SOURCE_PROPERTY = "source"; static const char* const TITLE_PROPERTY = "title"; static const char* const POSITION_PROPERTY = "position"; @@ -92,8 +93,12 @@ void InteractiveWindow::forwardKeyReleaseEvent(int key, int modifiers) { * @property {InteractiveWindow.PresentationWindowInfo} [presentationWindowInfo] - Controls how a NATIVE window is * displayed. If used, the window is docked to the specified edge of the Interface window, otherwise the window is * displayed as its own separate window. - * @property {InteractiveWindow.Flags} [flags=0] - Window behavior flags, set at window creation. Possible flag values are - * provided as {@link Desktop|Desktop.ALWAYS_ON_TOP} and {@link Desktop|Desktop.CLOSE_BUTTON_HIDES}. + * @property {InteractiveWindow.AdditionalFlags} [additionalFlags=0] - Window behavior flags in addition to "native window flags" (minimize/maximize/close), + * set at window creation. Possible flag values are provided as {@link Desktop|Desktop.ALWAYS_ON_TOP} and {@link Desktop|Desktop.CLOSE_BUTTON_HIDES}. + * Additional flag values can be found on Qt's website at https://doc.qt.io/qt-5/qt.html#WindowType-enum. + * @property {InteractiveWindow.OverrideFlags} [overrideFlags=0] - Window behavior flags instead of the default window flags. + * Set at window creation. Possible flag values are provided as {@link Desktop|Desktop.ALWAYS_ON_TOP} and {@link Desktop|Desktop.CLOSE_BUTTON_HIDES}. + * Additional flag values can be found on Qt's website at https://doc.qt.io/qt-5/qt.html#WindowType-enum. */ InteractiveWindow::InteractiveWindow(const QString& sourceUrl, const QVariantMap& properties) { InteractiveWindowPresentationMode presentationMode = InteractiveWindowPresentationMode::Native; @@ -179,8 +184,11 @@ InteractiveWindow::InteractiveWindow(const QString& sourceUrl, const QVariantMap offscreenUi->loadInNewContext(CONTENT_WINDOW_QML, [&](QQmlContext* context, QObject* object) { _qmlWindow = object; context->setContextProperty(EVENT_BRIDGE_PROPERTY, this); - if (properties.contains(FLAGS_PROPERTY)) { - object->setProperty(FLAGS_PROPERTY, properties[FLAGS_PROPERTY].toUInt()); + if (properties.contains(ADDITIONAL_FLAGS_PROPERTY)) { + object->setProperty(ADDITIONAL_FLAGS_PROPERTY, properties[ADDITIONAL_FLAGS_PROPERTY].toUInt()); + } + if (properties.contains(OVERRIDE_FLAGS_PROPERTY)) { + object->setProperty(OVERRIDE_FLAGS_PROPERTY, properties[OVERRIDE_FLAGS_PROPERTY].toUInt()); } if (properties.contains(PRESENTATION_MODE_PROPERTY)) { object->setProperty(PRESENTATION_MODE_PROPERTY, properties[PRESENTATION_MODE_PROPERTY].toInt()); @@ -201,6 +209,10 @@ InteractiveWindow::InteractiveWindow(const QString& sourceUrl, const QVariantMap } connect(object, SIGNAL(sendToScript(QVariant)), this, SLOT(qmlToScript(const QVariant&)), Qt::QueuedConnection); + QObject::connect(object, SIGNAL(keyPressEvent(int, int)), this, SLOT(forwardKeyPressEvent(int, int)), + Qt::QueuedConnection); + QObject::connect(object, SIGNAL(keyReleaseEvent(int, int)), this, SLOT(forwardKeyReleaseEvent(int, int)), + Qt::QueuedConnection); connect(object, SIGNAL(interactiveWindowPositionChanged()), this, SIGNAL(positionChanged()), Qt::QueuedConnection); connect(object, SIGNAL(interactiveWindowSizeChanged()), this, SIGNAL(sizeChanged()), Qt::QueuedConnection); connect(object, SIGNAL(interactiveWindowVisibleChanged()), this, SIGNAL(visibleChanged()), Qt::QueuedConnection); diff --git a/interface/src/ui/Snapshot.cpp b/interface/src/ui/Snapshot.cpp index d97c401351..926588e4ca 100644 --- a/interface/src/ui/Snapshot.cpp +++ b/interface/src/ui/Snapshot.cpp @@ -143,10 +143,6 @@ void Snapshot::save360Snapshot(const glm::vec3& cameraPosition, secondaryCameraRenderConfig->enableSecondaryCameraRenderConfigs(true); } - // Initialize some secondary camera render config options for 360 snapshot capture - static_cast(qApp->getRenderEngine()->getConfiguration()->getConfig("SecondaryCameraJob.ToneMapping")) - ->setCurve(0); - secondaryCameraRenderConfig->resetSizeSpectatorCamera(static_cast(CUBEMAP_SIDE_PIXEL_DIMENSION), static_cast(CUBEMAP_SIDE_PIXEL_DIMENSION)); secondaryCameraRenderConfig->setProperty("attachedEntityId", ""); @@ -209,7 +205,6 @@ void Snapshot::takeNextSnapshot() { // Reset secondary camera render config SecondaryCameraJobConfig* config = static_cast(qApp->getRenderEngine()->getConfiguration()->getConfig("SecondaryCamera")); - static_cast(qApp->getRenderEngine()->getConfiguration()->getConfig("SecondaryCameraJob.ToneMapping"))->setCurve(1); config->resetSizeSpectatorCamera(qApp->getWindow()->geometry().width(), qApp->getWindow()->geometry().height()); config->setProperty("attachedEntityId", _oldAttachedEntityId); config->setProperty("vFoV", _oldvFoV); diff --git a/launchers/darwin/nib/ProcessScreen.xib b/launchers/darwin/nib/ProcessScreen.xib index d6a1da91c9..d16d71e5fa 100644 --- a/launchers/darwin/nib/ProcessScreen.xib +++ b/launchers/darwin/nib/ProcessScreen.xib @@ -22,12 +22,12 @@ - + - + @@ -36,7 +36,7 @@ - + @@ -49,6 +49,10 @@ + + + + @@ -56,6 +60,7 @@ + diff --git a/launchers/darwin/src/CustomUI.h b/launchers/darwin/src/CustomUI.h index a9d93d03c7..a5e27f5c1b 100644 --- a/launchers/darwin/src/CustomUI.h +++ b/launchers/darwin/src/CustomUI.h @@ -25,6 +25,6 @@ extern NSString* hifiBackgroundFilename; @end @interface Hyperlink : NSTextField { - + } @end diff --git a/launchers/darwin/src/CustomUI.m b/launchers/darwin/src/CustomUI.m index 156efe04d5..61f92fe51f 100644 --- a/launchers/darwin/src/CustomUI.m +++ b/launchers/darwin/src/CustomUI.m @@ -24,19 +24,19 @@ NSString* hifiBackgroundFilename = @"hifi_window"; [NSApp sendAction:(NSSelectorFromString(@"paste:")) to:nil from:self]; return TRUE; } - + if ([[event charactersIgnoringModifiers] isEqualToString:@"c"]) { [NSApp sendAction:(NSSelectorFromString(@"copy:")) to:nil from:self]; return TRUE; } - + if ([[event charactersIgnoringModifiers] isEqualToString:@"a"]) { [NSApp sendAction:(NSSelectorFromString(@"selectAll:")) to:nil from:self]; return TRUE; } } } - + return [super performKeyEquivalent:event]; } @@ -46,7 +46,7 @@ NSString* hifiBackgroundFilename = @"hifi_window"; NSTextView *fieldEditor = (NSTextView*)[self.window fieldEditor:YES forObject:self]; fieldEditor.insertionPointColor = insertionPointColor; - + } -(BOOL)becomeFirstResponder @@ -75,7 +75,7 @@ NSString* hifiBackgroundFilename = @"hifi_window"; NSTextView *fieldEditor = (NSTextView*)[self.window fieldEditor:YES forObject:self]; fieldEditor.insertionPointColor = insertionPointColor; - + } @@ -97,19 +97,19 @@ NSString* hifiBackgroundFilename = @"hifi_window"; [NSApp sendAction:(NSSelectorFromString(@"paste:")) to:nil from:self]; return TRUE; } - + if ([[event charactersIgnoringModifiers] isEqualToString:@"c"]) { [NSApp sendAction:(NSSelectorFromString(@"copy:")) to:nil from:self]; return TRUE; } - + if ([[event charactersIgnoringModifiers] isEqualToString:@"a"]) { [NSApp sendAction:(NSSelectorFromString(@"selectAll:")) to:nil from:self]; return TRUE; } } } - + return [super performKeyEquivalent:event]; } @end @@ -126,7 +126,7 @@ NSString* hifiBackgroundFilename = @"hifi_window"; - (void)awakeFromNib { [super awakeFromNib]; - + self.wantsLayer = YES; self.layer.backgroundColor = [NSColor blackColor].CGColor; self.layer.borderColor = [NSColor whiteColor].CGColor; @@ -134,16 +134,16 @@ NSString* hifiBackgroundFilename = @"hifi_window"; self.layer.masksToBounds = YES; _titleLayer = [[CATextLayer alloc] init]; - + CGSize buttonSize = self.frame.size; CGSize titleSize = [self.title sizeWithAttributes:@{NSFontAttributeName: self.font}]; CGFloat x = (buttonSize.width - titleSize.width) / 2.0; // Title's origin x CGFloat y = (buttonSize.height - titleSize.height) / 2.0; // Title's origin y - + self.titleLayer.frame = NSMakeRect(round(x), round(y), ceil(titleSize.width), ceil(titleSize.height)); self.titleLayer.string = self.title; self.titleLayer.foregroundColor = [NSColor whiteColor].CGColor; - + // TODO(huffman) Fix this to be dynamic based on screen? self.titleLayer.contentsScale = 2.0; @@ -151,7 +151,7 @@ NSString* hifiBackgroundFilename = @"hifi_window"; self.titleLayer.fontSize = self.font.pointSize; //self.titleLayer.allowsEdgeAntialiasing = YES; //self.titleLayer.allowsFontSubpixelQuantization = YES; - + [self.layer addSublayer:self.titleLayer]; } diff --git a/launchers/darwin/src/DownloadDomainContent.h b/launchers/darwin/src/DownloadDomainContent.h index c35c8b8f09..80d03fd1c8 100644 --- a/launchers/darwin/src/DownloadDomainContent.h +++ b/launchers/darwin/src/DownloadDomainContent.h @@ -2,7 +2,10 @@ @interface DownloadDomainContent : NSObject { } - +@property (nonatomic, assign) double progressPercentage; +@property (nonatomic, assign) double taskProgressPercentage; - (void) downloadDomainContent:(NSString*) domainContentUrl; +- (double) getProgressPercentage; + @end diff --git a/launchers/darwin/src/DownloadDomainContent.m b/launchers/darwin/src/DownloadDomainContent.m index 170ee1d43b..f95ae39fc8 100644 --- a/launchers/darwin/src/DownloadDomainContent.m +++ b/launchers/darwin/src/DownloadDomainContent.m @@ -3,8 +3,15 @@ @implementation DownloadDomainContent +- (double) getProgressPercentage +{ + return (self.progressPercentage * 0.70) + (self.taskProgressPercentage * 0.30); +} + - (void) downloadDomainContent:(NSString *)domainContentUrl { + self.progressPercentage = 0.0; + self.taskProgressPercentage = 0.0; NSURLRequest* request = [NSURLRequest requestWithURL:[NSURL URLWithString:domainContentUrl] cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:60.0]; @@ -17,7 +24,10 @@ -(void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didWriteData:(int64_t)bytesWritten totalBytesWritten:(int64_t)totalBytesWritten totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite { CGFloat prog = (float)totalBytesWritten/totalBytesExpectedToWrite; - NSLog(@"domain content downloaded %d%%", (int)(100.0*prog)); + NSLog(@"domain content downloaded %f", (100.0*prog)); + + self.progressPercentage = (int)(100.0 * prog); + [[Launcher sharedLauncher] updateProgressIndicator]; } @@ -27,6 +37,11 @@ -(void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didFinishDownloadingToURL:(NSURL *)location { NSLog(@"Did finish downloading to url"); + NSTimer* timer = [NSTimer scheduledTimerWithTimeInterval: 0.1 + target: self + selector: @selector(updatePercentage:) + userInfo:nil + repeats: YES]; NSError *error = nil; NSFileManager *fileManager = [NSFileManager defaultManager]; NSString *destinationFileName = downloadTask.originalRequest.URL.lastPathComponent; @@ -47,6 +62,7 @@ if (error) { NSLog(@"DownlodDomainContent: failed to move file to destintation -> error: %@", error); + [timer invalidate]; [sharedLauncher displayErrorPage]; return; } @@ -55,18 +71,33 @@ BOOL extractionSuccessful = [sharedLauncher extractZipFileAtDestination:[[sharedLauncher getDownloadPathForContentAndScripts] stringByAppendingString:@"content"] :[[sharedLauncher getDownloadPathForContentAndScripts] stringByAppendingString:[sharedLauncher getDownloadContentFilename]]]; if (!extractionSuccessful) { + [timer invalidate]; [sharedLauncher displayErrorPage]; return; } NSLog(@"finished extracting content file"); + [timer invalidate]; + self.taskProgressPercentage = 100.0; + [sharedLauncher updateProgressIndicator]; [sharedLauncher domainContentDownloadFinished]; } --(void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error { +- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error { NSLog(@"completed; error: %@", error); if (error) { [[Launcher sharedLauncher] displayErrorPage]; } } +- (void) updatePercentage:(NSTimer*) timer { + if (self.taskProgressPercentage < 100.0) { + self.taskProgressPercentage += 1.5; + + if (self.taskProgressPercentage > 100.0) { + self.taskProgressPercentage = 100.0; + } + } + [[Launcher sharedLauncher] updateProgressIndicator]; +} + @end diff --git a/launchers/darwin/src/DownloadInterface.h b/launchers/darwin/src/DownloadInterface.h index 08968f19f0..9d90688654 100644 --- a/launchers/darwin/src/DownloadInterface.h +++ b/launchers/darwin/src/DownloadInterface.h @@ -3,6 +3,10 @@ @interface DownloadInterface : NSObject { } @property (nonatomic, assign) NSString* finalFilePath; +@property (nonatomic, assign) double progressPercentage; +@property (nonatomic, assign) double taskProgressPercentage; - (void) downloadInterface:(NSString*) downloadUrl; + +- (double) getProgressPercentage; @end diff --git a/launchers/darwin/src/DownloadInterface.m b/launchers/darwin/src/DownloadInterface.m index 28980310c5..f0bdb645da 100644 --- a/launchers/darwin/src/DownloadInterface.m +++ b/launchers/darwin/src/DownloadInterface.m @@ -6,6 +6,8 @@ - (void) downloadInterface:(NSString*) downloadUrl { + self.progressPercentage = 0.0; + self.taskProgressPercentage = 0.0; NSURLRequest* request = [NSURLRequest requestWithURL:[NSURL URLWithString:downloadUrl] cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:60.0]; @@ -21,6 +23,14 @@ CGFloat prog = (float)totalBytesWritten/totalBytesExpectedToWrite; NSLog(@"interface downloaded %d%%", (int)(100.0*prog)); + self.progressPercentage = (100.0 * prog); + [[Launcher sharedLauncher] updateProgressIndicator]; + +} + +- (double) getProgressPercentage +{ + return (self.progressPercentage * 0.70) + (self.taskProgressPercentage * 0.30); } -(void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didResumeAtOffset:(int64_t)fileOffset expectedTotalBytes:(int64_t)expectedTotalBytes { @@ -29,6 +39,11 @@ -(void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didFinishDownloadingToURL:(NSURL *)location { NSLog(@"Did finish downloading to url"); + NSTimer* timer = [NSTimer scheduledTimerWithTimeInterval: 0.1 + target: self + selector: @selector(updateTaskPercentage:) + userInfo:nil + repeats: YES]; NSError *error = nil; NSFileManager *fileManager = [NSFileManager defaultManager]; NSString *destinationFileName = downloadTask.originalRequest.URL.lastPathComponent; @@ -44,6 +59,7 @@ if (error) { NSLog(@"Download Interface: failed to move file to destination -> error: %@", error); + [timer invalidate]; [sharedLauncher displayErrorPage]; return; } @@ -54,6 +70,7 @@ NSLog(@"extract interface zip"); BOOL success = [sharedLauncher extractZipFileAtDestination:appPath :[appPath stringByAppendingString:downloadFileName]]; if (!success) { + [timer invalidate]; [sharedLauncher displayErrorPage]; return; } @@ -71,6 +88,9 @@ NSString* launcherPath = [appPath stringByAppendingString:@"Launcher"]; [[Settings sharedSettings] setLauncherPath:launcherPath]; + [timer invalidate]; + self.taskProgressPercentage = 100.0; + [sharedLauncher updateProgressIndicator]; [sharedLauncher interfaceFinishedDownloading]; } @@ -81,5 +101,16 @@ } } +- (void) updateTaskPercentage:(NSTimer*) timer { + if (self.taskProgressPercentage < 100.0) { + self.taskProgressPercentage += 1.5; + + if (self.taskProgressPercentage > 100.0) { + self.taskProgressPercentage = 100.0; + } + } + [[Launcher sharedLauncher] updateProgressIndicator]; +} + @end diff --git a/launchers/darwin/src/ErrorViewController.m b/launchers/darwin/src/ErrorViewController.m index 0ae321763f..84dee95678 100644 --- a/launchers/darwin/src/ErrorViewController.m +++ b/launchers/darwin/src/ErrorViewController.m @@ -20,7 +20,7 @@ -(IBAction)resartLauncher:(id)sender { - [[Launcher sharedLauncher] showLoginScreen]; + [[Launcher sharedLauncher] restart]; } @end diff --git a/launchers/darwin/src/LatestBuildRequest.m b/launchers/darwin/src/LatestBuildRequest.m index 767c67eea1..deb6d9795b 100644 --- a/launchers/darwin/src/LatestBuildRequest.m +++ b/launchers/darwin/src/LatestBuildRequest.m @@ -32,13 +32,18 @@ // We're using an ephermeral session here to ensure the tags api response is never cached. NSURLSession * session = [NSURLSession sessionWithConfiguration:NSURLSessionConfiguration.ephemeralSessionConfiguration]; NSURLSessionDataTask* dataTask = [session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) { - - NSLog(@"Latest Build Request error: %@", error); NSLog(@"Latest Build Request Data: %@", data); NSHTTPURLResponse *ne = (NSHTTPURLResponse *)response; NSLog(@"Latest Build Request Response: %ld", [ne statusCode]); Launcher* sharedLauncher = [Launcher sharedLauncher]; + + if ([ne statusCode] == 500) { + dispatch_async(dispatch_get_main_queue(), ^{ + [sharedLauncher displayErrorPage]; + }); + return; + } NSMutableData* webData = [NSMutableData data]; [webData appendData:data]; NSString* jsonString = [[NSString alloc] initWithBytes: [webData mutableBytes] length:[data length] encoding:NSUTF8StringEncoding]; diff --git a/launchers/darwin/src/Launcher.h b/launchers/darwin/src/Launcher.h index 9eb1cbf3b5..de67850bfe 100644 --- a/launchers/darwin/src/Launcher.h +++ b/launchers/darwin/src/Launcher.h @@ -21,6 +21,12 @@ typedef enum LoginErrorTypes CREDENTIALS } LoginError; +struct LatestBuildInfo { + NSString* downloadURL; + BOOL shouldDownload; + BOOL requestBuildFinished; +}; + @interface Launcher : NSObject { } @property (nonatomic, retain) NSString* password; @@ -34,6 +40,7 @@ typedef enum LoginErrorTypes @property (nonatomic, retain) NSString* domainURL; @property (nonatomic, retain) NSString* domainContentUrl; @property (nonatomic, retain) NSString* domainScriptsUrl; +@property (nonatomic, retain) NSString* interfaceDownloadUrl; @property (nonatomic, retain) DownloadInterface* downloadInterface; @property (nonatomic, retain) CredentialsRequest* credentialsRequest; @property (nonatomic, retain) DownloadDomainContent* downloadDomainContent; @@ -44,9 +51,17 @@ typedef enum LoginErrorTypes @property (nonatomic) BOOL waitingForCredentialReponse; @property (nonatomic) BOOL gotCredentialResponse; @property (nonatomic) BOOL waitingForInterfaceToTerminate; +@property (nonatomic) BOOL shouldDownloadInterface; +@property (nonatomic) BOOL latestBuildRequestFinished; +@property (nonatomic, assign) NSTimer* updateProgressIndicatorTimer; @property (nonatomic, assign, readwrite) ProcessState processState; @property (nonatomic, assign, readwrite) LoginError loginError; +@property (nonatomic, assign) NSProgressIndicator* progressIndicator; +@property (nonatomic) double progressTarget; +@property (nonatomic) struct LatestBuildInfo buildInfo; +- (NSProgressIndicator*) getProgressView; +- (void) setProgressView:(NSProgressIndicator*) aProgressIndicator; - (void) displayNameEntered:(NSString*)aDisplayName; - (void) credentialsEntered:(NSString*)aOrginization :(NSString*)aUsername :(NSString*)aPassword; - (void) credentialsAccepted:(BOOL) aCredentialsAccepted; @@ -57,6 +72,7 @@ typedef enum LoginErrorTypes - (BOOL) loginShouldSetErrorState; - (void) displayErrorPage; - (void) showLoginScreen; +- (void) restart; - (NSString*) getLauncherPath; - (ProcessState) currentProccessState; - (void) setCurrentProcessState:(ProcessState) aProcessState; @@ -76,8 +92,13 @@ typedef enum LoginErrorTypes - (NSString*) getDownloadContentFilename; - (NSString*) getDownloadScriptsFilename; - (NSString*) getDownloadFilename; +- (void) startUpdateProgressIndicatorTimer; +- (void) endUpdateProgressIndicatorTimer; - (BOOL) isLoadedIn; - (NSString*) getAppPath; +- (void) updateProgressIndicator; +- (void) setLatestBuildInfo:(struct LatestBuildInfo) latestBuildInfo; +- (struct LatestBuildInfo) getLatestBuildInfo; + (id) sharedLauncher; @end diff --git a/launchers/darwin/src/Launcher.m b/launchers/darwin/src/Launcher.m index 209060d90d..71eb7828e9 100644 --- a/launchers/darwin/src/Launcher.m +++ b/launchers/darwin/src/Launcher.m @@ -17,6 +17,7 @@ static BOOL const DELETE_ZIP_FILES = TRUE; @implementation Launcher + + (id) sharedLauncher { static Launcher* sharedLauncher = nil; static dispatch_once_t onceToken; @@ -35,11 +36,18 @@ static BOOL const DELETE_ZIP_FILES = TRUE; self.latestBuildRequest = [LatestBuildRequest alloc]; self.organizationRequest = [OrganizationRequest alloc]; self.downloadScripts = [DownloadScripts alloc]; + struct LatestBuildInfo latestBuildInfo; + latestBuildInfo.downloadURL = nil; + latestBuildInfo.shouldDownload = FALSE; + latestBuildInfo.requestBuildFinished = FALSE; + self.buildInfo = latestBuildInfo; self.credentialsAccepted = TRUE; self.gotCredentialResponse = FALSE; self.waitingForCredentialReponse = FALSE; self.waitingForInterfaceToTerminate = FALSE; + self.latestBuildRequestFinished = FALSE; self.userToken = nil; + self.progressIndicator = nil; self.processState = DOWNLOADING_INTERFACE; } return self; @@ -79,6 +87,29 @@ static BOOL const DELETE_ZIP_FILES = TRUE; return [[[NSBundle mainBundle] bundlePath] stringByAppendingString:@"/Contents/MacOS/"]; } +- (void) updateProgressIndicator +{ + double contentPercentage = [self.downloadDomainContent getProgressPercentage]; + double interfacePercentage = [self.downloadInterface getProgressPercentage]; + double currentTotalPercentage = self.progressTarget; + if (self.processState == DOWNLOADING_INTERFACE) { + if (self.shouldDownloadInterface) { + currentTotalPercentage = (contentPercentage * 0.5) + (interfacePercentage * 0.5); + } else { + currentTotalPercentage = contentPercentage; + } + } else { + currentTotalPercentage = interfacePercentage; + } + self.progressTarget = currentTotalPercentage; +} + +- (double) lerp:(double) pointA :(double) pointB :(double) interp +{ + double lerpValue = pointA + interp * (pointB - pointA); + return lerpValue; +} + - (BOOL) extractZipFileAtDestination:(NSString *)destination :(NSString*)file { NSTask* task = [[NSTask alloc] init]; @@ -101,6 +132,24 @@ static BOOL const DELETE_ZIP_FILES = TRUE; return TRUE; } +-(void) setProgressView:(NSProgressIndicator*) aProgressIndicator +{ + self.progressIndicator = aProgressIndicator; +} + +-(NSProgressIndicator*) getProgressView +{ + return self.progressIndicator; +} + +- (void) restart +{ + SplashScreen* splashScreen = [[SplashScreen alloc] initWithNibName:@"SplashScreen" bundle:nil]; + [[[[NSApplication sharedApplication] windows] objectAtIndex:0] setContentViewController: splashScreen]; + + [self checkLoginStatus]; +} + - (void) displayErrorPage { ErrorViewController* errorPage = [[ErrorViewController alloc] initWithNibName:@"ErrorScreen" bundle:nil]; @@ -109,19 +158,11 @@ static BOOL const DELETE_ZIP_FILES = TRUE; - (void) checkLoginStatus { - if ([self isLoadedIn]) { - Launcher* sharedLauncher = [Launcher sharedLauncher]; - [sharedLauncher setCurrentProcessState:CHECKING_UPDATE]; - ProcessScreen* processScreen = [[ProcessScreen alloc] initWithNibName:@"ProcessScreen" bundle:nil]; - [[[[NSApplication sharedApplication] windows] objectAtIndex:0] setContentViewController: processScreen]; - [self.latestBuildRequest requestLatestBuildInfo]; - } else { - [NSTimer scheduledTimerWithTimeInterval:2.0 - target:self - selector:@selector(onSplashScreenTimerFinished:) - userInfo:nil - repeats:NO]; - } + [NSTimer scheduledTimerWithTimeInterval:1.0 + target:self + selector:@selector(onSplashScreenTimerFinished:) + userInfo:nil + repeats:NO]; [[NSApplication sharedApplication] activateIgnoringOtherApps:TRUE]; } @@ -145,6 +186,31 @@ static BOOL const DELETE_ZIP_FILES = TRUE; return self.scriptsFilename; } +- (void) startUpdateProgressIndicatorTimer +{ + self.progressTarget = 0.0; + self.updateProgressIndicatorTimer = [NSTimer scheduledTimerWithTimeInterval: 0.0016 + target: self + selector: @selector(updateIndicator:) + userInfo:nil + repeats: YES]; + + [[NSRunLoop mainRunLoop] addTimer:self.updateProgressIndicatorTimer forMode:NSRunLoopCommonModes]; +} + +- (void) endUpdateProgressIndicatorTimer +{ + [self.updateProgressIndicatorTimer invalidate]; + self.updateProgressIndicatorTimer = nil; +} + +- (void) updateIndicator:(NSTimer*) timer +{ + NSProgressIndicator* progressIndicator = [self getProgressView]; + double oldValue = progressIndicator.doubleValue; + progressIndicator.doubleValue = [self lerp:oldValue :self.progressTarget :0.3]; +} + - (void)didTerminateApp:(NSNotification *)notification { if (self.waitingForInterfaceToTerminate) { NSString* appName = [notification.userInfo valueForKey:@"NSApplicationName"]; @@ -199,6 +265,7 @@ static BOOL const DELETE_ZIP_FILES = TRUE; - (void) displayNameEntered:(NSString*)aDiplayName { self.processState = DOWNLOADING_INTERFACE; + [self startUpdateProgressIndicatorTimer]; ProcessScreen* processScreen = [[ProcessScreen alloc] initWithNibName:@"ProcessScreen" bundle:nil]; [[[[NSApplication sharedApplication] windows] objectAtIndex:0] setContentViewController: processScreen]; [self.downloadDomainContent downloadDomainContent:self.domainContentUrl]; @@ -207,8 +274,11 @@ static BOOL const DELETE_ZIP_FILES = TRUE; - (void) domainContentDownloadFinished { - //.[self.downloadScripts downloadScripts:self.domainScriptsUrl]; - [self.latestBuildRequest requestLatestBuildInfo]; + if (self.shouldDownloadInterface) { + [self.downloadInterface downloadInterface: self.interfaceDownloadUrl]; + return; + } + [self interfaceFinishedDownloading]; } - (void) domainScriptsDownloadFinished @@ -235,14 +305,21 @@ static BOOL const DELETE_ZIP_FILES = TRUE; - (void) interfaceFinishedDownloading { - if (self.processState == DOWNLOADING_INTERFACE) { - self.processState = RUNNING_INTERFACE_AFTER_DOWNLOAD; + [self endUpdateProgressIndicatorTimer]; + NSProgressIndicator* progressIndicator = [self getProgressView]; + progressIndicator.doubleValue = self.progressTarget; + Launcher* sharedLauncher = [Launcher sharedLauncher]; + if ([sharedLauncher currentProccessState] == DOWNLOADING_INTERFACE) { + [sharedLauncher setCurrentProcessState: RUNNING_INTERFACE_AFTER_DOWNLOAD]; } else { - self.processState = RUNNING_INTERFACE_AFTER_UPDATE; + [sharedLauncher setCurrentProcessState: RUNNING_INTERFACE_AFTER_UPDATE]; } - ProcessScreen* processScreen = [[ProcessScreen alloc] initWithNibName:@"ProcessScreen" bundle:nil]; - [[[[NSApplication sharedApplication] windows] objectAtIndex:0] setContentViewController: processScreen]; - [self launchInterface]; + + [NSTimer scheduledTimerWithTimeInterval: 0.2 + target: self + selector: @selector(callLaunchInterface:) + userInfo:nil + repeats: NO]; } - (void) credentialsEntered:(NSString*)aOrginization :(NSString*)aUsername :(NSString*)aPassword @@ -269,6 +346,16 @@ static BOOL const DELETE_ZIP_FILES = TRUE; return YES; } +- (struct LatestBuildInfo) getLatestBuildInfo +{ + return self.buildInfo; +} + +- (void) setLatestBuildInfo:(struct LatestBuildInfo) latestBuildInfo +{ + self.buildInfo = latestBuildInfo; +} + -(void) showLoginScreen { LoginScreen* loginScreen = [[LoginScreen alloc] initWithNibName:@"LoginScreen" bundle:nil]; @@ -277,17 +364,29 @@ static BOOL const DELETE_ZIP_FILES = TRUE; - (void) shouldDownloadLatestBuild:(BOOL) shouldDownload :(NSString*) downloadUrl { - if (shouldDownload) { - [self.downloadInterface downloadInterface: downloadUrl]; - return; + self.shouldDownloadInterface = shouldDownload; + self.interfaceDownloadUrl = downloadUrl; + self.latestBuildRequestFinished = TRUE; + if ([self isLoadedIn]) { + Launcher* sharedLauncher = [Launcher sharedLauncher]; + [sharedLauncher setCurrentProcessState:CHECKING_UPDATE]; + if (shouldDownload) { + ProcessScreen* processScreen = [[ProcessScreen alloc] initWithNibName:@"ProcessScreen" bundle:nil]; + [[[[NSApplication sharedApplication] windows] objectAtIndex:0] setContentViewController: processScreen]; + [self startUpdateProgressIndicatorTimer]; + [self.downloadInterface downloadInterface: downloadUrl]; + return; + } + [self interfaceFinishedDownloading]; + } else { + [[NSApplication sharedApplication] activateIgnoringOtherApps:TRUE]; + [self showLoginScreen]; } - [self launchInterface]; } -(void)onSplashScreenTimerFinished:(NSTimer *)timer { - [[NSApplication sharedApplication] activateIgnoringOtherApps:TRUE]; - [self showLoginScreen]; + [self.latestBuildRequest requestLatestBuildInfo]; } -(void)setCurrentProcessState:(ProcessState)aProcessState @@ -369,7 +468,11 @@ static BOOL const DELETE_ZIP_FILES = TRUE; } [workspace launchApplicationAtURL:url options:NSWorkspaceLaunchNewInstance configuration:[NSDictionary dictionaryWithObject:arguments forKey:NSWorkspaceLaunchConfigurationArguments] error:&error]; - [NSApp terminate:self]; + [NSTimer scheduledTimerWithTimeInterval: 3.0 + target: self + selector: @selector(exitLauncher:) + userInfo:nil + repeats: NO]; } - (ProcessState) currentProccessState @@ -377,4 +480,17 @@ static BOOL const DELETE_ZIP_FILES = TRUE; return self.processState; } +- (void) callLaunchInterface:(NSTimer*) timer +{ + ProcessScreen* processScreen = [[ProcessScreen alloc] initWithNibName:@"ProcessScreen" bundle:nil]; + [[[[NSApplication sharedApplication] windows] objectAtIndex:0] setContentViewController: processScreen]; + [self launchInterface]; +} + + +- (void) exitLauncher:(NSTimer*) timer +{ + [NSApp terminate:self]; +} + @end diff --git a/launchers/darwin/src/LoginScreen.m b/launchers/darwin/src/LoginScreen.m index 4c83558160..d654a14f1b 100644 --- a/launchers/darwin/src/LoginScreen.m +++ b/launchers/darwin/src/LoginScreen.m @@ -38,25 +38,25 @@ [self.backgroundImage setImage:[NSImage imageNamed:hifiBackgroundFilename]]; [self.smallLogo setImage:[NSImage imageNamed:hifiSmallLogoFilename]]; - + NSMutableAttributedString* usernameString = [[NSMutableAttributedString alloc] initWithString:@"Username"]; - + [usernameString addAttribute:NSForegroundColorAttributeName value:[NSColor grayColor] range:NSMakeRange(0,8)]; [usernameString addAttribute:NSFontAttributeName value:[NSFont systemFontOfSize:18] range:NSMakeRange(0,8)]; - + NSMutableAttributedString* orgName = [[NSMutableAttributedString alloc] initWithString:@"Organization Name"]; [orgName addAttribute:NSForegroundColorAttributeName value:[NSColor grayColor] range:NSMakeRange(0,17)]; [orgName addAttribute:NSFontAttributeName value:[NSFont systemFontOfSize:18] range:NSMakeRange(0,17)]; - + NSMutableAttributedString* passwordString = [[NSMutableAttributedString alloc] initWithString:@"Password"]; - + [passwordString addAttribute:NSForegroundColorAttributeName value:[NSColor grayColor] range:NSMakeRange(0,8)]; [passwordString addAttribute:NSFontAttributeName value:[NSFont systemFontOfSize:18] range:NSMakeRange(0,8)]; - + [self.username setPlaceholderAttributedString:usernameString]; [self.orginization setPlaceholderAttributedString:orgName]; [self.password setPlaceholderAttributedString:passwordString]; - + [self.password setTarget:self]; [self.password setAction:@selector(goToLogin:)]; } diff --git a/launchers/darwin/src/ProcessScreen.m b/launchers/darwin/src/ProcessScreen.m index 4aeb8abda1..85ec5c8d5b 100644 --- a/launchers/darwin/src/ProcessScreen.m +++ b/launchers/darwin/src/ProcessScreen.m @@ -8,6 +8,7 @@ @property (nonatomic, assign) IBOutlet NSImageView* voxelImage; @property (nonatomic, assign) IBOutlet NSTextField* boldStatus; @property (nonatomic, assign) IBOutlet NSTextField* smallStatus; +@property (nonatomic, assign) IBOutlet NSProgressIndicator* progressView; @end @implementation ProcessScreen @@ -20,6 +21,7 @@ [self.smallStatus setStringValue:@"Set up may take several minutes."]; break; case RUNNING_INTERFACE_AFTER_DOWNLOAD: + [self.progressView setHidden: YES]; [self.boldStatus setStringValue:@"Your new HQ is all setup"]; [self.smallStatus setStringValue:@"Thanks for being patient."]; break; @@ -28,6 +30,7 @@ [self.smallStatus setStringValue:@"We're getting the latest and greatest for you, one sec."]; break; case RUNNING_INTERFACE_AFTER_UPDATE: + [self.progressView setHidden: YES]; [self.boldStatus setStringValue:@"You're good to go!"]; [self.smallStatus setStringValue:@"Thanks for being patient."]; break; @@ -37,10 +40,11 @@ [self.background setImage: [NSImage imageNamed:hifiBackgroundFilename]]; [self.smallLogo setImage: [NSImage imageNamed:hifiSmallLogoFilename]]; [self.voxelImage setImage: [NSImage imageNamed:hifiVoxelFilename]]; + if (self.progressView != nil) { + [sharedLauncher setProgressView: self.progressView]; + } self.imageRotation = 0; - //[self.voxelImage setFrameCenterRotation:90]; - [NSTimer scheduledTimerWithTimeInterval:0.016 target:self selector:@selector(rotateView:) diff --git a/launchers/win32/Launcher.rc b/launchers/win32/Launcher.rc index 4d9e0ffcd6..eb72dced4c 100644 --- a/launchers/win32/Launcher.rc +++ b/launchers/win32/Launcher.rc @@ -21,6 +21,7 @@ #if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +#pragma code_page(1252) #ifdef APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// @@ -91,7 +92,8 @@ STYLE DS_SETFONT | DS_FIXEDSYS | WS_POPUP | WS_VISIBLE | WS_CAPTION EXSTYLE WS_EX_APPWINDOW FONT 10, "MS Shell Dlg", 400, 0, 0x0 BEGIN - CONTROL "",IDC_VOXEL,"Static",SS_BLACKRECT,65,27,174,123 + CONTROL "",IDC_VOXEL,"Static",SS_BLACKRECT,65,3,174,123, NOT WS_VISIBLE + CONTROL "", IDC_PROGRESS, "Static", SS_BLACKRECT, 35, 170, 239, 4, NOT WS_VISIBLE EDITTEXT IDC_ORGNAME,44,68,219,12,ES_AUTOHSCROLL | NOT WS_VISIBLE | NOT WS_BORDER EDITTEXT IDC_USERNAME,44,95,219,12,ES_AUTOHSCROLL | NOT WS_VISIBLE | NOT WS_BORDER EDITTEXT IDC_PASSWORD,44,122,219,12,ES_PASSWORD | ES_AUTOHSCROLL | NOT WS_VISIBLE | NOT WS_BORDER @@ -100,10 +102,10 @@ BEGIN LTEXT "Password",IDC_PASSWORD_BANNER,48,122,219,12,NOT WS_VISIBLE CTEXT "",IDC_MESSAGE_LABEL,5,39,299,23,NOT WS_VISIBLE CTEXT "",IDC_ACTION_LABEL,10,15,286,25,NOT WS_VISIBLE - CTEXT "",IDC_MESSAGE2_LABEL,35,172,239,15,NOT WS_VISIBLE - CTEXT "",IDC_ACTION2_LABEL,15,147,278,25,NOT WS_VISIBLE + CTEXT "",IDC_MESSAGE2_LABEL,35,148,239,15,NOT WS_VISIBLE + CTEXT "",IDC_ACTION2_LABEL,15,123,278,25,NOT WS_VISIBLE RTEXT "",IDC_TERMS,15,172,180,15,NOT WS_VISIBLE - CONTROL "",IDC_TERMS_LINK,"Button", BS_OWNERDRAW | BS_FLAT | NOT WS_VISIBLE | WS_TABSTOP,197,172,80,15 + CONTROL "",IDC_TERMS_LINK,"Button",BS_OWNERDRAW | BS_FLAT | NOT WS_VISIBLE | WS_TABSTOP,197,172,80,15 CTEXT "",IDC_TROUBLE,65,203,174,15,NOT WS_VISIBLE CONTROL "NEXT",IDC_BUTTON_NEXT,"Button",BS_OWNERDRAW | BS_FLAT | NOT WS_VISIBLE | WS_TABSTOP,107,158,94,16 CONTROL "Having Trouble?",IDC_TROUBLE_LINK,"Button",BS_OWNERDRAW | BS_FLAT | NOT WS_VISIBLE | WS_TABSTOP,126,203,56,11 diff --git a/launchers/win32/LauncherApp.cpp b/launchers/win32/LauncherApp.cpp index 4ed20fea13..c15ba75a9b 100644 --- a/launchers/win32/LauncherApp.cpp +++ b/launchers/win32/LauncherApp.cpp @@ -32,19 +32,36 @@ CLauncherApp theApp; // CLauncherApp initialization BOOL CLauncherApp::InitInstance() { - // don't launch if already running - CreateMutex(NULL, TRUE, _T("HQ_Launcher_Mutex")); - if (GetLastError() == ERROR_ALREADY_EXISTS) { - return FALSE; + // 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); - if (iNumOfArgs > 1 && CString(pArgs[1]).Compare(_T("--uninstall")) == 0) { + bool isUninstalling = false; + bool isRestarting = false; + if (iNumOfArgs > 1) { + if (CString(pArgs[1]).Compare(_T("--uninstall")) == 0) { + isUninstalling = true; + } else if (CString(pArgs[1]).Compare(_T("--restart")) == 0) { + isRestarting = true; + } + } + if (!isRestarting) { + // don't launch if already running + CreateMutex(NULL, TRUE, _T("HQ_Launcher_Mutex")); + if (GetLastError() == ERROR_ALREADY_EXISTS) { + return FALSE; + } + } + + if (isUninstalling) { _manager.uninstall(); } else { _manager.init(); } - if (!_manager.installLauncher()) { + if (!_manager.hasFailed() && !_manager.installLauncher()) { return FALSE; } installFont(IDR_FONT_REGULAR); diff --git a/launchers/win32/LauncherDlg.cpp b/launchers/win32/LauncherDlg.cpp index a4fe9e494b..704a2f3050 100644 --- a/launchers/win32/LauncherDlg.cpp +++ b/launchers/win32/LauncherDlg.cpp @@ -9,6 +9,7 @@ // #include "stdafx.h" +#include #include "LauncherApp.h" #include "LauncherDlg.h" @@ -109,8 +110,10 @@ BOOL CLauncherDlg::OnInitDialog() { m_trouble = (CStatic *)GetDlgItem(IDC_TROUBLE); m_voxel = (CStatic *)GetDlgItem(IDC_VOXEL); + m_progress = (CStatic *)GetDlgItem(IDC_PROGRESS); m_voxel->EnableD2DSupport(); + m_progress->EnableD2DSupport(); m_pRenderTarget = GetRenderTarget(); @@ -119,22 +122,58 @@ 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; } else if (pMsg->wParam == VK_RETURN) { OnNextClicked(); return TRUE; + } else if (pMsg->wParam == VK_ESCAPE) { + theApp._manager.onCancel(); } + break; + case WM_LBUTTONDOWN: + if (pMsg->hwnd == GetSafeHwnd()) { + _draggingWindow = true; + _dragOffset = getMouseCoords(pMsg); + SetCapture(); + } + break; + case WM_LBUTTONUP: + if (_draggingWindow) { + ReleaseCapture(); + _draggingWindow = false; + } + break; + case WM_MOUSEMOVE: + if (_draggingWindow) { + POINT pos = getMouseCoords(pMsg); + RECT windowRect; + GetWindowRect(&windowRect); + int width = windowRect.right - windowRect.left; + int height = windowRect.bottom - windowRect.top; + ClientToScreen(&pos); + MoveWindow(pos.x - _dragOffset.x, pos.y - _dragOffset.y, width, height, FALSE); + } + break; + default: + break; } return CDialog::PreTranslateMessage(pMsg); } @@ -174,19 +213,11 @@ void CLauncherDlg::startProcess() { theApp._manager.addToLog(_T("Starting Process Setup")); setDrawDialog(DrawStep::DrawProcessSetup); } - theApp._manager.addToLog(_T("Deleting directories before install")); - - CString installDir; - theApp._manager.getAndCreatePaths(LauncherManager::PathType::Interface_Directory, installDir); + theApp._manager.addToLog(_T("Deleting download directory")); CString downloadDir; theApp._manager.getAndCreatePaths(LauncherManager::PathType::Download_Directory, downloadDir); - - LauncherUtils::deleteDirectoriesOnThread(installDir, downloadDir, [&](int error) { - LauncherUtils::DeleteDirError deleteError = (LauncherUtils::DeleteDirError)error; - switch(error) { - case LauncherUtils::DeleteDirError::NoErrorDeleting: - theApp._manager.addToLog(_T("Install directory deleted.")); - theApp._manager.addToLog(_T("Downloads directory deleted.")); + LauncherUtils::deleteDirectoryOnThread(downloadDir, [&](bool error) { + if (!error) { if (!theApp._manager.isLoggedIn()) { theApp._manager.addToLog(_T("Downloading Content")); theApp._manager.downloadContent(); @@ -194,20 +225,12 @@ void CLauncherDlg::startProcess() { theApp._manager.addToLog(_T("Downloading App")); theApp._manager.downloadApplication(); } - break; - case LauncherUtils::DeleteDirError::ErrorDeletingBothDirs: - theApp._manager.addToLog(_T("Error deleting directories.")); - break; - case LauncherUtils::DeleteDirError::ErrorDeletingApplicationDir: - theApp._manager.addToLog(_T("Error deleting application directory.")); - break; - case LauncherUtils::DeleteDirError::ErrorDeletingDownloadsDir: - theApp._manager.addToLog(_T("Error deleting downloads directory.")); - break; - default: - break; + } else { + theApp._manager.addToLog(_T("Error deleting download directory.")); + theApp._manager.setFailed(true); } }); + } BOOL CLauncherDlg::getHQInfo(const CString& orgname) { @@ -230,13 +253,26 @@ afx_msg void CLauncherDlg::OnTermsClicked() { } afx_msg void CLauncherDlg::OnNextClicked() { - if (_drawStep != DrawStep::DrawChoose) { + if (_drawStep == DrawStep::DrawChoose) { + CString displayName; + m_username.GetWindowTextW(displayName); + theApp._manager.setDisplayName(displayName); + theApp._manager.addToLog(_T("Setting display name: " + displayName)); + startProcess(); + } else if (_drawStep == DrawStep::DrawError) { + theApp._manager.restartLauncher(); + } else if (_drawStep == DrawStep::DrawLoginLogin || + _drawStep == DrawStep::DrawLoginErrorCred || + _drawStep == DrawStep::DrawLoginErrorOrg) { CString token; CString username, password, orgname; m_orgname.GetWindowTextW(orgname); m_username.GetWindowTextW(username); m_password.GetWindowTextW(password); - + // trim spaces + orgname = CString(std::regex_replace(LauncherUtils::cStringToStd(orgname), std::regex("^ +| +$|( ) +"), "$1").c_str()); + username = CString(std::regex_replace(LauncherUtils::cStringToStd(username), std::regex("^ +| +$|( ) +"), "$1").c_str()); + // encode username = LauncherUtils::urlEncodeString(username); password = LauncherUtils::urlEncodeString(password); LauncherUtils::ResponseError error; @@ -261,19 +297,14 @@ afx_msg void CLauncherDlg::OnNextClicked() { setDrawDialog(DrawStep::DrawLoginErrorOrg); } } - } else { - CString displayName; - m_username.GetWindowTextW(displayName); - theApp._manager.setDisplayName(displayName); - theApp._manager.addToLog(_T("Setting display name: " + displayName)); - startProcess(); } } void CLauncherDlg::drawBackground(CHwndRenderTarget* pRenderTarget) { CD2DBitmap m_pBitmamBackground(pRenderTarget, IDB_PNG1, _T("PNG")); - auto size = pRenderTarget->GetSize(); + auto size = GetRenderTarget()->GetSize(); CD2DRectF backRec(0.0f, 0.0f, size.width, size.height); + GetRenderTarget()->DrawBitmap(&m_pBitmamBackground, backRec); pRenderTarget->DrawBitmap(&m_pBitmamBackground, backRec); } @@ -283,7 +314,7 @@ void CLauncherDlg::drawLogo(CHwndRenderTarget* pRenderTarget) { int logoWidth = 231; int logoHeight = 173; float logoPosX = 0.5f * (size.width - logoWidth); - float logoPosY = 0.95f * (size.height - logoHeight); + float logoPosY = 0.5f * (size.height - logoHeight); CD2DRectF logoRec(logoPosX, logoPosY, logoPosX + logoWidth, logoPosY + logoHeight); pRenderTarget->DrawBitmap(&m_pBitmamLogo, logoRec); } @@ -318,6 +349,27 @@ void CLauncherDlg::drawVoxel(CHwndRenderTarget* pRenderTarget) { pRenderTarget->SetTransform(D2D1::Matrix3x2F::Identity()); } +void CLauncherDlg::drawProgress(CHwndRenderTarget* pRenderTarget, float progress, const D2D1::ColorF& color) { + auto size = pRenderTarget->GetPixelSize(); + if (progress == 0.0f) { + return; + } else { + progress = min(1.0f, progress); + } + CRect winRec; + float fullHeight = (float)size.height; + float halfHeight = 0.5f * (float)size.height; + CD2DRectF bkCircleRect1 = CD2DRectF(0.0f, 0.0f, fullHeight, fullHeight); + float progPos = halfHeight + (float)(size.width - size.height) * progress; + CD2DRectF bkCircleRect2 = CD2DRectF(progPos - halfHeight, 0.0f, progPos + halfHeight, fullHeight); + CD2DRectF bkRect = CD2DRectF(halfHeight, 0.0f, progPos, fullHeight); + CD2DEllipse bkCircle1 = CD2DEllipse(bkCircleRect1); + CD2DEllipse bkCircle2 = CD2DEllipse(bkCircleRect2); + CD2DSolidColorBrush brush(pRenderTarget, color); + pRenderTarget->FillEllipse(bkCircle1, &brush); + pRenderTarget->FillEllipse(bkCircle2, &brush); + pRenderTarget->FillRectangle(bkRect, &brush); +} void CLauncherDlg::showWindows(std::vector windows, bool show) { for (auto window : windows) { @@ -327,6 +379,7 @@ void CLauncherDlg::showWindows(std::vector windows, bool show) { void CLauncherDlg::prepareLogin(DrawStep step) { m_voxel->ShowWindow(SW_HIDE); + m_progress->ShowWindow(SW_HIDE); m_orgname_banner->SetWindowTextW(_T("Organization Name")); m_username_banner->SetWindowTextW(_T("Username")); m_password_banner->SetWindowTextW(_T("Password")); @@ -342,7 +395,7 @@ void CLauncherDlg::prepareLogin(DrawStep step) { m_password.ShowWindow(SW_SHOW); CString actionText = step == DrawStep::DrawLoginLogin ? _T("Please log in") : _T("Uh-oh, we have a problem"); CString messageText = step == DrawStep::DrawLoginLogin ? _T("Be sure you've uploaded your Avatar before signing in.") : - step == DrawStep::DrawLoginErrorCred ? _T("There is a problem with your credentials\n please try again.") : _T("There is a problem with your Organization name\n please try again."); + step == DrawStep::DrawLoginErrorCred ? _T("There is a problem with your credentials.\n Please try again.") : _T("There is a problem with your Organization name.\n Please try again."); m_action_label->SetWindowTextW(actionText); m_message_label->SetWindowTextW(messageText); m_action_label->ShowWindow(SW_SHOW); @@ -351,10 +404,8 @@ void CLauncherDlg::prepareLogin(DrawStep step) { m_trouble->SetWindowTextW(_T("Having Trouble?")); m_trouble->ShowWindow(SW_SHOW); m_trouble_link.ShowWindow(SW_SHOW); - } - void CLauncherDlg::prepareChoose() { m_orgname.ShowWindow(SW_HIDE); m_username.SetWindowTextW(_T("")); @@ -371,14 +422,7 @@ void CLauncherDlg::prepareChoose() { m_terms_link.ShowWindow(SW_SHOW); m_terms->SetWindowTextW(_T("By signing in, you agree to the High Fidelity")); m_terms_link.SetWindowTextW(_T("Terms of Service")); - CRect rec; - m_btnNext.GetWindowRect(&rec); - ScreenToClient(&rec); - if (rec.top > 281) { - rec.bottom -= 35; - rec.top -= 35; - m_btnNext.MoveWindow(rec, FALSE); - } + setVerticalElement(&m_btnNext, -35, 0, false); m_btnNext.ShowWindow(SW_SHOW); } @@ -399,8 +443,10 @@ void CLauncherDlg::prepareProcess(DrawStep step) { m_action_label->ShowWindow(SW_HIDE); m_message_label->ShowWindow(SW_HIDE); m_voxel->ShowWindow(SW_SHOW); + m_progress->ShowWindow(SW_SHOW); CString actionText = _T(""); CString messageText = _T(""); + switch (step) { case DrawStep::DrawProcessSetup: actionText = _T("We're building your virtual HQ"); @@ -422,6 +468,16 @@ void CLauncherDlg::prepareProcess(DrawStep step) { actionText = _T("Uninstalling..."); messageText = _T("It'll take one sec."); break; + case DrawStep::DrawError: + actionText = _T("Uh oh."); + messageText = _T("We seem to have a problem.\nPlease restart HQ."); + setVerticalElement(m_message2_label, 0, 5, false); + setVerticalElement(&m_btnNext, 10); + m_btnNext.ShowWindow(SW_SHOW); + m_progress->ShowWindow(SW_HIDE); + break; + default: + break; } m_action2_label->SetWindowTextW(actionText); m_message2_label->SetWindowTextW(messageText); @@ -429,9 +485,6 @@ void CLauncherDlg::prepareProcess(DrawStep step) { m_message2_label->ShowWindow(SW_SHOW); } -void CLauncherDlg::prepareError() { -} - BOOL CLauncherDlg::getTextFormat(int resID, TextFormat& formatOut) { // Set default values for message BOOL isText = TRUE; @@ -485,7 +538,6 @@ BOOL CLauncherDlg::getTextFormat(int resID, TextFormat& formatOut) { HBRUSH CLauncherDlg::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor) { - HBRUSH hbr = CDialog::OnCtlColor(pDC, pWnd, nCtlColor); TextFormat textFormat; int resId = pWnd->GetDlgCtrlID(); @@ -505,6 +557,7 @@ HBRUSH CLauncherDlg::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor) CRect lineRect = CRect(rect.left + padding, rect.bottom, rect.right - padding, rect.bottom + borderThick); lineRect.MoveToY(lineRect.bottom + 1); pDC->FillSolidRect(lineRect, COLOR_GREY); + } } return (HBRUSH)GetStockObject(BLACK_BRUSH); @@ -523,6 +576,8 @@ void CLauncherDlg::OnDrawItem(int nIDCtl, LPDRAWITEMSTRUCT lpDrawItemStruct) btnName += _drawStep == DrawStep::DrawLoginLogin ? _T("NEXT") : _T("LOG IN"); int xpan = -20; defrect = CRect(rect.left - xpan, rect.top, rect.right + xpan, rect.bottom); + } else if (_drawStep == DrawStep::DrawError) { + btnName += _T("RESTART"); } else { btnName += _T("TRY AGAIN"); } @@ -592,66 +647,105 @@ BOOL CLauncherDlg::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message) } void CLauncherDlg::OnTimer(UINT_PTR nIDEvent) { - const int CONSOLE_MAX_SHUTDOWN_TRY_COUNT = 10; - const int CONSOLE_DELTATIME_BETWEEN_TRYS = 10; - if (_drawStep == DrawStep::DrawProcessSetup || - _drawStep == DrawStep::DrawProcessUpdate || - _drawStep == DrawStep::DrawProcessUninstall) { - // Refresh - setDrawDialog(_drawStep, true); + + + if (theApp._manager.hasFailed() && _drawStep != DrawStep::DrawError) { + theApp._manager.saveErrorLog(); + prepareProcess(DrawStep::DrawError); + setDrawDialog(DrawStep::DrawError, false); } - if (_showSplash) { - if (_splashStep == 0){ - if (theApp._manager.needsUninstall()) { - theApp._manager.addToLog(_T("Waiting to uninstall")); - setDrawDialog(DrawStep::DrawProcessUninstall); - } else { - theApp._manager.addToLog(_T("Start splash screen")); - setDrawDialog(DrawStep::DrawLogo); - } - } else if (_splashStep > 100) { - _showSplash = false; - if (theApp._manager.shouldShutDown()) { - if (_applicationWND != NULL) { - ::SetForegroundWindow(_applicationWND); - ::SetActiveWindow(_applicationWND); + if (_drawStep != DrawStep::DrawError) { + if (_drawStep == DrawStep::DrawProcessSetup || + _drawStep == DrawStep::DrawProcessUpdate || + _drawStep == DrawStep::DrawProcessUninstall || + _drawStep == DrawStep::DrawProcessFinishHq || + _drawStep == DrawStep::DrawProcessFinishUpdate) { + // Refresh + setDrawDialog(_drawStep, true); + } + if (_showSplash) { + if (_splashStep == 0) { + if (theApp._manager.needsUninstall()) { + theApp._manager.addToLog(_T("Waiting to uninstall")); + setDrawDialog(DrawStep::DrawProcessUninstall); + } else { + theApp._manager.addToLog(_T("Start splash screen")); + setDrawDialog(DrawStep::DrawLogo); } - if (LauncherUtils::IsProcessRunning(L"interface.exe")) { - exit(0); + } else if (_splashStep > 100) { + _showSplash = false; + if (theApp._manager.shouldShutDown()) { + if (_applicationWND != NULL) { + ::SetForegroundWindow(_applicationWND); + ::SetActiveWindow(_applicationWND); + } + if (LauncherUtils::isProcessWindowOpened(L"interface.exe")) { + exit(0); + } + } else if (theApp._manager.needsUpdate()) { + startProcess(); + } else if (theApp._manager.needsUninstall()) { + if (theApp._manager.uninstallApplication()) { + theApp._manager.addToLog(_T("HQ uninstalled successfully.")); + exit(0); + } else { + theApp._manager.addToLog(_T("HQ failed to uninstall.")); + theApp._manager.setFailed(true); + } + } else { + theApp._manager.addToLog(_T("Starting login")); + setDrawDialog(DrawStep::DrawLoginLogin); } - } else if (theApp._manager.needsUpdate()) { - startProcess(); } else if (theApp._manager.needsUninstall()) { - theApp._manager.uninstallApplication(); + theApp._manager.updateProgress(LauncherManager::ProcessType::Uninstall, (float)_splashStep/100); + } + _splashStep++; + } else if (theApp._manager.shouldShutDown()) { + if (LauncherUtils::isProcessWindowOpened(L"interface.exe")) { exit(0); - } else { - theApp._manager.addToLog(_T("Starting login")); - setDrawDialog(DrawStep::DrawLoginLogin); } } - _splashStep++; - } else if (theApp._manager.shouldShutDown()) { - if (LauncherUtils::IsProcessRunning(L"interface.exe")) { - exit(0); + if (theApp._manager.shouldLaunch()) { + if (theApp._manager.needsInstall() || theApp._manager.needsUpdate()) { + auto finishProcess = theApp._manager.needsUpdate() ? DrawStep::DrawProcessFinishUpdate : DrawStep::DrawProcessFinishHq; + setDrawDialog(finishProcess); + } + _applicationWND = theApp._manager.launchApplication(); } } - if (theApp._manager.shouldLaunch()) { - _applicationWND = theApp._manager.launchApplication(); +} + +void CLauncherDlg::setVerticalElement(CWnd* element, int verticalOffset, int heightOffset, bool fromMainWindowBottom) { + CRect elementRec; + CRect windowRec; + if (element != NULL) { + element->GetWindowRect(&elementRec); + ScreenToClient(&elementRec); + int offset = verticalOffset; + if (fromMainWindowBottom) { + GetWindowRect(&windowRec); + ScreenToClient(&windowRec); + int currentDistance = windowRec.bottom - elementRec.bottom; + offset = currentDistance - verticalOffset; + } + elementRec.bottom = elementRec.bottom + offset + heightOffset; + elementRec.top = elementRec.top + offset; + element->MoveWindow(elementRec, FALSE); } } void CLauncherDlg::setDrawDialog(DrawStep step, BOOL isUpdate) { _drawStep = step; + float progress = 0.0f; auto m_pRenderTarget = GetRenderTarget(); auto m_voxelRenderTarget = m_voxel->GetRenderTarget(); + auto m_progressRenderTarget = m_progress->GetRenderTarget(); switch (_drawStep) { case DrawStep::DrawLogo: m_pRenderTarget->BeginDraw(); drawBackground(m_pRenderTarget); + drawLogo(m_pRenderTarget); m_pRenderTarget->EndDraw(); - m_voxelRenderTarget->BeginDraw(); - drawLogo(m_voxelRenderTarget); - m_voxelRenderTarget->EndDraw(); break; case DrawStep::DrawLoginLogin: case DrawStep::DrawLoginErrorOrg: @@ -671,6 +765,7 @@ void CLauncherDlg::setDrawDialog(DrawStep step, BOOL isUpdate) { m_pRenderTarget->EndDraw(); RedrawWindow(); break; + case DrawStep::DrawError: case DrawStep::DrawProcessFinishHq: case DrawStep::DrawProcessFinishUpdate: case DrawStep::DrawProcessUpdate: @@ -686,7 +781,12 @@ void CLauncherDlg::setDrawDialog(DrawStep step, BOOL isUpdate) { drawSmallLogo(m_pRenderTarget); m_pRenderTarget->EndDraw(); RedrawWindow(); - } + } + m_progressRenderTarget->BeginDraw(); + m_progressRenderTarget->Clear(D2D1::ColorF(0.0f, 0.0f, 0.0f, 1.0f)); + drawProgress(m_progressRenderTarget, 1.0f, D2D1::ColorF(0.2f, 0.2f, 0.2f)); + drawProgress(m_progressRenderTarget, theApp._manager.getProgress(), D2D1::ColorF(0.0f, 0.62f, 0.9f)); + m_progressRenderTarget->EndDraw(); m_voxelRenderTarget->BeginDraw(); drawVoxel(m_voxelRenderTarget); m_voxelRenderTarget->EndDraw(); diff --git a/launchers/win32/LauncherDlg.h b/launchers/win32/LauncherDlg.h index 6357c2a5b0..faebc8a822 100644 --- a/launchers/win32/LauncherDlg.h +++ b/launchers/win32/LauncherDlg.h @@ -43,30 +43,33 @@ public: void setDrawDialog(DrawStep step, BOOL isUpdate = FALSE); - // Dialog Data #ifdef AFX_DESIGN_TIME enum { IDD = IDD_LAUNCHER_DIALOG }; #endif - protected: +// Implementation +protected: virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support void startProcess(); void setCustomDialog(); - -// Implementation -protected: - + void setVerticalElement(CWnd* element, int verticalOffset, int heightOffset = 0, bool fromMainWindowBottom = true); BOOL getHQInfo(const CString& orgname); DrawStep _drawStep { DrawStep::DrawLogo }; BOOL getTextFormat(int ResID, TextFormat& formatOut); void showWindows(std::vector 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; @@ -81,6 +84,7 @@ protected: CStatic* m_terms; CStatic* m_trouble; CStatic* m_voxel; + CStatic* m_progress; CEdit m_orgname; CEdit m_username; @@ -96,11 +100,11 @@ protected: void drawLogo(CHwndRenderTarget* pRenderTarget); void drawSmallLogo(CHwndRenderTarget* pRenderTarget); void drawVoxel(CHwndRenderTarget* pRenderTarget); + void drawProgress(CHwndRenderTarget* pRenderTarget, float progress, const D2D1::ColorF& color); void prepareLogin(DrawStep step); void prepareProcess(DrawStep step); void prepareChoose(); - void prepareError(); void redrawBanner(const CEdit& edit, CStatic* banner); diff --git a/launchers/win32/LauncherManager.cpp b/launchers/win32/LauncherManager.cpp index 47c84f1124..e56e0e71fc 100644 --- a/launchers/win32/LauncherManager.cpp +++ b/launchers/win32/LauncherManager.cpp @@ -15,31 +15,43 @@ #include "LauncherManager.h" -LauncherManager::LauncherManager() -{ +LauncherManager::LauncherManager() { } - -LauncherManager::~LauncherManager() -{ +LauncherManager::~LauncherManager() { } void LauncherManager::init() { initLog(); addToLog(_T("Getting most recent build")); - getMostRecentBuild(_latestApplicationURL, _latestVersion); - addToLog(_T("Latest version: ") + _latestVersion); - CString currentVersion; - if (isApplicationInstalled(currentVersion, _domainURL, _contentURL, _loggedIn) && _loggedIn) { - addToLog(_T("Installed version: ") + currentVersion); - if (_latestVersion.Compare(currentVersion) == 0) { - addToLog(_T("Already running most recent build. Launching interface.exe")); - _shouldLaunch = TRUE; - _shouldShutdown = TRUE; - } else { - addToLog(_T("New build found. Updating")); + CString response; + LauncherUtils::ResponseError error = getMostRecentBuild(_latestApplicationURL, _latestVersion, response); + if (error == LauncherUtils::ResponseError::NoError) { + addToLog(_T("Latest version: ") + _latestVersion); + CString currentVersion; + if (isApplicationInstalled(currentVersion, _domainURL, _contentURL, _loggedIn) && _loggedIn) { + addToLog(_T("Installed version: ") + currentVersion); + if (_latestVersion.Compare(currentVersion) == 0) { + addToLog(_T("Already running most recent build. Launching interface.exe")); + _shouldLaunch = TRUE; + _shouldShutdown = TRUE; + } else { + addToLog(_T("New build found. Updating")); + _shouldUpdate = TRUE; + } + } else if (_loggedIn) { + addToLog(_T("Interface not found but logged in. Reinstalling")); _shouldUpdate = TRUE; + } else { + _shouldInstall = TRUE; } + } else { + _hasFailed = true; + CString msg; + msg.Format(_T("Getting most recent build has failed with error: %d"), error); + addToLog(msg); + msg.Format(_T("Response: %s"), response); + addToLog(msg); } } @@ -74,8 +86,19 @@ void LauncherManager::closeLog() { } } +void LauncherManager::saveErrorLog() { + CString logPath = _logFile.GetFilePath(); + CString errorLogPath; + auto result = getAndCreatePaths(PathType::Launcher_Directory, errorLogPath); + if (result) { + CString filename; + errorLogPath += _T("log_error.txt"); + closeLog(); + CopyFile(logPath, errorLogPath, FALSE); + } +} + BOOL LauncherManager::installLauncher() { - addToLog(_T("Installing Launcher.")); CString appPath; BOOL result = getAndCreatePaths(PathType::Running_Path, appPath); if (!result) { @@ -93,13 +116,17 @@ BOOL LauncherManager::installLauncher() { if (!_shouldUninstall) { // The installer is not running on the desired location and has to be installed // Kill of running before self-copy - if (LauncherUtils::IsProcessRunning(LAUNCHER_EXE_FILENAME)) { - ShellExecute(NULL, NULL, L"taskkill", L"/F /T /IM " + LAUNCHER_EXE_FILENAME, NULL, SW_HIDE); + addToLog(_T("Installing Launcher.")); + 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); } } else if (_shouldUninstall) { - addToLog(_T("Launching uninstall mode.")); + addToLog(_T("Launching Uninstall mode.")); CString tempPath; if (getAndCreatePaths(PathType::Temp_Directory, tempPath)) { tempPath += _T("\\HQ_uninstaller_tmp.exe"); @@ -111,6 +138,52 @@ BOOL LauncherManager::installLauncher() { return TRUE; } +BOOL LauncherManager::restartLauncher() { + addToLog(_T("Restarting Launcher.")); + CString installDirectory; + if (getAndCreatePaths(PathType::Launcher_Directory, installDirectory)) { + CString installPath = installDirectory + LAUNCHER_EXE_FILENAME; + LauncherUtils::launchApplication(installPath, _T(" --restart")); + exit(0); + } + addToLog(_T("Error restarting Launcher.")); + return FALSE; +} + +void LauncherManager::updateProgress(ProcessType processType, float progress) { + switch (processType) { + case ProcessType::Uninstall: + _progress = progress; + break; + case ProcessType::DownloadContent: + _progress = DOWNLOAD_CONTENT_INSTALL_WEIGHT * progress; + break; + case ProcessType::UnzipContent: + _progress = DOWNLOAD_CONTENT_INSTALL_WEIGHT + + EXTRACT_CONTENT_INSTALL_WEIGHT * progress; + break; + case ProcessType::DownloadApplication: + _progress = !_shouldUpdate ? + (DOWNLOAD_CONTENT_INSTALL_WEIGHT + + EXTRACT_CONTENT_INSTALL_WEIGHT + + DOWNLOAD_APPLICATION_INSTALL_WEIGHT * progress) : + DOWNLOAD_APPLICATION_UPDATE_WEIGHT * progress; + break; + case ProcessType::UnzipApplication: + _progress = !_shouldUpdate ? + (DOWNLOAD_CONTENT_INSTALL_WEIGHT + + EXTRACT_CONTENT_INSTALL_WEIGHT + + DOWNLOAD_APPLICATION_INSTALL_WEIGHT + + EXTRACT_APPLICATION_INSTALL_WEIGHT * progress) : + (DOWNLOAD_APPLICATION_UPDATE_WEIGHT + + EXTRACT_APPLICATION_UPDATE_WEIGHT * progress); + break; + default: + break; + } + TRACE("progress = %f\n", _progress); +} + BOOL LauncherManager::createShortcuts() { CString desktopLnkPath; addToLog(_T("Creating shortcuts.")); @@ -119,7 +192,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; @@ -127,13 +200,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; @@ -157,9 +230,9 @@ BOOL LauncherManager::isApplicationInstalled(CString& version, CString& domain, CString applicationPath = applicationDir + "interface\\interface.exe"; BOOL isApplicationInstalled = PathFileExistsW(applicationPath); BOOL configFileExist = PathFileExistsW(applicationDir + _T("interface\\config.json")); - if (isApplicationInstalled && configFileExist) { + if (configFileExist) { LauncherUtils::ResponseError status = readConfigJSON(version, domain, content, loggedIn); - return status == LauncherUtils::ResponseError::NoError; + return isApplicationInstalled && status == LauncherUtils::ResponseError::NoError; } return FALSE; } @@ -223,8 +296,9 @@ HWND LauncherManager::launchApplication() { LauncherManager::getAndCreatePaths(PathType::Interface_Directory, installDir); CString interfaceExe = installDir + _T("\\interface.exe"); CString urlParam = _T("--url \"") + _domainURL + ("\" "); - CString scriptsURL = installDir + _T("\\scripts\\simplifiedUI"); - CString scriptsParam = _T("--scripts \"") + scriptsURL + ("\" "); + CString scriptsURL = installDir + _T("\\scripts\\simplifiedUIBootstrapper.js"); + scriptsURL.Replace(_T("\\"), _T("/")); + CString scriptsParam = _T("--defaultScriptsOverride \"") + scriptsURL + ("\" "); CString cacheDir; LauncherManager::getAndCreatePaths(PathType::Content_Directory, cacheDir); CString cacheParam = _T("--cache \"") + cacheDir + ("\" "); @@ -266,7 +340,8 @@ BOOL LauncherManager::createConfigJSON() { return TRUE; } -LauncherUtils::ResponseError LauncherManager::readConfigJSON(CString& version, CString& domain, CString& content, bool& loggedIn) { +LauncherUtils::ResponseError LauncherManager::readConfigJSON(CString& version, CString& domain, + CString& content, bool& loggedIn) { CString configPath; getAndCreatePaths(PathType::Interface_Directory, configPath); configPath += "\\config.json"; @@ -276,7 +351,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(); @@ -293,8 +369,10 @@ LauncherUtils::ResponseError LauncherManager::readOrganizationJSON(const CString CString contentTypeJson = L"content-type:application/json"; CString response; CString url = _T("/organizations/") + hash + _T(".json"); - LauncherUtils::ResponseError error = LauncherUtils::makeHTTPCall(L"HQ Launcher", L"orgs.highfidelity.com", url, - contentTypeJson, CStringA(), response, false); + LauncherUtils::ResponseError error = LauncherUtils::makeHTTPCall(L"HQ Launcher", + L"orgs.highfidelity.com", url, + contentTypeJson, CStringA(), + response, false); if (error != LauncherUtils::ResponseError::NoError) { return error; } @@ -309,11 +387,14 @@ LauncherUtils::ResponseError LauncherManager::readOrganizationJSON(const CString return LauncherUtils::ResponseError::ParsingJSON; } -LauncherUtils::ResponseError LauncherManager::getMostRecentBuild(CString& urlOut, CString& versionOut) { +LauncherUtils::ResponseError LauncherManager::getMostRecentBuild(CString& urlOut, CString& versionOut, + CString& response) { CString contentTypeJson = L"content-type:application/json"; - CString response; - LauncherUtils::ResponseError error = LauncherUtils::makeHTTPCall(L"HQ Launcher", L"thunder.highfidelity.com", L"/builds/api/tags/latest?format=json", - contentTypeJson, CStringA(), response, false); + LauncherUtils::ResponseError error = LauncherUtils::makeHTTPCall(L"HQ Launcher", + L"thunder.highfidelity.com", + L"/builds/api/tags/latest?format=json", + contentTypeJson, CStringA(), + response, false); if (error != LauncherUtils::ResponseError::NoError) { return error; } @@ -341,7 +422,8 @@ LauncherUtils::ResponseError LauncherManager::getMostRecentBuild(CString& urlOut return LauncherUtils::ResponseError::ParsingJSON; } -LauncherUtils::ResponseError LauncherManager::getAccessTokenForCredentials(const CString& username, const CString& password) { +LauncherUtils::ResponseError LauncherManager::getAccessTokenForCredentials(const CString& username, + const CString& password) { CStringA post = "grant_type=password&username="; post += username; post += "&password="; @@ -350,8 +432,11 @@ LauncherUtils::ResponseError LauncherManager::getAccessTokenForCredentials(const CString contentTypeText = L"content-type:application/x-www-form-urlencoded"; CString response; - LauncherUtils::ResponseError error = LauncherUtils::makeHTTPCall(L"HQ Launcher", L"metaverse.highfidelity.com", L"/oauth/token", - contentTypeText, post, response, true); + LauncherUtils::ResponseError error = LauncherUtils::makeHTTPCall(L"HQ Launcher", + L"metaverse.highfidelity.com", + L"/oauth/token", + contentTypeText, post, + response, true); if (error != LauncherUtils::ResponseError::NoError) { return error; } @@ -395,21 +480,19 @@ BOOL LauncherManager::uninstallApplication() { CString installDir; getAndCreatePaths(PathType::Launcher_Directory, installDir); BOOL success = LauncherUtils::deleteFileOrDirectory(installDir); - success = success && (deleteShortcuts()); - success = success && (deleteApplicationRegistryKeys()); + if (success) { + deleteShortcuts(); + deleteApplicationRegistryKeys(); + } return success; } -void LauncherManager::onZipExtracted(ZipType type, int size) { - if (type == ZipType::ZipContent) { +void LauncherManager::onZipExtracted(ProcessType type, int size) { + if (type == ProcessType::UnzipContent) { addToLog(_T("Downloading application.")); downloadApplication(); - } else if (type == ZipType::ZipApplication) { + } else if (type == ProcessType::UnzipApplication) { createShortcuts(); - CString versionPath; - getAndCreatePaths(LauncherManager::PathType::Launcher_Directory, versionPath); - addToLog(_T("Creating config.json")); - createConfigJSON(); addToLog(_T("Launching application.")); _shouldLaunch = TRUE; if (!_shouldUpdate) { @@ -423,10 +506,24 @@ void LauncherManager::onZipExtracted(ZipType type, int size) { BOOL LauncherManager::extractApplication() { CString installPath; getAndCreatePaths(LauncherManager::PathType::Interface_Directory, installPath); - BOOL success = LauncherUtils::unzipFileOnThread(ZipType::ZipApplication, LauncherUtils::cStringToStd(_applicationZipPath), - LauncherUtils::cStringToStd(installPath), [&](int type, int size) { - onZipExtracted((ZipType)type, size); - }); + std::function onExtractFinished = [&](int type, int size) { + addToLog(_T("Creating config.json")); + createConfigJSON(); + if (size > 0) { + onZipExtracted((ProcessType)type, size); + } else { + addToLog(_T("Error decompressing application zip file.")); + _hasFailed = true; + } + }; + std::function onProgress = [&](float progress) { + updateProgress(ProcessType::UnzipApplication, progress); + }; + _currentProcess = ProcessType::UnzipApplication; + BOOL success = LauncherUtils::unzipFileOnThread(ProcessType::UnzipApplication, + LauncherUtils::cStringToStd(_applicationZipPath), + LauncherUtils::cStringToStd(installPath), + onExtractFinished, onProgress); if (success) { addToLog(_T("Created thread for unzipping application.")); } else { @@ -435,13 +532,33 @@ BOOL LauncherManager::extractApplication() { return success; } -void LauncherManager::onFileDownloaded(DownloadType type) { - if (type == DownloadType::DownloadContent) { - addToLog(_T("Installing content.")); - installContent(); - } else if (type == DownloadType::DownloadApplication) { - addToLog(_T("Installing application.")); - extractApplication(); +void LauncherManager::onFileDownloaded(ProcessType type) { + if (type == ProcessType::DownloadContent) { + addToLog(_T("Deleting content directory before install")); + CString contentDir; + getAndCreatePaths(PathType::Content_Directory, contentDir); + LauncherUtils::deleteDirectoryOnThread(contentDir, [&](bool error) { + if (!error) { + addToLog(_T("Installing content.")); + installContent(); + } else { + addToLog(_T("Error deleting content directory.")); + setFailed(true); + } + }); + } else if (type == ProcessType::DownloadApplication) { + addToLog(_T("Deleting application directory before install")); + CString applicationDir; + getAndCreatePaths(PathType::Interface_Directory, applicationDir); + LauncherUtils::deleteDirectoryOnThread(applicationDir, [&](bool error) { + if (!error) { + addToLog(_T("Installing application.")); + extractApplication(); + } else { + addToLog(_T("Error deleting install directory.")); + setFailed(true); + } + }); } } @@ -450,10 +567,22 @@ BOOL LauncherManager::installContent() { std::string contentZipFile = LauncherUtils::cStringToStd(_contentZipPath); CString contentPath; getAndCreatePaths(LauncherManager::PathType::Content_Directory, contentPath); - BOOL success = LauncherUtils::unzipFileOnThread(ZipType::ZipContent, contentZipFile, - LauncherUtils::cStringToStd(contentPath), [&](int type, int size) { - onZipExtracted((ZipType)type, size); - }); + std::function onInstallFinished = [&](int type, int size) { + if (size > 0) { + addToLog(_T("Content zip decompresed.")); + onZipExtracted((ProcessType)type, size); + } + else { + addToLog(_T("Error decompressing content zip file.")); + _hasFailed = true; + } + }; + std::function onProgress = [&](float progress) { + updateProgress(ProcessType::UnzipContent, progress); + }; + _currentProcess = ProcessType::UnzipContent; + BOOL success = LauncherUtils::unzipFileOnThread(ProcessType::UnzipContent, contentZipFile, + LauncherUtils::cStringToStd(contentPath), onInstallFinished, onProgress); if (success) { addToLog(_T("Created thread for unzipping content.")); } else { @@ -463,15 +592,32 @@ BOOL LauncherManager::installContent() { } -BOOL LauncherManager::downloadFile(DownloadType type, const CString& url, CString& outPath) { +BOOL LauncherManager::downloadFile(ProcessType type, const CString& url, CString& outPath) { CString fileName = url.Mid(url.ReverseFind('/') + 1); CString downloadDirectory; BOOL success = getAndCreatePaths(LauncherManager::PathType::Download_Directory, downloadDirectory); outPath = downloadDirectory + fileName; + _currentProcess = type; if (success) { - if (!LauncherUtils::downloadFileOnThread(type, url, outPath, [&](int type) { - onFileDownloaded((DownloadType)type); - })) { + addToLog(_T("Downloading: ") + url); + std::function onDownloadFinished = [&](int type, bool error) { + if (!error) { + onFileDownloaded((ProcessType)type); + } + else { + if (type == ProcessType::DownloadApplication) { + addToLog(_T("Error downloading content.")); + } + else { + addToLog(_T("Error downloading application.")); + } + _hasFailed = true; + } + }; + std::function onProgress = [&](float progress) { + updateProgress(_currentProcess, progress); + }; + if (!LauncherUtils::downloadFileOnThread(type, url, outPath, onDownloadFinished, onProgress)) { success = FALSE; } } @@ -481,10 +627,18 @@ BOOL LauncherManager::downloadFile(DownloadType type, const CString& url, CStrin BOOL LauncherManager::downloadContent() { addToLog(_T("Downloading content.")); CString contentURL = getContentURL(); - return downloadFile(DownloadType::DownloadContent, contentURL, _contentZipPath); + return downloadFile(ProcessType::DownloadContent, contentURL, _contentZipPath); } BOOL LauncherManager::downloadApplication() { CString applicationURL = getLatestInterfaceURL(); - return downloadFile(DownloadType::DownloadApplication, applicationURL, _applicationZipPath); + return downloadFile(ProcessType::DownloadApplication, applicationURL, _applicationZipPath); +} + +void LauncherManager::onCancel() { + if (_currentProcess == ProcessType::UnzipApplication) { + _latestVersion = _T(""); + _version = _T(""); + createConfigJSON(); + } } diff --git a/launchers/win32/LauncherManager.h b/launchers/win32/LauncherManager.h index 6fa7efeeda..cb707e0a14 100644 --- a/launchers/win32/LauncherManager.h +++ b/launchers/win32/LauncherManager.h @@ -19,6 +19,12 @@ const CString DIRECTORY_NAME_CONTENT = _T("content"); const CString EXTRA_PARAMETERS = _T(" --suppress-settings-reset --no-launcher --no-updater"); const CString LAUNCHER_EXE_FILENAME = _T("HQ Launcher.exe"); const bool INSTALL_ZIP = true; +const float DOWNLOAD_CONTENT_INSTALL_WEIGHT = 0.2f; +const float EXTRACT_CONTENT_INSTALL_WEIGHT = 0.1f; +const float DOWNLOAD_APPLICATION_INSTALL_WEIGHT = 0.5f; +const float EXTRACT_APPLICATION_INSTALL_WEIGHT = 0.2f; +const float DOWNLOAD_APPLICATION_UPDATE_WEIGHT = 0.75f; +const float EXTRACT_APPLICATION_UPDATE_WEIGHT = 0.25f; class LauncherManager { @@ -33,16 +39,8 @@ public: StartMenu_Directory, Temp_Directory }; - enum ZipType { - ZipContent = 0, - ZipApplication - }; - enum DownloadType { - DownloadContent = 0, - DownloadApplication - }; enum ErrorType { - ErrorNetworkAuth, + ErrorNetworkAuth = 0, ErrorNetworkUpdate, ErrorNetworkHq, ErrorDownloading, @@ -50,18 +48,26 @@ public: ErrorInstall, ErrorIOFiles }; + enum ProcessType { + DownloadContent, + DownloadApplication, + UnzipContent, + UnzipApplication, + Uninstall + }; LauncherManager(); ~LauncherManager(); void init(); BOOL initLog(); BOOL addToLog(const CString& line); void closeLog(); + void saveErrorLog(); BOOL getAndCreatePaths(PathType type, CString& outPath); BOOL getInstalledVersion(const CString& path, CString& version); BOOL isApplicationInstalled(CString& version, CString& domain, CString& content, bool& loggedIn); LauncherUtils::ResponseError getAccessTokenForCredentials(const CString& username, const CString& password); - LauncherUtils::ResponseError getMostRecentBuild(CString& urlOut, CString& versionOut); + LauncherUtils::ResponseError getMostRecentBuild(CString& urlOut, CString& versionOut, CString& response); LauncherUtils::ResponseError readOrganizationJSON(const CString& hash); LauncherUtils::ResponseError readConfigJSON(CString& version, CString& domain, CString& content, bool& loggedIn); @@ -73,6 +79,7 @@ public: HWND launchApplication(); BOOL uninstallApplication(); BOOL installLauncher(); + BOOL restartLauncher(); // getters const CString& getContentURL() const { return _contentURL; } @@ -82,20 +89,27 @@ public: BOOL shouldLaunch() const { return _shouldLaunch; } BOOL needsUpdate() { return _shouldUpdate; } BOOL needsUninstall() { return _shouldUninstall; } + BOOL needsInstall() { return _shouldInstall; } void setDisplayName(const CString& displayName) { _displayName = displayName; } bool isLoggedIn() { return _loggedIn; } + bool hasFailed() { return _hasFailed; } + void setFailed(bool hasFailed) { _hasFailed = hasFailed; } const CString& getLatestInterfaceURL() const { return _latestApplicationURL; } void uninstall() { _shouldUninstall = true; }; - BOOL downloadFile(DownloadType type, const CString& url, CString& localPath); + BOOL downloadFile(ProcessType type, const CString& url, CString& localPath); BOOL downloadContent(); BOOL downloadApplication(); BOOL installContent(); BOOL extractApplication(); - void onZipExtracted(ZipType type, int size); - void onFileDownloaded(DownloadType type); + void onZipExtracted(ProcessType type, int size); + void onFileDownloaded(ProcessType type); + float getProgress() { return _progress; } + void updateProgress(ProcessType processType, float progress); + void onCancel(); private: + ProcessType _currentProcess { ProcessType::DownloadApplication }; CString _latestApplicationURL; CString _latestVersion; CString _contentURL; @@ -105,11 +119,14 @@ private: CString _tokensJSON; CString _applicationZipPath; CString _contentZipPath; - bool _loggedIn{ false }; - BOOL _shouldUpdate{ FALSE }; - BOOL _shouldUninstall{ FALSE }; - BOOL _shouldShutdown{ FALSE }; - BOOL _shouldLaunch{ FALSE }; + bool _loggedIn { false }; + bool _hasFailed { false }; + BOOL _shouldUpdate { FALSE }; + BOOL _shouldUninstall { FALSE }; + BOOL _shouldInstall { FALSE }; + BOOL _shouldShutdown { FALSE }; + BOOL _shouldLaunch { FALSE }; + float _progress { 0.0f }; CStdioFile _logFile; }; diff --git a/launchers/win32/LauncherUtils.cpp b/launchers/win32/LauncherUtils.cpp index 3ffbd37c58..3ba4b26901 100644 --- a/launchers/win32/LauncherUtils.cpp +++ b/launchers/win32/LauncherUtils.cpp @@ -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(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(&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 @@ -236,7 +272,9 @@ BOOL LauncherUtils::getFont(const CString& fontName, int fontSize, bool isBold, return TRUE; } -uint64_t LauncherUtils::extractZip(const std::string& zipFile, const std::string& path, std::vector& files) { +uint64_t LauncherUtils::extractZip(const std::string& zipFile, const std::string& path, + std::vector& files, + std::function progressCallback) { { CString msg; msg.Format(_T("Reading zip file %s, extracting to %s"), CString(zipFile.c_str()), CString(path.c_str())); @@ -256,40 +294,58 @@ uint64_t LauncherUtils::extractZip(const std::string& zipFile, const std::string theApp._manager.addToLog(msg); return 0; } - int fileCount = (int)mz_zip_reader_get_num_files(&zip_archive); - if (fileCount == 0) { - theApp._manager.addToLog(_T("Zip archive has a file count of 0")); + { + CString msg; + msg.Format(_T("Zip archive has a file count of %d"), fileCount); + theApp._manager.addToLog(msg); + } + if (fileCount == 0) { mz_zip_reader_end(&zip_archive); return 0; } mz_zip_archive_file_stat file_stat; if (!mz_zip_reader_file_stat(&zip_archive, 0, &file_stat)) { theApp._manager.addToLog(_T("Zip archive cannot be stat'd")); - mz_zip_reader_end(&zip_archive); return 0; } // Get root folder CString lastDir = _T(""); uint64_t totalSize = 0; + uint64_t totalCompressedSize = 0; + bool _shouldFail = false; for (int i = 0; i < fileCount; i++) { if (!mz_zip_reader_file_stat(&zip_archive, i, &file_stat)) continue; std::string filename = file_stat.m_filename; std::replace(filename.begin(), filename.end(), '/', '\\'); CString fullFilename = CString(path.c_str()) + "\\" + CString(filename.c_str()); if (mz_zip_reader_is_file_a_directory(&zip_archive, i)) { - if (SHCreateDirectoryEx(NULL, fullFilename, NULL) || ERROR_ALREADY_EXISTS == GetLastError()) { - break; - } else { - continue; + int error = SHCreateDirectoryEx(NULL, fullFilename, NULL); + if (error == ERROR_BAD_PATHNAME || + error == ERROR_FILENAME_EXCED_RANGE || + error == ERROR_PATH_NOT_FOUND || + error == ERROR_CANCELLED) { + CString msg; + msg.Format(_T("Unzipping error: %d creating folder: %s"), error, fullFilename); + theApp._manager.addToLog(msg); + mz_zip_reader_end(&zip_archive); + return 0; } + continue; } CT2A destFile(fullFilename); if (mz_zip_reader_extract_to_file(&zip_archive, i, destFile, 0)) { + totalCompressedSize += (uint64_t)file_stat.m_comp_size; totalSize += (uint64_t)file_stat.m_uncomp_size; + progressCallback((float)totalCompressedSize / (float)zip_archive.m_archive_size); files.emplace_back(destFile); + } else { + CString msg; + msg.Format(_T("Error unzipping the file: %s"), fullFilename); + theApp._manager.addToLog(msg); + _shouldFail = true; } } @@ -414,41 +470,40 @@ BOOL LauncherUtils::hMac256(const CString& cmessage, const char* keystr, CString DWORD WINAPI LauncherUtils::unzipThread(LPVOID lpParameter) { UnzipThreadData& data = *((UnzipThreadData*)lpParameter); - uint64_t size = LauncherUtils::extractZip(data._zipFile, data._path, std::vector()); + uint64_t size = LauncherUtils::extractZip(data._zipFile, data._path, std::vector(), data.progressCallback); int mb_size = (int)(size * 0.001f); data.callback(data._type, mb_size); delete &data; return 0; } -DWORD WINAPI LauncherUtils::downloadThread(LPVOID lpParameter) -{ +DWORD WINAPI LauncherUtils::downloadThread(LPVOID lpParameter) { DownloadThreadData& data = *((DownloadThreadData*)lpParameter); - auto hr = URLDownloadToFile(0, data._url, data._file, 0, NULL); - data.callback(data._type); + ProgressCallback progressCallback; + progressCallback.setProgressCallback(data.progressCallback); + auto hr = URLDownloadToFile(0, data._url, data._file, 0, + static_cast(&progressCallback)); + data.callback(data._type, hr != S_OK); return 0; } -DWORD WINAPI LauncherUtils::deleteDirectoriesThread(LPVOID lpParameter) { +DWORD WINAPI LauncherUtils::deleteDirectoryThread(LPVOID lpParameter) { DeleteThreadData& data = *((DeleteThreadData*)lpParameter); - DeleteDirError error = DeleteDirError::NoErrorDeleting; - if (!LauncherUtils::deleteFileOrDirectory(data._applicationDir)) { - error = DeleteDirError::ErrorDeletingApplicationDir; - } - if (!LauncherUtils::deleteFileOrDirectory(data._downloadsDir)) { - error = error == NoError ? DeleteDirError::ErrorDeletingDownloadsDir : DeleteDirError::ErrorDeletingBothDirs; - } - data.callback(error); + BOOL success = LauncherUtils::deleteFileOrDirectory(data._dirPath); + data.callback(!success); return 0; } -BOOL LauncherUtils::unzipFileOnThread(int type, const std::string& zipFile, const std::string& path, std::function callback) { +BOOL LauncherUtils::unzipFileOnThread(int type, const std::string& zipFile, const std::string& path, + std::function callback, + std::function progressCallback) { DWORD myThreadID; UnzipThreadData* unzipThreadData = new UnzipThreadData(); unzipThreadData->_type = type; unzipThreadData->_zipFile = zipFile; unzipThreadData->_path = path; unzipThreadData->setCallback(callback); + unzipThreadData->setProgressCallback(progressCallback); HANDLE myHandle = CreateThread(0, 0, unzipThread, unzipThreadData, 0, &myThreadID); if (myHandle) { CloseHandle(myHandle); @@ -457,13 +512,16 @@ BOOL LauncherUtils::unzipFileOnThread(int type, const std::string& zipFile, cons return FALSE; } -BOOL LauncherUtils::downloadFileOnThread(int type, const CString& url, const CString& file, std::function callback) { +BOOL LauncherUtils::downloadFileOnThread(int type, const CString& url, const CString& file, + std::function callback, + std::function progressCallback) { DWORD myThreadID; DownloadThreadData* downloadThreadData = new DownloadThreadData(); downloadThreadData->_type = type; downloadThreadData->_url = url; downloadThreadData->_file = file; downloadThreadData->setCallback(callback); + downloadThreadData->setProgressCallback(progressCallback); HANDLE myHandle = CreateThread(0, 0, downloadThread, downloadThreadData, 0, &myThreadID); if (myHandle) { CloseHandle(myHandle); @@ -472,15 +530,12 @@ BOOL LauncherUtils::downloadFileOnThread(int type, const CString& url, const CSt return FALSE; } -BOOL LauncherUtils::deleteDirectoriesOnThread(const CString& applicationDir, - const CString& downloadsDir, - std::function callback) { +BOOL LauncherUtils::deleteDirectoryOnThread(const CString& dirPath, std::function callback) { DWORD myThreadID; DeleteThreadData* deleteThreadData = new DeleteThreadData(); - deleteThreadData->_applicationDir = applicationDir; - deleteThreadData->_downloadsDir = downloadsDir; + deleteThreadData->_dirPath = dirPath; deleteThreadData->setCallback(callback); - HANDLE myHandle = CreateThread(0, 0, deleteDirectoriesThread, deleteThreadData, 0, &myThreadID); + HANDLE myHandle = CreateThread(0, 0, deleteDirectoryThread, deleteThreadData, 0, &myThreadID); if (myHandle) { CloseHandle(myHandle); return TRUE; diff --git a/launchers/win32/LauncherUtils.h b/launchers/win32/LauncherUtils.h index a1cc553128..3e07d2af05 100644 --- a/launchers/win32/LauncherUtils.h +++ b/launchers/win32/LauncherUtils.h @@ -15,9 +15,57 @@ #include "libs/json/json.h" #include "libs/miniz.h" -class LauncherUtils -{ +class LauncherUtils { public: + class ProgressCallback : public IBindStatusCallback { + public: + HRESULT __stdcall QueryInterface(const IID &, void **) { + return E_NOINTERFACE; + } + ULONG STDMETHODCALLTYPE AddRef(void) { + return 1; + } + ULONG STDMETHODCALLTYPE Release(void) { + return 1; + } + HRESULT STDMETHODCALLTYPE OnStartBinding(DWORD dwReserved, IBinding *pib) { + return E_NOTIMPL; + } + virtual HRESULT STDMETHODCALLTYPE GetPriority(LONG *pnPriority) { + return E_NOTIMPL; + } + virtual HRESULT STDMETHODCALLTYPE OnLowResource(DWORD reserved) { + return S_OK; + } + virtual HRESULT STDMETHODCALLTYPE OnStopBinding(HRESULT hresult, LPCWSTR szError) { + return E_NOTIMPL; + } + virtual HRESULT STDMETHODCALLTYPE GetBindInfo(DWORD *grfBINDF, BINDINFO *pbindinfo) { + return E_NOTIMPL; + } + virtual HRESULT STDMETHODCALLTYPE OnDataAvailable(DWORD grfBSCF, DWORD dwSize, + FORMATETC *pformatetc, STGMEDIUM *pstgmed) { + return E_NOTIMPL; + } + virtual HRESULT STDMETHODCALLTYPE OnObjectAvailable(REFIID riid, IUnknown *punk) { + return E_NOTIMPL; + } + + virtual HRESULT __stdcall OnProgress(ULONG ulProgress, ULONG ulProgressMax, + ULONG ulStatusCode, LPCWSTR szStatusText) { + float progress = (float)ulProgress / ulProgressMax; + if (!isnan(progress)) { + onProgressCallback(progress); + } + return S_OK; + } + void setProgressCallback(std::function fn) { + onProgressCallback = std::bind(fn, std::placeholders::_1); + } + private: + std::function onProgressCallback; + }; + enum ResponseError { Open = 0, Connect, @@ -30,21 +78,18 @@ public: NoError }; - enum DeleteDirError { - NoErrorDeleting = 0, - ErrorDeletingApplicationDir, - ErrorDeletingDownloadsDir, - ErrorDeletingBothDirs - }; - struct DownloadThreadData { int _type; CString _url; CString _file; - std::function callback; - // function(type) - void setCallback(std::function fn) { - callback = std::bind(fn, std::placeholders::_1); + std::function callback; + std::function progressCallback; + // function(type, errorType) + void setCallback(std::function fn) { + callback = std::bind(fn, std::placeholders::_1, std::placeholders::_2); + } + void setProgressCallback(std::function fn) { + progressCallback = std::bind(fn, std::placeholders::_1); } }; @@ -54,16 +99,28 @@ public: std::string _path; // function(type, size) std::function callback; + std::function progressCallback; void setCallback(std::function fn) { callback = std::bind(fn, std::placeholders::_1, std::placeholders::_2); } + void setProgressCallback(std::function fn) { + progressCallback = std::bind(fn, std::placeholders::_1); + } }; struct DeleteThreadData { - CString _applicationDir; - CString _downloadsDir; - std::function callback; - void setCallback(std::function fn) { callback = std::bind(fn, std::placeholders::_1); } + CString _dirPath; + std::function callback; + std::function progressCallback; + void setCallback(std::function fn) { callback = std::bind(fn, std::placeholders::_1); } + void setProgressCallback(std::function fn) { + progressCallback = std::bind(fn, std::placeholders::_1); + } + }; + + struct ProcessData { + int processID = -1; + BOOL isOpened = FALSE; }; static BOOL parseJSON(const CString& jsonTxt, Json::Value& jsonObject); @@ -73,19 +130,27 @@ 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& files); + static uint64_t extractZip(const std::string& zipFile, const std::string& path, + std::vector& files, + std::function progressCallback); static BOOL deleteRegistryKey(const CString& registryPath); - static BOOL unzipFileOnThread(int type, const std::string& zipFile, const std::string& path, std::function callback); - static BOOL downloadFileOnThread(int type, const CString& url, const CString& file, std::function callback); - static BOOL deleteDirectoriesOnThread(const CString& applicationDir, - const CString& downloadsDir, - std::function callback); + static BOOL unzipFileOnThread(int type, const std::string& zipFile, const std::string& path, + std::function callback, + std::function progressCallback); + static BOOL downloadFileOnThread(int type, const CString& url, const CString& file, + std::function callback, + std::function progressCallback); + static BOOL deleteDirectoryOnThread(const CString& dirPath, std::function callback); + static CString urlEncodeString(const CString& url); static HWND executeOnForeground(const CString& path, const CString& params); @@ -93,5 +158,5 @@ private: // Threads static DWORD WINAPI unzipThread(LPVOID lpParameter); static DWORD WINAPI downloadThread(LPVOID lpParameter); - static DWORD WINAPI deleteDirectoriesThread(LPVOID lpParameter); + static DWORD WINAPI deleteDirectoryThread(LPVOID lpParameter); }; \ No newline at end of file diff --git a/launchers/win32/resource.h b/launchers/win32/resource.h index f5a1e3ef07..74c62b75cb 100644 --- a/launchers/win32/resource.h +++ b/launchers/win32/resource.h @@ -26,6 +26,7 @@ #define IDC_TERMS_LINK 1022 #define IDC_TROUBLE 1023 #define IDC_VOXEL 1024 +#define IDC_PROGRESS 1025 #define IDC_TROUBLE_LINK 1027 // Next default values for new objects diff --git a/libraries/animation/src/AnimVariant.cpp b/libraries/animation/src/AnimVariant.cpp index cf7228b27b..930dbed2d9 100644 --- a/libraries/animation/src/AnimVariant.cpp +++ b/libraries/animation/src/AnimVariant.cpp @@ -159,15 +159,15 @@ std::map AnimVariantMap::toDebugMap() const { arg(QString::number(value.y, 'f', 3)). arg(QString::number(value.z, 'f', 3)). arg(QString::number(value.w, 'f', 3)); - break; */ + break; } case AnimVariant::Type::String: // To prevent filling up anim stats, don't show string values /* result[pair.first] = pair.second.getString(); - break; */ + break; default: // invalid AnimVariant::Type assert(false); diff --git a/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp b/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp index fb7eddd582..5af98100dc 100644 --- a/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp +++ b/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp @@ -1108,7 +1108,7 @@ void Avatar::renderDisplayName(gpu::Batch& batch, const ViewFrustum& view, const batch.setModelTransform(textTransform); { PROFILE_RANGE_BATCH(batch, __FUNCTION__":renderText"); - renderer->draw(batch, text_x, -text_y, nameUTF8.data(), textColor, glm::vec2(-1.0f), forward); + renderer->draw(batch, text_x, -text_y, nameUTF8.data(), textColor, glm::vec2(-1.0f), true, forward); } } } diff --git a/libraries/avatars-renderer/src/avatars-renderer/SkeletonModel.cpp b/libraries/avatars-renderer/src/avatars-renderer/SkeletonModel.cpp index d8f24208b0..40b65c54a1 100644 --- a/libraries/avatars-renderer/src/avatars-renderer/SkeletonModel.cpp +++ b/libraries/avatars-renderer/src/avatars-renderer/SkeletonModel.cpp @@ -331,18 +331,19 @@ void SkeletonModel::renderBoundingCollisionShapes(RenderArgs* args, gpu::Batch& // draw a blue sphere at the capsule top point glm::vec3 topPoint = _translation + _rotation * (scale * (_boundingCapsuleLocalOffset + (0.5f * _boundingCapsuleHeight) * Vectors::UNIT_Y)); batch.setModelTransform(Transform().setTranslation(topPoint).postScale(scale * _boundingCapsuleRadius)); - geometryCache->renderSolidSphereInstance(args, batch, glm::vec4(0.6f, 0.6f, 0.8f, alpha)); + auto pipeline = geometryCache->getShapePipelinePointer(alpha < 1.0f, false, args->_renderMethod == render::Args::RenderMethod::FORWARD); + geometryCache->renderSolidSphereInstance(args, batch, glm::vec4(0.6f, 0.6f, 0.8f, alpha), pipeline); // draw a yellow sphere at the capsule bottom point glm::vec3 bottomPoint = topPoint - _rotation * glm::vec3(0.0f, scale * _boundingCapsuleHeight, 0.0f); batch.setModelTransform(Transform().setTranslation(bottomPoint).postScale(scale * _boundingCapsuleRadius)); - geometryCache->renderSolidSphereInstance(args, batch, glm::vec4(0.8f, 0.8f, 0.6f, alpha)); + geometryCache->renderSolidSphereInstance(args, batch, glm::vec4(0.8f, 0.8f, 0.6f, alpha), pipeline); // draw a green cylinder between the two points float capsuleDiameter = 2.0f * _boundingCapsuleRadius; glm::vec3 cylinderDimensions = glm::vec3(capsuleDiameter, _boundingCapsuleHeight, capsuleDiameter); batch.setModelTransform(Transform().setScale(scale * cylinderDimensions).setRotation(_rotation).setTranslation(0.5f * (topPoint + bottomPoint))); - geometryCache->renderSolidShapeInstance(args, batch, GeometryCache::Shape::Cylinder, glm::vec4(0.6f, 0.8f, 0.6f, alpha)); + geometryCache->renderSolidShapeInstance(args, batch, GeometryCache::Shape::Cylinder, glm::vec4(0.6f, 0.8f, 0.6f, alpha), pipeline); } bool SkeletonModel::hasSkeleton() { diff --git a/libraries/avatars/src/AvatarHashMap.cpp b/libraries/avatars/src/AvatarHashMap.cpp index cb14d7ef41..0c7054424f 100644 --- a/libraries/avatars/src/AvatarHashMap.cpp +++ b/libraries/avatars/src/AvatarHashMap.cpp @@ -280,6 +280,10 @@ AvatarSharedPointer AvatarHashMap::parseAvatarData(QSharedPointertrue if billboardMode is "yaw", false * if it isn't. Setting this property to false sets the billboardMode to "none". @@ -1723,6 +1726,7 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_RIGHT_MARGIN, rightMargin); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_TOP_MARGIN, topMargin); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_BOTTOM_MARGIN, bottomMargin); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_UNLIT, unlit); } // Zones only @@ -2098,6 +2102,7 @@ void EntityItemProperties::copyFromScriptValue(const QScriptValue& object, bool COPY_PROPERTY_FROM_QSCRIPTVALUE(rightMargin, float, setRightMargin); COPY_PROPERTY_FROM_QSCRIPTVALUE(topMargin, float, setTopMargin); COPY_PROPERTY_FROM_QSCRIPTVALUE(bottomMargin, float, setBottomMargin); + COPY_PROPERTY_FROM_QSCRIPTVALUE(unlit, bool, setUnlit); // Zone _keyLight.copyFromScriptValue(object, _defaultSettings); @@ -2381,6 +2386,7 @@ void EntityItemProperties::merge(const EntityItemProperties& other) { COPY_PROPERTY_IF_CHANGED(rightMargin); COPY_PROPERTY_IF_CHANGED(topMargin); COPY_PROPERTY_IF_CHANGED(bottomMargin); + COPY_PROPERTY_IF_CHANGED(unlit); // Zone _keyLight.merge(other._keyLight); @@ -2739,6 +2745,7 @@ bool EntityItemProperties::getPropertyInfo(const QString& propertyName, EntityPr ADD_PROPERTY_TO_MAP(PROP_RIGHT_MARGIN, RightMargin, rightMargin, float); ADD_PROPERTY_TO_MAP(PROP_TOP_MARGIN, TopMargin, topMargin, float); ADD_PROPERTY_TO_MAP(PROP_BOTTOM_MARGIN, BottomMargin, bottomMargin, float); + ADD_PROPERTY_TO_MAP(PROP_UNLIT, Unlit, unlit, bool); // Zone { // Keylight @@ -3168,6 +3175,7 @@ OctreeElement::AppendState EntityItemProperties::encodeEntityEditPacket(PacketTy APPEND_ENTITY_PROPERTY(PROP_RIGHT_MARGIN, properties.getRightMargin()); APPEND_ENTITY_PROPERTY(PROP_TOP_MARGIN, properties.getTopMargin()); APPEND_ENTITY_PROPERTY(PROP_BOTTOM_MARGIN, properties.getBottomMargin()); + APPEND_ENTITY_PROPERTY(PROP_UNLIT, properties.getUnlit()); } if (properties.getType() == EntityTypes::Zone) { @@ -3646,6 +3654,7 @@ bool EntityItemProperties::decodeEntityEditPacket(const unsigned char* data, int READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_RIGHT_MARGIN, float, setRightMargin); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_TOP_MARGIN, float, setTopMargin); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_BOTTOM_MARGIN, float, setBottomMargin); + READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_UNLIT, bool, setUnlit); } if (properties.getType() == EntityTypes::Zone) { @@ -4038,6 +4047,7 @@ void EntityItemProperties::markAllChanged() { _rightMarginChanged = true; _topMarginChanged = true; _bottomMarginChanged = true; + _unlitChanged = true; // Zone _keyLight.markAllChanged(); @@ -4627,6 +4637,9 @@ QList EntityItemProperties::listChangedProperties() { if (bottomMarginChanged()) { out += "bottomMargin"; } + if (unlitChanged()) { + out += "unlit"; + } // Zone getKeyLight().listChangedProperties(out); diff --git a/libraries/entities/src/EntityItemProperties.h b/libraries/entities/src/EntityItemProperties.h index 619af97ee5..456ee3cdec 100644 --- a/libraries/entities/src/EntityItemProperties.h +++ b/libraries/entities/src/EntityItemProperties.h @@ -314,6 +314,7 @@ public: DEFINE_PROPERTY_REF(PROP_RIGHT_MARGIN, RightMargin, rightMargin, float, TextEntityItem::DEFAULT_MARGIN); DEFINE_PROPERTY_REF(PROP_TOP_MARGIN, TopMargin, topMargin, float, TextEntityItem::DEFAULT_MARGIN); DEFINE_PROPERTY_REF(PROP_BOTTOM_MARGIN, BottomMargin, bottomMargin, float, TextEntityItem::DEFAULT_MARGIN); + DEFINE_PROPERTY_REF(PROP_UNLIT, Unlit, unlit, bool, false); // Zone DEFINE_PROPERTY_GROUP(KeyLight, keyLight, KeyLightPropertyGroup); diff --git a/libraries/entities/src/EntityPropertyFlags.h b/libraries/entities/src/EntityPropertyFlags.h index e86cccb997..f98ee913a2 100644 --- a/libraries/entities/src/EntityPropertyFlags.h +++ b/libraries/entities/src/EntityPropertyFlags.h @@ -241,6 +241,7 @@ enum EntityPropertyList { PROP_RIGHT_MARGIN = PROP_DERIVED_7, PROP_TOP_MARGIN = PROP_DERIVED_8, PROP_BOTTOM_MARGIN = PROP_DERIVED_9, + PROP_UNLIT = PROP_DERIVED_10, // Zone // Keylight diff --git a/libraries/entities/src/TextEntityItem.cpp b/libraries/entities/src/TextEntityItem.cpp index 5dff645c89..08200084f4 100644 --- a/libraries/entities/src/TextEntityItem.cpp +++ b/libraries/entities/src/TextEntityItem.cpp @@ -64,6 +64,7 @@ EntityItemProperties TextEntityItem::getProperties(const EntityPropertyFlags& de COPY_ENTITY_PROPERTY_TO_PROPERTIES(rightMargin, getRightMargin); COPY_ENTITY_PROPERTY_TO_PROPERTIES(topMargin, getTopMargin); COPY_ENTITY_PROPERTY_TO_PROPERTIES(bottomMargin, getBottomMargin); + COPY_ENTITY_PROPERTY_TO_PROPERTIES(unlit, getUnlit); return properties; } @@ -87,6 +88,7 @@ bool TextEntityItem::setProperties(const EntityItemProperties& properties) { SET_ENTITY_PROPERTY_FROM_PROPERTIES(rightMargin, setRightMargin); SET_ENTITY_PROPERTY_FROM_PROPERTIES(topMargin, setTopMargin); SET_ENTITY_PROPERTY_FROM_PROPERTIES(bottomMargin, setBottomMargin); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(unlit, setUnlit); if (somethingChanged) { bool wantDebug = false; @@ -129,7 +131,8 @@ int TextEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data, READ_ENTITY_PROPERTY(PROP_RIGHT_MARGIN, float, setRightMargin); READ_ENTITY_PROPERTY(PROP_TOP_MARGIN, float, setTopMargin); READ_ENTITY_PROPERTY(PROP_BOTTOM_MARGIN, float, setBottomMargin); - + READ_ENTITY_PROPERTY(PROP_UNLIT, bool, setUnlit); + return bytesRead; } @@ -149,6 +152,7 @@ EntityPropertyFlags TextEntityItem::getEntityProperties(EncodeBitstreamParams& p requestedProperties += PROP_RIGHT_MARGIN; requestedProperties += PROP_TOP_MARGIN; requestedProperties += PROP_BOTTOM_MARGIN; + requestedProperties += PROP_UNLIT; return requestedProperties; } @@ -179,6 +183,7 @@ void TextEntityItem::appendSubclassData(OctreePacketData* packetData, EncodeBits APPEND_ENTITY_PROPERTY(PROP_RIGHT_MARGIN, getRightMargin()); APPEND_ENTITY_PROPERTY(PROP_TOP_MARGIN, getTopMargin()); APPEND_ENTITY_PROPERTY(PROP_BOTTOM_MARGIN, getBottomMargin()); + APPEND_ENTITY_PROPERTY(PROP_UNLIT, getUnlit()); } glm::vec3 TextEntityItem::getRaycastDimensions() const { @@ -382,6 +387,18 @@ float TextEntityItem::getBottomMargin() const { }); } +void TextEntityItem::setUnlit(bool value) { + withWriteLock([&] { + _unlit = value; + }); +} + +bool TextEntityItem::getUnlit() const { + return resultWithReadLock([&] { + return _unlit; + }); +} + PulsePropertyGroup TextEntityItem::getPulseProperties() const { return resultWithReadLock([&] { return _pulseProperties; diff --git a/libraries/entities/src/TextEntityItem.h b/libraries/entities/src/TextEntityItem.h index 1ead9d3e15..a962482cde 100644 --- a/libraries/entities/src/TextEntityItem.h +++ b/libraries/entities/src/TextEntityItem.h @@ -97,6 +97,9 @@ public: float getBottomMargin() const; void setBottomMargin(float value); + bool getUnlit() const; + void setUnlit(bool value); + PulsePropertyGroup getPulseProperties() const; private: @@ -113,6 +116,7 @@ private: float _rightMargin; float _topMargin; float _bottomMargin; + bool _unlit; }; #endif // hifi_TextEntityItem_h diff --git a/libraries/networking/src/LimitedNodeList.cpp b/libraries/networking/src/LimitedNodeList.cpp index 3519408960..7d2f085d6f 100644 --- a/libraries/networking/src/LimitedNodeList.cpp +++ b/libraries/networking/src/LimitedNodeList.cpp @@ -584,7 +584,7 @@ SharedNodePointer LimitedNodeList::nodeWithLocalID(Node::LocalID localID) const return idIter == _localIDMap.cend() ? nullptr : idIter->second; } -void LimitedNodeList::eraseAllNodes() { +void LimitedNodeList::eraseAllNodes(QString reason) { std::vector killedNodes; { @@ -593,7 +593,7 @@ void LimitedNodeList::eraseAllNodes() { QWriteLocker writeLocker(&_nodeMutex); if (_nodeHash.size() > 0) { - qCDebug(networking) << "LimitedNodeList::eraseAllNodes() removing all nodes from NodeList."; + qCDebug(networking) << "LimitedNodeList::eraseAllNodes() removing all nodes from NodeList:" << reason; killedNodes.reserve(_nodeHash.size()); for (auto& pair : _nodeHash) { @@ -611,8 +611,8 @@ void LimitedNodeList::eraseAllNodes() { _delayedNodeAdds.clear(); } -void LimitedNodeList::reset() { - eraseAllNodes(); +void LimitedNodeList::reset(QString reason) { + eraseAllNodes(reason); // we need to make sure any socket connections are gone so wait on that here _nodeSocket.clearConnections(); @@ -1258,7 +1258,7 @@ void LimitedNodeList::setLocalSocket(const HifiSockAddr& sockAddr) { qCInfo(networking) << "Local socket has changed from" << _localSockAddr << "to" << sockAddr; _localSockAddr = sockAddr; if (_hasTCPCheckedLocalSocket) { // Force a port change for NAT: - reset(); + reset("local socket change"); _nodeSocket.rebind(0); _localSockAddr.setPort(_nodeSocket.localPort()); qCInfo(networking) << "Local port changed to" << _localSockAddr.getPort(); diff --git a/libraries/networking/src/LimitedNodeList.h b/libraries/networking/src/LimitedNodeList.h index 5f24401b10..a61deeef96 100644 --- a/libraries/networking/src/LimitedNodeList.h +++ b/libraries/networking/src/LimitedNodeList.h @@ -111,7 +111,8 @@ public: enum ConnectReason : quint32 { Connect = 0, - SilentDomainDisconnect + SilentDomainDisconnect, + Awake }; Q_ENUM(ConnectReason); @@ -347,8 +348,8 @@ public: }; public slots: - void reset(); - void eraseAllNodes(); + void reset(QString reason); + void eraseAllNodes(QString reason); void removeSilentNodes(); @@ -358,6 +359,7 @@ public slots: virtual void sendSTUNRequest(); bool killNodeWithUUID(const QUuid& nodeUUID, ConnectionID newConnectionID = NULL_CONNECTION_ID); + void noteAwakening() { _connectReason = Awake; } private slots: void sampleConnectionStats(); diff --git a/libraries/networking/src/NodeList.cpp b/libraries/networking/src/NodeList.cpp index 9dd7716823..306e0155d3 100644 --- a/libraries/networking/src/NodeList.cpp +++ b/libraries/networking/src/NodeList.cpp @@ -116,7 +116,11 @@ NodeList::NodeList(char newOwnerType, int socketListenPort, int dtlsListenPort) connect(&_domainHandler, SIGNAL(connectedToDomain(QUrl)), &_keepAlivePingTimer, SLOT(start())); connect(&_domainHandler, &DomainHandler::disconnectedFromDomain, &_keepAlivePingTimer, &QTimer::stop); - connect(&_domainHandler, &DomainHandler::limitOfSilentDomainCheckInsReached, this, [this]() { _connectReason = LimitedNodeList::SilentDomainDisconnect; }); + connect(&_domainHandler, &DomainHandler::limitOfSilentDomainCheckInsReached, this, [this]() { + if (_connectReason != Awake) { + _connectReason = SilentDomainDisconnect; + } + }); // set our sockAddrBelongsToDomainOrNode method as the connection creation filter for the udt::Socket using std::placeholders::_1; @@ -259,8 +263,7 @@ void NodeList::reset(QString reason, bool skipDomainHandlerReset) { Q_ARG(bool, skipDomainHandlerReset)); return; } - - LimitedNodeList::reset(); + LimitedNodeList::reset(reason); // lock and clear our set of ignored IDs _ignoredSetLock.lockForWrite(); @@ -337,7 +340,8 @@ void NodeList::sendDomainServerCheckIn() { if (!domainIsConnected) { auto hostname = _domainHandler.getHostname(); - qCDebug(networking_ice) << "Sending connect request to domain-server at" << hostname; + QMetaEnum metaEnum = QMetaEnum::fromType(); + qCDebug(networking_ice) << "Sending connect request ( REASON:" << QString(metaEnum.valueToKey(_connectReason)) << ") to domain-server at" << hostname; // is this our localhost domain-server? // if so we need to make sure we have an up-to-date local port in case it restarted diff --git a/libraries/networking/src/RSAKeypairGenerator.cpp b/libraries/networking/src/RSAKeypairGenerator.cpp index e83615e3df..df04297383 100644 --- a/libraries/networking/src/RSAKeypairGenerator.cpp +++ b/libraries/networking/src/RSAKeypairGenerator.cpp @@ -28,6 +28,7 @@ RSAKeypairGenerator::RSAKeypairGenerator(QObject* parent) : } void RSAKeypairGenerator::run() { + qCDebug(networking) << "KEYPAIR: thread started"; generateKeypair(); } @@ -53,6 +54,7 @@ void RSAKeypairGenerator::generateKeypair() { BN_free(exponent); return; } + qCDebug(networking) << "KEYPAIR: OpenSSL generated a" << RSA_KEY_BITS << "bit RSA key-pair"; // we don't need the BIGNUM anymore so clean that up BN_free(exponent); @@ -95,5 +97,6 @@ void RSAKeypairGenerator::generateKeypair() { OPENSSL_free(publicKeyDER); OPENSSL_free(privateKeyDER); + qCDebug(networking) << "KEYPAIR: emitting generated signal and finishing"; emit generatedKeypair(_publicKey, _privateKey); } diff --git a/libraries/networking/src/udt/PacketHeaders.h b/libraries/networking/src/udt/PacketHeaders.h index 6230b8b11e..736296a2d6 100644 --- a/libraries/networking/src/udt/PacketHeaders.h +++ b/libraries/networking/src/udt/PacketHeaders.h @@ -271,6 +271,7 @@ enum class EntityVersion : PacketVersion { ParticleShapeType, ParticleShapeTypeDeadlockFix, PrivateUserData, + TextUnlit, // Add new versions above here NUM_PACKET_TYPE, diff --git a/libraries/platform/src/platform/Platform.h b/libraries/platform/src/platform/Platform.h index 9405c77ae0..8cda6332ee 100644 --- a/libraries/platform/src/platform/Platform.h +++ b/libraries/platform/src/platform/Platform.h @@ -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(); diff --git a/libraries/platform/src/platform/PlatformKeys.h b/libraries/platform/src/platform/PlatformKeys.h index e6c255ce75..5008a4f6ce 100644 --- a/libraries/platform/src/platform/PlatformKeys.h +++ b/libraries/platform/src/platform/PlatformKeys.h @@ -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; diff --git a/libraries/platform/src/platform/Profiler.cpp b/libraries/platform/src/platform/Profiler.cpp index 1c055a5ec9..3e4dff9fd1 100644 --- a/libraries/platform/src/platform/Profiler.cpp +++ b/libraries/platform/src/platform/Profiler.cpp @@ -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() : ""); - auto gpuInfo = platform::getGPU(0); + auto gpuInfo = platform::getGPU(getMasterGPU()); const auto gpuModel = (gpuInfo.count(keys::gpu::model) ? gpuInfo[keys::gpu::model].get() : ""); @@ -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; diff --git a/libraries/platform/src/platform/backend/AndroidPlatform.cpp b/libraries/platform/src/platform/backend/AndroidPlatform.cpp index b0a4c5e67b..4487d305cf 100644 --- a/libraries/platform/src/platform/backend/AndroidPlatform.cpp +++ b/libraries/platform/src/platform/backend/AndroidPlatform.cpp @@ -10,6 +10,7 @@ #include "../PlatformKeys.h" #include #include +#include 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(); diff --git a/libraries/platform/src/platform/backend/AndroidPlatform.h b/libraries/platform/src/platform/backend/AndroidPlatform.h index 6592b3519d..488f564057 100644 --- a/libraries/platform/src/platform/backend/AndroidPlatform.h +++ b/libraries/platform/src/platform/backend/AndroidPlatform.h @@ -16,7 +16,7 @@ namespace platform { public: void enumerateCpus() override; - void enumerateGpus() override; + void enumerateGpusAndDisplays() override; void enumerateMemory() override; void enumerateComputer() override; }; diff --git a/libraries/platform/src/platform/backend/LinuxPlatform.cpp b/libraries/platform/src/platform/backend/LinuxPlatform.cpp index 61501669cb..eb2c8d4259 100644 --- a/libraries/platform/src/platform/backend/LinuxPlatform.cpp +++ b/libraries/platform/src/platform/backend/LinuxPlatform.cpp @@ -12,6 +12,9 @@ #include #include #include + +#include + #include #include @@ -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(); diff --git a/libraries/platform/src/platform/backend/LinuxPlatform.h b/libraries/platform/src/platform/backend/LinuxPlatform.h index 2f2529db7c..0d2e567e0b 100644 --- a/libraries/platform/src/platform/backend/LinuxPlatform.h +++ b/libraries/platform/src/platform/backend/LinuxPlatform.h @@ -16,7 +16,7 @@ namespace platform { public: void enumerateCpus() override; - void enumerateGpus() override; + void enumerateGpusAndDisplays() override; void enumerateMemory() override; void enumerateComputer() override; }; diff --git a/libraries/platform/src/platform/backend/MACOSPlatform.cpp b/libraries/platform/src/platform/backend/MACOSPlatform.cpp index cacbd06816..66c9cd2c5d 100644 --- a/libraries/platform/src/platform/backend/MACOSPlatform.cpp +++ b/libraries/platform/src/platform/backend/MACOSPlatform.cpp @@ -12,16 +12,22 @@ #include #include #include -#include + +#include #ifdef Q_OS_MAC #include #include #include +#include +#include + #include #include #include +#include +#include #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 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 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()); - 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 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 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 + } diff --git a/libraries/platform/src/platform/backend/MACOSPlatform.h b/libraries/platform/src/platform/backend/MACOSPlatform.h index e893dda739..f249dad001 100644 --- a/libraries/platform/src/platform/backend/MACOSPlatform.h +++ b/libraries/platform/src/platform/backend/MACOSPlatform.h @@ -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; }; diff --git a/libraries/platform/src/platform/backend/Platform.cpp b/libraries/platform/src/platform/backend/Platform.cpp index 9284e0b3a0..17d9d8019e 100644 --- a/libraries/platform/src/platform/backend/Platform.cpp +++ b/libraries/platform/src/platform/backend/Platform.cpp @@ -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(); } diff --git a/libraries/platform/src/platform/backend/PlatformInstance.cpp b/libraries/platform/src/platform/backend/PlatformInstance.cpp index 33b19cd012..038521d398 100644 --- a/libraries/platform/src/platform/backend/PlatformInstance.cpp +++ b/libraries/platform/src/platform/backend/PlatformInstance.cpp @@ -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()) { + _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, diff --git a/libraries/platform/src/platform/backend/PlatformInstance.h b/libraries/platform/src/platform/backend/PlatformInstance.h index 6ceacaa3ff..069124853e 100644 --- a/libraries/platform/src/platform/backend/PlatformInstance.h +++ b/libraries/platform/src/platform/backend/PlatformInstance.h @@ -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 _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 diff --git a/libraries/platform/src/platform/backend/WINPlatform.cpp b/libraries/platform/src/platform/backend/WINPlatform.cpp index d07bb83510..e528618fe1 100644 --- a/libraries/platform/src/platform/backend/WINPlatform.cpp +++ b/libraries/platform/src/platform/backend/WINPlatform.cpp @@ -11,21 +11,31 @@ #include #include + #include -#include + +#include #ifdef Q_OS_WIN +#include +#include +#include #include #include #include #include +#include +#pragma comment(lib, "dxgi.lib") +#include +#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()); - 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 validAdapterList; + using AdapterEntry = std::pair, std::vector>; + std::vector 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()); + 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 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().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 -} \ No newline at end of file +} diff --git a/libraries/platform/src/platform/backend/WINPlatform.h b/libraries/platform/src/platform/backend/WINPlatform.h index 4926d578f7..cc56ebfbbc 100644 --- a/libraries/platform/src/platform/backend/WINPlatform.h +++ b/libraries/platform/src/platform/backend/WINPlatform.h @@ -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; diff --git a/libraries/render-utils/src/GeometryCache.cpp b/libraries/render-utils/src/GeometryCache.cpp index 88cca1693b..a2040b02ba 100644 --- a/libraries/render-utils/src/GeometryCache.cpp +++ b/libraries/render-utils/src/GeometryCache.cpp @@ -722,42 +722,12 @@ gpu::ShaderPointer GeometryCache::_forwardUnlitShader; gpu::ShaderPointer GeometryCache::_forwardSimpleFadeShader; gpu::ShaderPointer GeometryCache::_forwardUnlitFadeShader; -render::ShapePipelinePointer GeometryCache::_simpleOpaquePipeline; -render::ShapePipelinePointer GeometryCache::_simpleTransparentPipeline; -render::ShapePipelinePointer GeometryCache::_forwardSimpleOpaquePipeline; -render::ShapePipelinePointer GeometryCache::_forwardSimpleTransparentPipeline; -render::ShapePipelinePointer GeometryCache::_simpleOpaqueFadePipeline; -render::ShapePipelinePointer GeometryCache::_simpleTransparentFadePipeline; -render::ShapePipelinePointer GeometryCache::_simpleWirePipeline; - -uint8_t GeometryCache::CUSTOM_PIPELINE_NUMBER = 0; - -render::ShapePipelinePointer GeometryCache::shapePipelineFactory(const render::ShapePlumber& plumber, const render::ShapeKey& key, gpu::Batch& batch) { - initializeShapePipelines(); - - if (key.isWireframe()) { - return _simpleWirePipeline; - } - - if (key.isFaded()) { - if (key.isTranslucent()) { - return _simpleTransparentFadePipeline; - } else { - return _simpleOpaqueFadePipeline; - } - } else { - if (key.isTranslucent()) { - return _simpleTransparentPipeline; - } else { - return _simpleOpaquePipeline; - } - } -} +std::map, render::ShapePipelinePointer> GeometryCache::_shapePipelines; GeometryCache::GeometryCache() : _nextID(0) { // Let's register its special shapePipeline factory: - registerShapePipeline(); + initializeShapePipelines(); buildShapes(); } @@ -799,16 +769,14 @@ void GeometryCache::releaseID(int id) { } void GeometryCache::initializeShapePipelines() { - if (!_simpleOpaquePipeline) { - _simpleOpaquePipeline = getShapePipeline(false, false, true, false); - _simpleTransparentPipeline = getShapePipeline(false, true, true, false); - _forwardSimpleOpaquePipeline = getShapePipeline(false, false, true, false, false, true); - _forwardSimpleTransparentPipeline = getShapePipeline(false, true, true, false, false, true); - - // FIXME: these need forward pipelines - _simpleOpaqueFadePipeline = getFadingShapePipeline(false, false, false, false, false); - _simpleTransparentFadePipeline = getFadingShapePipeline(false, true, false, false, false); - _simpleWirePipeline = getShapePipeline(false, false, true, true); + if (_shapePipelines.empty()) { + const int NUM_PIPELINES = 8; + for (int i = 0; i < NUM_PIPELINES; ++i) { + bool transparent = i & 1; + bool unlit = i & 2; + bool forward = i & 4; + _shapePipelines[std::make_tuple(transparent, unlit, forward)] = getShapePipeline(false, transparent, true, unlit, false, forward); + } } } @@ -1027,7 +995,7 @@ void GeometryCache::updateVertices(int id, const QVector& points, con int* colorData = new int[details.vertices]; int* colorDataAt = colorData; - const glm::vec3 NORMAL(0.0f, 1.0f, 0.0f); + const glm::vec3 NORMAL(0.0f, -1.0f, 0.0f); auto pointCount = points.size(); auto colorCount = colors.size(); int compactColor = 0; @@ -1105,7 +1073,7 @@ void GeometryCache::updateVertices(int id, const QVector& points, con int* colorData = new int[details.vertices]; int* colorDataAt = colorData; - const glm::vec3 NORMAL(0.0f, 1.0f, 0.0f); + const glm::vec3 NORMAL(0.0f, -1.0f, 0.0f); auto pointCount = points.size(); auto colorCount = colors.size(); for (auto i = 0; i < pointCount; i++) { @@ -1193,7 +1161,7 @@ void GeometryCache::updateVertices(int id, const QVector& points, con int* colorData = new int[details.vertices]; int* colorDataAt = colorData; - const glm::vec3 NORMAL(0.0f, 1.0f, 0.0f); + const glm::vec3 NORMAL(0.0f, -1.0f, 0.0f); for (int i = 0; i < points.size(); i++) { glm::vec3 point = points[i]; glm::vec2 texCoord = texCoords[i]; @@ -2281,8 +2249,7 @@ void renderInstances(RenderArgs* args, gpu::Batch& batch, const glm::vec4& color if (isWire) { DependencyManager::get()->renderWireShapeInstances(batch, shape, data.count(), data.buffers[INSTANCE_COLOR_BUFFER]); - } - else { + } else { DependencyManager::get()->renderShapeInstances(batch, shape, data.count(), data.buffers[INSTANCE_COLOR_BUFFER]); } }); diff --git a/libraries/render-utils/src/GeometryCache.h b/libraries/render-utils/src/GeometryCache.h index a42b059a8c..687e91f3b3 100644 --- a/libraries/render-utils/src/GeometryCache.h +++ b/libraries/render-utils/src/GeometryCache.h @@ -157,14 +157,6 @@ public: static void computeSimpleHullPointListForShape(int entityShape, const glm::vec3 &entityExtents, QVector &outPointList); - static uint8_t CUSTOM_PIPELINE_NUMBER; - static render::ShapePipelinePointer shapePipelineFactory(const render::ShapePlumber& plumber, const render::ShapeKey& key, gpu::Batch& batch); - static void registerShapePipeline() { - if (!CUSTOM_PIPELINE_NUMBER) { - CUSTOM_PIPELINE_NUMBER = render::ShapePipeline::registerCustomShapePipelineFactory(shapePipelineFactory); - } - } - int allocateID() { return _nextID++; } void releaseID(int id); static const int UNKNOWN_ID; @@ -180,11 +172,7 @@ public: gpu::PipelinePointer getWebBrowserProgram(bool transparent); static void initializeShapePipelines(); - - render::ShapePipelinePointer getOpaqueShapePipeline() { assert(_simpleOpaquePipeline != nullptr); return _simpleOpaquePipeline; } - render::ShapePipelinePointer getTransparentShapePipeline() { assert(_simpleTransparentPipeline != nullptr); return _simpleTransparentPipeline; } - render::ShapePipelinePointer getForwardOpaqueShapePipeline() { assert(_forwardSimpleOpaquePipeline != nullptr); return _forwardSimpleOpaquePipeline; } - render::ShapePipelinePointer getForwardTransparentShapePipeline() { assert(_forwardSimpleTransparentPipeline != nullptr); return _forwardSimpleTransparentPipeline; } + render::ShapePipelinePointer getShapePipelinePointer(bool transparent, bool unlit, bool forward) { return _shapePipelines[std::make_tuple(transparent, unlit, forward)]; } // Static (instanced) geometry void renderShapeInstances(gpu::Batch& batch, Shape shape, size_t count, gpu::BufferPointer& colorBuffer); @@ -195,17 +183,17 @@ public: void renderWireFadeShapeInstances(gpu::Batch& batch, Shape shape, size_t count, gpu::BufferPointer& colorBuffer, gpu::BufferPointer& fadeBuffer1, gpu::BufferPointer& fadeBuffer2, gpu::BufferPointer& fadeBuffer3); - void renderSolidShapeInstance(RenderArgs* args, gpu::Batch& batch, Shape shape, const glm::vec4& color = glm::vec4(1), - const render::ShapePipelinePointer& pipeline = _simpleOpaquePipeline); + void renderSolidShapeInstance(RenderArgs* args, gpu::Batch& batch, Shape shape, const glm::vec4& color, + const render::ShapePipelinePointer& pipeline); void renderSolidShapeInstance(RenderArgs* args, gpu::Batch& batch, Shape shape, const glm::vec3& color, - const render::ShapePipelinePointer& pipeline = _simpleOpaquePipeline) { + const render::ShapePipelinePointer& pipeline) { renderSolidShapeInstance(args, batch, shape, glm::vec4(color, 1.0f), pipeline); } - void renderWireShapeInstance(RenderArgs* args, gpu::Batch& batch, Shape shape, const glm::vec4& color = glm::vec4(1), - const render::ShapePipelinePointer& pipeline = _simpleOpaquePipeline); + void renderWireShapeInstance(RenderArgs* args, gpu::Batch& batch, Shape shape, const glm::vec4& color, + const render::ShapePipelinePointer& pipeline); void renderWireShapeInstance(RenderArgs* args, gpu::Batch& batch, Shape shape, const glm::vec3& color, - const render::ShapePipelinePointer& pipeline = _simpleOpaquePipeline) { + const render::ShapePipelinePointer& pipeline) { renderWireShapeInstance(args, batch, shape, glm::vec4(color, 1.0f), pipeline); } @@ -217,33 +205,33 @@ public: const render::ShapePipelinePointer& pipeline); void renderSolidSphereInstance(RenderArgs* args, gpu::Batch& batch, const glm::vec4& color, - const render::ShapePipelinePointer& pipeline = _simpleOpaquePipeline); + const render::ShapePipelinePointer& pipeline); void renderSolidSphereInstance(RenderArgs* args, gpu::Batch& batch, const glm::vec3& color, - const render::ShapePipelinePointer& pipeline = _simpleOpaquePipeline) { + const render::ShapePipelinePointer& pipeline) { renderSolidSphereInstance(args, batch, glm::vec4(color, 1.0f), pipeline); } - + void renderWireSphereInstance(RenderArgs* args, gpu::Batch& batch, const glm::vec4& color, - const render::ShapePipelinePointer& pipeline = _simpleWirePipeline); + const render::ShapePipelinePointer& pipeline); void renderWireSphereInstance(RenderArgs* args, gpu::Batch& batch, const glm::vec3& color, - const render::ShapePipelinePointer& pipeline = _simpleWirePipeline) { + const render::ShapePipelinePointer& pipeline) { renderWireSphereInstance(args, batch, glm::vec4(color, 1.0f), pipeline); } - + void renderSolidCubeInstance(RenderArgs* args, gpu::Batch& batch, const glm::vec4& color, - const render::ShapePipelinePointer& pipeline = _simpleOpaquePipeline); + const render::ShapePipelinePointer& pipeline); void renderSolidCubeInstance(RenderArgs* args, gpu::Batch& batch, const glm::vec3& color, - const render::ShapePipelinePointer& pipeline = _simpleOpaquePipeline) { + const render::ShapePipelinePointer& pipeline) { renderSolidCubeInstance(args, batch, glm::vec4(color, 1.0f), pipeline); } - + void renderWireCubeInstance(RenderArgs* args, gpu::Batch& batch, const glm::vec4& color, - const render::ShapePipelinePointer& pipeline = _simpleWirePipeline); + const render::ShapePipelinePointer& pipeline); void renderWireCubeInstance(RenderArgs* args, gpu::Batch& batch, const glm::vec3& color, - const render::ShapePipelinePointer& pipeline = _simpleWirePipeline) { + const render::ShapePipelinePointer& pipeline) { renderWireCubeInstance(args, batch, glm::vec4(color, 1.0f), pipeline); } - + // Dynamic geometry void renderShape(gpu::Batch& batch, Shape shape); void renderWireShape(gpu::Batch& batch, Shape shape); @@ -467,14 +455,7 @@ private: static gpu::ShaderPointer _forwardSimpleFadeShader; static gpu::ShaderPointer _forwardUnlitFadeShader; - static render::ShapePipelinePointer _simpleOpaquePipeline; - static render::ShapePipelinePointer _simpleTransparentPipeline; - static render::ShapePipelinePointer _forwardSimpleOpaquePipeline; - static render::ShapePipelinePointer _forwardSimpleTransparentPipeline; - static render::ShapePipelinePointer _simpleOpaqueFadePipeline; - static render::ShapePipelinePointer _simpleTransparentFadePipeline; - static render::ShapePipelinePointer _simpleWirePipeline; - + static std::map, render::ShapePipelinePointer> _shapePipelines; static QHash _simplePrograms; gpu::ShaderPointer _simpleOpaqueWebBrowserShader; diff --git a/libraries/render-utils/src/TextRenderer3D.cpp b/libraries/render-utils/src/TextRenderer3D.cpp index d3ea20273e..8c514df91d 100644 --- a/libraries/render-utils/src/TextRenderer3D.cpp +++ b/libraries/render-utils/src/TextRenderer3D.cpp @@ -67,11 +67,11 @@ float TextRenderer3D::getFontSize() const { } void TextRenderer3D::draw(gpu::Batch& batch, float x, float y, const QString& str, const glm::vec4& color, - const glm::vec2& bounds, bool forward) { + const glm::vec2& bounds, bool unlit, bool forward) { // The font does all the OpenGL work if (_font) { _color = color; - _font->drawString(batch, _drawInfo, str, _color, _effectType, { x, y }, bounds, forward); + _font->drawString(batch, _drawInfo, str, _color, _effectType, { x, y }, bounds, unlit, forward); } } diff --git a/libraries/render-utils/src/TextRenderer3D.h b/libraries/render-utils/src/TextRenderer3D.h index ce4dd9f9e5..8118aa883c 100644 --- a/libraries/render-utils/src/TextRenderer3D.h +++ b/libraries/render-utils/src/TextRenderer3D.h @@ -39,7 +39,7 @@ public: float getFontSize() const; // Pixel size void draw(gpu::Batch& batch, float x, float y, const QString& str, const glm::vec4& color, - const glm::vec2& bounds, bool forward); + const glm::vec2& bounds, bool unlit, bool forward); private: TextRenderer3D(const char* family, float pointSize, int weight = -1, bool italic = false, diff --git a/libraries/render-utils/src/forward_simple.slf b/libraries/render-utils/src/forward_simple.slf index 677c369033..50e3cdc511 100644 --- a/libraries/render-utils/src/forward_simple.slf +++ b/libraries/render-utils/src/forward_simple.slf @@ -52,7 +52,7 @@ void main(void) { 1.0, DEFAULT_OCCLUSION, fragPosition, - normal, + normal * (2.0 * float(gl_FrontFacing) - 1.0), diffuse, DEFAULT_FRESNEL, length(specular), diff --git a/libraries/render-utils/src/forward_simple_textured.slf b/libraries/render-utils/src/forward_simple_textured.slf index 373ab13d1a..79e1bf1dbc 100644 --- a/libraries/render-utils/src/forward_simple_textured.slf +++ b/libraries/render-utils/src/forward_simple_textured.slf @@ -49,7 +49,7 @@ void main(void) { 1.0, DEFAULT_OCCLUSION, fragPosition, - normalize(_normalWS), + normalize(_normalWS) * (2.0 * float(gl_FrontFacing) - 1.0), albedo, fresnel, metallic, diff --git a/libraries/render-utils/src/forward_simple_textured_transparent.slf b/libraries/render-utils/src/forward_simple_textured_transparent.slf index 1b5047507b..6cff37ba9d 100644 --- a/libraries/render-utils/src/forward_simple_textured_transparent.slf +++ b/libraries/render-utils/src/forward_simple_textured_transparent.slf @@ -50,7 +50,7 @@ void main(void) { 1.0, DEFAULT_OCCLUSION, fragPosition, - normalize(_normalWS), + normalize(_normalWS) * (2.0 * float(gl_FrontFacing) - 1.0), albedo, fresnel, metallic, diff --git a/libraries/render-utils/src/render-utils/forward_sdf_text3D.slp b/libraries/render-utils/src/render-utils/sdf_text3D_forward.slp similarity index 100% rename from libraries/render-utils/src/render-utils/forward_sdf_text3D.slp rename to libraries/render-utils/src/render-utils/sdf_text3D_forward.slp diff --git a/libraries/render-utils/src/render-utils/sdf_text3D_translucent.slp b/libraries/render-utils/src/render-utils/sdf_text3D_translucent.slp new file mode 100644 index 0000000000..52dfbe4f9c --- /dev/null +++ b/libraries/render-utils/src/render-utils/sdf_text3D_translucent.slp @@ -0,0 +1 @@ +VERTEX sdf_text3D \ No newline at end of file diff --git a/libraries/render-utils/src/render-utils/sdf_text3D_translucent_unlit.slp b/libraries/render-utils/src/render-utils/sdf_text3D_translucent_unlit.slp new file mode 100644 index 0000000000..52dfbe4f9c --- /dev/null +++ b/libraries/render-utils/src/render-utils/sdf_text3D_translucent_unlit.slp @@ -0,0 +1 @@ +VERTEX sdf_text3D \ No newline at end of file diff --git a/libraries/render-utils/src/render-utils/sdf_text3D_transparent.slp b/libraries/render-utils/src/render-utils/sdf_text3D_transparent.slp deleted file mode 100644 index 3eea3a0da0..0000000000 --- a/libraries/render-utils/src/render-utils/sdf_text3D_transparent.slp +++ /dev/null @@ -1 +0,0 @@ -VERTEX sdf_text3D diff --git a/libraries/render-utils/src/render-utils/sdf_text3D_unlit.slp b/libraries/render-utils/src/render-utils/sdf_text3D_unlit.slp new file mode 100644 index 0000000000..52dfbe4f9c --- /dev/null +++ b/libraries/render-utils/src/render-utils/sdf_text3D_unlit.slp @@ -0,0 +1 @@ +VERTEX sdf_text3D \ No newline at end of file diff --git a/libraries/render-utils/src/forward_sdf_text3D.slf b/libraries/render-utils/src/sdf_text3D_forward.slf similarity index 97% rename from libraries/render-utils/src/forward_sdf_text3D.slf rename to libraries/render-utils/src/sdf_text3D_forward.slf index 09b10c0c42..02ad49fc43 100644 --- a/libraries/render-utils/src/forward_sdf_text3D.slf +++ b/libraries/render-utils/src/sdf_text3D_forward.slf @@ -1,7 +1,7 @@ <@include gpu/Config.slh@> <$VERSION_HEADER$> // Generated on <$_SCRIBE_DATE$> -// sdf_text3D_transparent.frag +// sdf_text3D_forward.frag // fragment shader // // Created by Bradley Austin Davis on 2015-02-04 @@ -53,5 +53,5 @@ void main() { DEFAULT_FRESNEL, DEFAULT_METALLIC, DEFAULT_ROUGHNESS), - 1.0); + alpha); } \ No newline at end of file diff --git a/libraries/render-utils/src/sdf_text3D_transparent.slf b/libraries/render-utils/src/sdf_text3D_translucent.slf similarity index 92% rename from libraries/render-utils/src/sdf_text3D_transparent.slf rename to libraries/render-utils/src/sdf_text3D_translucent.slf index c4a80091de..bf72345f38 100644 --- a/libraries/render-utils/src/sdf_text3D_transparent.slf +++ b/libraries/render-utils/src/sdf_text3D_translucent.slf @@ -1,7 +1,7 @@ <@include gpu/Config.slh@> <$VERSION_HEADER$> // Generated on <$_SCRIBE_DATE$> -// sdf_text3D_transparent.frag +// sdf_text3D_translucent.frag // fragment shader // // Created by Bradley Austin Davis on 2015-02-04 @@ -12,8 +12,8 @@ <@include DefaultMaterials.slh@> -<@include ForwardGlobalLight.slh@> -<$declareEvalGlobalLightingAlphaBlended()$> +<@include DeferredGlobalLight.slh@> +<$declareEvalGlobalLightingAlphaBlendedWithHaze()$> <@include gpu/Transform.slh@> <$declareStandardCameraTransform()$> diff --git a/libraries/render-utils/src/sdf_text3D_translucent_unlit.slf b/libraries/render-utils/src/sdf_text3D_translucent_unlit.slf new file mode 100644 index 0000000000..43742b0c53 --- /dev/null +++ b/libraries/render-utils/src/sdf_text3D_translucent_unlit.slf @@ -0,0 +1,38 @@ +<@include gpu/Config.slh@> +<$VERSION_HEADER$> +// Generated on <$_SCRIBE_DATE$> +// sdf_text3D_translucent.frag +// fragment shader +// +// Created by Bradley Austin Davis on 2015-02-04 +// Based on fragment shader code from +// https://github.com/paulhoux/Cinder-Samples/blob/master/TextRendering/include/text/Text.cpp +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html + +<@include DefaultMaterials.slh@> + +<@include LightingModel.slh@> + +<@include render-utils/ShaderConstants.h@> + +<@include sdf_text3D.slh@> +<$declareEvalSDFSuperSampled()$> + +layout(location=RENDER_UTILS_ATTR_COLOR) in vec4 _color; +layout(location=RENDER_UTILS_ATTR_TEXCOORD01) in vec4 _texCoord01; +#define _texCoord0 _texCoord01.xy +#define _texCoord1 _texCoord01.zw + +layout(location=0) out vec4 _fragColor0; + +void main() { + float a = evalSDFSuperSampled(_texCoord0); + + float alpha = a * _color.a; + if (alpha <= 0.0) { + discard; + } + + _fragColor0 = vec4(_color.rgb * isUnlitEnabled(), alpha); +} \ No newline at end of file diff --git a/libraries/render-utils/src/sdf_text3D_unlit.slf b/libraries/render-utils/src/sdf_text3D_unlit.slf new file mode 100644 index 0000000000..db8366518e --- /dev/null +++ b/libraries/render-utils/src/sdf_text3D_unlit.slf @@ -0,0 +1,32 @@ +<@include gpu/Config.slh@> +<$VERSION_HEADER$> +// Generated on <$_SCRIBE_DATE$> +// sdf_text3D_unlit.frag +// fragment shader +// +// Created by Bradley Austin Davis on 2015-02-04 +// Based on fragment shader code from +// https://github.com/paulhoux/Cinder-Samples/blob/master/TextRendering/include/text/Text.cpp +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html + +<@include DeferredBufferWrite.slh@> +<@include render-utils/ShaderConstants.h@> + +<@include sdf_text3D.slh@> +<$declareEvalSDFSuperSampled()$> + +layout(location=RENDER_UTILS_ATTR_NORMAL_WS) in vec3 _normalWS; +layout(location=RENDER_UTILS_ATTR_COLOR) in vec4 _color; +layout(location=RENDER_UTILS_ATTR_TEXCOORD01) in vec4 _texCoord01; +#define _texCoord0 _texCoord01.xy +#define _texCoord1 _texCoord01.zw + +void main() { + float a = evalSDFSuperSampled(_texCoord0); + + packDeferredFragmentUnlit( + normalize(_normalWS), + a, + _color.rgb); +} \ No newline at end of file diff --git a/libraries/render-utils/src/simple.slf b/libraries/render-utils/src/simple.slf index 469c0976aa..884c7468bb 100644 --- a/libraries/render-utils/src/simple.slf +++ b/libraries/render-utils/src/simple.slf @@ -60,7 +60,7 @@ float getProceduralFragmentWithPosition(inout ProceduralFragmentWithPosition pro #line 2030 void main(void) { - vec3 normal = normalize(_normalWS.xyz); + vec3 normal = normalize(_normalWS.xyz) * (2.0 * float(gl_FrontFacing) - 1.0); vec3 diffuse = _color.rgb; float roughness = DEFAULT_ROUGHNESS; float metallic = DEFAULT_METALLIC; diff --git a/libraries/render-utils/src/simple_textured.slf b/libraries/render-utils/src/simple_textured.slf index dbc49fcb5d..c79ff8cea3 100644 --- a/libraries/render-utils/src/simple_textured.slf +++ b/libraries/render-utils/src/simple_textured.slf @@ -33,7 +33,7 @@ void main(void) { texel.rgb *= _color.rgb; packDeferredFragment( - normalize(_normalWS), + normalize(_normalWS) * (2.0 * float(gl_FrontFacing) - 1.0), 1.0, texel.rgb, DEFAULT_ROUGHNESS, diff --git a/libraries/render-utils/src/simple_textured_fade.slf b/libraries/render-utils/src/simple_textured_fade.slf index 5a9eb0688e..5fa4a70fad 100644 --- a/libraries/render-utils/src/simple_textured_fade.slf +++ b/libraries/render-utils/src/simple_textured_fade.slf @@ -48,13 +48,13 @@ void main(void) { const float ALPHA_THRESHOLD = 0.999; if (texel.a < ALPHA_THRESHOLD) { packDeferredFragmentTranslucent( - normalize(_normalWS), + normalize(_normalWS) * (2.0 * float(gl_FrontFacing) - 1.0), texel.a, texel.rgb + fadeEmissive, DEFAULT_ROUGHNESS); } else { packDeferredFragment( - normalize(_normalWS), + normalize(_normalWS) * (2.0 * float(gl_FrontFacing) - 1.0), 1.0, texel.rgb, DEFAULT_ROUGHNESS, diff --git a/libraries/render-utils/src/simple_textured_unlit.slf b/libraries/render-utils/src/simple_textured_unlit.slf index 475428f0ae..7aa1970aee 100644 --- a/libraries/render-utils/src/simple_textured_unlit.slf +++ b/libraries/render-utils/src/simple_textured_unlit.slf @@ -36,13 +36,13 @@ void main(void) { const float ALPHA_THRESHOLD = 0.999; if (texel.a < ALPHA_THRESHOLD) { packDeferredFragmentTranslucent( - normalize(_normalWS), + normalize(_normalWS) * (2.0 * float(gl_FrontFacing) - 1.0), texel.a, texel.rgb, DEFAULT_ROUGHNESS); } else { packDeferredFragmentUnlit( - normalize(_normalWS), + normalize(_normalWS) * (2.0 * float(gl_FrontFacing) - 1.0), 1.0, texel.rgb); } diff --git a/libraries/render-utils/src/simple_textured_unlit_fade.slf b/libraries/render-utils/src/simple_textured_unlit_fade.slf index d0ba4c13fe..079a046757 100644 --- a/libraries/render-utils/src/simple_textured_unlit_fade.slf +++ b/libraries/render-utils/src/simple_textured_unlit_fade.slf @@ -48,13 +48,13 @@ void main(void) { const float ALPHA_THRESHOLD = 0.999; if (texel.a < ALPHA_THRESHOLD) { packDeferredFragmentTranslucent( - normalize(_normalWS), + normalize(_normalWS) * (2.0 * float(gl_FrontFacing) - 1.0), texel.a, texel.rgb + fadeEmissive, DEFAULT_ROUGHNESS); } else { packDeferredFragmentUnlit( - normalize(_normalWS), + normalize(_normalWS) * (2.0 * float(gl_FrontFacing) - 1.0), 1.0, texel.rgb + fadeEmissive); } diff --git a/libraries/render-utils/src/simple_transparent.slf b/libraries/render-utils/src/simple_transparent.slf index 6d8348f50c..4fc7da60ea 100644 --- a/libraries/render-utils/src/simple_transparent.slf +++ b/libraries/render-utils/src/simple_transparent.slf @@ -65,7 +65,7 @@ float getProceduralFragmentWithPosition(inout ProceduralFragmentWithPosition pro #line 2030 void main(void) { - vec3 normal = normalize(_normalWS.xyz); + vec3 normal = normalize(_normalWS.xyz) * (2.0 * float(gl_FrontFacing) - 1.0); vec3 diffuse = _color.rgb; float alpha = _color.a; float occlusion = DEFAULT_OCCLUSION; diff --git a/libraries/render-utils/src/simple_transparent_textured.slf b/libraries/render-utils/src/simple_transparent_textured.slf index 9f8a88c7c2..64e052b376 100644 --- a/libraries/render-utils/src/simple_transparent_textured.slf +++ b/libraries/render-utils/src/simple_transparent_textured.slf @@ -50,7 +50,7 @@ void main(void) { 1.0, DEFAULT_OCCLUSION, fragPosition, - normalize(_normalWS), + normalize(_normalWS) * (2.0 * float(gl_FrontFacing) - 1.0), albedo, fresnel, metallic, diff --git a/libraries/render-utils/src/simple_transparent_textured_fade.slf b/libraries/render-utils/src/simple_transparent_textured_fade.slf index d401989f90..44e849be69 100644 --- a/libraries/render-utils/src/simple_transparent_textured_fade.slf +++ b/libraries/render-utils/src/simple_transparent_textured_fade.slf @@ -52,7 +52,7 @@ void main(void) { texel.a *= abs(_color.a); vec3 fragPosition = _positionES.xyz; - vec3 fragNormal = normalize(_normalWS); + vec3 fragNormal = normalize(_normalWS) * (2.0 * float(gl_FrontFacing) - 1.0); TransformCamera cam = getTransformCamera(); diff --git a/libraries/render-utils/src/text/Font.cpp b/libraries/render-utils/src/text/Font.cpp index c69db5e055..eee6a7daea 100644 --- a/libraries/render-utils/src/text/Font.cpp +++ b/libraries/render-utils/src/text/Font.cpp @@ -15,9 +15,7 @@ static std::mutex fontMutex; -gpu::PipelinePointer Font::_deferredPipeline; -gpu::PipelinePointer Font::_forwardPipeline; -gpu::PipelinePointer Font::_transparentPipeline; +std::map, gpu::PipelinePointer> Font::_pipelines; gpu::Stream::FormatPointer Font::_format; struct TextureVertex { @@ -221,31 +219,28 @@ void Font::read(QIODevice& in) { } void Font::setupGPU() { - if (!_deferredPipeline) { - // Setup render pipeline - { - { - auto state = std::make_shared(); - state->setCullMode(gpu::State::CULL_BACK); - state->setDepthTest(true, true, gpu::LESS_EQUAL); - state->setBlendFunction(false, - gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA, - gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE); - PrepareStencil::testMaskDrawShape(*state); - _deferredPipeline = gpu::Pipeline::create(gpu::Shader::createProgram(shader::render_utils::program::sdf_text3D), state); - _forwardPipeline = gpu::Pipeline::create(gpu::Shader::createProgram(shader::render_utils::program::forward_sdf_text3D), state); - } + if (_pipelines.empty()) { + using namespace shader::render_utils::program; - { - auto state = std::make_shared(); - state->setCullMode(gpu::State::CULL_BACK); - state->setDepthTest(true, true, gpu::LESS_EQUAL); - state->setBlendFunction(true, - gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA, - gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE); + static const std::vector> keys = { + std::make_tuple(false, false, false, sdf_text3D), std::make_tuple(true, false, false, sdf_text3D_translucent), + std::make_tuple(false, true, false, sdf_text3D_unlit), std::make_tuple(true, true, false, sdf_text3D_translucent_unlit), + std::make_tuple(false, false, true, sdf_text3D_forward), std::make_tuple(true, false, true, sdf_text3D_forward/*sdf_text3D_translucent_forward*/), + std::make_tuple(false, true, true, sdf_text3D_translucent_unlit/*sdf_text3D_unlit_forward*/), std::make_tuple(true, true, true, sdf_text3D_translucent_unlit/*sdf_text3D_translucent_unlit_forward*/) + }; + for (auto& key : keys) { + auto state = std::make_shared(); + state->setCullMode(gpu::State::CULL_BACK); + state->setDepthTest(true, true, gpu::LESS_EQUAL); + state->setBlendFunction(std::get<0>(key), + gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA, + gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE); + if (std::get<0>(key)) { PrepareStencil::testMask(*state); - _transparentPipeline = gpu::Pipeline::create(gpu::Shader::createProgram(shader::render_utils::program::sdf_text3D_transparent), state); + } else { + PrepareStencil::testMaskDrawShape(*state); } + _pipelines[std::make_tuple(std::get<0>(key), std::get<1>(key), std::get<2>(key))] = gpu::Pipeline::create(gpu::Shader::createProgram(std::get<3>(key)), state); } // Sanity checks @@ -349,7 +344,7 @@ void Font::buildVertices(Font::DrawInfo& drawInfo, const QString& str, const glm } void Font::drawString(gpu::Batch& batch, Font::DrawInfo& drawInfo, const QString& str, const glm::vec4& color, - EffectType effectType, const glm::vec2& origin, const glm::vec2& bounds, bool forward) { + EffectType effectType, const glm::vec2& origin, const glm::vec2& bounds, bool unlit, bool forward) { if (str == "") { return; } @@ -376,7 +371,7 @@ void Font::drawString(gpu::Batch& batch, Font::DrawInfo& drawInfo, const QString } // need the gamma corrected color here - batch.setPipeline(color.a < 1.0f ? _transparentPipeline : (forward ? _forwardPipeline : _deferredPipeline)); + batch.setPipeline(_pipelines[std::make_tuple(color.a < 1.0f, unlit, forward)]); batch.setInputFormat(_format); batch.setInputBuffer(0, drawInfo.verticesBuffer, 0, _format->getChannels().at(0)._stride); batch.setResourceTexture(render_utils::slot::texture::TextFont, _texture); diff --git a/libraries/render-utils/src/text/Font.h b/libraries/render-utils/src/text/Font.h index 893ab59981..be1e890e3d 100644 --- a/libraries/render-utils/src/text/Font.h +++ b/libraries/render-utils/src/text/Font.h @@ -46,11 +46,10 @@ public: // Render string to batch void drawString(gpu::Batch& batch, DrawInfo& drawInfo, const QString& str, const glm::vec4& color, EffectType effectType, - const glm::vec2& origin, const glm::vec2& bound, bool forward); + const glm::vec2& origin, const glm::vec2& bound, bool unlit, bool forward); static Pointer load(const QString& family); - private: static Pointer load(QIODevice& fontFile); QStringList tokenizeForWrapping(const QString& str) const; @@ -80,9 +79,7 @@ private: gpu::TexturePointer _texture; gpu::BufferStreamPointer _stream; - static gpu::PipelinePointer _deferredPipeline; - static gpu::PipelinePointer _forwardPipeline; - static gpu::PipelinePointer _transparentPipeline; + static std::map, gpu::PipelinePointer> _pipelines; static gpu::Stream::FormatPointer _format; }; diff --git a/libraries/render/src/render/Item.h b/libraries/render/src/render/Item.h index 4736359832..6b66e844c0 100644 --- a/libraries/render/src/render/Item.h +++ b/libraries/render/src/render/Item.h @@ -614,7 +614,7 @@ public: virtual ShapeKey getShapeKey() = 0; virtual Item::Bound getBound() = 0; virtual void render(RenderArgs* args) = 0; - virtual uint32_t metaFetchMetaSubItems(ItemIDs& subItems) = 0; + virtual uint32_t metaFetchMetaSubItems(ItemIDs& subItems) const = 0; }; template <> const ItemKey payloadGetKey(const PayloadProxyInterface::Pointer& payload); diff --git a/libraries/script-engine/src/ScriptEngines.cpp b/libraries/script-engine/src/ScriptEngines.cpp index 17f2aea9a5..f94fca3463 100644 --- a/libraries/script-engine/src/ScriptEngines.cpp +++ b/libraries/script-engine/src/ScriptEngines.cpp @@ -29,6 +29,7 @@ static const QString DESKTOP_LOCATION = QStandardPaths::writableLocation(QStanda static const bool HIFI_SCRIPT_DEBUGGABLES { true }; static const QString SETTINGS_KEY { "RunningScripts" }; static const QUrl DEFAULT_SCRIPTS_LOCATION { "file:///~//defaultScripts.js" }; + // Using a QVariantList so this is human-readable in the settings file static Setting::Handle runningScriptsHandle(SETTINGS_KEY, { QVariant(DEFAULT_SCRIPTS_LOCATION) }); @@ -64,8 +65,8 @@ void ScriptEngines::onErrorLoadingScript(const QString& url) { emit errorLoadingScript(url); } -ScriptEngines::ScriptEngines(ScriptEngine::Context context) - : _context(context) +ScriptEngines::ScriptEngines(ScriptEngine::Context context, const QUrl& defaultScriptsOverride) + : _context(context), _defaultScriptsOverride(defaultScriptsOverride) { _scriptsModelFilter.setSourceModel(&_scriptsModel); _scriptsModelFilter.sort(0, Qt::AscendingOrder); @@ -322,13 +323,22 @@ void ScriptEngines::loadScripts() { // loads all saved scripts auto runningScripts = runningScriptsHandle.get(); + bool defaultScriptsOverrideSet = !_defaultScriptsOverride.isEmpty(); for (auto script : runningScripts) { - auto string = script.toString(); - if (!string.isEmpty()) { - loadScript(string); + auto url = script.toUrl(); + if (!url.isEmpty()) { + if (defaultScriptsOverrideSet && url == DEFAULT_SCRIPTS_LOCATION) { + _defaultScriptsWasRunning = true; + } else { + loadScript(url); + } } } + + if (defaultScriptsOverrideSet) { + loadScript(_defaultScriptsOverride, false); + } } void ScriptEngines::saveScripts() { @@ -359,6 +369,10 @@ void ScriptEngines::saveScripts() { } } + if (_defaultScriptsWasRunning) { + list.append(DEFAULT_SCRIPTS_LOCATION); + } + runningScriptsHandle.set(list); } diff --git a/libraries/script-engine/src/ScriptEngines.h b/libraries/script-engine/src/ScriptEngines.h index 4db150fce5..de836a3e09 100644 --- a/libraries/script-engine/src/ScriptEngines.h +++ b/libraries/script-engine/src/ScriptEngines.h @@ -56,7 +56,7 @@ class ScriptEngines : public QObject, public Dependency { public: using ScriptInitializer = ScriptInitializerMixin::ScriptInitializer; - ScriptEngines(ScriptEngine::Context context); + ScriptEngines(ScriptEngine::Context context, const QUrl& defaultScriptsOverride = QUrl()); void registerScriptInitializer(ScriptInitializer initializer); int runScriptInitializers(ScriptEnginePointer engine); void loadScripts(); @@ -284,6 +284,12 @@ protected: std::atomic _isReloading { false }; bool _defaultScriptsLocationOverridden { false }; QString _debugScriptUrl; + + // If this is set, defaultScripts.js will not be run if it is in the settings, + // and this will be run instead. This script will not be persisted to settings. + const QUrl _defaultScriptsOverride { }; + // If an override is set, this will be true if defaultScripts.js was previously running. + bool _defaultScriptsWasRunning { false }; }; QUrl normalizeScriptURL(const QUrl& rawScriptURL); diff --git a/script-archive/example/ui/MyEnergyBar.js b/script-archive/example/ui/MyEnergyBar.js index 2d01a66317..98fb35814c 100644 --- a/script-archive/example/ui/MyEnergyBar.js +++ b/script-archive/example/ui/MyEnergyBar.js @@ -33,14 +33,14 @@ var bar = Overlays.addOverlay("text", { // Takes an energy value between 0 and 1 and sets energy bar width appropriately function setEnergy(energy) { - energy = clamp(energy, 0, 1); + energy = hifiClamp(energy, 0, 1); var barWidth = totalWidth * energy; var color = energy <= lowEnergyThreshold ? lowEnergyColor: energyColor; Overlays.editOverlay(bar, { width: barWidth, backgroundColor: color}); } function update() { - currentEnergy = clamp(MyAvatar.energy, 0, 1); + currentEnergy = hifiClamp(MyAvatar.energy, 0, 1); setEnergy(currentEnergy); } diff --git a/script-archive/example/ui/energyBar.js b/script-archive/example/ui/energyBar.js index 498eef2751..6a97f88472 100644 --- a/script-archive/example/ui/energyBar.js +++ b/script-archive/example/ui/energyBar.js @@ -45,14 +45,14 @@ var bar = Overlays.addOverlay("text", { // Takes an energy value between 0 and 1 and sets energy bar width appropriately function setEnergy(energy) { - energy = clamp(energy, 0, 1); + energy = hifiClamp(energy, 0, 1); var barWidth = totalWidth * energy; var color = energy <= lowEnergyThreshold ? lowEnergyColor: energyColor; Overlays.editOverlay(bar, { width: barWidth, backgroundColor: color}); } function update() { - currentEnergy = clamp(MyAvatar.energy, 0, 1); + currentEnergy = hifiClamp(MyAvatar.energy, 0, 1); setEnergy(currentEnergy); } diff --git a/scripts/developer/tests/interactiveWindowTest.js b/scripts/developer/tests/interactiveWindowTest.js index c17deba617..16388d52c0 100644 --- a/scripts/developer/tests/interactiveWindowTest.js +++ b/scripts/developer/tests/interactiveWindowTest.js @@ -19,7 +19,7 @@ function getPreferredTitle() { var virtualWindow = Desktop.createWindow(Script.resourcesPath() + 'qml/OverlayWindowTest.qml', { title: getPreferredTitle(), - flags: Desktop.ALWAYS_ON_TOP, + additionalFlags: Desktop.ALWAYS_ON_TOP, presentationMode: getPreferredPresentationMode(), size: {x: 500, y: 400} }); diff --git a/scripts/developer/utilities/lib/prop/PropGroup.qml b/scripts/developer/utilities/lib/prop/PropGroup.qml index 848ff8b288..c6b2c694f6 100644 --- a/scripts/developer/utilities/lib/prop/PropGroup.qml +++ b/scripts/developer/utilities/lib/prop/PropGroup.qml @@ -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 = {}; diff --git a/scripts/developer/utilities/render/engineProfiler.js b/scripts/developer/utilities/render/engineProfiler.js index 418cab8622..88ab388c75 100644 --- a/scripts/developer/utilities/render/engineProfiler.js +++ b/scripts/developer/utilities/render/engineProfiler.js @@ -36,7 +36,7 @@ var qml = Script.resolvePath(QMLAPP_URL); window = Desktop.createWindow(Script.resolvePath(QMLAPP_URL), { title: 'Render Engine Profiler', - flags: Desktop.ALWAYS_ON_TOP, + additionalFlags: Desktop.ALWAYS_ON_TOP, presentationMode: Desktop.PresentationMode.NATIVE, size: {x: 500, y: 100} }); diff --git a/scripts/developer/utilities/render/lod.js b/scripts/developer/utilities/render/lod.js index f3e4208034..ba8cbf65f8 100644 --- a/scripts/developer/utilities/render/lod.js +++ b/scripts/developer/utilities/render/lod.js @@ -52,7 +52,7 @@ var qml = Script.resolvePath(QMLAPP_URL); window = Desktop.createWindow(Script.resolvePath(QMLAPP_URL), { title: TABLET_BUTTON_NAME, - flags: Desktop.ALWAYS_ON_TOP, + additionalFlags: Desktop.ALWAYS_ON_TOP, presentationMode: Desktop.PresentationMode.NATIVE, size: {x: 400, y: 600} }); diff --git a/scripts/developer/utilities/render/performanceSetup.qml b/scripts/developer/utilities/render/performanceSetup.qml index 4654736f72..be9b6a3271 100644 --- a/scripts/developer/utilities/render/performanceSetup.qml +++ b/scripts/developer/utilities/render/performanceSetup.qml @@ -51,6 +51,7 @@ Rectangle { } Prop.PropFolderPanel { label: "Platform" + isUnfold: true panelFrameData: Component { Platform { } diff --git a/scripts/developer/utilities/workload/avatars.js b/scripts/developer/utilities/workload/avatars.js index 3080ef09db..c0aaec9b43 100644 --- a/scripts/developer/utilities/workload/avatars.js +++ b/scripts/developer/utilities/workload/avatars.js @@ -52,7 +52,7 @@ var qml = Script.resolvePath(QMLAPP_URL); window = Desktop.createWindow(Script.resolvePath(QMLAPP_URL), { title: TABLET_BUTTON_NAME, - flags: Desktop.ALWAYS_ON_TOP, + additionalFlags: Desktop.ALWAYS_ON_TOP, presentationMode: Desktop.PresentationMode.NATIVE, size: {x: 400, y: 600} }); diff --git a/scripts/developer/utilities/workload/workload.js b/scripts/developer/utilities/workload/workload.js index ada3cbbf09..8871936a95 100644 --- a/scripts/developer/utilities/workload/workload.js +++ b/scripts/developer/utilities/workload/workload.js @@ -52,7 +52,7 @@ var qml = Script.resolvePath(QMLAPP_URL); window = Desktop.createWindow(Script.resolvePath(QMLAPP_URL), { title: 'Workload Inspector', - flags: Desktop.ALWAYS_ON_TOP, + additionalFlags: Desktop.ALWAYS_ON_TOP, presentationMode: Desktop.PresentationMode.NATIVE, size: {x: 400, y: 600} }); diff --git a/scripts/simplifiedUI/defaultScripts.js b/scripts/simplifiedUI/defaultScripts.js deleted file mode 100644 index ccefcc3a95..0000000000 --- a/scripts/simplifiedUI/defaultScripts.js +++ /dev/null @@ -1,39 +0,0 @@ -"use strict"; -/* jslint vars: true, plusplus: true */ - -// -// defaultScripts.js -// -// Authors: Zach Fox -// Created: 2019-05-23 -// Copyright 2019 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -var DEFAULT_SCRIPTS_SEPARATE = [ - "system/controllers/controllerScripts.js", - "ui/simplifiedUI.js" -]; -function loadSeparateDefaults() { - for (var i in DEFAULT_SCRIPTS_SEPARATE) { - Script.load(DEFAULT_SCRIPTS_SEPARATE[i]); - } -} - - -var DEFAULT_SCRIPTS_COMBINED = [ - "system/request-service.js", - "system/progress.js", - "system/away.js" -]; -function runDefaultsTogether() { - for (var i in DEFAULT_SCRIPTS_COMBINED) { - Script.include(DEFAULT_SCRIPTS_COMBINED[i]); - } - loadSeparateDefaults(); -} - - -runDefaultsTogether(); diff --git a/scripts/simplifiedUI/modules/appUi.js b/scripts/simplifiedUI/modules/appUi.js deleted file mode 100644 index 9771348377..0000000000 --- a/scripts/simplifiedUI/modules/appUi.js +++ /dev/null @@ -1,387 +0,0 @@ -"use strict"; -/* global Tablet, Script */ -// -// libraries/appUi.js -// -// Created by Howard Stearns on 3/20/18. -// Copyright 2018 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -function AppUi(properties) { - var request = Script.require('request').request; - /* Example development order: - 1. var AppUi = Script.require('appUi'); - 2. Put appname-i.svg, appname-a.svg in graphicsDirectory (where non-default graphicsDirectory can be added in #3). - 3. ui = new AppUi({buttonName: "APPNAME", home: "qml-or-html-path"}); - (And if converting an existing app, - define var tablet = ui.tablet, button = ui.button; as needed. - remove button.clicked.[dis]connect and tablet.remove(button).) - 4. Define onOpened and onClosed behavior in #3, if any. - (And if converting an existing app, remove screenChanged.[dis]connect.) - 5. Define onMessage and sendMessage in #3, if any. onMessage is wired/unwired on open/close. If you - want a handler to be "always on", connect it yourself at script startup. - (And if converting an existing app, remove code that [un]wires that message handling such as - fromQml/sendToQml or webEventReceived/emitScriptEvent.) - 6. (If converting an existing app, cleanup stuff that is no longer necessary, like references to button, tablet, - and use isOpen, open(), and close() as needed.) - 7. lint! - */ - var that = this; - function defaultButton(name, suffix) { - var base = that[name] || (that.buttonPrefix + suffix); - that[name] = (base.indexOf('/') >= 0) ? base : (that.graphicsDirectory + base); // poor man's merge - } - - // Defaults: - that.tabletName = "com.highfidelity.interface.tablet.system"; - that.inject = ""; - that.graphicsDirectory = "icons/tablet-icons/"; // Where to look for button svgs. See below. - that.additionalAppScreens = []; - that.checkIsOpen = function checkIsOpen(type, tabletUrl) { // Are we active? Value used to set isOpen. - // Actual url may have prefix or suffix. - return that.currentVisibleUrl && - ((that.home.indexOf(that.currentVisibleUrl) > -1) || - (that.additionalAppScreens.indexOf(that.currentVisibleUrl) > -1)); - }; - that.setCurrentVisibleScreenMetadata = function setCurrentVisibleScreenMetadata(type, url) { - that.currentVisibleScreenType = type; - that.currentVisibleUrl = url; - }; - that.open = function open(optionalUrl, optionalInject) { // How to open the app. - var url = optionalUrl || that.home; - var inject = optionalInject || that.inject; - - if (that.isQMLUrl(url)) { - that.tablet.loadQMLSource(url); - } else { - that.tablet.gotoWebScreen(url, inject); - } - }; - // Opens some app on top of the current app (on desktop, opens new window) - that.openNewAppOnTop = function openNewAppOnTop(url, optionalInject) { - var inject = optionalInject || ""; - if (that.isQMLUrl(url)) { - that.tablet.loadQMLOnTop(url); - } else { - that.tablet.loadWebScreenOnTop(url, inject); - } - }; - that.close = function close() { // How to close the app. - that.currentVisibleUrl = ""; - // for toolbar-mode: go back to home screen, this will close the window. - that.tablet.gotoHomeScreen(); - }; - that.buttonActive = function buttonActive(isActive) { // How to make the button active (white). - that.button.editProperties({isActive: isActive}); - }; - that.isQMLUrl = function isQMLUrl(url) { - var type = /.qml$/.test(url) ? 'QML' : 'Web'; - return type === 'QML'; - }; - that.isCurrentlyOnQMLScreen = function isCurrentlyOnQMLScreen() { - return that.currentVisibleScreenType === 'QML'; - }; - - // - // START Notification Handling Defaults - // - that.messagesWaiting = function messagesWaiting(isWaiting) { // How to indicate a message light on button. - // Note that waitingButton doesn't have to exist unless someone explicitly calls this with isWaiting true. - that.button.editProperties({ - icon: isWaiting ? that.normalMessagesButton : that.normalButton, - activeIcon: isWaiting ? that.activeMessagesButton : that.activeButton - }); - }; - that.notificationPollTimeout = [false]; - that.notificationPollTimeoutMs = [60000]; - that.notificationPollEndpoint = [false]; - that.notificationPollStopPaginatingConditionMet = [false]; - that.notificationDataProcessPage = function (data) { - return data; - }; - that.notificationPollCallback = [that.ignore]; - that.notificationPollCaresAboutSince = [false]; - that.notificationInitialCallbackMade = [false]; - that.notificationDisplayBanner = function (message) { - if (!that.isOpen) { - Window.displayAnnouncement(message); - } - }; - // - // END Notification Handling Defaults - // - - // Handlers - that.onScreenChanged = function onScreenChanged(type, url) { - // Set isOpen, wireEventBridge, set buttonActive as appropriate, - // and finally call onOpened() or onClosed() IFF defined. - that.setCurrentVisibleScreenMetadata(type, url); - - if (that.checkIsOpen(type, url)) { - that.wireEventBridge(true); - if (!that.isOpen) { - that.buttonActive(true); - if (that.onOpened) { - that.onOpened(); - } - that.isOpen = true; - } - } else { - // A different screen is now visible, or the tablet has been closed. - // Tablet visibility is controlled separately by `tabletShownChanged()` - that.wireEventBridge(false); - if (that.isOpen) { - that.buttonActive(false); - if (that.onClosed) { - that.onClosed(); - } - that.isOpen = false; - } - } - }; - - // Overwrite with the given properties: - Object.keys(properties).forEach(function (key) { - that[key] = properties[key]; - }); - - // - // START Notification Handling - // - - var currentDataPageToRetrieve = []; - var concatenatedServerResponse = []; - for (var i = 0; i < that.notificationPollEndpoint.length; i++) { - currentDataPageToRetrieve[i] = 1; - concatenatedServerResponse[i] = new Array(); - } - - var MAX_LOG_LENGTH_CHARACTERS = 300; - function requestCallback(error, response, optionalParams) { - var indexOfRequest = optionalParams.indexOfRequest; - var urlOfRequest = optionalParams.urlOfRequest; - - if (error || (response.status !== 'success')) { - print("Error: unable to complete request from URL. Error:", error || response.status); - startNotificationTimer(indexOfRequest); - return; - } - - if (!that.notificationPollStopPaginatingConditionMet[indexOfRequest] || - that.notificationPollStopPaginatingConditionMet[indexOfRequest](response)) { - startNotificationTimer(indexOfRequest); - - var notificationData; - if (concatenatedServerResponse[indexOfRequest].length) { - notificationData = concatenatedServerResponse[indexOfRequest]; - } else { - notificationData = that.notificationDataProcessPage[indexOfRequest](response); - } - console.debug(that.buttonName, - 'truncated notification data for processing:', - JSON.stringify(notificationData).substring(0, MAX_LOG_LENGTH_CHARACTERS)); - that.notificationPollCallback[indexOfRequest](notificationData); - that.notificationInitialCallbackMade[indexOfRequest] = true; - currentDataPageToRetrieve[indexOfRequest] = 1; - concatenatedServerResponse[indexOfRequest] = new Array(); - } else { - concatenatedServerResponse[indexOfRequest] = - concatenatedServerResponse[indexOfRequest].concat(that.notificationDataProcessPage[indexOfRequest](response)); - currentDataPageToRetrieve[indexOfRequest]++; - request({ - json: true, - uri: (urlOfRequest + "&page=" + currentDataPageToRetrieve[indexOfRequest]) - }, requestCallback, optionalParams); - } - } - - - var METAVERSE_BASE = Account.metaverseServerURL; - var MS_IN_SEC = 1000; - that.notificationPoll = function (i) { - if (!that.notificationPollEndpoint[i]) { - return; - } - - // User is "appearing offline" or is not logged in - if (GlobalServices.findableBy === "none" || Account.username === "Unknown user") { - // The notification polling will restart when the user changes their availability - // or when they log in, so it's not necessary to restart a timer here. - console.debug(that.buttonName + " Notifications: User is appearing offline or not logged in. " + - that.buttonName + " will poll for notifications when user logs in and has their availability " + - "set to not appear offline."); - return; - } - - var url = METAVERSE_BASE + that.notificationPollEndpoint[i]; - - var settingsKey = "notifications/" + that.notificationPollEndpoint[i] + "/lastPoll"; - var currentTimestamp = new Date().getTime(); - var lastPollTimestamp = Settings.getValue(settingsKey, currentTimestamp); - if (that.notificationPollCaresAboutSince[i]) { - url = url + "&since=" + lastPollTimestamp / MS_IN_SEC; - } - Settings.setValue(settingsKey, currentTimestamp); - - request({ - json: true, - uri: url - }, - requestCallback, - { - indexOfRequest: i, - urlOfRequest: url - }); - }; - - // This won't do anything if there isn't a notification endpoint set - for (i = 0; i < that.notificationPollEndpoint.length; i++) { - that.notificationPoll(i); - } - - function startNotificationTimer(indexOfRequest) { - that.notificationPollTimeout[indexOfRequest] = Script.setTimeout(function () { - that.notificationPoll(indexOfRequest); - }, that.notificationPollTimeoutMs[indexOfRequest]); - } - - function restartNotificationPoll() { - for (var j = 0; j < that.notificationPollEndpoint.length; j++) { - that.notificationInitialCallbackMade[j] = false; - if (that.notificationPollTimeout[j]) { - Script.clearTimeout(that.notificationPollTimeout[j]); - that.notificationPollTimeout[j] = false; - } - that.notificationPoll(j); - } - } - // - // END Notification Handling - // - - // Properties: - that.tablet = Tablet.getTablet(that.tabletName); - // Must be after we gather properties. - that.buttonPrefix = that.buttonPrefix || that.buttonName.toLowerCase() + "-"; - defaultButton('normalButton', 'i.svg'); - defaultButton('activeButton', 'a.svg'); - defaultButton('normalMessagesButton', 'i-msg.svg'); - defaultButton('activeMessagesButton', 'a-msg.svg'); - var buttonOptions = { - icon: that.normalButton, - activeIcon: that.activeButton, - text: that.buttonName - }; - // `TabletScriptingInterface` looks for the presence of a `sortOrder` key. - // What it SHOULD do is look to see if the value inside that key is defined. - // To get around the current code, we do this instead. - if (that.sortOrder) { - buttonOptions.sortOrder = that.sortOrder; - } - that.button = that.tablet.addButton(buttonOptions); - that.ignore = function ignore() { }; - that.hasOutboundEventBridge = false; - that.hasInboundQmlEventBridge = false; - that.hasInboundHtmlEventBridge = false; - // HTML event bridge uses strings, not objects. Here we abstract over that. - // (Although injected javascript still has to use JSON.stringify/JSON.parse.) - that.sendToHtml = function (messageObject) { - that.tablet.emitScriptEvent(JSON.stringify(messageObject)); - }; - that.fromHtml = function (messageString) { - var parsedMessage = JSON.parse(messageString); - parsedMessage.messageSrc = "HTML"; - that.onMessage(parsedMessage); - }; - that.sendMessage = that.ignore; - that.wireEventBridge = function wireEventBridge(on) { - // Uniquivocally sets that.sendMessage(messageObject) to do the right thing. - // Sets has*EventBridge and wires onMessage to the proper event bridge as appropriate, IFF onMessage defined. - var isCurrentlyOnQMLScreen = that.isCurrentlyOnQMLScreen(); - // Outbound (always, regardless of whether there is an inbound handler). - if (on) { - that.sendMessage = isCurrentlyOnQMLScreen ? that.tablet.sendToQml : that.sendToHtml; - that.hasOutboundEventBridge = true; - } else { - that.sendMessage = that.ignore; - that.hasOutboundEventBridge = false; - } - - if (!that.onMessage) { - return; - } - - // Inbound - if (on) { - if (isCurrentlyOnQMLScreen && !that.hasInboundQmlEventBridge) { - console.debug(that.buttonName, 'connecting', that.tablet.fromQml); - that.tablet.fromQml.connect(that.onMessage); - that.hasInboundQmlEventBridge = true; - } else if (!isCurrentlyOnQMLScreen && !that.hasInboundHtmlEventBridge) { - console.debug(that.buttonName, 'connecting', that.tablet.webEventReceived); - that.tablet.webEventReceived.connect(that.fromHtml); - that.hasInboundHtmlEventBridge = true; - } - } else { - if (that.hasInboundQmlEventBridge) { - console.debug(that.buttonName, 'disconnecting', that.tablet.fromQml); - that.tablet.fromQml.disconnect(that.onMessage); - that.hasInboundQmlEventBridge = false; - } - if (that.hasInboundHtmlEventBridge) { - console.debug(that.buttonName, 'disconnecting', that.tablet.webEventReceived); - that.tablet.webEventReceived.disconnect(that.fromHtml); - that.hasInboundHtmlEventBridge = false; - } - } - }; - that.isOpen = false; - // To facilitate incremental development, only wire onClicked to do something when "home" is defined in properties. - that.onClicked = that.home - ? function onClicked() { - // Call open() or close(), and reset type based on current home property. - if (that.isOpen) { - that.close(); - } else { - that.open(); - } - } : that.ignore; - that.onScriptEnding = function onScriptEnding() { - // Close if necessary, clean up any remaining handlers, and remove the button. - GlobalServices.myUsernameChanged.disconnect(restartNotificationPoll); - GlobalServices.findableByChanged.disconnect(restartNotificationPoll); - that.tablet.screenChanged.disconnect(that.onScreenChanged); - if (that.isOpen) { - that.close(); - that.onScreenChanged("", ""); - } - if (that.button) { - if (that.onClicked) { - that.button.clicked.disconnect(that.onClicked); - } - that.tablet.removeButton(that.button); - } - for (var i = 0; i < that.notificationPollTimeout.length; i++) { - if (that.notificationPollTimeout[i]) { - Script.clearInterval(that.notificationPollTimeout[i]); - that.notificationPollTimeout[i] = false; - } - } - }; - // Set up the handlers. - that.tablet.screenChanged.connect(that.onScreenChanged); - that.button.clicked.connect(that.onClicked); - Script.scriptEnding.connect(that.onScriptEnding); - GlobalServices.findableByChanged.connect(restartNotificationPoll); - GlobalServices.myUsernameChanged.connect(restartNotificationPoll); - if (that.buttonName === Settings.getValue("startUpApp")) { - Settings.setValue("startUpApp", ""); - Script.setTimeout(function () { - that.open(); - }, 1000); - } -} -module.exports = AppUi; diff --git a/scripts/simplifiedUI/modules/request.js b/scripts/simplifiedUI/modules/request.js deleted file mode 100644 index 37f3ac0d7b..0000000000 --- a/scripts/simplifiedUI/modules/request.js +++ /dev/null @@ -1,83 +0,0 @@ -"use strict"; - -// request.js -// -// Created by Cisco Fresquet on 04/24/2017. -// Copyright 2017 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -/* global module */ -// @module request -// -// This module contains the `request` module implementation - -// =========================================================================================== -module.exports = { - - // ------------------------------------------------------------------ - // cb(error, responseOfCorrectContentType, optionalCallbackParameter) of url. A subset of npm request. - request: function (options, callback, optionalCallbackParameter) { - var httpRequest = new XMLHttpRequest(), key; - // QT bug: apparently doesn't handle onload. Workaround using readyState. - httpRequest.onreadystatechange = function () { - var READY_STATE_DONE = 4; - var HTTP_OK = 200; - if (httpRequest.readyState >= READY_STATE_DONE) { - var error = (httpRequest.status !== HTTP_OK) && httpRequest.status.toString() + ':' + httpRequest.statusText, - response = !error && httpRequest.responseText, - contentType = !error && httpRequest.getResponseHeader('content-type'); - if (!error && contentType.indexOf('application/json') === 0) { // ignoring charset, etc. - try { - response = JSON.parse(response); - } catch (e) { - error = e; - } - } - if (error) { - response = { statusCode: httpRequest.status }; - } - callback(error, response, optionalCallbackParameter); - } - }; - if (typeof options === 'string') { - options = { uri: options }; - } - if (options.url) { - options.uri = options.url; - } - if (!options.method) { - options.method = 'GET'; - } - if (options.body && (options.method === 'GET')) { // add query parameters - var params = [], appender = (-1 === options.uri.search('?')) ? '?' : '&'; - for (key in options.body) { - if (options.body.hasOwnProperty(key)) { - params.push(key + '=' + options.body[key]); - } - } - options.uri += appender + params.join('&'); - delete options.body; - } - if (options.json) { - options.headers = options.headers || {}; - options.headers["Content-type"] = "application/json"; - options.body = JSON.stringify(options.body); - } - for (key in options.headers || {}) { - if (options.headers.hasOwnProperty(key)) { - httpRequest.setRequestHeader(key, options.headers[key]); - } - } - httpRequest.open(options.method, options.uri, true); - httpRequest.send(options.body || null); - } -}; - -// =========================================================================================== -// @function - debug logging -function debug() { - print('RequestModule | ' + [].slice.call(arguments).join(' ')); -} diff --git a/scripts/simplifiedUI/modules/vec3.js b/scripts/simplifiedUI/modules/vec3.js deleted file mode 100644 index f164f01374..0000000000 --- a/scripts/simplifiedUI/modules/vec3.js +++ /dev/null @@ -1,69 +0,0 @@ -// Example of using a "system module" to decouple Vec3's implementation details. -// -// Users would bring Vec3 support in as a module: -// var vec3 = Script.require('vec3'); -// - -// (this example is compatible with using as a Script.include and as a Script.require module) -try { - // Script.require - module.exports = vec3; -} catch(e) { - // Script.include - Script.registerValue("vec3", vec3); -} - -vec3.fromObject = function(v) { - //return new vec3(v.x, v.y, v.z); - //... this is even faster and achieves the same effect - v.__proto__ = vec3.prototype; - return v; -}; - -vec3.prototype = { - multiply: function(v2) { - // later on could support overrides like so: - // if (v2 instanceof quat) { [...] } - // which of the below is faster (C++ or JS)? - // (dunno -- but could systematically find out and go with that version) - - // pure JS option - // return new vec3(this.x * v2.x, this.y * v2.y, this.z * v2.z); - - // hybrid C++ option - return vec3.fromObject(Vec3.multiply(this, v2)); - }, - // detects any NaN and Infinity values - isValid: function() { - return isFinite(this.x) && isFinite(this.y) && isFinite(this.z); - }, - // format Vec3's, eg: - // var v = vec3(); - // print(v); // outputs [Vec3 (0.000, 0.000, 0.000)] - toString: function() { - if (this === vec3.prototype) { - return "{Vec3 prototype}"; - } - function fixed(n) { return n.toFixed(3); } - return "[Vec3 (" + [this.x, this.y, this.z].map(fixed) + ")]"; - }, -}; - -vec3.DEBUG = true; - -function vec3(x, y, z) { - if (!(this instanceof vec3)) { - // if vec3 is called as a function then re-invoke as a constructor - // (so that `value instanceof vec3` holds true for created values) - return new vec3(x, y, z); - } - - // unfold default arguments (vec3(), vec3(.5), vec3(0,1), etc.) - this.x = x !== undefined ? x : 0; - this.y = y !== undefined ? y : this.x; - this.z = z !== undefined ? z : this.y; - - if (vec3.DEBUG && !this.isValid()) - throw new Error('vec3() -- invalid initial values ['+[].slice.call(arguments)+']'); -}; - diff --git a/scripts/simplifiedUI/system/assets/animations/Cheering.fbx b/scripts/simplifiedUI/system/assets/animations/Cheering.fbx deleted file mode 100644 index 8787bf4bd8..0000000000 Binary files a/scripts/simplifiedUI/system/assets/animations/Cheering.fbx and /dev/null differ diff --git a/scripts/simplifiedUI/system/assets/animations/Clapping.fbx b/scripts/simplifiedUI/system/assets/animations/Clapping.fbx deleted file mode 100644 index d05b41866d..0000000000 Binary files a/scripts/simplifiedUI/system/assets/animations/Clapping.fbx and /dev/null differ diff --git a/scripts/simplifiedUI/system/assets/animations/Crying.fbx b/scripts/simplifiedUI/system/assets/animations/Crying.fbx deleted file mode 100644 index 2e60ba2450..0000000000 Binary files a/scripts/simplifiedUI/system/assets/animations/Crying.fbx and /dev/null differ diff --git a/scripts/simplifiedUI/system/assets/animations/Dancing.fbx b/scripts/simplifiedUI/system/assets/animations/Dancing.fbx deleted file mode 100644 index 7759d273b7..0000000000 Binary files a/scripts/simplifiedUI/system/assets/animations/Dancing.fbx and /dev/null differ diff --git a/scripts/simplifiedUI/system/assets/animations/Fall.fbx b/scripts/simplifiedUI/system/assets/animations/Fall.fbx deleted file mode 100644 index 627e909bb4..0000000000 Binary files a/scripts/simplifiedUI/system/assets/animations/Fall.fbx and /dev/null differ diff --git a/scripts/simplifiedUI/system/assets/animations/Love.fbx b/scripts/simplifiedUI/system/assets/animations/Love.fbx deleted file mode 100644 index 159ccafd04..0000000000 Binary files a/scripts/simplifiedUI/system/assets/animations/Love.fbx and /dev/null differ diff --git a/scripts/simplifiedUI/system/assets/animations/Pointing.fbx b/scripts/simplifiedUI/system/assets/animations/Pointing.fbx deleted file mode 100644 index da3c9bbeca..0000000000 Binary files a/scripts/simplifiedUI/system/assets/animations/Pointing.fbx and /dev/null differ diff --git a/scripts/simplifiedUI/system/assets/animations/Sit1.fbx b/scripts/simplifiedUI/system/assets/animations/Sit1.fbx deleted file mode 100644 index db75219980..0000000000 Binary files a/scripts/simplifiedUI/system/assets/animations/Sit1.fbx and /dev/null differ diff --git a/scripts/simplifiedUI/system/assets/animations/Sit2.fbx b/scripts/simplifiedUI/system/assets/animations/Sit2.fbx deleted file mode 100644 index 400b599794..0000000000 Binary files a/scripts/simplifiedUI/system/assets/animations/Sit2.fbx and /dev/null differ diff --git a/scripts/simplifiedUI/system/assets/animations/Sit3.fbx b/scripts/simplifiedUI/system/assets/animations/Sit3.fbx deleted file mode 100644 index 174fd75c4e..0000000000 Binary files a/scripts/simplifiedUI/system/assets/animations/Sit3.fbx and /dev/null differ diff --git a/scripts/simplifiedUI/system/assets/animations/Surprised.fbx b/scripts/simplifiedUI/system/assets/animations/Surprised.fbx deleted file mode 100644 index 49362605b3..0000000000 Binary files a/scripts/simplifiedUI/system/assets/animations/Surprised.fbx and /dev/null differ diff --git a/scripts/simplifiedUI/system/assets/animations/Waving.fbx b/scripts/simplifiedUI/system/assets/animations/Waving.fbx deleted file mode 100644 index e2442f64f4..0000000000 Binary files a/scripts/simplifiedUI/system/assets/animations/Waving.fbx and /dev/null differ diff --git a/scripts/simplifiedUI/system/assets/data/createAppTooltips.json b/scripts/simplifiedUI/system/assets/data/createAppTooltips.json deleted file mode 100644 index b59797fca7..0000000000 --- a/scripts/simplifiedUI/system/assets/data/createAppTooltips.json +++ /dev/null @@ -1,623 +0,0 @@ -{ - "shape": { - "tooltip": "The shape of this entity's geometry." - }, - "color": { - "tooltip": "The RGB value of this entity." - }, - "text": { - "tooltip": "The text to display on the entity." - }, - "textColor": { - "tooltip": "The color of the text." - }, - "textAlpha": { - "tooltip": "The alpha of the text." - }, - "backgroundColor": { - "tooltip": "The color of the background." - }, - "backgroundAlpha": { - "tooltip": "The alpha of the background." - }, - "lineHeight": { - "tooltip": "The height of each line of text. This determines the size of the text." - }, - "textBillboardMode": { - "tooltip": "If enabled, determines how the entity will face the camera.", - "jsPropertyName": "billboardMode" - }, - "topMargin": { - "tooltip": "The top margin, in meters." - }, - "rightMargin": { - "tooltip": "The right margin, in meters." - }, - "bottomMargin": { - "tooltip": "The bottom margin, in meters." - }, - "leftMargin": { - "tooltip": "The left margin, in meters." - }, - "zoneShapeType": { - "tooltip": "The shape of the volume in which the zone's lighting effects and avatar permissions have effect.", - "jsPropertyName": "shapeType" - }, - "zoneCompoundShapeURL": { - "tooltip": "The model file to use for the compound shape if Shape Type is \"Use Compound Shape URL\".", - "jsPropertyName": "compoundShapeURL" - }, - "flyingAllowed": { - "tooltip": "If enabled, users can fly in the zone." - }, - "ghostingAllowed": { - "tooltip": "If enabled, users with avatar collisions turned off will not collide with content in the zone." - }, - "filterURL": { - "tooltip": "The URL of a JS file that checks for changes to entity properties within the zone. Runs periodically." - }, - "keyLightMode": { - "tooltip": "Configures the key light in the zone. This light is directional." - }, - "keyLight.color": { - "tooltip": "The color of the key light." - }, - "keyLight.intensity": { - "tooltip": "The intensity of the key light." - }, - "keyLight.direction.y": { - "tooltip": "The angle in deg at which light emits. Starts in the entity's -z direction, and rotates around its y axis." - }, - "keyLight.direction.x": { - "tooltip": "The angle in deg at which light emits. Starts in the entity's -z direction, and rotates around its x axis." - }, - "keyLight.castShadows": { - "tooltip": "If enabled, shadows are cast. The entity or avatar casting the shadow must also have Cast Shadows enabled." - }, - "skyboxMode": { - "tooltip": "Configures the skybox in the zone. The skybox is a cube map image." - }, - "skybox.color": { - "tooltip": "If the URL is blank, this changes the color of the sky, otherwise it modifies the color of the skybox." - }, - "skybox.url": { - "tooltip": "A cube map image that is used to render the sky." - }, - "ambientLightMode": { - "tooltip": "Configures the ambient light in the zone. Use this if you want your skybox to reflect light on the content." - }, - "ambientLight.ambientIntensity": { - "tooltip": "The intensity of the ambient light." - }, - "ambientLight.ambientURL": { - "tooltip": "A cube map image that defines the color of the light coming from each direction." - }, - "hazeMode": { - "tooltip": "Configures the haze in the scene." - }, - "haze.hazeRange": { - "tooltip": "How far the haze extends out. This is measured in meters." - }, - "haze.hazeAltitudeEffect": { - "tooltip": "If enabled, this adjusts the haze intensity as it gets higher." - }, - "haze.hazeBaseRef": { - "tooltip": "The base of the altitude range. Measured in entity space." - }, - "haze.hazeCeiling": { - "tooltip": "The ceiling of the altitude range. Measured in entity space." - }, - "haze.hazeColor": { - "tooltip": "The color of the haze." - }, - "haze.hazeBackgroundBlend": { - "tooltip": "How much the skybox shows through the haze. The higher the value, the more it shows through." - }, - "haze.hazeEnableGlare": { - "tooltip": "If enabled, a glare is enabled on the skybox, based on the key light." - }, - "haze.hazeGlareColor": { - "tooltip": "The color of the glare based on the key light." - }, - "haze.hazeGlareAngle": { - "tooltip": "The angular size of the glare and how much it encompasses the skybox, based on the key light." - }, - "bloomMode": { - "tooltip": "Configures how much bright areas of the scene glow." - }, - "bloom.bloomIntensity": { - "tooltip": "The intensity, or brightness, of the bloom effect." - }, - "bloom.bloomThreshold": { - "tooltip": "The cutoff of the bloom. The higher the value, the more only bright areas of the scene will glow." - }, - "bloom.bloomSize": { - "tooltip": "The radius of bloom. The higher the value, the larger the bloom." - }, - "avatarPriority": { - "tooltip": "Alter Avatars' update priorities." - }, - "modelURL": { - "tooltip": "A mesh model from an FBX or OBJ file." - }, - "shapeType": { - "tooltip": "The shape of the collision hull used if collisions are enabled. This affects how an entity collides." - }, - "compoundShapeURL": { - "tooltip": "The model file to use for the compound shape if Collision Shape is \"Compound\"." - }, - "animation.url": { - "tooltip": "An animation to play on the model." - }, - "animation.running": { - "tooltip": "If enabled, the animation on the model will play automatically." - }, - "animation.allowTranslation": { - "tooltip": "If enabled, this allows an entity to move in space during an animation." - }, - "animation.loop": { - "tooltip": "If enabled, then the animation will continuously repeat." - }, - "animation.hold": { - "tooltip": "If enabled, then rotations and translations of the last frame played are maintained when the animation stops." - }, - "animation.currentFrame": { - "tooltip": "The current frame being played in the animation." - }, - "animation.firstFrame": { - "tooltip": "The first frame to play in the animation." - }, - "animation.lastFrame": { - "tooltip": "The last frame to play in the animation." - }, - "animation.fps": { - "tooltip": "The speed of the animation." - }, - "textures": { - "tooltip": "A JSON string containing a texture. Use a name from the Original Texture property to override it." - }, - "originalTextures": { - "tooltip": "A JSON string containing the original texture used on the model." - }, - "imageURL": { - "tooltip": "The URL for the image source." - }, - "imageColor": { - "tooltip": "The tint to be applied to the image.", - "jsPropertyName": "color" - }, - "emissive": { - "tooltip": "If enabled, the image will display at full brightness." - }, - "subImage": { - "tooltip": "The area of the image that is displayed." - }, - "imageBillboardMode": { - "tooltip": "If enabled, determines how the entity will face the camera.", - "jsPropertyName": "billboardMode" - }, - "keepAspectRatio": { - "tooltip": "If enabled, the image will maintain its original aspect ratio." - }, - "sourceUrl": { - "tooltip": "The URL for the web page source." - }, - "dpi": { - "tooltip": "The resolution to display the page at, in pixels per inch. Use this to resize your web source in the frame." - }, - "isEmitting": { - "tooltip": "If enabled, then particles are emitted." - }, - "lifespan": { - "tooltip": "How long each particle lives, measured in seconds." - }, - "maxParticles": { - "tooltip": "The maximum number of particles to render at one time. Older particles are swapped out for new ones." - }, - "particleTextures": { - "tooltip": "The URL of a JPG or PNG image file to display for each particle.", - "jsPropertyName": "textures" - }, - "emitRate": { - "tooltip": "The number of particles per second to emit." - }, - "emitSpeed": { - "tooltip": "The speed that each particle is emitted at, measured in m/s." - }, - "speedSpread": { - "tooltip": "The spread in speeds at which particles are emitted at, resulting in a variety of speeds." - }, - "particleShapeType": { - "tooltip": "The shape of the surface from which to emit particles.", - "jsPropertyName": "shapeType" - }, - "particleCompoundShapeURL": { - "tooltip": "The model file to use for the particle emitter if Shape Type is \"Use Compound Shape URL\".", - "jsPropertyName": "compoundShapeURL" - }, - "emitDimensions": { - "tooltip": "The outer limit radius in dimensions that the particles can be emitted from." - }, - "emitOrientation": { - "tooltip": "The orientation of particle emission relative to the entity's axes." - }, - "emitRadiusStart": { - "tooltip": "The inner limit radius in dimensions that the particles start emitting from." - }, - "emitterShouldTrail": { - "tooltip": "If enabled, then particles are \"left behind\" as the emitter moves, otherwise they are not." - }, - "particleRadiusTriple": { - "tooltip": "The size of each particle.", - "jsPropertyName": "particleRadius" - }, - "particleRadius": { - "tooltip": "The size of each particle." - }, - "radiusStart": { - "tooltip": "The start size of each particle." - }, - "radiusFinish": { - "tooltip": "The finish size of each particle." - }, - "radiusSpread": { - "tooltip": "The spread in size that each particle is given, resulting in a variety of sizes." - }, - "particleColorTriple": { - "tooltip": "The color of each particle.", - "jsPropertyName": "color" - }, - "particleColor": { - "tooltip": "The color of each particle.", - "jsPropertyName": "color" - }, - "colorStart": { - "tooltip": "The start color of each particle." - }, - "colorFinish": { - "tooltip": "The finish color of each particle." - }, - "colorSpread": { - "tooltip": "The spread in color that each particle is given, resulting in a variety of colors." - }, - "particleAlphaTriple": { - "tooltip": "The alpha of each particle.", - "jsPropertyName": "alpha" - }, - "alpha": { - "tooltip": "The alpha of each particle." - }, - "alphaStart": { - "tooltip": "The start alpha of each particle." - }, - "alphaFinish": { - "tooltip": "The finish alpha of each particle." - }, - "alphaSpread": { - "tooltip": "The spread in alpha that each particle is given, resulting in a variety of alphas." - }, - "emitAcceleration": { - "tooltip": "The acceleration that is applied to each particle during its lifetime." - }, - "accelerationSpread": { - "tooltip": "The spread in accelerations that each particle is given, resulting in a variety of accelerations." - }, - "particleSpinTriple": { - "tooltip": "The spin of each particle.", - "jsPropertyName": "particleSpin" - }, - "particleSpin": { - "tooltip": "The spin of each particle." - }, - "spinStart": { - "tooltip": "The start spin of each particle." - }, - "spinFinish": { - "tooltip": "The finish spin of each particle." - }, - "spinSpread": { - "tooltip": "The spread in spin that each particle is given, resulting in a variety of spins." - }, - "rotateWithEntity": { - "tooltip": "If enabled, each particle will spin relative to the rotation of the entity as a whole." - }, - "particlePolarTriple": { - "tooltip": "The angle range in deg at which particles are emitted. Starts in the entity's -z direction, and rotates around its y axis.", - "skipJSProperty": true - }, - "polarStart": { - "tooltip": "The start angle in deg at which particles are emitted. Starts in the entity's -z direction, and rotates around its y axis." - }, - "polarFinish": { - "tooltip": "The finish angle in deg at which particles are emitted. Starts in the entity's -z direction, and rotates around its y axis." - }, - "particleAzimuthTriple": { - "tooltip": "The angle range in deg at which particles are emitted. Starts in the entity's -x direction, and rotates around its z axis.", - "skipJSProperty": true - }, - "azimuthStart": { - "tooltip": "The start angle in deg at which particles are emitted. Starts in the entity's -x direction, and rotates around its z axis." - }, - "azimuthFinish": { - "tooltip": "The finish angle in deg at which particles are emitted. Starts in the entity's -x direction, and rotates around its z axis." - }, - "lightColor": { - "tooltip": "The color of the light emitted.", - "jsPropertyName": "color" - }, - "intensity": { - "tooltip": "The brightness of the light." - }, - "falloffRadius": { - "tooltip": "The distance from the light's center where the intensity is reduced." - }, - "isSpotlight": { - "tooltip": "If enabled, then the light is directional, otherwise the light is a point light which emits light in all directions." - }, - "exponent": { - "tooltip": "Affects the softness of the spotlight beam; the higher the value, the softer the beam." - }, - "cutoff": { - "tooltip": "Affects the size of the spotlight beam; the higher the value, the larger the beam." - }, - "materialURL": { - "tooltip": "The URL to an external JSON file or \"materialData\", \"materialData? to use Material Data." - }, - "materialData": { - "tooltip": "Can be used instead of a JSON file when material set to materialData." - }, - "parentMaterialName": { - "tooltip": "The target mesh indices or material names that this material entity should be assigned to on it's parent. This only supports parents that are Avatars as well as Shape or Model entity types." - }, - "priority": { - "tooltip": "The priority of the material, where a larger number means higher priority. Original materials = 0." - }, - "materialMappingMode": { - "tooltip": "How the material is mapped to the entity. If set to \"UV space\", then the material will be applied with the target entity's UV coordinates. If set to \"3D Projected\", then the 3D transform of the material entity will be used." - }, - "materialMappingPos": { - "tooltip": "The offset position of the bottom left of the material within the parent's UV space." - }, - "materialMappingScale": { - "tooltip": "How many times the material will repeat in each direction within the parent's UV space." - }, - "materialMappingRot": { - "tooltip": "How much to rotate the material within the parent's UV-space, in degrees." - }, - "materialRepeat": { - "tooltip": "If enabled, the material will repeat, otherwise it will clamp." - }, - "followCamera": { - "tooltip": "If enabled, the grid is always visible even as the camera moves to another position." - }, - "majorGridEvery": { - "tooltip": "The number of \"Minor Grid Every\" intervals at which to draw a thick grid line." - }, - "minorGridEvery": { - "tooltip": "The real number of meters at which to draw thin grid lines." - }, - "id": { - "tooltip": "The unique identifier of this entity." - }, - "name": { - "tooltip": "The name of this entity." - }, - "description": { - "tooltip": "Use this field to describe the entity." - }, - "position": { - "tooltip": "The global position of this entity." - }, - "localPosition": { - "tooltip": "The local position of this entity." - }, - "rotation": { - "tooltip": "The global rotation of this entity." - }, - "localRotation": { - "tooltip": "The local rotation of this entity." - }, - "dimensions": { - "tooltip": "The global dimensions of this entity." - }, - "localDimensions": { - "tooltip": "The local dimensions of this entity." - }, - "scale": { - "tooltip": "The global scaling of this entity.", - "skipJSProperty": true - }, - "registrationPoint": { - "tooltip": "The point in the entity at which the entity is rotated about." - }, - "visible": { - "tooltip": "If enabled, this entity will be visible." - }, - "locked": { - "tooltip": "If enabled, this entity will be locked." - }, - "collisionless": { - "tooltip": "If enabled, this entity will collide with other entities or avatars." - }, - "dynamic": { - "tooltip": "If enabled, this entity has collisions associated with it that can affect its movement." - }, - "collidesWithStatic": { - "tooltip": "If enabled, this entity will collide with other non-moving, static entities.", - "jsPropertyName": "collidesWith" - }, - "collidesWithDynamic": { - "tooltip": "If enabled, this entity will collide with other dynamic entities.", - "jsPropertyName": "collidesWith" - }, - "collidesWithKinematic": { - "tooltip": "If enabled, this entity will collide with other kinematic entities (they have velocity but are not dynamic).", - "jsPropertyName": "collidesWith" - }, - "collidesWithOtherAvatar": { - "tooltip": "If enabled, this entity will collide with other user's avatars.", - "jsPropertyName": "collidesWith" - }, - "collidesWithMyAvatar": { - "tooltip": "If enabled, this entity will collide with your own avatar.", - "jsPropertyName": "collidesWith" - }, - "collisionSoundURL": { - "tooltip": "The URL of a sound to play when the entity collides with something else." - }, - "grab.grabbable": { - "tooltip": "If enabled, this entity will allow grabbing input and will be movable." - }, - "grab.triggerable": { - "tooltip": "If enabled, the collider on this entity is used for triggering events." - }, - "cloneable": { - "tooltip": "If enabled, this entity can be duplicated." - }, - "cloneLifetime": { - "tooltip": "The lifetime for clones of this entity." - }, - "cloneLimit": { - "tooltip": "The total number of clones of this entity that can exist in the domain at any given time." - }, - "cloneDynamic": { - "tooltip": "If enabled, then clones created from this entity will be dynamic, allowing the clone to collide." - }, - "cloneAvatarEntity": { - "tooltip": "If enabled, then clones created from this entity will be created as avatar entities." - }, - "grab.grabFollowsController": { - "tooltip": "If enabled, grabbed entities will follow the movements of your hand controller instead of your avatar's hand." - }, - "canCastShadow": { - "tooltip": "If enabled, this geometry of this entity casts shadows when a shadow-casting light source shines on it." - }, - "ignorePickIntersection": { - "tooltip": "If enabled, this entity will not be considered for ray picks, and will also not occlude other entities when picking." - }, - "parentID": { - "tooltip": "The ID of the entity or avatar that this entity is parented to." - }, - "parentJointIndex": { - "tooltip": "If the entity is parented to an avatar, this joint defines where on the avatar the entity is parented." - }, - "href": { - "tooltip": "The URL that will be opened when a user clicks on this entity. Useful for web pages and portals." - }, - "script": { - "tooltip": "The URL to an external JS file to add behaviors to the client." - }, - "serverScripts": { - "tooltip": "The URL to an external JS file to add behaviors to the server." - }, - "serverScriptsStatus": { - "tooltip": "The status of the server script, if provided. This shows if it's running or has an error.", - "skipJSProperty": true - }, - "hasLifetime": { - "tooltip": "If enabled, the entity will disappear after a certain amount of time specified by Lifetime.", - "jsPropertyName": "lifetime" - }, - "lifetime": { - "tooltip": "The time this entity will exist in the environment for." - }, - "userData": { - "tooltip": "Used to store extra data about the entity in JSON format." - }, - "localVelocity": { - "tooltip": "The linear velocity vector of the entity. The velocity at which this entity moves forward in space." - }, - "damping": { - "tooltip": "The linear damping to slow down the linear velocity of an entity over time." - }, - "localAngularVelocity": { - "tooltip": "The angular velocity of the entity in rad/s with respect to its axes, about its pivot point." - }, - "angularDamping": { - "tooltip": "The angular damping to slow down the angular velocity of an entity over time." - }, - "restitution": { - "tooltip": "If enabled, the entity can bounce against other objects that also have Bounciness." - }, - "friction": { - "tooltip": "The friction applied to slow down an entity when it's moving against another entity." - }, - "density": { - "tooltip": "The density of the entity. The higher the density, the harder the entity is to move." - }, - "gravity": { - "tooltip": "The acceleration due to gravity that the entity should move with, in world space." - }, - "acceleration": { - "tooltip": "A acceleration that the entity should move with, in world space." - }, - "renderLayer": { - "tooltip": "The layer on which this entity is rendered." - }, - "primitiveMode": { - "tooltip": "The mode in which to draw an entity, either \"Solid\" or \"Wireframe\"." - }, - "groupCulled": { - "tooltip": "If false, individual pieces of the entity may be culled by the render engine. If true, either the entire entity will be culled, or it won't at all." - }, - "webColor": { - "tooltip": "The tint of the web entity." - }, - "webAlpha": { - "tooltip": "The alpha of the web entity." - }, - "maxFPS": { - "tooltip": "The FPS at which to render the web entity. Higher values will have a performance impact." - }, - "scriptURL": { - "tooltip": "The URL of a script to inject into the web page." - }, - "alignToGrid": { - "tooltip": "Used to align entities to the grid, or floor of the environment.", - "skipJSProperty": true - }, - "createModel": { - "tooltip": "An entity that is based on a custom mesh created from an .OBJ or .FBX.", - "skipJSProperty": true - }, - "createShape": { - "tooltip": "An entity that has many different primitive shapes.", - "skipJSProperty": true - }, - "createLight": { - "tooltip": "An entity that emits light.", - "skipJSProperty": true - }, - "createText": { - "tooltip": "An entity that displays text on a panel.", - "skipJSProperty": true - }, - "createImage": { - "tooltip": "An entity that displays an image on a panel.", - "skipJSProperty": true - }, - "createWeb": { - "tooltip": "An entity that displays a web page on a panel.", - "skipJSProperty": true - }, - "createZone": { - "tooltip": "An entity that can be used for skyboxes, lighting, and can constrain or change avatar behaviors.", - "skipJSProperty": true - }, - "createParticle": { - "tooltip": "An entity that emits particles.", - "skipJSProperty": true - }, - "createMaterial": { - "tooltip": "An entity that creates a material that can be attached to a Shape or Model.", - "skipJSProperty": true - }, - "useAssetServer": { - "tooltip": "A server that hosts content and assets. You can't take items that are hosted here into other domains.", - "skipJSProperty": true - }, - "importNewEntity": { - "tooltip": "Import a local or hosted file that can be used across domains.", - "skipJSProperty": true - } -} diff --git a/scripts/simplifiedUI/system/assets/images/Overlay-Viz-blank.png b/scripts/simplifiedUI/system/assets/images/Overlay-Viz-blank.png deleted file mode 100644 index bbbf44f7a9..0000000000 Binary files a/scripts/simplifiedUI/system/assets/images/Overlay-Viz-blank.png and /dev/null differ diff --git a/scripts/simplifiedUI/system/assets/images/Particle-Sprite-Smoke-1.png b/scripts/simplifiedUI/system/assets/images/Particle-Sprite-Smoke-1.png deleted file mode 100644 index 78c9b3da4a..0000000000 Binary files a/scripts/simplifiedUI/system/assets/images/Particle-Sprite-Smoke-1.png and /dev/null differ diff --git a/scripts/simplifiedUI/system/assets/images/close-small-light.svg b/scripts/simplifiedUI/system/assets/images/close-small-light.svg deleted file mode 100644 index f9edf95fca..0000000000 --- a/scripts/simplifiedUI/system/assets/images/close-small-light.svg +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - - - - - diff --git a/scripts/simplifiedUI/system/assets/images/grabsprite-3.png b/scripts/simplifiedUI/system/assets/images/grabsprite-3.png deleted file mode 100644 index 4ecc772a41..0000000000 Binary files a/scripts/simplifiedUI/system/assets/images/grabsprite-3.png and /dev/null differ diff --git a/scripts/simplifiedUI/system/assets/images/ignore-target.svg b/scripts/simplifiedUI/system/assets/images/ignore-target.svg deleted file mode 100644 index 3d685139ec..0000000000 --- a/scripts/simplifiedUI/system/assets/images/ignore-target.svg +++ /dev/null @@ -1,53 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - diff --git a/scripts/simplifiedUI/system/assets/images/kick-target.svg b/scripts/simplifiedUI/system/assets/images/kick-target.svg deleted file mode 100644 index 21cb3a5462..0000000000 --- a/scripts/simplifiedUI/system/assets/images/kick-target.svg +++ /dev/null @@ -1,33 +0,0 @@ - - - - - - - - - - - - - - - - - diff --git a/scripts/simplifiedUI/system/assets/images/lock.svg b/scripts/simplifiedUI/system/assets/images/lock.svg deleted file mode 100644 index bb9658de00..0000000000 --- a/scripts/simplifiedUI/system/assets/images/lock.svg +++ /dev/null @@ -1,90 +0,0 @@ - - - - - - - - - - - - - - - image/svg+xml - - - - - - - - - - diff --git a/scripts/simplifiedUI/system/assets/images/lod-a.svg b/scripts/simplifiedUI/system/assets/images/lod-a.svg deleted file mode 100644 index 6845e0ff78..0000000000 --- a/scripts/simplifiedUI/system/assets/images/lod-a.svg +++ /dev/null @@ -1,46 +0,0 @@ - - - -image/svg+xml \ No newline at end of file diff --git a/scripts/simplifiedUI/system/assets/images/lod-i.svg b/scripts/simplifiedUI/system/assets/images/lod-i.svg deleted file mode 100644 index f909f3b495..0000000000 --- a/scripts/simplifiedUI/system/assets/images/lod-i.svg +++ /dev/null @@ -1,46 +0,0 @@ - - - -image/svg+xml \ No newline at end of file diff --git a/scripts/simplifiedUI/system/assets/images/luci-a.svg b/scripts/simplifiedUI/system/assets/images/luci-a.svg deleted file mode 100644 index 40e1481eba..0000000000 --- a/scripts/simplifiedUI/system/assets/images/luci-a.svg +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - diff --git a/scripts/simplifiedUI/system/assets/images/luci-i.svg b/scripts/simplifiedUI/system/assets/images/luci-i.svg deleted file mode 100644 index 2d73339908..0000000000 --- a/scripts/simplifiedUI/system/assets/images/luci-i.svg +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - diff --git a/scripts/simplifiedUI/system/assets/images/materials/GridPattern.json b/scripts/simplifiedUI/system/assets/images/materials/GridPattern.json deleted file mode 100644 index 468b709ea4..0000000000 --- a/scripts/simplifiedUI/system/assets/images/materials/GridPattern.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "materialVersion": 1, - "materials": { - "albedo": [ - 0.0, - 0.0, - 7.0 - ], - "unlit": true, - "opacity": 0.4, - "albedoMap": "GridPattern.png" - } -} diff --git a/scripts/simplifiedUI/system/assets/images/materials/GridPattern.png b/scripts/simplifiedUI/system/assets/images/materials/GridPattern.png deleted file mode 100644 index 2ecc7f8570..0000000000 Binary files a/scripts/simplifiedUI/system/assets/images/materials/GridPattern.png and /dev/null differ diff --git a/scripts/simplifiedUI/system/assets/images/min-max-toggle.svg b/scripts/simplifiedUI/system/assets/images/min-max-toggle.svg deleted file mode 100644 index 1699cc705d..0000000000 --- a/scripts/simplifiedUI/system/assets/images/min-max-toggle.svg +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - - - - - - - - - - diff --git a/scripts/simplifiedUI/system/assets/images/mute-target.svg b/scripts/simplifiedUI/system/assets/images/mute-target.svg deleted file mode 100644 index 1ed642c79e..0000000000 --- a/scripts/simplifiedUI/system/assets/images/mute-target.svg +++ /dev/null @@ -1,33 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - diff --git a/scripts/simplifiedUI/system/assets/images/progress-bar-2k.svg b/scripts/simplifiedUI/system/assets/images/progress-bar-2k.svg deleted file mode 100644 index 45758c7c68..0000000000 --- a/scripts/simplifiedUI/system/assets/images/progress-bar-2k.svg +++ /dev/null @@ -1,26 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - diff --git a/scripts/simplifiedUI/system/assets/images/progress-bar-4k.svg b/scripts/simplifiedUI/system/assets/images/progress-bar-4k.svg deleted file mode 100644 index 609ab9610b..0000000000 --- a/scripts/simplifiedUI/system/assets/images/progress-bar-4k.svg +++ /dev/null @@ -1,26 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - diff --git a/scripts/simplifiedUI/system/assets/images/progress-bar-text.svg b/scripts/simplifiedUI/system/assets/images/progress-bar-text.svg deleted file mode 100644 index 05ebb3f637..0000000000 --- a/scripts/simplifiedUI/system/assets/images/progress-bar-text.svg +++ /dev/null @@ -1,103 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/scripts/simplifiedUI/system/assets/images/run.svg b/scripts/simplifiedUI/system/assets/images/run.svg deleted file mode 100644 index 0957166346..0000000000 --- a/scripts/simplifiedUI/system/assets/images/run.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/scripts/simplifiedUI/system/assets/images/textures/dirt.jpeg b/scripts/simplifiedUI/system/assets/images/textures/dirt.jpeg deleted file mode 100644 index 694e4f3c9a..0000000000 Binary files a/scripts/simplifiedUI/system/assets/images/textures/dirt.jpeg and /dev/null differ diff --git a/scripts/simplifiedUI/system/assets/images/textures/grass.png b/scripts/simplifiedUI/system/assets/images/textures/grass.png deleted file mode 100644 index d51fe0cf28..0000000000 Binary files a/scripts/simplifiedUI/system/assets/images/textures/grass.png and /dev/null differ diff --git a/scripts/simplifiedUI/system/assets/images/tools/add-remove-friends.svg b/scripts/simplifiedUI/system/assets/images/tools/add-remove-friends.svg deleted file mode 100644 index 6ee9ce842d..0000000000 --- a/scripts/simplifiedUI/system/assets/images/tools/add-remove-friends.svg +++ /dev/null @@ -1,55 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/scripts/simplifiedUI/system/assets/images/tools/assets-01.svg b/scripts/simplifiedUI/system/assets/images/tools/assets-01.svg deleted file mode 100644 index d7bdd1d7f0..0000000000 --- a/scripts/simplifiedUI/system/assets/images/tools/assets-01.svg +++ /dev/null @@ -1,186 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/scripts/simplifiedUI/system/assets/images/tools/bubble.svg b/scripts/simplifiedUI/system/assets/images/tools/bubble.svg deleted file mode 100644 index 064b7734a9..0000000000 --- a/scripts/simplifiedUI/system/assets/images/tools/bubble.svg +++ /dev/null @@ -1,275 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/scripts/simplifiedUI/system/assets/images/tools/cube-01.svg b/scripts/simplifiedUI/system/assets/images/tools/cube-01.svg deleted file mode 100644 index f8cf96e4f2..0000000000 --- a/scripts/simplifiedUI/system/assets/images/tools/cube-01.svg +++ /dev/null @@ -1,103 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/scripts/simplifiedUI/system/assets/images/tools/directory.svg b/scripts/simplifiedUI/system/assets/images/tools/directory.svg deleted file mode 100644 index 09f3c14bf0..0000000000 --- a/scripts/simplifiedUI/system/assets/images/tools/directory.svg +++ /dev/null @@ -1,255 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/scripts/simplifiedUI/system/assets/images/tools/edit.svg b/scripts/simplifiedUI/system/assets/images/tools/edit.svg deleted file mode 100644 index f65e0cd84d..0000000000 --- a/scripts/simplifiedUI/system/assets/images/tools/edit.svg +++ /dev/null @@ -1,123 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/scripts/simplifiedUI/system/assets/images/tools/help.svg b/scripts/simplifiedUI/system/assets/images/tools/help.svg deleted file mode 100644 index b7fa8ca5cd..0000000000 --- a/scripts/simplifiedUI/system/assets/images/tools/help.svg +++ /dev/null @@ -1,110 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/scripts/simplifiedUI/system/assets/images/tools/ignore.svg b/scripts/simplifiedUI/system/assets/images/tools/ignore.svg deleted file mode 100644 index f315c5f249..0000000000 --- a/scripts/simplifiedUI/system/assets/images/tools/ignore.svg +++ /dev/null @@ -1,177 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/scripts/simplifiedUI/system/assets/images/tools/kick.svg b/scripts/simplifiedUI/system/assets/images/tools/kick.svg deleted file mode 100644 index 1eed6e7f43..0000000000 --- a/scripts/simplifiedUI/system/assets/images/tools/kick.svg +++ /dev/null @@ -1,140 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/scripts/simplifiedUI/system/assets/images/tools/light-01.svg b/scripts/simplifiedUI/system/assets/images/tools/light-01.svg deleted file mode 100644 index 4573c7d636..0000000000 --- a/scripts/simplifiedUI/system/assets/images/tools/light-01.svg +++ /dev/null @@ -1,112 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/scripts/simplifiedUI/system/assets/images/tools/market.svg b/scripts/simplifiedUI/system/assets/images/tools/market.svg deleted file mode 100644 index 0cec030933..0000000000 --- a/scripts/simplifiedUI/system/assets/images/tools/market.svg +++ /dev/null @@ -1,147 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/scripts/simplifiedUI/system/assets/images/tools/mic.svg b/scripts/simplifiedUI/system/assets/images/tools/mic.svg deleted file mode 100644 index 3a7c183bc4..0000000000 --- a/scripts/simplifiedUI/system/assets/images/tools/mic.svg +++ /dev/null @@ -1,123 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/scripts/simplifiedUI/system/assets/images/tools/min-max-toggle.svg b/scripts/simplifiedUI/system/assets/images/tools/min-max-toggle.svg deleted file mode 100644 index 1699cc705d..0000000000 --- a/scripts/simplifiedUI/system/assets/images/tools/min-max-toggle.svg +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - - - - - - - - - - diff --git a/scripts/simplifiedUI/system/assets/images/tools/model-01.svg b/scripts/simplifiedUI/system/assets/images/tools/model-01.svg deleted file mode 100644 index e760d74d5c..0000000000 --- a/scripts/simplifiedUI/system/assets/images/tools/model-01.svg +++ /dev/null @@ -1,111 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/scripts/simplifiedUI/system/assets/images/tools/particle-01.svg b/scripts/simplifiedUI/system/assets/images/tools/particle-01.svg deleted file mode 100644 index cfcfb0ea7f..0000000000 --- a/scripts/simplifiedUI/system/assets/images/tools/particle-01.svg +++ /dev/null @@ -1,161 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/scripts/simplifiedUI/system/assets/images/tools/people.svg b/scripts/simplifiedUI/system/assets/images/tools/people.svg deleted file mode 100644 index 5fedfefa75..0000000000 --- a/scripts/simplifiedUI/system/assets/images/tools/people.svg +++ /dev/null @@ -1,161 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/scripts/simplifiedUI/system/assets/images/tools/polyvox.svg b/scripts/simplifiedUI/system/assets/images/tools/polyvox.svg deleted file mode 100644 index 69f1e978ff..0000000000 --- a/scripts/simplifiedUI/system/assets/images/tools/polyvox.svg +++ /dev/null @@ -1,39 +0,0 @@ - - - - -polyvox - - - -voxels - - diff --git a/scripts/simplifiedUI/system/assets/images/tools/snap.svg b/scripts/simplifiedUI/system/assets/images/tools/snap.svg deleted file mode 100644 index c540f307ae..0000000000 --- a/scripts/simplifiedUI/system/assets/images/tools/snap.svg +++ /dev/null @@ -1,109 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/scripts/simplifiedUI/system/assets/images/tools/sphere-01.svg b/scripts/simplifiedUI/system/assets/images/tools/sphere-01.svg deleted file mode 100644 index 975199c8da..0000000000 --- a/scripts/simplifiedUI/system/assets/images/tools/sphere-01.svg +++ /dev/null @@ -1,108 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/scripts/simplifiedUI/system/assets/images/tools/sphere-add.svg b/scripts/simplifiedUI/system/assets/images/tools/sphere-add.svg deleted file mode 100644 index 59ca489b5f..0000000000 --- a/scripts/simplifiedUI/system/assets/images/tools/sphere-add.svg +++ /dev/null @@ -1,77 +0,0 @@ - - - -image/svg+xmladd - \ No newline at end of file diff --git a/scripts/simplifiedUI/system/assets/images/tools/sphere-delete.svg b/scripts/simplifiedUI/system/assets/images/tools/sphere-delete.svg deleted file mode 100644 index 6997654500..0000000000 --- a/scripts/simplifiedUI/system/assets/images/tools/sphere-delete.svg +++ /dev/null @@ -1,76 +0,0 @@ - - - -image/svg+xmldelete - \ No newline at end of file diff --git a/scripts/simplifiedUI/system/assets/images/tools/steam-invite.svg b/scripts/simplifiedUI/system/assets/images/tools/steam-invite.svg deleted file mode 100644 index ce225cca68..0000000000 --- a/scripts/simplifiedUI/system/assets/images/tools/steam-invite.svg +++ /dev/null @@ -1,112 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/scripts/simplifiedUI/system/assets/images/tools/switch.svg b/scripts/simplifiedUI/system/assets/images/tools/switch.svg deleted file mode 100644 index e67a9aac04..0000000000 --- a/scripts/simplifiedUI/system/assets/images/tools/switch.svg +++ /dev/null @@ -1,167 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/scripts/simplifiedUI/system/assets/images/tools/text-01.svg b/scripts/simplifiedUI/system/assets/images/tools/text-01.svg deleted file mode 100644 index d33d66d4a5..0000000000 --- a/scripts/simplifiedUI/system/assets/images/tools/text-01.svg +++ /dev/null @@ -1,80 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/scripts/simplifiedUI/system/assets/images/tools/upload-01.svg b/scripts/simplifiedUI/system/assets/images/tools/upload-01.svg deleted file mode 100644 index 149b10f3bc..0000000000 --- a/scripts/simplifiedUI/system/assets/images/tools/upload-01.svg +++ /dev/null @@ -1,103 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/scripts/simplifiedUI/system/assets/images/tools/voxel-add.svg b/scripts/simplifiedUI/system/assets/images/tools/voxel-add.svg deleted file mode 100644 index 8e6e2c5b35..0000000000 --- a/scripts/simplifiedUI/system/assets/images/tools/voxel-add.svg +++ /dev/null @@ -1,104 +0,0 @@ - - - -image/svg+xmladd - \ No newline at end of file diff --git a/scripts/simplifiedUI/system/assets/images/tools/voxel-delete.svg b/scripts/simplifiedUI/system/assets/images/tools/voxel-delete.svg deleted file mode 100644 index 0b0d0b9787..0000000000 --- a/scripts/simplifiedUI/system/assets/images/tools/voxel-delete.svg +++ /dev/null @@ -1,103 +0,0 @@ - - - -image/svg+xmldelete - \ No newline at end of file diff --git a/scripts/simplifiedUI/system/assets/images/tools/voxel-terrain.svg b/scripts/simplifiedUI/system/assets/images/tools/voxel-terrain.svg deleted file mode 100644 index e5ed16dbcd..0000000000 --- a/scripts/simplifiedUI/system/assets/images/tools/voxel-terrain.svg +++ /dev/null @@ -1,101 +0,0 @@ - - - -image/svg+xmlterrain - \ No newline at end of file diff --git a/scripts/simplifiedUI/system/assets/images/tools/voxels.svg b/scripts/simplifiedUI/system/assets/images/tools/voxels.svg deleted file mode 100644 index a0dbd63d45..0000000000 --- a/scripts/simplifiedUI/system/assets/images/tools/voxels.svg +++ /dev/null @@ -1,35 +0,0 @@ - - - - - - - - - - - - - - - - - - diff --git a/scripts/simplifiedUI/system/assets/images/tools/web-01.svg b/scripts/simplifiedUI/system/assets/images/tools/web-01.svg deleted file mode 100644 index 903b3ac819..0000000000 --- a/scripts/simplifiedUI/system/assets/images/tools/web-01.svg +++ /dev/null @@ -1,76 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/scripts/simplifiedUI/system/assets/images/tools/zone-01.svg b/scripts/simplifiedUI/system/assets/images/tools/zone-01.svg deleted file mode 100644 index 29d17e5187..0000000000 --- a/scripts/simplifiedUI/system/assets/images/tools/zone-01.svg +++ /dev/null @@ -1,131 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/scripts/simplifiedUI/system/assets/images/unlock.svg b/scripts/simplifiedUI/system/assets/images/unlock.svg deleted file mode 100644 index 789a8b0ed5..0000000000 --- a/scripts/simplifiedUI/system/assets/images/unlock.svg +++ /dev/null @@ -1,90 +0,0 @@ - - - - - - - - - - - - - - - image/svg+xml - - - - - - - - - - diff --git a/scripts/simplifiedUI/system/assets/models/Avatar-Overlay-v1.fbx b/scripts/simplifiedUI/system/assets/models/Avatar-Overlay-v1.fbx deleted file mode 100644 index db710702f2..0000000000 Binary files a/scripts/simplifiedUI/system/assets/models/Avatar-Overlay-v1.fbx and /dev/null differ diff --git a/scripts/simplifiedUI/system/assets/models/Bubble-v14.fbx b/scripts/simplifiedUI/system/assets/models/Bubble-v14.fbx deleted file mode 100644 index c7d3122f00..0000000000 Binary files a/scripts/simplifiedUI/system/assets/models/Bubble-v14.fbx and /dev/null differ diff --git a/scripts/simplifiedUI/system/assets/models/black-sphere.fbx b/scripts/simplifiedUI/system/assets/models/black-sphere.fbx deleted file mode 100644 index 2e6dea233f..0000000000 Binary files a/scripts/simplifiedUI/system/assets/models/black-sphere.fbx and /dev/null differ diff --git a/scripts/simplifiedUI/system/assets/models/miniTabletBlank.fbx b/scripts/simplifiedUI/system/assets/models/miniTabletBlank.fbx deleted file mode 100644 index a2faa2a80a..0000000000 Binary files a/scripts/simplifiedUI/system/assets/models/miniTabletBlank.fbx and /dev/null differ diff --git a/scripts/simplifiedUI/system/assets/models/oculusSensorv11.fbx b/scripts/simplifiedUI/system/assets/models/oculusSensorv11.fbx deleted file mode 100644 index 52fadc77dc..0000000000 Binary files a/scripts/simplifiedUI/system/assets/models/oculusSensorv11.fbx and /dev/null differ diff --git a/scripts/simplifiedUI/system/assets/models/teleport-cancel.fbx b/scripts/simplifiedUI/system/assets/models/teleport-cancel.fbx deleted file mode 100644 index 1c12e28159..0000000000 Binary files a/scripts/simplifiedUI/system/assets/models/teleport-cancel.fbx and /dev/null differ diff --git a/scripts/simplifiedUI/system/assets/models/teleport-destination.fbm/Teleportation-Destination-Texture2.png b/scripts/simplifiedUI/system/assets/models/teleport-destination.fbm/Teleportation-Destination-Texture2.png deleted file mode 100644 index eb9addcfca..0000000000 Binary files a/scripts/simplifiedUI/system/assets/models/teleport-destination.fbm/Teleportation-Destination-Texture2.png and /dev/null differ diff --git a/scripts/simplifiedUI/system/assets/models/teleport-destination.fbx b/scripts/simplifiedUI/system/assets/models/teleport-destination.fbx deleted file mode 100644 index 5fdb0d56af..0000000000 Binary files a/scripts/simplifiedUI/system/assets/models/teleport-destination.fbx and /dev/null differ diff --git a/scripts/simplifiedUI/system/assets/models/teleport-seat.fbx b/scripts/simplifiedUI/system/assets/models/teleport-seat.fbx deleted file mode 100644 index cd7a9abc7e..0000000000 Binary files a/scripts/simplifiedUI/system/assets/models/teleport-seat.fbx and /dev/null differ diff --git a/scripts/simplifiedUI/system/assets/models/teleportationSpotBasev8.fbx b/scripts/simplifiedUI/system/assets/models/teleportationSpotBasev8.fbx deleted file mode 100644 index d651575dea..0000000000 Binary files a/scripts/simplifiedUI/system/assets/models/teleportationSpotBasev8.fbx and /dev/null differ diff --git a/scripts/simplifiedUI/system/assets/models/trackingSpacev18.fbx b/scripts/simplifiedUI/system/assets/models/trackingSpacev18.fbx deleted file mode 100644 index 16597eb285..0000000000 Binary files a/scripts/simplifiedUI/system/assets/models/trackingSpacev18.fbx and /dev/null differ diff --git a/scripts/simplifiedUI/system/assets/sounds/bubble.wav b/scripts/simplifiedUI/system/assets/sounds/bubble.wav deleted file mode 100644 index fd23a235d4..0000000000 Binary files a/scripts/simplifiedUI/system/assets/sounds/bubble.wav and /dev/null differ diff --git a/scripts/simplifiedUI/system/assets/sounds/button-click.wav b/scripts/simplifiedUI/system/assets/sounds/button-click.wav deleted file mode 100644 index 30a097ce45..0000000000 Binary files a/scripts/simplifiedUI/system/assets/sounds/button-click.wav and /dev/null differ diff --git a/scripts/simplifiedUI/system/assets/sounds/button-hover.wav b/scripts/simplifiedUI/system/assets/sounds/button-hover.wav deleted file mode 100644 index cd76d0174c..0000000000 Binary files a/scripts/simplifiedUI/system/assets/sounds/button-hover.wav and /dev/null differ diff --git a/scripts/simplifiedUI/system/assets/sounds/countdown-tick.wav b/scripts/simplifiedUI/system/assets/sounds/countdown-tick.wav deleted file mode 100644 index 015e1f642e..0000000000 Binary files a/scripts/simplifiedUI/system/assets/sounds/countdown-tick.wav and /dev/null differ diff --git a/scripts/simplifiedUI/system/assets/sounds/entitySnap.wav b/scripts/simplifiedUI/system/assets/sounds/entitySnap.wav deleted file mode 100644 index 4584f3dcaa..0000000000 Binary files a/scripts/simplifiedUI/system/assets/sounds/entitySnap.wav and /dev/null differ diff --git a/scripts/simplifiedUI/system/assets/sounds/finish-recording.wav b/scripts/simplifiedUI/system/assets/sounds/finish-recording.wav deleted file mode 100644 index f224049f97..0000000000 Binary files a/scripts/simplifiedUI/system/assets/sounds/finish-recording.wav and /dev/null differ diff --git a/scripts/simplifiedUI/system/assets/sounds/goodbye.wav b/scripts/simplifiedUI/system/assets/sounds/goodbye.wav deleted file mode 100644 index bd6c51a5c0..0000000000 Binary files a/scripts/simplifiedUI/system/assets/sounds/goodbye.wav and /dev/null differ diff --git a/scripts/simplifiedUI/system/assets/sounds/hello.wav b/scripts/simplifiedUI/system/assets/sounds/hello.wav deleted file mode 100644 index 6269dab5db..0000000000 Binary files a/scripts/simplifiedUI/system/assets/sounds/hello.wav and /dev/null differ diff --git a/scripts/simplifiedUI/system/assets/sounds/notification-general1.raw b/scripts/simplifiedUI/system/assets/sounds/notification-general1.raw deleted file mode 100644 index be81fa15c5..0000000000 Binary files a/scripts/simplifiedUI/system/assets/sounds/notification-general1.raw and /dev/null differ diff --git a/scripts/simplifiedUI/system/assets/sounds/notification-general2.raw b/scripts/simplifiedUI/system/assets/sounds/notification-general2.raw deleted file mode 100644 index 58f0bac19c..0000000000 Binary files a/scripts/simplifiedUI/system/assets/sounds/notification-general2.raw and /dev/null differ diff --git a/scripts/simplifiedUI/system/assets/sounds/rezzing.wav b/scripts/simplifiedUI/system/assets/sounds/rezzing.wav deleted file mode 100644 index 3c059aecdf..0000000000 Binary files a/scripts/simplifiedUI/system/assets/sounds/rezzing.wav and /dev/null differ diff --git a/scripts/simplifiedUI/system/assets/sounds/short1.wav b/scripts/simplifiedUI/system/assets/sounds/short1.wav deleted file mode 100644 index fb03f5dd49..0000000000 Binary files a/scripts/simplifiedUI/system/assets/sounds/short1.wav and /dev/null differ diff --git a/scripts/simplifiedUI/system/assets/sounds/start-recording.wav b/scripts/simplifiedUI/system/assets/sounds/start-recording.wav deleted file mode 100644 index 71c69f3372..0000000000 Binary files a/scripts/simplifiedUI/system/assets/sounds/start-recording.wav and /dev/null differ diff --git a/scripts/simplifiedUI/system/attachedEntitiesManager.js b/scripts/simplifiedUI/system/attachedEntitiesManager.js deleted file mode 100644 index 061e27f595..0000000000 --- a/scripts/simplifiedUI/system/attachedEntitiesManager.js +++ /dev/null @@ -1,285 +0,0 @@ -// -// attachedEntitiesManager.js -// -// Created by Seth Alves on 2016-1-20 -// Copyright 2016 High Fidelity, Inc. -// -// This script handles messages from the grab script related to wearables, and interacts with a doppelganger. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -Script.include("libraries/utils.js"); - -var DEFAULT_WEARABLE_DATA = { - joints: {} -}; - - -var MINIMUM_DROP_DISTANCE_FROM_JOINT = 0.8; -var ATTACHED_ENTITY_SEARCH_DISTANCE = 10.0; -var ATTACHED_ENTITIES_SETTINGS_KEY = "ATTACHED_ENTITIES"; -var DRESSING_ROOM_DISTANCE = 2.0; -var SHOW_TOOL_BAR = false; - -// tool bar - -if (SHOW_TOOL_BAR) { - var BUTTON_SIZE = 64; - var PADDING = 6; - Script.include(["libraries/toolBars.js"]); - - var toolBar = new ToolBar(0, 0, ToolBar.HORIZONTAL, "highfidelity.attachedEntities.toolbar"); - var lockButton = toolBar.addTool({ - width: BUTTON_SIZE, - height: BUTTON_SIZE, - imageURL: Script.resolvePath("assets/images/lock.svg"), - color: { - red: 255, - green: 255, - blue: 255 - }, - alpha: 1, - visible: true - }, false); -} - - -function mousePressEvent(event) { - var clickedOverlay = Overlays.getOverlayAtPoint({ - x: event.x, - y: event.y - }); - - if (lockButton === toolBar.clicked(clickedOverlay)) { - manager.toggleLocked(); - } -} - -function scriptEnding() { - if (SHOW_TOOL_BAR) { - toolBar.cleanup(); - } -} - -if (SHOW_TOOL_BAR) { - Controller.mousePressEvent.connect(mousePressEvent); -} -Script.scriptEnding.connect(scriptEnding); - - - -// attached entites - - -function AttachedEntitiesManager() { - var clothingLocked = false; - - this.subscribeToMessages = function() { - Messages.subscribe('Hifi-Object-Manipulation'); - Messages.messageReceived.connect(this.handleWearableMessages); - } - - this.handleWearableMessages = function(channel, message, sender) { - if (channel !== 'Hifi-Object-Manipulation') { - return; - } - - var parsedMessage = null; - - try { - parsedMessage = JSON.parse(message); - } catch (e) { - print('error parsing wearable message'); - return; - } - - if (parsedMessage.action === 'update' || - parsedMessage.action === 'loaded') { - // ignore - } else if (parsedMessage.action === 'release') { - manager.handleEntityRelease(parsedMessage.grabbedEntity, parsedMessage.joint) - // manager.saveAttachedEntities(); - } else if (parsedMessage.action === 'equip') { - // manager.saveAttachedEntities(); - } else { - print('attachedEntitiesManager -- unknown actions: ' + parsedMessage.action); - } - } - - this.handleEntityRelease = function(grabbedEntity, releasedFromJoint) { - // if this is still equipped, just rewrite the position information. - var grabData = getEntityCustomData('grabKey', grabbedEntity, {}); - - var allowedJoints = getEntityCustomData('wearable', grabbedEntity, DEFAULT_WEARABLE_DATA).joints; - - var props = Entities.getEntityProperties(grabbedEntity, ["position", "parentID", "parentJointIndex"]); - if (props.parentID === Uuid.NULL || props.parentID === MyAvatar.sessionUUID) { - var bestJointName = ""; - var bestJointIndex = -1; - var bestJointDistance = 0; - var bestJointOffset = null; - for (var jointName in allowedJoints) { - if ((releasedFromJoint == "LeftHand" || releasedFromJoint == "RightHand") && - (jointName == "LeftHand" || jointName == "RightHand")) { - // don't auto-attach to a hand if a hand just dropped something - continue; - } - var jointIndex = MyAvatar.getJointIndex(jointName); - if (jointIndex >= 0) { - var jointPosition = MyAvatar.getJointPosition(jointIndex); - var distanceFromJoint = Vec3.distance(jointPosition, props.position); - if (distanceFromJoint <= MINIMUM_DROP_DISTANCE_FROM_JOINT) { - if (bestJointIndex == -1 || distanceFromJoint < bestJointDistance) { - bestJointName = jointName; - bestJointIndex = jointIndex; - bestJointDistance = distanceFromJoint; - bestJointOffset = allowedJoints[jointName]; - } - } - } - } - - if (bestJointIndex != -1) { - var wearProps = Entities.getEntityProperties(grabbedEntity); - wearProps.parentID = MyAvatar.sessionUUID; - wearProps.parentJointIndex = bestJointIndex; - delete wearProps.localPosition; - delete wearProps.localRotation; - var updatePresets = false; - if (bestJointOffset && bestJointOffset.constructor === Array) { - if (!clothingLocked || bestJointOffset.length < 2) { - // we're unlocked or this thing didn't have a preset position, so update it - updatePresets = true; - } else { - // don't snap the entity to the preferred position if unlocked - wearProps.localPosition = bestJointOffset[0]; - wearProps.localRotation = bestJointOffset[1]; - } - } - - Entities.deleteEntity(grabbedEntity); - //the true boolean here after add entity adds it as an 'avatar entity', which can travel with you from server to server. - - var newEntity = Entities.addEntity(wearProps, true); - - if (updatePresets) { - this.updateRelativeOffsets(newEntity); - } - } else if (props.parentID != Uuid.NULL) { - // drop the entity and set it to have no parent (not on the avatar), unless it's being equipped in a hand. - if (props.parentID === MyAvatar.sessionUUID && - (props.parentJointIndex == MyAvatar.getJointIndex("RightHand") || - props.parentJointIndex == MyAvatar.getJointIndex("LeftHand"))) { - // this is equipped on a hand -- don't clear the parent. - } else { - var wearProps = Entities.getEntityProperties(grabbedEntity); - wearProps.parentID = Uuid.NULL; - wearProps.parentJointIndex = -1; - delete wearProps.id; - delete wearProps.created; - delete wearProps.age; - delete wearProps.ageAsText; - delete wearProps.naturalDimensions; - delete wearProps.naturalPosition; - delete wearProps.actionData; - delete wearProps.sittingPoints; - delete wearProps.boundingBox; - delete wearProps.avatarEntity; - delete wearProps.owningAvatarID; - delete wearProps.localPosition; - delete wearProps.localRotation; - Entities.deleteEntity(grabbedEntity); - Entities.addEntity(wearProps); - } - } - } - } - - this.updateRelativeOffsets = function(entityID) { - // save the preferred (current) relative position and rotation into the user-data of the entity - var props = Entities.getEntityProperties(entityID); - if (props.parentID == MyAvatar.sessionUUID) { - grabData = getEntityCustomData('grabKey', entityID, {}); - var wearableData = getEntityCustomData('wearable', entityID, DEFAULT_WEARABLE_DATA); - var currentJointName = MyAvatar.getJointNames()[props.parentJointIndex]; - wearableData.joints[currentJointName] = [props.localPosition, props.localRotation]; - setEntityCustomData('wearable', entityID, wearableData); - return true; - } - return false; - } - - // this.saveAttachedEntities = function() { - // print("--- saving attached entities ---"); - // saveData = []; - // var nearbyEntities = Entities.findEntities(MyAvatar.position, ATTACHED_ENTITY_SEARCH_DISTANCE); - // for (i = 0; i < nearbyEntities.length; i++) { - // var entityID = nearbyEntities[i]; - // if (this.updateRelativeOffsets(entityID)) { - // var props = Entities.getEntityProperties(entityID); // refresh, because updateRelativeOffsets changed them - // this.scrubProperties(props); - // saveData.push(props); - // } - // } - // Settings.setValue(ATTACHED_ENTITIES_SETTINGS_KEY, JSON.stringify(saveData)); - // } - - // this.scrubProperties = function(props) { - // var toScrub = ["queryAACube", "position", "rotation", - // "created", "ageAsText", "naturalDimensions", - // "naturalPosition", "velocity", "acceleration", - // "angularVelocity", "boundingBox"]; - // toScrub.forEach(function(propertyName) { - // delete props[propertyName]; - // }); - // // if the userData has a grabKey, clear old state - // if ("userData" in props) { - // try { - // parsedUserData = JSON.parse(props.userData); - // if ("grabKey" in parsedUserData) { - // parsedUserData.grabKey.refCount = 0; - // delete parsedUserData.grabKey["avatarId"]; - // props["userData"] = JSON.stringify(parsedUserData); - // } - // } catch (e) { - // } - // } - // } - - // this.loadAttachedEntities = function(grabbedEntity) { - // print("--- loading attached entities ---"); - // jsonAttachmentData = Settings.getValue(ATTACHED_ENTITIES_SETTINGS_KEY); - // var loadData = []; - // try { - // loadData = JSON.parse(jsonAttachmentData); - // } catch (e) { - // print('error parsing saved attachment data'); - // return; - // } - - // for (i = 0; i < loadData.length; i ++) { - // var savedProps = loadData[ i ]; - // var currentProps = Entities.getEntityProperties(savedProps.id); - // if (currentProps.id == savedProps.id && - // // TODO -- also check that parentJointIndex matches? - // currentProps.parentID == MyAvatar.sessionUUID) { - // // entity is already in-world. TODO -- patch it up? - // continue; - // } - // this.scrubProperties(savedProps); - // delete savedProps["id"]; - // savedProps.parentID = MyAvatar.sessionUUID; // this will change between sessions - // var loadedEntityID = Entities.addEntity(savedProps, true); - - // Messages.sendMessage('Hifi-Object-Manipulation', JSON.stringify({ - // action: 'loaded', - // grabbedEntity: loadedEntityID - // })); - // } - // } -} - -var manager = new AttachedEntitiesManager(); -manager.subscribeToMessages(); \ No newline at end of file diff --git a/scripts/simplifiedUI/system/audio.js b/scripts/simplifiedUI/system/audio.js deleted file mode 100644 index a161b40ffd..0000000000 --- a/scripts/simplifiedUI/system/audio.js +++ /dev/null @@ -1,92 +0,0 @@ -"use strict"; - -// -// audio.js -// -// Created by Howard Stearns on 2 Jun 2016 -// Copyright 2016 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// -/* eslint indent: ["error", 4, { "outerIIFEBody": 0 }] */ - -(function() { // BEGIN LOCAL_SCOPE - -var TABLET_BUTTON_NAME = "AUDIO"; -var HOME_BUTTON_TEXTURE = "http://hifi-content.s3.amazonaws.com/alan/dev/tablet-with-home-button.fbx/tablet-with-home-button.fbm/button-root.png"; -var AUDIO_QML_SOURCE = "hifi/audio/Audio.qml"; - -var MUTE_ICONS = { - icon: "icons/tablet-icons/mic-mute-i.svg", - activeIcon: "icons/tablet-icons/mic-mute-a.svg" -}; - -var UNMUTE_ICONS = { - icon: "icons/tablet-icons/mic-unmute-i.svg", - activeIcon: "icons/tablet-icons/mic-unmute-a.svg" -}; -var PTT_ICONS = { - icon: "icons/tablet-icons/mic-ptt-i.svg", - activeIcon: "icons/tablet-icons/mic-ptt-a.svg" -}; - -function onMuteToggled() { - if (Audio.pushToTalk) { - button.editProperties(PTT_ICONS); - } else if (Audio.muted) { - button.editProperties(MUTE_ICONS); - } else { - button.editProperties(UNMUTE_ICONS); - } -} - -var onAudioScreen = false; - -function onClicked() { - if (onAudioScreen) { - // for toolbar-mode: go back to home screen, this will close the window. - tablet.gotoHomeScreen(); - } else { - if (HMD.tabletID) { - Entities.editEntity(HMD.tabletID, { textures: JSON.stringify({ "tex.close": HOME_BUTTON_TEXTURE }) }); - } - tablet.loadQMLSource(AUDIO_QML_SOURCE); - } -} - -function onScreenChanged(type, url) { - onAudioScreen = (type === "QML" && url === AUDIO_QML_SOURCE); - // for toolbar mode: change button to active when window is first openend, false otherwise. - button.editProperties({isActive: onAudioScreen}); -} - -var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); -var button = tablet.addButton({ - icon: Audio.pushToTalk ? PTT_ICONS.icon : Audio.muted ? MUTE_ICONS.icon : UNMUTE_ICONS.icon, - activeIcon: Audio.pushToTalk ? PTT_ICONS.activeIcon : Audio.muted ? MUTE_ICONS.activeIcon : UNMUTE_ICONS.activeIcon, - text: TABLET_BUTTON_NAME, - sortOrder: 1 -}); - -onMuteToggled(); - -button.clicked.connect(onClicked); -tablet.screenChanged.connect(onScreenChanged); -Audio.mutedChanged.connect(onMuteToggled); -Audio.pushToTalkChanged.connect(onMuteToggled); -HMD.displayModeChanged.connect(onMuteToggled); - -Script.scriptEnding.connect(function () { - if (onAudioScreen) { - tablet.gotoHomeScreen(); - } - button.clicked.disconnect(onClicked); - tablet.screenChanged.disconnect(onScreenChanged); - Audio.mutedChanged.disconnect(onMuteToggled); - Audio.pushToTalkChanged.disconnect(onMuteToggled); - HMD.displayModeChanged.disconnect(onMuteToggled); - tablet.removeButton(button); -}); - -}()); // END LOCAL_SCOPE diff --git a/scripts/simplifiedUI/system/audioMuteOverlay.js b/scripts/simplifiedUI/system/audioMuteOverlay.js deleted file mode 100644 index 9acc5ab123..0000000000 --- a/scripts/simplifiedUI/system/audioMuteOverlay.js +++ /dev/null @@ -1,130 +0,0 @@ -// -// audioMuteOverlay.js -// -// client script that creates an overlay to provide mute feedback -// -// Created by Triplelexx on 17/03/09 -// Reworked by Seth Alves on 2019-2-17 -// Copyright 2017 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -"use strict"; - -/* global Audio, Script, Overlays, Quat, MyAvatar, HMD */ - -(function() { // BEGIN LOCAL_SCOPE - - var lastShortTermInputLoudness = 0.0; - var lastLongTermInputLoudness = 0.0; - var sampleRate = 8.0; // Hz - - var shortTermAttackTC = Math.exp(-1.0 / (sampleRate * 0.500)); // 500 milliseconds attack - var shortTermReleaseTC = Math.exp(-1.0 / (sampleRate * 1.000)); // 1000 milliseconds release - - var longTermAttackTC = Math.exp(-1.0 / (sampleRate * 5.0)); // 5 second attack - var longTermReleaseTC = Math.exp(-1.0 / (sampleRate * 10.0)); // 10 seconds release - - var activationThreshold = 0.05; // how much louder short-term needs to be than long-term to trigger warning - - var holdReset = 2.0 * sampleRate; // 2 seconds hold - var holdCount = 0; - var warningOverlayID = null; - var pollInterval = null; - var warningText = "Muted"; - - function showWarning() { - if (warningOverlayID) { - return; - } - - if (HMD.active) { - warningOverlayID = Overlays.addOverlay("text3d", { - name: "Muted-Warning", - localPosition: { x: 0.0, y: -0.45, z: -1.0 }, - localOrientation: Quat.fromVec3Degrees({ x: 0.0, y: 0.0, z: 0.0, w: 1.0 }), - text: warningText, - textAlpha: 1, - textColor: { red: 226, green: 51, blue: 77 }, - backgroundAlpha: 0, - lineHeight: 0.042, - dimensions: { x: 0.11, y: 0.05 }, - visible: true, - ignoreRayIntersection: true, - drawInFront: true, - grabbable: false, - parentID: MyAvatar.SELF_ID, - parentJointIndex: MyAvatar.getJointIndex("_CAMERA_MATRIX") - }); - } - } - - function hideWarning() { - if (!warningOverlayID) { - return; - } - Overlays.deleteOverlay(warningOverlayID); - warningOverlayID = null; - } - - function startPoll() { - if (pollInterval) { - return; - } - pollInterval = Script.setInterval(function() { - var shortTermInputLoudness = Audio.inputLevel; - var longTermInputLoudness = shortTermInputLoudness; - - var shortTc = (shortTermInputLoudness > lastShortTermInputLoudness) ? shortTermAttackTC : shortTermReleaseTC; - var longTc = (longTermInputLoudness > lastLongTermInputLoudness) ? longTermAttackTC : longTermReleaseTC; - - shortTermInputLoudness += shortTc * (lastShortTermInputLoudness - shortTermInputLoudness); - longTermInputLoudness += longTc * (lastLongTermInputLoudness - longTermInputLoudness); - - lastShortTermInputLoudness = shortTermInputLoudness; - lastLongTermInputLoudness = longTermInputLoudness; - - if (shortTermInputLoudness > lastLongTermInputLoudness + activationThreshold) { - holdCount = holdReset; - } else { - holdCount = Math.max(holdCount - 1, 0); - } - - if (holdCount > 0) { - showWarning(); - } else { - hideWarning(); - } - }, 1000.0 / sampleRate); - } - - function stopPoll() { - if (!pollInterval) { - return; - } - Script.clearInterval(pollInterval); - pollInterval = null; - hideWarning(); - } - - function startOrStopPoll() { - if (Audio.warnWhenMuted && Audio.muted) { - startPoll(); - } else { - stopPoll(); - } - } - - function cleanup() { - stopPoll(); - } - - Script.scriptEnding.connect(cleanup); - - startOrStopPoll(); - Audio.mutedChanged.connect(startOrStopPoll); - Audio.warnWhenMutedChanged.connect(startOrStopPoll); - -}()); // END LOCAL_SCOPE diff --git a/scripts/simplifiedUI/system/audioScope.js b/scripts/simplifiedUI/system/audioScope.js deleted file mode 100644 index 81d8e8fbd4..0000000000 --- a/scripts/simplifiedUI/system/audioScope.js +++ /dev/null @@ -1,95 +0,0 @@ -"use strict"; -// -// audioScope.js -// scripts/system/ -// -// Created by Brad Hefta-Gaub on 3/10/2016 -// Copyright 2016 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// -/* global Script, Tablet, AudioScope, Audio */ - -(function () { // BEGIN LOCAL_SCOPE - - var scopeVisibile = AudioScope.getVisible(); - var scopePaused = AudioScope.getPause(); - var autoPause = false; - - var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); - var showScopeButton = tablet.addButton({ - icon: "icons/tablet-icons/scope.svg", - text: "Audio Scope", - isActive: scopeVisibile - }); - - var scopePauseImage = "icons/tablet-icons/scope-pause.svg"; - var scopePlayImage = "icons/tablet-icons/scope-play.svg"; - - var pauseScopeButton = tablet.addButton({ - icon: scopePaused ? scopePlayImage : scopePauseImage, - text: scopePaused ? "Unpause" : "Pause", - isActive: scopePaused - }); - - var autoPauseScopeButton = tablet.addButton({ - icon: "icons/tablet-icons/scope-auto.svg", - text: "Auto Pause", - isActive: autoPause - }); - - function setScopePause(paused) { - scopePaused = paused; - pauseScopeButton.editProperties({ - isActive: scopePaused, - icon: scopePaused ? scopePlayImage : scopePauseImage, - text: scopePaused ? "Unpause" : "Pause" - }); - AudioScope.setPause(scopePaused); - } - - showScopeButton.clicked.connect(function () { - // toggle button active state - scopeVisibile = !scopeVisibile; - showScopeButton.editProperties({ - isActive: scopeVisibile - }); - - AudioScope.setVisible(scopeVisibile); - }); - - pauseScopeButton.clicked.connect(function () { - // toggle button active state - setScopePause(!scopePaused); - }); - - autoPauseScopeButton.clicked.connect(function () { - // toggle button active state - autoPause = !autoPause; - autoPauseScopeButton.editProperties({ - isActive: autoPause, - text: autoPause ? "Auto Pause" : "Manual" - }); - }); - - Script.scriptEnding.connect(function () { - tablet.removeButton(showScopeButton); - tablet.removeButton(pauseScopeButton); - tablet.removeButton(autoPauseScopeButton); - }); - - Audio.noiseGateOpened.connect(function(){ - if (autoPause) { - setScopePause(false); - } - }); - - Audio.noiseGateClosed.connect(function(){ - // noise gate closed - if (autoPause) { - setScopePause(true); - } - }); - -}()); // END LOCAL_SCOPE \ No newline at end of file diff --git a/scripts/simplifiedUI/system/avatarFinderBeacon.js b/scripts/simplifiedUI/system/avatarFinderBeacon.js deleted file mode 100644 index 00f3d15fbb..0000000000 --- a/scripts/simplifiedUI/system/avatarFinderBeacon.js +++ /dev/null @@ -1,93 +0,0 @@ -// avatarFinderBeacon.js -// -// Created by Thijs Wenker on 12/7/16 -// Copyright 2016 High Fidelity, Inc. -// -// Shows 2km long red beams for each avatar outside of the 20 meter radius of your avatar, tries to ignore AC Agents. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html - -var MIN_DISPLAY_DISTANCE = 20.0; // meters -var BEAM_COLOR = {red: 255, green: 0, blue: 0}; -var SHOW_THROUGH_WALLS = false; -var BEACON_LENGTH = 2000.0; // meters -var TRY_TO_IGNORE_AC_AGENTS = true; - -var HALF_BEACON_LENGTH = BEACON_LENGTH / 2.0; - -var beacons = {}; - -// List of .fst files used by AC scripts, that should be ignored in the script in case TRY_TO_IGNORE_AC_AGENTS is enabled -var POSSIBLE_AC_AVATARS = [ - 'http://hifi-content.s3.amazonaws.com/ozan/dev/avatars/invisible_avatar/invisible_avatar.fst', - 'http://hifi-content.s3.amazonaws.com/ozan/dev/avatars/camera_man/pod/_latest/camera_man_pod.fst' -]; - -AvatarFinderBeacon = function(avatar) { - var visible = false; - var avatarSessionUUID = avatar.sessionUUID; - this.overlay = Overlays.addOverlay('line3d', { - color: BEAM_COLOR, - dashed: false, - start: Vec3.sum(avatar.position, {x: 0, y: -HALF_BEACON_LENGTH, z: 0}), - end: Vec3.sum(avatar.position, {x: 0, y: HALF_BEACON_LENGTH, z: 0}), - rotation: {x: 0, y: 0, z: 0, w: 1}, - visible: visible, - drawInFront: SHOW_THROUGH_WALLS, - ignoreRayIntersection: true, - parentID: avatarSessionUUID, - parentJointIndex: -2 - }); - this.cleanup = function() { - Overlays.deleteOverlay(this.overlay); - }; - this.shouldShow = function() { - return Vec3.distance(MyAvatar.position, avatar.position) >= MIN_DISPLAY_DISTANCE; - }; - this.update = function() { - avatar = AvatarList.getAvatar(avatarSessionUUID); - Overlays.editOverlay(this.overlay, { - visible: this.shouldShow() - }); - }; -}; - -function updateBeacon(avatarSessionUUID) { - if (!(avatarSessionUUID in beacons)) { - var avatar = AvatarList.getAvatar(avatarSessionUUID); - if (TRY_TO_IGNORE_AC_AGENTS - && (POSSIBLE_AC_AVATARS.indexOf(avatar.skeletonModelURL) !== -1 || Vec3.length(avatar.position) === 0.0)) { - return; - } - beacons[avatarSessionUUID] = new AvatarFinderBeacon(avatar); - return; - } - beacons[avatarSessionUUID].update(); -} - -Window.domainChanged.connect(function () { - beacons = {}; -}); - -Script.update.connect(function() { - AvatarList.getAvatarIdentifiers().forEach(function(avatarSessionUUID) { - updateBeacon(avatarSessionUUID); - }); -}); - -AvatarList.avatarRemovedEvent.connect(function(avatarSessionUUID) { - if (avatarSessionUUID in beacons) { - beacons[avatarSessionUUID].cleanup(); - delete beacons[avatarSessionUUID]; - } -}); - -Script.scriptEnding.connect(function() { - for (var sessionUUID in beacons) { - if (!beacons.hasOwnProperty(sessionUUID)) { - return; - } - beacons[sessionUUID].cleanup(); - } -}); diff --git a/scripts/simplifiedUI/system/avatarapp.js b/scripts/simplifiedUI/system/avatarapp.js deleted file mode 100644 index 6439d30023..0000000000 --- a/scripts/simplifiedUI/system/avatarapp.js +++ /dev/null @@ -1,663 +0,0 @@ -"use strict"; -/*jslint vars:true, plusplus:true, forin:true*/ -/*global Tablet, Script, Entities, MyAvatar, Camera, Quat, HMD, Account, UserActivityLogger, Messages, print, - AvatarBookmarks, ContextOverlay, AddressManager -*/ -/* eslint indent: ["error", 4, { "outerIIFEBody": 0 }] */ -// -// avatarapp.js -// -// Created by Alexander Ivash on April 30, 2018 -// Copyright 2016 High Fidelity, Inc -// -// Distributed under the Apache License, Version 2.0 -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -(function() { // BEGIN LOCAL_SCOPE - -var AVATARAPP_QML_SOURCE = "hifi/AvatarApp.qml"; -Script.include("/~/system/libraries/controllers.js"); - -// constants from AvatarBookmarks.h -var ENTRY_AVATAR_URL = "avatarUrl"; -var ENTRY_AVATAR_ENTITIES = "avatarEntites"; -var ENTRY_AVATAR_SCALE = "avatarScale"; - -function executeLater(callback) { - Script.setTimeout(callback, 300); -} - -function isWearable(avatarEntity) { - return avatarEntity.properties.visible === true && - (avatarEntity.properties.parentID === MyAvatar.sessionUUID || avatarEntity.properties.parentID === MyAvatar.SELF_ID); -} - -function getMyAvatarWearables() { - var entitiesArray = MyAvatar.getAvatarEntitiesVariant(); - var wearablesArray = []; - - for (var i = 0; i < entitiesArray.length; ++i) { - var entity = entitiesArray[i]; - if (!isWearable(entity)) { - continue; - } - - var localRotation = entity.properties.localRotation; - entity.properties.localRotationAngles = Quat.safeEulerAngles(localRotation); - wearablesArray.push(entity); - } - - return wearablesArray; -} - -function getMyAvatar() { - var avatar = {}; - avatar[ENTRY_AVATAR_URL] = MyAvatar.skeletonModelURL; - avatar[ENTRY_AVATAR_SCALE] = MyAvatar.getAvatarScale(); - avatar[ENTRY_AVATAR_ENTITIES] = getMyAvatarWearables(); - return avatar; -} - -function getMyAvatarSettings() { - return { - dominantHand: MyAvatar.getDominantHand(), - hmdAvatarAlignmentType: MyAvatar.getHmdAvatarAlignmentType(), - collisionsEnabled: MyAvatar.getCollisionsEnabled(), - otherAvatarsCollisionsEnabled: MyAvatar.getOtherAvatarsCollisionsEnabled(), - collisionSoundUrl : MyAvatar.collisionSoundURL, - animGraphUrl: MyAvatar.getAnimGraphUrl(), - animGraphOverrideUrl : MyAvatar.getAnimGraphOverrideUrl(), - }; -} - -function updateAvatarWearables(avatar, callback, wearablesOverride) { - executeLater(function() { - var wearables = wearablesOverride ? wearablesOverride : getMyAvatarWearables(); - avatar[ENTRY_AVATAR_ENTITIES] = wearables; - - sendToQml({'method' : 'wearablesUpdated', 'wearables' : wearables}); - sendToQml({ 'method' : 'wearablesFrozenChanged', 'wearablesFrozen' : getWearablesFrozen()}); - - if(callback) - callback(); - }); -} - -var adjustWearables = { - opened : false, - cameraMode : '', - setOpened : function(value) { - if(this.opened !== value) { - if(value) { - this.cameraMode = Camera.mode; - - if(!HMD.active) { - Camera.mode = 'mirror'; - } - } else { - Camera.mode = this.cameraMode; - } - - this.opened = value; - } - } -}; - -var currentAvatarWearablesBackup = null; -var currentAvatar = null; -var currentAvatarSettings = getMyAvatarSettings(); - -var notifyScaleChanged = true; -function onTargetScaleChanged() { - if(currentAvatar.scale !== MyAvatar.getAvatarScale()) { - currentAvatar.scale = MyAvatar.getAvatarScale(); - if(notifyScaleChanged) { - sendToQml({'method' : 'scaleChanged', 'value' : currentAvatar.scale}); - } - } -} - -function onSkeletonModelURLChanged() { - if(currentAvatar || (currentAvatar.skeletonModelURL !== MyAvatar.skeletonModelURL)) { - fromQml({'method' : 'getAvatars'}); - } -} - -function onDominantHandChanged(dominantHand) { - if(currentAvatarSettings.dominantHand !== dominantHand) { - currentAvatarSettings.dominantHand = dominantHand; - sendToQml({'method' : 'settingChanged', 'name' : 'dominantHand', 'value' : dominantHand}); - } -} - -function onHmdAvatarAlignmentTypeChanged(type) { - if (currentAvatarSettings.hmdAvatarAlignmentType !== type) { - currentAvatarSettings.hmdAvatarAlignmentType = type; - sendToQml({'method' : 'settingChanged', 'name' : 'hmdAvatarAlignmentType', 'value' : type}); - } -} - -function onCollisionsEnabledChanged(enabled) { - if(currentAvatarSettings.collisionsEnabled !== enabled) { - currentAvatarSettings.collisionsEnabled = enabled; - sendToQml({'method' : 'settingChanged', 'name' : 'collisionsEnabled', 'value' : enabled}); - } -} - -function onOtherAvatarsCollisionsEnabledChanged(enabled) { - if (currentAvatarSettings.otherAvatarsCollisionsEnabled !== enabled) { - currentAvatarSettings.otherAvatarsCollisionsEnabled = enabled; - sendToQml({ 'method': 'settingChanged', 'name': 'otherAvatarsCollisionsEnabled', 'value': enabled }); - } -} - -function onNewCollisionSoundUrl(url) { - if(currentAvatarSettings.collisionSoundUrl !== url) { - currentAvatarSettings.collisionSoundUrl = url; - sendToQml({'method' : 'settingChanged', 'name' : 'collisionSoundUrl', 'value' : url}); - } -} - -function onAnimGraphUrlChanged(url) { - if (currentAvatarSettings.animGraphUrl !== url) { - currentAvatarSettings.animGraphUrl = url; - sendToQml({ 'method': 'settingChanged', 'name': 'animGraphUrl', 'value': currentAvatarSettings.animGraphUrl }); - - if (currentAvatarSettings.animGraphOverrideUrl !== MyAvatar.getAnimGraphOverrideUrl()) { - currentAvatarSettings.animGraphOverrideUrl = MyAvatar.getAnimGraphOverrideUrl(); - sendToQml({ 'method': 'settingChanged', 'name': 'animGraphOverrideUrl', - 'value': currentAvatarSettings.animGraphOverrideUrl }); - } - } -} - -var selectedAvatarEntityID = null; -var grabbedAvatarEntityChangeNotifier = null; - -var MARKETPLACE_PURCHASES_QML_PATH = "hifi/commerce/wallet/Wallet.qml"; -var MARKETPLACE_URL = Account.metaverseServerURL + "/marketplace"; -var MARKETPLACES_INJECT_SCRIPT_URL = Script.resolvePath("html/js/marketplacesInject.js"); - -function getWearablesFrozen() { - var wearablesFrozen = true; - var wearablesArray = getMyAvatarWearables(); - wearablesArray.forEach(function(wearable) { - if (isGrabbable(wearable.id)) { - wearablesFrozen = false; - } - }); - - return wearablesFrozen; -} - -function freezeWearables() { - var wearablesArray = getMyAvatarWearables(); - wearablesArray.forEach(function(wearable) { - setGrabbable(wearable.id, false); - }); -} - -function unfreezeWearables() { - var wearablesArray = getMyAvatarWearables(); - wearablesArray.forEach(function(wearable) { - setGrabbable(wearable.id, true); - }); -} - - -function fromQml(message) { // messages are {method, params}, like json-rpc. See also sendToQml. - switch (message.method) { - case 'getAvatars': - currentAvatar = getMyAvatar(); - currentAvatarSettings = getMyAvatarSettings(); - - message.data = { - 'bookmarks' : AvatarBookmarks.getBookmarks(), - 'displayName' : MyAvatar.displayName, - 'currentAvatar' : currentAvatar, - 'currentAvatarSettings' : currentAvatarSettings - }; - - for(var bookmarkName in message.data.bookmarks) { - var bookmark = message.data.bookmarks[bookmarkName]; - - if (bookmark.avatarEntites) { - bookmark.avatarEntites.forEach(function(avatarEntity) { - avatarEntity.properties.localRotationAngles = Quat.safeEulerAngles(avatarEntity.properties.localRotation); - }); - } - } - - sendToQml(message); - break; - case 'selectAvatar': - Entities.addingWearable.disconnect(onAddingWearable); - Entities.deletingWearable.disconnect(onDeletingWearable); - AvatarBookmarks.loadBookmark(message.name); - Entities.addingWearable.connect(onAddingWearable); - Entities.deletingWearable.connect(onDeletingWearable); - sendToQml({ 'method' : 'wearablesFrozenChanged', 'wearablesFrozen' : getWearablesFrozen()}); - break; - case 'deleteAvatar': - AvatarBookmarks.removeBookmark(message.name); - break; - case 'addAvatar': - AvatarBookmarks.addBookmark(message.name); - break; - case 'adjustWearable': - if(message.properties.localRotationAngles) { - message.properties.localRotation = Quat.fromVec3Degrees(message.properties.localRotationAngles); - } - - Entities.editEntity(message.entityID, message.properties); - message.properties = Entities.getEntityProperties(message.entityID, Object.keys(message.properties)); - - if(message.properties.localRotation) { - message.properties.localRotationAngles = Quat.safeEulerAngles(message.properties.localRotation); - } - - sendToQml({'method' : 'wearableUpdated', 'entityID' : message.entityID, wearableIndex : message.wearableIndex, properties : message.properties, updateUI : false}); - break; - case 'adjustWearablesOpened': - currentAvatarWearablesBackup = getMyAvatarWearables(); - adjustWearables.setOpened(true); - unfreezeWearables(); - - Entities.mousePressOnEntity.connect(onSelectedEntity); - Messages.subscribe('Hifi-Object-Manipulation'); - Messages.messageReceived.connect(handleWearableMessages); - break; - case 'adjustWearablesClosed': - if(!message.save) { - // revert changes using snapshot of wearables - if(currentAvatarWearablesBackup !== null) { - AvatarBookmarks.updateAvatarEntities(currentAvatarWearablesBackup); - updateAvatarWearables(currentAvatar, null, currentAvatarWearablesBackup); - } - } else { - sendToQml({'method' : 'updateAvatarInBookmarks'}); - } - - adjustWearables.setOpened(false); - ensureWearableSelected(null); - Entities.mousePressOnEntity.disconnect(onSelectedEntity); - Messages.messageReceived.disconnect(handleWearableMessages); - Messages.unsubscribe('Hifi-Object-Manipulation'); - break; - case 'addWearable': - - var joints = MyAvatar.getJointNames(); - var hipsIndex = -1; - - for(var i = 0; i < joints.length; ++i) { - if(joints[i] === 'Hips') { - hipsIndex = i; - break; - } - } - - var properties = { - name: "Custom wearable", - type: "Model", - modelURL: message.url, - parentID: MyAvatar.sessionUUID, - relayParentJoints: false, - parentJointIndex: hipsIndex - }; - - Entities.addingWearable.disconnect(onAddingWearable); - var entityID = Entities.addEntity(properties, true); - Entities.addingWearable.connect(onAddingWearable); - - updateAvatarWearables(currentAvatar, function() { - onSelectedEntity(entityID); - }); - break; - case 'selectWearable': - ensureWearableSelected(message.entityID); - break; - case 'deleteWearable': - - Entities.deletingWearable.disconnect(onDeletingWearable); - Entities.deleteEntity(message.entityID); - Entities.deletingWearable.connect(onDeletingWearable); - - updateAvatarWearables(currentAvatar); - break; - case 'changeDisplayName': - if (MyAvatar.displayName !== message.displayName) { - MyAvatar.displayName = message.displayName; - UserActivityLogger.palAction("display_name_change", message.displayName); - } - break; - case 'applyExternalAvatar': - var currentAvatarURL = MyAvatar.getFullAvatarURLFromPreferences(); - if(currentAvatarURL !== message.avatarURL) { - MyAvatar.useFullAvatarURL(message.avatarURL); - sendToQml({'method' : 'externalAvatarApplied', 'avatarURL' : message.avatarURL}); - } - break; - case 'navigate': - var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); - if(message.url.indexOf('app://') === 0) { - if (message.url === 'app://marketplace') { - tablet.gotoWebScreen(MARKETPLACE_URL, MARKETPLACES_INJECT_SCRIPT_URL); - } else if (message.url === 'app://purchases') { - tablet.pushOntoStack(MARKETPLACE_PURCHASES_QML_PATH); - } - - } else if(message.url.indexOf('hifi://') === 0) { - AddressManager.handleLookupString(message.url, false); - } else if(message.url.indexOf('https://') === 0 || message.url.indexOf('http://') === 0) { - tablet.gotoWebScreen(message.url, MARKETPLACES_INJECT_SCRIPT_URL); - } - - break; - case 'setScale': - notifyScaleChanged = false; - MyAvatar.setAvatarScale(message.avatarScale); - currentAvatar.avatarScale = message.avatarScale; - notifyScaleChanged = true; - break; - case 'revertScale': - MyAvatar.setAvatarScale(message.avatarScale); - currentAvatar.avatarScale = message.avatarScale; - break; - case 'saveSettings': - MyAvatar.setAvatarScale(message.avatarScale); - currentAvatar.avatarScale = message.avatarScale; - - MyAvatar.setDominantHand(message.settings.dominantHand); - MyAvatar.setHmdAvatarAlignmentType(message.settings.hmdAvatarAlignmentType); - MyAvatar.setOtherAvatarsCollisionsEnabled(message.settings.otherAvatarsCollisionsEnabled); - MyAvatar.setCollisionsEnabled(message.settings.collisionsEnabled); - MyAvatar.collisionSoundURL = message.settings.collisionSoundUrl; - MyAvatar.setAnimGraphOverrideUrl(message.settings.animGraphOverrideUrl); - - currentAvatarSettings = getMyAvatarSettings(); - break; - case 'toggleWearablesFrozen': - var wearablesFrozen = getWearablesFrozen(); - wearablesFrozen = !wearablesFrozen; - if (wearablesFrozen) { - freezeWearables(); - } else { - unfreezeWearables(); - } - sendToQml({'method' : 'wearablesFrozenChanged', 'wearablesFrozen' : wearablesFrozen}); - break; - default: - print('Unrecognized message from AvatarApp.qml'); - } -} - -function isGrabbable(entityID) { - if(entityID === null) { - return false; - } - - var properties = Entities.getEntityProperties(entityID, ['avatarEntity', 'grab.grabbable']); - if (properties.avatarEntity) { - return properties.grab.grabbable; - } - - return false; -} - -function setGrabbable(entityID, grabbable) { - var properties = Entities.getEntityProperties(entityID, ['avatarEntity', 'grab.grabbable']); - if (properties.avatarEntity && properties.grab.grabbable != grabbable) { - var editProps = { grab: { grabbable: grabbable }}; - Entities.editEntity(entityID, editProps); - sendToQml({ 'method' : 'wearablesFrozenChanged', 'wearablesFrozen' : getWearablesFrozen()}); - } -} - -function ensureWearableSelected(entityID) { - if(selectedAvatarEntityID !== entityID) { - if(grabbedAvatarEntityChangeNotifier !== null) { - Script.clearInterval(grabbedAvatarEntityChangeNotifier); - grabbedAvatarEntityChangeNotifier = null; - } - selectedAvatarEntityID = entityID; - return true; - } - - return false; -} - -function isEntityBeingWorn(entityID) { - return Entities.getEntityProperties(entityID, 'parentID').parentID === MyAvatar.sessionUUID; -} - -function onSelectedEntity(entityID, pointerEvent) { - if(selectedAvatarEntityID !== entityID && isEntityBeingWorn(entityID)) - { - if(ensureWearableSelected(entityID)) { - sendToQml({'method' : 'selectAvatarEntity', 'entityID' : selectedAvatarEntityID}); - } - } -} - -function onAddingWearable(entityID) { - updateAvatarWearables(currentAvatar, function() { - sendToQml({'method' : 'updateAvatarInBookmarks'}); - }); - sendToQml({ 'method' : 'wearablesFrozenChanged', 'wearablesFrozen' : getWearablesFrozen()}); -} - -function onDeletingWearable(entityID) { - updateAvatarWearables(currentAvatar, function() { - sendToQml({'method' : 'updateAvatarInBookmarks'}); - }); - sendToQml({ 'method' : 'wearablesFrozenChanged', 'wearablesFrozen' : getWearablesFrozen()}); -} - -function handleWearableMessages(channel, message, sender) { - if (channel !== 'Hifi-Object-Manipulation') { - return; - } - - var parsedMessage = null; - - try { - parsedMessage = JSON.parse(message); - } catch (e) { - return; - } - - var entityID = parsedMessage.grabbedEntity; - - var updateWearable = function() { - // for some reasons Entities.getEntityProperties returns more than was asked.. - var propertyNames = ['localPosition', 'localRotation', 'dimensions', 'naturalDimensions']; - var entityProperties = Entities.getEntityProperties(selectedAvatarEntityID, propertyNames); - var properties = {}; - - propertyNames.forEach(function(propertyName) { - properties[propertyName] = entityProperties[propertyName]; - }); - - properties.localRotationAngles = Quat.safeEulerAngles(properties.localRotation); - sendToQml({'method' : 'wearableUpdated', 'entityID' : selectedAvatarEntityID, - 'wearableIndex' : -1, 'properties' : properties, updateUI : true}); - - }; - - if(parsedMessage.action === 'grab') { - if(selectedAvatarEntityID !== entityID) { - ensureWearableSelected(entityID); - sendToQml({'method' : 'selectAvatarEntity', 'entityID' : selectedAvatarEntityID}); - } - - grabbedAvatarEntityChangeNotifier = Script.setInterval(updateWearable, 1000); - } else if(parsedMessage.action === 'release') { - if(grabbedAvatarEntityChangeNotifier !== null) { - Script.clearInterval(grabbedAvatarEntityChangeNotifier); - grabbedAvatarEntityChangeNotifier = null; - updateWearable(); - } - } -} - -function sendToQml(message) { - tablet.sendToQml(message); -} - -function onBookmarkLoaded(bookmarkName) { - executeLater(function() { - currentAvatar = getMyAvatar(); - sendToQml({'method' : 'bookmarkLoaded', 'data' : {'name' : bookmarkName, 'currentAvatar' : currentAvatar} }); - }); -} - -function onBookmarkDeleted(bookmarkName) { - sendToQml({'method' : 'bookmarkDeleted', 'name' : bookmarkName}); -} - -function onBookmarkAdded(bookmarkName) { - var bookmark = AvatarBookmarks.getBookmark(bookmarkName); - bookmark.avatarEntites.forEach(function(avatarEntity) { - avatarEntity.properties.localRotationAngles = Quat.safeEulerAngles(avatarEntity.properties.localRotation); - }); - - sendToQml({ 'method': 'bookmarkAdded', 'bookmarkName': bookmarkName, 'bookmark': bookmark }); -} - -// -// Manage the connection between the button and the window. -// -var button; -var buttonName = "AVATAR"; -var tablet = null; - -function startup() { - tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); - button = tablet.addButton({ - text: buttonName, - icon: "icons/tablet-icons/avatar-i.svg", - activeIcon: "icons/tablet-icons/avatar-a.svg", - sortOrder: 7 - }); - button.clicked.connect(onTabletButtonClicked); - tablet.screenChanged.connect(onTabletScreenChanged); -} - -startup(); - -var isWired = false; -function off() { - if(adjustWearables.opened) { - adjustWearables.setOpened(false); - ensureWearableSelected(null); - Entities.mousePressOnEntity.disconnect(onSelectedEntity); - - Messages.messageReceived.disconnect(handleWearableMessages); - Messages.unsubscribe('Hifi-Object-Manipulation'); - } - - if (isWired) { // It is not ok to disconnect these twice, hence guard. - isWired = false; - - AvatarBookmarks.bookmarkLoaded.disconnect(onBookmarkLoaded); - AvatarBookmarks.bookmarkDeleted.disconnect(onBookmarkDeleted); - AvatarBookmarks.bookmarkAdded.disconnect(onBookmarkAdded); - - Entities.addingWearable.disconnect(onAddingWearable); - Entities.deletingWearable.disconnect(onDeletingWearable); - MyAvatar.skeletonModelURLChanged.disconnect(onSkeletonModelURLChanged); - MyAvatar.dominantHandChanged.disconnect(onDominantHandChanged); - MyAvatar.hmdAvatarAlignmentTypeChanged.disconnect(onHmdAvatarAlignmentTypeChanged); - MyAvatar.collisionsEnabledChanged.disconnect(onCollisionsEnabledChanged); - MyAvatar.otherAvatarsCollisionsEnabledChanged.disconnect(onOtherAvatarsCollisionsEnabledChanged); - MyAvatar.newCollisionSoundURL.disconnect(onNewCollisionSoundUrl); - MyAvatar.animGraphUrlChanged.disconnect(onAnimGraphUrlChanged); - MyAvatar.targetScaleChanged.disconnect(onTargetScaleChanged); - } -} - -function on() { - - if (!isWired) { // It is not ok to connect these twice, hence guard. - isWired = true; - - AvatarBookmarks.bookmarkLoaded.connect(onBookmarkLoaded); - AvatarBookmarks.bookmarkDeleted.connect(onBookmarkDeleted); - AvatarBookmarks.bookmarkAdded.connect(onBookmarkAdded); - - Entities.addingWearable.connect(onAddingWearable); - Entities.deletingWearable.connect(onDeletingWearable); - MyAvatar.skeletonModelURLChanged.connect(onSkeletonModelURLChanged); - MyAvatar.dominantHandChanged.connect(onDominantHandChanged); - MyAvatar.hmdAvatarAlignmentTypeChanged.connect(onHmdAvatarAlignmentTypeChanged); - MyAvatar.collisionsEnabledChanged.connect(onCollisionsEnabledChanged); - MyAvatar.otherAvatarsCollisionsEnabledChanged.connect(onOtherAvatarsCollisionsEnabledChanged); - MyAvatar.newCollisionSoundURL.connect(onNewCollisionSoundUrl); - MyAvatar.animGraphUrlChanged.connect(onAnimGraphUrlChanged); - MyAvatar.targetScaleChanged.connect(onTargetScaleChanged); - } -} - -function onTabletButtonClicked() { - if (onAvatarAppScreen) { - // for toolbar-mode: go back to home screen, this will close the window. - tablet.gotoHomeScreen(); - } else { - ContextOverlay.enabled = false; - tablet.loadQMLSource(AVATARAPP_QML_SOURCE); - } -} -var hasEventBridge = false; -function wireEventBridge(on) { - if (on) { - if (!hasEventBridge) { - tablet.fromQml.connect(fromQml); - hasEventBridge = true; - } - } else { - if (hasEventBridge) { - tablet.fromQml.disconnect(fromQml); - hasEventBridge = false; - } - } -} - -var onAvatarAppScreen = false; -function onTabletScreenChanged(type, url) { - var onAvatarAppScreenNow = (type === "QML" && url === AVATARAPP_QML_SOURCE); - wireEventBridge(onAvatarAppScreenNow); - // for toolbar mode: change button to active when window is first openend, false otherwise. - button.editProperties({isActive: onAvatarAppScreenNow}); - - if (!onAvatarAppScreen && onAvatarAppScreenNow) { - on(); - } else if(onAvatarAppScreen && !onAvatarAppScreenNow) { - off(); - } - - onAvatarAppScreen = onAvatarAppScreenNow; - - if(onAvatarAppScreenNow) { - sendToQml({ 'method' : 'initialize', 'data' : { jointNames : MyAvatar.getJointNames() }}); - sendToQml({ 'method' : 'wearablesFrozenChanged', 'wearablesFrozen' : getWearablesFrozen()}); - } -} - -function shutdown() { - if (onAvatarAppScreen) { - tablet.gotoHomeScreen(); - } - button.clicked.disconnect(onTabletButtonClicked); - tablet.removeButton(button); - tablet.screenChanged.disconnect(onTabletScreenChanged); - - off(); -} - -// -// Cleanup. -// -Script.scriptEnding.connect(shutdown); - -}()); // END LOCAL_SCOPE diff --git a/scripts/simplifiedUI/system/away.js b/scripts/simplifiedUI/system/away.js deleted file mode 100644 index 6293c0c452..0000000000 --- a/scripts/simplifiedUI/system/away.js +++ /dev/null @@ -1,387 +0,0 @@ -"use strict"; - -// -// away.js -// -// examples -// -// Created by Howard Stearns 11/3/15 -// Copyright 2015 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// -// Goes into "paused" when the '.' key (and automatically when started in HMD), and normal when pressing any key. -// See MAIN CONTROL, below, for what "paused" actually does. - -/* eslint indent: ["error", 4, { "outerIIFEBody": 0 }] */ - -(function() { // BEGIN LOCAL_SCOPE - -var BASIC_TIMER_INTERVAL = 50; // 50ms = 20hz -var OVERLAY_WIDTH = 1920; -var OVERLAY_HEIGHT = 1080; -var OVERLAY_DATA = { - width: OVERLAY_WIDTH, - height: OVERLAY_HEIGHT, - imageURL: Script.resolvePath("assets/images/Overlay-Viz-blank.png"), - emissive: true, - drawInFront: true, - alpha: 1 -}; -var AVATAR_MOVE_FOR_ACTIVE_DISTANCE = 0.8; // meters -- no longer away if avatar moves this far while away - -var CAMERA_MATRIX = -7; - -var OVERLAY_DATA_HMD = { - localPosition: {x: 0, y: 0, z: -1 * MyAvatar.sensorToWorldScale}, - localRotation: {x: 0, y: 0, z: 0, w: 1}, - width: OVERLAY_WIDTH, - height: OVERLAY_HEIGHT, - url: Script.resolvePath("assets/images/Overlay-Viz-blank.png"), - color: {red: 255, green: 255, blue: 255}, - alpha: 1, - scale: 2 * MyAvatar.sensorToWorldScale, - emissive: true, - drawInFront: true, - parentID: MyAvatar.SELF_ID, - parentJointIndex: CAMERA_MATRIX, - ignorePickIntersection: true -}; - -var AWAY_INTRO = { - url: "http://hifi-content.s3.amazonaws.com/ozan/dev/anim/standard_anims_160127/kneel.fbx", - playbackRate: 30.0, - loopFlag: false, - startFrame: 0.0, - endFrame: 83.0 -}; - -// MAIN CONTROL -var isEnabled = true; -var wasMuted; // unknonwn? -var isAway = false; // we start in the un-away state -var eventMappingName = "io.highfidelity.away"; // goActive on hand controller button events, too. -var eventMapping = Controller.newMapping(eventMappingName); -var avatarPosition = MyAvatar.position; -var wasHmdMounted = HMD.mounted; -var previousBubbleState = Users.getIgnoreRadiusEnabled(); - -var enterAwayStateWhenFocusLostInVR = HMD.enterAwayStateWhenFocusLostInVR; - -// some intervals we may create/delete -var avatarMovedInterval; - - -// prefetch the kneel animation and hold a ref so it's always resident in memory when we need it. -var _animation = AnimationCache.prefetch(AWAY_INTRO.url); - -function playAwayAnimation() { - MyAvatar.overrideAnimation(AWAY_INTRO.url, - AWAY_INTRO.playbackRate, - AWAY_INTRO.loopFlag, - AWAY_INTRO.startFrame, - AWAY_INTRO.endFrame); -} - -function stopAwayAnimation() { - MyAvatar.restoreAnimation(); -} - -// OVERLAY -var overlay = Overlays.addOverlay("image", OVERLAY_DATA); -var overlayHMD = Overlays.addOverlay("image3d", OVERLAY_DATA_HMD); - -function showOverlay() { - if (HMD.active) { - // make sure desktop version is hidden - Overlays.editOverlay(overlay, { visible: false }); - Overlays.editOverlay(overlayHMD, { visible: true }); - } else { - // make sure HMD is hidden - Overlays.editOverlay(overlayHMD, { visible: false }); - - // Update for current screen size, keeping overlay proportions constant. - var screen = Controller.getViewportDimensions(); - - // keep the overlay it's natural size and always center it... - Overlays.editOverlay(overlay, { - visible: true, - x: ((screen.x - OVERLAY_WIDTH) / 2), - y: ((screen.y - OVERLAY_HEIGHT) / 2) - }); - } -} - -function hideOverlay() { - Overlays.editOverlay(overlay, {visible: false}); - Overlays.editOverlay(overlayHMD, {visible: false}); -} - -hideOverlay(); - -function maybeMoveOverlay() { - if (isAway) { - // if we switched from HMD to Desktop, make sure to hide our HUD overlay and show the - // desktop overlay - if (!HMD.active) { - showOverlay(); // this will also recenter appropriately - } - - if (HMD.active) { - - var sensorScaleFactor = MyAvatar.sensorToWorldScale; - var localPosition = {x: 0, y: 0, z: -1 * sensorScaleFactor}; - Overlays.editOverlay(overlayHMD, { visible: true, localPosition: localPosition, scale: 2 * sensorScaleFactor }); - - // make sure desktop version is hidden - Overlays.editOverlay(overlay, { visible: false }); - - // also remember avatar position - avatarPosition = MyAvatar.position; - - } - } -} - -function ifAvatarMovedGoActive() { - var newAvatarPosition = MyAvatar.position; - if (Vec3.distance(newAvatarPosition, avatarPosition) > AVATAR_MOVE_FOR_ACTIVE_DISTANCE) { - goActive(); - } - avatarPosition = newAvatarPosition; -} - -function goAway(fromStartup) { - if (!isEnabled || isAway) { - return; - } - - // If we're entering away mode from some other state than startup, then we create our move timer immediately. - // However if we're just stating up, we need to delay this process so that we don't think the initial teleport - // is actually a move. - if (fromStartup === undefined || fromStartup === false) { - avatarMovedInterval = Script.setInterval(ifAvatarMovedGoActive, BASIC_TIMER_INTERVAL); - } else { - var WAIT_FOR_MOVE_ON_STARTUP = 3000; // 3 seconds - Script.setTimeout(function() { - avatarMovedInterval = Script.setInterval(ifAvatarMovedGoActive, BASIC_TIMER_INTERVAL); - }, WAIT_FOR_MOVE_ON_STARTUP); - } - - previousBubbleState = Users.getIgnoreRadiusEnabled(); - if (!previousBubbleState) { - Users.toggleIgnoreRadius(); - } - UserActivityLogger.privacyShieldToggled(Users.getIgnoreRadiusEnabled()); - UserActivityLogger.toggledAway(true); - MyAvatar.isAway = true; -} - -function goActive() { - if (!isAway) { - return; - } - - UserActivityLogger.toggledAway(false); - MyAvatar.isAway = false; - - if (Users.getIgnoreRadiusEnabled() !== previousBubbleState) { - Users.toggleIgnoreRadius(); - UserActivityLogger.privacyShieldToggled(Users.getIgnoreRadiusEnabled()); - } - - if (!Window.hasFocus()) { - Window.setFocus(); - } -} - -MyAvatar.wentAway.connect(setAwayProperties); -MyAvatar.wentActive.connect(setActiveProperties); - -function setAwayProperties() { - isAway = true; - wasMuted = Audio.muted; - if (!wasMuted) { - Audio.muted = !Audio.muted; - } - MyAvatar.setEnableMeshVisible(false); // just for our own display, without changing point of view - playAwayAnimation(); // animation is still seen by others - showOverlay(); - - HMD.requestShowHandControllers(); - - // tell the Reticle, we want to stop capturing the mouse until we come back - Reticle.allowMouseCapture = false; - // Allow users to find their way to other applications, our menus, etc. - // For desktop, that means we want the reticle visible. - // For HMD, the hmd preview will show the system mouse because of allowMouseCapture, - // but we want to turn off our Reticle so that we don't get two in preview and a stuck one in headset. - Reticle.visible = !HMD.active; - wasHmdMounted = HMD.mounted; // always remember the correct state - - avatarPosition = MyAvatar.position; -} - -function setActiveProperties() { - isAway = false; - if (Audio.muted && !wasMuted) { - Audio.muted = false; - } - MyAvatar.setEnableMeshVisible(true); // IWBNI we respected Developer->Avatar->Draw Mesh setting. - stopAwayAnimation(); - - HMD.requestHideHandControllers(); - - // update the UI sphere to be centered about the current HMD orientation. - HMD.centerUI(); - - // forget about any IK joint limits - MyAvatar.clearIKJointLimitHistory(); - - // update the avatar hips to point in the same direction as the HMD orientation. - MyAvatar.centerBody(); - - hideOverlay(); - - // tell the Reticle, we are ready to capture the mouse again and it should be visible - Reticle.allowMouseCapture = true; - Reticle.visible = true; - if (HMD.active) { - Reticle.position = HMD.getHUDLookAtPosition2D(); - } - wasHmdMounted = HMD.mounted; // always remember the correct state - - Script.clearInterval(avatarMovedInterval); -} - -function maybeGoActive(event) { - if (event.isAutoRepeat) { // isAutoRepeat is true when held down (or when Windows feels like it) - return; - } - if (!isAway && (event.text === 'ESC')) { - goAway(); - } else { - goActive(); - } -} - -var wasHmdActive = HMD.active; -var wasMouseCaptured = Reticle.mouseCaptured; - -function maybeGoAway() { - // If our active state change (went to or from HMD mode), and we are now in the HMD, go into away - if (HMD.active !== wasHmdActive) { - wasHmdActive = !wasHmdActive; - if (wasHmdActive) { - goAway(); - return; - } - } - - // If the mouse has gone from captured, to non-captured state, then it likely means the person is still in the HMD, - // but tabbed away from the application (meaning they don't have mouse control) and they likely want to go into - // an away state - if (Reticle.mouseCaptured !== wasMouseCaptured) { - wasMouseCaptured = !wasMouseCaptured; - if (!wasMouseCaptured) { - if (enterAwayStateWhenFocusLostInVR) { - goAway(); - return; - } - } - } - - // If you've removed your HMD from your head, and we can detect it, we will also go away... - if (HMD.mounted !== wasHmdMounted) { - wasHmdMounted = HMD.mounted; - print("HMD mounted changed..."); - - // We're putting the HMD on... switch to those devices - if (HMD.mounted) { - print("NOW mounted..."); - } else { - print("HMD NOW un-mounted..."); - - if (HMD.active) { - goAway(); - return; - } - } - } -} - -function setEnabled(value) { - if (!value) { - goActive(); - } - isEnabled = value; -} - -function checkAudioToggled() { - if (isAway && !Audio.muted) { - goActive(); - } -} - - -var CHANNEL_AWAY_ENABLE = "Hifi-Away-Enable"; -var handleMessage = function(channel, message, sender) { - if (channel === CHANNEL_AWAY_ENABLE && sender === MyAvatar.sessionUUID) { - print("away.js | Got message on Hifi-Away-Enable: ", message); - setEnabled(message === 'enable'); - } -}; -Messages.subscribe(CHANNEL_AWAY_ENABLE); -Messages.messageReceived.connect(handleMessage); - -var maybeIntervalTimer = Script.setInterval(function() { - maybeMoveOverlay(); - maybeGoAway(); - checkAudioToggled(); -}, BASIC_TIMER_INTERVAL); - - -Controller.mousePressEvent.connect(goActive); -Controller.keyPressEvent.connect(maybeGoActive); -// Note peek() so as to not interfere with other mappings. -eventMapping.from(Controller.Standard.LeftPrimaryThumb).peek().to(goActive); -eventMapping.from(Controller.Standard.RightPrimaryThumb).peek().to(goActive); -eventMapping.from(Controller.Standard.LeftSecondaryThumb).peek().to(goActive); -eventMapping.from(Controller.Standard.RightSecondaryThumb).peek().to(goActive); -eventMapping.from(Controller.Standard.LT).peek().to(goActive); -eventMapping.from(Controller.Standard.LB).peek().to(goActive); -eventMapping.from(Controller.Standard.LS).peek().to(goActive); -eventMapping.from(Controller.Standard.LeftGrip).peek().to(goActive); -eventMapping.from(Controller.Standard.RT).peek().to(goActive); -eventMapping.from(Controller.Standard.RB).peek().to(goActive); -eventMapping.from(Controller.Standard.RS).peek().to(goActive); -eventMapping.from(Controller.Standard.RightGrip).peek().to(goActive); -eventMapping.from(Controller.Standard.Back).peek().to(goActive); -eventMapping.from(Controller.Standard.Start).peek().to(goActive); -Controller.enableMapping(eventMappingName); - -function awayStateWhenFocusLostInVRChanged(enabled) { - enterAwayStateWhenFocusLostInVR = enabled; -} - -Script.scriptEnding.connect(function () { - Script.clearInterval(maybeIntervalTimer); - goActive(); - HMD.awayStateWhenFocusLostInVRChanged.disconnect(awayStateWhenFocusLostInVRChanged); - Controller.disableMapping(eventMappingName); - Controller.mousePressEvent.disconnect(goActive); - Controller.keyPressEvent.disconnect(maybeGoActive); - Messages.messageReceived.disconnect(handleMessage); - Messages.unsubscribe(CHANNEL_AWAY_ENABLE); -}); - -HMD.awayStateWhenFocusLostInVRChanged.connect(awayStateWhenFocusLostInVRChanged); - -if (HMD.active && !HMD.mounted) { - print("Starting script, while HMD is active and not mounted..."); - goAway(true); -} - - -}()); // END LOCAL_SCOPE diff --git a/scripts/simplifiedUI/system/bubble.js b/scripts/simplifiedUI/system/bubble.js deleted file mode 100644 index eca3b3dcd4..0000000000 --- a/scripts/simplifiedUI/system/bubble.js +++ /dev/null @@ -1,206 +0,0 @@ -"use strict"; - -// -// bubble.js -// scripts/system/ -// -// Created by Brad Hefta-Gaub on 11/18/2016 -// Copyright 2016 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// -/* global Script, Users, Overlays, AvatarList, Controller, Camera, getControllerWorldLocation, UserActivityLogger */ - -(function () { // BEGIN LOCAL_SCOPE - var button; - // Used for animating and disappearing the bubble - var bubbleOverlayTimestamp; - // Used for rate limiting the bubble sound - var lastBubbleSoundTimestamp = 0; - // Affects bubble height - var BUBBLE_HEIGHT_SCALE = 0.15; - // The bubble model itself - var bubbleOverlay = Overlays.addOverlay("model", { - url: Script.resolvePath("assets/models/Bubble-v14.fbx"), // If you'd like to change the model, modify this line (and the dimensions below) - dimensions: { x: MyAvatar.sensorToWorldScale, y: 0.75 * MyAvatar.sensorToWorldScale, z: MyAvatar.sensorToWorldScale }, - position: { x: MyAvatar.position.x, y: -MyAvatar.scale * 2 + MyAvatar.position.y + MyAvatar.scale * BUBBLE_HEIGHT_SCALE, z: MyAvatar.position.z }, - rotation: Quat.multiply(MyAvatar.orientation, Quat.fromVec3Degrees({x: 0.0, y: 180.0, z: 0.0})), - scale: { x: 2 , y: MyAvatar.scale * 0.5 + 0.5, z: 2 }, - visible: false, - ignoreRayIntersection: true - }); - // The bubble activation sound - var bubbleActivateSound = SoundCache.getSound(Script.resolvePath("assets/sounds/bubble.wav")); - // Is the update() function connected? - var updateConnected = false; - - var BUBBLE_VISIBLE_DURATION_MS = 3000; - var BUBBLE_RAISE_ANIMATION_DURATION_MS = 750; - var BUBBLE_SOUND_RATE_LIMIT_MS = 15000; - - // Hides the bubble model overlay - function hideOverlays() { - Overlays.editOverlay(bubbleOverlay, { - visible: false - }); - } - - // Make the bubble overlay visible, set its position, and play the sound - function createOverlays() { - var nowTimestamp = Date.now(); - if (nowTimestamp - lastBubbleSoundTimestamp >= BUBBLE_SOUND_RATE_LIMIT_MS) { - Audio.playSound(bubbleActivateSound, { - position: { x: MyAvatar.position.x, y: MyAvatar.position.y, z: MyAvatar.position.z }, - localOnly: true, - volume: 0.2 - }); - lastBubbleSoundTimestamp = nowTimestamp; - } - hideOverlays(); - if (updateConnected === true) { - updateConnected = false; - Script.update.disconnect(update); - } - - Overlays.editOverlay(bubbleOverlay, { - dimensions: { - x: MyAvatar.sensorToWorldScale, - y: 0.75 * MyAvatar.sensorToWorldScale, - z: MyAvatar.sensorToWorldScale - }, - position: { - x: MyAvatar.position.x, - y: -MyAvatar.scale * 2 + MyAvatar.position.y + MyAvatar.scale * BUBBLE_HEIGHT_SCALE, - z: MyAvatar.position.z - }, - rotation: Quat.multiply(MyAvatar.orientation, Quat.fromVec3Degrees({x: 0.0, y: 180.0, z: 0.0})), - scale: { - x: 2 , - y: MyAvatar.scale * 0.5 + 0.5 , - z: 2 - }, - visible: true - }); - bubbleOverlayTimestamp = nowTimestamp; - Script.update.connect(update); - updateConnected = true; - } - - // Called from the C++ scripting interface to show the bubble overlay - function enteredIgnoreRadius() { - createOverlays(); - UserActivityLogger.privacyShieldActivated(); - } - - // Used to set the state of the bubble HUD button - function writeButtonProperties(parameter) { - button.editProperties({isActive: parameter}); - } - - // The bubble script's update function - function update() { - var timestamp = Date.now(); - var delay = (timestamp - bubbleOverlayTimestamp); - var overlayAlpha = 1.0 - (delay / BUBBLE_VISIBLE_DURATION_MS); - if (overlayAlpha > 0) { - if (delay < BUBBLE_RAISE_ANIMATION_DURATION_MS) { - Overlays.editOverlay(bubbleOverlay, { - dimensions: { - x: MyAvatar.sensorToWorldScale, - y: 0.75 * MyAvatar.sensorToWorldScale, - z: MyAvatar.sensorToWorldScale - }, - // Quickly raise the bubble from the ground up - position: { - x: MyAvatar.position.x, - y: (-((BUBBLE_RAISE_ANIMATION_DURATION_MS - delay) / BUBBLE_RAISE_ANIMATION_DURATION_MS)) * MyAvatar.scale * 2 + MyAvatar.position.y + MyAvatar.scale * BUBBLE_HEIGHT_SCALE, - z: MyAvatar.position.z - }, - rotation: Quat.multiply(MyAvatar.orientation, Quat.fromVec3Degrees({x: 0.0, y: 180.0, z: 0.0})), - scale: { - x: 2 , - y: ((1 - ((BUBBLE_RAISE_ANIMATION_DURATION_MS - delay) / BUBBLE_RAISE_ANIMATION_DURATION_MS)) * MyAvatar.scale * 0.5 + 0.5), - z: 2 - } - }); - } else { - // Keep the bubble in place for a couple seconds - Overlays.editOverlay(bubbleOverlay, { - dimensions: { - x: MyAvatar.sensorToWorldScale, - y: 0.75 * MyAvatar.sensorToWorldScale, - z: MyAvatar.sensorToWorldScale - }, - position: { - x: MyAvatar.position.x, - y: MyAvatar.position.y + MyAvatar.scale * BUBBLE_HEIGHT_SCALE, - z: MyAvatar.position.z - }, - rotation: Quat.multiply(MyAvatar.orientation, Quat.fromVec3Degrees({x: 0.0, y: 180.0, z: 0.0})), - scale: { - x: 2, - y: MyAvatar.scale * 0.5 + 0.5 , - z: 2 - } - }); - } - } else { - hideOverlays(); - if (updateConnected === true) { - Script.update.disconnect(update); - updateConnected = false; - } - } - } - - // When the space bubble is toggled... - // NOTE: the c++ calls this with just the first param -- we added a second - // just for not logging the initial state of the bubble when we startup. - function onBubbleToggled(enabled, doNotLog) { - writeButtonProperties(enabled); - if (doNotLog !== true) { - UserActivityLogger.privacyShieldToggled(enabled); - } - if (enabled) { - createOverlays(); - } else { - hideOverlays(); - if (updateConnected === true) { - Script.update.disconnect(update); - updateConnected = false; - } - } - } - - // Setup the bubble button - var buttonName = "SHIELD"; - var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); - button = tablet.addButton({ - icon: "icons/tablet-icons/bubble-i.svg", - activeIcon: "icons/tablet-icons/bubble-a.svg", - text: buttonName, - sortOrder: 4 - }); - - onBubbleToggled(Users.getIgnoreRadiusEnabled(), true); // pass in true so we don't log this initial one in the UserActivity table - - button.clicked.connect(Users.toggleIgnoreRadius); - Users.ignoreRadiusEnabledChanged.connect(onBubbleToggled); - Users.enteredIgnoreRadius.connect(enteredIgnoreRadius); - - // Cleanup the tablet button and overlays when script is stopped - Script.scriptEnding.connect(function () { - button.clicked.disconnect(Users.toggleIgnoreRadius); - if (tablet) { - tablet.removeButton(button); - } - Users.ignoreRadiusEnabledChanged.disconnect(onBubbleToggled); - Users.enteredIgnoreRadius.disconnect(enteredIgnoreRadius); - Overlays.deleteOverlay(bubbleOverlay); - if (updateConnected === true) { - Script.update.disconnect(update); - } - }); - -}()); // END LOCAL_SCOPE diff --git a/scripts/simplifiedUI/system/chat.js b/scripts/simplifiedUI/system/chat.js deleted file mode 100644 index 749665f3d8..0000000000 --- a/scripts/simplifiedUI/system/chat.js +++ /dev/null @@ -1,1010 +0,0 @@ -"use strict"; - -// Chat.js -// By Don Hopkins (dhopkins@donhopkins.com) -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -(function() { - - var webPageURL = Script.resolvePath("html/ChatPage.html"); // URL of tablet web page. - var randomizeWebPageURL = true; // Set to true for debugging. - var lastWebPageURL = ""; // Last random URL of tablet web page. - var onChatPage = false; // True when chat web page is opened. - var webHandlerConnected = false; // True when the web handler has been connected. - var channelName = "Chat"; // Unique name for channel that we listen to. - var tabletButtonName = "CHAT"; // Tablet button label. - var tabletButtonIcon = "icons/tablet-icons/menu-i.svg"; // Icon for chat button. - var tabletButtonActiveIcon = "icons/tablet-icons/menu-a.svg"; // Active icon for chat button. - var tabletButton = null; // The button we create in the tablet. - var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); // The awesome tablet. - var chatLog = []; // Array of chat messages in the form of [avatarID, displayName, message, data]. - var avatarIdentifiers = {}; // Map of avatar ids to dict of identifierParams. - var speechBubbleShowing = false; // Is the speech bubble visible? - var speechBubbleMessage = null; // The message shown in the speech bubble. - var speechBubbleData = null; // The data of the speech bubble message. - var speechBubbleTextID = null; // The id of the speech bubble local text entity. - var speechBubbleTimer = null; // The timer to pop down the speech bubble. - var speechBubbleParams = null; // The params used to create or edit the speech bubble. - - // Persistent variables saved in the Settings. - var chatName = ''; // The user's name shown in chat. - var chatLogMaxSize = 100; // The maximum number of chat messages we remember. - var sendTyping = true; // Send typing begin and end notification. - var identifyAvatarDuration = 10; // How long to leave the avatar identity line up, in seconds. - var identifyAvatarLineColor = { red: 0, green: 255, blue: 0 }; // The color of the avatar identity line. - var identifyAvatarMyJointName = 'Head'; // My bone from which to draw the avatar identity line. - var identifyAvatarYourJointName = 'Head'; // Your bone to which to draw the avatar identity line. - var speechBubbleDuration = 10; // How long to leave the speech bubble up, in seconds. - var speechBubbleTextColor = {red: 255, green: 255, blue: 255}; // The text color of the speech bubble. - var speechBubbleBackgroundColor = {red: 0, green: 0, blue: 0}; // The background color of the speech bubble. - var speechBubbleOffset = {x: 0, y: 0.3, z: 0.0}; // The offset from the joint to whic the speech bubble is attached. - var speechBubbleJointName = 'Head'; // The name of the joint to which the speech bubble is attached. - var speechBubbleLineHeight = 0.05; // The height of a line of text in the speech bubble. - var SPEECH_BUBBLE_MAX_WIDTH = 1; // meters - - var textSizeOverlay = Overlays.addOverlay("text3d", { - position: MyAvatar.position, - lineHeight: speechBubbleLineHeight, - leftMargin: 0, - topMargin: 0, - rightMargin: 0, - bottomMargin: 0, - ignoreRayIntersection: true, - visible: false - }); - - // Load the persistent variables from the Settings, with defaults. - function loadSettings() { - chatName = Settings.getValue('Chat_chatName', MyAvatar.displayName); - if (!chatName) { - chatName = randomAvatarName(); - } - chatLogMaxSize = Settings.getValue('Chat_chatLogMaxSize', 100); - sendTyping = Settings.getValue('Chat_sendTyping', true); - identifyAvatarDuration = Settings.getValue('Chat_identifyAvatarDuration', 10); - identifyAvatarLineColor = Settings.getValue('Chat_identifyAvatarLineColor', { red: 0, green: 255, blue: 0 }); - identifyAvatarMyJointName = Settings.getValue('Chat_identifyAvatarMyJointName', 'Head'); - identifyAvatarYourJointName = Settings.getValue('Chat_identifyAvatarYourJointName', 'Head'); - speechBubbleDuration = Settings.getValue('Chat_speechBubbleDuration', 10); - speechBubbleTextColor = Settings.getValue('Chat_speechBubbleTextColor', {red: 255, green: 255, blue: 255}); - speechBubbleBackgroundColor = Settings.getValue('Chat_speechBubbleBackgroundColor', {red: 0, green: 0, blue: 0}); - speechBubbleOffset = Settings.getValue('Chat_speechBubbleOffset', {x: 0.0, y: 0.3, z:0.0}); - speechBubbleJointName = Settings.getValue('Chat_speechBubbleJointName', 'Head'); - speechBubbleLineHeight = Settings.getValue('Chat_speechBubbleLineHeight', 0.05); - Overlays.editOverlay(textSizeOverlay, { - lineHeight: speechBubbleLineHeight - }); - - saveSettings(); - } - - // Save the persistent variables to the Settings. - function saveSettings() { - Settings.setValue('Chat_chatName', chatName); - Settings.setValue('Chat_chatLogMaxSize', chatLogMaxSize); - Settings.setValue('Chat_sendTyping', sendTyping); - Settings.setValue('Chat_identifyAvatarDuration', identifyAvatarDuration); - Settings.setValue('Chat_identifyAvatarLineColor', identifyAvatarLineColor); - Settings.setValue('Chat_identifyAvatarMyJointName', identifyAvatarMyJointName); - Settings.setValue('Chat_identifyAvatarYourJointName', identifyAvatarYourJointName); - Settings.setValue('Chat_speechBubbleDuration', speechBubbleDuration); - Settings.setValue('Chat_speechBubbleTextColor', speechBubbleTextColor); - Settings.setValue('Chat_speechBubbleBackgroundColor', speechBubbleBackgroundColor); - Settings.setValue('Chat_speechBubbleOffset', speechBubbleOffset); - Settings.setValue('Chat_speechBubbleJointName', speechBubbleJointName); - Settings.setValue('Chat_speechBubbleLineHeight', speechBubbleLineHeight); - } - - // Reset the Settings and persistent variables to the defaults. - function resetSettings() { - Settings.setValue('Chat_chatName', null); - Settings.setValue('Chat_chatLogMaxSize', null); - Settings.setValue('Chat_sendTyping', null); - Settings.setValue('Chat_identifyAvatarDuration', null); - Settings.setValue('Chat_identifyAvatarLineColor', null); - Settings.setValue('Chat_identifyAvatarMyJointName', null); - Settings.setValue('Chat_identifyAvatarYourJointName', null); - Settings.setValue('Chat_speechBubbleDuration', null); - Settings.setValue('Chat_speechBubbleTextColor', null); - Settings.setValue('Chat_speechBubbleBackgroundColor', null); - Settings.setValue('Chat_speechBubbleOffset', null); - Settings.setValue('Chat_speechBubbleJointName', null); - Settings.setValue('Chat_speechBubbleLineHeight', null); - - loadSettings(); - } - - // Update anything that might depend on the settings. - function updateSettings() { - updateSpeechBubble(); - trimChatLog(); - updateChatPage(); - } - - // Trim the chat log so it is no longer than chatLogMaxSize lines. - function trimChatLog() { - if (chatLog.length > chatLogMaxSize) { - chatLog.splice(0, chatLogMaxSize - chatLog.length); - } - } - - // Clear the local chat log. - function clearChatLog() { - //print("clearChatLog"); - chatLog = []; - updateChatPage(); - } - - // We got a chat message from the channel. - // Trim the chat log, save the latest message in the chat log, - // and show the message on the tablet, if the chat page is showing. - function handleTransmitChatMessage(avatarID, displayName, message, data) { - //print("receiveChat", "avatarID", avatarID, "displayName", displayName, "message", message, "data", data); - - trimChatLog(); - chatLog.push([avatarID, displayName, message, data]); - - if (onChatPage) { - tablet.emitScriptEvent( - JSON.stringify({ - type: "ReceiveChatMessage", - avatarID: avatarID, - displayName: displayName, - message: message, - data: data - })); - } - } - - // Trim the chat log, save the latest log message in the chat log, - // and show the message on the tablet, if the chat page is showing. - function logMessage(message, data) { - //print("logMessage", message, data); - - trimChatLog(); - chatLog.push([null, null, message, data]); - - if (onChatPage) { - tablet.emitScriptEvent( - JSON.stringify({ - type: "LogMessage", - message: message, - data: data - })); - } - } - - // An empty chat message was entered. - // Hide our speech bubble. - function emptyChatMessage(data) { - popDownSpeechBubble(); - } - - // Notification that we typed a keystroke. - function type() { - //print("type"); - } - - // Notification that we began typing. - // Notify everyone that we started typing. - function beginTyping() { - //print("beginTyping"); - if (!sendTyping) { - return; - } - - Messages.sendMessage( - channelName, - JSON.stringify({ - type: 'AvatarBeginTyping', - avatarID: MyAvatar.sessionUUID, - displayName: chatName - })); - } - - // Notification that somebody started typing. - function handleAvatarBeginTyping(avatarID, displayName) { - //print("handleAvatarBeginTyping:", "avatarID", avatarID, displayName); - } - - // Notification that we stopped typing. - // Notify everyone that we stopped typing. - function endTyping() { - //print("endTyping"); - if (!sendTyping) { - return; - } - - Messages.sendMessage( - channelName, - JSON.stringify({ - type: 'AvatarEndTyping', - avatarID: MyAvatar.sessionUUID, - displayName: chatName - })); - } - - // Notification that somebody stopped typing. - function handleAvatarEndTyping(avatarID, displayName) { - //print("handleAvatarEndTyping:", "avatarID", avatarID, displayName); - } - - // Identify an avatar by drawing a line from our head to their head. - // If the avatar is our own, then just draw a line up into the sky. - function identifyAvatar(yourAvatarID) { - //print("identifyAvatar", yourAvatarID); - - unidentifyAvatars(); - - var myAvatarID = MyAvatar.sessionUUID; - var myJointIndex = MyAvatar.getJointIndex(identifyAvatarMyJointName); - var myJointRotation = - Quat.multiply( - MyAvatar.orientation, - MyAvatar.getAbsoluteJointRotationInObjectFrame(myJointIndex)); - var myJointPosition = - Vec3.sum( - MyAvatar.position, - Vec3.multiplyQbyV( - MyAvatar.orientation, - MyAvatar.getAbsoluteJointTranslationInObjectFrame(myJointIndex))); - - var yourJointIndex = -1; - var yourJointPosition; - - if (yourAvatarID == myAvatarID) { - - // You pointed at your own name, so draw a line up from your head. - - yourJointPosition = { - x: myJointPosition.x, - y: myJointPosition.y + 1000.0, - z: myJointPosition.z - }; - - } else { - - // You pointed at somebody else's name, so draw a line from your head to their head. - - var yourAvatar = AvatarList.getAvatar(yourAvatarID); - if (!yourAvatar) { - return; - } - - yourJointIndex = yourAvatar.getJointIndex(identifyAvatarMyJointName) - - var yourJointRotation = - Quat.multiply( - yourAvatar.orientation, - yourAvatar.getAbsoluteJointRotationInObjectFrame(yourJointIndex)); - yourJointPosition = - Vec3.sum( - yourAvatar.position, - Vec3.multiplyQbyV( - yourAvatar.orientation, - yourAvatar.getAbsoluteJointTranslationInObjectFrame(yourJointIndex))); - - } - - var identifierParams = { - parentID: myAvatarID, - parentJointIndex: myJointIndex, - lifetime: identifyAvatarDuration, - start: myJointPosition, - endParentID: yourAvatarID, - endParentJointIndex: yourJointIndex, - end: yourJointPosition, - color: identifyAvatarLineColor, - alpha: 1 - }; - - avatarIdentifiers[yourAvatarID] = identifierParams; - - identifierParams.lineID = Overlays.addOverlay("line3d", identifierParams); - - //print("ADDOVERLAY lineID", lineID, "myJointPosition", JSON.stringify(myJointPosition), "yourJointPosition", JSON.stringify(yourJointPosition), "lineData", JSON.stringify(lineData)); - - identifierParams.timer = - Script.setTimeout(function() { - //print("DELETEOVERLAY lineID"); - unidentifyAvatar(yourAvatarID); - }, identifyAvatarDuration * 1000); - - } - - // Stop identifying an avatar. - function unidentifyAvatar(yourAvatarID) { - //print("unidentifyAvatar", yourAvatarID); - - var identifierParams = avatarIdentifiers[yourAvatarID]; - if (!identifierParams) { - return; - } - - if (identifierParams.timer) { - Script.clearTimeout(identifierParams.timer); - } - - if (identifierParams.lineID) { - Overlays.deleteOverlay(identifierParams.lineID); - } - - delete avatarIdentifiers[yourAvatarID]; - } - - // Stop identifying all avatars. - function unidentifyAvatars() { - var ids = []; - - for (var avatarID in avatarIdentifiers) { - ids.push(avatarID); - } - - for (var i = 0, n = ids.length; i < n; i++) { - var avatarID = ids[i]; - unidentifyAvatar(avatarID); - } - - } - - // Turn to face another avatar. - function faceAvatar(yourAvatarID, displayName) { - //print("faceAvatar:", yourAvatarID, displayName); - - var myAvatarID = MyAvatar.sessionUUID; - if (yourAvatarID == myAvatarID) { - // You clicked on yourself. - return; - } - - var yourAvatar = AvatarList.getAvatar(yourAvatarID); - if (!yourAvatar) { - logMessage(displayName + ' is not here!', null); - return; - } - - // Project avatar positions to the floor and get the direction between those points, - // then face my avatar towards your avatar. - var yourPosition = yourAvatar.position; - yourPosition.y = 0; - var myPosition = MyAvatar.position; - myPosition.y = 0; - var myOrientation = Quat.lookAtSimple(myPosition, yourPosition); - MyAvatar.orientation = myOrientation; - } - - // Make a hopefully unique random anonymous avatar name. - function randomAvatarName() { - return 'Anon_' + Math.floor(Math.random() * 1000000); - } - - // Change the avatar size to bigger. - function biggerSize() { - //print("biggerSize"); - logMessage("Increasing avatar size", null); - MyAvatar.increaseSize(); - } - - // Change the avatar size to smaller. - function smallerSize() { - //print("smallerSize"); - logMessage("Decreasing avatar size", null); - MyAvatar.decreaseSize(); - } - - // Set the avatar size to normal. - function normalSize() { - //print("normalSize"); - logMessage("Resetting avatar size to normal!", null); - MyAvatar.resetSize(); - } - - // Send out a "Who" message, including our avatarID as myAvatarID, - // which will be sent in the response, so we can tell the reply - // is to our request. - function transmitWho() { - //print("transmitWho"); - logMessage("Who is here?", null); - Messages.sendMessage( - channelName, - JSON.stringify({ - type: 'Who', - myAvatarID: MyAvatar.sessionUUID - })); - } - - // Send a reply to a "Who" message, with a friendly message, - // our avatarID and our displayName. myAvatarID is the id - // of the avatar who send the Who message, to whom we're - // responding. - function handleWho(myAvatarID) { - var avatarID = MyAvatar.sessionUUID; - if (myAvatarID == avatarID) { - // Don't reply to myself. - return; - } - - var message = "I'm here!"; - var data = {}; - - Messages.sendMessage( - channelName, - JSON.stringify({ - type: 'ReplyWho', - myAvatarID: myAvatarID, - avatarID: avatarID, - displayName: chatName, - message: message, - data: data - })); - } - - // Receive the reply to a "Who" message. Ignore it unless we were the one - // who sent it out (if myAvatarIS is our avatar's id). - function handleReplyWho(myAvatarID, avatarID, displayName, message, data) { - if (myAvatarID != MyAvatar.sessionUUID) { - return; - } - - handleTransmitChatMessage(avatarID, displayName, message, data); - } - - // Handle input form the user, possibly multiple lines separated by newlines. - // Each line may be a chat command starting with "/", or a chat message. - function handleChatMessage(message, data) { - - var messageLines = message.trim().split('\n'); - - for (var i = 0, n = messageLines.length; i < n; i++) { - var messageLine = messageLines[i]; - - if (messageLine.substr(0, 1) == '/') { - handleChatCommand(messageLine, data); - } else { - transmitChatMessage(messageLine, data); - } - } - - } - - // Handle a chat command prefixed by "/". - function handleChatCommand(message, data) { - - var commandLine = message.substr(1); - var tokens = commandLine.trim().split(' '); - var command = tokens[0]; - var rest = commandLine.substr(command.length + 1).trim(); - - //print("commandLine", commandLine, "command", command, "tokens", tokens, "rest", rest); - - switch (command) { - - case '?': - case 'help': - logMessage('Type "/?" or "/help" for help', null); - logMessage('Type "/name " to set your chat name, or "/name" to use your display name. If your display name is not defined, a random name will be used.', null); - logMessage('Type "/close" to close your overhead chat message.', null); - logMessage('Type "/say " to display a new message.', null); - logMessage('Type "/clear" to clear your chat log.', null); - logMessage('Type "/who" to ask who is in the chat session.', null); - logMessage('Type "/bigger", "/smaller" or "/normal" to change your avatar size.', null); - break; - - case 'name': - if (rest == '') { - if (MyAvatar.displayName) { - chatName = MyAvatar.displayName; - saveSettings(); - logMessage('Your chat name has been set to your display name "' + chatName + '".', null); - } else { - chatName = randomAvatarName(); - saveSettings(); - logMessage('Your avatar\'s display name is not defined, so your chat name has been set to "' + chatName + '".', null); - } - } else { - chatName = rest; - saveSettings(); - logMessage('Your chat name has been set to "' + chatName + '".', null); - } - break; - - case 'close': - popDownSpeechBubble(); - logMessage('Overhead chat message closed.', null); - break; - - case 'say': - if (rest == '') { - emptyChatMessage(data); - } else { - transmitChatMessage(rest, data); - } - break; - - case 'who': - transmitWho(); - break; - - case 'clear': - clearChatLog(); - break; - - case 'bigger': - biggerSize(); - break; - - case 'smaller': - smallerSize(); - break; - - case 'normal': - normalSize(); - break; - - case 'resetsettings': - resetSettings(); - updateSettings(); - break; - - case 'speechbubbleheight': - var y = parseInt(rest); - if (!isNaN(y)) { - speechBubbleOffset.y = y; - } - saveSettings(); - updateSettings(); - break; - - case 'speechbubbleduration': - var duration = parseFloat(rest); - if (!isNaN(duration)) { - speechBubbleDuration = duration; - } - saveSettings(); - updateSettings(); - break; - - default: - logMessage('Unknown chat command. Type "/help" or "/?" for help.', null); - break; - - } - - } - - // Send out a chat message to everyone. - function transmitChatMessage(message, data) { - //print("transmitChatMessage", 'avatarID', avatarID, 'displayName', displayName, 'message', message, 'data', data); - - popUpSpeechBubble(message, data); - - Messages.sendMessage( - channelName, - JSON.stringify({ - type: 'TransmitChatMessage', - avatarID: MyAvatar.sessionUUID, - displayName: chatName, - message: message, - data: data - })); - - } - - // Show the speech bubble. - function popUpSpeechBubble(message, data) { - //print("popUpSpeechBubble", message, data); - - popDownSpeechBubble(); - - speechBubbleShowing = true; - speechBubbleMessage = message; - speechBubbleData = data; - - updateSpeechBubble(); - - if (speechBubbleDuration > 0) { - speechBubbleTimer = Script.setTimeout( - function () { - popDownSpeechBubble(); - }, - speechBubbleDuration * 1000); - } - } - - // Update the speech bubble. - // This is factored out so we can update an existing speech bubble if any settings change. - function updateSpeechBubble() { - if (!speechBubbleShowing) { - return; - } - - var jointIndex = MyAvatar.getJointIndex(speechBubbleJointName); - var dimensions = { - x: 100.0, - y: 100.0, - z: 0.1 - }; - - speechBubbleParams = { - type: "Text", - lifetime: speechBubbleDuration, - parentID: MyAvatar.sessionUUID, - jointIndex: jointIndex, - dimensions: dimensions, - lineHeight: speechBubbleLineHeight, - leftMargin: 0, - topMargin: 0, - rightMargin: 0, - bottomMargin: 0, - faceCamera: true, - drawInFront: true, - ignoreRayIntersection: true, - text: speechBubbleMessage, - textColor: speechBubbleTextColor, - color: speechBubbleTextColor, - backgroundColor: speechBubbleBackgroundColor - }; - - // Only overlay text3d has a way to measure the text, not entities. - // So we make a temporary one just for measuring text, then delete it. - var speechBubbleTextOverlayID = Overlays.addOverlay("text3d", speechBubbleParams); - var textSize = Overlays.textSize(textSizeOverlay, speechBubbleMessage); - try { - Overlays.deleteOverlay(speechBubbleTextOverlayID); - } catch (e) {} - - //print("updateSpeechBubble:", "speechBubbleMessage", speechBubbleMessage, "textSize", textSize.width, textSize.height); - - var fudge = 0.02; - - var width = textSize.width + fudge; - var height = speechBubbleLineHeight + fudge; - - if (textSize.width >= SPEECH_BUBBLE_MAX_WIDTH) { - var numLines = Math.ceil(width); - height = speechBubbleLineHeight * numLines + fudge; - width = SPEECH_BUBBLE_MAX_WIDTH; - } - - dimensions = { - x: width, - y: height, - z: 0.1 - }; - speechBubbleParams.dimensions = dimensions; - - var headRotation = - Quat.multiply( - MyAvatar.orientation, - MyAvatar.getAbsoluteJointRotationInObjectFrame(jointIndex)); - var headPosition = - Vec3.sum( - MyAvatar.position, - Vec3.multiplyQbyV( - MyAvatar.orientation, - MyAvatar.getAbsoluteJointTranslationInObjectFrame(jointIndex))); - var rotatedOffset = - Vec3.multiplyQbyV( - headRotation, - speechBubbleOffset); - var position = - Vec3.sum( - headPosition, - rotatedOffset); - position.y += height / 2; // offset based on half of bubble height - speechBubbleParams.position = position; - - if (!speechBubbleTextID) { - speechBubbleTextID = - Entities.addEntity(speechBubbleParams, true); - } else { - Entities.editEntity(speechBubbleTextID, speechBubbleParams); - } - - //print("speechBubbleTextID:", speechBubbleTextID, "speechBubbleParams", JSON.stringify(speechBubbleParams)); - } - - // Hide the speech bubble. - function popDownSpeechBubble() { - cancelSpeechBubbleTimer(); - - speechBubbleShowing = false; - - //print("popDownSpeechBubble speechBubbleTextID", speechBubbleTextID); - - if (speechBubbleTextID) { - try { - Entities.deleteEntity(speechBubbleTextID); - } catch (e) {} - speechBubbleTextID = null; - } - } - - // Cancel the speech bubble popup timer. - function cancelSpeechBubbleTimer() { - if (speechBubbleTimer) { - Script.clearTimeout(speechBubbleTimer); - speechBubbleTimer = null; - } - } - - // Show the tablet web page and connect the web handler. - function showTabletWebPage() { - var url = Script.resolvePath(webPageURL); - if (randomizeWebPageURL) { - url += '?rand=' + Math.random(); - } - lastWebPageURL = url; - onChatPage = true; - tablet.gotoWebScreen(lastWebPageURL); - // Connect immediately so we don't miss anything. - connectWebHandler(); - } - - // Update the tablet web page with the chat log. - function updateChatPage() { - if (!onChatPage) { - return; - } - - tablet.emitScriptEvent( - JSON.stringify({ - type: "Update", - chatLog: chatLog - })); - } - - function onChatMessageReceived(channel, message, senderID) { - - // Ignore messages to any other channel than mine. - if (channel != channelName) { - return; - } - - // Parse the message and pull out the message parameters. - var messageData = JSON.parse(message); - var messageType = messageData.type; - - //print("MESSAGE", message); - //print("MESSAGEDATA", messageData, JSON.stringify(messageData)); - - switch (messageType) { - - case 'TransmitChatMessage': - handleTransmitChatMessage(messageData.avatarID, messageData.displayName, messageData.message, messageData.data); - break; - - case 'AvatarBeginTyping': - handleAvatarBeginTyping(messageData.avatarID, messageData.displayName); - break; - - case 'AvatarEndTyping': - handleAvatarEndTyping(messageData.avatarID, messageData.displayName); - break; - - case 'Who': - handleWho(messageData.myAvatarID); - break; - - case 'ReplyWho': - handleReplyWho(messageData.myAvatarID, messageData.avatarID, messageData.displayName, messageData.message, messageData.data); - break; - - default: - print("onChatMessageReceived: unknown messageType", messageType, "message", message); - break; - - } - - } - - // Handle events from the tablet web page. - function onWebEventReceived(event) { - if (!onChatPage) { - return; - } - - //print("onWebEventReceived: event", event); - - var eventData = JSON.parse(event); - var eventType = eventData.type; - - switch (eventType) { - - case 'Ready': - updateChatPage(); - break; - - case 'Update': - updateChatPage(); - break; - - case 'HandleChatMessage': - var message = eventData.message; - var data = eventData.data; - //print("onWebEventReceived: HandleChatMessage:", 'message', message, 'data', data); - handleChatMessage(message, data); - break; - - case 'PopDownSpeechBubble': - popDownSpeechBubble(); - break; - - case 'EmptyChatMessage': - emptyChatMessage(); - break; - - case 'Type': - type(); - break; - - case 'BeginTyping': - beginTyping(); - break; - - case 'EndTyping': - endTyping(); - break; - - case 'IdentifyAvatar': - identifyAvatar(eventData.avatarID); - break; - - case 'UnidentifyAvatar': - unidentifyAvatar(eventData.avatarID); - break; - - case 'FaceAvatar': - faceAvatar(eventData.avatarID, eventData.displayName); - break; - - case 'ClearChatLog': - clearChatLog(); - break; - - case 'Who': - transmitWho(); - break; - - case 'Bigger': - biggerSize(); - break; - - case 'Smaller': - smallerSize(); - break; - - case 'Normal': - normalSize(); - break; - - default: - print("onWebEventReceived: unexpected eventType", eventType); - break; - - } - } - - function onScreenChanged(type, url) { - //print("onScreenChanged", "type", type, "url", url, "lastWebPageURL", lastWebPageURL); - - if ((type === "Web") && - (url === lastWebPageURL)) { - if (!onChatPage) { - onChatPage = true; - connectWebHandler(); - } - } else { - if (onChatPage) { - onChatPage = false; - disconnectWebHandler(); - } - } - - } - - function connectWebHandler() { - if (webHandlerConnected) { - return; - } - - try { - tablet.webEventReceived.connect(onWebEventReceived); - } catch (e) { - print("connectWebHandler: error connecting: " + e); - return; - } - - webHandlerConnected = true; - //print("connectWebHandler connected"); - - updateChatPage(); - } - - function disconnectWebHandler() { - if (!webHandlerConnected) { - return; - } - - try { - tablet.webEventReceived.disconnect(onWebEventReceived); - } catch (e) { - print("disconnectWebHandler: error disconnecting web handler: " + e); - return; - } - webHandlerConnected = false; - - //print("disconnectWebHandler: disconnected"); - } - - // Show the tablet web page when the chat button on the tablet is clicked. - function onTabletButtonClicked() { - showTabletWebPage(); - } - - // Shut down the chat application when the tablet button is destroyed. - function onTabletButtonDestroyed() { - shutDown(); - } - - // Start up the chat application. - function startUp() { - //print("startUp"); - - loadSettings(); - - tabletButton = tablet.addButton({ - icon: tabletButtonIcon, - activeIcon: tabletButtonActiveIcon, - text: tabletButtonName - }); - - Messages.subscribe(channelName); - - tablet.screenChanged.connect(onScreenChanged); - - Messages.messageReceived.connect(onChatMessageReceived); - - tabletButton.clicked.connect(onTabletButtonClicked); - - Script.scriptEnding.connect(onTabletButtonDestroyed); - - logMessage('Type "/?" or "/help" for help with chat.', null); - - //print("Added chat button to tablet."); - } - - // Shut down the chat application. - function shutDown() { - //print("shutDown"); - - popDownSpeechBubble(); - unidentifyAvatars(); - disconnectWebHandler(); - - Overlays.deleteOverlay(textSizeOverlay); - - if (onChatPage) { - tablet.gotoHomeScreen(); - onChatPage = false; - } - - tablet.screenChanged.disconnect(onScreenChanged); - - Messages.messageReceived.disconnect(onChatMessageReceived); - - // Clean up the tablet button we made. - tabletButton.clicked.disconnect(onTabletButtonClicked); - tablet.removeButton(tabletButton); - tabletButton = null; - - //print("Removed chat button from tablet."); - } - - // Kick off the chat application! - startUp(); - -}()); diff --git a/scripts/simplifiedUI/system/clickToAvatarApp.js b/scripts/simplifiedUI/system/clickToAvatarApp.js deleted file mode 100644 index 8024f595b5..0000000000 --- a/scripts/simplifiedUI/system/clickToAvatarApp.js +++ /dev/null @@ -1,7 +0,0 @@ -(function () { - var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); - this.clickDownOnEntity = function (entityID, mouseEvent) { - tablet.loadQMLSource("hifi/AvatarApp.qml"); - }; -} -); diff --git a/scripts/simplifiedUI/system/commerce/wallet.js b/scripts/simplifiedUI/system/commerce/wallet.js deleted file mode 100644 index 86806fd8b4..0000000000 --- a/scripts/simplifiedUI/system/commerce/wallet.js +++ /dev/null @@ -1,737 +0,0 @@ -"use strict"; -/* jslint vars:true, plusplus:true, forin:true */ -/* eslint indent: ["error", 4, { "outerIIFEBody": 0 }] */ -// -// wallet.js -// -// Created by Zach Fox on 2017-08-17 -// Copyright 2017 High Fidelity, Inc -// -// Distributed under the Apache License, Version 2.0 -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -/* global getConnectionData getControllerWorldLocation openLoginWindow WalletScriptingInterface */ - -(function () { // BEGIN LOCAL_SCOPE -Script.include("/~/system/libraries/accountUtils.js"); -Script.include("/~/system/libraries/connectionUtils.js"); -var AppUi = Script.require('appUi'); - -var MARKETPLACE_URL = Account.metaverseServerURL + "/marketplace"; - -// BEGIN AVATAR SELECTOR LOGIC -var UNSELECTED_COLOR = { red: 0x1F, green: 0xC6, blue: 0xA6 }; -var SELECTED_COLOR = { red: 0xF3, green: 0x91, blue: 0x29 }; -var HOVER_COLOR = { red: 0xD0, green: 0xD0, blue: 0xD0 }; - -var overlays = {}; // Keeps track of all our extended overlay data objects, keyed by target identifier. - -function ExtendedOverlay(key, type, properties) { // A wrapper around overlays to store the key it is associated with. - overlays[key] = this; - this.key = key; - this.selected = false; - this.hovering = false; - this.activeOverlay = Overlays.addOverlay(type, properties); // We could use different overlays for (un)selected... -} -// Instance methods: -ExtendedOverlay.prototype.deleteOverlay = function () { // remove display and data of this overlay - Overlays.deleteOverlay(this.activeOverlay); - delete overlays[this.key]; -}; - -ExtendedOverlay.prototype.editOverlay = function (properties) { // change display of this overlay - Overlays.editOverlay(this.activeOverlay, properties); -}; - -function color(selected, hovering) { - var base = hovering ? HOVER_COLOR : selected ? SELECTED_COLOR : UNSELECTED_COLOR; - function scale(component) { - return component; - } - return { red: scale(base.red), green: scale(base.green), blue: scale(base.blue) }; -} -// so we don't have to traverse the overlays to get the last one -var lastHoveringId = 0; -ExtendedOverlay.prototype.hover = function (hovering) { - this.hovering = hovering; - if (this.key === lastHoveringId) { - if (hovering) { - return; - } - lastHoveringId = 0; - } - this.editOverlay({ color: color(this.selected, hovering) }); - if (hovering) { - // un-hover the last hovering overlay - if (lastHoveringId && lastHoveringId !== this.key) { - ExtendedOverlay.get(lastHoveringId).hover(false); - } - lastHoveringId = this.key; - } -}; -ExtendedOverlay.prototype.select = function (selected) { - if (this.selected === selected) { - return; - } - - this.editOverlay({ color: color(selected, this.hovering) }); - this.selected = selected; -}; -// Class methods: -var selectedId = false; -ExtendedOverlay.isSelected = function (id) { - return selectedId === id; -}; -ExtendedOverlay.get = function (key) { // answer the extended overlay data object associated with the given avatar identifier - return overlays[key]; -}; -ExtendedOverlay.some = function (iterator) { // Bails early as soon as iterator returns truthy. - var key; - for (key in overlays) { - if (iterator(ExtendedOverlay.get(key))) { - return; - } - } -}; -ExtendedOverlay.unHover = function () { // calls hover(false) on lastHoveringId (if any) - if (lastHoveringId) { - ExtendedOverlay.get(lastHoveringId).hover(false); - } -}; - -// hit(overlay) on the one overlay intersected by pickRay, if any. -// noHit() if no ExtendedOverlay was intersected (helps with hover) -ExtendedOverlay.applyPickRay = function (pickRay, hit, noHit) { - // Depends on nearer coverOverlays to extend closer to us than farther ones. - var pickedOverlay = Overlays.findRayIntersection(pickRay); - if (!pickedOverlay.intersects) { - if (noHit) { - return noHit(); - } - return; - } - ExtendedOverlay.some(function (overlay) { // See if pickedOverlay is one of ours. - if ((overlay.activeOverlay) === pickedOverlay.overlayID) { - hit(overlay); - return true; - } - }); -}; - -function addAvatarNode(id) { - return new ExtendedOverlay(id, "sphere", { - drawInFront: true, - solid: true, - alpha: 0.8, - color: color(false, false), - ignoreRayIntersection: false - }); -} - -var pingPong = true; -var OVERLAY_SCALE = 0.032; -function updateOverlays() { - var eye = Camera.position; - AvatarList.getAvatarIdentifiers().forEach(function (id) { - if (!id) { - return; // don't update ourself, or avatars we're not interested in - } - var avatar = AvatarList.getAvatar(id); - if (!avatar) { - return; // will be deleted below if there had been an overlay. - } - var overlay = ExtendedOverlay.get(id); - if (!overlay) { // For now, we're treating this as a temporary loss, as from the personal space bubble. Add it back. - overlay = addAvatarNode(id); - } - var target = avatar.position; - var distance = Vec3.distance(target, eye); - var offset = 0.2; - // get diff between target and eye (a vector pointing to the eye from avatar position) - var diff = Vec3.subtract(target, eye); - var headIndex = avatar.getJointIndex("Head"); // base offset on 1/2 distance from hips to head if we can - if (headIndex > 0) { - offset = avatar.getAbsoluteJointTranslationInObjectFrame(headIndex).y / 2; - } - - // move a bit in front, towards the camera - target = Vec3.subtract(target, Vec3.multiply(Vec3.normalize(diff), offset)); - - // now bump it up a bit - target.y = target.y + offset; - - overlay.ping = pingPong; - overlay.editOverlay({ - color: color(ExtendedOverlay.isSelected(id), overlay.hovering), - position: target, - dimensions: OVERLAY_SCALE * distance - }); - }); - pingPong = !pingPong; - ExtendedOverlay.some(function (overlay) { // Remove any that weren't updated. (User is gone.) - if (overlay.ping === pingPong) { - overlay.deleteOverlay(); - } - }); -} -function removeOverlays() { - selectedId = false; - lastHoveringId = 0; - ExtendedOverlay.some(function (overlay) { - overlay.deleteOverlay(); - }); -} - -// -// Clicks. -// -function usernameFromIDReply(id, username, machineFingerprint, isAdmin) { - if (selectedId === id) { - var message = { - method: 'updateSelectedRecipientUsername', - userName: username === "" ? "unknown username" : username - }; - ui.sendMessage(message); - } -} -function handleClick(pickRay) { - ExtendedOverlay.applyPickRay(pickRay, function (overlay) { - var nextSelectedStatus = !overlay.selected; - var avatarId = overlay.key; - selectedId = nextSelectedStatus ? avatarId : false; - if (nextSelectedStatus) { - Users.requestUsernameFromID(avatarId); - } - var message = { - method: 'selectRecipient', - id: avatarId, - isSelected: nextSelectedStatus, - displayName: '"' + AvatarList.getAvatar(avatarId).sessionDisplayName + '"', - userName: '' - }; - ui.sendMessage(message); - - ExtendedOverlay.some(function (overlay) { - var id = overlay.key; - var selected = ExtendedOverlay.isSelected(id); - overlay.select(selected); - }); - - return true; - }); -} -function handleMouseEvent(mousePressEvent) { // handleClick if we get one. - if (!mousePressEvent.isLeftButton) { - return; - } - handleClick(Camera.computePickRay(mousePressEvent.x, mousePressEvent.y)); -} -function handleMouseMove(pickRay) { // given the pickRay, just do the hover logic - ExtendedOverlay.applyPickRay(pickRay, function (overlay) { - overlay.hover(true); - }, function () { - ExtendedOverlay.unHover(); - }); -} - -// handy global to keep track of which hand is the mouse (if any) -var currentHandPressed = 0; -var TRIGGER_CLICK_THRESHOLD = 0.85; -var TRIGGER_PRESS_THRESHOLD = 0.05; - -function handleMouseMoveEvent(event) { // find out which overlay (if any) is over the mouse position - var pickRay; - if (HMD.active) { - if (currentHandPressed !== 0) { - pickRay = controllerComputePickRay(currentHandPressed); - } else { - // nothing should hover, so - ExtendedOverlay.unHover(); - return; - } - } else { - pickRay = Camera.computePickRay(event.x, event.y); - } - handleMouseMove(pickRay); -} -function handleTriggerPressed(hand, value) { - // The idea is if you press one trigger, it is the one - // we will consider the mouse. Even if the other is pressed, - // we ignore it until this one is no longer pressed. - var isPressed = value > TRIGGER_PRESS_THRESHOLD; - if (currentHandPressed === 0) { - currentHandPressed = isPressed ? hand : 0; - return; - } - if (currentHandPressed === hand) { - currentHandPressed = isPressed ? hand : 0; - return; - } - // otherwise, the other hand is still triggered - // so do nothing. -} - -// We get mouseMoveEvents from the handControllers, via handControllerPointer. -// But we don't get mousePressEvents. -var triggerMapping = Controller.newMapping(Script.resolvePath('') + '-click'); -var triggerPressMapping = Controller.newMapping(Script.resolvePath('') + '-press'); -function controllerComputePickRay(hand) { - var controllerPose = getControllerWorldLocation(hand, true); - if (controllerPose.valid) { - return { origin: controllerPose.position, direction: Quat.getUp(controllerPose.orientation) }; - } -} -function makeClickHandler(hand) { - return function (clicked) { - if (clicked > TRIGGER_CLICK_THRESHOLD) { - var pickRay = controllerComputePickRay(hand); - handleClick(pickRay); - } - }; -} -function makePressHandler(hand) { - return function (value) { - handleTriggerPressed(hand, value); - }; -} -triggerMapping.from(Controller.Standard.RTClick).peek().to(makeClickHandler(Controller.Standard.RightHand)); -triggerMapping.from(Controller.Standard.LTClick).peek().to(makeClickHandler(Controller.Standard.LeftHand)); -triggerPressMapping.from(Controller.Standard.RT).peek().to(makePressHandler(Controller.Standard.RightHand)); -triggerPressMapping.from(Controller.Standard.LT).peek().to(makePressHandler(Controller.Standard.LeftHand)); -// END AVATAR SELECTOR LOGIC - -var sendMoneyRecipient; -var sendMoneyParticleEffectUpdateTimer; -var particleEffectTimestamp; -var sendMoneyParticleEffect; -var SEND_MONEY_PARTICLE_TIMER_UPDATE = 250; -var SEND_MONEY_PARTICLE_EMITTING_DURATION = 3000; -var SEND_MONEY_PARTICLE_LIFETIME_SECONDS = 8; -var SEND_MONEY_PARTICLE_PROPERTIES = { - accelerationSpread: { x: 0, y: 0, z: 0 }, - alpha: 1, - alphaFinish: 1, - alphaSpread: 0, - alphaStart: 1, - azimuthFinish: 0, - azimuthStart: -6, - color: { red: 143, green: 5, blue: 255 }, - colorFinish: { red: 255, green: 0, blue: 204 }, - colorSpread: { red: 0, green: 0, blue: 0 }, - colorStart: { red: 0, green: 136, blue: 255 }, - emitAcceleration: { x: 0, y: 0, z: 0 }, // Immediately gets updated to be accurate - emitDimensions: { x: 0, y: 0, z: 0 }, - emitOrientation: { x: 0, y: 0, z: 0 }, - emitRate: 4, - emitSpeed: 2.1, - emitterShouldTrail: true, - isEmitting: 1, - lifespan: SEND_MONEY_PARTICLE_LIFETIME_SECONDS + 1, // Immediately gets updated to be accurate - lifetime: SEND_MONEY_PARTICLE_LIFETIME_SECONDS + 1, - maxParticles: 20, - name: 'hfc-particles', - particleRadius: 0.2, - polarFinish: 0, - polarStart: 0, - radiusFinish: 0.05, - radiusSpread: 0, - radiusStart: 0.2, - speedSpread: 0, - textures: "http://hifi-content.s3.amazonaws.com/alan/dev/Particles/Bokeh-Particle-HFC.png", - type: 'ParticleEffect' -}; - -var MS_PER_SEC = 1000; -function updateSendMoneyParticleEffect() { - var timestampNow = Date.now(); - if ((timestampNow - particleEffectTimestamp) > (SEND_MONEY_PARTICLE_LIFETIME_SECONDS * MS_PER_SEC)) { - deleteSendMoneyParticleEffect(); - return; - } else if ((timestampNow - particleEffectTimestamp) > SEND_MONEY_PARTICLE_EMITTING_DURATION) { - Entities.editEntity(sendMoneyParticleEffect, { - isEmitting: 0 - }); - } else if (sendMoneyParticleEffect) { - var recipientPosition = AvatarList.getAvatar(sendMoneyRecipient).position; - var distance = Vec3.distance(recipientPosition, MyAvatar.position); - var accel = Vec3.subtract(recipientPosition, MyAvatar.position); - accel.y -= 3.0; - var life = Math.sqrt(2 * distance / Vec3.length(accel)); - Entities.editEntity(sendMoneyParticleEffect, { - emitAcceleration: accel, - lifespan: life - }); - } -} - -function deleteSendMoneyParticleEffect() { - if (sendMoneyParticleEffectUpdateTimer) { - Script.clearInterval(sendMoneyParticleEffectUpdateTimer); - sendMoneyParticleEffectUpdateTimer = null; - } - if (sendMoneyParticleEffect) { - sendMoneyParticleEffect = Entities.deleteEntity(sendMoneyParticleEffect); - } - sendMoneyRecipient = null; -} - -function onUsernameChanged() { - if (ui.checkIsOpen()) { - ui.open(WALLET_QML_SOURCE); - } -} - -var MARKETPLACE_QML_PATH = "hifi/commerce/marketplace/Marketplace.qml"; -function openMarketplace(optionalItem) { - ui.open(MARKETPLACE_QML_PATH); - - if (optionalItem) { - ui.tablet.sendToQml({ - method: 'updateMarketplaceQMLItem', - params: { itemId: optionalItem } - }); - } -} - -function setCertificateInfo(itemCertificateId) { - ui.tablet.sendToQml({ - method: 'inspectionCertificate_setCertificateId', - entityId: "", - certificateId: itemCertificateId - }); -} - -// Function Name: fromQml() -// -// Description: -// -Called when a message is received from SpectatorCamera.qml. The "message" argument is what is sent from the QML -// in the format "{method, params}", like json-rpc. See also sendToQml(). -function fromQml(message) { - switch (message.method) { - case 'passphrasePopup_cancelClicked': - case 'needsLogIn_cancelClicked': - ui.close(); - break; - case 'walletSetup_cancelClicked': - switch (message.referrer) { - case '': // User clicked "Wallet" app - case undefined: - case null: - ui.close(); - break; - case 'purchases': - case 'marketplace cta': - case 'mainPage': - openMarketplace(); - break; - default: - openMarketplace(); - break; - } - break; - case 'needsLogIn_loginClicked': - openLoginWindow(); - break; - case 'disableHmdPreview': - break; // do nothing here, handled in marketplaces.js - case 'maybeEnableHmdPreview': - break; // do nothing here, handled in marketplaces.js - case 'transactionHistory_linkClicked': - openMarketplace(message.itemId); - break; - case 'goToMarketplaceMainPage': - openMarketplace(); - break; - case 'goToMarketplaceItemPage': - openMarketplace(message.itemId); - break; - case 'refreshConnections': - print('Refreshing Connections...'); - getConnectionData(false); - break; - case 'enable_ChooseRecipientNearbyMode': - if (!isUpdateOverlaysWired) { - Script.update.connect(updateOverlays); - isUpdateOverlaysWired = true; - } - break; - case 'disable_ChooseRecipientNearbyMode': - if (isUpdateOverlaysWired) { - Script.update.disconnect(updateOverlays); - isUpdateOverlaysWired = false; - } - removeOverlays(); - break; - case 'sendAsset_sendPublicly': - deleteSendMoneyParticleEffect(); - sendMoneyRecipient = message.recipient; - var props = SEND_MONEY_PARTICLE_PROPERTIES; - props.parentID = MyAvatar.sessionUUID; - props.position = MyAvatar.position; - props.position.y += 0.2; - if (message.effectImage) { - props.textures = message.effectImage; - } - sendMoneyParticleEffect = Entities.addEntity(props, true); - particleEffectTimestamp = Date.now(); - updateSendMoneyParticleEffect(); - sendMoneyParticleEffectUpdateTimer = - Script.setInterval(updateSendMoneyParticleEffect, SEND_MONEY_PARTICLE_TIMER_UPDATE); - break; - case 'transactionHistory_goToBank': - if (Account.metaverseServerURL.indexOf("staging") >= 0) { - Window.location = "hifi://hifiqa-master-metaverse-staging"; // So that we can test in staging. - } else { - Window.location = "hifi://BankOfHighFidelity"; - } - break; - case 'purchases_updateWearables': - var currentlyWornWearables = []; - var ATTACHMENT_SEARCH_RADIUS = 100; // meters (just in case) - - var nearbyEntities = Entities.findEntitiesByType('Model', MyAvatar.position, ATTACHMENT_SEARCH_RADIUS); - - for (var i = 0; i < nearbyEntities.length; i++) { - var currentProperties = Entities.getEntityProperties( - nearbyEntities[i], ['certificateID', 'editionNumber', 'parentID'] - ); - if (currentProperties.parentID === MyAvatar.sessionUUID) { - currentlyWornWearables.push({ - entityID: nearbyEntities[i], - entityCertID: currentProperties.certificateID, - entityEdition: currentProperties.editionNumber - }); - } - } - - ui.tablet.sendToQml({ method: 'updateWearables', wornWearables: currentlyWornWearables }); - break; - case 'purchases_walletNotSetUp': - ui.tablet.sendToQml({ - method: 'updateWalletReferrer', - referrer: "purchases" - }); - break; - case 'purchases_openGoTo': - ui.open("hifi/tablet/TabletAddressDialog.qml"); - break; - case 'purchases_itemInfoClicked': - var itemId = message.itemId; - if (itemId && itemId !== "") { - openMarketplace(itemId); - } - break; - case 'purchases_itemCertificateClicked': - setCertificateInfo(message.itemCertificateId); - break; - case 'clearShouldShowDotHistory': - shouldShowDotHistory = false; - ui.messagesWaiting(shouldShowDotUpdates || shouldShowDotHistory); - break; - case 'clearShouldShowDotUpdates': - shouldShowDotUpdates = false; - ui.messagesWaiting(shouldShowDotUpdates || shouldShowDotHistory); - break; - case 'http.request': - // Handled elsewhere, don't log. - break; - case 'closeSendAsset': - ui.close(); - break; - default: - print('wallet.js: Unrecognized message from QML'); - } -} - -var isWired = false; -function walletOpened() { - Users.usernameFromIDReply.connect(usernameFromIDReply); - Controller.mousePressEvent.connect(handleMouseEvent); - Controller.mouseMoveEvent.connect(handleMouseMoveEvent); - triggerMapping.enable(); - triggerPressMapping.enable(); - isWired = true; - - if (shouldShowDotHistory) { - ui.sendMessage({ - method: 'updateRecentActivityMessageLight', - messagesWaiting: shouldShowDotHistory - }); - } -} - -function walletClosed() { - off(); -} - -function notificationDataProcessPageUpdates(data) { - return data.data.updates; -} - -function notificationDataProcessPageHistory(data) { - return data.data.history; -} - -var shouldShowDotUpdates = false; -function notificationPollCallbackUpdates(updatesArray) { - shouldShowDotUpdates = updatesArray.length > 0; - ui.messagesWaiting(shouldShowDotUpdates || shouldShowDotHistory); - - if (updatesArray.length > 0) { - var message; - if (!ui.notificationInitialCallbackMade[0]) { - message = updatesArray.length + " of your purchased items " + - (updatesArray.length === 1 ? "has an update " : "have updates ") + - "available. Open INVENTORY to update."; - ui.notificationDisplayBanner(message); - - ui.notificationPollCaresAboutSince[0] = true; - } else { - for (var i = 0; i < updatesArray.length; i++) { - message = "Update available for \"" + - updatesArray[i].base_item_title + "\"." + - "Open INVENTORY to update."; - ui.notificationDisplayBanner(message); - } - } - } -} -var shouldShowDotHistory = false; -function notificationPollCallbackHistory(historyArray) { - if (!ui.isOpen) { - var notificationCount = historyArray.length; - shouldShowDotHistory = shouldShowDotHistory || notificationCount > 0; - ui.messagesWaiting(shouldShowDotUpdates || shouldShowDotHistory); - - if (notificationCount > 0) { - var message; - if (!ui.notificationInitialCallbackMade[1]) { - message = "You have " + notificationCount + " unread recent " + - "transaction" + (notificationCount === 1 ? "" : "s") + ". Open INVENTORY to see all activity."; - ui.notificationDisplayBanner(message); - } else { - for (var i = 0; i < notificationCount; i++) { - var historyMessage = historyArray[i].message; - var sanitizedHistoryMessage = historyMessage.replace(/<\/?[^>]+(>|$)/g, ""); - message = '"' + sanitizedHistoryMessage + '" ' + - "Open INVENTORY to see all activity."; - ui.notificationDisplayBanner(message); - } - } - } - } -} - -function isReturnedDataEmptyUpdates(data) { - var updatesArray = data.data.updates; - return updatesArray.length === 0; -} - -function isReturnedDataEmptyHistory(data) { - var historyArray = data.data.history; - return historyArray.length === 0; -} - -var DEVELOPER_MENU = "Developer"; -var MARKETPLACE_ITEM_TESTER_LABEL = "Marketplace Item Tester"; -var MARKETPLACE_ITEM_TESTER_QML_SOURCE = "hifi/commerce/marketplaceItemTester/MarketplaceItemTester.qml"; -function installMarketplaceItemTester() { - if (!Menu.menuExists(DEVELOPER_MENU)) { - Menu.addMenu(DEVELOPER_MENU); - } - if (!Menu.menuItemExists(DEVELOPER_MENU, MARKETPLACE_ITEM_TESTER_LABEL)) { - Menu.addMenuItem({ - menuName: DEVELOPER_MENU, - menuItemName: MARKETPLACE_ITEM_TESTER_LABEL, - isCheckable: false - }); - } - - Menu.menuItemEvent.connect(function (menuItem) { - if (menuItem === MARKETPLACE_ITEM_TESTER_LABEL) { - ui.open(MARKETPLACE_ITEM_TESTER_QML_SOURCE); - } - }); -} - -function uninstallMarketplaceItemTester() { - if (Menu.menuExists(DEVELOPER_MENU) && - Menu.menuItemExists(DEVELOPER_MENU, MARKETPLACE_ITEM_TESTER_LABEL) - ) { - Menu.removeMenuItem(DEVELOPER_MENU, MARKETPLACE_ITEM_TESTER_LABEL); - } -} - -var BUTTON_NAME = "INVENTORY"; -var WALLET_QML_SOURCE = "hifi/commerce/wallet/Wallet.qml"; -var SENDASSET_QML_SOURCE = "hifi/commerce/common/sendAsset/SendAsset.qml"; -var NOTIFICATION_POLL_TIMEOUT = 300000; -var ui; -function startup() { - var notificationPollEndpointArray = ["/api/v1/commerce/available_updates?per_page=10"]; - var notificationPollTimeoutMsArray = [NOTIFICATION_POLL_TIMEOUT]; - var notificationDataProcessPageArray = [notificationDataProcessPageUpdates]; - var notificationPollCallbackArray = [notificationPollCallbackUpdates]; - var notificationPollStopPaginatingConditionMetArray = [isReturnedDataEmptyUpdates]; - var notificationPollCaresAboutSinceArray = [false]; - - if (!WalletScriptingInterface.limitedCommerce) { - notificationPollEndpointArray[1] = "/api/v1/commerce/history?per_page=10"; - notificationPollTimeoutMsArray[1] = NOTIFICATION_POLL_TIMEOUT; - notificationDataProcessPageArray[1] = notificationDataProcessPageHistory; - notificationPollCallbackArray[1] = notificationPollCallbackHistory; - notificationPollStopPaginatingConditionMetArray[1] = isReturnedDataEmptyHistory; - notificationPollCaresAboutSinceArray[1] = true; - } - - ui = new AppUi({ - buttonName: BUTTON_NAME, - sortOrder: 10, - home: WALLET_QML_SOURCE, - additionalAppScreens: SENDASSET_QML_SOURCE, - onOpened: walletOpened, - onClosed: walletClosed, - onMessage: fromQml, - notificationPollEndpoint: notificationPollEndpointArray, - notificationPollTimeoutMs: notificationPollTimeoutMsArray, - notificationDataProcessPage: notificationDataProcessPageArray, - notificationPollCallback: notificationPollCallbackArray, - notificationPollStopPaginatingConditionMet: notificationPollStopPaginatingConditionMetArray, - notificationPollCaresAboutSince: notificationPollCaresAboutSinceArray - }); - GlobalServices.myUsernameChanged.connect(onUsernameChanged); - installMarketplaceItemTester(); -} - -var isUpdateOverlaysWired = false; -function off() { - if (isWired) { - Users.usernameFromIDReply.disconnect(usernameFromIDReply); - Controller.mousePressEvent.disconnect(handleMouseEvent); - Controller.mouseMoveEvent.disconnect(handleMouseMoveEvent); - triggerMapping.disable(); - triggerPressMapping.disable(); - isWired = false; - } - - if (isUpdateOverlaysWired) { - Script.update.disconnect(updateOverlays); - isUpdateOverlaysWired = false; - } - removeOverlays(); -} - -function shutdown() { - GlobalServices.myUsernameChanged.disconnect(onUsernameChanged); - deleteSendMoneyParticleEffect(); - uninstallMarketplaceItemTester(); - off(); -} - -// -// Run the functions. -// -startup(); -Script.scriptEnding.connect(shutdown); -}()); // END LOCAL_SCOPE diff --git a/scripts/simplifiedUI/system/controllers/+android_questInterface/controllerScripts.js b/scripts/simplifiedUI/system/controllers/+android_questInterface/controllerScripts.js deleted file mode 100644 index d313efaca1..0000000000 --- a/scripts/simplifiedUI/system/controllers/+android_questInterface/controllerScripts.js +++ /dev/null @@ -1,58 +0,0 @@ -"use strict"; - -// controllerScripts.js -// -// Created by David Rowe on 15 Mar 2017. -// Copyright 2017 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -/* global Script, Menu */ - -var CONTOLLER_SCRIPTS = [ - "squeezeHands.js", - "controllerDisplayManager.js", - "toggleAdvancedMovementForHandControllers.js", - "controllerDispatcher.js", - "controllerModules/nearParentGrabOverlay.js", - "controllerModules/stylusInput.js", - "controllerModules/equipEntity.js", - "controllerModules/nearTrigger.js", - "controllerModules/webSurfaceLaserInput.js", - "controllerModules/inVREditMode.js", - "controllerModules/disableOtherModule.js", - "controllerModules/farTrigger.js", - "controllerModules/teleport.js", - "controllerModules/hudOverlayPointer.js", - "controllerModules/scaleEntity.js", - "controllerModules/nearGrabHyperLinkEntity.js", - "controllerModules/nearTabletHighlight.js", - "controllerModules/nearGrabEntity.js", - "controllerModules/farGrabEntity.js" -]; - -var DEBUG_MENU_ITEM = "Debug defaultScripts.js"; - -function runDefaultsTogether() { - for (var j in CONTOLLER_SCRIPTS) { - if (CONTOLLER_SCRIPTS.hasOwnProperty(j)) { - Script.include(CONTOLLER_SCRIPTS[j]); - } - } -} - -function runDefaultsSeparately() { - for (var i in CONTOLLER_SCRIPTS) { - if (CONTOLLER_SCRIPTS.hasOwnProperty(i)) { - Script.load(CONTOLLER_SCRIPTS[i]); - } - } -} - -if (Menu.isOptionChecked(DEBUG_MENU_ITEM)) { - runDefaultsSeparately(); -} else { - runDefaultsTogether(); -} diff --git a/scripts/simplifiedUI/system/controllers/controllerDispatcher.js b/scripts/simplifiedUI/system/controllers/controllerDispatcher.js deleted file mode 100644 index 0a9fa4dce1..0000000000 --- a/scripts/simplifiedUI/system/controllers/controllerDispatcher.js +++ /dev/null @@ -1,615 +0,0 @@ -"use strict"; - -// controllerDispatcher.js -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html - -/* jslint bitwise: true */ - -/* global Script, Entities, Overlays, Controller, Vec3, Quat, getControllerWorldLocation, - controllerDispatcherPlugins:true, controllerDispatcherPluginsNeedSort:true, - LEFT_HAND, RIGHT_HAND, NEAR_GRAB_PICK_RADIUS, DEFAULT_SEARCH_SPHERE_DISTANCE, DISPATCHER_PROPERTIES, - getGrabPointSphereOffset, HMD, MyAvatar, Messages, findHandChildEntities, Picks, PickType, Pointers, - PointerManager, getGrabPointSphereOffset, HMD, MyAvatar, Messages, findHandChildEntities, Picks, PickType, Pointers, - PointerManager, print, Keyboard -*/ - -controllerDispatcherPlugins = {}; -controllerDispatcherPluginsNeedSort = false; - -Script.include("/~/system/libraries/utils.js"); -Script.include("/~/system/libraries/controllers.js"); -Script.include("/~/system/libraries/controllerDispatcherUtils.js"); - -(function() { - Script.include("/~/system/libraries/pointersUtils.js"); - - var NEAR_MAX_RADIUS = 0.1; - var NEAR_TABLET_MAX_RADIUS = 0.05; - - var TARGET_UPDATE_HZ = 60; // 50hz good enough, but we're using update - var BASIC_TIMER_INTERVAL_MS = 1000 / TARGET_UPDATE_HZ; - - var PROFILE = false; - var DEBUG = false; - var SHOW_GRAB_SPHERE = false; - - - if (typeof Test !== "undefined") { - PROFILE = true; - } - - function ControllerDispatcher() { - var _this = this; - this.lastInterval = Date.now(); - this.intervalCount = 0; - this.totalDelta = 0; - this.totalVariance = 0; - this.highVarianceCount = 0; - this.veryhighVarianceCount = 0; - this.orderedPluginNames = []; - this.tabletID = null; - this.blacklist = []; - this.pointerManager = new PointerManager(); - this.grabSphereOverlays = [null, null]; - this.targetIDs = {}; - - // a module can occupy one or more "activity" slots while it's running. If all the required slots for a module are - // not set to false (not in use), a module cannot start. When a module is using a slot, that module's name - // is stored as the value, rather than false. - this.activitySlots = { - head: false, - leftHand: false, - rightHand: false, - rightHandTrigger: false, - leftHandTrigger: false, - rightHandEquip: false, - leftHandEquip: false, - mouse: false - }; - - this.laserVisibleStatus = [false, false, false, false]; - this.laserLockStatus = [false, false, false, false]; - - this.slotsAreAvailableForPlugin = function (plugin) { - for (var i = 0; i < plugin.parameters.activitySlots.length; i++) { - if (_this.activitySlots[plugin.parameters.activitySlots[i]]) { - return false; // something is already using a slot which _this plugin requires - } - } - return true; - }; - - this.markSlots = function (plugin, pluginName) { - for (var i = 0; i < plugin.parameters.activitySlots.length; i++) { - _this.activitySlots[plugin.parameters.activitySlots[i]] = pluginName; - } - }; - - this.unmarkSlotsForPluginName = function (runningPluginName) { - // this is used to free activity-slots when a plugin is deactivated while it's running. - for (var activitySlot in _this.activitySlots) { - if (activitySlot.hasOwnProperty(activitySlot) && _this.activitySlots[activitySlot] === runningPluginName) { - _this.activitySlots[activitySlot] = false; - } - } - }; - - this.runningPluginNames = {}; - this.leftTriggerValue = 0; - this.leftTriggerClicked = 0; - this.rightTriggerValue = 0; - this.rightTriggerClicked = 0; - this.leftSecondaryValue = 0; - this.rightSecondaryValue = 0; - - this.leftTriggerPress = function (value) { - _this.leftTriggerValue = value; - }; - this.leftTriggerClick = function (value) { - _this.leftTriggerClicked = value; - }; - this.rightTriggerPress = function (value) { - _this.rightTriggerValue = value; - }; - this.rightTriggerClick = function (value) { - _this.rightTriggerClicked = value; - }; - this.leftSecondaryPress = function (value) { - _this.leftSecondaryValue = value; - }; - this.rightSecondaryPress = function (value) { - _this.rightSecondaryValue = value; - }; - - this.dataGatherers = {}; - this.dataGatherers.leftControllerLocation = function () { - return getControllerWorldLocation(Controller.Standard.LeftHand, true); - }; - this.dataGatherers.rightControllerLocation = function () { - return getControllerWorldLocation(Controller.Standard.RightHand, true); - }; - - this.updateTimings = function () { - _this.intervalCount++; - var thisInterval = Date.now(); - var deltaTimeMsec = thisInterval - _this.lastInterval; - var deltaTime = deltaTimeMsec / 1000; - _this.lastInterval = thisInterval; - - _this.totalDelta += deltaTimeMsec; - - var variance = Math.abs(deltaTimeMsec - BASIC_TIMER_INTERVAL_MS); - _this.totalVariance += variance; - - if (variance > 1) { - _this.highVarianceCount++; - } - - if (variance > 5) { - _this.veryhighVarianceCount++; - } - - return deltaTime; - }; - - this.setIgnorePointerItems = function() { - if (HMD.tabletID && HMD.tabletID !== this.tabletID) { - this.tabletID = HMD.tabletID; - Pointers.setIgnoreItems(_this.leftPointer, _this.blacklist); - Pointers.setIgnoreItems(_this.rightPointer, _this.blacklist); - } - }; - - this.update = function () { - try { - _this.updateInternal(); - } catch (e) { - print(e); - } - Script.setTimeout(_this.update, BASIC_TIMER_INTERVAL_MS); - }; - - this.updateInternal = function () { - if (PROFILE) { - Script.beginProfileRange("dispatch.pre"); - } - var sensorScaleFactor = MyAvatar.sensorToWorldScale; - var deltaTime = _this.updateTimings(); - _this.setIgnorePointerItems(); - - if (controllerDispatcherPluginsNeedSort) { - _this.orderedPluginNames = []; - for (var pluginName in controllerDispatcherPlugins) { - if (controllerDispatcherPlugins.hasOwnProperty(pluginName)) { - _this.orderedPluginNames.push(pluginName); - } - } - _this.orderedPluginNames.sort(function (a, b) { - return controllerDispatcherPlugins[a].parameters.priority - - controllerDispatcherPlugins[b].parameters.priority; - }); - - controllerDispatcherPluginsNeedSort = false; - } - - if (PROFILE) { - Script.endProfileRange("dispatch.pre"); - } - - if (PROFILE) { - Script.beginProfileRange("dispatch.gather"); - } - - var controllerLocations = [ - _this.dataGatherers.leftControllerLocation(), - _this.dataGatherers.rightControllerLocation() - ]; - - // find 3d overlays near each hand - var nearbyOverlayIDs = []; - var h; - for (h = LEFT_HAND; h <= RIGHT_HAND; h++) { - if (controllerLocations[h].valid) { - var nearbyOverlays = - Overlays.findOverlays(controllerLocations[h].position, NEAR_MAX_RADIUS * sensorScaleFactor); - - // Tablet and mini-tablet must be within NEAR_TABLET_MAX_RADIUS in order to be grabbed. - // Mini tablet can only be grabbed the hand it's displayed on. - var tabletIndex = nearbyOverlays.indexOf(HMD.tabletID); - var miniTabletIndex = nearbyOverlays.indexOf(HMD.miniTabletID); - if (tabletIndex !== -1 || miniTabletIndex !== -1) { - var closebyOverlays = - Overlays.findOverlays(controllerLocations[h].position, NEAR_TABLET_MAX_RADIUS * sensorScaleFactor); - // Assumes that the tablet and mini-tablet are not displayed at the same time. - if (tabletIndex !== -1 && closebyOverlays.indexOf(HMD.tabletID) === -1) { - nearbyOverlays.splice(tabletIndex, 1); - } - if (miniTabletIndex !== -1 && - ((closebyOverlays.indexOf(HMD.miniTabletID) === -1) || h !== HMD.miniTabletHand)) { - nearbyOverlays.splice(miniTabletIndex, 1); - } - } - - nearbyOverlays.sort(function (a, b) { - var aPosition = Overlays.getProperty(a, "position"); - var aDistance = Vec3.distance(aPosition, controllerLocations[h].position); - var bPosition = Overlays.getProperty(b, "position"); - var bDistance = Vec3.distance(bPosition, controllerLocations[h].position); - return aDistance - bDistance; - }); - - nearbyOverlayIDs.push(nearbyOverlays); - } else { - nearbyOverlayIDs.push([]); - } - } - - // find entities near each hand - var nearbyEntityProperties = [[], []]; - var nearbyEntityPropertiesByID = {}; - for (h = LEFT_HAND; h <= RIGHT_HAND; h++) { - if (controllerLocations[h].valid) { - var controllerPosition = controllerLocations[h].position; - var findRadius = NEAR_MAX_RADIUS * sensorScaleFactor; - - if (SHOW_GRAB_SPHERE) { - if (this.grabSphereOverlays[h]) { - Overlays.editOverlay(this.grabSphereOverlays[h], { position: controllerLocations[h].position }); - } else { - var grabSphereSize = findRadius * 2; - this.grabSphereOverlays[h] = Overlays.addOverlay("sphere", { - position: controllerLocations[h].position, - dimensions: { x: grabSphereSize, y: grabSphereSize, z: grabSphereSize }, - color: { red: 30, green: 30, blue: 255 }, - alpha: 0.3, - solid: true, - visible: true, - // lineWidth: 2.0, - drawInFront: false, - grabbable: false - }); - } - } - - var nearbyEntityIDs = Entities.findEntities(controllerPosition, findRadius); - for (var j = 0; j < nearbyEntityIDs.length; j++) { - var entityID = nearbyEntityIDs[j]; - var props = Entities.getEntityProperties(entityID, DISPATCHER_PROPERTIES); - props.id = entityID; - props.distance = Vec3.distance(props.position, controllerLocations[h].position); - nearbyEntityPropertiesByID[entityID] = props; - nearbyEntityProperties[h].push(props); - } - } - } - - // raypick for each controller - var rayPicks = [ - Pointers.getPrevPickResult(_this.leftPointer), - Pointers.getPrevPickResult(_this.rightPointer) - ]; - var hudRayPicks = [ - Pointers.getPrevPickResult(_this.leftHudPointer), - Pointers.getPrevPickResult(_this.rightHudPointer) - ]; - var mouseRayPick = Pointers.getPrevPickResult(_this.mouseRayPick); - // if the pickray hit something very nearby, put it into the nearby entities list - for (h = LEFT_HAND; h <= RIGHT_HAND; h++) { - - // XXX find a way to extract searchRay from samuel's stuff - rayPicks[h].searchRay = { - origin: controllerLocations[h].position, - direction: Quat.getUp(controllerLocations[h].orientation), - length: 1000 - }; - - if (rayPicks[h].type === Picks.INTERSECTED_ENTITY) { - // XXX check to make sure this one isn't already in nearbyEntityProperties? - if (rayPicks[h].distance < NEAR_GRAB_PICK_RADIUS * sensorScaleFactor) { - var nearEntityID = rayPicks[h].objectID; - var nearbyProps = Entities.getEntityProperties(nearEntityID, DISPATCHER_PROPERTIES); - nearbyProps.id = nearEntityID; - nearbyProps.distance = rayPicks[h].distance; - nearbyEntityPropertiesByID[nearEntityID] = nearbyProps; - nearbyEntityProperties[h].push(nearbyProps); - } - } - - // sort by distance from each hand - nearbyEntityProperties[h].sort(function (a, b) { - return a.distance - b.distance; - }); - } - - // sometimes, during a HMD snap-turn, an equipped or held item wont be near - // the hand when the findEntities is done. Gather up any hand-children here. - for (h = LEFT_HAND; h <= RIGHT_HAND; h++) { - var handChildrenIDs = findHandChildEntities(h); - handChildrenIDs.forEach(function (handChildID) { - if (handChildID in nearbyEntityPropertiesByID) { - return; - } - var props = Entities.getEntityProperties(handChildID, DISPATCHER_PROPERTIES); - props.id = handChildID; - nearbyEntityPropertiesByID[handChildID] = props; - }); - } - - // also make sure we have the properties from the current module's target - for (var tIDRunningPluginName in _this.runningPluginNames) { - if (_this.runningPluginNames.hasOwnProperty(tIDRunningPluginName)) { - var targetIDs = _this.targetIDs[tIDRunningPluginName]; - if (targetIDs) { - for (var k = 0; k < targetIDs.length; k++) { - var targetID = targetIDs[k]; - if (!nearbyEntityPropertiesByID[targetID]) { - var targetProps = Entities.getEntityProperties(targetID, DISPATCHER_PROPERTIES); - targetProps.id = targetID; - nearbyEntityPropertiesByID[targetID] = targetProps; - } - } - } - } - } - - // bundle up all the data about the current situation - var controllerData = { - triggerValues: [_this.leftTriggerValue, _this.rightTriggerValue], - triggerClicks: [_this.leftTriggerClicked, _this.rightTriggerClicked], - secondaryValues: [_this.leftSecondaryValue, _this.rightSecondaryValue], - controllerLocations: controllerLocations, - nearbyEntityProperties: nearbyEntityProperties, - nearbyEntityPropertiesByID: nearbyEntityPropertiesByID, - nearbyOverlayIDs: nearbyOverlayIDs, - rayPicks: rayPicks, - hudRayPicks: hudRayPicks, - mouseRayPick: mouseRayPick - }; - if (PROFILE) { - Script.endProfileRange("dispatch.gather"); - } - - if (PROFILE) { - Script.beginProfileRange("dispatch.isReady"); - } - // check for plugins that would like to start. ask in order of increasing priority value - for (var pluginIndex = 0; pluginIndex < _this.orderedPluginNames.length; pluginIndex++) { - var orderedPluginName = _this.orderedPluginNames[pluginIndex]; - var candidatePlugin = controllerDispatcherPlugins[orderedPluginName]; - - if (_this.slotsAreAvailableForPlugin(candidatePlugin)) { - if (PROFILE) { - Script.beginProfileRange("dispatch.isReady." + orderedPluginName); - } - var readiness = candidatePlugin.isReady(controllerData, deltaTime); - if (readiness.active) { - // this plugin will start. add it to the list of running plugins and mark the - // activity-slots which this plugin consumes as "in use" - _this.runningPluginNames[orderedPluginName] = true; - _this.markSlots(candidatePlugin, orderedPluginName); - _this.pointerManager.makePointerVisible(candidatePlugin.parameters.handLaser); - if (DEBUG) { - print("controllerDispatcher running " + orderedPluginName); - } - } - if (PROFILE) { - Script.endProfileRange("dispatch.isReady." + orderedPluginName); - } - } - } - if (PROFILE) { - Script.endProfileRange("dispatch.isReady"); - } - - if (PROFILE) { - Script.beginProfileRange("dispatch.run"); - } - // give time to running plugins - for (var runningPluginName in _this.runningPluginNames) { - if (_this.runningPluginNames.hasOwnProperty(runningPluginName)) { - var plugin = controllerDispatcherPlugins[runningPluginName]; - if (!plugin) { - // plugin was deactivated while running. find the activity-slots it was using and make - // them available. - delete _this.runningPluginNames[runningPluginName]; - _this.unmarkSlotsForPluginName(runningPluginName); - } else { - if (PROFILE) { - Script.beginProfileRange("dispatch.run." + runningPluginName); - } - var runningness = plugin.run(controllerData, deltaTime); - - if (DEBUG) { - if (JSON.stringify(_this.targetIDs[runningPluginName]) != JSON.stringify(runningness.targets)) { - print("controllerDispatcher targetIDs[" + runningPluginName + "] = " + - JSON.stringify(runningness.targets)); - } - } - - _this.targetIDs[runningPluginName] = runningness.targets; - if (!runningness.active) { - // plugin is finished running, for now. remove it from the list - // of running plugins and mark its activity-slots as "not in use" - delete _this.runningPluginNames[runningPluginName]; - delete _this.targetIDs[runningPluginName]; - if (DEBUG) { - print("controllerDispatcher deleted targetIDs[" + runningPluginName + "]"); - } - _this.markSlots(plugin, false); - _this.pointerManager.makePointerInvisible(plugin.parameters.handLaser); - if (DEBUG) { - print("controllerDispatcher stopping " + runningPluginName); - } - } - _this.pointerManager.lockPointerEnd(plugin.parameters.handLaser, runningness.laserLockInfo); - if (PROFILE) { - Script.endProfileRange("dispatch.run." + runningPluginName); - } - } - } - } - _this.pointerManager.updatePointersRenderState(controllerData.triggerClicks, controllerData.triggerValues); - if (PROFILE) { - Script.endProfileRange("dispatch.run"); - } - }; - - this.leftBlacklistTabletIDs = []; - this.rightBlacklistTabletIDs = []; - - this.setLeftBlacklist = function () { - Pointers.setIgnoreItems(_this.leftPointer, _this.blacklist.concat(_this.leftBlacklistTabletIDs)); - }; - this.setRightBlacklist = function () { - Pointers.setIgnoreItems(_this.rightPointer, _this.blacklist.concat(_this.rightBlacklistTabletIDs)); - }; - - this.setBlacklist = function() { - _this.setLeftBlacklist(); - _this.setRightBlacklist(); - }; - - var MAPPING_NAME = "com.highfidelity.controllerDispatcher"; - var mapping = Controller.newMapping(MAPPING_NAME); - mapping.from([Controller.Standard.RT]).peek().to(_this.rightTriggerPress); - mapping.from([Controller.Standard.RTClick]).peek().to(_this.rightTriggerClick); - mapping.from([Controller.Standard.LT]).peek().to(_this.leftTriggerPress); - mapping.from([Controller.Standard.LTClick]).peek().to(_this.leftTriggerClick); - - mapping.from([Controller.Standard.RB]).peek().to(_this.rightSecondaryPress); - mapping.from([Controller.Standard.LB]).peek().to(_this.leftSecondaryPress); - mapping.from([Controller.Standard.LeftGrip]).peek().to(_this.leftSecondaryPress); - mapping.from([Controller.Standard.RightGrip]).peek().to(_this.rightSecondaryPress); - - Controller.enableMapping(MAPPING_NAME); - - this.leftPointer = this.pointerManager.createPointer(false, PickType.Ray, { - joint: "_CAMERA_RELATIVE_CONTROLLER_LEFTHAND", - filter: Picks.PICK_OVERLAYS | Picks.PICK_ENTITIES | Picks.PICK_INCLUDE_NONCOLLIDABLE, - triggers: [{action: Controller.Standard.LTClick, button: "Focus"}, {action: Controller.Standard.LTClick, button: "Primary"}], - posOffset: getGrabPointSphereOffset(Controller.Standard.LeftHand, true), - hover: true, - scaleWithParent: true, - distanceScaleEnd: true, - hand: LEFT_HAND - }); - Keyboard.setLeftHandLaser(this.leftPointer); - this.rightPointer = this.pointerManager.createPointer(false, PickType.Ray, { - joint: "_CAMERA_RELATIVE_CONTROLLER_RIGHTHAND", - filter: Picks.PICK_OVERLAYS | Picks.PICK_ENTITIES | Picks.PICK_INCLUDE_NONCOLLIDABLE, - triggers: [{action: Controller.Standard.RTClick, button: "Focus"}, {action: Controller.Standard.RTClick, button: "Primary"}], - posOffset: getGrabPointSphereOffset(Controller.Standard.RightHand, true), - hover: true, - scaleWithParent: true, - distanceScaleEnd: true, - hand: RIGHT_HAND - }); - Keyboard.setRightHandLaser(this.rightPointer); - this.leftHudPointer = this.pointerManager.createPointer(true, PickType.Ray, { - joint: "_CAMERA_RELATIVE_CONTROLLER_LEFTHAND", - filter: Picks.PICK_HUD, - maxDistance: DEFAULT_SEARCH_SPHERE_DISTANCE, - posOffset: getGrabPointSphereOffset(Controller.Standard.LeftHand, true), - triggers: [{action: Controller.Standard.LTClick, button: "Focus"}, {action: Controller.Standard.LTClick, button: "Primary"}], - hover: true, - scaleWithParent: true, - distanceScaleEnd: true, - hand: LEFT_HAND - }); - this.rightHudPointer = this.pointerManager.createPointer(true, PickType.Ray, { - joint: "_CAMERA_RELATIVE_CONTROLLER_RIGHTHAND", - filter: Picks.PICK_HUD, - maxDistance: DEFAULT_SEARCH_SPHERE_DISTANCE, - posOffset: getGrabPointSphereOffset(Controller.Standard.RightHand, true), - triggers: [{action: Controller.Standard.RTClick, button: "Focus"}, {action: Controller.Standard.RTClick, button: "Primary"}], - hover: true, - scaleWithParent: true, - distanceScaleEnd: true, - hand: RIGHT_HAND - }); - - this.mouseRayPick = Pointers.createPointer(PickType.Ray, { - joint: "Mouse", - filter: Picks.PICK_OVERLAYS | Picks.PICK_ENTITIES | Picks.PICK_INCLUDE_NONCOLLIDABLE, - enabled: true - }); - this.handleMessage = function (channel, data, sender) { - var message; - if (sender === MyAvatar.sessionUUID) { - try { - if (channel === 'Hifi-Hand-RayPick-Blacklist') { - message = JSON.parse(data); - var action = message.action; - var id = message.id; - var index = _this.blacklist.indexOf(id); - - if (action === 'add' && index === -1) { - _this.blacklist.push(id); - _this.setBlacklist(); - } - - if (action === 'remove') { - if (index > -1) { - _this.blacklist.splice(index, 1); - _this.setBlacklist(); - } - } - - if (action === "tablet") { - var tabletIDs = message.blacklist ? - [HMD.tabletID, HMD.tabletScreenID, HMD.homeButtonID, HMD.homeButtonHighlightID] : - []; - if (message.hand === LEFT_HAND) { - _this.leftBlacklistTabletIDs = tabletIDs; - _this.setLeftBlacklist(); - } else { - _this.rightBlacklistTabletIDs = tabletIDs; - _this.setRightBlacklist(); - } - } - } - } catch (e) { - print("WARNING: handControllerGrab.js -- error parsing message: " + data); - } - } - }; - - this.cleanup = function () { - Controller.disableMapping(MAPPING_NAME); - _this.pointerManager.removePointers(); - Pointers.removePointer(this.mouseRayPick); - }; - } - - function mouseReleaseOnOverlay(overlayID, event) { - if (HMD.homeButtonID && overlayID === HMD.homeButtonID && event.button === "Primary") { - Messages.sendLocalMessage("home", overlayID); - } - } - - var HAPTIC_STYLUS_STRENGTH = 1.0; - var HAPTIC_STYLUS_DURATION = 20.0; - function mousePress(id, event) { - if (HMD.active) { - var runningPlugins = controllerDispatcher.runningPluginNames; - if (event.id === controllerDispatcher.leftPointer && event.button === "Primary" && runningPlugins.LeftWebSurfaceLaserInput) { - Controller.triggerHapticPulse(HAPTIC_STYLUS_STRENGTH, HAPTIC_STYLUS_DURATION, LEFT_HAND); - } else if (event.id === controllerDispatcher.rightPointer && event.button === "Primary" && runningPlugins.RightWebSurfaceLaserInput) { - Controller.triggerHapticPulse(HAPTIC_STYLUS_STRENGTH, HAPTIC_STYLUS_DURATION, RIGHT_HAND); - } - } - } - - Overlays.mouseReleaseOnOverlay.connect(mouseReleaseOnOverlay); - Overlays.mousePressOnOverlay.connect(mousePress); - Entities.mousePressOnEntity.connect(mousePress); - - var controllerDispatcher = new ControllerDispatcher(); - Messages.subscribe('Hifi-Hand-RayPick-Blacklist'); - Messages.messageReceived.connect(controllerDispatcher.handleMessage); - - Script.scriptEnding.connect(controllerDispatcher.cleanup); - Script.setTimeout(controllerDispatcher.update, BASIC_TIMER_INTERVAL_MS); -}()); diff --git a/scripts/simplifiedUI/system/controllers/controllerDisplay.js b/scripts/simplifiedUI/system/controllers/controllerDisplay.js deleted file mode 100644 index e40b761307..0000000000 --- a/scripts/simplifiedUI/system/controllers/controllerDisplay.js +++ /dev/null @@ -1,292 +0,0 @@ -// -// controllerDisplay.js -// -// Created by Anthony J. Thibault on 10/20/16 -// Originally created by Ryan Huffman on 9/21/2016 -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html - -/* globals createControllerDisplay:true, deleteControllerDisplay:true, Controller, Overlays, Vec3, MyAvatar, Quat */ - -function clamp(value, min, max) { - if (value < min) { - return min; - } else if (value > max) { - return max; - } - return value; -} - -function resolveHardware(path) { - if (typeof path === 'string') { - var parts = path.split("."); - function resolveInner(base, path, i) { - if (i >= path.length) { - return base; - } - return resolveInner(base[path[i]], path, ++i); - } - return resolveInner(Controller.Hardware, parts, 0); - } - return path; -} - -var DEBUG = true; -function debug() { - if (DEBUG) { - var args = Array.prototype.slice.call(arguments); - args.unshift("controllerDisplay.js | "); - print.apply(this, args); - } -} - -createControllerDisplay = function(config) { - var controllerDisplay = { - overlays: [], - partOverlays: {}, - parts: {}, - mappingName: "mapping-display-" + Math.random(), - partValues: {}, - - setVisible: function(visible) { - for (var i = 0; i < this.overlays.length; ++i) { - Overlays.editOverlay(this.overlays[i], { - visible: visible - }); - } - }, - - setPartVisible: function(partName, visible) { - // Disabled - /* - if (partName in this.partOverlays) { - for (var i = 0; i < this.partOverlays[partName].length; ++i) { - Overlays.editOverlay(this.partOverlays[partName][i], { - //visible: visible - }); - } - } - */ - }, - - setLayerForPart: function(partName, layerName) { - if (partName in this.parts) { - var part = this.parts[partName]; - if (part.textureLayers && layerName in part.textureLayers) { - var layer = part.textureLayers[layerName]; - var textures = {}; - if (layer.defaultTextureURL) { - textures[part.textureName] = layer.defaultTextureURL; - } - for (var i = 0; i < this.partOverlays[partName].length; ++i) { - Overlays.editOverlay(this.partOverlays[partName][i], { - textures: textures - }); - } - } - } - }, - - resize: function(sensorScaleFactor) { - if (this.overlays.length >= 0) { - var controller = config.controllers[0]; - var position = controller.position; - - // first overlay is main body. - var overlayID = this.overlays[0]; - var localPosition = Vec3.multiply(sensorScaleFactor, Vec3.sum(Vec3.multiplyQbyV(controller.rotation, controller.naturalPosition), position)); - var dimensions = Vec3.multiply(sensorScaleFactor, controller.dimensions); - - Overlays.editOverlay(overlayID, { - dimensions: dimensions, - localPosition: localPosition - }); - - if (controller.parts) { - var i = 1; - for (var partName in controller.parts) { - overlayID = this.overlays[i++]; - var part = controller.parts[partName]; - localPosition = Vec3.subtract(part.naturalPosition, controller.naturalPosition); - var localRotation; - var value = this.partValues[partName]; - var offset, rotation; - if (value !== undefined) { - if (part.type === "linear") { - offset = Vec3.multiply(part.maxTranslation * value, part.axis); - localPosition = Vec3.sum(localPosition, offset); - localRotation = undefined; - } else if (part.type === "joystick") { - rotation = Quat.fromPitchYawRollDegrees(value.y * part.xHalfAngle, 0, value.x * part.yHalfAngle); - if (part.originOffset) { - offset = Vec3.multiplyQbyV(rotation, part.originOffset); - offset = Vec3.subtract(part.originOffset, offset); - } else { - offset = { x: 0, y: 0, z: 0 }; - } - localPosition = Vec3.sum(offset, localPosition); - localRotation = rotation; - } else if (part.type === "rotational") { - value = clamp(value, part.minValue, part.maxValue); - var pct = (value - part.minValue) / part.maxValue; - var angle = pct * part.maxAngle; - rotation = Quat.angleAxis(angle, part.axis); - if (part.origin) { - offset = Vec3.multiplyQbyV(rotation, part.origin); - offset = Vec3.subtract(offset, part.origin); - } else { - offset = { x: 0, y: 0, z: 0 }; - } - localPosition = Vec3.sum(offset, localPosition); - localRotation = rotation; - } - } - if (localRotation !== undefined) { - Overlays.editOverlay(overlayID, { - dimensions: Vec3.multiply(sensorScaleFactor, part.naturalDimensions), - localPosition: Vec3.multiply(sensorScaleFactor, localPosition), - localRotation: localRotation - }); - } else { - Overlays.editOverlay(overlayID, { - dimensions: Vec3.multiply(sensorScaleFactor, part.naturalDimensions), - localPosition: Vec3.multiply(sensorScaleFactor, localPosition) - }); - } - } - } - } - } - }; - - var mapping = Controller.newMapping(controllerDisplay.mappingName); - for (var i = 0; i < config.controllers.length; ++i) { - var controller = config.controllers[i]; - var position = controller.position; - var sensorScaleFactor = MyAvatar.sensorToWorldScale; - - if (controller.naturalPosition) { - position = Vec3.sum(Vec3.multiplyQbyV(controller.rotation, controller.naturalPosition), position); - } else { - controller.naturalPosition = { x: 0, y: 0, z: 0 }; - } - - var baseOverlayID = Overlays.addOverlay("model", { - url: controller.modelURL, - dimensions: Vec3.multiply(sensorScaleFactor, controller.dimensions), - localRotation: controller.rotation, - localPosition: Vec3.multiply(sensorScaleFactor, position), - parentID: MyAvatar.SELF_ID, - parentJointIndex: controller.jointIndex, - ignoreRayIntersection: true - }); - - controllerDisplay.overlays.push(baseOverlayID); - - if (controller.parts) { - for (var partName in controller.parts) { - var part = controller.parts[partName]; - var localPosition = Vec3.subtract(part.naturalPosition, controller.naturalPosition); - var localRotation = { x: 0, y: 0, z: 0, w: 1 }; - - controllerDisplay.parts[partName] = controller.parts[partName]; - - var properties = { - url: part.modelURL, - localPosition: localPosition, - localRotation: localRotation, - parentID: baseOverlayID, - ignoreRayIntersection: true - }; - - if (part.defaultTextureLayer) { - var textures = {}; - textures[part.textureName] = part.textureLayers[part.defaultTextureLayer].defaultTextureURL; - properties.textures = textures; - } - - var overlayID = Overlays.addOverlay("model", properties); - - if (part.type === "rotational") { - var input = resolveHardware(part.input); - mapping.from([input]).peek().to(function(partName) { - return function(value) { - // insert the most recent controller value into controllerDisplay.partValues. - controllerDisplay.partValues[partName] = value; - controllerDisplay.resize(MyAvatar.sensorToWorldScale); - }; - }(partName)); - } else if (part.type === "touchpad") { - var visibleInput = resolveHardware(part.visibleInput); - var xInput = resolveHardware(part.xInput); - var yInput = resolveHardware(part.yInput); - - // TODO: Touchpad inputs are currently only working for half - // of the touchpad. When that is fixed, it would be useful - // to update these to display the current finger position. - mapping.from([visibleInput]).peek().to(function(value) { - }); - mapping.from([xInput]).peek().to(function(value) { - }); - mapping.from([yInput]).peek().invert().to(function(value) { - }); - } else if (part.type === "joystick") { - (function(part, partName) { - var xInput = resolveHardware(part.xInput); - var yInput = resolveHardware(part.yInput); - mapping.from([xInput]).peek().to(function(value) { - // insert the most recent controller value into controllerDisplay.partValues. - if (controllerDisplay.partValues[partName]) { - controllerDisplay.partValues[partName].x = value; - } else { - controllerDisplay.partValues[partName] = {x: value, y: 0}; - } - controllerDisplay.resize(MyAvatar.sensorToWorldScale); - }); - mapping.from([yInput]).peek().to(function(value) { - // insert the most recent controller value into controllerDisplay.partValues. - if (controllerDisplay.partValues[partName]) { - controllerDisplay.partValues[partName].y = value; - } else { - controllerDisplay.partValues[partName] = {x: 0, y: value}; - } - controllerDisplay.resize(MyAvatar.sensorToWorldScale); - }); - })(part, partName); - - } else if (part.type === "linear") { - (function(part, partName) { - var input = resolveHardware(part.input); - mapping.from([input]).peek().to(function(value) { - // insert the most recent controller value into controllerDisplay.partValues. - controllerDisplay.partValues[partName] = value; - controllerDisplay.resize(MyAvatar.sensorToWorldScale); - }); - })(part, partName); - - } else if (part.type === "static") { - // do nothing - } else { - debug("TYPE NOT SUPPORTED: ", part.type); - } - - controllerDisplay.overlays.push(overlayID); - if (!(partName in controllerDisplay.partOverlays)) { - controllerDisplay.partOverlays[partName] = []; - } - controllerDisplay.partOverlays[partName].push(overlayID); - } - } - } - Controller.enableMapping(controllerDisplay.mappingName); - controllerDisplay.resize(MyAvatar.sensorToWorldScale); - return controllerDisplay; -}; - -deleteControllerDisplay = function(controllerDisplay) { - for (var i = 0; i < controllerDisplay.overlays.length; ++i) { - Overlays.deleteOverlay(controllerDisplay.overlays[i]); - } - Controller.disableMapping(controllerDisplay.mappingName); -}; diff --git a/scripts/simplifiedUI/system/controllers/controllerDisplayManager.js b/scripts/simplifiedUI/system/controllers/controllerDisplayManager.js deleted file mode 100644 index f93f8b1624..0000000000 --- a/scripts/simplifiedUI/system/controllers/controllerDisplayManager.js +++ /dev/null @@ -1,195 +0,0 @@ -// -// controllerDisplayManager.js -// -// Created by Anthony J. Thibault on 10/20/16 -// Originally created by Ryan Huffman on 9/21/2016 -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html - -/* globals ControllerDisplayManager:true, createControllerDisplay, deleteControllerDisplay, - VIVE_CONTROLLER_CONFIGURATION_LEFT, VIVE_CONTROLLER_CONFIGURATION_RIGHT, Script, HMD, Controller, - MyAvatar, Overlays, TOUCH_CONTROLLER_CONFIGURATION_LEFT, TOUCH_CONTROLLER_CONFIGURATION_RIGHT, Messages */ -/* eslint indent: ["error", 4, { "outerIIFEBody": 0 }] */ - -(function () { - -Script.include("controllerDisplay.js"); -Script.include("viveControllerConfiguration.js"); -Script.include("touchControllerConfiguration.js"); - -var HIDE_CONTROLLERS_ON_EQUIP = false; - -// -// Management of controller display -// -ControllerDisplayManager = function() { - var self = this; - var controllerLeft = null; - var controllerRight = null; - var controllerCheckerIntervalID = null; - - this.setLeftVisible = function(visible) { - if (controllerLeft) { - controllerLeft.setVisible(visible); - } - }; - - this.setRightVisible = function(visible) { - if (controllerRight) { - controllerRight.setVisible(visible); - } - }; - - function updateControllers() { - if (HMD.active && HMD.shouldShowHandControllers()) { - var leftConfig = null; - var rightConfig = null; - - if ("Vive" in Controller.Hardware) { - leftConfig = VIVE_CONTROLLER_CONFIGURATION_LEFT; - rightConfig = VIVE_CONTROLLER_CONFIGURATION_RIGHT; - } - - if ("OculusTouch" in Controller.Hardware) { - leftConfig = TOUCH_CONTROLLER_CONFIGURATION_LEFT; - rightConfig = TOUCH_CONTROLLER_CONFIGURATION_RIGHT; - } - - if (leftConfig !== null && rightConfig !== null) { - if (controllerLeft === null) { - controllerLeft = createControllerDisplay(leftConfig); - controllerLeft.setVisible(true); - } - if (controllerRight === null) { - controllerRight = createControllerDisplay(rightConfig); - controllerRight.setVisible(true); - } - // We've found the controllers, we no longer need to look for active controllers - if (controllerCheckerIntervalID) { - Script.clearInterval(controllerCheckerIntervalID); - controllerCheckerIntervalID = null; - } - - } else { - self.deleteControllerDisplays(); - if (!controllerCheckerIntervalID) { - controllerCheckerIntervalID = Script.setInterval(updateControllers, 1000); - } - } - } else { - // We aren't in HMD mode, we no longer need to look for active controllers - if (controllerCheckerIntervalID) { - Script.clearInterval(controllerCheckerIntervalID); - controllerCheckerIntervalID = null; - } - self.deleteControllerDisplays(); - } - } - - function resizeControllers(sensorScaleFactor) { - if (controllerLeft) { - controllerLeft.resize(sensorScaleFactor); - } - if (controllerRight) { - controllerRight.resize(sensorScaleFactor); - } - } - - var handleMessages = function(channel, message, sender) { - var i, data, name, visible; - if (!controllerLeft && !controllerRight) { - return; - } - - if (sender === MyAvatar.sessionUUID) { - if (channel === 'Controller-Display') { - data = JSON.parse(message); - name = data.name; - visible = data.visible; - if (controllerLeft) { - if (name in controllerLeft.annotations) { - for (i = 0; i < controllerLeft.annotations[name].length; ++i) { - Overlays.editOverlay(controllerLeft.annotations[name][i], { visible: visible }); - } - } - } - if (controllerRight) { - if (name in controllerRight.annotations) { - for (i = 0; i < controllerRight.annotations[name].length; ++i) { - Overlays.editOverlay(controllerRight.annotations[name][i], { visible: visible }); - } - } - } - } else if (channel === 'Controller-Display-Parts') { - data = JSON.parse(message); - for (name in data) { - visible = data[name]; - if (controllerLeft) { - controllerLeft.setPartVisible(name, visible); - } - if (controllerRight) { - controllerRight.setPartVisible(name, visible); - } - } - } else if (channel === 'Controller-Set-Part-Layer') { - data = JSON.parse(message); - for (name in data) { - var layer = data[name]; - if (controllerLeft) { - controllerLeft.setLayerForPart(name, layer); - } - if (controllerRight) { - controllerRight.setLayerForPart(name, layer); - } - } - } else if (channel === 'Hifi-Object-Manipulation') { - if (HIDE_CONTROLLERS_ON_EQUIP) { - data = JSON.parse(message); - visible = data.action !== 'equip'; - if (data.joint === "LeftHand") { - self.setLeftVisible(visible); - } else if (data.joint === "RightHand") { - self.setRightVisible(visible); - } - } - } - } - }; - - Messages.messageReceived.connect(handleMessages); - - this.deleteControllerDisplays = function() { - if (controllerLeft) { - deleteControllerDisplay(controllerLeft); - controllerLeft = null; - } - if (controllerRight) { - deleteControllerDisplay(controllerRight); - controllerRight = null; - } - }; - - this.destroy = function() { - Messages.messageReceived.disconnect(handleMessages); - - HMD.displayModeChanged.disconnect(updateControllers); - HMD.shouldShowHandControllersChanged.disconnect(updateControllers); - - self.deleteControllerDisplays(); - }; - - HMD.displayModeChanged.connect(updateControllers); - HMD.shouldShowHandControllersChanged.connect(updateControllers); - MyAvatar.sensorToWorldScaleChanged.connect(resizeControllers); - - updateControllers(); -}; - -var controllerDisplayManager = new ControllerDisplayManager(); - -Script.scriptEnding.connect(function () { - controllerDisplayManager.destroy(); -}); - -}()); diff --git a/scripts/simplifiedUI/system/controllers/controllerModules/disableOtherModule.js b/scripts/simplifiedUI/system/controllers/controllerModules/disableOtherModule.js deleted file mode 100644 index 7636c56f65..0000000000 --- a/scripts/simplifiedUI/system/controllers/controllerModules/disableOtherModule.js +++ /dev/null @@ -1,83 +0,0 @@ -"use strict"; - -// disableOtherModule.js -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html - - -/* global Script, MyAvatar, RIGHT_HAND, LEFT_HAND, enableDispatcherModule, disableDispatcherModule, - makeDispatcherModuleParameters, makeRunningValues, getEnabledModuleByName, Messages -*/ - -Script.include("/~/system/libraries/controllerDispatcherUtils.js"); - -(function() { - function DisableModules(hand) { - this.hand = hand; - this.disableModules = false; - this.parameters = makeDispatcherModuleParameters( - 90, - this.hand === RIGHT_HAND ? - ["rightHand", "rightHandEquip", "rightHandTrigger"] : - ["leftHand", "leftHandEquip", "leftHandTrigger"], - [], - 100); - - this.isReady = function(controllerData) { - if (this.disableModules) { - return makeRunningValues(true, [], []); - } - return false; - }; - - this.run = function(controllerData) { - var teleportModuleName = this.hand === RIGHT_HAND ? "RightTeleporter" : "LeftTeleporter"; - var teleportModule = getEnabledModuleByName(teleportModuleName); - - if (teleportModule) { - var ready = teleportModule.isReady(controllerData); - if (ready.active) { - return makeRunningValues(false, [], []); - } - } - if (!this.disableModules) { - return makeRunningValues(false, [], []); - } - return makeRunningValues(true, [], []); - }; - } - - var leftDisableModules = new DisableModules(LEFT_HAND); - var rightDisableModules = new DisableModules(RIGHT_HAND); - - enableDispatcherModule("LeftDisableModules", leftDisableModules); - enableDispatcherModule("RightDisableModules", rightDisableModules); - function handleMessage(channel, message, sender) { - if (sender === MyAvatar.sessionUUID) { - if (channel === 'Hifi-Hand-Disabler') { - if (message === 'left') { - leftDisableModules.disableModules = true; - } else if (message === 'right') { - rightDisableModules.disableModules = true; - } else if (message === 'both') { - leftDisableModules.disableModules = true; - rightDisableModules.disableModules = true; - } else if (message === 'none') { - leftDisableModules.disableModules = false; - rightDisableModules.disableModules = false; - } else { - print("disableOtherModule -- unknown command: " + message); - } - } - } - } - - Messages.subscribe('Hifi-Hand-Disabler'); - function cleanup() { - disableDispatcherModule("LeftDisableModules"); - disableDispatcherModule("RightDisableModules"); - } - Messages.messageReceived.connect(handleMessage); - Script.scriptEnding.connect(cleanup); -}()); diff --git a/scripts/simplifiedUI/system/controllers/controllerModules/equipEntity.js b/scripts/simplifiedUI/system/controllers/controllerModules/equipEntity.js deleted file mode 100644 index 54b56ff271..0000000000 --- a/scripts/simplifiedUI/system/controllers/controllerModules/equipEntity.js +++ /dev/null @@ -1,867 +0,0 @@ -"use strict"; - -// equipEntity.js -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html - - -/* global Script, Entities, MyAvatar, Controller, RIGHT_HAND, LEFT_HAND, Camera, print, getControllerJointIndex, - enableDispatcherModule, disableDispatcherModule, Messages, makeDispatcherModuleParameters, - makeRunningValues, Settings, entityHasActions, Vec3, Overlays, flatten, Xform, getControllerWorldLocation, ensureDynamic, - entityIsCloneable, cloneEntity, DISPATCHER_PROPERTIES, Uuid, isInEditMode, getGrabbableData, - entityIsEquippable, HMD -*/ - -Script.include("/~/system/libraries/Xform.js"); -Script.include("/~/system/libraries/controllerDispatcherUtils.js"); -Script.include("/~/system/libraries/controllers.js"); -Script.include("/~/system/libraries/cloneEntityUtils.js"); - - -var DEFAULT_SPHERE_MODEL_URL = "http://hifi-content.s3.amazonaws.com/alan/dev/equip-Fresnel-3.fbx"; -var EQUIP_SPHERE_SCALE_FACTOR = 0.65; - - -// Each overlayInfoSet describes a single equip hotspot. -// It is an object with the following keys: -// timestamp - last time this object was updated, used to delete stale hotspot overlays. -// entityID - entity assosicated with this hotspot -// localPosition - position relative to the entity -// hotspot - hotspot object -// overlays - array of overlay objects created by Overlay.addOverlay() -// currentSize - current animated scale value -// targetSize - the target of our scale animations -// type - "sphere" or "model". -function EquipHotspotBuddy() { - // holds map from {string} hotspot.key to {object} overlayInfoSet. - this.map = {}; - - // array of all hotspots that are highlighed. - this.highlightedHotspots = []; -} -EquipHotspotBuddy.prototype.clear = function() { - var keys = Object.keys(this.map); - for (var i = 0; i < keys.length; i++) { - var overlayInfoSet = this.map[keys[i]]; - this.deleteOverlayInfoSet(overlayInfoSet); - } - this.map = {}; - this.highlightedHotspots = []; -}; -EquipHotspotBuddy.prototype.highlightHotspot = function(hotspot) { - this.highlightedHotspots.push(hotspot.key); -}; -EquipHotspotBuddy.prototype.updateHotspot = function(hotspot, timestamp) { - var overlayInfoSet = this.map[hotspot.key]; - if (!overlayInfoSet) { - // create a new overlayInfoSet - overlayInfoSet = { - timestamp: timestamp, - entityID: hotspot.entityID, - localPosition: hotspot.localPosition, - hotspot: hotspot, - currentSize: 0, - targetSize: 1, - overlays: [] - }; - - var dimensions = hotspot.radius * 2 * EQUIP_SPHERE_SCALE_FACTOR; - - if (hotspot.indicatorURL) { - dimensions = hotspot.indicatorScale; - } - - // override default sphere with a user specified model, if it exists. - overlayInfoSet.overlays.push(Overlays.addOverlay("model", { - name: "hotspot overlay", - url: hotspot.indicatorURL ? hotspot.indicatorURL : DEFAULT_SPHERE_MODEL_URL, - position: hotspot.worldPosition, - rotation: { - x: 0, - y: 0, - z: 0, - w: 1 - }, - dimensions: dimensions, - ignoreRayIntersection: true - })); - overlayInfoSet.type = "model"; - this.map[hotspot.key] = overlayInfoSet; - } else { - overlayInfoSet.timestamp = timestamp; - } -}; -EquipHotspotBuddy.prototype.updateHotspots = function(hotspots, timestamp) { - var _this = this; - hotspots.forEach(function(hotspot) { - _this.updateHotspot(hotspot, timestamp); - }); - this.highlightedHotspots = []; -}; -EquipHotspotBuddy.prototype.update = function(deltaTime, timestamp, controllerData) { - - var HIGHLIGHT_SIZE = 1.1; - var NORMAL_SIZE = 1.0; - - var keys = Object.keys(this.map); - for (var i = 0; i < keys.length; i++) { - var overlayInfoSet = this.map[keys[i]]; - - // this overlayInfo is highlighted. - if (this.highlightedHotspots.indexOf(keys[i]) !== -1) { - overlayInfoSet.targetSize = HIGHLIGHT_SIZE; - } else { - overlayInfoSet.targetSize = NORMAL_SIZE; - } - - // start to fade out this hotspot. - if (overlayInfoSet.timestamp !== timestamp) { - overlayInfoSet.targetSize = 0; - } - - // animate the size. - var SIZE_TIMESCALE = 0.1; - var tau = deltaTime / SIZE_TIMESCALE; - if (tau > 1.0) { - tau = 1.0; - } - overlayInfoSet.currentSize += (overlayInfoSet.targetSize - overlayInfoSet.currentSize) * tau; - - if (overlayInfoSet.timestamp !== timestamp && overlayInfoSet.currentSize <= 0.05) { - // this is an old overlay, that has finished fading out, delete it! - overlayInfoSet.overlays.forEach(Overlays.deleteOverlay); - delete this.map[keys[i]]; - } else { - // update overlay position, rotation to follow the object it's attached to. - var props = controllerData.nearbyEntityPropertiesByID[overlayInfoSet.entityID]; - if (props) { - var entityXform = new Xform(props.rotation, props.position); - var position = entityXform.xformPoint(overlayInfoSet.localPosition); - - var dimensions; - if (overlayInfoSet.hotspot.indicatorURL) { - var ratio = overlayInfoSet.currentSize / overlayInfoSet.targetSize; - dimensions = { - x: overlayInfoSet.hotspot.dimensions.x * ratio, - y: overlayInfoSet.hotspot.dimensions.y * ratio, - z: overlayInfoSet.hotspot.dimensions.z * ratio - }; - } else { - dimensions = (overlayInfoSet.hotspot.radius / 2) * overlayInfoSet.currentSize; - } - - overlayInfoSet.overlays.forEach(function(overlay) { - Overlays.editOverlay(overlay, { - position: position, - rotation: props.rotation, - dimensions: dimensions - }); - }); - } else { - overlayInfoSet.overlays.forEach(Overlays.deleteOverlay); - delete this.map[keys[i]]; - } - } - } -}; - - -(function() { - - var ATTACH_POINT_SETTINGS = "io.highfidelity.attachPoints"; - - var HAPTIC_PULSE_STRENGTH = 1.0; - var HAPTIC_PULSE_DURATION = 13.0; - var HAPTIC_TEXTURE_STRENGTH = 0.1; - var HAPTIC_TEXTURE_DURATION = 3.0; - var HAPTIC_TEXTURE_DISTANCE = 0.002; - var HAPTIC_DEQUIP_STRENGTH = 0.75; - var HAPTIC_DEQUIP_DURATION = 50.0; - - var TRIGGER_SMOOTH_RATIO = 0.1; // Time averaging of trigger - 0.0 disables smoothing - var TRIGGER_OFF_VALUE = 0.1; - var TRIGGER_ON_VALUE = TRIGGER_OFF_VALUE + 0.05; // Squeezed just enough to activate search or near grab - var BUMPER_ON_VALUE = 0.5; - var ATTACHPOINT_MAX_DISTANCE = 3.0; - - // var EMPTY_PARENT_ID = "{00000000-0000-0000-0000-000000000000}"; - - var UNEQUIP_KEY = "u"; - - function getWearableData(props) { - if (props.grab.equippable) { - return { - joints: { - LeftHand: [ props.grab.equippableLeftPosition, props.grab.equippableLeftRotation ], - RightHand: [ props.grab.equippableRightPosition, props.grab.equippableRightRotation ] - }, - indicatorURL: props.grab.equippableIndicatorURL, - indicatorScale: props.grab.equippableIndicatorScale, - indicatorOffset: props.grab.equippableIndicatorOffset - }; - } else { - return null; - } - } - - function getAttachPointSettings() { - try { - var str = Settings.getValue(ATTACH_POINT_SETTINGS); - if (str === "false" || str === "") { - return {}; - } else { - return JSON.parse(str); - } - } catch (err) { - print("Error parsing attachPointSettings: " + err); - return {}; - } - } - - function setAttachPointSettings(attachPointSettings) { - var str = JSON.stringify(attachPointSettings); - Settings.setValue(ATTACH_POINT_SETTINGS, str); - } - - function getAttachPointForHotspotFromSettings(hotspot, hand) { - var skeletonModelURL = MyAvatar.skeletonModelURL; - var attachPointSettings = getAttachPointSettings(); - var avatarSettingsData = attachPointSettings[skeletonModelURL]; - if (avatarSettingsData) { - var jointName = (hand === RIGHT_HAND) ? "RightHand" : "LeftHand"; - var joints = avatarSettingsData[hotspot.key]; - if (joints) { - // make sure they are reasonable - if (joints[jointName] && joints[jointName][0] && - Vec3.length(joints[jointName][0]) > ATTACHPOINT_MAX_DISTANCE) { - print("equipEntity -- Warning: rejecting settings attachPoint " + Vec3.length(joints[jointName][0])); - return undefined; - } - return joints[jointName]; - } - } - return undefined; - } - - function storeAttachPointForHotspotInSettings(hotspot, hand, offsetPosition, offsetRotation) { - var attachPointSettings = getAttachPointSettings(); - var skeletonModelURL = MyAvatar.skeletonModelURL; - var avatarSettingsData = attachPointSettings[skeletonModelURL]; - if (!avatarSettingsData) { - avatarSettingsData = {}; - attachPointSettings[skeletonModelURL] = avatarSettingsData; - } - var jointName = (hand === RIGHT_HAND) ? "RightHand" : "LeftHand"; - var joints = avatarSettingsData[hotspot.key]; - if (!joints) { - joints = {}; - avatarSettingsData[hotspot.key] = joints; - } - joints[jointName] = [offsetPosition, offsetRotation]; - setAttachPointSettings(attachPointSettings); - } - - function clearAttachPoints() { - setAttachPointSettings({}); - } - - function EquipEntity(hand) { - this.hand = hand; - this.targetEntityID = null; - this.prevHandIsUpsideDown = false; - this.triggerValue = 0; - this.messageGrabEntity = false; - this.grabEntityProps = null; - this.shouldSendStart = false; - this.equipedWithSecondary = false; - this.handHasBeenRightsideUp = false; - - this.parameters = makeDispatcherModuleParameters( - 115, - this.hand === RIGHT_HAND ? ["rightHand", "rightHandEquip"] : ["leftHand", "leftHandEquip"], - [], - 100); - - var equipHotspotBuddy = new EquipHotspotBuddy(); - - this.setMessageGrabData = function(entityProperties) { - if (entityProperties) { - this.messageGrabEntity = true; - this.grabEntityProps = entityProperties; - } - }; - - // returns a list of all equip-hotspots assosiated with this entity. - // @param {UUID} entityID - // @returns {Object[]} array of objects with the following fields. - // * key {string} a string that can be used to uniquely identify this hotspot - // * entityID {UUID} - // * localPosition {Vec3} position of the hotspot in object space. - // * worldPosition {vec3} position of the hotspot in world space. - // * radius {number} radius of equip hotspot - // * joints {Object} keys are joint names values are arrays of two elements: - // offset position {Vec3} and offset rotation {Quat}, both are in the coordinate system of the joint. - // * indicatorURL {string} url for model to use instead of default sphere. - // * indicatorScale {Vec3} scale factor for model - this.collectEquipHotspots = function(props) { - var result = []; - var entityID = props.id; - var entityXform = new Xform(props.rotation, props.position); - - var wearableProps = getWearableData(props); - var sensorToScaleFactor = MyAvatar.sensorToWorldScale; - if (wearableProps && wearableProps.joints) { - result.push({ - key: entityID.toString() + "0", - entityID: entityID, - localPosition: wearableProps.indicatorOffset, - worldPosition: entityXform.pos, - radius: ((wearableProps.indicatorScale.x + - wearableProps.indicatorScale.y + - wearableProps.indicatorScale.z) / 3) * sensorToScaleFactor, - dimensions: wearableProps.indicatorScale, - joints: wearableProps.joints, - indicatorURL: wearableProps.indicatorURL, - indicatorScale: wearableProps.indicatorScale, - }); - } - return result; - }; - - this.hotspotIsEquippable = function(hotspot, controllerData) { - var props = controllerData.nearbyEntityPropertiesByID[hotspot.entityID]; - - var hasParent = true; - if (props.parentID === Uuid.NULL) { - hasParent = false; - } - - if (hasParent || entityHasActions(hotspot.entityID)) { - return false; - } - - return true; - }; - - this.handToController = function() { - return (this.hand === RIGHT_HAND) ? Controller.Standard.RightHand : Controller.Standard.LeftHand; - }; - - this.updateSmoothedTrigger = function(controllerData) { - var triggerValue = controllerData.triggerValues[this.hand]; - // smooth out trigger value - this.triggerValue = (this.triggerValue * TRIGGER_SMOOTH_RATIO) + - (triggerValue * (1.0 - TRIGGER_SMOOTH_RATIO)); - }; - - this.triggerSmoothedGrab = function() { - return this.triggerClicked; - }; - - this.triggerSmoothedSqueezed = function() { - return this.triggerValue > TRIGGER_ON_VALUE; - }; - - this.triggerSmoothedReleased = function() { - return this.triggerValue < TRIGGER_OFF_VALUE; - }; - - this.secondaryReleased = function() { - return this.rawSecondaryValue < BUMPER_ON_VALUE; - }; - - this.secondarySmoothedSqueezed = function() { - return this.rawSecondaryValue > BUMPER_ON_VALUE; - }; - - this.chooseNearEquipHotspots = function(candidateEntityProps, controllerData) { - var _this = this; - var collectedHotspots = flatten(candidateEntityProps.map(function(props) { - return _this.collectEquipHotspots(props); - })); - var controllerLocation = controllerData.controllerLocations[_this.hand]; - var worldControllerPosition = controllerLocation.position; - var equippableHotspots = collectedHotspots.filter(function(hotspot) { - var hotspotDistance = Vec3.distance(hotspot.worldPosition, worldControllerPosition); - return _this.hotspotIsEquippable(hotspot, controllerData) && - hotspotDistance < hotspot.radius; - }); - return equippableHotspots; - }; - - this.cloneHotspot = function(props, controllerData) { - if (entityIsCloneable(props)) { - var cloneID = cloneEntity(props); - return cloneID; - } - - return null; - }; - - this.chooseBestEquipHotspot = function(candidateEntityProps, controllerData) { - var equippableHotspots = this.chooseNearEquipHotspots(candidateEntityProps, controllerData); - if (equippableHotspots.length > 0) { - // sort by distance; - var controllerLocation = controllerData.controllerLocations[this.hand]; - var worldControllerPosition = controllerLocation.position; - equippableHotspots.sort(function(a, b) { - var aDistance = Vec3.distance(a.worldPosition, worldControllerPosition); - var bDistance = Vec3.distance(b.worldPosition, worldControllerPosition); - return aDistance - bDistance; - }); - return equippableHotspots[0]; - } else { - return null; - } - }; - - this.dropGestureReset = function() { - this.prevHandIsUpsideDown = false; - }; - - this.dropGestureProcess = function (deltaTime) { - var worldHandRotation = getControllerWorldLocation(this.handToController(), true).orientation; - var localHandUpAxis = this.hand === RIGHT_HAND ? { x: 1, y: 0, z: 0 } : { x: -1, y: 0, z: 0 }; - var worldHandUpAxis = Vec3.multiplyQbyV(worldHandRotation, localHandUpAxis); - var DOWN = { x: 0, y: -1, z: 0 }; - - var DROP_ANGLE = Math.PI / 3; - var HYSTERESIS_FACTOR = 1.1; - var ROTATION_ENTER_THRESHOLD = Math.cos(DROP_ANGLE); - var ROTATION_EXIT_THRESHOLD = Math.cos(DROP_ANGLE * HYSTERESIS_FACTOR); - var rotationThreshold = this.prevHandIsUpsideDown ? ROTATION_EXIT_THRESHOLD : ROTATION_ENTER_THRESHOLD; - - var handIsUpsideDown = false; - if (Vec3.dot(worldHandUpAxis, DOWN) > rotationThreshold) { - handIsUpsideDown = true; - } - - if (handIsUpsideDown !== this.prevHandIsUpsideDown) { - this.prevHandIsUpsideDown = handIsUpsideDown; - Controller.triggerHapticPulse(HAPTIC_DEQUIP_STRENGTH, HAPTIC_DEQUIP_DURATION, this.hand); - } - - return handIsUpsideDown; - }; - - this.clearEquipHaptics = function() { - this.prevPotentialEquipHotspot = null; - }; - - this.updateEquipHaptics = function(potentialEquipHotspot, currentLocation) { - if (potentialEquipHotspot && !this.prevPotentialEquipHotspot || - !potentialEquipHotspot && this.prevPotentialEquipHotspot) { - Controller.triggerHapticPulse(HAPTIC_TEXTURE_STRENGTH, HAPTIC_TEXTURE_DURATION, this.hand); - this.lastHapticPulseLocation = currentLocation; - } else if (potentialEquipHotspot && - Vec3.distance(this.lastHapticPulseLocation, currentLocation) > HAPTIC_TEXTURE_DISTANCE) { - Controller.triggerHapticPulse(HAPTIC_TEXTURE_STRENGTH, HAPTIC_TEXTURE_DURATION, this.hand); - this.lastHapticPulseLocation = currentLocation; - } - this.prevPotentialEquipHotspot = potentialEquipHotspot; - }; - - this.startEquipEntity = function (controllerData) { - var _this = this; - - this.dropGestureReset(); - this.clearEquipHaptics(); - Controller.triggerHapticPulse(HAPTIC_PULSE_STRENGTH, HAPTIC_PULSE_DURATION, this.hand); - - var grabbedProperties = Entities.getEntityProperties(this.targetEntityID, DISPATCHER_PROPERTIES); - var grabData = getGrabbableData(grabbedProperties); - - // if an object is "equipped" and has a predefined offset, use it. - if (this.grabbedHotspot) { - var offsets = getAttachPointForHotspotFromSettings(this.grabbedHotspot, this.hand); - if (offsets) { - this.offsetPosition = offsets[0]; - this.offsetRotation = offsets[1]; - } else { - var handJointName = this.hand === RIGHT_HAND ? "RightHand" : "LeftHand"; - if (this.grabbedHotspot.joints[handJointName]) { - this.offsetPosition = this.grabbedHotspot.joints[handJointName][0]; - this.offsetRotation = this.grabbedHotspot.joints[handJointName][1]; - } - } - } - - var handJointIndex; - if (HMD.mounted && HMD.isHandControllerAvailable() && grabData.grabFollowsController) { - handJointIndex = this.controllerJointIndex; - } else { - handJointIndex = MyAvatar.getJointIndex(this.hand === RIGHT_HAND ? "RightHand" : "LeftHand"); - } - - var reparentProps = { - parentID: MyAvatar.SELF_ID, - parentJointIndex: handJointIndex, - localVelocity: {x: 0, y: 0, z: 0}, - localAngularVelocity: {x: 0, y: 0, z: 0}, - localPosition: this.offsetPosition, - localRotation: this.offsetRotation - }; - - var isClone = false; - if (entityIsCloneable(grabbedProperties)) { - var cloneID = this.cloneHotspot(grabbedProperties, controllerData); - this.targetEntityID = cloneID; - controllerData.nearbyEntityPropertiesByID[this.targetEntityID] = grabbedProperties; - isClone = true; - } else if (grabbedProperties.locked) { - this.grabbedHotspot = null; - this.targetEntityID = null; - return; - } - - - // HACK -- when - // https://highfidelity.fogbugz.com/f/cases/21767/entity-edits-shortly-after-an-add-often-fail - // is resolved, this can just be an editEntity rather than a setTimeout. - this.editDelayTimeout = Script.setTimeout(function () { - _this.editDelayTimeout = null; - Entities.editEntity(_this.targetEntityID, reparentProps); - }, 100); - - // we don't want to send startEquip message until the trigger is released. otherwise, - // guns etc will fire right as they are equipped. - this.shouldSendStart = true; - - Messages.sendMessage('Hifi-Object-Manipulation', JSON.stringify({ - action: 'equip', - grabbedEntity: this.targetEntityID, - joint: this.hand === RIGHT_HAND ? "RightHand" : "LeftHand" - })); - - var grabEquipCheck = function() { - var args = [_this.hand === RIGHT_HAND ? "right" : "left", MyAvatar.sessionUUID]; - Entities.callEntityMethod(_this.targetEntityID, "startEquip", args); - }; - - if (isClone) { - // 100 ms seems to be sufficient time to force the check even occur after the object has been initialized. - Script.setTimeout(grabEquipCheck, 100); - } - }; - - this.endEquipEntity = function () { - - if (this.editDelayTimeout) { - Script.clearTimeout(this.editDelayTimeout); - this.editDelayTimeout = null; - } - - this.storeAttachPointInSettings(); - Entities.editEntity(this.targetEntityID, { - parentID: Uuid.NULL, - parentJointIndex: -1 - }); - - var args = [this.hand === RIGHT_HAND ? "right" : "left", MyAvatar.sessionUUID]; - Entities.callEntityMethod(this.targetEntityID, "releaseEquip", args); - - Messages.sendMessage('Hifi-Object-Manipulation', JSON.stringify({ - action: 'release', - grabbedEntity: this.targetEntityID, - joint: this.hand === RIGHT_HAND ? "RightHand" : "LeftHand" - })); - - ensureDynamic(this.targetEntityID); - this.targetEntityID = null; - this.messageGrabEntity = false; - this.grabEntityProps = null; - }; - - this.updateInputs = function (controllerData) { - this.rawTriggerValue = controllerData.triggerValues[this.hand]; - this.triggerClicked = controllerData.triggerClicks[this.hand]; - this.rawSecondaryValue = controllerData.secondaryValues[this.hand]; - this.updateSmoothedTrigger(controllerData); - }; - - this.checkNearbyHotspots = function (controllerData, deltaTime, timestamp) { - this.controllerJointIndex = getControllerJointIndex(this.hand); - - if (this.triggerSmoothedReleased() && this.secondaryReleased()) { - this.waitForTriggerRelease = false; - } - - var controllerLocation = getControllerWorldLocation(this.handToController(), true); - var worldHandPosition = controllerLocation.position; - var candidateEntityProps = controllerData.nearbyEntityProperties[this.hand]; - - - var potentialEquipHotspot = null; - if (this.messageGrabEntity) { - var hotspots = this.collectEquipHotspots(this.grabEntityProps); - if (hotspots.length > -1) { - potentialEquipHotspot = hotspots[0]; - } - } else { - potentialEquipHotspot = this.chooseBestEquipHotspot(candidateEntityProps, controllerData); - } - - if (!this.waitForTriggerRelease) { - this.updateEquipHaptics(potentialEquipHotspot, worldHandPosition); - } - - var nearEquipHotspots = this.chooseNearEquipHotspots(candidateEntityProps, controllerData); - equipHotspotBuddy.updateHotspots(nearEquipHotspots, timestamp); - if (potentialEquipHotspot) { - equipHotspotBuddy.highlightHotspot(potentialEquipHotspot); - } - - equipHotspotBuddy.update(deltaTime, timestamp, controllerData); - - // if the potentialHotspot is cloneable, clone it and return it - // if the potentialHotspot is not cloneable and locked return null - if (potentialEquipHotspot && - (((this.triggerSmoothedSqueezed() || this.secondarySmoothedSqueezed()) && !this.waitForTriggerRelease) || - this.messageGrabEntity)) { - this.grabbedHotspot = potentialEquipHotspot; - this.targetEntityID = this.grabbedHotspot.entityID; - this.startEquipEntity(controllerData); - this.equipedWithSecondary = this.secondarySmoothedSqueezed(); - return makeRunningValues(true, [this.targetEntityID], []); - } else { - return makeRunningValues(false, [], []); - } - }; - - this.isTargetIDValid = function(controllerData) { - var entityProperties = controllerData.nearbyEntityPropertiesByID[this.targetEntityID]; - return entityProperties && "type" in entityProperties; - }; - - this.isReady = function (controllerData, deltaTime) { - var timestamp = Date.now(); - this.updateInputs(controllerData); - this.handHasBeenRightsideUp = false; - return this.checkNearbyHotspots(controllerData, deltaTime, timestamp); - }; - - this.run = function (controllerData, deltaTime) { - var timestamp = Date.now(); - this.updateInputs(controllerData); - - if (!this.messageGrabEntity && !this.isTargetIDValid(controllerData)) { - this.endEquipEntity(); - return makeRunningValues(false, [], []); - } - - if (!this.targetEntityID) { - return this.checkNearbyHotspots(controllerData, deltaTime, timestamp); - } - - if (controllerData.secondaryValues[this.hand] && !this.equipedWithSecondary) { - // this.secondaryReleased() will always be true when not depressed - // so we cannot simply rely on that for release - ensure that the - // trigger was first "prepared" by being pushed in before the release - this.preparingHoldRelease = true; - } - - if (this.preparingHoldRelease && !controllerData.secondaryValues[this.hand]) { - // we have an equipped object and the secondary trigger was released - // short-circuit the other checks and release it - this.preparingHoldRelease = false; - this.endEquipEntity(); - return makeRunningValues(false, [], []); - } - - var handIsUpsideDown = this.dropGestureProcess(deltaTime); - var dropDetected = false; - if (this.handHasBeenRightsideUp) { - dropDetected = handIsUpsideDown; - } - if (!handIsUpsideDown) { - this.handHasBeenRightsideUp = true; - } - - if (this.triggerSmoothedReleased() || this.secondaryReleased()) { - if (this.shouldSendStart) { - // we don't want to send startEquip message until the trigger is released. otherwise, - // guns etc will fire right as they are equipped. - var startArgs = [this.hand === RIGHT_HAND ? "right" : "left", MyAvatar.sessionUUID]; - Entities.callEntityMethod(this.targetEntityID, "startEquip", startArgs); - this.shouldSendStart = false; - } - this.waitForTriggerRelease = false; - if (this.secondaryReleased() && this.equipedWithSecondary) { - this.equipedWithSecondary = false; - } - } - - if (dropDetected && this.prevDropDetected !== dropDetected) { - this.waitForTriggerRelease = true; - } - - // highlight the grabbed hotspot when the dropGesture is detected. - if (dropDetected && this.grabbedHotspot) { - equipHotspotBuddy.updateHotspot(this.grabbedHotspot, timestamp); - equipHotspotBuddy.highlightHotspot(this.grabbedHotspot); - } - - if (dropDetected && !this.waitForTriggerRelease && this.triggerSmoothedGrab()) { - this.waitForTriggerRelease = true; - // store the offset attach points into preferences. - this.endEquipEntity(); - return makeRunningValues(false, [], []); - } - this.prevDropDetected = dropDetected; - - equipHotspotBuddy.update(deltaTime, timestamp, controllerData); - - if (!this.shouldSendStart) { - var args = [this.hand === RIGHT_HAND ? "right" : "left", MyAvatar.sessionUUID]; - Entities.callEntityMethod(this.targetEntityID, "continueEquip", args); - } - - return makeRunningValues(true, [this.targetEntityID], []); - }; - - this.storeAttachPointInSettings = function() { - if (this.grabbedHotspot && this.targetEntityID) { - var prefProps = Entities.getEntityProperties(this.targetEntityID, ["localPosition", "localRotation"]); - if (prefProps && prefProps.localPosition && prefProps.localRotation) { - storeAttachPointForHotspotInSettings(this.grabbedHotspot, this.hand, - prefProps.localPosition, prefProps.localRotation); - } - } - }; - - this.cleanup = function () { - if (this.targetEntityID) { - this.endEquipEntity(); - } - }; - } - - var handleMessage = function(channel, message, sender) { - var data; - if (sender === MyAvatar.sessionUUID) { - if (channel === 'Hifi-Hand-Grab') { - try { - data = JSON.parse(message); - var equipModule = (data.hand === "left") ? leftEquipEntity : rightEquipEntity; - var entityProperties = Entities.getEntityProperties(data.entityID, DISPATCHER_PROPERTIES); - entityProperties.id = data.entityID; - equipModule.setMessageGrabData(entityProperties); - } catch (e) { - print("WARNING: equipEntity.js -- error parsing Hifi-Hand-Grab message: " + message); - } - } else if (channel === 'Hifi-Hand-Drop') { - if (message === "left") { - leftEquipEntity.endEquipEntity(); - } else if (message === "right") { - rightEquipEntity.endEquipEntity(); - } else if (message === "both") { - leftEquipEntity.endEquipEntity(); - rightEquipEntity.endEquipEntity(); - } - } - } - }; - - var clearGrabActions = function(entityID) { - var actionIDs = Entities.getActionIDs(entityID); - var myGrabTag = "grab-" + MyAvatar.sessionUUID; - for (var actionIndex = 0; actionIndex < actionIDs.length; actionIndex++) { - var actionID = actionIDs[actionIndex]; - var actionArguments = Entities.getActionArguments(entityID, actionID); - var tag = actionArguments.tag; - if (tag === myGrabTag) { - Entities.deleteAction(entityID, actionID); - } - } - }; - - var onMousePress = function(event) { - if (isInEditMode() || !event.isLeftButton) { // don't consider any left clicks on the entity while in edit - return; - } - var pickRay = Camera.computePickRay(event.x, event.y); - var intersection = Entities.findRayIntersection(pickRay, true); - if (intersection.intersects) { - var entityID = intersection.entityID; - var entityProperties = Entities.getEntityProperties(entityID, DISPATCHER_PROPERTIES); - entityProperties.id = entityID; - var hasEquipData = getWearableData(entityProperties); - if (hasEquipData && entityIsEquippable(entityProperties)) { - entityProperties.id = entityID; - var rightHandPosition = MyAvatar.getJointPosition("RightHand"); - var leftHandPosition = MyAvatar.getJointPosition("LeftHand"); - var distanceToRightHand = Vec3.distance(entityProperties.position, rightHandPosition); - var distanceToLeftHand = Vec3.distance(entityProperties.position, leftHandPosition); - var leftHandAvailable = leftEquipEntity.targetEntityID === null; - var rightHandAvailable = rightEquipEntity.targetEntityID === null; - if (rightHandAvailable && (distanceToRightHand < distanceToLeftHand || !leftHandAvailable)) { - // clear any existing grab actions on the entity now (their later removal could affect bootstrapping flags) - clearGrabActions(entityID); - rightEquipEntity.setMessageGrabData(entityProperties); - } else if (leftHandAvailable && (distanceToLeftHand < distanceToRightHand || !rightHandAvailable)) { - // clear any existing grab actions on the entity now (their later removal could affect bootstrapping flags) - clearGrabActions(entityID); - leftEquipEntity.setMessageGrabData(entityProperties); - } - } - } - }; - - var onKeyPress = function(event) { - if (event.text.toLowerCase() === UNEQUIP_KEY) { - if (rightEquipEntity.targetEntityID) { - rightEquipEntity.endEquipEntity(); - } - if (leftEquipEntity.targetEntityID) { - leftEquipEntity.endEquipEntity(); - } - } - }; - - var deleteEntity = function(entityID) { - if (rightEquipEntity.targetEntityID === entityID) { - rightEquipEntity.endEquipEntity(); - } - if (leftEquipEntity.targetEntityID === entityID) { - leftEquipEntity.endEquipEntity(); - } - }; - - var clearEntities = function() { - if (rightEquipEntity.targetEntityID) { - rightEquipEntity.endEquipEntity(); - } - if (leftEquipEntity.targetEntityID) { - leftEquipEntity.endEquipEntity(); - } - }; - - Messages.subscribe('Hifi-Hand-Grab'); - Messages.subscribe('Hifi-Hand-Drop'); - Messages.messageReceived.connect(handleMessage); - Controller.mousePressEvent.connect(onMousePress); - Controller.keyPressEvent.connect(onKeyPress); - Entities.deletingEntity.connect(deleteEntity); - Entities.clearingEntities.connect(clearEntities); - - var leftEquipEntity = new EquipEntity(LEFT_HAND); - var rightEquipEntity = new EquipEntity(RIGHT_HAND); - - enableDispatcherModule("LeftEquipEntity", leftEquipEntity); - enableDispatcherModule("RightEquipEntity", rightEquipEntity); - - function cleanup() { - leftEquipEntity.cleanup(); - rightEquipEntity.cleanup(); - disableDispatcherModule("LeftEquipEntity"); - disableDispatcherModule("RightEquipEntity"); - clearAttachPoints(); - Messages.messageReceived.disconnect(handleMessage); - Controller.mousePressEvent.disconnect(onMousePress); - Controller.keyPressEvent.disconnect(onKeyPress); - Entities.deletingEntity.disconnect(deleteEntity); - Entities.clearingEntities.disconnect(clearEntities); - } - Script.scriptEnding.connect(cleanup); -}()); diff --git a/scripts/simplifiedUI/system/controllers/controllerModules/farActionGrabEntity.js b/scripts/simplifiedUI/system/controllers/controllerModules/farActionGrabEntity.js deleted file mode 100644 index 1eaed44ce2..0000000000 --- a/scripts/simplifiedUI/system/controllers/controllerModules/farActionGrabEntity.js +++ /dev/null @@ -1,591 +0,0 @@ -"use strict"; - -// farActionGrabEntity.js -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html - -/* jslint bitwise: true */ - -/* global Script, Controller, RIGHT_HAND, LEFT_HAND, Mat4, MyAvatar, Vec3, Camera, Quat, - getEnabledModuleByName, makeRunningValues, Entities, - enableDispatcherModule, disableDispatcherModule, entityIsDistanceGrabbable, entityIsGrabbable, - makeDispatcherModuleParameters, MSECS_PER_SEC, HAPTIC_PULSE_STRENGTH, HAPTIC_PULSE_DURATION, - TRIGGER_OFF_VALUE, TRIGGER_ON_VALUE, ZERO_VEC, ensureDynamic, - getControllerWorldLocation, projectOntoEntityXYPlane, ContextOverlay, HMD, - Picks, makeLaserLockInfo, makeLaserParams, AddressManager, getEntityParents, Selection, DISPATCHER_HOVERING_LIST, - worldPositionToRegistrationFrameMatrix, DISPATCHER_PROPERTIES, Uuid, Picks -*/ - -Script.include("/~/system/libraries/controllerDispatcherUtils.js"); -Script.include("/~/system/libraries/controllers.js"); - -(function() { - - var MARGIN = 25; - - function TargetObject(entityID, entityProps) { - this.entityID = entityID; - this.entityProps = entityProps; - this.targetEntityID = null; - this.targetEntityProps = null; - this.previousCollisionStatus = null; - this.madeDynamic = null; - - this.makeDynamic = function() { - if (this.targetEntityID) { - var newProps = { - dynamic: true, - collisionless: true - }; - this.previousCollisionStatus = this.targetEntityProps.collisionless; - Entities.editEntity(this.targetEntityID, newProps); - this.madeDynamic = true; - } - }; - - this.restoreTargetEntityOriginalProps = function() { - if (this.madeDynamic) { - var props = {}; - props.dynamic = false; - props.collisionless = this.previousCollisionStatus; - var zeroVector = {x: 0, y: 0, z:0}; - props.localVelocity = zeroVector; - props.localRotation = zeroVector; - Entities.editEntity(this.targetEntityID, props); - } - }; - - this.getTargetEntity = function() { - var parentPropsLength = this.parentProps.length; - if (parentPropsLength !== 0) { - var targetEntity = { - id: this.parentProps[parentPropsLength - 1].id, - props: this.parentProps[parentPropsLength - 1]}; - this.targetEntityID = targetEntity.id; - this.targetEntityProps = targetEntity.props; - return targetEntity; - } - this.targetEntityID = this.entityID; - this.targetEntityProps = this.entityProps; - return { - id: this.entityID, - props: this.entityProps}; - }; - } - - function FarActionGrabEntity(hand) { - this.hand = hand; - this.grabbedThingID = null; - this.targetObject = null; - this.actionID = null; // action this script created... - this.entityToLockOnto = null; - this.potentialEntityWithContextOverlay = false; - this.entityWithContextOverlay = false; - this.contextOverlayTimer = false; - this.locked = false; - this.reticleMinX = MARGIN; - this.reticleMaxX = null; - this.reticleMinY = MARGIN; - this.reticleMaxY = null; - - this.ignoredEntities = []; - - var ACTION_TTL = 15; // seconds - - var DISTANCE_HOLDING_RADIUS_FACTOR = 3.5; // multiplied by distance between hand and object - var DISTANCE_HOLDING_ACTION_TIMEFRAME = 0.1; // how quickly objects move to their new position - var DISTANCE_HOLDING_UNITY_MASS = 1200; // The mass at which the distance holding action timeframe is unmodified - var DISTANCE_HOLDING_UNITY_DISTANCE = 6; // The distance at which the distance holding action timeframe is unmodified - - this.parameters = makeDispatcherModuleParameters( - 550, - this.hand === RIGHT_HAND ? ["rightHand"] : ["leftHand"], - [], - 100, - makeLaserParams(this.hand, false)); - - - this.handToController = function() { - return (this.hand === RIGHT_HAND) ? Controller.Standard.RightHand : Controller.Standard.LeftHand; - }; - - this.distanceGrabTimescale = function(mass, distance) { - var timeScale = DISTANCE_HOLDING_ACTION_TIMEFRAME * mass / - DISTANCE_HOLDING_UNITY_MASS * distance / - DISTANCE_HOLDING_UNITY_DISTANCE; - if (timeScale < DISTANCE_HOLDING_ACTION_TIMEFRAME) { - timeScale = DISTANCE_HOLDING_ACTION_TIMEFRAME; - } - return timeScale; - }; - - this.getMass = function(dimensions, density) { - return (dimensions.x * dimensions.y * dimensions.z) * density; - }; - - this.startFarGrabAction = function (controllerData, grabbedProperties) { - var controllerLocation = controllerData.controllerLocations[this.hand]; - var worldControllerPosition = controllerLocation.position; - var worldControllerRotation = controllerLocation.orientation; - - // transform the position into room space - var worldToSensorMat = Mat4.inverse(MyAvatar.getSensorToWorldMatrix()); - var roomControllerPosition = Mat4.transformPoint(worldToSensorMat, worldControllerPosition); - - var now = Date.now(); - - // add the action and initialize some variables - this.currentObjectPosition = grabbedProperties.position; - this.currentObjectRotation = grabbedProperties.rotation; - this.currentObjectTime = now; - this.currentCameraOrientation = Camera.orientation; - - this.grabRadius = this.grabbedDistance; - this.grabRadialVelocity = 0.0; - - // offset between controller vector at the grab radius and the entity position - var targetPosition = Vec3.multiply(this.grabRadius, Quat.getUp(worldControllerRotation)); - targetPosition = Vec3.sum(targetPosition, worldControllerPosition); - this.offsetPosition = Vec3.subtract(this.currentObjectPosition, targetPosition); - - // compute a constant based on the initial conditions which we use below to exaggerate hand motion - // onto the held object - this.radiusScalar = Math.log(this.grabRadius + 1.0); - if (this.radiusScalar < 1.0) { - this.radiusScalar = 1.0; - } - - // compute the mass for the purpose of energy and how quickly to move object - this.mass = this.getMass(grabbedProperties.dimensions, grabbedProperties.density); - var distanceToObject = Vec3.length(Vec3.subtract(MyAvatar.position, grabbedProperties.position)); - var timeScale = this.distanceGrabTimescale(this.mass, distanceToObject); - this.linearTimeScale = timeScale; - this.actionID = Entities.addAction("far-grab", this.grabbedThingID, { - targetPosition: this.currentObjectPosition, - linearTimeScale: timeScale, - targetRotation: this.currentObjectRotation, - angularTimeScale: timeScale, - tag: "far-grab-" + MyAvatar.sessionUUID, - ttl: ACTION_TTL - }); - if (this.actionID === Uuid.NULL) { - this.actionID = null; - } - - if (this.actionID !== null) { - var args = [this.hand === RIGHT_HAND ? "right" : "left", MyAvatar.sessionUUID]; - Entities.callEntityMethod(this.grabbedThingID, "startDistanceGrab", args); - } - - Controller.triggerHapticPulse(HAPTIC_PULSE_STRENGTH, HAPTIC_PULSE_DURATION, this.hand); - this.previousRoomControllerPosition = roomControllerPosition; - }; - - this.continueDistanceHolding = function(controllerData) { - var controllerLocation = controllerData.controllerLocations[this.hand]; - var worldControllerPosition = controllerLocation.position; - var worldControllerRotation = controllerLocation.orientation; - - // also transform the position into room space - var worldToSensorMat = Mat4.inverse(MyAvatar.getSensorToWorldMatrix()); - var roomControllerPosition = Mat4.transformPoint(worldToSensorMat, worldControllerPosition); - - var grabbedProperties = Entities.getEntityProperties(this.grabbedThingID, DISPATCHER_PROPERTIES); - var now = Date.now(); - var deltaObjectTime = (now - this.currentObjectTime) / MSECS_PER_SEC; // convert to seconds - this.currentObjectTime = now; - - // the action was set up when this.distanceHolding was called. update the targets. - var radius = Vec3.distance(this.currentObjectPosition, worldControllerPosition) * - this.radiusScalar * DISTANCE_HOLDING_RADIUS_FACTOR; - if (radius < 1.0) { - radius = 1.0; - } - - var roomHandDelta = Vec3.subtract(roomControllerPosition, this.previousRoomControllerPosition); - var worldHandDelta = Mat4.transformVector(MyAvatar.getSensorToWorldMatrix(), roomHandDelta); - var handMoved = Vec3.multiply(worldHandDelta, radius); - this.currentObjectPosition = Vec3.sum(this.currentObjectPosition, handMoved); - - var args = [this.hand === RIGHT_HAND ? "right" : "left", MyAvatar.sessionUUID]; - Entities.callEntityMethod(this.grabbedThingID, "continueDistanceGrab", args); - - // Update radialVelocity - var lastVelocity = Vec3.multiply(worldHandDelta, 1.0 / deltaObjectTime); - var delta = Vec3.normalize(Vec3.subtract(grabbedProperties.position, worldControllerPosition)); - var newRadialVelocity = Vec3.dot(lastVelocity, delta); - - var VELOCITY_AVERAGING_TIME = 0.016; - var blendFactor = deltaObjectTime / VELOCITY_AVERAGING_TIME; - if (blendFactor < 0.0) { - blendFactor = 0.0; - } else if (blendFactor > 1.0) { - blendFactor = 1.0; - } - this.grabRadialVelocity = blendFactor * newRadialVelocity + (1.0 - blendFactor) * this.grabRadialVelocity; - - var RADIAL_GRAB_AMPLIFIER = 10.0; - if (Math.abs(this.grabRadialVelocity) > 0.0) { - this.grabRadius = this.grabRadius + (this.grabRadialVelocity * deltaObjectTime * - this.grabRadius * RADIAL_GRAB_AMPLIFIER); - } - - // don't let grabRadius go all the way to zero, because it can't come back from that - var MINIMUM_GRAB_RADIUS = 0.1; - if (this.grabRadius < MINIMUM_GRAB_RADIUS) { - this.grabRadius = MINIMUM_GRAB_RADIUS; - } - var newTargetPosition = Vec3.multiply(this.grabRadius, Quat.getUp(worldControllerRotation)); - newTargetPosition = Vec3.sum(newTargetPosition, worldControllerPosition); - newTargetPosition = Vec3.sum(newTargetPosition, this.offsetPosition); - - // XXX - // this.maybeScale(grabbedProperties); - - var distanceToObject = Vec3.length(Vec3.subtract(MyAvatar.position, this.currentObjectPosition)); - - this.linearTimeScale = (this.linearTimeScale / 2); - if (this.linearTimeScale <= DISTANCE_HOLDING_ACTION_TIMEFRAME) { - this.linearTimeScale = DISTANCE_HOLDING_ACTION_TIMEFRAME; - } - var success = Entities.updateAction(this.grabbedThingID, this.actionID, { - targetPosition: newTargetPosition, - linearTimeScale: this.linearTimeScale, - targetRotation: this.currentObjectRotation, - angularTimeScale: this.distanceGrabTimescale(this.mass, distanceToObject), - ttl: ACTION_TTL - }); - if (!success) { - print("continueDistanceHolding -- updateAction failed: " + this.actionID); - this.actionID = null; - } - - this.previousRoomControllerPosition = roomControllerPosition; - }; - - this.endFarGrabAction = function () { - ensureDynamic(this.grabbedThingID); - this.distanceHolding = false; - this.distanceRotating = false; - Entities.deleteAction(this.grabbedThingID, this.actionID); - - var args = [this.hand === RIGHT_HAND ? "right" : "left", MyAvatar.sessionUUID]; - Entities.callEntityMethod(this.grabbedThingID, "releaseGrab", args); - if (this.targetObject) { - this.targetObject.restoreTargetEntityOriginalProps(); - } - this.actionID = null; - this.grabbedThingID = null; - this.targetObject = null; - this.potentialEntityWithContextOverlay = false; - }; - - this.updateRecommendedArea = function() { - var dims = Controller.getViewportDimensions(); - this.reticleMaxX = dims.x - MARGIN; - this.reticleMaxY = dims.y - MARGIN; - }; - - this.calculateNewReticlePosition = function(intersection) { - this.updateRecommendedArea(); - var point2d = HMD.overlayFromWorldPoint(intersection); - point2d.x = Math.max(this.reticleMinX, Math.min(point2d.x, this.reticleMaxX)); - point2d.y = Math.max(this.reticleMinY, Math.min(point2d.y, this.reticleMaxY)); - return point2d; - }; - - this.restoreIgnoredEntities = function() { - for (var i = 0; i < this.ignoredEntities.length; i++) { - var data = { - action: 'remove', - id: this.ignoredEntities[i] - }; - Messages.sendMessage('Hifi-Hand-RayPick-Blacklist', JSON.stringify(data)); - } - this.ignoredEntities = []; - }; - - this.notPointingAtEntity = function(controllerData) { - var intersection = controllerData.rayPicks[this.hand]; - var entityProperty = Entities.getEntityProperties(intersection.objectID, DISPATCHER_PROPERTIES); - var entityType = entityProperty.type; - var hudRayPick = controllerData.hudRayPicks[this.hand]; - var point2d = this.calculateNewReticlePosition(hudRayPick.intersection); - if ((intersection.type === Picks.INTERSECTED_ENTITY && entityType === "Web") || - intersection.type === Picks.INTERSECTED_OVERLAY || Window.isPointOnDesktopWindow(point2d)) { - return true; - } - return false; - }; - - this.distanceRotate = function(otherFarGrabModule) { - this.distanceRotating = true; - this.distanceHolding = false; - - var worldControllerRotation = getControllerWorldLocation(this.handToController(), true).orientation; - var controllerRotationDelta = - Quat.multiply(worldControllerRotation, Quat.inverse(this.previousWorldControllerRotation)); - // Rotate entity by twice the delta rotation. - controllerRotationDelta = Quat.multiply(controllerRotationDelta, controllerRotationDelta); - - // Perform the rotation in the translation controller's action update. - otherFarGrabModule.currentObjectRotation = Quat.multiply(controllerRotationDelta, - otherFarGrabModule.currentObjectRotation); - - this.previousWorldControllerRotation = worldControllerRotation; - }; - - this.prepareDistanceRotatingData = function(controllerData) { - var intersection = controllerData.rayPicks[this.hand]; - - var controllerLocation = getControllerWorldLocation(this.handToController(), true); - var worldControllerPosition = controllerLocation.position; - var worldControllerRotation = controllerLocation.orientation; - - var grabbedProperties = Entities.getEntityProperties(intersection.objectID, DISPATCHER_PROPERTIES); - this.currentObjectPosition = grabbedProperties.position; - this.grabRadius = intersection.distance; - - // Offset between controller vector at the grab radius and the entity position. - var targetPosition = Vec3.multiply(this.grabRadius, Quat.getUp(worldControllerRotation)); - targetPosition = Vec3.sum(targetPosition, worldControllerPosition); - this.offsetPosition = Vec3.subtract(this.currentObjectPosition, targetPosition); - - // Initial controller rotation. - this.previousWorldControllerRotation = worldControllerRotation; - }; - - this.destroyContextOverlay = function(controllerData) { - if (this.entityWithContextOverlay) { - ContextOverlay.destroyContextOverlay(this.entityWithContextOverlay); - this.entityWithContextOverlay = false; - this.potentialEntityWithContextOverlay = false; - } - }; - - this.targetIsNull = function() { - var properties = Entities.getEntityProperties(this.grabbedThingID, DISPATCHER_PROPERTIES); - if (Object.keys(properties).length === 0 && this.distanceHolding) { - return true; - } - return false; - }; - - this.isReady = function (controllerData) { - if (HMD.active) { - if (this.notPointingAtEntity(controllerData)) { - return makeRunningValues(false, [], []); - } - - this.distanceHolding = false; - this.distanceRotating = false; - - if (controllerData.triggerValues[this.hand] > TRIGGER_ON_VALUE) { - this.prepareDistanceRotatingData(controllerData); - return makeRunningValues(true, [], []); - } else { - this.destroyContextOverlay(); - return makeRunningValues(false, [], []); - } - } - return makeRunningValues(false, [], []); - }; - - this.run = function (controllerData) { - - var intersection = controllerData.rayPicks[this.hand]; - if (intersection.type === Picks.INTERSECTED_ENTITY && !Window.isPhysicsEnabled()) { - // add to ignored items. - if (this.ignoredEntities.indexOf(intersection.objectID) === -1) { - var data = { - action: 'add', - id: intersection.objectID - }; - Messages.sendMessage('Hifi-Hand-RayPick-Blacklist', JSON.stringify(data)); - this.ignoredEntities.push(intersection.objectID); - } - } - if (controllerData.triggerValues[this.hand] < TRIGGER_OFF_VALUE || - (this.notPointingAtEntity(controllerData) && Window.isPhysicsEnabled()) || this.targetIsNull()) { - this.endFarGrabAction(); - this.restoreIgnoredEntities(); - return makeRunningValues(false, [], []); - } - this.intersectionDistance = controllerData.rayPicks[this.hand].distance; - - var otherModuleName =this.hand === RIGHT_HAND ? "LeftFarActionGrabEntity" : "RightFarActionGrabEntity"; - var otherFarGrabModule = getEnabledModuleByName(otherModuleName); - - // gather up the readiness of the near-grab modules - var nearGrabNames = [ - this.hand === RIGHT_HAND ? "RightScaleAvatar" : "LeftScaleAvatar", - this.hand === RIGHT_HAND ? "RightFarTriggerEntity" : "LeftFarTriggerEntity", - this.hand === RIGHT_HAND ? "RightNearActionGrabEntity" : "LeftNearActionGrabEntity", - this.hand === RIGHT_HAND ? "RightNearParentingGrabEntity" : "LeftNearParentingGrabEntity", - this.hand === RIGHT_HAND ? "RightNearParentingGrabOverlay" : "LeftNearParentingGrabOverlay", - this.hand === RIGHT_HAND ? "RightNearTabletHighlight" : "LeftNearTabletHighlight" - ]; - - var nearGrabReadiness = []; - for (var i = 0; i < nearGrabNames.length; i++) { - var nearGrabModule = getEnabledModuleByName(nearGrabNames[i]); - var ready = nearGrabModule ? nearGrabModule.isReady(controllerData) : makeRunningValues(false, [], []); - nearGrabReadiness.push(ready); - } - - if (this.actionID) { - // if we are doing a distance grab and the object or tablet gets close enough to the controller, - // stop the far-grab so the near-grab or equip can take over. - for (var k = 0; k < nearGrabReadiness.length; k++) { - if (nearGrabReadiness[k].active && (nearGrabReadiness[k].targets[0] === this.grabbedThingID || - HMD.tabletID && nearGrabReadiness[k].targets[0] === HMD.tabletID)) { - this.endFarGrabAction(); - this.restoreIgnoredEntities(); - return makeRunningValues(false, [], []); - } - } - - this.continueDistanceHolding(controllerData); - } else { - // if we are doing a distance search and this controller moves into a position - // where it could near-grab something, stop searching. - for (var j = 0; j < nearGrabReadiness.length; j++) { - if (nearGrabReadiness[j].active) { - this.endFarGrabAction(); - this.restoreIgnoredEntities(); - return makeRunningValues(false, [], []); - } - } - - var rayPickInfo = controllerData.rayPicks[this.hand]; - if (rayPickInfo.type === Picks.INTERSECTED_ENTITY) { - if (controllerData.triggerClicks[this.hand]) { - var entityID = rayPickInfo.objectID; - var targetProps = Entities.getEntityProperties(entityID, DISPATCHER_PROPERTIES); - if (targetProps.href !== "") { - AddressManager.handleLookupString(targetProps.href); - this.restoreIgnoredEntities(); - return makeRunningValues(false, [], []); - } - - this.targetObject = new TargetObject(entityID, targetProps); - this.targetObject.parentProps = getEntityParents(targetProps); - - if (this.contextOverlayTimer) { - Script.clearTimeout(this.contextOverlayTimer); - } - this.contextOverlayTimer = false; - if (entityID === this.entityWithContextOverlay) { - this.destroyContextOverlay(); - } else { - Selection.removeFromSelectedItemsList("contextOverlayHighlightList", "entity", entityID); - } - - var targetEntity = this.targetObject.getTargetEntity(); - entityID = targetEntity.id; - targetProps = targetEntity.props; - - if (entityIsGrabbable(targetProps) || entityIsGrabbable(this.targetObject.entityProps)) { - if (!entityIsDistanceGrabbable(targetProps)) { - this.targetObject.makeDynamic(); - } - - if (!this.distanceRotating) { - this.grabbedThingID = entityID; - this.grabbedDistance = rayPickInfo.distance; - } - - if (otherFarGrabModule.grabbedThingID === this.grabbedThingID && - otherFarGrabModule.distanceHolding) { - this.prepareDistanceRotatingData(controllerData); - this.distanceRotate(otherFarGrabModule); - } else { - this.distanceHolding = true; - this.distanceRotating = false; - this.startFarGrabAction(controllerData, targetProps); - } - } - } else if (!this.entityWithContextOverlay) { - var _this = this; - - if (_this.potentialEntityWithContextOverlay !== rayPickInfo.objectID) { - if (_this.contextOverlayTimer) { - Script.clearTimeout(_this.contextOverlayTimer); - } - _this.contextOverlayTimer = false; - _this.potentialEntityWithContextOverlay = rayPickInfo.objectID; - } - - if (!_this.contextOverlayTimer) { - _this.contextOverlayTimer = Script.setTimeout(function () { - if (!_this.entityWithContextOverlay && - _this.contextOverlayTimer && - _this.potentialEntityWithContextOverlay === rayPickInfo.objectID) { - var props = Entities.getEntityProperties(rayPickInfo.objectID, DISPATCHER_PROPERTIES); - var pointerEvent = { - type: "Move", - id: _this.hand + 1, // 0 is reserved for hardware mouse - pos2D: projectOntoEntityXYPlane(rayPickInfo.objectID, - rayPickInfo.intersection, props), - pos3D: rayPickInfo.intersection, - normal: rayPickInfo.surfaceNormal, - direction: Vec3.subtract(ZERO_VEC, rayPickInfo.surfaceNormal), - button: "Secondary" - }; - if (ContextOverlay.createOrDestroyContextOverlay(rayPickInfo.objectID, pointerEvent)) { - _this.entityWithContextOverlay = rayPickInfo.objectID; - } - } - _this.contextOverlayTimer = false; - }, 500); - } - } - } else if (this.distanceRotating) { - this.distanceRotate(otherFarGrabModule); - } - } - return this.exitIfDisabled(controllerData); - }; - - this.exitIfDisabled = function(controllerData) { - var moduleName = this.hand === RIGHT_HAND ? "RightDisableModules" : "LeftDisableModules"; - var disableModule = getEnabledModuleByName(moduleName); - if (disableModule) { - if (disableModule.disableModules) { - this.endFarGrabAction(); - Selection.removeFromSelectedItemsList(DISPATCHER_HOVERING_LIST, "entity", - this.highlightedEntity); - this.highlightedEntity = null; - this.restoreIgnoredEntities(); - return makeRunningValues(false, [], []); - } - } - var grabbedThing = (this.distanceHolding || this.distanceRotating) ? this.targetObject.entityID : null; - var offset = this.calculateOffset(controllerData); - var laserLockInfo = makeLaserLockInfo(grabbedThing, false, this.hand, offset); - return makeRunningValues(true, [], [], laserLockInfo); - }; - - this.calculateOffset = function(controllerData) { - if (this.distanceHolding || this.distanceRotating) { - var targetProps = Entities.getEntityProperties(this.targetObject.entityID, - [ "position", "rotation", "registrationPoint", "dimensions" ]); - return worldPositionToRegistrationFrameMatrix(targetProps, controllerData.rayPicks[this.hand].intersection); - } - return undefined; - }; - } - - var leftFarActionGrabEntity = new FarActionGrabEntity(LEFT_HAND); - var rightFarActionGrabEntity = new FarActionGrabEntity(RIGHT_HAND); - - enableDispatcherModule("LeftFarActionGrabEntity", leftFarActionGrabEntity); - enableDispatcherModule("RightFarActionGrabEntity", rightFarActionGrabEntity); - - function cleanup() { - disableDispatcherModule("LeftFarActionGrabEntity"); - disableDispatcherModule("RightFarActionGrabEntity"); - } - Script.scriptEnding.connect(cleanup); -}()); diff --git a/scripts/simplifiedUI/system/controllers/controllerModules/farGrabEntity.js b/scripts/simplifiedUI/system/controllers/controllerModules/farGrabEntity.js deleted file mode 100644 index ecafa3cb26..0000000000 --- a/scripts/simplifiedUI/system/controllers/controllerModules/farGrabEntity.js +++ /dev/null @@ -1,585 +0,0 @@ -"use strict"; - -// farGrabEntity.js -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html - -/* jslint bitwise: true */ - -/* global Script, Controller, RIGHT_HAND, LEFT_HAND, Mat4, MyAvatar, Vec3, Quat, getEnabledModuleByName, makeRunningValues, - Entities, enableDispatcherModule, disableDispatcherModule, entityIsGrabbable, makeDispatcherModuleParameters, MSECS_PER_SEC, - HAPTIC_PULSE_STRENGTH, HAPTIC_PULSE_DURATION, TRIGGER_OFF_VALUE, TRIGGER_ON_VALUE, ZERO_VEC, - projectOntoEntityXYPlane, ContextOverlay, HMD, Picks, makeLaserLockInfo, makeLaserParams, AddressManager, - getEntityParents, Selection, DISPATCHER_HOVERING_LIST, unhighlightTargetEntity, Messages, findGrabbableGroupParent, - worldPositionToRegistrationFrameMatrix, DISPATCHER_PROPERTIES -*/ - -Script.include("/~/system/libraries/controllerDispatcherUtils.js"); -Script.include("/~/system/libraries/controllers.js"); - -(function () { - var MARGIN = 25; - - function TargetObject(entityID, entityProps) { - this.entityID = entityID; - this.entityProps = entityProps; - this.targetEntityID = null; - this.targetEntityProps = null; - - this.getTargetEntity = function () { - var parentPropsLength = this.parentProps.length; - if (parentPropsLength !== 0) { - var targetEntity = { - id: this.parentProps[parentPropsLength - 1].id, - props: this.parentProps[parentPropsLength - 1] - }; - this.targetEntityID = targetEntity.id; - this.targetEntityProps = targetEntity.props; - return targetEntity; - } - this.targetEntityID = this.entityID; - this.targetEntityProps = this.entityProps; - return { - id: this.entityID, - props: this.entityProps - }; - }; - } - - function FarGrabEntity(hand) { - this.hand = hand; - this.grabbing = false; - this.targetEntityID = null; - this.targetObject = null; - this.previouslyUnhooked = {}; - this.potentialEntityWithContextOverlay = false; - this.entityWithContextOverlay = false; - this.contextOverlayTimer = false; - this.reticleMinX = MARGIN; - this.reticleMaxX = 0; - this.reticleMinY = MARGIN; - this.reticleMaxY = 0; - this.endedGrab = 0; - this.MIN_HAPTIC_PULSE_INTERVAL = 500; // ms - this.disabled = false; - var _this = this; - this.initialControllerRotation = Quat.IDENTITY; - this.currentControllerRotation = Quat.IDENTITY; - this.manipulating = false; - this.wasManipulating = false; - - var FAR_GRAB_JOINTS = [65527, 65528]; // FARGRAB_LEFTHAND_INDEX, FARGRAB_RIGHTHAND_INDEX - - var DISTANCE_HOLDING_RADIUS_FACTOR = 3.5; // multiplied by distance between hand and object - var DISTANCE_HOLDING_ACTION_TIMEFRAME = 0.1; // how quickly objects move to their new position - var DISTANCE_HOLDING_UNITY_MASS = 1200; // The mass at which the distance holding action timeframe is unmodified - var DISTANCE_HOLDING_UNITY_DISTANCE = 6; // The distance at which the distance holding action timeframe is unmodified - - this.parameters = makeDispatcherModuleParameters( - 540, - this.hand === RIGHT_HAND ? ["rightHand"] : ["leftHand"], - [], - 100, - makeLaserParams(this.hand, false)); - - this.getOtherModule = function () { - return getEnabledModuleByName(this.hand === RIGHT_HAND ? ("LeftFarGrabEntity") : ("RightFarGrabEntity")); - }; - - // Get the rotation of the fargrabbed entity. - this.getTargetRotation = function () { - if (this.targetIsNull()) { - return null; - } else { - var props = Entities.getEntityProperties(this.targetEntityID, ["rotation"]); - return props.rotation; - } - }; - - this.getOffhand = function () { - return (this.hand === RIGHT_HAND ? LEFT_HAND : RIGHT_HAND); - } - - // Activation criteria for rotating a fargrabbed entity. If we're changing the mapping, this is where to do it. - this.shouldManipulateTarget = function (controllerData) { - return (controllerData.triggerValues[this.getOffhand()] > TRIGGER_ON_VALUE || controllerData.secondaryValues[this.getOffhand()] > TRIGGER_ON_VALUE) ? true : false; - }; - - // Get the delta between the current rotation and where the controller was when manipulation started. - this.calculateEntityRotationManipulation = function (controllerRotation) { - return Quat.multiply(controllerRotation, Quat.inverse(this.initialControllerRotation)); - }; - - this.setJointTranslation = function (newTargetPosLocal) { - MyAvatar.setJointTranslation(FAR_GRAB_JOINTS[this.hand], newTargetPosLocal); - }; - - this.setJointRotation = function (newTargetRotLocal) { - MyAvatar.setJointRotation(FAR_GRAB_JOINTS[this.hand], newTargetRotLocal); - }; - - this.setJointRotation = function (newTargetRotLocal) { - MyAvatar.setJointRotation(FAR_GRAB_JOINTS[this.hand], newTargetRotLocal); - }; - - this.handToController = function () { - return (this.hand === RIGHT_HAND) ? Controller.Standard.RightHand : Controller.Standard.LeftHand; - }; - - this.distanceGrabTimescale = function (mass, distance) { - var timeScale = DISTANCE_HOLDING_ACTION_TIMEFRAME * mass / - DISTANCE_HOLDING_UNITY_MASS * distance / - DISTANCE_HOLDING_UNITY_DISTANCE; - if (timeScale < DISTANCE_HOLDING_ACTION_TIMEFRAME) { - timeScale = DISTANCE_HOLDING_ACTION_TIMEFRAME; - } - return timeScale; - }; - - this.getMass = function (dimensions, density) { - return (dimensions.x * dimensions.y * dimensions.z) * density; - }; - - this.startFarGrabEntity = function (controllerData, targetProps) { - var controllerLocation = controllerData.controllerLocations[this.hand]; - var worldControllerPosition = controllerLocation.position; - var worldControllerRotation = controllerLocation.orientation; - // transform the position into room space - var worldToSensorMat = Mat4.inverse(MyAvatar.getSensorToWorldMatrix()); - var roomControllerPosition = Mat4.transformPoint(worldToSensorMat, worldControllerPosition); - - var now = Date.now(); - - // add the action and initialize some variables - this.currentObjectPosition = targetProps.position; - this.currentObjectRotation = targetProps.rotation; - this.currentObjectTime = now; - - this.grabRadius = this.grabbedDistance; - this.grabRadialVelocity = 0.0; - - // offset between controller vector at the grab radius and the entity position - var targetPosition = Vec3.multiply(this.grabRadius, Quat.getUp(worldControllerRotation)); - targetPosition = Vec3.sum(targetPosition, worldControllerPosition); - this.offsetPosition = Vec3.subtract(this.currentObjectPosition, targetPosition); - - // compute a constant based on the initial conditions which we use below to exaggerate hand motion - // onto the held object - this.radiusScalar = Math.log(this.grabRadius + 1.0); - if (this.radiusScalar < 1.0) { - this.radiusScalar = 1.0; - } - - // compute the mass for the purpose of energy and how quickly to move object - this.mass = this.getMass(targetProps.dimensions, targetProps.density); - - // Debounce haptic pules. Can occur as near grab controller module vacillates between being ready or not due to - // changing positions and floating point rounding. - if (Date.now() - this.endedGrab > this.MIN_HAPTIC_PULSE_INTERVAL) { - Controller.triggerHapticPulse(HAPTIC_PULSE_STRENGTH, HAPTIC_PULSE_DURATION, this.hand); - } - - unhighlightTargetEntity(this.targetEntityID); - var message = { - hand: this.hand, - entityID: this.targetEntityID - }; - - Messages.sendLocalMessage('Hifi-unhighlight-entity', JSON.stringify(message)); - - var newTargetPosLocal = MyAvatar.worldToJointPoint(targetProps.position); - var newTargetRotLocal = targetProps.rotation; - this.setJointTranslation(newTargetPosLocal); - this.setJointRotation(newTargetRotLocal); - - var args = [this.hand === RIGHT_HAND ? "right" : "left", MyAvatar.sessionUUID]; - Entities.callEntityMethod(targetProps.id, "startDistanceGrab", args); - - this.targetEntityID = targetProps.id; - - - if (this.grabID) { - MyAvatar.releaseGrab(this.grabID); - } - var farJointIndex = FAR_GRAB_JOINTS[this.hand]; - this.grabID = MyAvatar.grab(targetProps.id, farJointIndex, - Entities.worldToLocalPosition(targetProps.position, MyAvatar.SELF_ID, farJointIndex), - Entities.worldToLocalRotation(targetProps.rotation, MyAvatar.SELF_ID, farJointIndex)); - - Messages.sendMessage('Hifi-Object-Manipulation', JSON.stringify({ - action: 'grab', - grabbedEntity: targetProps.id, - joint: this.hand === RIGHT_HAND ? "RightHand" : "LeftHand" - })); - this.grabbing = true; - - this.previousRoomControllerPosition = roomControllerPosition; - }; - - this.continueDistanceHolding = function (controllerData) { - var controllerLocation = controllerData.controllerLocations[this.hand]; - var worldControllerPosition = controllerLocation.position; - var worldControllerRotation = controllerLocation.orientation; - - // also transform the position into room space - var worldToSensorMat = Mat4.inverse(MyAvatar.getSensorToWorldMatrix()); - var roomControllerPosition = Mat4.transformPoint(worldToSensorMat, worldControllerPosition); - - var targetProps = Entities.getEntityProperties(this.targetEntityID, DISPATCHER_PROPERTIES); - var now = Date.now(); - var deltaObjectTime = (now - this.currentObjectTime) / MSECS_PER_SEC; // convert to seconds - this.currentObjectTime = now; - - // the action was set up when this.distanceHolding was called. update the targets. - var radius = Vec3.distance(this.currentObjectPosition, worldControllerPosition) * - this.radiusScalar * DISTANCE_HOLDING_RADIUS_FACTOR; - if (radius < 1.0) { - radius = 1.0; - } - - var roomHandDelta = Vec3.subtract(roomControllerPosition, this.previousRoomControllerPosition); - var worldHandDelta = Mat4.transformVector(MyAvatar.getSensorToWorldMatrix(), roomHandDelta); - var handMoved = Vec3.multiply(worldHandDelta, radius); - this.currentObjectPosition = Vec3.sum(this.currentObjectPosition, handMoved); - - var args = [this.hand === RIGHT_HAND ? "right" : "left", MyAvatar.sessionUUID]; - Entities.callEntityMethod(this.targetEntityID, "continueDistanceGrab", args); - - // Update radialVelocity - var lastVelocity = Vec3.multiply(worldHandDelta, 1.0 / deltaObjectTime); - var delta = Vec3.normalize(Vec3.subtract(targetProps.position, worldControllerPosition)); - var newRadialVelocity = Vec3.dot(lastVelocity, delta); - - var VELOCITY_AVERAGING_TIME = 0.016; - var blendFactor = deltaObjectTime / VELOCITY_AVERAGING_TIME; - if (blendFactor < 0.0) { - blendFactor = 0.0; - } else if (blendFactor > 1.0) { - blendFactor = 1.0; - } - this.grabRadialVelocity = blendFactor * newRadialVelocity + (1.0 - blendFactor) * this.grabRadialVelocity; - - var RADIAL_GRAB_AMPLIFIER = 10.0; - if (Math.abs(this.grabRadialVelocity) > 0.0) { - this.grabRadius = this.grabRadius + (this.grabRadialVelocity * deltaObjectTime * - this.grabRadius * RADIAL_GRAB_AMPLIFIER); - } - - // don't let grabRadius go all the way to zero, because it can't come back from that - var MINIMUM_GRAB_RADIUS = 0.1; - if (this.grabRadius < MINIMUM_GRAB_RADIUS) { - this.grabRadius = MINIMUM_GRAB_RADIUS; - } - var newTargetPosition = Vec3.multiply(this.grabRadius, Quat.getUp(worldControllerRotation)); - newTargetPosition = Vec3.sum(newTargetPosition, worldControllerPosition); - newTargetPosition = Vec3.sum(newTargetPosition, this.offsetPosition); - - var newTargetPosLocal = MyAvatar.worldToJointPoint(newTargetPosition); - - // This block handles the user's ability to rotate the object they're FarGrabbing - if (this.shouldManipulateTarget(controllerData)) { - // Get the pose of the controller that is not grabbing. - var pose = Controller.getPoseValue((this.getOffhand() ? Controller.Standard.RightHand : Controller.Standard.LeftHand)); - if (pose.valid) { - // If we weren't manipulating the object yet, initialize the entity's original position. - if (!this.manipulating) { - // This will only be triggered if we've let go of the off-hand trigger and pulled it again without ending a grab. - // Need to poll the entity's rotation again here. - if (!this.wasManipulating) { - this.initialEntityRotation = this.getTargetRotation(); - } - // Save the original controller orientation, we only care about the delta between this rotation and wherever - // the controller rotates, so that we can apply it to the entity's rotation. - this.initialControllerRotation = Quat.multiply(pose.rotation, MyAvatar.orientation); - this.manipulating = true; - } - } - - var rot = Quat.multiply(pose.rotation, MyAvatar.orientation); - var rotBetween = this.calculateEntityRotationManipulation(rot); - var doubleRot = Quat.multiply(rotBetween, rotBetween); - this.lastJointRotation = Quat.multiply(doubleRot, this.initialEntityRotation); - this.setJointRotation(this.lastJointRotation); - } else { - // If we were manipulating but the user isn't currently expressing this intent, we want to know so we preserve the rotation - // between manipulations without ending the fargrab. - if (this.manipulating) { - this.initialEntityRotation = this.lastJointRotation; - this.wasManipulating = true; - } - this.manipulating = false; - // Reset the inital controller position. - this.initialControllerRotation = Quat.IDENTITY; - } - this.setJointTranslation(newTargetPosLocal); - - this.previousRoomControllerPosition = roomControllerPosition; - }; - - this.endFarGrabEntity = function (controllerData) { - if (this.grabID) { - MyAvatar.releaseGrab(this.grabID); - this.grabID = null; - } - - this.endedGrab = Date.now(); - - var args = [this.hand === RIGHT_HAND ? "right" : "left", MyAvatar.sessionUUID]; - Entities.callEntityMethod(this.targetEntityID, "releaseGrab", args); - Messages.sendMessage('Hifi-Object-Manipulation', JSON.stringify({ - action: 'release', - grabbedEntity: this.targetEntityID, - joint: this.hand === RIGHT_HAND ? "RightHand" : "LeftHand" - })); - unhighlightTargetEntity(this.targetEntityID); - this.grabbing = false; - this.potentialEntityWithContextOverlay = false; - MyAvatar.clearJointData(FAR_GRAB_JOINTS[this.hand]); - this.initialEntityRotation = Quat.IDENTITY; - this.initialControllerRotation = Quat.IDENTITY; - this.targetEntityID = null; - this.manipulating = false; - this.wasManipulating = false; - var otherModule = this.getOtherModule(); - otherModule.disabled = false; - }; - - this.updateRecommendedArea = function () { - var dims = Controller.getViewportDimensions(); - this.reticleMaxX = dims.x - MARGIN; - this.reticleMaxY = dims.y - MARGIN; - }; - - this.calculateNewReticlePosition = function (intersection) { - this.updateRecommendedArea(); - var point2d = HMD.overlayFromWorldPoint(intersection); - point2d.x = Math.max(this.reticleMinX, Math.min(point2d.x, this.reticleMaxX)); - point2d.y = Math.max(this.reticleMinY, Math.min(point2d.y, this.reticleMaxY)); - return point2d; - }; - - this.notPointingAtEntity = function (controllerData) { - var intersection = controllerData.rayPicks[this.hand]; - var entityProperty = Entities.getEntityProperties(intersection.objectID, DISPATCHER_PROPERTIES); - var entityType = entityProperty.type; - var hudRayPick = controllerData.hudRayPicks[this.hand]; - var point2d = this.calculateNewReticlePosition(hudRayPick.intersection); - if ((intersection.type === Picks.INTERSECTED_ENTITY && entityType === "Web") || - intersection.type === Picks.INTERSECTED_OVERLAY || Window.isPointOnDesktopWindow(point2d)) { - return true; - } - return false; - }; - - this.destroyContextOverlay = function (controllerData) { - if (this.entityWithContextOverlay) { - ContextOverlay.destroyContextOverlay(this.entityWithContextOverlay); - this.entityWithContextOverlay = false; - this.potentialEntityWithContextOverlay = false; - } - }; - - this.targetIsNull = function () { - var properties = Entities.getEntityProperties(this.targetEntityID, DISPATCHER_PROPERTIES); - if (Object.keys(properties).length === 0 && this.distanceHolding) { - return true; - } - return false; - }; - - this.getTargetProps = function (controllerData) { - var targetEntity = controllerData.rayPicks[this.hand].objectID; - if (targetEntity) { - var gtProps = Entities.getEntityProperties(targetEntity, DISPATCHER_PROPERTIES); - if (entityIsGrabbable(gtProps)) { - // if we've attempted to grab a child, roll up to the root of the tree - var groupRootProps = findGrabbableGroupParent(controllerData, gtProps); - if (entityIsGrabbable(groupRootProps)) { - return groupRootProps; - } - return gtProps; - } - } - return null; - }; - - this.isReady = function (controllerData) { - if (HMD.active) { - if (this.notPointingAtEntity(controllerData)) { - return makeRunningValues(false, [], []); - } - - this.distanceHolding = false; - - if (controllerData.triggerValues[this.hand] > TRIGGER_ON_VALUE && !this.disabled) { - var otherModule = this.getOtherModule(); - otherModule.disabled = true; - return makeRunningValues(true, [], []); - } else { - this.destroyContextOverlay(); - } - } - return makeRunningValues(false, [], []); - }; - - this.run = function (controllerData) { - if (controllerData.triggerValues[this.hand] < TRIGGER_OFF_VALUE || this.targetIsNull()) { - this.endFarGrabEntity(controllerData); - return makeRunningValues(false, [], []); - } - this.intersectionDistance = controllerData.rayPicks[this.hand].distance; - - // gather up the readiness of the near-grab modules - var nearGrabNames = [ - this.hand === RIGHT_HAND ? "RightScaleAvatar" : "LeftScaleAvatar", - this.hand === RIGHT_HAND ? "RightFarTriggerEntity" : "LeftFarTriggerEntity", - this.hand === RIGHT_HAND ? "RightNearGrabEntity" : "LeftNearGrabEntity" - ]; - if (!this.grabbing) { - nearGrabNames.push(this.hand === RIGHT_HAND ? "RightNearParentingGrabOverlay" : "LeftNearParentingGrabOverlay"); - nearGrabNames.push(this.hand === RIGHT_HAND ? "RightNearTabletHighlight" : "LeftNearTabletHighlight"); - } - - var nearGrabReadiness = []; - for (var i = 0; i < nearGrabNames.length; i++) { - var nearGrabModule = getEnabledModuleByName(nearGrabNames[i]); - var ready = nearGrabModule ? nearGrabModule.isReady(controllerData) : makeRunningValues(false, [], []); - nearGrabReadiness.push(ready); - } - - if (this.targetEntityID) { - // if we are doing a distance grab and the object gets close enough to the controller, - // stop the far-grab so the near-grab or equip can take over. - for (var k = 0; k < nearGrabReadiness.length; k++) { - if (nearGrabReadiness[k].active && (nearGrabReadiness[k].targets[0] === this.targetEntityID)) { - this.endFarGrabEntity(controllerData); - return makeRunningValues(false, [], []); - } - } - - this.continueDistanceHolding(controllerData); - } else { - // if we are doing a distance search and this controller moves into a position - // where it could near-grab something, stop searching. - for (var j = 0; j < nearGrabReadiness.length; j++) { - if (nearGrabReadiness[j].active) { - this.endFarGrabEntity(controllerData); - return makeRunningValues(false, [], []); - } - } - - var rayPickInfo = controllerData.rayPicks[this.hand]; - if (rayPickInfo.type === Picks.INTERSECTED_ENTITY) { - if (controllerData.triggerClicks[this.hand]) { - var entityID = rayPickInfo.objectID; - var targetProps = Entities.getEntityProperties(entityID, DISPATCHER_PROPERTIES); - if (targetProps.href !== "") { - AddressManager.handleLookupString(targetProps.href); - return makeRunningValues(false, [], []); - } - - this.targetObject = new TargetObject(entityID, targetProps); - this.targetObject.parentProps = getEntityParents(targetProps); - - if (this.contextOverlayTimer) { - Script.clearTimeout(this.contextOverlayTimer); - } - this.contextOverlayTimer = false; - if (entityID === this.entityWithContextOverlay) { - this.destroyContextOverlay(); - } else { - Selection.removeFromSelectedItemsList("contextOverlayHighlightList", "entity", entityID); - } - - var targetEntity = this.targetObject.getTargetEntity(); - entityID = targetEntity.id; - targetProps = targetEntity.props; - - if (entityIsGrabbable(targetProps) || entityIsGrabbable(this.targetObject.entityProps)) { - - this.targetEntityID = entityID; - this.grabbedDistance = rayPickInfo.distance; - this.distanceHolding = true; - this.startFarGrabEntity(controllerData, targetProps); - } - } else if (!this.entityWithContextOverlay) { - var _this = this; - - if (_this.potentialEntityWithContextOverlay !== rayPickInfo.objectID) { - if (_this.contextOverlayTimer) { - Script.clearTimeout(_this.contextOverlayTimer); - } - _this.contextOverlayTimer = false; - _this.potentialEntityWithContextOverlay = rayPickInfo.objectID; - } - - if (!_this.contextOverlayTimer) { - _this.contextOverlayTimer = Script.setTimeout(function () { - if (!_this.entityWithContextOverlay && - _this.contextOverlayTimer && - _this.potentialEntityWithContextOverlay === rayPickInfo.objectID) { - var cotProps = Entities.getEntityProperties(rayPickInfo.objectID, - DISPATCHER_PROPERTIES); - var pointerEvent = { - type: "Move", - id: _this.hand + 1, // 0 is reserved for hardware mouse - pos2D: projectOntoEntityXYPlane(rayPickInfo.objectID, - rayPickInfo.intersection, cotProps), - pos3D: rayPickInfo.intersection, - normal: rayPickInfo.surfaceNormal, - direction: Vec3.subtract(ZERO_VEC, rayPickInfo.surfaceNormal), - button: "Secondary" - }; - if (ContextOverlay.createOrDestroyContextOverlay(rayPickInfo.objectID, pointerEvent)) { - _this.entityWithContextOverlay = rayPickInfo.objectID; - } - } - _this.contextOverlayTimer = false; - }, 500); - } - } - } - } - return this.exitIfDisabled(controllerData); - }; - - this.exitIfDisabled = function (controllerData) { - var moduleName = this.hand === RIGHT_HAND ? "RightDisableModules" : "LeftDisableModules"; - var disableModule = getEnabledModuleByName(moduleName); - if (disableModule) { - if (disableModule.disableModules) { - this.endFarGrabEntity(controllerData); - Selection.removeFromSelectedItemsList(DISPATCHER_HOVERING_LIST, "entity", this.highlightedEntity); - this.highlightedEntity = null; - return makeRunningValues(false, [], []); - } - } - var grabbedThing = this.distanceHolding ? this.targetObject.entityID : null; - var offset = this.calculateOffset(controllerData); - var laserLockInfo = makeLaserLockInfo(grabbedThing, false, this.hand, offset); - return makeRunningValues(true, [], [], laserLockInfo); - }; - - this.calculateOffset = function (controllerData) { - if (this.distanceHolding) { - var targetProps = Entities.getEntityProperties(this.targetObject.entityID, - ["position", "rotation", "registrationPoint", "dimensions"]); - return worldPositionToRegistrationFrameMatrix(targetProps, controllerData.rayPicks[this.hand].intersection); - } - return undefined; - }; - } - - var leftFarGrabEntity = new FarGrabEntity(LEFT_HAND); - var rightFarGrabEntity = new FarGrabEntity(RIGHT_HAND); - - enableDispatcherModule("LeftFarGrabEntity", leftFarGrabEntity); - enableDispatcherModule("RightFarGrabEntity", rightFarGrabEntity); - - function cleanup() { - disableDispatcherModule("LeftFarGrabEntity"); - disableDispatcherModule("RightFarGrabEntity"); - } - Script.scriptEnding.connect(cleanup); -}()); diff --git a/scripts/simplifiedUI/system/controllers/controllerModules/farTrigger.js b/scripts/simplifiedUI/system/controllers/controllerModules/farTrigger.js deleted file mode 100644 index c9c9d3deee..0000000000 --- a/scripts/simplifiedUI/system/controllers/controllerModules/farTrigger.js +++ /dev/null @@ -1,102 +0,0 @@ -"use strict"; - -// farTrigger.js -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html - - -/* global Script, RIGHT_HAND, LEFT_HAND, MyAvatar, - makeRunningValues, Entities, enableDispatcherModule, disableDispatcherModule, makeDispatcherModuleParameters, - getGrabbableData, makeLaserParams, DISPATCHER_PROPERTIES -*/ - -Script.include("/~/system/libraries/controllerDispatcherUtils.js"); -Script.include("/~/system/libraries/controllers.js"); - -(function() { - function entityWantsFarTrigger(props) { - var grabbableData = getGrabbableData(props); - return grabbableData.triggerable; - } - - function FarTriggerEntity(hand) { - this.hand = hand; - this.targetEntityID = null; - this.grabbing = false; - this.previousParentID = {}; - this.previousParentJointIndex = {}; - this.previouslyUnhooked = {}; - - this.parameters = makeDispatcherModuleParameters( - 520, - this.hand === RIGHT_HAND ? ["rightHand"] : ["leftHand"], - [], - 100, - makeLaserParams(this.hand, false)); - - this.getTargetProps = function (controllerData) { - var targetEntity = controllerData.rayPicks[this.hand].objectID; - if (targetEntity && controllerData.rayPicks[this.hand].type === RayPick.INTERSECTED_ENTITY) { - var targetProperties = Entities.getEntityProperties(targetEntity, DISPATCHER_PROPERTIES); - if (entityWantsFarTrigger(targetProperties)) { - return targetProperties; - } - } - return null; - }; - - this.startFarTrigger = function (controllerData) { - var args = [this.hand === RIGHT_HAND ? "right" : "left", MyAvatar.sessionUUID]; - Entities.callEntityMethod(this.targetEntityID, "startFarTrigger", args); - }; - - this.continueFarTrigger = function (controllerData) { - var args = [this.hand === RIGHT_HAND ? "right" : "left", MyAvatar.sessionUUID]; - Entities.callEntityMethod(this.targetEntityID, "continueFarTrigger", args); - }; - - this.endFarTrigger = function (controllerData) { - var args = [this.hand === RIGHT_HAND ? "right" : "left", MyAvatar.sessionUUID]; - Entities.callEntityMethod(this.targetEntityID, "stopFarTrigger", args); - }; - - this.isReady = function (controllerData) { - this.targetEntityID = null; - if (controllerData.triggerClicks[this.hand] === 0) { - return makeRunningValues(false, [], []); - } - - var targetProps = this.getTargetProps(controllerData); - if (targetProps) { - this.targetEntityID = targetProps.id; - this.startFarTrigger(controllerData); - return makeRunningValues(true, [this.targetEntityID], []); - } else { - return makeRunningValues(false, [], []); - } - }; - - this.run = function (controllerData) { - var targetEntity = controllerData.rayPicks[this.hand].objectID; - if (controllerData.triggerClicks[this.hand] === 0 || this.targetEntityID !== targetEntity) { - this.endFarTrigger(controllerData); - return makeRunningValues(false, [], []); - } - this.continueFarTrigger(controllerData); - return makeRunningValues(true, [this.targetEntityID], []); - }; - } - - var leftFarTriggerEntity = new FarTriggerEntity(LEFT_HAND); - var rightFarTriggerEntity = new FarTriggerEntity(RIGHT_HAND); - - enableDispatcherModule("LeftFarTriggerEntity", leftFarTriggerEntity); - enableDispatcherModule("RightFarTriggerEntity", rightFarTriggerEntity); - - function cleanup() { - disableDispatcherModule("LeftFarTriggerEntity"); - disableDispatcherModule("RightFarTriggerEntity"); - } - Script.scriptEnding.connect(cleanup); -}()); diff --git a/scripts/simplifiedUI/system/controllers/controllerModules/hudOverlayPointer.js b/scripts/simplifiedUI/system/controllers/controllerModules/hudOverlayPointer.js deleted file mode 100644 index f7d5b5a2dd..0000000000 --- a/scripts/simplifiedUI/system/controllers/controllerModules/hudOverlayPointer.js +++ /dev/null @@ -1,126 +0,0 @@ -// -// hudOverlayPointer.js -// -// scripts/system/controllers/controllerModules/ -// -// Created by Dante Ruiz 2017-9-21 -// Copyright 2017 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -/* global Script, Controller, RIGHT_HAND, LEFT_HAND, HMD, makeLaserParams */ -(function() { - Script.include("/~/system/libraries/controllers.js"); - var ControllerDispatcherUtils = Script.require("/~/system/libraries/controllerDispatcherUtils.js"); - var MARGIN = 25; - var HUD_LASER_OFFSET = 2; - function HudOverlayPointer(hand) { - this.hand = hand; - this.running = false; - this.reticleMinX = MARGIN; - this.reticleMaxX; - this.reticleMinY = MARGIN; - this.reticleMaxY; - this.parameters = ControllerDispatcherUtils.makeDispatcherModuleParameters( - 160, // Same as webSurfaceLaserInput. - this.hand === RIGHT_HAND ? ["rightHand"] : ["leftHand"], - [], - 100, - makeLaserParams((this.hand + HUD_LASER_OFFSET), false)); - - this.getFarGrab = function () { - return getEnabledModuleByName(this.hand === RIGHT_HAND ? ("RightFarGrabEntity") : ("LeftFarGrabEntity")); - } - - this.farGrabActive = function () { - var farGrab = this.getFarGrab(); - // farGrab will be null if module isn't loaded. - if (farGrab) { - return farGrab.targetIsNull(); - } else { - return false; - } - }; - - this.getOtherHandController = function() { - return (this.hand === RIGHT_HAND) ? Controller.Standard.LeftHand : Controller.Standard.RightHand; - }; - - this.handToController = function() { - return (this.hand === RIGHT_HAND) ? Controller.Standard.RightHand : Controller.Standard.LeftHand; - }; - - this.updateRecommendedArea = function() { - var dims = Controller.getViewportDimensions(); - this.reticleMaxX = dims.x - MARGIN; - this.reticleMaxY = dims.y - MARGIN; - }; - - this.calculateNewReticlePosition = function(intersection) { - this.updateRecommendedArea(); - var point2d = HMD.overlayFromWorldPoint(intersection); - point2d.x = Math.max(this.reticleMinX, Math.min(point2d.x, this.reticleMaxX)); - point2d.y = Math.max(this.reticleMinY, Math.min(point2d.y, this.reticleMaxY)); - return point2d; - }; - - this.pointingAtTablet = function(controllerData) { - var rayPick = controllerData.rayPicks[this.hand]; - return (HMD.tabletScreenID && HMD.homeButtonID && (rayPick.objectID === HMD.tabletScreenID || rayPick.objectID === HMD.homeButtonID)); - }; - - this.getOtherModule = function() { - return this.hand === RIGHT_HAND ? leftHudOverlayPointer : rightHudOverlayPointer; - }; - - this.processLaser = function(controllerData) { - var controllerLocation = controllerData.controllerLocations[this.hand]; - if ((controllerData.triggerValues[this.hand] < ControllerDispatcherUtils.TRIGGER_ON_VALUE || !controllerLocation.valid) || - this.pointingAtTablet(controllerData)) { - return false; - } - var hudRayPick = controllerData.hudRayPicks[this.hand]; - var point2d = this.calculateNewReticlePosition(hudRayPick.intersection); - if (!Window.isPointOnDesktopWindow(point2d) && !this.triggerClicked) { - return false; - } - - this.triggerClicked = controllerData.triggerClicks[this.hand]; - return true; - }; - - this.isReady = function (controllerData) { - var otherModuleRunning = this.getOtherModule().running; - if (!otherModuleRunning && HMD.active && !this.farGrabActive()) { - if (this.processLaser(controllerData)) { - this.running = true; - return ControllerDispatcherUtils.makeRunningValues(true, [], []); - } else { - this.running = false; - return ControllerDispatcherUtils.makeRunningValues(false, [], []); - } - } - return ControllerDispatcherUtils.makeRunningValues(false, [], []); - }; - - this.run = function (controllerData, deltaTime) { - return this.isReady(controllerData); - }; - } - - - var leftHudOverlayPointer = new HudOverlayPointer(LEFT_HAND); - var rightHudOverlayPointer = new HudOverlayPointer(RIGHT_HAND); - - ControllerDispatcherUtils.enableDispatcherModule("LeftHudOverlayPointer", leftHudOverlayPointer); - ControllerDispatcherUtils.enableDispatcherModule("RightHudOverlayPointer", rightHudOverlayPointer); - - function cleanup() { - ControllerDispatcherUtils.disableDispatcherModule("LeftHudOverlayPointer"); - ControllerDispatcherUtils.disableDispatcherModule("RightHudOverlayPointer"); - } - Script.scriptEnding.connect(cleanup); - -})(); diff --git a/scripts/simplifiedUI/system/controllers/controllerModules/inEditMode.js b/scripts/simplifiedUI/system/controllers/controllerModules/inEditMode.js deleted file mode 100644 index 5709b19efe..0000000000 --- a/scripts/simplifiedUI/system/controllers/controllerModules/inEditMode.js +++ /dev/null @@ -1,253 +0,0 @@ -"use strict"; - -// inEditMode.js -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html - -/* jslint bitwise: true */ - -/* global Script, Controller, RIGHT_HAND, LEFT_HAND, enableDispatcherModule, disableDispatcherModule, makeRunningValues, - Messages, makeDispatcherModuleParameters, HMD, getEnabledModuleByName, TRIGGER_ON_VALUE, isInEditMode, Picks, - makeLaserParams -*/ - -Script.include("/~/system/libraries/controllerDispatcherUtils.js"); -Script.include("/~/system/libraries/controllers.js"); -Script.include("/~/system/libraries/utils.js"); - -(function () { - var MARGIN = 25; - function InEditMode(hand) { - this.hand = hand; - this.isEditing = false; - this.triggerClicked = false; - this.selectedTarget = null; - this.reticleMinX = MARGIN; - this.reticleMaxX = null; - this.reticleMinY = MARGIN; - this.reticleMaxY = null; - - this.parameters = makeDispatcherModuleParameters( - 165, // Lower priority than webSurfaceLaserInput and hudOverlayPointer. - this.hand === RIGHT_HAND ? ["rightHand", "rightHandEquip", "rightHandTrigger"] : ["leftHand", "leftHandEquip", "leftHandTrigger"], - [], - 100, - makeLaserParams(this.hand, false)); - - this.nearTablet = function(overlays) { - for (var i = 0; i < overlays.length; i++) { - if (HMD.tabletID && overlays[i] === HMD.tabletID) { - return true; - } - } - return false; - }; - - this.handToController = function() { - return (this.hand === RIGHT_HAND) ? Controller.Standard.RightHand : Controller.Standard.LeftHand; - }; - - this.pointingAtTablet = function(objectID) { - return (HMD.tabletScreenID && objectID === HMD.tabletScreenID) || - (HMD.homeButtonID && objectID === HMD.homeButtonID); - }; - - this.calculateNewReticlePosition = function(intersection) { - var dims = Controller.getViewportDimensions(); - this.reticleMaxX = dims.x - MARGIN; - this.reticleMaxY = dims.y - MARGIN; - var point2d = HMD.overlayFromWorldPoint(intersection); - point2d.x = Math.max(this.reticleMinX, Math.min(point2d.x, this.reticleMaxX)); - point2d.y = Math.max(this.reticleMinY, Math.min(point2d.y, this.reticleMaxY)); - return point2d; - }; - - this.ENTITY_TOOL_UPDATES_CHANNEL = "entityToolUpdates"; - - this.sendPickData = function(controllerData) { - if (controllerData.triggerClicks[this.hand]) { - var hand = this.hand === RIGHT_HAND ? Controller.Standard.RightHand : Controller.Standard.LeftHand; - if (!this.triggerClicked) { - this.selectedTarget = controllerData.rayPicks[this.hand]; - if (!this.selectedTarget.intersects) { - Messages.sendLocalMessage(this.ENTITY_TOOL_UPDATES_CHANNEL, JSON.stringify({ - method: "clearSelection", - hand: hand - })); - } else { - if (this.selectedTarget.type === Picks.INTERSECTED_ENTITY) { - Messages.sendLocalMessage(this.ENTITY_TOOL_UPDATES_CHANNEL, JSON.stringify({ - method: "selectEntity", - entityID: this.selectedTarget.objectID, - hand: hand - })); - } else if (this.selectedTarget.type === Picks.INTERSECTED_OVERLAY) { - Messages.sendLocalMessage(this.ENTITY_TOOL_UPDATES_CHANNEL, JSON.stringify({ - method: "selectOverlay", - overlayID: this.selectedTarget.objectID, - hand: hand - })); - } - } - } - - this.triggerClicked = true; - } - - this.sendPointingAtData(controllerData); - }; - - this.sendPointingAtData = function(controllerData) { - var rayPick = controllerData.rayPicks[this.hand]; - var hudRayPick = controllerData.hudRayPicks[this.hand]; - var point2d = this.calculateNewReticlePosition(hudRayPick.intersection); - var desktopWindow = Window.isPointOnDesktopWindow(point2d); - var tablet = this.pointingAtTablet(rayPick.objectID); - var rightHand = this.hand === RIGHT_HAND; - Messages.sendLocalMessage(this.ENTITY_TOOL_UPDATES_CHANNEL, JSON.stringify({ - method: "pointingAt", - desktopWindow: desktopWindow, - tablet: tablet, - rightHand: rightHand - })); - }; - - this.runModule = function() { - return makeRunningValues(true, [], []); - }; - - this.exitModule = function() { - return makeRunningValues(false, [], []); - }; - - this.isReady = function(controllerData) { - if (isInEditMode()) { - if (controllerData.triggerValues[this.hand] < TRIGGER_ON_VALUE) { - this.triggerClicked = false; - } - Messages.sendLocalMessage('Hifi-unhighlight-all', ''); - return this.runModule(); - } - this.triggerClicked = false; - return this.exitModule(); - }; - - this.run = function(controllerData) { - - // Tablet stylus. - var tabletStylusInput = getEnabledModuleByName(this.hand === RIGHT_HAND - ? "RightTabletStylusInput" : "LeftTabletStylusInput"); - if (tabletStylusInput) { - var tabletReady = tabletStylusInput.isReady(controllerData); - if (tabletReady.active) { - return this.exitModule(); - } - } - - // Tablet surface. - var webLaser = getEnabledModuleByName(this.hand === RIGHT_HAND - ? "RightWebSurfaceLaserInput" : "LeftWebSurfaceLaserInput"); - if (webLaser) { - var webLaserReady = webLaser.isReady(controllerData); - var target = controllerData.rayPicks[this.hand].objectID; - this.sendPointingAtData(controllerData); - if (webLaserReady.active && this.pointingAtTablet(target)) { - return this.exitModule(); - } - } - - // HUD overlay. - if (!controllerData.triggerClicks[this.hand]) { // Don't grab if trigger pressed when laser starts intersecting. - var hudLaser = getEnabledModuleByName(this.hand === RIGHT_HAND - ? "RightHudOverlayPointer" : "LeftHudOverlayPointer"); - if (hudLaser) { - var hudLaserReady = hudLaser.isReady(controllerData); - if (hudLaserReady.active) { - return this.exitModule(); - } - } - } - - // Tablet highlight and grabbing. - var tabletHighlight = getEnabledModuleByName(this.hand === RIGHT_HAND - ? "RightNearTabletHighlight" : "LeftNearTabletHighlight"); - if (tabletHighlight) { - var tabletHighlightReady = tabletHighlight.isReady(controllerData); - if (tabletHighlightReady.active) { - return this.exitModule(); - } - } - - // Teleport. - var teleport = getEnabledModuleByName(this.hand === RIGHT_HAND ? "RightTeleporter" : "LeftTeleporter"); - if (teleport) { - var teleportReady = teleport.isReady(controllerData); - if (teleportReady.active) { - return this.exitModule(); - } - } - - if ((controllerData.triggerClicks[this.hand] === 0 && controllerData.secondaryValues[this.hand] === 0)) { - var stopRunning = false; - controllerData.nearbyOverlayIDs[this.hand].forEach(function(overlayID) { - var overlayName = Overlays.getProperty(overlayID, "name"); - if (overlayName === "KeyboardAnchor") { - stopRunning = true; - } - }); - - if (stopRunning) { - return this.exitModule(); - } - } - - this.sendPickData(controllerData); - return this.isReady(controllerData); - }; - } - - var leftHandInEditMode = new InEditMode(LEFT_HAND); - var rightHandInEditMode = new InEditMode(RIGHT_HAND); - - enableDispatcherModule("LeftHandInEditMode", leftHandInEditMode); - enableDispatcherModule("RightHandInEditMode", rightHandInEditMode); - - var INEDIT_STATUS_CHANNEL = "Hifi-InEdit-Status"; - var HAND_RAYPICK_BLACKLIST_CHANNEL = "Hifi-Hand-RayPick-Blacklist"; - this.handleMessage = function (channel, data, sender) { - if (channel === INEDIT_STATUS_CHANNEL && sender === MyAvatar.sessionUUID) { - var message; - - try { - message = JSON.parse(data); - } catch (e) { - return; - } - - switch (message.method) { - case "editing": - if (message.hand === LEFT_HAND) { - leftHandInEditMode.isEditing = message.editing; - } else { - rightHandInEditMode.isEditing = message.editing; - } - Messages.sendLocalMessage(HAND_RAYPICK_BLACKLIST_CHANNEL, JSON.stringify({ - action: "tablet", - hand: message.hand, - blacklist: message.editing - })); - break; - } - } - }; - Messages.subscribe(INEDIT_STATUS_CHANNEL); - Messages.messageReceived.connect(this.handleMessage); - - function cleanup() { - disableDispatcherModule("LeftHandInEditMode"); - disableDispatcherModule("RightHandInEditMode"); - } - - Script.scriptEnding.connect(cleanup); -}()); diff --git a/scripts/simplifiedUI/system/controllers/controllerModules/inVREditMode.js b/scripts/simplifiedUI/system/controllers/controllerModules/inVREditMode.js deleted file mode 100644 index 104e37d76c..0000000000 --- a/scripts/simplifiedUI/system/controllers/controllerModules/inVREditMode.js +++ /dev/null @@ -1,185 +0,0 @@ -"use strict"; - -// inVREditMode.js -// -// Created by David Rowe on 16 Sep 2017. -// Copyright 2017 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html - -/* global Script, HMD, Messages, MyAvatar, RIGHT_HAND, LEFT_HAND, enableDispatcherModule, disableDispatcherModule, - makeDispatcherModuleParameters, makeRunningValues, getEnabledModuleByName, makeLaserParams -*/ - -Script.include("/~/system/libraries/controllerDispatcherUtils.js"); - -(function () { - - function InVREditMode(hand) { - this.hand = hand; - this.isAppActive = false; - this.isEditing = false; - this.running = false; - var NO_HAND_LASER = -1; // Invalid hand parameter so that standard laser is not displayed. - this.parameters = makeDispatcherModuleParameters( - 166, // Slightly lower priority than inEditMode. - this.hand === RIGHT_HAND - ? ["rightHand", "rightHandEquip", "rightHandTrigger"] - : ["leftHand", "leftHandEquip", "leftHandTrigger"], - [], - 100, - makeLaserParams(NO_HAND_LASER, false) - ); - - this.pointingAtTablet = function (objectID) { - return (HMD.tabletScreenID && objectID === HMD.tabletScreenID) || - (HMD.homeButtonID && objectID === HMD.homeButtonID); - }; - - // The Shapes app has a non-standard laser: in particular, the laser end dot displays on its own when the laser is - // pointing at the Shapes UI. The laser on/off is controlled by this module but the laser is implemented in the Shapes - // app. - // If, in the future, the Shapes app laser interaction is adopted as a standard UI style then the laser could be - // implemented in the controller modules along side the other laser styles. - var INVREDIT_MODULE_RUNNING = "Hifi-InVREdit-Module-Running"; - - this.runModule = function () { - if (!this.running) { - Messages.sendLocalMessage(INVREDIT_MODULE_RUNNING, JSON.stringify({ - hand: this.hand, - running: true - })); - this.running = true; - } - return makeRunningValues(true, [], []); - }; - - this.exitModule = function () { - if (this.running) { - Messages.sendLocalMessage(INVREDIT_MODULE_RUNNING, JSON.stringify({ - hand: this.hand, - running: false - })); - this.running = false; - } - return makeRunningValues(false, [], []); - }; - - this.isReady = function (controllerData) { - if (this.isAppActive) { - return makeRunningValues(true, [], []); - } - return makeRunningValues(false, [], []); - }; - - this.run = function (controllerData) { - // Default behavior if disabling is not enabled. - if (!this.isAppActive) { - return this.exitModule(); - } - - // Tablet stylus. - var tabletStylusInput = getEnabledModuleByName(this.hand === RIGHT_HAND - ? "RightTabletStylusInput" : "LeftTabletStylusInput"); - if (tabletStylusInput) { - var tabletReady = tabletStylusInput.isReady(controllerData); - if (tabletReady.active) { - return this.exitModule(); - } - } - - // Tablet surface. - var overlayLaser = getEnabledModuleByName(this.hand === RIGHT_HAND - ? "RightWebSurfaceLaserInput" : "LeftWebSurfaceLaserInput"); - if (overlayLaser) { - var overlayLaserReady = overlayLaser.isReady(controllerData); - var target = controllerData.rayPicks[this.hand].objectID; - if (overlayLaserReady.active && this.pointingAtTablet(target)) { - return this.exitModule(); - } - } - - // Tablet highlight and grabbing. - var tabletHighlight = getEnabledModuleByName(this.hand === RIGHT_HAND - ? "RightNearTabletHighlight" : "LeftNearTabletHighlight"); - if (tabletHighlight) { - var tabletHighlightReady = tabletHighlight.isReady(controllerData); - if (tabletHighlightReady.active) { - return this.exitModule(); - } - } - - // HUD overlay. - if (!controllerData.triggerClicks[this.hand]) { - var hudLaser = getEnabledModuleByName(this.hand === RIGHT_HAND - ? "RightHudOverlayPointer" : "LeftHudOverlayPointer"); - if (hudLaser) { - var hudLaserReady = hudLaser.isReady(controllerData); - if (hudLaserReady.active) { - return this.exitModule(); - } - } - } - - // Teleport. - var teleporter = getEnabledModuleByName(this.hand === RIGHT_HAND - ? "RightTeleporter" : "LeftTeleporter"); - if (teleporter) { - var teleporterReady = teleporter.isReady(controllerData); - if (teleporterReady.active) { - return this.exitModule(); - } - } - - // Other behaviors are disabled. - return this.runModule(); - }; - } - - var leftHandInVREditMode = new InVREditMode(LEFT_HAND); - var rightHandInVREditMode = new InVREditMode(RIGHT_HAND); - enableDispatcherModule("LeftHandInVREditMode", leftHandInVREditMode); - enableDispatcherModule("RightHandInVREditMode", rightHandInVREditMode); - - var INVREDIT_STATUS_CHANNEL = "Hifi-InVREdit-Status"; - var HAND_RAYPICK_BLACKLIST_CHANNEL = "Hifi-Hand-RayPick-Blacklist"; - this.handleMessage = function (channel, data, sender) { - if (channel === INVREDIT_STATUS_CHANNEL && sender === MyAvatar.sessionUUID) { - var message; - - try { - message = JSON.parse(data); - } catch (e) { - return; - } - - switch (message.method) { - case "active": - leftHandInVREditMode.isAppActive = message.active; - rightHandInVREditMode.isAppActive = message.active; - break; - case "editing": - if (message.hand === LEFT_HAND) { - leftHandInVREditMode.isEditing = message.editing; - } else { - rightHandInVREditMode.isEditing = message.editing; - } - Messages.sendLocalMessage(HAND_RAYPICK_BLACKLIST_CHANNEL, JSON.stringify({ - action: "tablet", - hand: message.hand, - blacklist: message.editing - })); - break; - } - } - }; - Messages.subscribe(INVREDIT_STATUS_CHANNEL); - Messages.messageReceived.connect(this.handleMessage); - - this.cleanup = function () { - disableDispatcherModule("LeftHandInVREditMode"); - disableDispatcherModule("RightHandInVREditMode"); - }; - Script.scriptEnding.connect(this.cleanup); -}()); diff --git a/scripts/simplifiedUI/system/controllers/controllerModules/mouseHMD.js b/scripts/simplifiedUI/system/controllers/controllerModules/mouseHMD.js deleted file mode 100644 index 172923a8e2..0000000000 --- a/scripts/simplifiedUI/system/controllers/controllerModules/mouseHMD.js +++ /dev/null @@ -1,151 +0,0 @@ -// -// mouseHMD.js -// -// scripts/system/controllers/controllerModules/ -// -// Created by Dante Ruiz 2017-9-22 -// Copyright 2017 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -/* global Script, HMD, Reticle, Vec3, Controller */ - -(function() { - var ControllerDispatcherUtils = Script.require("/~/system/libraries/controllerDispatcherUtils.js"); - - function TimeLock(experation) { - this.experation = experation; - this.last = 0; - this.update = function(time) { - this.last = time || Date.now(); - }; - - this.expired = function(time) { - return ((time || Date.now()) - this.last) > this.experation; - }; - } - - function MouseHMD() { - var _this = this; - this.hmdWasActive = HMD.active; - this.mouseMoved = false; - this.mouseActivity = new TimeLock(5000); - this.handControllerActivity = new TimeLock(4000); - this.parameters = ControllerDispatcherUtils.makeDispatcherModuleParameters( - 10, - ["mouse"], - [], - 100); - - this.onMouseMove = function() { - _this.updateMouseActivity(); - }; - - this.onMouseClick = function() { - _this.updateMouseActivity(); - }; - - this.updateMouseActivity = function(isClick) { - if (_this.ignoreMouseActivity()) { - return; - } - - if (HMD.active) { - var now = Date.now(); - _this.mouseActivity.update(now); - } - }; - - this.adjustReticleDepth = function(controllerData) { - if (Reticle.isPointingAtSystemOverlay(Reticle.position)) { - var reticlePositionOnHUD = HMD.worldPointFromOverlay(Reticle.position); - Reticle.depth = Vec3.distance(reticlePositionOnHUD, HMD.position); - } else { - var APPARENT_MAXIMUM_DEPTH = 100.0; - var result = controllerData.mouseRayPick; - Reticle.depth = result.intersects ? result.distance : APPARENT_MAXIMUM_DEPTH; - } - }; - - this.ignoreMouseActivity = function() { - if (!Reticle.allowMouseCapture) { - return true; - } - - var pos = Reticle.position; - if (!pos || (pos.x === -1 && pos.y === -1)) { - return true; - } - - if (!_this.handControllerActivity.expired()) { - return true; - } - - return false; - }; - - this.triggersPressed = function(controllerData, now) { - var onValue = ControllerDispatcherUtils.TRIGGER_ON_VALUE; - var rightHand = ControllerDispatcherUtils.RIGHT_HAND; - var leftHand = ControllerDispatcherUtils.LEFT_HAND; - var leftTriggerValue = controllerData.triggerValues[leftHand]; - var rightTriggerValue = controllerData.triggerValues[rightHand]; - - if (leftTriggerValue > onValue || rightTriggerValue > onValue) { - this.handControllerActivity.update(now); - return true; - } - - return false; - }; - - this.isReady = function(controllerData, deltaTime) { - var now = Date.now(); - var hmdChanged = this.hmdWasActive !== HMD.active; - this.hmdWasActive = HMD.active; - this.triggersPressed(controllerData, now); - if (HMD.active) { - if (!this.mouseActivity.expired(now) && _this.handControllerActivity.expired()) { - Reticle.visible = true; - return ControllerDispatcherUtils.makeRunningValues(true, [], []); - } else { - Reticle.visible = false; - } - } else if (hmdChanged && !Reticle.visible) { - Reticle.visible = true; - } - - return ControllerDispatcherUtils.makeRunningValues(false, [], []); - }; - - this.run = function(controllerData, deltaTime) { - var now = Date.now(); - var hmdActive = HMD.active; - if (this.mouseActivity.expired(now) || this.triggersPressed(controllerData, now) || !hmdActive) { - if (!hmdActive) { - Reticle.visible = true; - } else { - Reticle.visible = false; - } - - return ControllerDispatcherUtils.makeRunningValues(false, [], []); - } - this.adjustReticleDepth(controllerData); - return ControllerDispatcherUtils.makeRunningValues(true, [], []); - }; - } - - var mouseHMD = new MouseHMD(); - ControllerDispatcherUtils.enableDispatcherModule("MouseHMD", mouseHMD); - - Controller.mouseMoveEvent.connect(mouseHMD.onMouseMove); - Controller.mousePressEvent.connect(mouseHMD.onMouseClick); - - function cleanup() { - ControllerDispatcherUtils.disableDispatcherModule("MouseHMD"); - } - - Script.scriptEnding.connect(cleanup); -})(); diff --git a/scripts/simplifiedUI/system/controllers/controllerModules/nearGrabEntity.js b/scripts/simplifiedUI/system/controllers/controllerModules/nearGrabEntity.js deleted file mode 100644 index 763c1a1ce0..0000000000 --- a/scripts/simplifiedUI/system/controllers/controllerModules/nearGrabEntity.js +++ /dev/null @@ -1,226 +0,0 @@ -"use strict"; - -// nearGrabEntity.js -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html - - -/* global Script, Entities, MyAvatar, Controller, RIGHT_HAND, LEFT_HAND, getControllerJointIndex, enableDispatcherModule, - disableDispatcherModule, Messages, HAPTIC_PULSE_STRENGTH, HAPTIC_PULSE_DURATION, TRIGGER_OFF_VALUE, - makeDispatcherModuleParameters, entityIsGrabbable, makeRunningValues, NEAR_GRAB_RADIUS, findGrabbableGroupParent, Vec3, - cloneEntity, entityIsCloneable, HAPTIC_PULSE_STRENGTH, HAPTIC_PULSE_DURATION, BUMPER_ON_VALUE, - distanceBetweenPointAndEntityBoundingBox, getGrabbableData, getEnabledModuleByName, DISPATCHER_PROPERTIES, HMD, - NEAR_GRAB_DISTANCE -*/ - -Script.include("/~/system/libraries/controllerDispatcherUtils.js"); -Script.include("/~/system/libraries/cloneEntityUtils.js"); -Script.include("/~/system/libraries/controllers.js"); - -(function() { - - function NearGrabEntity(hand) { - this.hand = hand; - this.targetEntityID = null; - this.grabbing = false; - this.cloneAllowed = true; - this.grabID = null; - - this.parameters = makeDispatcherModuleParameters( - 500, - this.hand === RIGHT_HAND ? ["rightHand"] : ["leftHand"], - [], - 100); - - this.startGrab = function (targetProps) { - if (this.grabID) { - MyAvatar.releaseGrab(this.grabID); - } - - var grabData = getGrabbableData(targetProps); - - var handJointIndex; - if (HMD.mounted && HMD.isHandControllerAvailable() && grabData.grabFollowsController) { - handJointIndex = getControllerJointIndex(this.hand); - } else { - handJointIndex = MyAvatar.getJointIndex(this.hand === RIGHT_HAND ? "RightHand" : "LeftHand"); - } - - this.targetEntityID = targetProps.id; - - var relativePosition = Entities.worldToLocalPosition(targetProps.position, MyAvatar.SELF_ID, handJointIndex); - var relativeRotation = Entities.worldToLocalRotation(targetProps.rotation, MyAvatar.SELF_ID, handJointIndex); - this.grabID = MyAvatar.grab(targetProps.id, handJointIndex, relativePosition, relativeRotation); - }; - - this.startNearGrabEntity = function (targetProps) { - Controller.triggerHapticPulse(HAPTIC_PULSE_STRENGTH, HAPTIC_PULSE_DURATION, this.hand); - - this.startGrab(targetProps); - - var args = [this.hand === RIGHT_HAND ? "right" : "left", MyAvatar.sessionUUID]; - Entities.callEntityMethod(targetProps.id, "startNearGrab", args); - - Messages.sendMessage('Hifi-Object-Manipulation', JSON.stringify({ - action: 'grab', - grabbedEntity: targetProps.id, - joint: this.hand === RIGHT_HAND ? "RightHand" : "LeftHand" - })); - - this.grabbing = true; - }; - - this.endGrab = function () { - if (this.grabID) { - MyAvatar.releaseGrab(this.grabID); - this.grabID = null; - } - }; - - this.endNearGrabEntity = function () { - this.endGrab(); - - var args = [this.hand === RIGHT_HAND ? "right" : "left", MyAvatar.sessionUUID]; - Entities.callEntityMethod(this.targetEntityID, "releaseGrab", args); - Messages.sendMessage('Hifi-Object-Manipulation', JSON.stringify({ - action: 'release', - grabbedEntity: this.targetEntityID, - joint: this.hand === RIGHT_HAND ? "RightHand" : "LeftHand" - })); - - this.grabbing = false; - this.targetEntityID = null; - }; - - this.getTargetProps = function (controllerData) { - // nearbyEntityProperties is already sorted by length from controller - var nearbyEntityProperties = controllerData.nearbyEntityProperties[this.hand]; - var sensorScaleFactor = MyAvatar.sensorToWorldScale; - var nearGrabDistance = NEAR_GRAB_DISTANCE * sensorScaleFactor; - var nearGrabRadius = NEAR_GRAB_RADIUS * sensorScaleFactor; - for (var i = 0; i < nearbyEntityProperties.length; i++) { - var props = nearbyEntityProperties[i]; - var grabPosition = controllerData.controllerLocations[this.hand].position; // Is offset from hand position. - var dist = distanceBetweenPointAndEntityBoundingBox(grabPosition, props); - var distance = Vec3.distance(grabPosition, props.position); - if ((dist > nearGrabDistance) || - (distance > nearGrabRadius)) { // Only smallish entities can be near grabbed. - continue; - } - if (entityIsGrabbable(props) || entityIsCloneable(props)) { - if (!entityIsCloneable(props)) { - // if we've attempted to grab a non-cloneable child, roll up to the root of the tree - var groupRootProps = findGrabbableGroupParent(controllerData, props); - if (entityIsGrabbable(groupRootProps)) { - return groupRootProps; - } - } - return props; - } - } - return null; - }; - - this.isReady = function (controllerData, deltaTime) { - this.targetEntityID = null; - this.grabbing = false; - - if (controllerData.triggerValues[this.hand] < TRIGGER_OFF_VALUE && - controllerData.secondaryValues[this.hand] < TRIGGER_OFF_VALUE) { - this.cloneAllowed = true; - return makeRunningValues(false, [], []); - } - - var scaleModuleName = this.hand === RIGHT_HAND ? "RightScaleEntity" : "LeftScaleEntity"; - var scaleModule = getEnabledModuleByName(scaleModuleName); - if (scaleModule && (scaleModule.grabbedThingID || scaleModule.isReady(controllerData).active)) { - // we're rescaling -- don't start a grab. - return makeRunningValues(false, [], []); - } - - var targetProps = this.getTargetProps(controllerData); - if (targetProps) { - this.targetEntityID = targetProps.id; - return makeRunningValues(true, [this.targetEntityID], []); - } else { - return makeRunningValues(false, [], []); - } - }; - - this.run = function (controllerData, deltaTime) { - - if (this.grabbing) { - if (controllerData.triggerClicks[this.hand] < TRIGGER_OFF_VALUE && - controllerData.secondaryValues[this.hand] < TRIGGER_OFF_VALUE) { - this.endNearGrabEntity(); - return makeRunningValues(false, [], []); - } - - var props = controllerData.nearbyEntityPropertiesByID[this.targetEntityID]; - if (!props) { - props = Entities.getEntityProperties(this.targetEntityID, DISPATCHER_PROPERTIES); - if (!props) { - // entity was deleted - this.grabbing = false; - this.targetEntityID = null; - return makeRunningValues(false, [], []); - } - } - - var args = [this.hand === RIGHT_HAND ? "right" : "left", MyAvatar.sessionUUID]; - Entities.callEntityMethod(this.targetEntityID, "continueNearGrab", args); - } else { - // still searching - var readiness = this.isReady(controllerData); - if (!readiness.active) { - return readiness; - } - if (controllerData.triggerClicks[this.hand] || controllerData.secondaryValues[this.hand] > BUMPER_ON_VALUE) { - // switch to grab - var targetProps = this.getTargetProps(controllerData); - var targetCloneable = entityIsCloneable(targetProps); - - if (targetCloneable) { - if (this.cloneAllowed) { - var cloneID = cloneEntity(targetProps); - if (cloneID !== null) { - var cloneProps = Entities.getEntityProperties(cloneID, DISPATCHER_PROPERTIES); - cloneProps.id = cloneID; - this.grabbing = true; - this.targetEntityID = cloneID; - this.startNearGrabEntity(cloneProps); - this.cloneAllowed = false; // prevent another clone call until inputs released - } - } - } else if (targetProps) { - this.grabbing = true; - this.startNearGrabEntity(targetProps); - } - } - } - - return makeRunningValues(true, [this.targetEntityID], []); - }; - - this.cleanup = function () { - if (this.targetEntityID) { - this.endNearGrabEntity(); - } - }; - } - - var leftNearGrabEntity = new NearGrabEntity(LEFT_HAND); - var rightNearGrabEntity = new NearGrabEntity(RIGHT_HAND); - - enableDispatcherModule("LeftNearGrabEntity", leftNearGrabEntity); - enableDispatcherModule("RightNearGrabEntity", rightNearGrabEntity); - - function cleanup() { - leftNearGrabEntity.cleanup(); - rightNearGrabEntity.cleanup(); - disableDispatcherModule("LeftNearGrabEntity"); - disableDispatcherModule("RightNearGrabEntity"); - } - Script.scriptEnding.connect(cleanup); -}()); diff --git a/scripts/simplifiedUI/system/controllers/controllerModules/nearGrabHyperLinkEntity.js b/scripts/simplifiedUI/system/controllers/controllerModules/nearGrabHyperLinkEntity.js deleted file mode 100644 index 962ae89bb9..0000000000 --- a/scripts/simplifiedUI/system/controllers/controllerModules/nearGrabHyperLinkEntity.js +++ /dev/null @@ -1,91 +0,0 @@ -"use strict"; - -// nearGrabHyperLinkEntity.js -// -// Created by Dante Ruiz on 03/02/2018 -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html - -/* global Script, MyAvatar, RIGHT_HAND, LEFT_HAND, enableDispatcherModule, disableDispatcherModule, - makeDispatcherModuleParameters, makeRunningValues, TRIGGER_OFF_VALUE, NEAR_GRAB_RADIUS, BUMPER_ON_VALUE, AddressManager -*/ - -(function() { - Script.include("/~/system/libraries/controllerDispatcherUtils.js"); - Script.include("/~/system/libraries/controllers.js"); - - function NearGrabHyperLinkEntity(hand) { - this.hand = hand; - this.targetEntityID = null; - this.hyperlink = ""; - - this.parameters = makeDispatcherModuleParameters( - 485, - this.hand === RIGHT_HAND ? ["rightHand"] : ["leftHand"], - [], - 100); - - - this.getTargetProps = function(controllerData) { - var nearbyEntitiesProperties = controllerData.nearbyEntityProperties[this.hand]; - var sensorScaleFactor = MyAvatar.sensorToWorldScale; - for (var i = 0; i < nearbyEntitiesProperties.length; i++) { - var props = nearbyEntitiesProperties[i]; - if (props.distance > NEAR_GRAB_RADIUS * sensorScaleFactor) { - continue; - } - if (props.href !== "" && props.href !== undefined) { - return props; - } - } - return null; - }; - - this.isReady = function(controllerData) { - this.targetEntityID = null; - if (controllerData.triggerValues[this.hand] < TRIGGER_OFF_VALUE && - controllerData.secondaryValues[this.hand] < TRIGGER_OFF_VALUE) { - return makeRunningValues(false, [], []); - } - - var targetProps = this.getTargetProps(controllerData); - if (targetProps) { - this.hyperlink = targetProps.href; - this.targetEntityID = targetProps.id; - return makeRunningValues(true, [], []); - } - - return makeRunningValues(false, [], []); - }; - - this.run = function(controllerData) { - if ((controllerData.triggerClicks[this.hand] < TRIGGER_OFF_VALUE && - controllerData.secondaryValues[this.hand] < TRIGGER_OFF_VALUE) || this.hyperlink === "") { - return makeRunningValues(false, [], []); - } - - if (controllerData.triggerClicks[this.hand] || - controllerData.secondaryValues[this.hand] > BUMPER_ON_VALUE) { - AddressManager.handleLookupString(this.hyperlink); - return makeRunningValues(false, [], []); - } - - return makeRunningValues(true, [], []); - }; - } - - var leftNearGrabHyperLinkEntity = new NearGrabHyperLinkEntity(LEFT_HAND); - var rightNearGrabHyperLinkEntity = new NearGrabHyperLinkEntity(RIGHT_HAND); - - enableDispatcherModule("LeftNearGrabHyperLink", leftNearGrabHyperLinkEntity); - enableDispatcherModule("RightNearGrabHyperLink", rightNearGrabHyperLinkEntity); - - function cleanup() { - disableDispatcherModule("LeftNearGrabHyperLink"); - disableDispatcherModule("RightNearGrabHyperLink"); - - } - - Script.scriptEnding.connect(cleanup); -}()); diff --git a/scripts/simplifiedUI/system/controllers/controllerModules/nearParentGrabOverlay.js b/scripts/simplifiedUI/system/controllers/controllerModules/nearParentGrabOverlay.js deleted file mode 100644 index 5dcfee23cb..0000000000 --- a/scripts/simplifiedUI/system/controllers/controllerModules/nearParentGrabOverlay.js +++ /dev/null @@ -1,255 +0,0 @@ -"use strict"; - -// nearParentGrabOverlay.js -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html - - -/* global Script, MyAvatar, Controller, RIGHT_HAND, LEFT_HAND, getControllerJointIndex, - enableDispatcherModule, disableDispatcherModule, Messages, HAPTIC_PULSE_STRENGTH, HAPTIC_PULSE_DURATION, - makeDispatcherModuleParameters, Overlays, makeRunningValues, Vec3, resizeTablet, getTabletWidthFromSettings, - NEAR_GRAB_RADIUS, HMD, Uuid, getEnabledModuleByName -*/ - -Script.include("/~/system/libraries/controllerDispatcherUtils.js"); -Script.include("/~/system/libraries/utils.js"); - -(function() { - - // XXX this.ignoreIK = (grabbableData.ignoreIK !== undefined) ? grabbableData.ignoreIK : true; - // XXX this.kinematicGrab = (grabbableData.kinematic !== undefined) ? grabbableData.kinematic : NEAR_GRABBING_KINEMATIC; - - function NearParentingGrabOverlay(hand) { - this.hand = hand; - this.grabbedThingID = null; - this.previousParentID = {}; - this.previousParentJointIndex = {}; - this.previouslyUnhooked = {}; - this.robbed = false; - - this.parameters = makeDispatcherModuleParameters( - 90, - this.hand === RIGHT_HAND ? ["rightHand"] : ["leftHand"], - [], - 100); - - - // XXX does handJointIndex change if the avatar changes? - this.handJointIndex = MyAvatar.getJointIndex(this.hand === RIGHT_HAND ? "RightHand" : "LeftHand"); - - this.getOtherModule = function() { - return (this.hand === RIGHT_HAND) ? leftNearParentingGrabOverlay : rightNearParentingGrabOverlay; - }; - - this.otherHandIsParent = function(props) { - return this.getOtherModule().thisHandIsParent(props); - }; - - this.isGrabbedThingVisible = function() { - return Overlays.getProperty(this.grabbedThingID, "visible"); - }; - - this.thisHandIsParent = function(props) { - if (props.parentID !== MyAvatar.sessionUUID && props.parentID !== MyAvatar.SELF_ID) { - return false; - } - - var handJointIndex = MyAvatar.getJointIndex(this.hand === RIGHT_HAND ? "RightHand" : "LeftHand"); - if (props.parentJointIndex === handJointIndex) { - return true; - } - - var controllerJointIndex = this.controllerJointIndex; - if (props.parentJointIndex === controllerJointIndex) { - return true; - } - - var controllerCRJointIndex = MyAvatar.getJointIndex(this.hand === RIGHT_HAND ? - "_CAMERA_RELATIVE_CONTROLLER_RIGHTHAND" : - "_CAMERA_RELATIVE_CONTROLLER_LEFTHAND"); - - if (props.parentJointIndex === controllerCRJointIndex) { - return true; - } - - return false; - }; - - this.getGrabbedProperties = function() { - return { - position: Overlays.getProperty(this.grabbedThingID, "position"), - rotation: Overlays.getProperty(this.grabbedThingID, "rotation"), - parentID: Overlays.getProperty(this.grabbedThingID, "parentID"), - parentJointIndex: Overlays.getProperty(this.grabbedThingID, "parentJointIndex"), - dynamic: false, - shapeType: "none" - }; - }; - - - this.startNearParentingGrabOverlay = function (controllerData) { - Controller.triggerHapticPulse(HAPTIC_PULSE_STRENGTH, HAPTIC_PULSE_DURATION, this.hand); - - this.controllerJointIndex = getControllerJointIndex(this.hand); - var handJointIndex = this.controllerJointIndex; - - var grabbedProperties = this.getGrabbedProperties(); - - var reparentProps = { - parentID: MyAvatar.SELF_ID, - parentJointIndex: handJointIndex, - velocity: {x: 0, y: 0, z: 0}, - angularVelocity: {x: 0, y: 0, z: 0} - }; - - if (this.thisHandIsParent(grabbedProperties)) { - // this should never happen, but if it does, don't set previous parent to be this hand. - // this.previousParentID[this.grabbedThingID] = NULL; - // this.previousParentJointIndex[this.grabbedThingID] = -1; - } else if (this.otherHandIsParent(grabbedProperties)) { - // the other hand is parent. Steal the object and information - var otherModule = this.getOtherModule(); - this.previousParentID[this.grabbedThingID] = otherModule.previousParentID[this.grabbedThingID]; - this.previousParentJointIndex[this.grabbedThingID] = otherModule.previousParentJointIndex[this.grabbedThingID]; - otherModule.robbed = true; - } else { - this.previousParentID[this.grabbedThingID] = grabbedProperties.parentID; - this.previousParentJointIndex[this.grabbedThingID] = grabbedProperties.parentJointIndex; - } - - // resizeTablet to counter adjust offsets to account for change of scale from sensorToWorldMatrix - if (HMD.tabletID && this.grabbedThingID === HMD.tabletID) { - reparentAndScaleTablet(getTabletWidthFromSettings(), reparentProps); - } else { - Entities.editEntity(this.grabbedThingID, reparentProps); - } - - Messages.sendMessage('Hifi-Object-Manipulation', JSON.stringify({ - action: 'grab', - grabbedEntity: this.grabbedThingID, - joint: this.hand === RIGHT_HAND ? "RightHand" : "LeftHand" - })); - }; - - this.endNearParentingGrabOverlay = function () { - var previousParentID = this.previousParentID[this.grabbedThingID]; - if ((previousParentID === Uuid.NULL || previousParentID === null) && !this.robbed) { - Overlays.editOverlay(this.grabbedThingID, { - parentID: Uuid.NULL, - parentJointIndex: -1 - }); - } else if (!this.robbed){ - // before we grabbed it, overlay was a child of something; put it back. - Entities.editEntity(this.grabbedThingID, { - parentID: this.previousParentID[this.grabbedThingID], - parentJointIndex: this.previousParentJointIndex[this.grabbedThingID] - }); - - // resizeTablet to counter adjust offsets to account for change of scale from sensorToWorldMatrix - if (HMD.tabletID && this.grabbedThingID === HMD.tabletID) { - resizeTablet(getTabletWidthFromSettings(), this.previousParentJointIndex[this.grabbedThingID]); - } - } - - Messages.sendMessage('Hifi-Object-Manipulation', JSON.stringify({ - action: 'release', - grabbedEntity: this.grabbedThingID, - joint: this.hand === RIGHT_HAND ? "RightHand" : "LeftHand" - })); - - this.grabbedThingID = null; - }; - - this.getTargetID = function(overlays, controllerData) { - var sensorScaleFactor = MyAvatar.sensorToWorldScale; - for (var i = 0; i < overlays.length; i++) { - var overlayPosition = Overlays.getProperty(overlays[i], "position"); - var handPosition = controllerData.controllerLocations[this.hand].position; - var distance = Vec3.distance(overlayPosition, handPosition); - if (distance <= NEAR_GRAB_RADIUS * sensorScaleFactor) { - if (overlays[i] !== HMD.miniTabletID || controllerData.secondaryValues[this.hand] === 0) { - // Don't grab mini tablet with grip. - return overlays[i]; - } - } - } - return null; - }; - - this.isEditing = function () { - var inEditModeModule = getEnabledModuleByName(this.hand === RIGHT_HAND - ? "RightHandInEditMode" : "LeftHandInEditMode"); - if (inEditModeModule && inEditModeModule.isEditing) { - return true; - } - var inVREditModeModule = getEnabledModuleByName(this.hand === RIGHT_HAND - ? "RightHandInVREditMode" : "LeftHandInVREditMode"); - if (inVREditModeModule && inVREditModeModule.isEditing) { - return true; - } - return false; - }; - - this.isReady = function (controllerData) { - if ((controllerData.triggerClicks[this.hand] === 0 && controllerData.secondaryValues[this.hand] === 0) - || this.isEditing()) { - this.robbed = false; - return makeRunningValues(false, [], []); - } - - this.grabbedThingID = null; - - var candidateOverlays = controllerData.nearbyOverlayIDs[this.hand]; - var grabbableOverlays = candidateOverlays.filter(function(overlayID) { - return Overlays.getProperty(overlayID, "grabbable"); - }); - - var targetID = this.getTargetID(grabbableOverlays, controllerData); - if (targetID && !this.robbed) { - this.grabbedThingID = targetID; - this.startNearParentingGrabOverlay(controllerData); - return makeRunningValues(true, [this.grabbedThingID], []); - } else { - return makeRunningValues(false, [], []); - } - }; - - this.run = function (controllerData) { - if ((controllerData.triggerClicks[this.hand] === 0 && controllerData.secondaryValues[this.hand] === 0) - || this.isEditing() || !this.isGrabbedThingVisible()) { - this.endNearParentingGrabOverlay(); - this.robbed = false; - return makeRunningValues(false, [], []); - } else { - // check if someone stole the target from us - var grabbedProperties = this.getGrabbedProperties(); - if (!this.thisHandIsParent(grabbedProperties)) { - return makeRunningValues(false, [], []); - } - - return makeRunningValues(true, [this.grabbedThingID], []); - } - }; - - this.cleanup = function () { - if (this.grabbedThingID) { - this.endNearParentingGrabOverlay(); - } - }; - } - - var leftNearParentingGrabOverlay = new NearParentingGrabOverlay(LEFT_HAND); - var rightNearParentingGrabOverlay = new NearParentingGrabOverlay(RIGHT_HAND); - - enableDispatcherModule("LeftNearParentingGrabOverlay", leftNearParentingGrabOverlay); - enableDispatcherModule("RightNearParentingGrabOverlay", rightNearParentingGrabOverlay); - - function cleanup() { - leftNearParentingGrabOverlay.cleanup(); - rightNearParentingGrabOverlay.cleanup(); - disableDispatcherModule("LeftNearParentingGrabOverlay"); - disableDispatcherModule("RightNearParentingGrabOverlay"); - } - Script.scriptEnding.connect(cleanup); -}()); diff --git a/scripts/simplifiedUI/system/controllers/controllerModules/nearTabletHighlight.js b/scripts/simplifiedUI/system/controllers/controllerModules/nearTabletHighlight.js deleted file mode 100644 index 2e046f5dc6..0000000000 --- a/scripts/simplifiedUI/system/controllers/controllerModules/nearTabletHighlight.js +++ /dev/null @@ -1,135 +0,0 @@ -// -// nearTabletHighlight.js -// -// Highlight the tablet if a hand is near enough to grab it and it isn't grabbed. -// -// Created by David Rowe on 28 Aug 2018. -// Copyright 2018 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -/* global LEFT_HAND, RIGHT_HAND, makeDispatcherModuleParameters, makeRunningValues, enableDispatcherModule, - * disableDispatcherModule, getEnabledModuleByName */ - -Script.include("/~/system/libraries/controllerDispatcherUtils.js"); - -(function () { - - "use strict"; - - var TABLET_GRABBABLE_SELECTION_NAME = "tabletGrabbableSelection"; - var TABLET_GRABBABLE_SELECTION_STYLE = { - outlineUnoccludedColor: { red: 0, green: 180, blue: 239 }, // #00b4ef - outlineUnoccludedAlpha: 1, - outlineOccludedColor: { red: 0, green: 0, blue: 0 }, - outlineOccludedAlpha: 0, - fillUnoccludedColor: { red: 0, green: 0, blue: 0 }, - fillUnoccludedAlpha: 0, - fillOccludedColor: { red: 0, green: 0, blue: 0 }, - fillOccludedAlpha: 0, - outlineWidth: 4, - isOutlineSmooth: false - }; - - var isTabletNearGrabbable = [false, false]; - var isTabletHighlighted = false; - - function setTabletNearGrabbable(hand, enabled) { - if (enabled === isTabletNearGrabbable[hand]) { - return; - } - - isTabletNearGrabbable[hand] = enabled; - - if (isTabletNearGrabbable[LEFT_HAND] || isTabletNearGrabbable[RIGHT_HAND]) { - if (!isTabletHighlighted) { - Selection.addToSelectedItemsList(TABLET_GRABBABLE_SELECTION_NAME, "overlay", HMD.tabletID); - isTabletHighlighted = true; - } - } else { - if (isTabletHighlighted) { - Selection.removeFromSelectedItemsList(TABLET_GRABBABLE_SELECTION_NAME, "overlay", HMD.tabletID); - isTabletHighlighted = false; - } - } - } - - function NearTabletHighlight(hand) { - this.hand = hand; - - this.parameters = makeDispatcherModuleParameters( - 95, - this.hand === RIGHT_HAND ? ["rightHand"] : ["leftHand"], - [], - 100 - ); - - this.isEditing = function () { - var inEditModeModule = getEnabledModuleByName(this.hand === RIGHT_HAND - ? "RightHandInEditMode" : "LeftHandInEditMode"); - if (inEditModeModule && inEditModeModule.isEditing) { - return true; - } - var inVREditModeModule = getEnabledModuleByName(this.hand === RIGHT_HAND - ? "RightHandInVREditMode" : "LeftHandInVREditMode"); - if (inVREditModeModule && inVREditModeModule.isEditing) { - return true; - } - return false; - }; - - this.isNearTablet = function (controllerData) { - return HMD.tabletID && controllerData.nearbyOverlayIDs[this.hand].indexOf(HMD.tabletID) !== -1; - }; - - this.isReady = function (controllerData) { - if (!this.isEditing() && this.isNearTablet(controllerData)) { - return makeRunningValues(true, [], []); - } - setTabletNearGrabbable(this.hand, false); - return makeRunningValues(false, [], []); - }; - - this.run = function (controllerData) { - if (this.isEditing() || !this.isNearTablet(controllerData)) { - setTabletNearGrabbable(this.hand, false); - return makeRunningValues(false, [], []); - } - - if (controllerData.triggerClicks[this.hand] || controllerData.secondaryValues[this.hand]) { - setTabletNearGrabbable(this.hand, false); - return makeRunningValues(false, [], []); - } - - setTabletNearGrabbable(this.hand, true); - return makeRunningValues(true, [], []); - }; - } - - var leftNearTabletHighlight = new NearTabletHighlight(LEFT_HAND); - var rightNearTabletHighlight = new NearTabletHighlight(RIGHT_HAND); - enableDispatcherModule("LeftNearTabletHighlight", leftNearTabletHighlight); - enableDispatcherModule("RightNearTabletHighlight", rightNearTabletHighlight); - - function onDisplayModeChanged() { - if (HMD.active) { - Selection.enableListHighlight(TABLET_GRABBABLE_SELECTION_NAME, TABLET_GRABBABLE_SELECTION_STYLE); - } else { - Selection.disableListHighlight(TABLET_GRABBABLE_SELECTION_NAME); - Selection.clearSelectedItemsList(TABLET_GRABBABLE_SELECTION_NAME); - } - } - HMD.displayModeChanged.connect(onDisplayModeChanged); - HMD.mountedChanged.connect(onDisplayModeChanged); - onDisplayModeChanged(); - - function cleanUp() { - disableDispatcherModule("LeftNearTabletHighlight"); - disableDispatcherModule("RightNearTabletHighlight"); - Selection.disableListHighlight(TABLET_GRABBABLE_SELECTION_NAME); - } - Script.scriptEnding.connect(cleanUp); - -}()); diff --git a/scripts/simplifiedUI/system/controllers/controllerModules/nearTrigger.js b/scripts/simplifiedUI/system/controllers/controllerModules/nearTrigger.js deleted file mode 100644 index 4bff4ea3f0..0000000000 --- a/scripts/simplifiedUI/system/controllers/controllerModules/nearTrigger.js +++ /dev/null @@ -1,120 +0,0 @@ -"use strict"; - -// nearTrigger.js -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html - - -/* global Script, Entities, MyAvatar, RIGHT_HAND, LEFT_HAND, enableDispatcherModule, disableDispatcherModule, getGrabbableData, - Vec3, TRIGGER_OFF_VALUE, makeDispatcherModuleParameters, makeRunningValues, NEAR_GRAB_RADIUS -*/ - -Script.include("/~/system/libraries/controllerDispatcherUtils.js"); - -(function() { - - function entityWantsNearTrigger(props) { - var grabbableData = getGrabbableData(props); - return grabbableData.triggerable; - } - - function NearTriggerEntity(hand) { - this.hand = hand; - this.targetEntityID = null; - this.grabbing = false; - this.previousParentID = {}; - this.previousParentJointIndex = {}; - this.previouslyUnhooked = {}; - this.startSent = false; - - this.parameters = makeDispatcherModuleParameters( - 480, - this.hand === RIGHT_HAND ? ["rightHandTrigger", "rightHand"] : ["leftHandTrigger", "leftHand"], - [], - 100); - - this.getTargetProps = function (controllerData) { - // nearbyEntityProperties is already sorted by length from controller - var nearbyEntityProperties = controllerData.nearbyEntityProperties[this.hand]; - var sensorScaleFactor = MyAvatar.sensorToWorldScale; - for (var i = 0; i < nearbyEntityProperties.length; i++) { - var props = nearbyEntityProperties[i]; - var handPosition = controllerData.controllerLocations[this.hand].position; - var distance = Vec3.distance(props.position, handPosition); - if (distance > NEAR_GRAB_RADIUS * sensorScaleFactor) { - continue; - } - if (entityWantsNearTrigger(props)) { - return props; - } - } - return null; - }; - - this.startNearTrigger = function (controllerData) { - var args = [this.hand === RIGHT_HAND ? "right" : "left", MyAvatar.sessionUUID]; - Entities.callEntityMethod(this.targetEntityID, "startNearTrigger", args); - }; - - this.continueNearTrigger = function (controllerData) { - var args = [this.hand === RIGHT_HAND ? "right" : "left", MyAvatar.sessionUUID]; - Entities.callEntityMethod(this.targetEntityID, "continueNearTrigger", args); - }; - - this.endNearTrigger = function (controllerData) { - var args = [this.hand === RIGHT_HAND ? "right" : "left", MyAvatar.sessionUUID]; - Entities.callEntityMethod(this.targetEntityID, "stopNearTrigger", args); - }; - - this.isReady = function (controllerData) { - this.targetEntityID = null; - - if (controllerData.triggerValues[this.hand] < TRIGGER_OFF_VALUE) { - return makeRunningValues(false, [], []); - } - - var targetProps = this.getTargetProps(controllerData); - if (targetProps) { - this.targetEntityID = targetProps.id; - return makeRunningValues(true, [this.targetEntityID], []); - } else { - return makeRunningValues(false, [], []); - } - }; - - this.run = function (controllerData) { - if (!this.startSent) { - this.startNearTrigger(controllerData); - this.startSent = true; - } else if (controllerData.triggerValues[this.hand] < TRIGGER_OFF_VALUE) { - this.endNearTrigger(controllerData); - this.startSent = false; - return makeRunningValues(false, [], []); - } else { - this.continueNearTrigger(controllerData); - } - return makeRunningValues(true, [this.targetEntityID], []); - }; - - this.cleanup = function () { - if (this.targetEntityID) { - this.endNearTrigger(); - } - }; - } - - var leftNearTriggerEntity = new NearTriggerEntity(LEFT_HAND); - var rightNearTriggerEntity = new NearTriggerEntity(RIGHT_HAND); - - enableDispatcherModule("LeftNearTriggerEntity", leftNearTriggerEntity); - enableDispatcherModule("RightNearTriggerEntity", rightNearTriggerEntity); - - function cleanup() { - leftNearTriggerEntity.cleanup(); - rightNearTriggerEntity.cleanup(); - disableDispatcherModule("LeftNearTriggerEntity"); - disableDispatcherModule("RightNearTriggerEntity"); - } - Script.scriptEnding.connect(cleanup); -}()); diff --git a/scripts/simplifiedUI/system/controllers/controllerModules/pushToTalk.js b/scripts/simplifiedUI/system/controllers/controllerModules/pushToTalk.js deleted file mode 100644 index 11335ba2f5..0000000000 --- a/scripts/simplifiedUI/system/controllers/controllerModules/pushToTalk.js +++ /dev/null @@ -1,64 +0,0 @@ -"use strict"; - -// Created by Jason C. Najera on 3/7/2019 -// Copyright 2019 High Fidelity, Inc. -// -// Handles Push-to-Talk functionality for HMD mode. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html - -Script.include("/~/system/libraries/controllerDispatcherUtils.js"); -Script.include("/~/system/libraries/controllers.js"); - -(function() { // BEGIN LOCAL_SCOPE - function PushToTalkHandler() { - var _this = this; - this.active = false; - - this.shouldTalk = function (controllerData) { - // Set up test against controllerData here... - var gripVal = controllerData.secondaryValues[LEFT_HAND] && controllerData.secondaryValues[RIGHT_HAND]; - return (gripVal) ? true : false; - }; - - this.shouldStopTalking = function (controllerData) { - var gripVal = controllerData.secondaryValues[LEFT_HAND] && controllerData.secondaryValues[RIGHT_HAND]; - return (gripVal) ? false : true; - }; - - this.isReady = function (controllerData, deltaTime) { - if (HMD.active && Audio.pushToTalk && this.shouldTalk(controllerData)) { - Audio.pushingToTalk = true; - return makeRunningValues(true, [], []); - } - - return makeRunningValues(false, [], []); - }; - - this.run = function (controllerData, deltaTime) { - if (this.shouldStopTalking(controllerData) || !Audio.pushToTalk) { - Audio.pushingToTalk = false; - print("Stop pushing to talk."); - return makeRunningValues(false, [], []); - } - - return makeRunningValues(true, [], []); - }; - - this.parameters = makeDispatcherModuleParameters( - 950, - ["head"], - [], - 100); - } - - var pushToTalk = new PushToTalkHandler(); - enableDispatcherModule("PushToTalk", pushToTalk); - - function cleanup() { - disableDispatcherModule("PushToTalk"); - }; - - Script.scriptEnding.connect(cleanup); -}()); // END LOCAL_SCOPE diff --git a/scripts/simplifiedUI/system/controllers/controllerModules/scaleAvatar.js b/scripts/simplifiedUI/system/controllers/controllerModules/scaleAvatar.js deleted file mode 100644 index 1868b0228a..0000000000 --- a/scripts/simplifiedUI/system/controllers/controllerModules/scaleAvatar.js +++ /dev/null @@ -1,88 +0,0 @@ -// scaleAvatar.js -// -// Created by Dante Ruiz on 9/11/17 -// -// Grabs physically moveable entities with hydra-like controllers; it works for either near or far objects. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html - -/* global Script, Vec3, MyAvatar, RIGHT_HAND */ - -(function () { - var dispatcherUtils = Script.require("/~/system/libraries/controllerDispatcherUtils.js"); - - function clamp(val, min, max) { - return Math.max(min, Math.min(max, val)); - } - - function ScaleAvatar(hand) { - this.hand = hand; - this.scalingStartAvatarScale = 0; - this.scalingStartDistance = 0; - - this.parameters = dispatcherUtils.makeDispatcherModuleParameters( - 120, - this.hand === RIGHT_HAND ? ["rightHand"] : ["leftHand"], - [], - 100 - ); - - this.otherHand = function() { - return this.hand === dispatcherUtils.RIGHT_HAND ? dispatcherUtils.LEFT_HAND : dispatcherUtils.RIGHT_HAND; - }; - - this.getOtherModule = function() { - var otherModule = this.hand === dispatcherUtils.RIGHT_HAND ? leftScaleAvatar : rightScaleAvatar; - return otherModule; - }; - - this.triggersPressed = function(controllerData) { - if (controllerData.triggerClicks[this.hand] && - controllerData.secondaryValues[this.hand] > dispatcherUtils.BUMPER_ON_VALUE) { - return true; - } - return false; - }; - - this.isReady = function(controllerData) { - var otherModule = this.getOtherModule(); - if (this.triggersPressed(controllerData) && otherModule.triggersPressed(controllerData)) { - this.scalingStartAvatarScale = MyAvatar.scale; - this.scalingStartDistance = Vec3.length(Vec3.subtract(controllerData.controllerLocations[this.hand].position, - controllerData.controllerLocations[this.otherHand()].position)); - return dispatcherUtils.makeRunningValues(true, [], []); - } - return dispatcherUtils.makeRunningValues(false, [], []); - }; - - this.run = function(controllerData) { - var otherModule = this.getOtherModule(); - if (this.triggersPressed(controllerData) && otherModule.triggersPressed(controllerData)) { - if (this.hand === dispatcherUtils.RIGHT_HAND) { - var scalingCurrentDistance = - Vec3.length(Vec3.subtract(controllerData.controllerLocations[this.hand].position, - controllerData.controllerLocations[this.otherHand()].position)); - - var newAvatarScale = (scalingCurrentDistance / this.scalingStartDistance) * this.scalingStartAvatarScale; - MyAvatar.scale = clamp(newAvatarScale, MyAvatar.getDomainMinScale(), MyAvatar.getDomainMaxScale()); - MyAvatar.scaleChanged(); - } - return dispatcherUtils.makeRunningValues(true, [], []); - } - return dispatcherUtils.makeRunningValues(false, [], []); - }; - } - - var leftScaleAvatar = new ScaleAvatar(dispatcherUtils.LEFT_HAND); - var rightScaleAvatar = new ScaleAvatar(dispatcherUtils.RIGHT_HAND); - - dispatcherUtils.enableDispatcherModule("LeftScaleAvatar", leftScaleAvatar); - dispatcherUtils.enableDispatcherModule("RightScaleAvatar", rightScaleAvatar); - - function cleanup() { - dispatcherUtils.disableDispatcherModule("LeftScaleAvatar"); - dispatcherUtils.disableDispatcherModule("RightScaleAvatar"); - } - Script.scriptEnding.connect(cleanup); -})(); diff --git a/scripts/simplifiedUI/system/controllers/controllerModules/scaleEntity.js b/scripts/simplifiedUI/system/controllers/controllerModules/scaleEntity.js deleted file mode 100644 index 50b6c5b853..0000000000 --- a/scripts/simplifiedUI/system/controllers/controllerModules/scaleEntity.js +++ /dev/null @@ -1,110 +0,0 @@ -// scaleEntity.js -// -// Created by Dante Ruiz on 9/18/17 -// -// Grabs physically moveable entities with hydra-like controllers; it works for either near or far objects. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html - -/* global Script, Vec3, MyAvatar, Entities, RIGHT_HAND, entityIsGrabbable */ - -(function() { - var dispatcherUtils = Script.require("/~/system/libraries/controllerDispatcherUtils.js"); - function ScaleEntity(hand) { - this.hand = hand; - this.grabbedThingID = false; - this.scalingStartDistance = false; - this.scalingStartDimensions = false; - - this.parameters = dispatcherUtils.makeDispatcherModuleParameters( - 120, - this.hand === RIGHT_HAND ? ["rightHandTrigger"] : ["leftHandTrigger"], - [], - 100 - ); - - this.otherHand = function() { - return this.hand === dispatcherUtils.RIGHT_HAND ? dispatcherUtils.LEFT_HAND : dispatcherUtils.RIGHT_HAND; - }; - - this.otherModule = function() { - return this.hand === dispatcherUtils.RIGHT_HAND ? leftScaleEntity : rightScaleEntity; - }; - - this.bumperPressed = function(controllerData) { - return ( controllerData.secondaryValues[this.hand] > dispatcherUtils.BUMPER_ON_VALUE); - }; - - this.getTargetProps = function(controllerData) { - // nearbyEntityProperties is already sorted by length from controller - var nearbyEntityProperties = controllerData.nearbyEntityProperties[this.hand]; - var sensorScaleFactor = MyAvatar.sensorToWorldScale; - for (var i = 0; i < nearbyEntityProperties.length; i++) { - var props = nearbyEntityProperties[i]; - var handPosition = controllerData.controllerLocations[this.hand].position; - var distance = Vec3.distance(props.position, handPosition); - if (distance > dispatcherUtils.NEAR_GRAB_RADIUS * sensorScaleFactor) { - continue; - } - if ((dispatcherUtils.entityIsGrabbable(props) || - dispatcherUtils.propsArePhysical(props)) && !props.locked) { - return props; - } - } - return null; - }; - - this.isReady = function(controllerData) { - var otherModule = this.otherModule(); - if (this.bumperPressed(controllerData) && otherModule.bumperPressed(controllerData)) { - var thisHandTargetProps = this.getTargetProps(controllerData); - var otherHandTargetProps = otherModule.getTargetProps(controllerData); - if (thisHandTargetProps && otherHandTargetProps) { - if (thisHandTargetProps.id === otherHandTargetProps.id) { - if (!entityIsGrabbable(thisHandTargetProps)) { - return dispatcherUtils.makeRunningValues(false, [], []); - } - this.grabbedThingID = thisHandTargetProps.id; - this.scalingStartDistance = - Vec3.length(Vec3.subtract(controllerData.controllerLocations[this.hand].position, - controllerData.controllerLocations[this.otherHand()].position)); - this.scalingStartDimensions = thisHandTargetProps.dimensions; - return dispatcherUtils.makeRunningValues(true, [], []); - } - } - } - this.grabbedThingID = false; - return dispatcherUtils.makeRunningValues(false, [], []); - }; - - this.run = function(controllerData) { - var otherModule = this.otherModule(); - if (this.bumperPressed(controllerData) && otherModule.bumperPressed(controllerData)) { - if (this.hand === dispatcherUtils.RIGHT_HAND) { - var scalingCurrentDistance = - Vec3.length(Vec3.subtract(controllerData.controllerLocations[this.hand].position, - controllerData.controllerLocations[this.otherHand()].position)); - var currentRescale = scalingCurrentDistance / this.scalingStartDistance; - var newDimensions = Vec3.multiply(currentRescale, this.scalingStartDimensions); - Entities.editEntity(this.grabbedThingID, { localDimensions: newDimensions }); - } - return dispatcherUtils.makeRunningValues(true, [], []); - } - this.grabbedThingID = false; - return dispatcherUtils.makeRunningValues(false, [], []); - }; - } - - var leftScaleEntity = new ScaleEntity(dispatcherUtils.LEFT_HAND); - var rightScaleEntity = new ScaleEntity(dispatcherUtils.RIGHT_HAND); - - dispatcherUtils.enableDispatcherModule("LeftScaleEntity", leftScaleEntity); - dispatcherUtils.enableDispatcherModule("RightScaleEntity", rightScaleEntity); - - function cleanup() { - dispatcherUtils.disableDispatcherModule("LeftScaleEntity"); - dispatcherUtils.disableDispatcherModule("RightScaleEntity"); - } - Script.scriptEnding.connect(cleanup); -})(); diff --git a/scripts/simplifiedUI/system/controllers/controllerModules/stylusInput.js b/scripts/simplifiedUI/system/controllers/controllerModules/stylusInput.js deleted file mode 100644 index c4aa9efd50..0000000000 --- a/scripts/simplifiedUI/system/controllers/controllerModules/stylusInput.js +++ /dev/null @@ -1,220 +0,0 @@ -"use strict"; - -// stylusInput.js -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html - -/* global Script, MyAvatar, Controller, Uuid, RIGHT_HAND, LEFT_HAND, enableDispatcherModule, disableDispatcherModule, - makeRunningValues, Vec3, makeDispatcherModuleParameters, Overlays, HMD, Settings, getEnabledModuleByName, Pointers, - Picks, PickType -*/ - -Script.include("/~/system/libraries/controllerDispatcherUtils.js"); -Script.include("/~/system/libraries/controllers.js"); - -(function() { - function isNearStylusTarget(stylusTargets, maxNormalDistance) { - var stylusTargetIDs = []; - for (var index = 0; index < stylusTargets.length; index++) { - var stylusTarget = stylusTargets[index]; - if (stylusTarget.distance <= maxNormalDistance && !(HMD.tabletID && stylusTarget.id === HMD.tabletID)) { - stylusTargetIDs.push(stylusTarget.id); - } - } - return stylusTargetIDs; - } - - function getOverlayDistance(controllerPosition, overlayID) { - var position = Overlays.getProperty(overlayID, "position"); - return { - id: overlayID, - distance: Vec3.distance(position, controllerPosition) - }; - } - - function StylusInput(hand) { - this.hand = hand; - - this.parameters = makeDispatcherModuleParameters( - 100, - this.hand === RIGHT_HAND ? ["rightHand"] : ["leftHand"], - [], - 100); - - this.pointer = Pointers.createPointer(PickType.Stylus, { - hand: this.hand, - filter: Picks.PICK_OVERLAYS, - hover: true, - enabled: true - }); - - this.disable = false; - - this.otherModuleNeedsToRun = function(controllerData) { - var grabOverlayModuleName = this.hand === RIGHT_HAND ? "RightNearParentingGrabOverlay" : "LeftNearParentingGrabOverlay"; - var grabOverlayModule = getEnabledModuleByName(grabOverlayModuleName); - var grabEntityModuleName = this.hand === RIGHT_HAND ? "RightNearParentingGrabEntity" : "LeftNearParentingGrabEntity"; - var grabEntityModule = getEnabledModuleByName(grabEntityModuleName); - var grabOverlayModuleReady = grabOverlayModule ? grabOverlayModule.isReady(controllerData) : makeRunningValues(false, [], []); - var grabEntityModuleReady = grabEntityModule ? grabEntityModule.isReady(controllerData) : makeRunningValues(false, [], []); - var farGrabModuleName = this.hand === RIGHT_HAND ? "RightFarActionGrabEntity" : "LeftFarActionGrabEntity"; - var farGrabModule = getEnabledModuleByName(farGrabModuleName); - var farGrabModuleReady = farGrabModule ? farGrabModule.isReady(controllerData) : makeRunningValues(false, [], []); - var nearTabletHighlightModuleName = - this.hand === RIGHT_HAND ? "RightNearTabletHighlight" : "LeftNearTabletHighlight"; - var nearTabletHighlightModule = getEnabledModuleByName(nearTabletHighlightModuleName); - var nearTabletHighlightModuleReady = nearTabletHighlightModule - ? nearTabletHighlightModule.isReady(controllerData) : makeRunningValues(false, [], []); - return grabOverlayModuleReady.active || farGrabModuleReady.active || grabEntityModuleReady.active - || nearTabletHighlightModuleReady.active; - }; - - this.overlayLaserActive = function(controllerData) { - var rightOverlayLaserModule = getEnabledModuleByName("RightWebSurfaceLaserInput"); - var leftOverlayLaserModule = getEnabledModuleByName("LeftWebSurfaceLaserInput"); - var rightModuleRunning = rightOverlayLaserModule ? rightOverlayLaserModule.isReady(controllerData).active : false; - var leftModuleRunning = leftOverlayLaserModule ? leftOverlayLaserModule.isReady(controllerData).active : false; - return leftModuleRunning || rightModuleRunning; - }; - - this.processStylus = function(controllerData) { - if (this.overlayLaserActive(controllerData) || this.otherModuleNeedsToRun(controllerData)) { - Pointers.setRenderState(this.pointer, "disabled"); - return false; - } - - var sensorScaleFactor = MyAvatar.sensorToWorldScale; - - // build list of stylus targets, near the stylusTip - var stylusTargets = []; - var candidateOverlays = controllerData.nearbyOverlayIDs; - var controllerPosition = controllerData.controllerLocations[this.hand].position; - var i, stylusTarget; - - for (i = 0; i < candidateOverlays.length; i++) { - if (!(HMD.tabletID && candidateOverlays[i] === HMD.tabletID) && - Overlays.getProperty(candidateOverlays[i], "visible")) { - stylusTarget = getOverlayDistance(controllerPosition, candidateOverlays[i]); - if (stylusTarget) { - stylusTargets.push(stylusTarget); - } - } - } - - // add the tabletScreen, if it is valid - if (HMD.tabletScreenID && HMD.tabletScreenID !== Uuid.NULL && - Overlays.getProperty(HMD.tabletScreenID, "visible")) { - stylusTarget = getOverlayDistance(controllerPosition, HMD.tabletScreenID); - if (stylusTarget) { - stylusTargets.push(stylusTarget); - } - } - - // add the tablet home button. - if (HMD.homeButtonID && HMD.homeButtonID !== Uuid.NULL && - Overlays.getProperty(HMD.homeButtonID, "visible")) { - stylusTarget = getOverlayDistance(controllerPosition, HMD.homeButtonID); - if (stylusTarget) { - stylusTargets.push(stylusTarget); - } - } - - // Add the mini tablet. - if (HMD.miniTabletScreenID && Overlays.getProperty(HMD.miniTabletScreenID, "visible")) { - stylusTarget = getOverlayDistance(controllerPosition, HMD.miniTabletScreenID); - if (stylusTarget) { - stylusTargets.push(stylusTarget); - } - } - - const WEB_DISPLAY_STYLUS_DISTANCE = (Keyboard.raised && Keyboard.preferMalletsOverLasers) ? 0.2 : 0.5; - var nearStylusTarget = isNearStylusTarget(stylusTargets, WEB_DISPLAY_STYLUS_DISTANCE * sensorScaleFactor); - - if (nearStylusTarget.length !== 0) { - if (!this.disable) { - Pointers.setRenderState(this.pointer,"events on"); - Pointers.setIncludeItems(this.pointer, nearStylusTarget); - } else { - Pointers.setRenderState(this.pointer,"events off"); - } - return true; - } else { - Pointers.setRenderState(this.pointer, "disabled"); - Pointers.setIncludeItems(this.pointer, []); - return false; - } - }; - - this.isReady = function (controllerData) { - var PREFER_STYLUS_OVER_LASER = "preferStylusOverLaser"; - var isUsingStylus = Settings.getValue(PREFER_STYLUS_OVER_LASER, false); - - if (isUsingStylus && this.processStylus(controllerData)) { - Pointers.enablePointer(this.pointer); - this.hand === RIGHT_HAND ? Keyboard.disableRightMallet() : Keyboard.disableLeftMallet(); - return makeRunningValues(true, [], []); - } else { - Pointers.disablePointer(this.pointer); - if (Keyboard.raised && Keyboard.preferMalletsOverLasers) { - this.hand === RIGHT_HAND ? Keyboard.enableRightMallet() : Keyboard.enableLeftMallet(); - } - return makeRunningValues(false, [], []); - } - }; - - this.run = function (controllerData, deltaTime) { - return this.isReady(controllerData); - }; - - this.cleanup = function () { - Pointers.removePointer(this.pointer); - }; - } - - function mouseHoverEnter(overlayID, event) { - if (event.id === leftTabletStylusInput.pointer && !rightTabletStylusInput.disable && !leftTabletStylusInput.disable) { - rightTabletStylusInput.disable = true; - } else if (event.id === rightTabletStylusInput.pointer && !leftTabletStylusInput.disable && !rightTabletStylusInput.disable) { - leftTabletStylusInput.disable = true; - } - } - - function mouseHoverLeave(overlayID, event) { - if (event.id === leftTabletStylusInput.pointer) { - rightTabletStylusInput.disable = false; - } else if (event.id === rightTabletStylusInput.pointer) { - leftTabletStylusInput.disable = false; - } - } - - var HAPTIC_STYLUS_STRENGTH = 1.0; - var HAPTIC_STYLUS_DURATION = 20.0; - function mousePress(overlayID, event) { - if (HMD.active) { - if (event.id === leftTabletStylusInput.pointer && event.button === "Primary") { - Controller.triggerHapticPulse(HAPTIC_STYLUS_STRENGTH, HAPTIC_STYLUS_DURATION, LEFT_HAND); - } else if (event.id === rightTabletStylusInput.pointer && event.button === "Primary") { - Controller.triggerHapticPulse(HAPTIC_STYLUS_STRENGTH, HAPTIC_STYLUS_DURATION, RIGHT_HAND); - } - } - } - - var leftTabletStylusInput = new StylusInput(LEFT_HAND); - var rightTabletStylusInput = new StylusInput(RIGHT_HAND); - - enableDispatcherModule("LeftTabletStylusInput", leftTabletStylusInput); - enableDispatcherModule("RightTabletStylusInput", rightTabletStylusInput); - - Overlays.hoverEnterOverlay.connect(mouseHoverEnter); - Overlays.hoverLeaveOverlay.connect(mouseHoverLeave); - Overlays.mousePressOnOverlay.connect(mousePress); - - this.cleanup = function () { - leftTabletStylusInput.cleanup(); - rightTabletStylusInput.cleanup(); - disableDispatcherModule("LeftTabletStylusInput"); - disableDispatcherModule("RightTabletStylusInput"); - }; - Script.scriptEnding.connect(this.cleanup); -}()); diff --git a/scripts/simplifiedUI/system/controllers/controllerModules/teleport.js b/scripts/simplifiedUI/system/controllers/controllerModules/teleport.js deleted file mode 100644 index 5a51773930..0000000000 --- a/scripts/simplifiedUI/system/controllers/controllerModules/teleport.js +++ /dev/null @@ -1,1108 +0,0 @@ -"use strict"; - -// Created by james b. pollack @imgntn on 7/2/2016 -// Copyright 2016 High Fidelity, Inc. -// -// Creates a beam and target and then teleports you there. Release when its close to you to cancel. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html - -/* jslint bitwise: true */ - -/* global Script, Entities, MyAvatar, Controller, Quat, RIGHT_HAND, LEFT_HAND, - enableDispatcherModule, disableDispatcherModule, Messages, makeDispatcherModuleParameters, makeRunningValues, Vec3, - HMD, Uuid, AvatarList, Picks, Pointers, PickType -*/ - -Script.include("/~/system/libraries/Xform.js"); -Script.include("/~/system/libraries/controllerDispatcherUtils.js"); -Script.include("/~/system/libraries/controllers.js"); - -(function() { // BEGIN LOCAL_SCOPE - - var TARGET_MODEL_URL = Script.resolvePath("../../assets/models/teleportationSpotBasev8.fbx"); - var SEAT_MODEL_URL = Script.resolvePath("../../assets/models/teleport-seat.fbx"); - - var TARGET_MODEL_DIMENSIONS = { x: 0.6552, y: 0.3063, z: 0.6552 }; - - var COLORS_TELEPORT_SEAT = { - red: 255, - green: 0, - blue: 170 - }; - - var COLORS_TELEPORT_CAN_TELEPORT = { - red: 97, - green: 247, - blue: 255 - }; - - var COLORS_TELEPORT_CANCEL = { - red: 255, - green: 184, - blue: 73 - }; - - var handInfo = { - right: { - controllerInput: Controller.Standard.RightHand - }, - left: { - controllerInput: Controller.Standard.LeftHand - } - }; - - var cancelPath = { - color: COLORS_TELEPORT_CANCEL, - alpha: 0.3, - width: 0.025, - drawInFront: true - }; - - var teleportPath = { - color: COLORS_TELEPORT_CAN_TELEPORT, - alpha: 0.7, - width: 0.025, - drawInFront: true - }; - - var seatPath = { - color: COLORS_TELEPORT_SEAT, - alpha: 0.7, - width: 0.025, - drawInFront: true - }; - - var teleportEnd = { - type: "model", - url: TARGET_MODEL_URL, - dimensions: TARGET_MODEL_DIMENSIONS, - ignorePickIntersection: true - }; - - var seatEnd = { - type: "model", - url: SEAT_MODEL_URL, - dimensions: TARGET_MODEL_DIMENSIONS, - ignorePickIntersection: true - }; - - var collisionEnd = { - type: "shape", - shape: "box", - dimensions: { x: 1.0, y: 0.001, z: 1.0 }, - alpha: 0.0, - ignorePickIntersection: true - }; - - var teleportRenderStates = [{name: "cancel", path: cancelPath}, - {name: "teleport", path: teleportPath, end: teleportEnd}, - {name: "seat", path: seatPath, end: seatEnd}, - {name: "collision", end: collisionEnd}]; - - var DEFAULT_DISTANCE = 8.0; - var teleportDefaultRenderStates = [{name: "cancel", distance: DEFAULT_DISTANCE, path: cancelPath}]; - - var ignoredEntities = []; - - var TELEPORTER_STATES = { - IDLE: 'idle', - TARGETTING: 'targetting', - TARGETTING_INVALID: 'targetting_invalid' - }; - - var TARGET = { - NONE: 'none', // Not currently targetting anything - INVALID: 'invalid', // The current target is invalid (wall, ceiling, etc.) - COLLIDES: 'collides', // Insufficient space to accommodate the avatar capsule - DISCREPANCY: 'discrepancy', // We are not 100% sure the avatar will fit so we trigger safe landing - SURFACE: 'surface', // The current target is a valid surface - SEAT: 'seat' // The current target is a seat - }; - - var speed = 9.3; - var accelerationAxis = {x: 0.0, y: -5.0, z: 0.0}; - - function Teleporter(hand) { - var _this = this; - this.init = false; - this.hand = hand; - this.buttonValue = 0; - this.standardAxisLY = 0.0; - this.standardAxisRY = 0.0; - this.disabled = false; // used by the 'Hifi-Teleport-Disabler' message handler - this.active = false; - this.state = TELEPORTER_STATES.IDLE; - this.currentTarget = TARGET.INVALID; - this.currentResult = null; - this.capsuleThreshold = 0.05; - this.pickHeightOffset = 0.05; - - this.getOtherModule = function() { - var otherModule = this.hand === RIGHT_HAND ? leftTeleporter : rightTeleporter; - return otherModule; - }; - - this.teleportHeadCollisionPick; - this.teleportHandCollisionPick; - this.teleportParabolaHandVisuals; - this.teleportParabolaHandCollisions; - this.teleportParabolaHeadVisuals; - this.teleportParabolaHeadCollisions; - - - this.PLAY_AREA_OVERLAY_MODEL = Script.resolvePath("../../assets/models/trackingSpacev18.fbx"); - this.PLAY_AREA_OVERLAY_MODEL_DIMENSIONS = { x: 1.969, y: 0.001, z: 1.969 }; - this.PLAY_AREA_FLOAT_ABOVE_FLOOR = 0.005; - this.PLAY_AREA_OVERLAY_OFFSET = // Offset from floor. - { x: 0, y: this.PLAY_AREA_OVERLAY_MODEL_DIMENSIONS.y / 2 + this.PLAY_AREA_FLOAT_ABOVE_FLOOR, z: 0 }; - this.PLAY_AREA_SENSOR_OVERLAY_MODEL = Script.resolvePath("../../assets/models/oculusSensorv11.fbx"); - this.PLAY_AREA_SENSOR_OVERLAY_DIMENSIONS = { x: 0.1198, y: 0.2981, z: 0.1198 }; - this.PLAY_AREA_SENSOR_OVERLAY_ROTATION = Quat.fromVec3Degrees({ x: 0, y: -90, z: 0 }); - this.PLAY_AREA_BOX_ALPHA = 1.0; - this.PLAY_AREA_SENSOR_ALPHA = 0.8; - this.playAreaSensorPositions = []; - this.playArea = { x: 0, y: 0 }; - this.playAreaCenterOffset = this.PLAY_AREA_OVERLAY_OFFSET; - this.isPlayAreaVisible = false; - this.wasPlayAreaVisible = false; - this.isPlayAreaAvailable = false; - this.targetOverlayID = null; - this.playAreaOverlay = null; - this.playAreaSensorPositionOverlays = []; - - this.TELEPORT_SCALE_DURATION = 130; - this.TELEPORT_SCALE_TIMEOUT = 25; - this.isTeleportVisible = false; - this.teleportScaleTimer = null; - this.teleportScaleStart = 0; - this.teleportScaleFactor = 0; - this.teleportScaleMode = "head"; - - this.TELEPORTED_FADE_DELAY_DURATION = 900; - this.TELEPORTED_FADE_DURATION = 200; - this.TELEPORTED_FADE_INTERVAL = 25; - this.TELEPORTED_FADE_DELAY_DELTA = this.TELEPORTED_FADE_INTERVAL / this.TELEPORTED_FADE_DELAY_DURATION; - this.TELEPORTED_FADE_DELTA = this.TELEPORTED_FADE_INTERVAL / this.TELEPORTED_FADE_DURATION; - this.teleportedFadeTimer = null; - this.teleportedFadeDelayFactor = 0; - this.teleportedFadeFactor = 0; - this.teleportedPosition = Vec3.ZERO; - this.TELEPORTED_TARGET_ALPHA = 1.0; - this.TELEPORTED_TARGET_ROTATION = Quat.fromVec3Degrees({ x: 0, y: 180, z: 0 }); - this.teleportedTargetOverlay = null; - - this.setPlayAreaDimensions = function () { - var avatarScale = MyAvatar.sensorToWorldScale; - - var playAreaOverlayProperties = { - dimensions: - Vec3.multiply(_this.teleportScaleFactor * avatarScale, { - x: _this.playArea.width, - y: _this.PLAY_AREA_OVERLAY_MODEL_DIMENSIONS.y, - z: _this.playArea.height - }) - }; - - if (_this.teleportScaleFactor < 1) { - // Adjust position of playAreOverlay so that its base is at correct height. - // Always parenting to teleport target is good enough for this. - var sensorToWorldMatrix = MyAvatar.sensorToWorldMatrix; - var sensorToWorldRotation = Mat4.extractRotation(MyAvatar.sensorToWorldMatrix); - var worldToSensorMatrix = Mat4.inverse(sensorToWorldMatrix); - var avatarSensorPosition = Mat4.transformPoint(worldToSensorMatrix, MyAvatar.position); - avatarSensorPosition.y = 0; - - var targetRotation = Overlays.getProperty(_this.targetOverlayID, "rotation"); - var relativePlayAreaCenterOffset = - Vec3.sum(_this.playAreaCenterOffset, { x: 0, y: -TARGET_MODEL_DIMENSIONS.y / 2, z: 0 }); - var localPosition = Vec3.multiplyQbyV(Quat.inverse(targetRotation), - Vec3.multiplyQbyV(sensorToWorldRotation, - Vec3.multiply(avatarScale, Vec3.subtract(relativePlayAreaCenterOffset, avatarSensorPosition)))); - localPosition.y = _this.teleportScaleFactor * localPosition.y; - - playAreaOverlayProperties.parentID = _this.targetOverlayID; - playAreaOverlayProperties.localPosition = localPosition; - } - - Overlays.editOverlay(_this.playAreaOverlay, playAreaOverlayProperties); - - for (var i = 0; i < _this.playAreaSensorPositionOverlays.length; i++) { - localPosition = _this.playAreaSensorPositions[i]; - localPosition = Vec3.multiply(avatarScale, localPosition); - // Position relative to the play area. - localPosition.y = avatarScale * (_this.PLAY_AREA_SENSOR_OVERLAY_DIMENSIONS.y / 2 - - _this.PLAY_AREA_OVERLAY_MODEL_DIMENSIONS.y / 2); - Overlays.editOverlay(_this.playAreaSensorPositionOverlays[i], { - dimensions: Vec3.multiply(_this.teleportScaleFactor * avatarScale, _this.PLAY_AREA_SENSOR_OVERLAY_DIMENSIONS), - parentID: _this.playAreaOverlay, - localPosition: localPosition - }); - } - }; - - this.updatePlayAreaScale = function () { - if (_this.isPlayAreaAvailable) { - _this.setPlayAreaDimensions(); - } - }; - - - this.teleporterSelectionName = "teleporterSelection" + hand.toString(); - this.TELEPORTER_SELECTION_STYLE = { - outlineUnoccludedColor: { red: 0, green: 0, blue: 0 }, - outlineUnoccludedAlpha: 0, - outlineOccludedColor: { red: 0, green: 0, blue: 0 }, - outlineOccludedAlpha: 0, - fillUnoccludedColor: { red: 0, green: 0, blue: 0 }, - fillUnoccludedAlpha: 0, - fillOccludedColor: { red: 0, green: 0, blue: 255 }, - fillOccludedAlpha: 0.84, - outlineWidth: 0, - isOutlineSmooth: false - }; - - this.addToSelectedItemsList = function (properties) { - for (var i = 0, length = teleportRenderStates.length; i < length; i++) { - var state = properties.renderStates[teleportRenderStates[i].name]; - if (state && state.end) { - Selection.addToSelectedItemsList(_this.teleporterSelectionName, "overlay", state.end); - } - } - }; - - - this.cleanup = function() { - Selection.removeListFromMap(_this.teleporterSelectionName); - Pointers.removePointer(_this.teleportParabolaHandVisuals); - Pointers.removePointer(_this.teleportParabolaHandCollisions); - Pointers.removePointer(_this.teleportParabolaHeadVisuals); - Pointers.removePointer(_this.teleportParabolaHeadCollisions); - Picks.removePick(_this.teleportHandCollisionPick); - Picks.removePick(_this.teleportHeadCollisionPick); - Overlays.deleteOverlay(_this.teleportedTargetOverlay); - Overlays.deleteOverlay(_this.playAreaOverlay); - for (var i = 0; i < _this.playAreaSensorPositionOverlays.length; i++) { - Overlays.deleteOverlay(_this.playAreaSensorPositionOverlays[i]); - } - _this.playAreaSensorPositionOverlays = []; - }; - - this.initPointers = function() { - if (_this.init) { - _this.cleanup(); - } - - _this.teleportParabolaHandVisuals = Pointers.createPointer(PickType.Parabola, { - joint: (_this.hand === RIGHT_HAND) ? "_CAMERA_RELATIVE_CONTROLLER_RIGHTHAND" : "_CAMERA_RELATIVE_CONTROLLER_LEFTHAND", - dirOffset: { x: 0, y: 1, z: 0.1 }, - posOffset: { x: (_this.hand === RIGHT_HAND) ? 0.03 : -0.03, y: 0.2, z: 0.02 }, - filter: Picks.PICK_ENTITIES | Picks.PICK_INCLUDE_INVISIBLE, - faceAvatar: true, - scaleWithParent: true, - centerEndY: false, - speed: speed, - accelerationAxis: accelerationAxis, - rotateAccelerationWithAvatar: true, - renderStates: teleportRenderStates, - defaultRenderStates: teleportDefaultRenderStates, - maxDistance: 8.0 - }); - - _this.teleportParabolaHandCollisions = Pointers.createPointer(PickType.Parabola, { - joint: (_this.hand === RIGHT_HAND) ? "_CAMERA_RELATIVE_CONTROLLER_RIGHTHAND" : "_CAMERA_RELATIVE_CONTROLLER_LEFTHAND", - dirOffset: { x: 0, y: 1, z: 0.1 }, - posOffset: { x: (_this.hand === RIGHT_HAND) ? 0.03 : -0.03, y: 0.2, z: 0.02 }, - filter: Picks.PICK_ENTITIES | Picks.PICK_INCLUDE_INVISIBLE, - faceAvatar: true, - scaleWithParent: true, - centerEndY: false, - speed: speed, - accelerationAxis: accelerationAxis, - rotateAccelerationWithAvatar: true, - renderStates: teleportRenderStates, - maxDistance: 8.0 - }); - - _this.teleportParabolaHeadVisuals = Pointers.createPointer(PickType.Parabola, { - joint: "Avatar", - filter: Picks.PICK_ENTITIES | Picks.PICK_INCLUDE_INVISIBLE, - faceAvatar: true, - scaleWithParent: true, - centerEndY: false, - speed: speed, - accelerationAxis: accelerationAxis, - rotateAccelerationWithAvatar: true, - renderStates: teleportRenderStates, - defaultRenderStates: teleportDefaultRenderStates, - maxDistance: 8.0 - }); - - _this.teleportParabolaHeadCollisions = Pointers.createPointer(PickType.Parabola, { - joint: "Avatar", - filter: Picks.PICK_ENTITIES | Picks.PICK_INCLUDE_INVISIBLE, - faceAvatar: true, - scaleWithParent: true, - centerEndY: false, - speed: speed, - accelerationAxis: accelerationAxis, - rotateAccelerationWithAvatar: true, - renderStates: teleportRenderStates, - maxDistance: 8.0 - }); - - _this.addToSelectedItemsList(Pointers.getPointerProperties(_this.teleportParabolaHandVisuals)); - _this.addToSelectedItemsList(Pointers.getPointerProperties(_this.teleportParabolaHeadVisuals)); - - - var capsuleData = MyAvatar.getCollisionCapsule(); - - var sensorToWorldScale = MyAvatar.getSensorToWorldScale(); - - var diameter = 2.0 * capsuleData.radius / sensorToWorldScale; - var height = (Vec3.distance(capsuleData.start, capsuleData.end) + diameter) / sensorToWorldScale; - var capsuleRatio = 5.0 * diameter / height; - var offset = _this.pickHeightOffset * capsuleRatio; - - _this.teleportHandCollisionPick = Picks.createPick(PickType.Collision, { - enabled: true, - parentID: Pointers.getPointerProperties(_this.teleportParabolaHandCollisions).renderStates["collision"].end, - filter: Picks.PICK_ENTITIES | Picks.PICK_AVATARS, - shape: { - shapeType: "capsule-y", - dimensions: { - x: diameter, - y: height, - z: diameter - } - }, - position: { x: 0, y: offset + height * 0.5, z: 0 }, - threshold: _this.capsuleThreshold - }); - - _this.teleportHeadCollisionPick = Picks.createPick(PickType.Collision, { - enabled: true, - parentID: Pointers.getPointerProperties(_this.teleportParabolaHeadCollisions).renderStates["collision"].end, - filter: Picks.PICK_ENTITIES | Picks.PICK_AVATARS, - shape: { - shapeType: "capsule-y", - dimensions: { - x: diameter, - y: height, - z: diameter - } - }, - position: { x: 0, y: offset + height * 0.5, z: 0 }, - threshold: _this.capsuleThreshold - }); - - - _this.playAreaOverlay = Overlays.addOverlay("model", { - url: _this.PLAY_AREA_OVERLAY_MODEL, - drawInFront: false, - visible: false - }); - - _this.teleportedTargetOverlay = Overlays.addOverlay("model", { - url: TARGET_MODEL_URL, - alpha: _this.TELEPORTED_TARGET_ALPHA, - visible: false - }); - - Selection.addToSelectedItemsList(_this.teleporterSelectionName, "overlay", _this.playAreaOverlay); - Selection.addToSelectedItemsList(_this.teleporterSelectionName, "overlay", _this.teleportedTargetOverlay); - - - _this.playArea = HMD.playArea; - _this.isPlayAreaAvailable = HMD.active && _this.playArea.width !== 0 && _this.playArea.height !== 0; - if (_this.isPlayAreaAvailable) { - _this.playAreaCenterOffset = Vec3.sum({ x: _this.playArea.x, y: 0, z: _this.playArea.y }, - _this.PLAY_AREA_OVERLAY_OFFSET); - _this.playAreaSensorPositions = HMD.sensorPositions; - - for (var i = 0; i < _this.playAreaSensorPositions.length; i++) { - if (i > _this.playAreaSensorPositionOverlays.length - 1) { - var overlay = Overlays.addOverlay("model", { - url: _this.PLAY_AREA_SENSOR_OVERLAY_MODEL, - dimensions: _this.PLAY_AREA_SENSOR_OVERLAY_DIMENSIONS, - parentID: _this.playAreaOverlay, - localRotation: _this.PLAY_AREA_SENSOR_OVERLAY_ROTATION, - drawInFront: false, - visible: false - }); - _this.playAreaSensorPositionOverlays.push(overlay); - Selection.addToSelectedItemsList(_this.teleporterSelectionName, "overlay", overlay); - } - } - - _this.setPlayAreaDimensions(); - } - - _this.init = true; - }; - - _this.initPointers(); - - - this.translateXAction = Controller.findAction("TranslateX"); - this.translateYAction = Controller.findAction("TranslateY"); - this.translateZAction = Controller.findAction("TranslateZ"); - - this.setPlayAreaVisible = function (visible, targetOverlayID, fade) { - if (!_this.isPlayAreaAvailable || _this.isPlayAreaVisible === visible) { - return; - } - - _this.wasPlayAreaVisible = _this.isPlayAreaVisible; - _this.isPlayAreaVisible = visible; - _this.targetOverlayID = targetOverlayID; - - if (_this.teleportedFadeTimer !== null) { - Script.clearTimeout(_this.teleportedFadeTimer); - _this.teleportedFadeTimer = null; - } - if (visible || !fade) { - // Immediately make visible or invisible. - _this.isPlayAreaVisible = visible; - Overlays.editOverlay(_this.playAreaOverlay, { - dimensions: Vec3.ZERO, - alpha: _this.PLAY_AREA_BOX_ALPHA, - visible: visible - }); - for (var i = 0; i < _this.playAreaSensorPositionOverlays.length; i++) { - Overlays.editOverlay(_this.playAreaSensorPositionOverlays[i], { - dimensions: Vec3.ZERO, - alpha: _this.PLAY_AREA_SENSOR_ALPHA, - visible: visible - }); - } - Overlays.editOverlay(_this.teleportedTargetOverlay, { visible: false }); - } else { - // Fading out of overlays is initiated in setTeleportVisible(). - } - }; - - this.updatePlayArea = function (position) { - var sensorToWorldMatrix = MyAvatar.sensorToWorldMatrix; - var sensorToWorldRotation = Mat4.extractRotation(MyAvatar.sensorToWorldMatrix); - var worldToSensorMatrix = Mat4.inverse(sensorToWorldMatrix); - var avatarSensorPosition = Mat4.transformPoint(worldToSensorMatrix, MyAvatar.position); - avatarSensorPosition.y = 0; - - var targetXZPosition = { x: position.x, y: 0, z: position.z }; - var avatarXZPosition = MyAvatar.position; - avatarXZPosition.y = 0; - var MIN_PARENTING_DISTANCE = 0.2; // Parenting under this distance results in the play area's rotation jittering. - if (Vec3.distance(targetXZPosition, avatarXZPosition) < MIN_PARENTING_DISTANCE) { - // Set play area position and rotation in world coordinates with no parenting. - Overlays.editOverlay(_this.playAreaOverlay, { - parentID: Uuid.NULL, - position: Vec3.sum(position, - Vec3.multiplyQbyV(sensorToWorldRotation, - Vec3.multiply(MyAvatar.sensorToWorldScale, - Vec3.subtract(_this.playAreaCenterOffset, avatarSensorPosition)))), - rotation: sensorToWorldRotation - }); - } else { - // Set play area position and rotation in local coordinates with parenting. - var targetRotation = Overlays.getProperty(_this.targetOverlayID, "rotation"); - var sensorToTargetRotation = Quat.multiply(Quat.inverse(targetRotation), sensorToWorldRotation); - var relativePlayAreaCenterOffset = - Vec3.sum(_this.playAreaCenterOffset, { x: 0, y: -TARGET_MODEL_DIMENSIONS.y / 2, z: 0 }); - Overlays.editOverlay(_this.playAreaOverlay, { - parentID: _this.targetOverlayID, - localPosition: Vec3.multiplyQbyV(Quat.inverse(targetRotation), - Vec3.multiplyQbyV(sensorToWorldRotation, - Vec3.multiply(MyAvatar.sensorToWorldScale, - Vec3.subtract(relativePlayAreaCenterOffset, avatarSensorPosition)))), - localRotation: sensorToTargetRotation - }); - } - }; - - - this.scaleInTeleport = function () { - _this.teleportScaleFactor = Math.min((Date.now() - _this.teleportScaleStart) / _this.TELEPORT_SCALE_DURATION, 1); - Pointers.editRenderState( - _this.teleportScaleMode === "head" ? _this.teleportParabolaHeadVisuals : _this.teleportParabolaHandVisuals, - "teleport", - { - path: teleportPath, // Teleport beam disappears if not included. - end: { dimensions: Vec3.multiply(_this.teleportScaleFactor, TARGET_MODEL_DIMENSIONS) } - } - ); - if (_this.isPlayAreaVisible) { - _this.setPlayAreaDimensions(); - } - if (_this.teleportScaleFactor < 1) { - _this.teleportScaleTimer = Script.setTimeout(_this.scaleInTeleport, _this.TELEPORT_SCALE_TIMEOUT); - } else { - _this.teleportScaleTimer = null; - } - }; - - this.fadeOutTeleport = function () { - var isAvatarMoving, - i, length; - - isAvatarMoving = Controller.getActionValue(_this.translateXAction) !== 0 - || Controller.getActionValue(_this.translateYAction) !== 0 - || Controller.getActionValue(_this.translateZAction) !== 0; - - if (_this.teleportedFadeDelayFactor > 0 && !_this.isTeleportVisible && !isAvatarMoving) { - // Delay fade. - _this.teleportedFadeDelayFactor = _this.teleportedFadeDelayFactor - _this.TELEPORTED_FADE_DELAY_DELTA; - _this.teleportedFadeTimer = Script.setTimeout(_this.fadeOutTeleport, _this.TELEPORTED_FADE_INTERVAL); - } else if (_this.teleportedFadeFactor > 0 && !_this.isTeleportVisible && !isAvatarMoving) { - // Fade. - _this.teleportedFadeFactor = _this.teleportedFadeFactor - _this.TELEPORTED_FADE_DELTA; - Overlays.editOverlay(_this.teleportedTargetOverlay, { - alpha: _this.teleportedFadeFactor * _this.TELEPORTED_TARGET_ALPHA - }); - if (_this.wasPlayAreaVisible) { - Overlays.editOverlay(_this.playAreaOverlay, { - alpha: _this.teleportedFadeFactor * _this.PLAY_AREA_BOX_ALPHA - }); - var sensorAlpha = _this.teleportedFadeFactor * _this.PLAY_AREA_SENSOR_ALPHA; - for (i = 0, length = _this.playAreaSensorPositionOverlays.length; i < length; i++) { - Overlays.editOverlay(_this.playAreaSensorPositionOverlays[i], { alpha: sensorAlpha }); - } - } - _this.teleportedFadeTimer = Script.setTimeout(_this.fadeOutTeleport, _this.TELEPORTED_FADE_INTERVAL); - } else { - // Make invisible. - Overlays.editOverlay(_this.teleportedTargetOverlay, { visible: false }); - if (_this.wasPlayAreaVisible) { - Overlays.editOverlay(_this.playAreaOverlay, { visible: false }); - for (i = 0, length = _this.playAreaSensorPositionOverlays.length; i < length; i++) { - Overlays.editOverlay(_this.playAreaSensorPositionOverlays[i], { visible: false }); - } - } - _this.teleportedFadeTimer = null; - Selection.disableListHighlight(_this.teleporterSelectionName); - } - }; - - this.cancelFade = function () { - // Other hand may call this to immediately hide fading overlays. - var i, length; - if (_this.teleportedFadeTimer) { - Overlays.editOverlay(_this.teleportedTargetOverlay, { visible: false }); - if (_this.wasPlayAreaVisible) { - Overlays.editOverlay(_this.playAreaOverlay, { visible: false }); - for (i = 0, length = _this.playAreaSensorPositionOverlays.length; i < length; i++) { - Overlays.editOverlay(_this.playAreaSensorPositionOverlays[i], { visible: false }); - } - } - _this.teleportedFadeTimer = null; - } - }; - - this.setTeleportVisible = function (visible, mode, fade) { - // Scales in teleport target and play area when start displaying them. - if (visible === _this.isTeleportVisible) { - return; - } - - if (visible) { - _this.teleportScaleMode = mode; - Pointers.editRenderState( - mode === "head" ? _this.teleportParabolaHeadVisuals : _this.teleportParabolaHandVisuals, - "teleport", - { - path: teleportPath, // Teleport beam disappears if not included. - end: { dimensions: Vec3.ZERO } - } - ); - _this.getOtherModule().cancelFade(); - _this.teleportScaleStart = Date.now(); - _this.teleportScaleFactor = 0; - _this.scaleInTeleport(); - Selection.enableListHighlight(_this.teleporterSelectionName, _this.TELEPORTER_SELECTION_STYLE); - } else { - if (_this.teleportScaleTimer !== null) { - Script.clearTimeout(_this.teleportScaleTimer); - _this.teleportScaleTimer = null; - } - - if (fade) { - // Copy of target at teleported position for fading. - var avatarScale = MyAvatar.sensorToWorldScale; - Overlays.editOverlay(_this.teleportedTargetOverlay, { - position: Vec3.sum(_this.teleportedPosition, { - x: 0, - y: -getAvatarFootOffset() + avatarScale * TARGET_MODEL_DIMENSIONS.y / 2, - z: 0 - }), - rotation: Quat.multiply(_this.TELEPORTED_TARGET_ROTATION, MyAvatar.orientation), - dimensions: Vec3.multiply(avatarScale, TARGET_MODEL_DIMENSIONS), - alpha: _this.TELEPORTED_TARGET_ALPHA, - visible: true - }); - - // Fade out over time. - _this.teleportedFadeDelayFactor = 1.0; - _this.teleportedFadeFactor = 1.0; - _this.teleportedFadeTimer = Script.setTimeout(_this.fadeOutTeleport, _this.TELEPORTED_FADE_DELAY); - } else { - Selection.disableListHighlight(_this.teleporterSelectionName); - } - } - - _this.isTeleportVisible = visible; - }; - - - this.axisButtonStateX = 0; // Left/right axis button pressed. - this.axisButtonStateY = 0; // Up/down axis button pressed. - this.BUTTON_TRANSITION_DELAY = 100; // Allow time for transition from direction buttons to touch-pad. - - this.axisButtonChangeX = function (value) { - if (value !== 0) { - _this.axisButtonStateX = value; - } else { - // Delay direction button release until after teleport possibly pressed. - Script.setTimeout(function () { - _this.axisButtonStateX = value; - }, _this.BUTTON_TRANSITION_DELAY); - } - }; - - this.axisButtonChangeY = function (value) { - if (value !== 0) { - _this.axisButtonStateY = value; - } else { - // Delay direction button release until after teleport possibly pressed. - Script.setTimeout(function () { - _this.axisButtonStateY = value; - }, _this.BUTTON_TRANSITION_DELAY); - } - }; - - this.teleportLocked = function () { - // Lock teleport if in advanced movement mode and have just transitioned from pressing a direction button. - return Controller.getValue(Controller.Hardware.Application.AdvancedMovement) && - (_this.axisButtonStateX !== 0 || _this.axisButtonStateY !== 0); - }; - - this.buttonPress = function (value) { - if (value === 0 || !_this.teleportLocked()) { - _this.buttonValue = value; - } - }; - - this.getStandardLY = function (value) { - _this.standardAxisLY = value; - }; - - this.getStandardRY = function (value) { - _this.standardAxisRY = value; - }; - - // Return value for the getDominantY and getOffhandY functions has to be inverted. - this.getDominantY = function () { - return (MyAvatar.getDominantHand() === "left") ? -(_this.standardAxisLY) : -(_this.standardAxisRY); - }; - - this.getOffhandY = function () { - return (MyAvatar.getDominantHand() === "left") ? -(_this.standardAxisRY) : -(_this.standardAxisLY); - }; - - this.getDominantHand = function () { - return (MyAvatar.getDominantHand() === "left") ? LEFT_HAND : RIGHT_HAND; - } - - this.getOffHand = function () { - return (MyAvatar.getDominantHand() === "left") ? RIGHT_HAND : LEFT_HAND; - } - - this.showReticle = function () { - return (_this.getDominantY() > TELEPORT_DEADZONE) ? true : false; - }; - - this.shouldTeleport = function () { - return (_this.getDominantY() > TELEPORT_DEADZONE && _this.getOffhandY() > TELEPORT_DEADZONE) ? true : false; - }; - - this.shouldCancel = function () { - //return (_this.getDominantY() < -TELEPORT_DEADZONE || _this.getOffhandY() < -TELEPORT_DEADZONE) ? true : false; - return (_this.getDominantY() <= TELEPORT_DEADZONE) ? true : false; - }; - - this.parameters = makeDispatcherModuleParameters( - 80, - this.hand === RIGHT_HAND ? ["rightHand"] : ["leftHand"], - [], - 100); - - this.enterTeleport = function() { - _this.state = TELEPORTER_STATES.TARGETTING; - }; - - this.isReady = function(controllerData, deltaTime) { - if ((Window.interstitialModeEnabled && !Window.isPhysicsEnabled()) || !MyAvatar.allowTeleporting) { - return makeRunningValues(false, [], []); - } - - var otherModule = this.getOtherModule(); - if (!this.disabled && this.showReticle() && !otherModule.active && this.hand === this.getDominantHand()) { - this.active = true; - this.enterTeleport(); - return makeRunningValues(true, [], []); - } - return makeRunningValues(false, [], []); - }; - - this.run = function(controllerData, deltaTime) { - // Kill condition: - if (_this.shouldCancel()) { - _this.disableLasers(); - this.active = false; - return makeRunningValues(false, [], []); - } - - // Get current hand pose information to see if the pose is valid - var pose = Controller.getPoseValue(handInfo[(_this.hand === RIGHT_HAND) ? 'right' : 'left'].controllerInput); - var mode = pose.valid ? _this.hand : 'head'; - if (!pose.valid) { - Pointers.disablePointer(_this.teleportParabolaHandVisuals); - Pointers.disablePointer(_this.teleportParabolaHandCollisions); - Picks.disablePick(_this.teleportHandCollisionPick); - Pointers.enablePointer(_this.teleportParabolaHeadVisuals); - Pointers.enablePointer(_this.teleportParabolaHeadCollisions); - Picks.enablePick(_this.teleportHeadCollisionPick); - } else { - Pointers.enablePointer(_this.teleportParabolaHandVisuals); - Pointers.enablePointer(_this.teleportParabolaHandCollisions); - Picks.enablePick(_this.teleportHandCollisionPick); - Pointers.disablePointer(_this.teleportParabolaHeadVisuals); - Pointers.disablePointer(_this.teleportParabolaHeadCollisions); - Picks.disablePick(_this.teleportHeadCollisionPick); - } - - // We do up to 2 picks to find a teleport location. - // There are 2 types of teleport locations we are interested in: - // - // 1. A visible floor. This can be any entity surface that points within some degree of "up" - // and where the avatar capsule can be positioned without colliding - // - // 2. A seat. The seat can be visible or invisible. - // - // The Collision Pick is currently parented to the end overlay on teleportParabolaXXXXCollisions - // - // TODO - // Parent the collision Pick directly to the teleportParabolaXXXXVisuals and get rid of teleportParabolaXXXXCollisions - // - var result, collisionResult; - if (mode === 'head') { - result = Pointers.getPrevPickResult(_this.teleportParabolaHeadCollisions); - collisionResult = Picks.getPrevPickResult(_this.teleportHeadCollisionPick); - } else { - result = Pointers.getPrevPickResult(_this.teleportParabolaHandCollisions); - collisionResult = Picks.getPrevPickResult(_this.teleportHandCollisionPick); - } - - var teleportLocationType = getTeleportTargetType(result, collisionResult); - - if (teleportLocationType === TARGET.NONE) { - // Use the cancel default state - _this.setTeleportState(mode, "cancel", ""); - } else if (teleportLocationType === TARGET.INVALID) { - _this.setTeleportState(mode, "", "cancel"); - } else if (teleportLocationType === TARGET.COLLIDES) { - _this.setTeleportState(mode, "cancel", "collision"); - } else if (teleportLocationType === TARGET.SURFACE || teleportLocationType === TARGET.DISCREPANCY) { - _this.setTeleportState(mode, "teleport", "collision"); - _this.updatePlayArea(result.intersection); - } else if (teleportLocationType === TARGET.SEAT) { - _this.setTeleportState(mode, "collision", "seat"); - } - return _this.teleport(result, teleportLocationType); - }; - - this.teleport = function(newResult, target) { - var result = newResult; - _this.teleportedPosition = newResult.intersection; - if (!_this.shouldTeleport()) { - return makeRunningValues(true, [], []); - } - - if (target === TARGET.NONE || target === TARGET.INVALID) { - // Do nothing - } else if (target === TARGET.SEAT) { - Entities.callEntityMethod(result.objectID, 'sit'); - } else if (target === TARGET.SURFACE || target === TARGET.DISCREPANCY) { - var offset = getAvatarFootOffset(); - result.intersection.y += offset; - var shouldLandSafe = target === TARGET.DISCREPANCY; - MyAvatar.goToLocation(result.intersection, true, HMD.orientation, false, shouldLandSafe); - HMD.centerUI(); - MyAvatar.centerBody(); - } - - _this.disableLasers(); - _this.active = false; - return makeRunningValues(false, [], []); - }; - - this.disableLasers = function() { - _this.setPlayAreaVisible(false, null, false); - _this.setTeleportVisible(false, null, false); - Pointers.disablePointer(_this.teleportParabolaHandVisuals); - Pointers.disablePointer(_this.teleportParabolaHandCollisions); - Pointers.disablePointer(_this.teleportParabolaHeadVisuals); - Pointers.disablePointer(_this.teleportParabolaHeadCollisions); - Picks.disablePick(_this.teleportHeadCollisionPick); - Picks.disablePick(_this.teleportHandCollisionPick); - }; - - this.teleportState = ""; - - this.setTeleportState = function (mode, visibleState, invisibleState) { - var teleportState = mode + visibleState + invisibleState; - if (teleportState === _this.teleportState) { - return; - } - _this.teleportState = teleportState; - - var pointerID; - if (mode === 'head') { - Pointers.setRenderState(_this.teleportParabolaHeadVisuals, visibleState); - Pointers.setRenderState(_this.teleportParabolaHeadCollisions, invisibleState); - pointerID = _this.teleportParabolaHeadVisuals; - } else { - Pointers.setRenderState(_this.teleportParabolaHandVisuals, visibleState); - Pointers.setRenderState(_this.teleportParabolaHandCollisions, invisibleState); - pointerID = _this.teleportParabolaHandVisuals; - } - var visible = visibleState === "teleport"; - _this.setPlayAreaVisible(visible && MyAvatar.showPlayArea, - Pointers.getPointerProperties(pointerID).renderStates.teleport.end, false); - _this.setTeleportVisible(visible, mode, false); - }; - - this.setIgnoreEntities = function(entitiesToIgnore) { - Pointers.setIgnoreItems(_this.teleportParabolaHandVisuals, entitiesToIgnore); - Pointers.setIgnoreItems(_this.teleportParabolaHandCollisions, entitiesToIgnore); - Pointers.setIgnoreItems(_this.teleportParabolaHeadVisuals, entitiesToIgnore); - Pointers.setIgnoreItems(_this.teleportParabolaHeadCollisions, entitiesToIgnore); - Picks.setIgnoreItems(_this.teleportHeadCollisionPick, entitiesToIgnore); - Picks.setIgnoreItems(_this.teleportHandCollisionPick, entitiesToIgnore); - }; - } - - // related to repositioning the avatar after you teleport - var FOOT_JOINT_NAMES = ["RightToe_End", "RightToeBase", "RightFoot"]; - var DEFAULT_ROOT_TO_FOOT_OFFSET = 0.5; - - function getAvatarFootOffset() { - - // find a valid foot jointIndex - var footJointIndex = -1; - var i, l = FOOT_JOINT_NAMES.length; - for (i = 0; i < l; i++) { - footJointIndex = MyAvatar.getJointIndex(FOOT_JOINT_NAMES[i]); - if (footJointIndex !== -1) { - break; - } - } - if (footJointIndex !== -1) { - // default vertical offset from foot to avatar root. - var footPos = MyAvatar.getAbsoluteDefaultJointTranslationInObjectFrame(footJointIndex); - if (footPos.x === 0 && footPos.y === 0 && footPos.z === 0.0) { - // if footPos is exactly zero, it's probably wrong because avatar is currently loading, fall back to default. - return DEFAULT_ROOT_TO_FOOT_OFFSET * MyAvatar.scale; - } else { - return -footPos.y; - } - } else { - return DEFAULT_ROOT_TO_FOOT_OFFSET * MyAvatar.scale; - } - } - - var mappingName, teleportMapping; - var isViveMapped = false; - - function parseJSON(json) { - try { - return JSON.parse(json); - } catch (e) { - return undefined; - } - } - // When determininig whether you can teleport to a location, the normal of the - // point that is being intersected with is looked at. If this normal is more - // than MAX_ANGLE_FROM_UP_TO_TELEPORT degrees from your avatar's up, then - // you can't teleport there. - var MAX_ANGLE_FROM_UP_TO_TELEPORT = 70; - var MAX_DISCREPANCY_DISTANCE = 1.0; - var MAX_DOT_SIGN = -0.6; - - function checkForMeshDiscrepancy(result, collisionResult) { - var intersectingObjects = collisionResult.intersectingObjects; - if (intersectingObjects.length > 0 && intersectingObjects.length < 3) { - for (var j = 0; j < collisionResult.intersectingObjects.length; j++) { - var intersectingObject = collisionResult.intersectingObjects[j]; - for (var i = 0; i < intersectingObject.collisionContacts.length; i++) { - var normal = intersectingObject.collisionContacts[i].normalOnPick; - var distanceToPick = Vec3.distance(intersectingObject.collisionContacts[i].pointOnPick, result.intersection); - var normalSign = Vec3.dot(normal, Quat.getUp(MyAvatar.orientation)); - if ((distanceToPick > MAX_DISCREPANCY_DISTANCE) || (normalSign > MAX_DOT_SIGN)) { - return false; - } - } - } - return true; - } - return false; - } - - function getTeleportTargetType(result, collisionResult) { - if (result.type === Picks.INTERSECTED_NONE) { - return TARGET.NONE; - } - - var props = Entities.getEntityProperties(result.objectID, ['userData', 'visible']); - var data = parseJSON(props.userData); - if (data !== undefined && data.seat !== undefined) { - var avatarUuid = Uuid.fromString(data.seat.user); - if (Uuid.isNull(avatarUuid) || !AvatarList.getAvatar(avatarUuid).sessionUUID) { - return TARGET.SEAT; - } else { - return TARGET.INVALID; - } - } - var isDiscrepancy = false; - if (collisionResult.collisionRegion != undefined) { - if (collisionResult.intersects) { - isDiscrepancy = checkForMeshDiscrepancy(result, collisionResult); - if (!isDiscrepancy) { - return TARGET.COLLIDES; - } - } - } - - var surfaceNormal = result.surfaceNormal; - var angle = Math.acos(Vec3.dot(surfaceNormal, Quat.getUp(MyAvatar.orientation))) * (180.0 / Math.PI); - - if (angle > MAX_ANGLE_FROM_UP_TO_TELEPORT) { - return TARGET.INVALID; - } else if (isDiscrepancy) { - return TARGET.DISCREPANCY; - } else { - return TARGET.SURFACE; - } - } - - function registerViveTeleportMapping() { - // Disable Vive teleport if touch is transitioning across touch-pad after pressing a direction button. - if (Controller.Hardware.Vive) { - var mappingName = 'Hifi-Teleporter-Dev-Vive-' + Math.random(); - var viveTeleportMapping = Controller.newMapping(mappingName); - viveTeleportMapping.from(Controller.Hardware.Vive.LSX).peek().to(leftTeleporter.axisButtonChangeX); - viveTeleportMapping.from(Controller.Hardware.Vive.LSY).peek().to(leftTeleporter.axisButtonChangeY); - viveTeleportMapping.from(Controller.Hardware.Vive.RSX).peek().to(rightTeleporter.axisButtonChangeX); - viveTeleportMapping.from(Controller.Hardware.Vive.RSY).peek().to(rightTeleporter.axisButtonChangeY); - Controller.enableMapping(mappingName); - isViveMapped = true; - } - } - - function onHardwareChanged() { - // Controller.Hardware.Vive is not immediately available at Interface start-up. - if (!isViveMapped && Controller.Hardware.Vive) { - registerViveTeleportMapping(); - } - } - - Controller.hardwareChanged.connect(onHardwareChanged); - - function registerMappings() { - mappingName = 'Hifi-Teleporter-Dev-' + Math.random(); - teleportMapping = Controller.newMapping(mappingName); - - // Vive teleport button lock-out. - registerViveTeleportMapping(); - - // Teleport actions. - teleportMapping.from(Controller.Standard.LeftPrimaryThumb).peek().to(leftTeleporter.buttonPress); - teleportMapping.from(Controller.Standard.RightPrimaryThumb).peek().to(rightTeleporter.buttonPress); - teleportMapping.from(Controller.Standard.LY).peek().to(leftTeleporter.getStandardLY); - teleportMapping.from(Controller.Standard.RY).peek().to(leftTeleporter.getStandardRY); - teleportMapping.from(Controller.Standard.LY).peek().to(rightTeleporter.getStandardLY); - teleportMapping.from(Controller.Standard.RY).peek().to(rightTeleporter.getStandardRY); - } - - var leftTeleporter = new Teleporter(LEFT_HAND); - var rightTeleporter = new Teleporter(RIGHT_HAND); - - enableDispatcherModule("LeftTeleporter", leftTeleporter); - enableDispatcherModule("RightTeleporter", rightTeleporter); - registerMappings(); - Controller.enableMapping(mappingName); - - function cleanup() { - Controller.hardwareChanged.disconnect(onHardwareChanged); - teleportMapping.disable(); - leftTeleporter.cleanup(); - rightTeleporter.cleanup(); - disableDispatcherModule("LeftTeleporter"); - disableDispatcherModule("RightTeleporter"); - } - Script.scriptEnding.connect(cleanup); - - var handleTeleportMessages = function(channel, message, sender) { - if (sender === MyAvatar.sessionUUID) { - if (channel === 'Hifi-Teleport-Disabler') { - if (message === 'both') { - leftTeleporter.disabled = true; - rightTeleporter.disabled = true; - } - if (message === 'left') { - leftTeleporter.disabled = true; - rightTeleporter.disabled = false; - } - if (message === 'right') { - leftTeleporter.disabled = false; - rightTeleporter.disabled = true; - } - if (message === 'none') { - leftTeleporter.disabled = false; - rightTeleporter.disabled = false; - } - } else if (channel === 'Hifi-Teleport-Ignore-Add' && - !Uuid.isNull(message) && - ignoredEntities.indexOf(message) === -1) { - ignoredEntities.push(message); - leftTeleporter.setIgnoreEntities(ignoredEntities); - rightTeleporter.setIgnoreEntities(ignoredEntities); - } else if (channel === 'Hifi-Teleport-Ignore-Remove' && !Uuid.isNull(message)) { - var removeIndex = ignoredEntities.indexOf(message); - if (removeIndex > -1) { - ignoredEntities.splice(removeIndex, 1); - leftTeleporter.setIgnoreEntities(ignoredEntities); - rightTeleporter.setIgnoreEntities(ignoredEntities); - } - } - } - }; - - MyAvatar.onLoadComplete.connect(function () { - Script.setTimeout(function () { - leftTeleporter.initPointers(); - rightTeleporter.initPointers(); - }, 500); - }); - - Messages.subscribe('Hifi-Teleport-Disabler'); - Messages.subscribe('Hifi-Teleport-Ignore-Add'); - Messages.subscribe('Hifi-Teleport-Ignore-Remove'); - Messages.messageReceived.connect(handleTeleportMessages); - - MyAvatar.sensorToWorldScaleChanged.connect(function () { - leftTeleporter.updatePlayAreaScale(); - rightTeleporter.updatePlayAreaScale(); - }); - -}()); // END LOCAL_SCOPE diff --git a/scripts/simplifiedUI/system/controllers/controllerModules/webSurfaceLaserInput.js b/scripts/simplifiedUI/system/controllers/controllerModules/webSurfaceLaserInput.js deleted file mode 100644 index cf700a8ad9..0000000000 --- a/scripts/simplifiedUI/system/controllers/controllerModules/webSurfaceLaserInput.js +++ /dev/null @@ -1,288 +0,0 @@ -"use strict"; - -// webSurfaceLaserInput.js -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html - -/* global Script, Entities, enableDispatcherModule, disableDispatcherModule, makeRunningValues, - makeDispatcherModuleParameters, Overlays, HMD, TRIGGER_ON_VALUE, TRIGGER_OFF_VALUE, getEnabledModuleByName, - ContextOverlay, Picks, makeLaserParams, Settings, MyAvatar, RIGHT_HAND, LEFT_HAND, DISPATCHER_PROPERTIES -*/ - -Script.include("/~/system/libraries/controllerDispatcherUtils.js"); -Script.include("/~/system/libraries/controllers.js"); - -(function() { - const intersectionType = { - None: 0, - WebOverlay: 1, - WebEntity: 2, - HifiKeyboard: 3, - Overlay: 4, - HifiTablet: 5, - }; - - function WebSurfaceLaserInput(hand) { - this.hand = hand; - this.otherHand = this.hand === RIGHT_HAND ? LEFT_HAND : RIGHT_HAND; - this.running = false; - this.ignoredObjects = []; - this.intersectedType = intersectionType["None"]; - - this.parameters = makeDispatcherModuleParameters( - 160, - this.hand === RIGHT_HAND ? ["rightHand"] : ["leftHand"], - [], - 100, - makeLaserParams(hand, true)); - - this.getFarGrab = function () { - return getEnabledModuleByName(this.hand === RIGHT_HAND ? ("RightFarGrabEntity") : ("LeftFarGrabEntity")); - }; - - this.farGrabActive = function () { - var farGrab = this.getFarGrab(); - // farGrab will be null if module isn't loaded. - if (farGrab) { - return farGrab.targetIsNull(); - } else { - return false; - } - }; - - this.grabModuleWantsNearbyOverlay = function(controllerData) { - if (controllerData.triggerValues[this.hand] > TRIGGER_ON_VALUE || controllerData.secondaryValues[this.hand] > BUMPER_ON_VALUE) { - var nearGrabName = this.hand === RIGHT_HAND ? "RightNearParentingGrabOverlay" : "LeftNearParentingGrabOverlay"; - var nearGrabModule = getEnabledModuleByName(nearGrabName); - if (nearGrabModule) { - var candidateOverlays = controllerData.nearbyOverlayIDs[this.hand]; - var grabbableOverlays = candidateOverlays.filter(function(overlayID) { - return Overlays.getProperty(overlayID, "grabbable"); - }); - var target = nearGrabModule.getTargetID(grabbableOverlays, controllerData); - if (target) { - return true; - } - } - nearGrabName = this.hand === RIGHT_HAND ? "RightNearParentingGrabEntity" : "LeftNearParentingGrabEntity"; - nearGrabModule = getEnabledModuleByName(nearGrabName); - if (nearGrabModule && nearGrabModule.isReady(controllerData)) { - // check for if near parent module is active. - var isNearGrabModuleActive = nearGrabModule.isReady(controllerData).active; - if (isNearGrabModuleActive) { - // if true, return true. - return isNearGrabModuleActive; - } else { - // check near action grab entity as a second pass. - nearGrabName = this.hand === RIGHT_HAND ? "RightNearActionGrabEntity" : "LeftNearActionGrabEntity"; - nearGrabModule = getEnabledModuleByName(nearGrabName); - if (nearGrabModule && nearGrabModule.isReady(controllerData)) { - return nearGrabModule.isReady(controllerData).active; - } - } - } - } - - var nearTabletHighlightModule = getEnabledModuleByName(this.hand === RIGHT_HAND - ? "RightNearTabletHighlight" : "LeftNearTabletHighlight"); - if (nearTabletHighlightModule) { - return nearTabletHighlightModule.isNearTablet(controllerData); - } - - return false; - }; - - this.getOtherModule = function() { - return this.hand === RIGHT_HAND ? leftOverlayLaserInput : rightOverlayLaserInput; - }; - - this.addObjectToIgnoreList = function(controllerData) { - if (Window.interstitialModeEnabled && !Window.isPhysicsEnabled()) { - var intersection = controllerData.rayPicks[this.hand]; - var objectID = intersection.objectID; - - if (intersection.type === Picks.INTERSECTED_OVERLAY) { - var overlayIndex = this.ignoredObjects.indexOf(objectID); - - var overlayName = Overlays.getProperty(objectID, "name"); - if (overlayName !== "Loading-Destination-Card-Text" && overlayName !== "Loading-Destination-Card-GoTo-Image" && - overlayName !== "Loading-Destination-Card-GoTo-Image-Hover") { - var data = { - action: 'add', - id: objectID - }; - Messages.sendMessage('Hifi-Hand-RayPick-Blacklist', JSON.stringify(data)); - this.ignoredObjects.push(objectID); - } - } else if (intersection.type === Picks.INTERSECTED_ENTITY) { - var entityIndex = this.ignoredObjects.indexOf(objectID); - var data = { - action: 'add', - id: objectID - }; - Messages.sendMessage('Hifi-Hand-RayPick-Blacklist', JSON.stringify(data)); - this.ignoredObjects.push(objectID); - } - } - }; - - this.restoreIgnoredObjects = function() { - for (var index = 0; index < this.ignoredObjects.length; index++) { - var data = { - action: 'remove', - id: this.ignoredObjects[index] - }; - Messages.sendMessage('Hifi-Hand-RayPick-Blacklist', JSON.stringify(data)); - } - - this.ignoredObjects = []; - }; - - this.getInteractableType = function(controllerData, triggerPressed, checkEntitiesOnly) { - // allow pointing at tablet, unlocked web entities, or web overlays automatically without pressing trigger, - // but for pointing at locked web entities or non-web overlays user must be pressing trigger - var intersection = controllerData.rayPicks[this.hand]; - var objectID = intersection.objectID; - if (intersection.type === Picks.INTERSECTED_OVERLAY && !checkEntitiesOnly) { - if ((HMD.tabletID && objectID === HMD.tabletID) || - (HMD.tabletScreenID && objectID === HMD.tabletScreenID) || - (HMD.homeButtonID && objectID === HMD.homeButtonID)) { - return intersectionType["HifiTablet"]; - } else { - var overlayType = Overlays.getOverlayType(objectID); - var type = intersectionType["None"]; - if (Keyboard.containsID(objectID) && !Keyboard.preferMalletsOverLasers) { - type = intersectionType["HifiKeyboard"]; - } else if (overlayType === "web3d") { - type = intersectionType["WebOverlay"]; - } else if (triggerPressed) { - type = intersectionType["Overlay"]; - } - - return type; - } - } else if (intersection.type === Picks.INTERSECTED_ENTITY) { - var entityProperties = Entities.getEntityProperties(objectID, DISPATCHER_PROPERTIES); - var entityType = entityProperties.type; - var isLocked = entityProperties.locked; - if (entityType === "Web" && (!isLocked || triggerPressed)) { - return intersectionType["WebEntity"]; - } - } - return intersectionType["None"]; - }; - - this.deleteContextOverlay = function() { - var farGrabModule = getEnabledModuleByName(this.hand === RIGHT_HAND ? - "RightFarActionGrabEntity" : - "LeftFarActionGrabEntity"); - if (farGrabModule) { - var entityWithContextOverlay = farGrabModule.entityWithContextOverlay; - - if (entityWithContextOverlay) { - ContextOverlay.destroyContextOverlay(entityWithContextOverlay); - farGrabModule.entityWithContextOverlay = false; - } - } - }; - - this.updateAlwaysOn = function(type) { - var PREFER_STYLUS_OVER_LASER = "preferStylusOverLaser"; - this.parameters.handLaser.alwaysOn = (!Settings.getValue(PREFER_STYLUS_OVER_LASER, false) || type === intersectionType["HifiKeyboard"]); - }; - - this.getDominantHand = function() { - return MyAvatar.getDominantHand() === "right" ? 1 : 0; - }; - - this.dominantHandOverride = false; - - this.isReady = function (controllerData) { - // Trivial rejection for when FarGrab is active. - if (this.farGrabActive()) { - return makeRunningValues(false, [], []); - } - - var isTriggerPressed = controllerData.triggerValues[this.hand] > TRIGGER_OFF_VALUE && - controllerData.triggerValues[this.otherHand] <= TRIGGER_OFF_VALUE; - var type = this.getInteractableType(controllerData, isTriggerPressed, false); - - if (type !== intersectionType["None"] && !this.grabModuleWantsNearbyOverlay(controllerData)) { - if (type === intersectionType["WebOverlay"] || type === intersectionType["WebEntity"] || type === intersectionType["HifiTablet"]) { - var otherModuleRunning = this.getOtherModule().running; - otherModuleRunning = otherModuleRunning && this.getDominantHand() !== this.hand; // Auto-swap to dominant hand. - var allowThisModule = !otherModuleRunning || isTriggerPressed; - - if (!allowThisModule) { - return makeRunningValues(true, [], []); - } - - if (isTriggerPressed) { - this.dominantHandOverride = true; // Override dominant hand. - this.getOtherModule().dominantHandOverride = false; - } - } - - this.updateAlwaysOn(type); - if (this.parameters.handLaser.alwaysOn || isTriggerPressed) { - return makeRunningValues(true, [], []); - } - } - - if (Window.interstitialModeEnabled && Window.isPhysicsEnabled()) { - this.restoreIgnoredObjects(); - } - return makeRunningValues(false, [], []); - }; - - this.shouldThisModuleRun = function(controllerData) { - var otherModuleRunning = this.getOtherModule().running; - otherModuleRunning = otherModuleRunning && this.getDominantHand() !== this.hand; // Auto-swap to dominant hand. - otherModuleRunning = otherModuleRunning || this.getOtherModule().dominantHandOverride; // Override dominant hand. - var grabModuleNeedsToRun = this.grabModuleWantsNearbyOverlay(controllerData); - // only allow for non-near grab - return !otherModuleRunning && !grabModuleNeedsToRun; - }; - - this.run = function(controllerData, deltaTime) { - this.addObjectToIgnoreList(controllerData); - var isTriggerPressed = controllerData.triggerValues[this.hand] > TRIGGER_OFF_VALUE; - var type = this.getInteractableType(controllerData, isTriggerPressed, false); - var laserOn = isTriggerPressed || this.parameters.handLaser.alwaysOn; - this.addObjectToIgnoreList(controllerData); - - if (type === intersectionType["HifiTablet"] && laserOn) { - if (this.shouldThisModuleRun(controllerData)) { - this.running = true; - return makeRunningValues(true, [], []); - } - } else if ((type === intersectionType["WebOverlay"] || type === intersectionType["WebEntity"]) && laserOn) { // auto laser on WebEntities andWebOverlays - if (this.shouldThisModuleRun(controllerData)) { - this.running = true; - return makeRunningValues(true, [], []); - } - } else if ((type === intersectionType["HifiKeyboard"] && laserOn) || type === intersectionType["Overlay"]) { - this.running = true; - return makeRunningValues(true, [], []); - } - - this.deleteContextOverlay(); - this.running = false; - this.dominantHandOverride = false; - return makeRunningValues(false, [], []); - }; - } - - var leftOverlayLaserInput = new WebSurfaceLaserInput(LEFT_HAND); - var rightOverlayLaserInput = new WebSurfaceLaserInput(RIGHT_HAND); - - enableDispatcherModule("LeftWebSurfaceLaserInput", leftOverlayLaserInput); - enableDispatcherModule("RightWebSurfaceLaserInput", rightOverlayLaserInput); - - function cleanup() { - disableDispatcherModule("LeftWebSurfaceLaserInput"); - disableDispatcherModule("RightWebSurfaceLaserInput"); - } - Script.scriptEnding.connect(cleanup); -}()); diff --git a/scripts/simplifiedUI/system/controllers/controllerScripts.js b/scripts/simplifiedUI/system/controllers/controllerScripts.js deleted file mode 100644 index c9cb61b5f5..0000000000 --- a/scripts/simplifiedUI/system/controllers/controllerScripts.js +++ /dev/null @@ -1,62 +0,0 @@ -"use strict"; - -// controllerScripts.js -// -// Created by David Rowe on 15 Mar 2017. -// Copyright 2017 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -/* global Script, Menu */ - -var CONTOLLER_SCRIPTS = [ - "squeezeHands.js", - "controllerDisplayManager.js", - "grab.js", - //"toggleAdvancedMovementForHandControllers.js", - "handTouch.js", - "controllerDispatcher.js", - "controllerModules/nearParentGrabOverlay.js", - "controllerModules/stylusInput.js", - "controllerModules/equipEntity.js", - "controllerModules/nearTrigger.js", - "controllerModules/webSurfaceLaserInput.js", - "controllerModules/inEditMode.js", - "controllerModules/inVREditMode.js", - "controllerModules/disableOtherModule.js", - "controllerModules/farTrigger.js", - "controllerModules/teleport.js", - "controllerModules/hudOverlayPointer.js", - "controllerModules/mouseHMD.js", - "controllerModules/nearGrabHyperLinkEntity.js", - "controllerModules/nearTabletHighlight.js", - "controllerModules/nearGrabEntity.js", - "controllerModules/farGrabEntity.js", - "controllerModules/pushToTalk.js" -]; - -var DEBUG_MENU_ITEM = "Debug defaultScripts.js"; - -function runDefaultsTogether() { - for (var j in CONTOLLER_SCRIPTS) { - if (CONTOLLER_SCRIPTS.hasOwnProperty(j)) { - Script.include(CONTOLLER_SCRIPTS[j]); - } - } -} - -function runDefaultsSeparately() { - for (var i in CONTOLLER_SCRIPTS) { - if (CONTOLLER_SCRIPTS.hasOwnProperty(i)) { - Script.load(CONTOLLER_SCRIPTS[i]); - } - } -} - -if (Menu.isOptionChecked(DEBUG_MENU_ITEM)) { - runDefaultsSeparately(); -} else { - runDefaultsTogether(); -} diff --git a/scripts/simplifiedUI/system/controllers/godView.js b/scripts/simplifiedUI/system/controllers/godView.js deleted file mode 100644 index 4b406399fd..0000000000 --- a/scripts/simplifiedUI/system/controllers/godView.js +++ /dev/null @@ -1,116 +0,0 @@ -"use strict"; -// -// godView.js -// scripts/system/ -// -// Created by Brad Hefta-Gaub on 1 Jun 2017 -// Copyright 2017 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// -/* globals HMD, Script, Menu, Tablet, Camera */ -/* eslint indent: ["error", 4, { "outerIIFEBody": 0 }] */ - -(function() { // BEGIN LOCAL_SCOPE - -var godView = false; - -var GOD_CAMERA_OFFSET = -1; // 1 meter below the avatar -var GOD_VIEW_HEIGHT = 300; // 300 meter above the ground -var ABOVE_GROUND_DROP = 2; -var MOVE_BY = 1; - -function moveTo(position) { - if (godView) { - MyAvatar.position = position; - Camera.position = Vec3.sum(MyAvatar.position, {x:0, y: GOD_CAMERA_OFFSET, z: 0}); - } else { - MyAvatar.position = position; - } -} - -function keyPressEvent(event) { - if (godView) { - switch(event.text) { - case "UP": - moveTo(Vec3.sum(MyAvatar.position, {x:0.0, y: 0, z: -1 * MOVE_BY})); - break; - case "DOWN": - moveTo(Vec3.sum(MyAvatar.position, {x:0, y: 0, z: MOVE_BY})); - break; - case "LEFT": - moveTo(Vec3.sum(MyAvatar.position, {x:-1 * MOVE_BY, y: 0, z: 0})); - break; - case "RIGHT": - moveTo(Vec3.sum(MyAvatar.position, {x:MOVE_BY, y: 0, z: 0})); - break; - } - } -} - -function mousePress(event) { - if (godView) { - var pickRay = Camera.computePickRay(event.x, event.y); - var pointingAt = Vec3.sum(pickRay.origin, Vec3.multiply(pickRay.direction,300)); - var moveToPosition = { x: pointingAt.x, y: MyAvatar.position.y, z: pointingAt.z }; - moveTo(moveToPosition); - } -} - - -var oldCameraMode = Camera.mode; - -function startGodView() { - if (!godView) { - oldCameraMode = Camera.mode; - MyAvatar.position = Vec3.sum(MyAvatar.position, {x:0, y: GOD_VIEW_HEIGHT, z: 0}); - Camera.mode = "independent"; - Camera.position = Vec3.sum(MyAvatar.position, {x:0, y: GOD_CAMERA_OFFSET, z: 0}); - Camera.orientation = Quat.fromPitchYawRollDegrees(-90,0,0); - godView = true; - } -} - -function endGodView() { - if (godView) { - Camera.mode = oldCameraMode; - MyAvatar.position = Vec3.sum(MyAvatar.position, {x:0, y: (-1 * GOD_VIEW_HEIGHT) + ABOVE_GROUND_DROP, z: 0}); - godView = false; - } -} - -var button; -var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); - -function onClicked() { - if (godView) { - endGodView(); - } else { - startGodView(); - } -} - -button = tablet.addButton({ - icon: "icons/tablet-icons/switch-desk-i.svg", // FIXME - consider a better icon from Alan - text: "God View" -}); - -button.clicked.connect(onClicked); -Controller.keyPressEvent.connect(keyPressEvent); -Controller.mousePressEvent.connect(mousePress); - - -Script.scriptEnding.connect(function () { - if (godView) { - endGodView(); - } - button.clicked.disconnect(onClicked); - if (tablet) { - tablet.removeButton(button); - } - Controller.keyPressEvent.disconnect(keyPressEvent); - Controller.mousePressEvent.disconnect(mousePress); -}); - -}()); // END LOCAL_SCOPE diff --git a/scripts/simplifiedUI/system/controllers/grab.js b/scripts/simplifiedUI/system/controllers/grab.js deleted file mode 100644 index 1fb82d3843..0000000000 --- a/scripts/simplifiedUI/system/controllers/grab.js +++ /dev/null @@ -1,522 +0,0 @@ -"use strict"; - -// grab.js -// examples -// -// Created by Eric Levin on May 1, 2015 -// Copyright 2015 High Fidelity, Inc. -// -// Grab's physically moveable entities with the mouse, by applying a spring force. -// -// Updated November 22, 2016 by Philip Rosedale: Add distance attenuation of grab effect -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -/* global MyAvatar, Entities, Script, HMD, Camera, Vec3, Reticle, Overlays, Messages, Quat, Controller, - isInEditMode, entityIsGrabbable, Picks, PickType, Pointers, unhighlightTargetEntity, DISPATCHER_PROPERTIES, - entityIsGrabbable, getMainTabletIDs -*/ -/* jslint bitwise: true */ - -(function() { // BEGIN LOCAL_SCOPE - -Script.include("/~/system/libraries/utils.js"); -Script.include("/~/system/libraries/controllerDispatcherUtils.js"); - -var MOUSE_GRAB_JOINT = 65526; // FARGRAB_MOUSE_INDEX - -var MAX_SOLID_ANGLE = 0.01; // objects that appear smaller than this can't be grabbed - -var DELAY_FOR_30HZ = 33; // milliseconds - -var ZERO_VEC3 = { x: 0, y: 0, z: 0 }; -var IDENTITY_QUAT = { x: 0, y: 0, z: 0, w: 1 }; - -// helper function -function mouseIntersectionWithPlane(pointOnPlane, planeNormal, event, maxDistance) { - var cameraPosition = Camera.getPosition(); - var localPointOnPlane = Vec3.subtract(pointOnPlane, cameraPosition); - var distanceFromPlane = Vec3.dot(localPointOnPlane, planeNormal); - var MIN_DISTANCE_FROM_PLANE = 0.001; - if (Math.abs(distanceFromPlane) < MIN_DISTANCE_FROM_PLANE) { - // camera is touching the plane - return pointOnPlane; - } - var pickRay = Camera.computePickRay(event.x, event.y); - var dirDotNorm = Vec3.dot(pickRay.direction, planeNormal); - var MIN_RAY_PLANE_DOT = 0.00001; - - var localIntersection; - var useMaxForwardGrab = false; - if (Math.abs(dirDotNorm) > MIN_RAY_PLANE_DOT) { - var distanceToIntersection = distanceFromPlane / dirDotNorm; - if (distanceToIntersection > 0 && distanceToIntersection < maxDistance) { - // ray points into the plane - localIntersection = Vec3.multiply(pickRay.direction, distanceFromPlane / dirDotNorm); - } else { - // ray intersects BEHIND the camera or else very far away - // so we clamp the grab point to be the maximum forward position - useMaxForwardGrab = true; - } - } else { - // ray points perpendicular to grab plane - // so we map the grab point to the maximum forward position - useMaxForwardGrab = true; - } - if (useMaxForwardGrab) { - // we re-route the intersection to be in front at max distance. - var rayDirection = Vec3.subtract(pickRay.direction, Vec3.multiply(planeNormal, dirDotNorm)); - rayDirection = Vec3.normalize(rayDirection); - localIntersection = Vec3.multiply(rayDirection, maxDistance); - localIntersection = Vec3.sum(localIntersection, Vec3.multiply(planeNormal, distanceFromPlane)); - } - var worldIntersection = Vec3.sum(cameraPosition, localIntersection); - return worldIntersection; -} - -// Mouse class stores mouse click and drag info -function Mouse() { - this.current = { - x: 0, - y: 0 - }; - this.previous = { - x: 0, - y: 0 - }; - this.rotateStart = { - x: 0, - y: 0 - }; - this.cursorRestore = { - x: 0, - y: 0 - }; -} - -Mouse.prototype.startDrag = function(position) { - this.current = { - x: position.x, - y: position.y - }; - this.startRotateDrag(); -}; - -Mouse.prototype.updateDrag = function(position) { - this.current = { - x: position.x, - y: position.y - }; -}; - -Mouse.prototype.startRotateDrag = function() { - this.previous = { - x: this.current.x, - y: this.current.y - }; - this.rotateStart = { - x: this.current.x, - y: this.current.y - }; - this.cursorRestore = Reticle.getPosition(); -}; - -Mouse.prototype.getDrag = function() { - var delta = { - x: this.current.x - this.previous.x, - y: this.current.y - this.previous.y - }; - this.previous = { - x: this.current.x, - y: this.current.y - }; - return delta; -}; - -Mouse.prototype.restoreRotateCursor = function() { - Reticle.setPosition(this.cursorRestore); - this.current = { - x: this.rotateStart.x, - y: this.rotateStart.y - }; -}; - -var mouse = new Mouse(); - -var beacon = { - type: "cube", - dimensions: { - x: 0.01, - y: 0, - z: 0.01 - }, - color: { - red: 200, - green: 200, - blue: 200 - }, - alpha: 1, - solid: true, - ignoreRayIntersection: true, - visible: true -}; - -// TODO: play sounds again when we aren't leaking AudioInjector threads -// var grabSound = SoundCache.getSound("https://hifi-public.s3.amazonaws.com/eric/sounds/CloseClamp.wav"); -// var releaseSound = SoundCache.getSound("https://hifi-public.s3.amazonaws.com/eric/sounds/ReleaseClamp.wav"); -// var VOLUME = 0.0; - - -// Grabber class stores and computes info for grab behavior -function Grabber() { - this.isGrabbing = false; - this.entityID = null; - this.startPosition = ZERO_VEC3; - this.lastRotation = IDENTITY_QUAT; - this.currentPosition = ZERO_VEC3; - this.planeNormal = ZERO_VEC3; - - // maxDistance is a function of the size of the object. - this.maxDistance = 0; - - // mode defines the degrees of freedom of the grab target positions - // relative to startPosition options include: - // xzPlane (default) - // verticalCylinder (SHIFT) - // rotate (CONTROL) - this.mode = "xzplane"; - - // offset allows the user to grab an object off-center. It points from the object's center - // to the point where the ray intersects the grab plane (at the moment the grab is initiated). - // Future target positions of the ray intersection are on the same plane, and the offset is subtracted - // to compute the target position of the object's center. - this.offset = { - x: 0, - y: 0, - z: 0 - }; - - this.liftKey = false; // SHIFT - this.rotateKey = false; // CONTROL - - this.mouseRayOverlays = Picks.createPick(PickType.Ray, { - joint: "Mouse", - filter: Picks.PICK_OVERLAYS | Picks.PICK_INCLUDE_NONCOLLIDABLE, - enabled: true - }); - var tabletItems = getMainTabletIDs(); - if (tabletItems.length > 0) { - Picks.setIncludeItems(this.mouseRayOverlays, tabletItems); - } - var renderStates = [{name: "grabbed", end: beacon}]; - this.mouseRayEntities = Pointers.createPointer(PickType.Ray, { - joint: "Mouse", - filter: Picks.PICK_ENTITIES | Picks.PICK_INCLUDE_NONCOLLIDABLE, - faceAvatar: true, - scaleWithParent: true, - enabled: true, - renderStates: renderStates - }); -} - -Grabber.prototype.computeNewGrabPlane = function() { - if (!this.isGrabbing) { - return; - } - - var modeWasRotate = (this.mode == "rotate"); - this.mode = "xzPlane"; - this.planeNormal = { - x: 0, - y: 1, - z: 0 - }; - if (this.rotateKey) { - this.mode = "rotate"; - mouse.startRotateDrag(); - } else { - if (modeWasRotate) { - // we reset the mouse screen position whenever we stop rotating - mouse.restoreRotateCursor(); - } - if (this.liftKey) { - this.mode = "verticalCylinder"; - // NOTE: during verticalCylinder mode a new planeNormal will be computed each move - } - } - - this.pointOnPlane = Vec3.subtract(this.currentPosition, this.offset); - var xzOffset = Vec3.subtract(this.pointOnPlane, Camera.getPosition()); - xzOffset.y = 0; - this.xzDistanceToGrab = Vec3.length(xzOffset); -}; - -Grabber.prototype.pressEvent = function(event) { - if (isInEditMode() || HMD.active) { - return; - } - if (event.button !== "LEFT") { - return; - } - if (event.isAlt || event.isMeta) { - return; - } - if (Overlays.getOverlayAtPoint(Reticle.position) > 0) { - // the mouse is pointing at an overlay; don't look for entities underneath the overlay. - return; - } - - var overlayResult = Picks.getPrevPickResult(this.mouseRayOverlays); - if (overlayResult.type != Picks.INTERSECTED_NONE) { - return; - } - - var pickResults = Pointers.getPrevPickResult(this.mouseRayEntities); - if (pickResults.type == Picks.INTERSECTED_NONE) { - Pointers.setRenderState(this.mouseRayEntities, ""); - return; - } - - var props = Entities.getEntityProperties(pickResults.objectID, DISPATCHER_PROPERTIES); - if (!entityIsGrabbable(props)) { - // only grab grabbable objects - return; - } - if (props.grab.equippable) { - // don't mouse-grab click-to-equip entities (let equipEntity.js handle these) - return; - } - - Pointers.setRenderState(this.mouseRayEntities, "grabbed"); - Pointers.setLockEndUUID(this.mouseRayEntities, pickResults.objectID, false); - unhighlightTargetEntity(pickResults.objectID); - - mouse.startDrag(event); - - var clickedEntity = pickResults.objectID; - var entityProperties = Entities.getEntityProperties(clickedEntity, DISPATCHER_PROPERTIES); - this.startPosition = entityProperties.position; - this.lastRotation = entityProperties.rotation; - var cameraPosition = Camera.getPosition(); - - var objectBoundingDiameter = Vec3.length(entityProperties.dimensions); - beacon.dimensions.y = objectBoundingDiameter; - Pointers.editRenderState(this.mouseRayEntities, "grabbed", {end: beacon}); - this.maxDistance = objectBoundingDiameter / MAX_SOLID_ANGLE; - if (Vec3.distance(this.startPosition, cameraPosition) > this.maxDistance) { - // don't allow grabs of things far away - return; - } - - this.isGrabbing = true; - - this.entityID = clickedEntity; - this.currentPosition = entityProperties.position; - - // compute the grab point - var pickRay = Camera.computePickRay(event.x, event.y); - var nearestPoint = Vec3.subtract(this.startPosition, cameraPosition); - var distanceToGrab = Vec3.dot(nearestPoint, pickRay.direction); - nearestPoint = Vec3.multiply(distanceToGrab, pickRay.direction); - this.pointOnPlane = Vec3.sum(cameraPosition, nearestPoint); - - // compute the grab offset (points from point of grab to object center) - this.offset = Vec3.subtract(this.startPosition, this.pointOnPlane); // offset in world-space - MyAvatar.setJointTranslation(MOUSE_GRAB_JOINT, MyAvatar.worldToJointPoint(this.startPosition)); - MyAvatar.setJointRotation(MOUSE_GRAB_JOINT, MyAvatar.worldToJointRotation(this.lastRotation)); - - this.computeNewGrabPlane(); - this.moveEvent(event); - - var args = "mouse"; - Entities.callEntityMethod(this.entityID, "startDistanceGrab", args); - - Messages.sendLocalMessage('Hifi-Object-Manipulation', JSON.stringify({ - action: 'grab', - grabbedEntity: this.entityID - })); - - if (this.grabID) { - MyAvatar.releaseGrab(this.grabID); - this.grabID = null; - } - this.grabID = MyAvatar.grab(this.entityID, MOUSE_GRAB_JOINT, ZERO_VEC3, IDENTITY_QUAT); - - // TODO: play sounds again when we aren't leaking AudioInjector threads - //Audio.playSound(grabSound, { position: entityProperties.position, volume: VOLUME }); -}; - -Grabber.prototype.releaseEvent = function(event) { - if (event.button !== "LEFT" && !HMD.active) { - return; - } - - if (this.moveEventTimer) { - Script.clearTimeout(this.moveEventTimer); - this.moveEventTimer = null; - } - - if (this.isGrabbing) { - this.isGrabbing = false; - - Pointers.setRenderState(this.mouseRayEntities, ""); - Pointers.setLockEndUUID(this.mouseRayEntities, null, false); - - var args = "mouse"; - Entities.callEntityMethod(this.entityID, "releaseGrab", args); - - Messages.sendLocalMessage('Hifi-Object-Manipulation', JSON.stringify({ - action: 'release', - grabbedEntity: this.entityID, - joint: "mouse" - })); - - if (this.grabID) { - MyAvatar.releaseGrab(this.grabID); - this.grabID = null; - } - - MyAvatar.clearJointData(MOUSE_GRAB_JOINT); - - // TODO: play sounds again when we aren't leaking AudioInjector threads - //Audio.playSound(releaseSound, { position: entityProperties.position, volume: VOLUME }); - } -}; - -Grabber.prototype.scheduleMouseMoveProcessor = function(event) { - var _this = this; - if (!this.moveEventTimer) { - this.moveEventTimer = Script.setTimeout(function() { - _this.moveEventProcess(); - }, DELAY_FOR_30HZ); - } -}; - -Grabber.prototype.moveEvent = function(event) { - // during the handling of the event, do as little as possible. We save the updated mouse position, - // and start a timer to react to the change. If more changes arrive before the timer fires, only - // the last update will be considered. This is done to avoid backing-up Qt's event queue. - if (!this.isGrabbing || HMD.active) { - return; - } - mouse.updateDrag(event); - this.scheduleMouseMoveProcessor(); -}; - -Grabber.prototype.moveEventProcess = function() { - this.moveEventTimer = null; - var entityProperties = Entities.getEntityProperties(this.entityID, DISPATCHER_PROPERTIES); - if (!entityProperties || HMD.active) { - return; - } - - this.currentPosition = entityProperties.position; - - if (this.mode === "rotate") { - var drag = mouse.getDrag(); - var orientation = Camera.getOrientation(); - var dragOffset = Vec3.multiply(drag.x, Quat.getRight(orientation)); - dragOffset = Vec3.sum(dragOffset, Vec3.multiply(-drag.y, Quat.getUp(orientation))); - var axis = Vec3.cross(dragOffset, Quat.getForward(orientation)); - axis = Vec3.normalize(axis); - var ROTATE_STRENGTH = 0.4; // magic number tuned by hand - var angle = ROTATE_STRENGTH * Math.sqrt((drag.x * drag.x) + (drag.y * drag.y)); - var deltaQ = Quat.angleAxis(angle, axis); - - this.lastRotation = Quat.multiply(deltaQ, this.lastRotation); - MyAvatar.setJointRotation(MOUSE_GRAB_JOINT, MyAvatar.worldToJointRotation(this.lastRotation)); - - } else { - var newPointOnPlane; - - if (this.mode === "verticalCylinder") { - // for this mode we recompute the plane based on current Camera - var planeNormal = Quat.getForward(Camera.getOrientation()); - planeNormal.y = 0; - planeNormal = Vec3.normalize(planeNormal); - var pointOnCylinder = Vec3.multiply(planeNormal, this.xzDistanceToGrab); - pointOnCylinder = Vec3.sum(Camera.getPosition(), pointOnCylinder); - newPointOnPlane = mouseIntersectionWithPlane(pointOnCylinder, planeNormal, mouse.current, this.maxDistance); - } else { - var cameraPosition = Camera.getPosition(); - newPointOnPlane = mouseIntersectionWithPlane(this.pointOnPlane, this.planeNormal, mouse.current, this.maxDistance); - var relativePosition = Vec3.subtract(newPointOnPlane, cameraPosition); - var distance = Vec3.length(relativePosition); - if (distance > this.maxDistance) { - // clamp distance - relativePosition = Vec3.multiply(relativePosition, this.maxDistance / distance); - newPointOnPlane = Vec3.sum(relativePosition, cameraPosition); - } - } - - MyAvatar.setJointTranslation(MOUSE_GRAB_JOINT, MyAvatar.worldToJointPoint(Vec3.sum(newPointOnPlane, this.offset))); - } - - this.scheduleMouseMoveProcessor(); -}; - -Grabber.prototype.keyReleaseEvent = function(event) { - if (event.text === "SHIFT") { - this.liftKey = false; - } - if (event.text === "CONTROL") { - this.rotateKey = false; - } - this.computeNewGrabPlane(); -}; - -Grabber.prototype.keyPressEvent = function(event) { - if (event.text === "SHIFT") { - this.liftKey = true; - } - if (event.text === "CONTROL") { - this.rotateKey = true; - } - this.computeNewGrabPlane(); -}; - -Grabber.prototype.cleanup = function() { - Pointers.removePointer(this.mouseRayEntities); - Picks.removePick(this.mouseRayOverlays); - if (this.grabID) { - MyAvatar.releaseGrab(this.grabID); - this.grabID = null; - } -}; - -var grabber = new Grabber(); - -function pressEvent(event) { - grabber.pressEvent(event); -} - -function moveEvent(event) { - grabber.moveEvent(event); -} - -function releaseEvent(event) { - grabber.releaseEvent(event); -} - -function keyPressEvent(event) { - grabber.keyPressEvent(event); -} - -function keyReleaseEvent(event) { - grabber.keyReleaseEvent(event); -} - -function cleanup() { - grabber.cleanup(); -} - -Controller.mousePressEvent.connect(pressEvent); -Controller.mouseMoveEvent.connect(moveEvent); -Controller.mouseReleaseEvent.connect(releaseEvent); -Controller.keyPressEvent.connect(keyPressEvent); -Controller.keyReleaseEvent.connect(keyReleaseEvent); -Script.scriptEnding.connect(cleanup); - -}()); // END LOCAL_SCOPE diff --git a/scripts/simplifiedUI/system/controllers/handTouch.js b/scripts/simplifiedUI/system/controllers/handTouch.js deleted file mode 100644 index 5939c6e3d2..0000000000 --- a/scripts/simplifiedUI/system/controllers/handTouch.js +++ /dev/null @@ -1,959 +0,0 @@ -// -// scripts/system/libraries/handTouch.js -// -// Created by Luis Cuenca on 12/29/17 -// Copyright 2017 High Fidelity, Inc. -// -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -/* jslint bitwise: true */ - -/* global Script, Overlays, Controller, Vec3, MyAvatar, Entities, RayPick -*/ - -(function () { - - var LEAP_MOTION_NAME = "LeapMotion"; - // Hand touch is disabled due to twitchy finger bug when walking near walls or tables. see BUGZ-154. - var handTouchEnabled = false; - var leapMotionEnabled = Controller.getRunningInputDeviceNames().indexOf(LEAP_MOTION_NAME) >= 0; - var MSECONDS_AFTER_LOAD = 2000; - var updateFingerWithIndex = 0; - var untouchableEntities = []; - - // Keys to access finger data - var fingerKeys = ["pinky", "ring", "middle", "index", "thumb"]; - - // Additionally close the hands to achieve a grabbing effect - var grabPercent = { left: 0, right: 0 }; - - var Palm = function() { - this.position = {x: 0, y: 0, z: 0}; - this.perpendicular = {x: 0, y: 0, z: 0}; - this.distance = 0; - this.fingers = { - pinky: {x: 0, y: 0, z: 0}, - middle: {x: 0, y: 0, z: 0}, - ring: {x: 0, y: 0, z: 0}, - thumb: {x: 0, y: 0, z: 0}, - index: {x: 0, y: 0, z: 0} - }; - this.set = false; - }; - - var palmData = { - left: new Palm(), - right: new Palm() - }; - - var handJointNames = {left: "LeftHand", right: "RightHand"}; - - // Store which fingers are touching - if all false restate the default poses - var isTouching = { - left: { - pinky: false, - middle: false, - ring: false, - thumb: false, - index: false - }, right: { - pinky: false, - middle: false, - ring: false, - thumb: false, - index: false - } - }; - - // frame count for transition to default pose - - var countToDefault = { - left: 0, - right: 0 - }; - - // joint data for open pose - var dataOpen = { - left: { - pinky: [ - {x: -0.0066, y: -0.0224, z: -0.2174, w: 0.9758}, - {x: 0.0112, y: 0.0001, z: 0.0093, w: 0.9999}, - {x: -0.0346, y: 0.0003, z: -0.0073, w: 0.9994} - ], - ring: [ - {x: -0.0029, y: -0.0094, z: -0.1413, w: 0.9899}, - {x: 0.0112, y: 0.0001, z: 0.0059, w: 0.9999}, - {x: -0.0346, y: 0.0002, z: -0.006, w: 0.9994} - ], - middle: [ - {x: -0.0016, y: 0, z: -0.0286, w: 0.9996}, - {x: 0.0112, y: -0.0001, z: -0.0063, w: 0.9999}, - {x: -0.0346, y: -0.0003, z: 0.0073, w: 0.9994} - ], - index: [ - {x: -0.0016, y: 0.0001, z: 0.0199, w: 0.9998}, - {x: 0.0112, y: 0, z: 0.0081, w: 0.9999}, - {x: -0.0346, y: 0.0008, z: -0.023, w: 0.9991} - ], - thumb: [ - {x: 0.0354, y: 0.0363, z: 0.3275, w: 0.9435}, - {x: -0.0945, y: 0.0938, z: 0.0995, w: 0.9861}, - {x: -0.0952, y: 0.0718, z: 0.1382, w: 0.9832} - ] - }, right: { - pinky: [ - {x: -0.0034, y: 0.023, z: 0.1051, w: 0.9942}, - {x: 0.0106, y: -0.0001, z: -0.0091, w: 0.9999}, - {x: -0.0346, y: -0.0003, z: 0.0075, w: 0.9994} - ], - ring: [ - {x: -0.0013, y: 0.0097, z: 0.0311, w: 0.9995}, - {x: 0.0106, y: -0.0001, z: -0.0056, w: 0.9999}, - {x: -0.0346, y: -0.0002, z: 0.0061, w: 0.9994} - ], - middle: [ - {x: -0.001, y: 0, z: 0.0285, w: 0.9996}, - {x: 0.0106, y: 0.0001, z: 0.0062, w: 0.9999}, - {x: -0.0346, y: 0.0003, z: -0.0074, w: 0.9994} - ], - index: [ - {x: -0.001, y: 0, z: -0.0199, w: 0.9998}, - {x: 0.0106, y: -0.0001, z: -0.0079, w: 0.9999}, - {x: -0.0346, y: -0.0008, z: 0.0229, w: 0.9991} - ], - thumb: [ - {x: 0.0355, y: -0.0363, z: -0.3263, w: 0.9439}, - {x: -0.0946, y: -0.0938, z: -0.0996, w: 0.9861}, - {x: -0.0952, y: -0.0719, z: -0.1376, w: 0.9833} - ] - } - }; - - // joint data for close pose - var dataClose = { - left: { - pinky: [ - {x: 0.5878, y: -0.1735, z: -0.1123, w: 0.7821}, - {x: 0.5704, y: 0.0053, z: 0.0076, w: 0.8213}, - {x: 0.6069, y: -0.0044, z: -0.0058, w: 0.7947} - ], - ring: [ - {x: 0.5761, y: -0.0989, z: -0.1025, w: 0.8048}, - {x: 0.5332, y: 0.0032, z: 0.005, w: 0.846}, - {x: 0.5773, y: -0.0035, z: -0.0049, w: 0.8165} - ], - middle: [ - {x: 0.543, y: -0.0469, z: -0.0333, w: 0.8378}, - {x: 0.5419, y: -0.0034, z: -0.0053, w: 0.8404}, - {x: 0.5015, y: 0.0037, z: 0.0063, w: 0.8651} - ], - index: [ - {x: 0.3051, y: -0.0156, z: -0.014, w: 0.9521}, - {x: 0.6414, y: 0.0051, z: 0.0063, w: 0.7671}, - {x: 0.5646, y: -0.013, z: -0.019, w: 0.8251} - ], - thumb: [ - {x: 0.313, y: -0.0348, z: 0.3192, w: 0.8938}, - {x: 0, y: 0, z: -0.37, w: 0.929}, - {x: 0, y: 0, z: -0.2604, w: 0.9655} - ] - }, right: { - pinky: [ - {x: 0.5881, y: 0.1728, z: 0.1114, w: 0.7823}, - {x: 0.5704, y: -0.0052, z: -0.0075, w: 0.8213}, - {x: 0.6069, y: 0.0046, z: 0.006, w: 0.7947} - ], - ring: [ - {x: 0.5729, y: 0.1181, z: 0.0898, w: 0.8061}, - {x: 0.5332, y: -0.003, z: -0.0048, w: 0.846}, - {x: 0.5773, y: 0.0035, z: 0.005, w: 0.8165} - ], - middle: [ - {x: 0.543, y: 0.0468, z: 0.0332, w: 0.8378}, - {x: 0.5419, y: 0.0034, z: 0.0052, w: 0.8404}, - {x: 0.5047, y: -0.0037, z: -0.0064, w: 0.8632} - ], - index: [ - {x: 0.306, y: -0.0076, z: -0.0584, w: 0.9502}, - {x: 0.6409, y: -0.005, z: -0.006, w: 0.7675}, - {x: 0.5646, y: 0.0129, z: 0.0189, w: 0.8251} - ], - thumb: [ - {x: 0.313, y: 0.0352, z: -0.3181, w: 0.8942}, - {x: 0, y: 0, z: 0.3698, w: 0.9291}, - {x: 0, y: 0, z: 0.2609, w: 0.9654} - ] - } - }; - - // snapshot for the default pose - var dataDefault = { - left: { - pinky: [{x: 0, y: 0, z: 0, w: 0},{x: 0, y: 0, z: 0, w: 0},{x: 0, y: 0, z: 0, w: 0}], - middle: [{x: 0, y: 0, z: 0, w: 0},{x: 0, y: 0, z: 0, w: 0},{x: 0, y: 0, z: 0, w: 0}], - ring: [{x: 0, y: 0, z: 0, w: 0},{x: 0, y: 0, z: 0, w: 0},{x: 0, y: 0, z: 0, w: 0}], - thumb: [{x: 0, y: 0, z: 0, w: 0},{x: 0, y: 0, z: 0, w: 0},{x: 0, y: 0, z: 0, w: 0}], - index: [{x: 0, y: 0, z: 0, w: 0},{x: 0, y: 0, z: 0, w: 0},{x: 0, y: 0, z: 0, w: 0}], - set: false - }, - right: { - pinky: [{x: 0, y: 0, z: 0, w: 0},{x: 0, y: 0, z: 0, w: 0},{x: 0, y: 0, z: 0, w: 0}], - middle: [{x: 0, y: 0, z: 0, w: 0},{x: 0, y: 0, z: 0, w: 0},{x: 0, y: 0, z: 0, w: 0}], - ring: [{x: 0, y: 0, z: 0, w: 0},{x: 0, y: 0, z: 0, w: 0},{x: 0, y: 0, z: 0, w: 0}], - thumb: [{x: 0, y: 0, z: 0, w: 0},{x: 0, y: 0, z: 0, w: 0},{x: 0, y: 0, z: 0, w: 0}], - index: [{x: 0, y: 0, z: 0, w: 0},{x: 0, y: 0, z: 0, w: 0},{x: 0, y: 0, z: 0, w: 0}], - set: false - } - }; - - // joint data for the current frame - var dataCurrent = { - left: { - pinky: [{x: 0, y: 0, z: 0, w: 0},{x: 0, y: 0, z: 0, w: 0},{x: 0, y: 0, z: 0, w: 0}], - middle: [{x: 0, y: 0, z: 0, w: 0},{x: 0, y: 0, z: 0, w: 0},{x: 0, y: 0, z: 0, w: 0}], - ring: [{x: 0, y: 0, z: 0, w: 0},{x: 0, y: 0, z: 0, w: 0},{x: 0, y: 0, z: 0, w: 0}], - thumb: [{x: 0, y: 0, z: 0, w: 0},{x: 0, y: 0, z: 0, w: 0},{x: 0, y: 0, z: 0, w: 0}], - index: [{x: 0, y: 0, z: 0, w: 0},{x: 0, y: 0, z: 0, w: 0},{x: 0, y: 0, z: 0, w: 0}] - }, - right: { - pinky: [{x: 0, y: 0, z: 0, w: 0},{x: 0, y: 0, z: 0, w: 0},{x: 0, y: 0, z: 0, w: 0}], - middle: [{x: 0, y: 0, z: 0, w: 0},{x: 0, y: 0, z: 0, w: 0},{x: 0, y: 0, z: 0, w: 0}], - ring: [{x: 0, y: 0, z: 0, w: 0},{x: 0, y: 0, z: 0, w: 0},{x: 0, y: 0, z: 0, w: 0}], - thumb: [{x: 0, y: 0, z: 0, w: 0},{x: 0, y: 0, z: 0, w: 0},{x: 0, y: 0, z: 0, w: 0}], - index: [{x: 0, y: 0, z: 0, w: 0},{x: 0, y: 0, z: 0, w: 0},{x: 0, y: 0, z: 0, w: 0}] - } - }; - - // interpolated values on joint data to smooth movement - var dataDelta = { - left: { - pinky: [{x: 0, y: 0, z: 0, w: 0},{x: 0, y: 0, z: 0, w: 0},{x: 0, y: 0, z: 0, w: 0}], - middle: [{x: 0, y: 0, z: 0, w: 0},{x: 0, y: 0, z: 0, w: 0},{x: 0, y: 0, z: 0, w: 0}], - ring: [{x: 0, y: 0, z: 0, w: 0},{x: 0, y: 0, z: 0, w: 0},{x: 0, y: 0, z: 0, w: 0}], - thumb: [{x: 0, y: 0, z: 0, w: 0},{x: 0, y: 0, z: 0, w: 0},{x: 0, y: 0, z: 0, w: 0}], - index: [{x: 0, y: 0, z: 0, w: 0},{x: 0, y: 0, z: 0, w: 0},{x: 0, y: 0, z: 0, w: 0}] - }, - right: { - pinky: [{x: 0, y: 0, z: 0, w: 0},{x: 0, y: 0, z: 0, w: 0},{x: 0, y: 0, z: 0, w: 0}], - middle: [{x: 0, y: 0, z: 0, w: 0},{x: 0, y: 0, z: 0, w: 0},{x: 0, y: 0, z: 0, w: 0}], - ring: [{x: 0, y: 0, z: 0, w: 0},{x: 0, y: 0, z: 0, w: 0},{x: 0, y: 0, z: 0, w: 0}], - thumb: [{x: 0, y: 0, z: 0, w: 0},{x: 0, y: 0, z: 0, w: 0},{x: 0, y: 0, z: 0, w: 0}], - index: [{x: 0, y: 0, z: 0, w: 0},{x: 0, y: 0, z: 0, w: 0},{x: 0, y: 0, z: 0, w: 0}] - } - }; - - // Acquire an updated value per hand every 5 frames when finger is touching (faster in) - var touchAnimationSteps = 5; - - // Acquire an updated value per hand every 20 frames when finger is returning to default position (slower out) - var defaultAnimationSteps = 10; - - // Debugging info - var showSphere = false; - var showLines = false; - - // This get setup on creation - var linesCreated = false; - var sphereCreated = false; - - // Register object with API Debugger - var varsToDebug = { - scriptLoaded: false, - toggleDebugSphere: function() { - showSphere = !showSphere; - if (showSphere && !sphereCreated) { - createDebugSphere(); - sphereCreated = true; - } - }, - toggleDebugLines: function() { - showLines = !showLines; - if (showLines && !linesCreated) { - createDebugLines(); - linesCreated = true; - } - }, - fingerPercent: { - left: { - pinky: 0.38, - middle: 0.38, - ring: 0.38, - thumb: 0.38, - index: 0.38 - } , - right: { - pinky: 0.38, - middle: 0.38, - ring: 0.38, - thumb: 0.38, - index: 0.38 - } - }, - triggerValues: { - leftTriggerValue: 0, - leftTriggerClicked: 0, - rightTriggerValue: 0, - rightTriggerClicked: 0, - leftSecondaryValue: 0, - rightSecondaryValue: 0 - }, - palmData: { - left: new Palm(), - right: new Palm() - }, - offset: {x: 0, y: 0, z: 0}, - avatarLoaded: false - }; - - // Add/Subtract the joint data - per finger joint - function addVals(val1, val2, sign) { - var val = []; - if (val1.length !== val2.length) { - return; - } - for (var i = 0; i < val1.length; i++) { - val.push({x: 0, y: 0, z: 0, w: 0}); - val[i].x = val1[i].x + sign*val2[i].x; - val[i].y = val1[i].y + sign*val2[i].y; - val[i].z = val1[i].z + sign*val2[i].z; - val[i].w = val1[i].w + sign*val2[i].w; - } - return val; - } - - // Multiply/Divide the joint data - per finger joint - function multiplyValsBy(val1, num) { - var val = []; - for (var i = 0; i < val1.length; i++) { - val.push({x: 0, y: 0, z: 0, w: 0}); - val[i].x = val1[i].x * num; - val[i].y = val1[i].y * num; - val[i].z = val1[i].z * num; - val[i].w = val1[i].w * num; - } - return val; - } - - // Calculate the finger lengths by adding its joint lengths - function getJointDistances(jointNamesArray) { - var result = {distances: [], totalDistance: 0}; - for (var i = 1; i < jointNamesArray.length; i++) { - var index0 = MyAvatar.getJointIndex(jointNamesArray[i-1]); - var index1 = MyAvatar.getJointIndex(jointNamesArray[i]); - var pos0 = MyAvatar.getJointPosition(index0); - var pos1 = MyAvatar.getJointPosition(index1); - var distance = Vec3.distance(pos0, pos1); - result.distances.push(distance); - result.totalDistance += distance; - } - return result; - } - - function dataRelativeToWorld(side, dataIn, dataOut) { - var handJoint = handJointNames[side]; - var jointIndex = MyAvatar.getJointIndex(handJoint); - var worldPosHand = MyAvatar.jointToWorldPoint({x: 0, y: 0, z: 0}, jointIndex); - - dataOut.position = MyAvatar.jointToWorldPoint(dataIn.position, jointIndex); - var localPerpendicular = side === "right" ? {x: 0.2, y: 0, z: 1} : {x: -0.2, y: 0, z: 1}; - dataOut.perpendicular = Vec3.normalize( - Vec3.subtract(MyAvatar.jointToWorldPoint(localPerpendicular, jointIndex), worldPosHand) - ); - dataOut.distance = dataIn.distance; - for (var i = 0; i < fingerKeys.length; i++) { - var finger = fingerKeys[i]; - dataOut.fingers[finger] = MyAvatar.jointToWorldPoint(dataIn.fingers[finger], jointIndex); - } - } - - function dataRelativeToHandJoint(side, dataIn, dataOut) { - var handJoint = handJointNames[side]; - var jointIndex = MyAvatar.getJointIndex(handJoint); - var worldPosHand = MyAvatar.jointToWorldPoint({x: 0, y: 0, z: 0}, jointIndex); - - dataOut.position = MyAvatar.worldToJointPoint(dataIn.position, jointIndex); - dataOut.perpendicular = MyAvatar.worldToJointPoint(Vec3.sum(worldPosHand, dataIn.perpendicular), jointIndex); - dataOut.distance = dataIn.distance; - for (var i = 0; i < fingerKeys.length; i++) { - var finger = fingerKeys[i]; - dataOut.fingers[finger] = MyAvatar.worldToJointPoint(dataIn.fingers[finger], jointIndex); - } - } - - // Calculate touch field; Sphere at the center of the palm, - // perpendicular vector from the palm plane and origin of the the finger rays - function estimatePalmData(side) { - // Return data object - var data = new Palm(); - - var jointOffset = { x: 0, y: 0, z: 0 }; - - var upperSide = side[0].toUpperCase() + side.substring(1); - var jointIndexHand = MyAvatar.getJointIndex(upperSide + "Hand"); - - // Store position of the hand joint - var worldPosHand = MyAvatar.jointToWorldPoint(jointOffset, jointIndexHand); - var minusWorldPosHand = {x: -worldPosHand.x, y: -worldPosHand.y, z: -worldPosHand.z}; - - // Data for finger rays - var directions = {pinky: undefined, middle: undefined, ring: undefined, thumb: undefined, index: undefined}; - var positions = {pinky: undefined, middle: undefined, ring: undefined, thumb: undefined, index: undefined}; - - var thumbLength = 0; - var weightCount = 0; - - // Calculate palm center - var handJointWeight = 1; - var fingerJointWeight = 2; - - var palmCenter = {x: 0, y: 0, z: 0}; - palmCenter = Vec3.sum(worldPosHand, palmCenter); - - weightCount += handJointWeight; - - for (var i = 0; i < fingerKeys.length; i++) { - var finger = fingerKeys[i]; - var jointSuffixes = 4; // Get 4 joint names with suffix numbers (0, 1, 2, 3) - var jointNames = getJointNames(side, finger, jointSuffixes); - var fingerLength = getJointDistances(jointNames).totalDistance; - - var jointIndex = MyAvatar.getJointIndex(jointNames[0]); - positions[finger] = MyAvatar.jointToWorldPoint(jointOffset, jointIndex); - directions[finger] = Vec3.normalize(Vec3.sum(positions[finger], minusWorldPosHand)); - data.fingers[finger] = Vec3.sum(positions[finger], Vec3.multiply(fingerLength, directions[finger])); - if (finger !== "thumb") { - // finger joints have double the weight than the hand joint - // This would better position the palm estimation - - palmCenter = Vec3.sum(Vec3.multiply(fingerJointWeight, positions[finger]), palmCenter); - weightCount += fingerJointWeight; - } else { - thumbLength = fingerLength; - } - } - - // perpendicular change direction depending on the side - data.perpendicular = (side === "right") ? - Vec3.normalize(Vec3.cross(directions.index, directions.pinky)): - Vec3.normalize(Vec3.cross(directions.pinky, directions.index)); - - data.position = Vec3.multiply(1.0/weightCount, palmCenter); - - if (side === "right") { - varsToDebug.offset = MyAvatar.worldToJointPoint(worldPosHand, jointIndexHand); - } - - var palmDistanceMultiplier = 1.55; // 1.55 based on test/error for the sphere radius that best fits the hand - data.distance = palmDistanceMultiplier*Vec3.distance(data.position, positions.index); - - // move back thumb ray origin - var thumbBackMultiplier = 0.2; - data.fingers.thumb = Vec3.sum( - data.fingers.thumb, Vec3.multiply( -thumbBackMultiplier * thumbLength, data.perpendicular)); - - // return getDataRelativeToHandJoint(side, data); - dataRelativeToHandJoint(side, data, palmData[side]); - palmData[side].set = true; - } - - // Register GlobalDebugger for API Debugger - Script.registerValue("GlobalDebugger", varsToDebug); - - // store the rays for the fingers - only for debug purposes - var fingerRays = { - left: { - pinky: undefined, - middle: undefined, - ring: undefined, - thumb: undefined, - index: undefined - }, - right: { - pinky: undefined, - middle: undefined, - ring: undefined, - thumb: undefined, - index: undefined - } - }; - - // Create debug overlays - finger rays + palm rays + spheres - var palmRay, sphereHand; - - function createDebugLines() { - for (var i = 0; i < fingerKeys.length; i++) { - fingerRays.left[fingerKeys[i]] = Overlays.addOverlay("line3d", { - color: { red: 0, green: 0, blue: 255 }, - start: { x: 0, y: 0, z: 0 }, - end: { x: 0, y: 1, z: 0 }, - visible: showLines - }); - fingerRays.right[fingerKeys[i]] = Overlays.addOverlay("line3d", { - color: { red: 0, green: 0, blue: 255 }, - start: { x: 0, y: 0, z: 0 }, - end: { x: 0, y: 1, z: 0 }, - visible: showLines - }); - } - - palmRay = { - left: Overlays.addOverlay("line3d", { - color: { red: 255, green: 0, blue: 0 }, - start: { x: 0, y: 0, z: 0 }, - end: { x: 0, y: 1, z: 0 }, - visible: showLines - }), - right: Overlays.addOverlay("line3d", { - color: { red: 255, green: 0, blue: 0 }, - start: { x: 0, y: 0, z: 0 }, - end: { x: 0, y: 1, z: 0 }, - visible: showLines - }) - }; - linesCreated = true; - } - - function createDebugSphere() { - sphereHand = { - right: Overlays.addOverlay("sphere", { - position: MyAvatar.position, - color: { red: 0, green: 255, blue: 0 }, - scale: { x: 0.01, y: 0.01, z: 0.01 }, - visible: showSphere - }), - left: Overlays.addOverlay("sphere", { - position: MyAvatar.position, - color: { red: 0, green: 255, blue: 0 }, - scale: { x: 0.01, y: 0.01, z: 0.01 }, - visible: showSphere - }) - }; - sphereCreated = true; - } - - function acquireDefaultPose(side) { - for (var i = 0; i < fingerKeys.length; i++) { - var finger = fingerKeys[i]; - var jointSuffixes = 3; // We need rotation of the 0, 1 and 2 joints - var names = getJointNames(side, finger, jointSuffixes); - for (var j = 0; j < names.length; j++) { - var index = MyAvatar.getJointIndex(names[j]); - var rotation = MyAvatar.getJointRotation(index); - dataDefault[side][finger][j] = dataCurrent[side][finger][j] = rotation; - } - } - dataDefault[side].set = true; - } - - var rayPicks = { - left: { - pinky: undefined, - middle: undefined, - ring: undefined, - thumb: undefined, - index: undefined - }, - right: { - pinky: undefined, - middle: undefined, - ring: undefined, - thumb: undefined, - index: undefined - } - }; - - var dataFailed = { - left: { - pinky: 0, - middle: 0, - ring: 0, - thumb: 0, - index: 0 - }, - right: { - pinky: 0, - middle: 0, - ring: 0, - thumb: 0, - index: 0 - } - }; - - function clearRayPicks(side) { - for (var i = 0; i < fingerKeys.length; i++) { - var finger = fingerKeys[i]; - if (rayPicks[side][finger] !== undefined) { - RayPick.removeRayPick(rayPicks[side][finger]); - rayPicks[side][finger] = undefined; - } - } - } - - function createRayPicks(side) { - var data = palmData[side]; - clearRayPicks(side); - for (var i = 0; i < fingerKeys.length; i++) { - var finger = fingerKeys[i]; - var LOOKUP_DISTANCE_MULTIPLIER = 1.5; - var dist = LOOKUP_DISTANCE_MULTIPLIER*data.distance; - var checkOffset = { - x: data.perpendicular.x * dist, - y: data.perpendicular.y * dist, - z: data.perpendicular.z * dist - }; - - var checkPoint = Vec3.sum(data.position, Vec3.multiply(2, checkOffset)); - var sensorToWorldScale = MyAvatar.getSensorToWorldScale(); - - var origin = data.fingers[finger]; - - var direction = Vec3.normalize(Vec3.subtract(checkPoint, origin)); - - origin = Vec3.multiply(1/sensorToWorldScale, origin); - - rayPicks[side][finger] = RayPick.createRayPick( - { - "enabled": false, - "joint": handJointNames[side], - "posOffset": origin, - "dirOffset": direction, - "filter": RayPick.PICK_ENTITIES - } - ); - - RayPick.setPrecisionPicking(rayPicks[side][finger], true); - } - } - - function activateNextRay(side, index) { - var nextIndex = (index < fingerKeys.length-1) ? index + 1 : 0; - for (var i = 0; i < fingerKeys.length; i++) { - var finger = fingerKeys[i]; - if (i === nextIndex) { - RayPick.enableRayPick(rayPicks[side][finger]); - } else { - RayPick.disableRayPick(rayPicks[side][finger]); - } - } - } - - function updateSphereHand(side) { - var data = new Palm(); - dataRelativeToWorld(side, palmData[side], data); - varsToDebug.palmData[side] = palmData[side]; - - var palmPoint = data.position; - var LOOKUP_DISTANCE_MULTIPLIER = 1.5; - var dist = LOOKUP_DISTANCE_MULTIPLIER*data.distance; - - // Situate the debugging overlays - var checkOffset = { - x: data.perpendicular.x * dist, - y: data.perpendicular.y * dist, - z: data.perpendicular.z * dist - }; - - var spherePos = Vec3.sum(palmPoint, checkOffset); - var checkPoint = Vec3.sum(palmPoint, Vec3.multiply(2, checkOffset)); - - if (showLines) { - Overlays.editOverlay(palmRay[side], { - start: palmPoint, - end: checkPoint, - visible: showLines - }); - for (var i = 0; i < fingerKeys.length; i++) { - Overlays.editOverlay(fingerRays[side][fingerKeys[i]], { - start: data.fingers[fingerKeys[i]], - end: checkPoint, - visible: showLines - }); - } - } - - if (showSphere) { - Overlays.editOverlay(sphereHand[side], { - position: spherePos, - scale: { - x: 2*dist, - y: 2*dist, - z: 2*dist - }, - visible: showSphere - }); - } - - // Update the intersection of only one finger at a time - var finger = fingerKeys[updateFingerWithIndex]; - var nearbyEntities = Entities.findEntities(spherePos, dist); - // Filter the entities that are allowed to be touched - var touchableEntities = nearbyEntities.filter(function (id) { - return untouchableEntities.indexOf(id) == -1; - }); - var intersection; - if (rayPicks[side][finger] !== undefined) { - intersection = RayPick.getPrevRayPickResult(rayPicks[side][finger]); - } - - var animationSteps = defaultAnimationSteps; - var newFingerData = dataDefault[side][finger]; - var isAbleToGrab = false; - if (touchableEntities.length > 0) { - RayPick.setIncludeItems(rayPicks[side][finger], touchableEntities); - - if (intersection === undefined) { - return; - } - - var percent = 0; // Initialize - isAbleToGrab = intersection.intersects && intersection.distance < LOOKUP_DISTANCE_MULTIPLIER*dist; - if (isAbleToGrab && !getTouching(side)) { - acquireDefaultPose(side); // take a snapshot of the default pose before touch starts - newFingerData = dataDefault[side][finger]; // assign default pose to finger data - } - // Store if this finger is touching something - isTouching[side][finger] = isAbleToGrab; - if (isAbleToGrab) { - // update the open/close percentage for this finger - var FINGER_REACT_MULTIPLIER = 2.8; - - percent = intersection.distance/(FINGER_REACT_MULTIPLIER*dist); - - var THUMB_FACTOR = 0.2; - var FINGER_FACTOR = 0.05; - - // Amount of grab coefficient added to the fingers - thumb is higher - var grabMultiplier = finger === "thumb" ? THUMB_FACTOR : FINGER_FACTOR; - percent += grabMultiplier * grabPercent[side]; - - // Calculate new interpolation data - var totalDistance = addVals(dataClose[side][finger], dataOpen[side][finger], -1); - // Assign close/open ratio to finger to simulate touch - newFingerData = addVals(dataOpen[side][finger], multiplyValsBy(totalDistance, percent), 1); - animationSteps = touchAnimationSteps; - } - varsToDebug.fingerPercent[side][finger] = percent; - - } - if (!isAbleToGrab) { - dataFailed[side][finger] = dataFailed[side][finger] === 0 ? 1 : 2; - } else { - dataFailed[side][finger] = 0; - } - // If it only fails once it will not update increments - if (dataFailed[side][finger] !== 1) { - // Calculate animation increments - dataDelta[side][finger] = - multiplyValsBy(addVals(newFingerData, dataCurrent[side][finger], -1), 1.0/animationSteps); - } - } - - // Recreate the finger joint names - function getJointNames(side, finger, count) { - var names = []; - for (var i = 1; i < count+1; i++) { - var name = side[0].toUpperCase()+side.substring(1)+"Hand"+finger[0].toUpperCase()+finger.substring(1)+(i); - names.push(name); - } - return names; - } - - // Capture the controller values - var leftTriggerPress = function (value) { - varsToDebug.triggerValues.leftTriggerValue = value; - // the value for the trigger increments the hand-close percentage - grabPercent.left = value; - }; - - var leftTriggerClick = function (value) { - varsToDebug.triggerValues.leftTriggerClicked = value; - }; - - var rightTriggerPress = function (value) { - varsToDebug.triggerValues.rightTriggerValue = value; - // the value for the trigger increments the hand-close percentage - grabPercent.right = value; - }; - - var rightTriggerClick = function (value) { - varsToDebug.triggerValues.rightTriggerClicked = value; - }; - - var leftSecondaryPress = function (value) { - varsToDebug.triggerValues.leftSecondaryValue = value; - }; - - var rightSecondaryPress = function (value) { - varsToDebug.triggerValues.rightSecondaryValue = value; - }; - - var MAPPING_NAME = "com.highfidelity.handTouch"; - var mapping = Controller.newMapping(MAPPING_NAME); - mapping.from([Controller.Standard.RT]).peek().to(rightTriggerPress); - mapping.from([Controller.Standard.RTClick]).peek().to(rightTriggerClick); - mapping.from([Controller.Standard.LT]).peek().to(leftTriggerPress); - mapping.from([Controller.Standard.LTClick]).peek().to(leftTriggerClick); - - mapping.from([Controller.Standard.RB]).peek().to(rightSecondaryPress); - mapping.from([Controller.Standard.LB]).peek().to(leftSecondaryPress); - mapping.from([Controller.Standard.LeftGrip]).peek().to(leftSecondaryPress); - mapping.from([Controller.Standard.RightGrip]).peek().to(rightSecondaryPress); - - Controller.enableMapping(MAPPING_NAME); - - if (showLines && !linesCreated) { - createDebugLines(); - linesCreated = true; - } - - if (showSphere && !sphereCreated) { - createDebugSphere(); - sphereCreated = true; - } - - function getTouching(side) { - var animating = false; - for (var i = 0; i < fingerKeys.length; i++) { - var finger = fingerKeys[i]; - animating = animating || isTouching[side][finger]; - } - return animating; // return false only if none of the fingers are touching - } - - function reEstimatePalmData() { - ["right", "left"].forEach(function(side) { - estimatePalmData(side); - }); - } - - function recreateRayPicks() { - ["right", "left"].forEach(function(side) { - createRayPicks(side); - }); - } - - function cleanUp() { - ["right", "left"].forEach(function (side) { - if (linesCreated) { - Overlays.deleteOverlay(palmRay[side]); - } - if (sphereCreated) { - Overlays.deleteOverlay(sphereHand[side]); - } - clearRayPicks(side); - for (var i = 0; i < fingerKeys.length; i++) { - var finger = fingerKeys[i]; - var jointSuffixes = 3; // We need to clear the joints 0, 1 and 2 joints - var names = getJointNames(side, finger, jointSuffixes); - for (var j = 0; j < names.length; j++) { - var index = MyAvatar.getJointIndex(names[j]); - MyAvatar.clearJointData(index); - } - if (linesCreated) { - Overlays.deleteOverlay(fingerRays[side][finger]); - } - } - }); - } - - MyAvatar.shouldDisableHandTouchChanged.connect(function (shouldDisable) { - if (shouldDisable) { - if (handTouchEnabled) { - cleanUp(); - } - } else { - if (!handTouchEnabled) { - reEstimatePalmData(); - recreateRayPicks(); - } - } - handTouchEnabled = !shouldDisable; - }); - - Controller.inputDeviceRunningChanged.connect(function (deviceName, isEnabled) { - if (deviceName == LEAP_MOTION_NAME) { - leapMotionEnabled = isEnabled; - } - }); - - MyAvatar.disableHandTouchForIDChanged.connect(function (entityID, disable) { - var entityIndex = untouchableEntities.indexOf(entityID); - if (disable) { - if (entityIndex == -1) { - untouchableEntities.push(entityID); - } - } else { - if (entityIndex != -1) { - untouchableEntities.splice(entityIndex, 1); - } - } - }); - - MyAvatar.onLoadComplete.connect(function () { - // Sometimes the rig is not ready when this signal is trigger - console.log("avatar loaded"); - Script.setTimeout(function() { - reEstimatePalmData(); - recreateRayPicks(); - }, MSECONDS_AFTER_LOAD); - }); - - MyAvatar.sensorToWorldScaleChanged.connect(function() { - reEstimatePalmData(); - }); - - Script.scriptEnding.connect(function () { - cleanUp(); - }); - - Script.update.connect(function () { - - if (!handTouchEnabled || leapMotionEnabled) { - return; - } - - // index of the finger that needs to be updated this frame - updateFingerWithIndex = (updateFingerWithIndex < fingerKeys.length-1) ? updateFingerWithIndex + 1 : 0; - - ["right", "left"].forEach(function(side) { - - if (!palmData[side].set) { - reEstimatePalmData(); - recreateRayPicks(); - } - - // recalculate the base data - updateSphereHand(side); - activateNextRay(side, updateFingerWithIndex); - - // this vars manage the transition to default pose - var isHandTouching = getTouching(side); - countToDefault[side] = isHandTouching ? 0 : countToDefault[side] + 1; - - for (var i = 0; i < fingerKeys.length; i++) { - var finger = fingerKeys[i]; - var jointSuffixes = 3; // We need to update rotation of the 0, 1 and 2 joints - var names = getJointNames(side, finger, jointSuffixes); - - // Add the animation increments - dataCurrent[side][finger] = addVals(dataCurrent[side][finger], dataDelta[side][finger], 1); - - // update every finger joint - for (var j = 0; j < names.length; j++) { - var index = MyAvatar.getJointIndex(names[j]); - // if no finger is touching restate the default poses - if (isHandTouching || (dataDefault[side].set && - countToDefault[side] < fingerKeys.length*touchAnimationSteps)) { - var quatRot = dataCurrent[side][finger][j]; - MyAvatar.setJointRotation(index, quatRot); - } else { - MyAvatar.clearJointData(index); - } - } - } - }); - }); -}()); diff --git a/scripts/simplifiedUI/system/controllers/squeezeHands.js b/scripts/simplifiedUI/system/controllers/squeezeHands.js deleted file mode 100644 index 69f44f46a9..0000000000 --- a/scripts/simplifiedUI/system/controllers/squeezeHands.js +++ /dev/null @@ -1,184 +0,0 @@ -"use strict"; - -// -// controllers/squeezeHands.js -// -// Created by Anthony J. Thibault -// Copyright 2015 High Fidelity, Inc. -// -// Default script to drive the animation of the hands based on hand controllers. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// -/* global Script, MyAvatar, Messages, Controller */ -/* eslint indent: ["error", 4, { "outerIIFEBody": 0 }] */ - -(function() { // BEGIN LOCAL_SCOPE - -var lastLeftTrigger = 0; -var lastRightTrigger = 0; -var leftHandOverlayAlpha = 0; -var rightHandOverlayAlpha = 0; - -// var CONTROLLER_DEAD_SPOT = 0.25; -var TRIGGER_SMOOTH_TIMESCALE = 0.1; -var OVERLAY_RAMP_RATE = 8.0; - -var animStateHandlerID; - -var leftIndexPointingOverride = 0; -var rightIndexPointingOverride = 0; -var leftThumbRaisedOverride = 0; -var rightThumbRaisedOverride = 0; - -var HIFI_POINT_INDEX_MESSAGE_CHANNEL = "Hifi-Point-Index"; - -var isLeftIndexPointing = false; -var isRightIndexPointing = false; -var isLeftThumbRaised = false; -var isRightThumbRaised = false; - -function clamp(val, min, max) { - return Math.min(Math.max(val, min), max); -} - -// function normalizeControllerValue(val) { -// return clamp((val - CONTROLLER_DEAD_SPOT) / (1 - CONTROLLER_DEAD_SPOT), 0, 1); -// } - -function lerp(a, b, alpha) { - return a * (1 - alpha) + b * alpha; -} - -function init() { - Script.update.connect(update); - animStateHandlerID = MyAvatar.addAnimationStateHandler( - animStateHandler, - [ - "leftHandOverlayAlpha", "leftHandGraspAlpha", - "rightHandOverlayAlpha", "rightHandGraspAlpha", - "isLeftHandGrasp", "isLeftIndexPoint", "isLeftThumbRaise", "isLeftIndexPointAndThumbRaise", - "isRightHandGrasp", "isRightIndexPoint", "isRightThumbRaise", "isRightIndexPointAndThumbRaise" - ] - ); - Messages.subscribe(HIFI_POINT_INDEX_MESSAGE_CHANNEL); - Messages.messageReceived.connect(handleMessages); -} - -function animStateHandler(props) { - return { - leftHandOverlayAlpha: leftHandOverlayAlpha, - leftHandGraspAlpha: lastLeftTrigger, - rightHandOverlayAlpha: rightHandOverlayAlpha, - rightHandGraspAlpha: lastRightTrigger, - - isLeftHandGrasp: !isLeftIndexPointing && !isLeftThumbRaised, - isLeftIndexPoint: isLeftIndexPointing && !isLeftThumbRaised, - isLeftThumbRaise: !isLeftIndexPointing && isLeftThumbRaised, - isLeftIndexPointAndThumbRaise: isLeftIndexPointing && isLeftThumbRaised, - - isRightHandGrasp: !isRightIndexPointing && !isRightThumbRaised, - isRightIndexPoint: isRightIndexPointing && !isRightThumbRaised, - isRightThumbRaise: !isRightIndexPointing && isRightThumbRaised, - isRightIndexPointAndThumbRaise: isRightIndexPointing && isRightThumbRaised - }; -} - -function update(dt) { - var leftTrigger = clamp(Controller.getValue(Controller.Standard.LT) + Controller.getValue(Controller.Standard.LeftGrip), 0, 1); - var rightTrigger = clamp(Controller.getValue(Controller.Standard.RT) + Controller.getValue(Controller.Standard.RightGrip), 0, 1); - - // Average last few trigger values together for a bit of smoothing - var tau = clamp(dt / TRIGGER_SMOOTH_TIMESCALE, 0, 1); - lastLeftTrigger = lerp(leftTrigger, lastLeftTrigger, tau); - lastRightTrigger = lerp(rightTrigger, lastRightTrigger, tau); - - // ramp on/off left hand overlay - var leftHandPose = Controller.getPoseValue(Controller.Standard.LeftHand); - if (leftHandPose.valid) { - leftHandOverlayAlpha = clamp(leftHandOverlayAlpha + OVERLAY_RAMP_RATE * dt, 0, 1); - } else { - leftHandOverlayAlpha = clamp(leftHandOverlayAlpha - OVERLAY_RAMP_RATE * dt, 0, 1); - } - - // ramp on/off right hand overlay - var rightHandPose = Controller.getPoseValue(Controller.Standard.RightHand); - if (rightHandPose.valid) { - rightHandOverlayAlpha = clamp(rightHandOverlayAlpha + OVERLAY_RAMP_RATE * dt, 0, 1); - } else { - rightHandOverlayAlpha = clamp(rightHandOverlayAlpha - OVERLAY_RAMP_RATE * dt, 0, 1); - } - - // Pointing index fingers and raising thumbs - isLeftIndexPointing = (leftIndexPointingOverride > 0) || (leftHandPose.valid && Controller.getValue(Controller.Standard.LeftIndexPoint) === 1); - isRightIndexPointing = (rightIndexPointingOverride > 0) || (rightHandPose.valid && Controller.getValue(Controller.Standard.RightIndexPoint) === 1); - isLeftThumbRaised = (leftThumbRaisedOverride > 0) || (leftHandPose.valid && Controller.getValue(Controller.Standard.LeftThumbUp) === 1); - isRightThumbRaised = (rightThumbRaisedOverride > 0) || (rightHandPose.valid && Controller.getValue(Controller.Standard.RightThumbUp) === 1); -} - -function handleMessages(channel, message, sender) { - if (sender === MyAvatar.sessionUUID && channel === HIFI_POINT_INDEX_MESSAGE_CHANNEL) { - var data = JSON.parse(message); - - if (data.pointIndex !== undefined) { - if (data.pointIndex) { - leftIndexPointingOverride++; - rightIndexPointingOverride++; - } else { - leftIndexPointingOverride--; - rightIndexPointingOverride--; - } - } - if (data.pointLeftIndex !== undefined) { - if (data.pointLeftIndex) { - leftIndexPointingOverride++; - } else { - leftIndexPointingOverride--; - } - } - if (data.pointRightIndex !== undefined) { - if (data.pointRightIndex) { - rightIndexPointingOverride++; - } else { - rightIndexPointingOverride--; - } - } - if (data.raiseThumbs !== undefined) { - if (data.raiseThumbs) { - leftThumbRaisedOverride++; - rightThumbRaisedOverride++; - } else { - leftThumbRaisedOverride--; - rightThumbRaisedOverride--; - } - } - if (data.raiseLeftThumb !== undefined) { - if (data.raiseLeftThumb) { - leftThumbRaisedOverride++; - } else { - leftThumbRaisedOverride--; - } - } - if (data.raiseRightThumb !== undefined) { - if (data.raiseRightThumb) { - rightThumbRaisedOverride++; - } else { - rightThumbRaisedOverride--; - } - } - } -} - -function shutdown() { - Script.update.disconnect(update); - MyAvatar.removeAnimationStateHandler(animStateHandlerID); - Messages.unsubscribe(HIFI_POINT_INDEX_MESSAGE_CHANNEL); - Messages.messageReceived.disconnect(handleMessages); -} - -Script.scriptEnding.connect(shutdown); - -init(); - -}()); // END LOCAL_SCOPE diff --git a/scripts/simplifiedUI/system/controllers/toggleAdvancedMovementForHandControllers.js b/scripts/simplifiedUI/system/controllers/toggleAdvancedMovementForHandControllers.js deleted file mode 100644 index 92f72f8724..0000000000 --- a/scripts/simplifiedUI/system/controllers/toggleAdvancedMovementForHandControllers.js +++ /dev/null @@ -1,174 +0,0 @@ -"use strict"; - -// Created by james b. pollack @imgntn on 8/18/2016 -// Copyright 2016 High Fidelity, Inc. -// -// advanced movements settings are in individual controller json files -// what we do is check the status of the 'advance movement' checkbox when you enter HMD mode -// if 'advanced movement' is checked...we give you the defaults that are in the json. -// if 'advanced movement' is not checked... we override the advanced controls with basic ones. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html - -/* jslint bitwise: true */ - -/* global Script, Quat, MyAvatar, HMD, Controller, Messages*/ - -(function() { // BEGIN LOCAL_SCOPE - - var TWO_SECONDS_INTERVAL = 2000; - var FLYING_MAPPING_NAME = 'Hifi-Flying-Dev-' + Math.random(); - var DRIVING_MAPPING_NAME = 'Hifi-Driving-Dev-' + Math.random(); - - var flyingMapping = null; - var drivingMapping = null; - - var TURN_RATE = 1000; - var isDisabled = false; - - var previousFlyingState = MyAvatar.getFlyingEnabled(); - var previousDrivingState = false; - - function rotate180() { - var newOrientation = Quat.multiply(MyAvatar.orientation, Quat.angleAxis(180, { - x: 0, - y: 1, - z: 0 - })); - MyAvatar.orientation = newOrientation; - } - - var inFlipTurn = false; - - function registerBasicMapping() { - - drivingMapping = Controller.newMapping(DRIVING_MAPPING_NAME); - drivingMapping.from(Controller.Standard.LY).to(function(value) { - if (isDisabled) { - return; - } - - if (value === 1 && Controller.Hardware.OculusTouch !== undefined) { - rotate180(); - } else if (Controller.Hardware.Vive !== undefined) { - if (value > 0.75 && inFlipTurn === false) { - inFlipTurn = true; - rotate180(); - Script.setTimeout(function() { - inFlipTurn = false; - }, TURN_RATE); - } - } - return; - }); - - flyingMapping = Controller.newMapping(FLYING_MAPPING_NAME); - flyingMapping.from(Controller.Standard.RY).to(function(value) { - if (isDisabled) { - return; - } - - if (value === 1 && Controller.Hardware.OculusTouch !== undefined) { - rotate180(); - } else if (Controller.Hardware.Vive !== undefined) { - if (value > 0.75 && inFlipTurn === false) { - inFlipTurn = true; - rotate180(); - Script.setTimeout(function() { - inFlipTurn = false; - }, TURN_RATE); - } - } - return; - }); - } - - function scriptEnding() { - Controller.disableMapping(FLYING_MAPPING_NAME); - Controller.disableMapping(DRIVING_MAPPING_NAME); - } - - Script.scriptEnding.connect(scriptEnding); - - registerBasicMapping(); - - Script.setTimeout(function() { - if (MyAvatar.useAdvanceMovementControls) { - Controller.disableMapping(DRIVING_MAPPING_NAME); - } else { - Controller.enableMapping(DRIVING_MAPPING_NAME); - } - - if (MyAvatar.getFlyingEnabled()) { - Controller.disableMapping(FLYING_MAPPING_NAME); - } else { - Controller.enableMapping(FLYING_MAPPING_NAME); - } - }, 100); - - - HMD.displayModeChanged.connect(function(isHMDMode) { - if (isHMDMode) { - if (Controller.Hardware.Vive !== undefined || Controller.Hardware.OculusTouch !== undefined) { - if (MyAvatar.useAdvancedMovementControls) { - Controller.disableMapping(DRIVING_MAPPING_NAME); - } else { - Controller.enableMapping(DRIVING_MAPPING_NAME); - } - - if (MyAvatar.getFlyingEnabled()) { - Controller.disableMapping(FLYING_MAPPING_NAME); - } else { - Controller.enableMapping(FLYING_MAPPING_NAME); - } - - } - } - }); - - - function update() { - if ((Controller.Hardware.Vive !== undefined || Controller.Hardware.OculusTouch !== undefined) && HMD.active) { - var flying = MyAvatar.getFlyingEnabled(); - var driving = MyAvatar.useAdvancedMovementControls; - - if (flying !== previousFlyingState) { - if (flying) { - Controller.disableMapping(FLYING_MAPPING_NAME); - } else { - Controller.enableMapping(FLYING_MAPPING_NAME); - } - - previousFlyingState = flying; - } - - if (driving !== previousDrivingState) { - if (driving) { - Controller.disableMapping(DRIVING_MAPPING_NAME); - } else { - Controller.enableMapping(DRIVING_MAPPING_NAME); - } - previousDrivingState = driving; - } - } - Script.setTimeout(update, TWO_SECONDS_INTERVAL); - } - - Script.setTimeout(update, TWO_SECONDS_INTERVAL); - - var HIFI_ADVANCED_MOVEMENT_DISABLER_CHANNEL = 'Hifi-Advanced-Movement-Disabler'; - function handleMessage(channel, message, sender) { - if (channel === HIFI_ADVANCED_MOVEMENT_DISABLER_CHANNEL) { - if (message === 'disable') { - isDisabled = true; - } else if (message === 'enable') { - isDisabled = false; - } - } - } - - Messages.subscribe(HIFI_ADVANCED_MOVEMENT_DISABLER_CHANNEL); - Messages.messageReceived.connect(handleMessage); - -}()); // END LOCAL_SCOPE diff --git a/scripts/simplifiedUI/system/controllers/touchControllerConfiguration.js b/scripts/simplifiedUI/system/controllers/touchControllerConfiguration.js deleted file mode 100644 index 991b77b8af..0000000000 --- a/scripts/simplifiedUI/system/controllers/touchControllerConfiguration.js +++ /dev/null @@ -1,372 +0,0 @@ - -// -// touchControllerConfiguration.js -// -// Created by Ryan Huffman on 12/06/16 -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -/* globals TOUCH_CONTROLLER_CONFIGURATION_LEFT:true, TOUCH_CONTROLLER_CONFIGURATION_RIGHT:true, - Quat, Vec3, Script, MyAvatar, Controller */ -/* eslint camelcase: ["error", { "properties": "never" }] */ - -var leftBaseRotation = Quat.multiply( - Quat.fromPitchYawRollDegrees(-90, 0, 0), - Quat.fromPitchYawRollDegrees(0, 0, 90) -); -var rightBaseRotation = Quat.multiply( - Quat.fromPitchYawRollDegrees(-90, 0, 0), - Quat.fromPitchYawRollDegrees(0, 0, -90) -); - -// keep these in sync with the values from OculusHelpers.cpp -var CONTROLLER_LENGTH_OFFSET = 0.0762; -// var CONTROLLER_LATERAL_OFFSET = 0.0381; -// var CONTROLLER_VERTICAL_OFFSET = 0.0381; -// var CONTROLLER_FORWARD_OFFSET = 0.1524; - -var leftBasePosition = Vec3.multiplyQbyV(leftBaseRotation, { - x: -CONTROLLER_LENGTH_OFFSET / 2.0, - y: CONTROLLER_LENGTH_OFFSET / 2.0, - z: CONTROLLER_LENGTH_OFFSET * 1.5 -}); -var rightBasePosition = Vec3.multiplyQbyV(rightBaseRotation, { - x: CONTROLLER_LENGTH_OFFSET / 2.0, - y: CONTROLLER_LENGTH_OFFSET / 2.0, - z: CONTROLLER_LENGTH_OFFSET * 1.5 -}); - -var BASE_URL = Script.resourcesPath() + "meshes/controller/touch/"; - -TOUCH_CONTROLLER_CONFIGURATION_LEFT = { - name: "Touch", - controllers: [ - { - modelURL: BASE_URL + "touch_l_body.fbx", - jointIndex: MyAvatar.getJointIndex("_CAMERA_RELATIVE_CONTROLLER_LEFTHAND"), - naturalPosition: { x: 0.01648625358939171, y: -0.03551870584487915, z: -0.018527675420045853 }, - dimensions: { x: 0.11053799837827682, y: 0.0995776429772377, z: 0.10139888525009155 }, - rotation: leftBaseRotation, - position: leftBasePosition, - - parts: { - tips: { - type: "static", - modelURL: BASE_URL + "Oculus-Labels-L.fbx", - naturalPosition: { x: -0.022335469722747803, y: 0.00022516027092933655, z: 0.020340695977211 }, - naturalDimensions: { x: 0.132063, y: 0.0856, z: 0.130282 }, - - textureName: "blank", - defaultTextureLayer: "blank", - textureLayers: { - blank: { - defaultTextureURL: BASE_URL + "Oculus-Labels-L.fbx/Oculus-Labels-L.fbm/Blank.png" - }, - trigger: { - defaultTextureURL: BASE_URL + "Oculus-Labels-L.fbx/Oculus-Labels-L.fbm/Trigger.png" - }, - arrows: { - defaultTextureURL: BASE_URL + "Oculus-Labels-L.fbx/Oculus-Labels-L.fbm/Rotate.png" - }, - grip: { - defaultTextureURL: BASE_URL + "Oculus-Labels-L.fbx/Oculus-Labels-L.fbm/Grip-oculus.png" - }, - teleport: { - defaultTextureURL: BASE_URL + "Oculus-Labels-L.fbx/Oculus-Labels-L.fbm/Teleport.png" - }, - both_triggers: { - defaultTextureURL: BASE_URL + "Oculus-Labels-L.fbx/Oculus-Labels-L.fbm/Grip-Trigger.png" - }, - } - }, - - trigger: { - type: "rotational", - modelURL: BASE_URL + "touch_l_trigger.fbx", - naturalPosition: { x: 0.0008544912561774254, y: -0.019867943599820137, z: 0.018800459802150726 }, - naturalDimensions: { x: 0.027509, y: 0.025211, z: 0.018443 }, - - // rotational - input: Controller.Standard.LT, - origin: { x: 0, y: -0.015, z: -0.00 }, - minValue: 0.0, - maxValue: 1.0, - axis: { x: 1, y: 0, z: 0 }, - maxAngle: 17, - - textureName: "tex-highlight", - defaultTextureLayer: "normal", - textureLayers: { - normal: { - defaultTextureURL: BASE_URL + "touch_l_trigger.fbx/touch_l_trigger.fbm/L_controller_DIF.jpg", - }, - highlight: { - defaultTextureURL: BASE_URL + "touch_l_trigger.fbx/touch_l_trigger.fbm/L_controller-highlight_DIF.jpg", - } - } - }, - - grip: { - type: "linear", - modelURL: BASE_URL + "touch_l_bumper.fbx", - naturalPosition: { x: 0.00008066371083259583, y: -0.02715788595378399, z: -0.02448512241244316 }, - naturalDimensions: { x: 0.017444, y: 0.020297, z: 0.026003 }, - - // linear properties - // Offset from origin = 0.36470, 0.11048, 0.11066 - input: "OculusTouch.LeftGrip", - axis: { x: 1, y: 0.302933918, z: 0.302933918 }, - maxTranslation: 0.003967, - - textureName: "tex-highlight", - defaultTextureLayer: "normal", - textureLayers: { - normal: { - defaultTextureURL: BASE_URL + "touch_l_bumper.fbx/touch_l_bumper.fbm/L_controller_DIF.jpg", - }, - highlight: { - defaultTextureURL: BASE_URL + "touch_l_bumper.fbx/touch_l_bumper.fbm/L_controller-highlight_DIF.jpg", - } - } - }, - - joystick: { - type: "joystick", - modelURL: BASE_URL + "touch_l_joystick.fbx", - naturalPosition: { x: 0.0075613949447870255, y: -0.008225866593420506, z: 0.004792703315615654 }, - naturalDimensions: { x: 0.027386, y: 0.033254, z: 0.027272 }, - - // joystick - xInput: "OculusTouch.LX", - yInput: "OculusTouch.LY", - originOffset: { x: 0, y: -0.0028564, z: -0.00 }, - xHalfAngle: 20, - yHalfAngle: 20, - - textureName: "tex-highlight", - defaultTextureLayer: "normal", - textureLayers: { - normal: { - defaultTextureURL: BASE_URL + "touch_l_joystick.fbx/touch_l_joystick.fbm/L_controller_DIF.jpg", - }, - highlight: { - defaultTextureURL: BASE_URL + "touch_l_joystick.fbx/touch_l_joystick.fbm/L_controller-highlight_DIF.jpg", - } - } - }, - - button_a: { - type: "linear", - modelURL: BASE_URL + "touch_l_button_x.fbx", - naturalPosition: { x: -0.009307309985160828, y: -0.00005015172064304352, z: -0.012594521045684814 }, - naturalDimensions: { x: 0.009861, y: 0.004345, z: 0.00982 }, - - input: "OculusTouch.X", - axis: { x: 0, y: -1, z: 0 }, - maxTranslation: 0.001, - - textureName: "tex-highlight", - defaultTextureLayer: "normal", - textureLayers: { - normal: { - defaultTextureURL: BASE_URL + "touch_l_button_x.fbx/touch_l_button_x.fbm/L_controller_DIF.jpg", - }, - highlight: { - defaultTextureURL: BASE_URL + "touch_l_button_x.fbx/touch_l_button_x.fbm/L_controller-highlight_DIF.jpg", - } - } - }, - - button_b: { - type: "linear", - modelURL: BASE_URL + "touch_l_button_y.fbx", - naturalPosition: { x: -0.01616849936544895, y: -0.000050364527851343155, z: 0.0017703399062156677 }, - naturalDimensions: { x: 0.010014, y: 0.004412, z: 0.009972 }, - - input: "OculusTouch.Y", - axis: { x: 0, y: -1, z: 0 }, - maxTranslation: 0.001, - - textureName: "tex-highlight", - defaultTextureLayer: "normal", - textureLayers: { - normal: { - defaultTextureURL: BASE_URL + "touch_l_button_y.fbx/touch_l_button_y.fbm/L_controller_DIF.jpg", - }, - highlight: { - defaultTextureURL: BASE_URL + "touch_l_button_y.fbx/touch_l_button_y.fbm/L_controller-highlight_DIF.jpg", - } - } - }, - } - } - ] -}; - -TOUCH_CONTROLLER_CONFIGURATION_RIGHT = { - name: "Touch", - controllers: [ - { - modelURL: BASE_URL + "touch_r_body.fbx", - jointIndex: MyAvatar.getJointIndex("_CAMERA_RELATIVE_CONTROLLER_RIGHTHAND"), - naturalPosition: { x: -0.016486231237649918, y: -0.03551865369081497, z: -0.018527653068304062 }, - dimensions: { x: 0.11053784191608429, y: 0.09957750141620636, z: 0.10139875113964081 }, - rotation: rightBaseRotation, - position: rightBasePosition, - - parts: { - tips: { - type: "static", - modelURL: BASE_URL + "Oculus-Labels-R.fbx", - naturalPosition: { x: 0.009739525616168976, y: -0.0017818436026573181, z: 0.016794726252555847 }, - naturalDimensions: { x: 0.129049, y: 0.078297, z: 0.139492 }, - - textureName: "blank", - defaultTextureLayer: "blank", - textureLayers: { - blank: { - defaultTextureURL: BASE_URL + "Oculus-Labels-R.fbx/Oculus-Labels-R.fbm/Blank.png" - }, - trigger: { - defaultTextureURL: BASE_URL + "Oculus-Labels-R.fbx/Oculus-Labels-R.fbm/Trigger.png" - }, - arrows: { - defaultTextureURL: BASE_URL + "Oculus-Labels-R.fbx/Oculus-Labels-R.fbm/Rotate.png" - }, - grip: { - defaultTextureURL: BASE_URL + "Oculus-Labels-R.fbx/Oculus-Labels-R.fbm/Grip-oculus.png" - }, - teleport: { - defaultTextureURL: BASE_URL + "Oculus-Labels-R.fbx/Oculus-Labels-R.fbm/Teleport.png" - }, - both_triggers: { - defaultTextureURL: BASE_URL + "Oculus-Labels-R.fbx/Oculus-Labels-R.fbm/Grip-Trigger.png" - }, - } - }, - - trigger: { - type: "rotational", - modelURL: BASE_URL + "touch_r_trigger.fbx", - naturalPosition: { x: -0.0008544912561774254, y: -0.019867943599820137, z: 0.018800459802150726 }, - naturalDimensions: { x: 0.027384, y: 0.025201, z: 0.018425 }, - - // rotational - input: "OculusTouch.RT", - origin: { x: 0, y: -0.015, z: 0 }, - minValue: 0.0, - maxValue: 1.0, - axis: { x: 1, y: 0, z: 0 }, - maxAngle: 17, - - textureName: "tex-highlight", - defaultTextureLayer: "normal", - textureLayers: { - normal: { - defaultTextureURL: BASE_URL + "touch_r_trigger.fbx/touch_r_trigger.fbm/R_controller_DIF.jpg", - }, - highlight: { - defaultTextureURL: BASE_URL + "touch_r_trigger.fbx/touch_r_trigger.fbm/R_controller-highlight_DIF.jpg", - } - } - }, - - grip: { - type: "linear", - modelURL: BASE_URL + "touch_r_bumper.fbx", - naturalPosition: { x: -0.0000806618481874466, y: -0.027157839387655258, z: -0.024485092610120773 }, - naturalDimensions: { x: 0.017268, y: 0.020366, z: 0.02599 }, - - // linear properties - // Offset from origin = 0.36470, 0.11048, 0.11066 - input: "OculusTouch.RightGrip", - axis: { x: -1, y: 0.302933918, z: 0.302933918 }, - maxTranslation: 0.003967, - - - textureName: "tex-highlight", - defaultTextureLayer: "normal", - textureLayers: { - normal: { - defaultTextureURL: BASE_URL + "touch_r_bumper.fbx/touch_r_bumper.fbm/R_controller_DIF.jpg", - }, - highlight: { - defaultTextureURL: BASE_URL + "touch_r_bumper.fbx/touch_r_bumper.fbm/R_controller-highlight_DIF.jpg", - } - } - }, - - joystick: { - type: "joystick", - modelURL: BASE_URL + "touch_r_joystick.fbx", - naturalPosition: { x: -0.007561382371932268, y: -0.008225853554904461, z: 0.00479268841445446 }, - naturalDimensions: { x: 0.027272, y: 0.033254, z: 0.027272 }, - - // joystick - xInput: "OculusTouch.RX", - yInput: "OculusTouch.RY", - originOffset: { x: 0, y: -0.0028564, z: 0 }, - xHalfAngle: 20, - yHalfAngle: 20, - - textureName: "tex-highlight", - defaultTextureLayer: "normal", - textureLayers: { - normal: { - defaultTextureURL: BASE_URL + "touch_r_joystick.fbx/touch_r_joystick.fbm/R_controller_DIF.jpg", - }, - highlight: { - defaultTextureURL: BASE_URL + "touch_r_joystick.fbx/touch_r_joystick.fbm/R_controller-highlight_DIF.jpg", - } - } - }, - - button_a: { - type: "linear", - modelURL: BASE_URL + "touch_r_button_a.fbx", - naturalPosition: { x: 0.009307296946644783, y: -0.00005015172064304352, z: -0.012594504281878471 }, - naturalDimensions: { x: 0.00982, y: 0.004345, z: 0.00982 }, - - input: "OculusTouch.A", - axis: { x: 0, y: -1, z: 0 }, - maxTranslation: 0.001, - - textureName: "tex-highlight", - defaultTextureLayer: "normal", - textureLayers: { - normal: { - defaultTextureURL: BASE_URL + "touch_r_button_a.fbx/touch_r_button_a.fbm/R_controller_DIF.jpg", - }, - highlight: { - defaultTextureURL: BASE_URL + "touch_r_button_a.fbx/touch_r_button_a.fbm/R_controller-highlight_DIF.jpg", - } - } - }, - - button_b: { - type: "linear", - modelURL: BASE_URL + "touch_r_button_b.fbx", - naturalPosition: { x: 0.01616847701370716, y: -0.000050364527851343155, z: 0.0017703361809253693 }, - naturalDimensions: { x: 0.009972, y: 0.004412, z: 0.009972 }, - - input: "OculusTouch.B", - axis: { x: 0, y: -1, z: 0 }, - maxTranslation: 0.001, - - textureName: "tex-highlight", - defaultTextureLayer: "normal", - textureLayers: { - normal: { - defaultTextureURL: BASE_URL + "touch_r_button_b.fbx/touch_r_button_b.fbm/R_controller_DIF.jpg", - }, - highlight: { - defaultTextureURL: BASE_URL + "touch_r_button_b.fbx/touch_r_button_b.fbm/R_controller-highlight_DIF.jpg", - } - } - }, - } - } - ] -}; diff --git a/scripts/simplifiedUI/system/controllers/viveControllerConfiguration.js b/scripts/simplifiedUI/system/controllers/viveControllerConfiguration.js deleted file mode 100644 index 09fd8adacc..0000000000 --- a/scripts/simplifiedUI/system/controllers/viveControllerConfiguration.js +++ /dev/null @@ -1,343 +0,0 @@ -// -// viveControllerConfiguration.js -// -// Created by Anthony J. Thibault on 10/20/16 -// Originally created by Ryan Huffman on 9/21/2016 -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -/* globals VIVE_CONTROLLER_CONFIGURATION_LEFT:true, VIVE_CONTROLLER_CONFIGURATION_RIGHT:true, - MyAvatar, Quat, Script, Vec3, Controller */ -/* eslint camelcase: ["error", { "properties": "never" }] */ - -// var LEFT_JOINT_INDEX = MyAvatar.getJointIndex("_CONTROLLER_LEFTHAND"); -// var RIGHT_JOINT_INDEX = MyAvatar.getJointIndex("_CONTROLLER_RIGHTHAND"); - -var leftBaseRotation = Quat.multiply( - Quat.fromPitchYawRollDegrees(0, 0, 45), - Quat.multiply( - Quat.fromPitchYawRollDegrees(90, 0, 0), - Quat.fromPitchYawRollDegrees(0, 0, 90) - ) -); - -var rightBaseRotation = Quat.multiply( - Quat.fromPitchYawRollDegrees(0, 0, -45), - Quat.multiply( - Quat.fromPitchYawRollDegrees(90, 0, 0), - Quat.fromPitchYawRollDegrees(0, 0, -90) - ) -); - -// keep these in sync with the values from plugins/openvr/src/OpenVrHelpers.cpp:303 -var CONTROLLER_LATERAL_OFFSET = 0.0381; -var CONTROLLER_VERTICAL_OFFSET = 0.0495; -var CONTROLLER_FORWARD_OFFSET = 0.1371; -var leftBasePosition = { - x: CONTROLLER_VERTICAL_OFFSET, - y: CONTROLLER_FORWARD_OFFSET, - z: CONTROLLER_LATERAL_OFFSET -}; -var rightBasePosition = { - x: -CONTROLLER_VERTICAL_OFFSET, - y: CONTROLLER_FORWARD_OFFSET, - z: CONTROLLER_LATERAL_OFFSET -}; - -var viveNaturalDimensions = { - x: 0.1174320001155138, - y: 0.08361100335605443, - z: 0.21942697931081057 -}; - -var viveNaturalPosition = { - x: 0, - y: -0.034076502197422087, - z: 0.06380049744620919 -}; - -var BASE_URL = Script.resourcesPath(); -// var TIP_TEXTURE_BASE_URL = BASE_URL + "meshes/controller/vive_tips.fbm/"; - -var viveModelURL = BASE_URL + "meshes/controller/vive_body.fbx"; -// var viveTipsModelURL = BASE_URL + "meshes/controller/vive_tips.fbx"; -var viveTriggerModelURL = "meshes/controller/vive_trigger.fbx"; - -VIVE_CONTROLLER_CONFIGURATION_LEFT = { - name: "Vive", - controllers: [ - { - modelURL: viveModelURL, - jointIndex: MyAvatar.getJointIndex("_CAMERA_RELATIVE_CONTROLLER_LEFTHAND"), - naturalPosition: viveNaturalPosition, - rotation: leftBaseRotation, - position: Vec3.multiplyQbyV(Quat.fromPitchYawRollDegrees(0, 0, 45), leftBasePosition), - - dimensions: viveNaturalDimensions, - - parts: { - // DISABLED FOR NOW - /* - tips: { - type: "static", - modelURL: viveTipsModelURL, - naturalPosition: {"x":-0.004377640783786774,"y":-0.034371938556432724,"z":0.06769277155399323}, - naturalDimensions: {x: 0.191437, y: 0.094095, z: 0.085656}, - - textureName: "Tex.Blank", - defaultTextureLayer: "blank", - textureLayers: { - blank: { - defaultTextureURL: TIP_TEXTURE_BASE_URL + "/Blank.png" - }, - trigger: { - defaultTextureURL: TIP_TEXTURE_BASE_URL + "/Trigger.png" - }, - arrows: { - defaultTextureURL: TIP_TEXTURE_BASE_URL + "/Rotate.png" - }, - grip: { - defaultTextureURL: TIP_TEXTURE_BASE_URL + "/Grip.png" - }, - teleport: { - defaultTextureURL: TIP_TEXTURE_BASE_URL + "/Teleport.png" - } - } - }, - */ - - // The touchpad type draws a dot indicating the current touch/thumb position - // and swaps in textures based on the thumb position. - touchpad: { - type: "touchpad", - modelURL: BASE_URL + "meshes/controller/vive_trackpad.fbx", - visibleInput: "Vive.RSTouch", - xInput: "Vive.LX", - yInput: "Vive.LY", - naturalPosition: {"x":0,"y":0.000979491975158453,"z":0.04872849956154823}, - naturalDimensions: {x: 0.042824, y: 0.012537, z: 0.043115}, - minValue: 0.0, - maxValue: 1.0, - minPosition: { x: -0.035, y: 0.004, z: -0.005 }, - maxPosition: { x: -0.035, y: 0.004, z: -0.005 }, - disable_textureName: "Tex.touchpad-blank", - - disable_defaultTextureLayer: "blank", - disable_textureLayers: { - blank: { - defaultTextureURL: BASE_URL + "meshes/controller/vive_trackpad.fbx/Touchpad.fbm/touchpad-blank.jpg" - }, - teleport: { - defaultTextureURL: BASE_URL + "meshes/controller/vive_trackpad.fbx/Touchpad.fbm/touchpad-teleport-active-LG.jpg" - }, - arrows: { - defaultTextureURL: BASE_URL + "meshes/controller/vive_trackpad.fbx/Touchpad.fbm/touchpad-look-arrows.jpg" - } - } - }, - - trigger: { - type: "rotational", - modelURL: BASE_URL + "meshes/controller/vive_trigger.fbx", - input: Controller.Standard.LT, - naturalPosition: {"x":0.000004500150680541992,"y":-0.027690507471561432,"z":0.04830199480056763}, - naturalDimensions: {x: 0.019105, y: 0.022189, z: 0.01909}, - origin: { x: 0, y: -0.015, z: -0.00 }, - minValue: 0.0, - maxValue: 1.0, - axis: { x: -1, y: 0, z: 0 }, - maxAngle: 25, - - textureName: "Tex.black-trigger", - defaultTextureLayer: "normal", - textureLayers: { - normal: { - defaultTextureURL: BASE_URL + viveTriggerModelURL + "/Trigger.fbm/black.jpg" - }, - highlight: { - defaultTextureURL: BASE_URL + viveTriggerModelURL + "/Trigger.fbm/yellow.jpg" - } - } - }, - - l_grip: { - type: "static", - modelURL: BASE_URL + "meshes/controller/vive_l_grip.fbx", - naturalPosition: {"x":-0.01720449887216091,"y":-0.014324013143777847,"z":0.08714400231838226}, - naturalDimensions: {x: 0.010094, y: 0.015064, z: 0.029552} - }, - - r_grip: { - type: "static", - modelURL: BASE_URL + "meshes/controller/vive_r_grip.fbx", - naturalPosition: {"x":0.01720449887216091,"y":-0.014324013143777847,"z":0.08714400231838226}, - naturalDimensions: {x: 0.010083, y: 0.015064, z: 0.029552} - }, - - sys_button: { - type: "static", - modelURL: BASE_URL + "meshes/controller/vive_sys_button.fbx", - naturalPosition: {"x":0,"y":0.0020399854984134436,"z":0.08825899660587311}, - naturalDimensions: {x: 0.009986, y: 0.004282, z: 0.010264} - }, - - button: { - type: "static", - modelURL: BASE_URL + "meshes/controller/vive_button.fbx", - naturalPosition: {"x":0,"y":0.005480996798723936,"z":0.019918499514460564}, - naturalDimensions: {x: 0.009986, y: 0.004496, z: 0.010121} - }, - button2: { - type: "static", - modelURL: BASE_URL + "meshes/controller/vive_button.fbx", - naturalPosition: {"x":0,"y":0.005480996798723936,"z":0.019918499514460564}, - naturalDimensions: {x: 0.009986, y: 0.004496, z: 0.010121} - } - } - } - ] -}; - - -VIVE_CONTROLLER_CONFIGURATION_RIGHT = { - name: "Vive Right", - controllers: [ - { - modelURL: viveModelURL, - jointIndex: MyAvatar.getJointIndex("_CAMERA_RELATIVE_CONTROLLER_RIGHTHAND"), - rotation: rightBaseRotation, - position: Vec3.multiplyQbyV(Quat.fromPitchYawRollDegrees(0, 0, -45), rightBasePosition), - - dimensions: viveNaturalDimensions, - - naturalPosition: { - x: 0, - y: -0.034076502197422087, - z: 0.06380049744620919 - }, - - parts: { - // DISABLED FOR NOW - /* - tips: { - type: "static", - modelURL: viveTipsModelURL, - naturalPosition: {"x":-0.004377640783786774,"y":-0.034371938556432724,"z":0.06769277155399323}, - naturalDimensions: {x: 0.191437, y: 0.094095, z: 0.085656}, - - textureName: "Tex.Blank", - - defaultTextureLayer: "blank", - textureLayers: { - blank: { - defaultTextureURL: TIP_TEXTURE_BASE_URL + "/Blank.png" - }, - trigger: { - defaultTextureURL: TIP_TEXTURE_BASE_URL + "/Trigger.png" - }, - arrows: { - defaultTextureURL: TIP_TEXTURE_BASE_URL + "/Rotate.png" - }, - grip: { - defaultTextureURL: TIP_TEXTURE_BASE_URL + "/Grip.png" - }, - teleport: { - defaultTextureURL: TIP_TEXTURE_BASE_URL + "/Teleport.png" - } - } - }, - */ - - // The touchpad type draws a dot indicating the current touch/thumb position - // and swaps in textures based on the thumb position. - touchpad: { - type: "touchpad", - modelURL: BASE_URL + "meshes/controller/vive_trackpad.fbx", - visibleInput: "Vive.RSTouch", - xInput: "Vive.RX", - yInput: "Vive.RY", - naturalPosition: { x: 0, y: 0.000979491975158453, z: 0.04872849956154823 }, - naturalDimensions: {x: 0.042824, y: 0.012537, z: 0.043115}, - minValue: 0.0, - maxValue: 1.0, - minPosition: { x: -0.035, y: 0.004, z: -0.005 }, - maxPosition: { x: -0.035, y: 0.004, z: -0.005 }, - disable_textureName: "Tex.touchpad-blank", - - disable_defaultTextureLayer: "blank", - disable_textureLayers: { - blank: { - defaultTextureURL: BASE_URL + "meshes/controller/vive_trackpad.fbx/Touchpad.fbm/touchpad-blank.jpg" - }, - teleport: { - defaultTextureURL: BASE_URL + "meshes/controller/vive_trackpad.fbx/Touchpad.fbm/touchpad-teleport-active-LG.jpg" - }, - arrows: { - defaultTextureURL: BASE_URL + "meshes/controller/vive_trackpad.fbx/Touchpad.fbm/touchpad-look-arrows-active.jpg" - } - } - }, - - trigger: { - type: "rotational", - modelURL: BASE_URL + "meshes/controller/vive_trigger.fbx", - input: Controller.Standard.RT, - naturalPosition: {"x":0.000004500150680541992,"y":-0.027690507471561432,"z":0.04830199480056763}, - naturalDimensions: {x: 0.019105, y: 0.022189, z: 0.01909}, - origin: { x: 0, y: -0.015, z: -0.00 }, - minValue: 0.0, - maxValue: 1.0, - axis: { x: -1, y: 0, z: 0 }, - maxAngle: 25, - - textureName: "Tex.black-trigger", - defaultTextureLayer: "normal", - textureLayers: { - normal: { - defaultTextureURL: BASE_URL + viveTriggerModelURL + "/Trigger.fbm/black.jpg" - }, - highlight: { - defaultTextureURL: BASE_URL + viveTriggerModelURL + "/Trigger.fbm/yellow.jpg" - } - } - }, - - l_grip: { - type: "static", - modelURL: BASE_URL + "meshes/controller/vive_l_grip.fbx", - naturalPosition: {"x":-0.01720449887216091,"y":-0.014324013143777847,"z":0.08714400231838226}, - naturalDimensions: {x: 0.010094, y: 0.015064, z: 0.029552} - }, - - r_grip: { - type: "static", - modelURL: BASE_URL + "meshes/controller/vive_r_grip.fbx", - naturalPosition: {"x":0.01720449887216091,"y":-0.014324013143777847,"z":0.08714400231838226}, - naturalDimensions: {x: 0.010083, y: 0.015064, z: 0.029552} - }, - - sys_button: { - type: "static", - modelURL: BASE_URL + "meshes/controller/vive_sys_button.fbx", - naturalPosition: {"x":0,"y":0.0020399854984134436,"z":0.08825899660587311}, - naturalDimensions: {x: 0.009986, y: 0.004282, z: 0.010264} - }, - - button: { - type: "static", - modelURL: BASE_URL + "meshes/controller/vive_button.fbx", - naturalPosition: {"x":0,"y":0.005480996798723936,"z":0.019918499514460564}, - naturalDimensions: {x: 0.009986, y: 0.004496, z: 0.010121} - }, - button2: { - type: "static", - modelURL: BASE_URL + "meshes/controller/vive_button.fbx", - naturalPosition: {"x":0,"y":0.005480996798723936,"z":0.019918499514460564}, - naturalDimensions: {x: 0.009986, y: 0.004496, z: 0.010121} - } - } - } - ] -}; diff --git a/scripts/simplifiedUI/system/create/Edit.qml b/scripts/simplifiedUI/system/create/Edit.qml deleted file mode 100644 index ca18388def..0000000000 --- a/scripts/simplifiedUI/system/create/Edit.qml +++ /dev/null @@ -1,60 +0,0 @@ -import QtQuick 2.7 -import QtQuick.Controls 2.3 - -StackView { - id: editRoot - objectName: "stack" - - signal sendToScript(var message); - - topPadding: 40 - leftPadding: 0 - rightPadding: 0 - bottomPadding: 0 - - property var itemProperties: {"y": editRoot.topPadding, - "width": editRoot.availableWidth, - "height": editRoot.availableHeight } - Component.onCompleted: { - tab.currentIndex = 0 - } - - background: Rectangle { - color: "#404040" //default background color - EditTabView { - id: tab - anchors.fill: parent - currentIndex: -1 - onCurrentIndexChanged: { - editRoot.replace(null, tab.itemAt(currentIndex).visualItem, - itemProperties, - StackView.Immediate) - } - } - } - - function pushSource(path) { - var item = Qt.createComponent(Qt.resolvedUrl("../../" + path)); - editRoot.push(item, itemProperties, - StackView.Immediate); - editRoot.currentItem.sendToScript.connect(editRoot.sendToScript); - } - - function popSource() { - editRoot.pop(StackView.Immediate); - } - - // Passes script messages to the item on the top of the stack - function fromScript(message) { - var currentItem = editRoot.currentItem; - if (currentItem && currentItem.fromScript) - currentItem.fromScript(message); - } - - Component.onDestruction: { - if (KeyboardScriptingInterface.raised) { - KeyboardScriptingInterface.raised = false; - } - } -} - diff --git a/scripts/simplifiedUI/system/create/EditEntityList.qml b/scripts/simplifiedUI/system/create/EditEntityList.qml deleted file mode 100644 index 94935c7bb5..0000000000 --- a/scripts/simplifiedUI/system/create/EditEntityList.qml +++ /dev/null @@ -1,16 +0,0 @@ -import QtQuick 2.7 -import QtQuick.Controls 2.2 -import QtWebChannel 1.0 -import controls 1.0 -import hifi.toolbars 1.0 -import QtGraphicalEffects 1.0 -import controlsUit 1.0 as HifiControls -import stylesUit 1.0 - - -WebView { - id: entityListToolWebView - url: Paths.defaultScripts + "/system/html/entityList.html" - enabled: true - blurOnCtrlShift: false -} diff --git a/scripts/simplifiedUI/system/create/EditTabButton.qml b/scripts/simplifiedUI/system/create/EditTabButton.qml deleted file mode 100644 index 5fc4341eb8..0000000000 --- a/scripts/simplifiedUI/system/create/EditTabButton.qml +++ /dev/null @@ -1,56 +0,0 @@ -// -// EditTabButton.qml -// qml/hifi/tablet -// -// Created by Vlad Stelmahovsky on 8/16/2017 -// Copyright 2017 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -import QtQuick 2.7 -import QtQuick.Controls 2.2 -import controlsUit 1.0 as HifiControls -import stylesUit 1.0 - -TabButton { - id: control - property alias title: control.text - property alias active: control.checkable - height: 40 - padding: 0 - spacing: 0 - HifiConstants { id: hifi; } - - contentItem: Text { - id: text - text: control.text - font.pixelSize: 14 - font.bold: true - color: "white" - horizontalAlignment: Text.AlignHCenter - verticalAlignment: Text.AlignVCenter - fontSizeMode: Text.HorizontalFit - property string glyphtext: "" - HiFiGlyphs { - anchors.centerIn: parent - size: 30 - color: "#ffffff" - text: text.glyphtext - } - Component.onCompleted: { - if (control.text === "P") { - text.text = " "; - text.glyphtext = "\ue004"; - } - } - } - - background: Rectangle { - color: control.checked ? "#404040" :"black" - implicitWidth: control.contentItem.width + 42 > text.paintedWidth ? control.contentItem.width + 42 : - text.paintedWidth + 10 - implicitHeight: 40 - } -} diff --git a/scripts/simplifiedUI/system/create/EditTabView.qml b/scripts/simplifiedUI/system/create/EditTabView.qml deleted file mode 100644 index 7e8789487c..0000000000 --- a/scripts/simplifiedUI/system/create/EditTabView.qml +++ /dev/null @@ -1,312 +0,0 @@ -import QtQuick 2.7 -import QtQuick.Controls 2.2 -import QtWebChannel 1.0 -import controls 1.0 -import hifi.toolbars 1.0 -import QtGraphicalEffects 1.0 -import controlsUit 1.0 as HifiControls -import stylesUit 1.0 - -TabBar { - id: editTabView - width: parent.width - contentWidth: parent.width - padding: 0 - spacing: 0 - - readonly property HifiConstants hifi: HifiConstants {} - - EditTabButton { - title: "CREATE" - active: true - enabled: true - property string originalUrl: "" - - property Component visualItem: Component { - - Rectangle { - color: "#404040" - id: container - - Flickable { - height: parent.height - width: parent.width - clip: true - - contentHeight: createEntitiesFlow.height + importButton.height + assetServerButton.height + - header.anchors.topMargin + createEntitiesFlow.anchors.topMargin + - assetServerButton.anchors.topMargin + importButton.anchors.topMargin + - header.paintedHeight - - contentWidth: width - - ScrollBar.vertical : ScrollBar { - visible: parent.contentHeight > parent.height - width: 20 - background: Rectangle { - color: hifi.colors.tableScrollBackgroundDark - } - } - - Text { - id: header - color: "#ffffff" - text: "Choose an Entity Type to Create:" - font.pixelSize: 14 - font.bold: true - anchors.top: parent.top - anchors.topMargin: 28 - anchors.left: parent.left - anchors.leftMargin: 28 - } - - Flow { - id: createEntitiesFlow - spacing: 35 - anchors.right: parent.right - anchors.rightMargin: 55 - anchors.left: parent.left - anchors.leftMargin: 55 - anchors.top: parent.top - anchors.topMargin: 70 - - - NewEntityButton { - icon: "create-icons/94-model-01.svg" - text: "MODEL" - onClicked: { - editRoot.sendToScript({ - method: "newEntityButtonClicked", - params: { buttonName: "newModelButton" } - }); - editTabView.currentIndex = 2 - } - } - - NewEntityButton { - icon: "create-icons/21-cube-01.svg" - text: "SHAPE" - onClicked: { - editRoot.sendToScript({ - method: "newEntityButtonClicked", - params: { buttonName: "newShapeButton" } - }); - editTabView.currentIndex = 2 - } - } - - NewEntityButton { - icon: "create-icons/24-light-01.svg" - text: "LIGHT" - onClicked: { - editRoot.sendToScript({ - method: "newEntityButtonClicked", - params: { buttonName: "newLightButton" } - }); - editTabView.currentIndex = 2 - } - } - - NewEntityButton { - icon: "create-icons/20-text-01.svg" - text: "TEXT" - onClicked: { - editRoot.sendToScript({ - method: "newEntityButtonClicked", - params: { buttonName: "newTextButton" } - }); - editTabView.currentIndex = 2 - } - } - - NewEntityButton { - icon: "create-icons/image.svg" - text: "IMAGE" - onClicked: { - editRoot.sendToScript({ - method: "newEntityButtonClicked", - params: { buttonName: "newImageButton" } - }); - editTabView.currentIndex = 2 - } - } - - NewEntityButton { - icon: "create-icons/25-web-1-01.svg" - text: "WEB" - onClicked: { - editRoot.sendToScript({ - method: "newEntityButtonClicked", - params: { buttonName: "newWebButton" } - }); - editTabView.currentIndex = 2 - } - } - - NewEntityButton { - icon: "create-icons/23-zone-01.svg" - text: "ZONE" - onClicked: { - editRoot.sendToScript({ - method: "newEntityButtonClicked", - params: { buttonName: "newZoneButton" } - }); - editTabView.currentIndex = 2 - } - } - - NewEntityButton { - icon: "create-icons/90-particles-01.svg" - text: "PARTICLE" - onClicked: { - editRoot.sendToScript({ - method: "newEntityButtonClicked", - params: { buttonName: "newParticleButton" } - }); - editTabView.currentIndex = 2 - } - } - - NewEntityButton { - icon: "create-icons/126-material-01.svg" - text: "MATERIAL" - onClicked: { - editRoot.sendToScript({ - method: "newEntityButtonClicked", - params: { buttonName: "newMaterialButton" } - }); - editTabView.currentIndex = 2 - } - } - } - - HifiControls.Button { - id: assetServerButton - text: "Open This Domain's Asset Server" - color: hifi.buttons.black - colorScheme: hifi.colorSchemes.dark - anchors.right: parent.right - anchors.rightMargin: 55 - anchors.left: parent.left - anchors.leftMargin: 55 - anchors.top: createEntitiesFlow.bottom - anchors.topMargin: 35 - onClicked: { - editRoot.sendToScript({ - method: "newEntityButtonClicked", - params: { buttonName: "openAssetBrowserButton" } - }); - } - } - - HifiControls.Button { - id: importButton - text: "Import Entities (.json)" - color: hifi.buttons.black - colorScheme: hifi.colorSchemes.dark - anchors.right: parent.right - anchors.rightMargin: 55 - anchors.left: parent.left - anchors.leftMargin: 55 - anchors.top: assetServerButton.bottom - anchors.topMargin: 20 - onClicked: { - editRoot.sendToScript({ - method: "newEntityButtonClicked", - params: { buttonName: "importEntitiesButton" } - }); - } - } - } - } // Flickable - } - } - - EditTabButton { - title: "LIST" - active: true - enabled: true - property string originalUrl: "" - - property Component visualItem: Component { - WebView { - id: entityListToolWebView - url: Paths.defaultScripts + "/system/html/entityList.html" - enabled: true - blurOnCtrlShift: false - } - } - } - - EditTabButton { - title: "PROPERTIES" - active: true - enabled: true - property string originalUrl: "" - - property Component visualItem: Component { - WebView { - id: entityPropertiesWebView - url: Paths.defaultScripts + "/system/html/entityProperties.html" - enabled: true - blurOnCtrlShift: false - } - } - } - - EditTabButton { - title: "GRID" - active: true - enabled: true - property string originalUrl: "" - - property Component visualItem: Component { - WebView { - id: gridControlsWebView - url: Paths.defaultScripts + "/system/html/gridControls.html" - enabled: true - blurOnCtrlShift: false - } - } - } - - function fromScript(message) { - switch (message.method) { - case 'selectTab': - selectTab(message.params.id); - break; - default: - console.warn('EditTabView.qml: Unrecognized message'); - } - } - - // Changes the current tab based on tab index or title as input - function selectTab(id) { - if (typeof id === 'number') { - if (id >= 0 && id <= 4) { - editTabView.currentIndex = id; - } else { - console.warn('Attempt to switch to invalid tab:', id); - } - } else if (typeof id === 'string'){ - switch (id.toLowerCase()) { - case 'create': - editTabView.currentIndex = 0; - break; - case 'list': - editTabView.currentIndex = 1; - break; - case 'properties': - editTabView.currentIndex = 2; - break; - case 'grid': - editTabView.currentIndex = 3; - break; - default: - console.warn('Attempt to switch to invalid tab:', id); - } - } else { - console.warn('Attempt to switch tabs with invalid input:', JSON.stringify(id)); - } - } -} diff --git a/scripts/simplifiedUI/system/create/EditTools.qml b/scripts/simplifiedUI/system/create/EditTools.qml deleted file mode 100644 index 468935b287..0000000000 --- a/scripts/simplifiedUI/system/create/EditTools.qml +++ /dev/null @@ -1,59 +0,0 @@ -import QtQuick 2.7 -import QtQuick.Controls 2.3 - -// FIXME pretty non-DRY code, should figure out a way to optionally hide one tab from the tab view, keep in sync with Edit.qml -StackView { - id: editRoot - objectName: "stack" - - signal sendToScript(var message); - - topPadding: 40 - leftPadding: 0 - rightPadding: 0 - bottomPadding: 0 - - anchors.fill: parent - - property var itemProperties: {"y": editRoot.topPadding, - "width": editRoot.availableWidth, - "height": editRoot.availableHeight } - Component.onCompleted: { - tab.currentIndex = 0 - } - - background: Rectangle { - color: "#404040" //default background color - EditToolsTabView { - id: tab - anchors.fill: parent - currentIndex: -1 - onCurrentIndexChanged: { - editRoot.replace(null, tab.itemAt(currentIndex).visualItem, - itemProperties, - StackView.Immediate) - } - } - } - - function pushSource(path) { - var item = Qt.createComponent(Qt.resolvedUrl(path)); - editRoot.push(item, itemProperties, - StackView.Immediate); - editRoot.currentItem.sendToScript.connect(editRoot.sendToScript); - } - - function popSource() { - editRoot.pop(StackView.Immediate); - } - - // Passes script messages to the item on the top of the stack - function fromScript(message) { - var currentItem = editRoot.currentItem; - if (currentItem && currentItem.fromScript) { - currentItem.fromScript(message); - } else if (tab.fromScript) { - tab.fromScript(message); - } - } -} diff --git a/scripts/simplifiedUI/system/create/EditToolsTabView.qml b/scripts/simplifiedUI/system/create/EditToolsTabView.qml deleted file mode 100644 index a333acc586..0000000000 --- a/scripts/simplifiedUI/system/create/EditToolsTabView.qml +++ /dev/null @@ -1,299 +0,0 @@ -import QtQuick 2.7 -import QtQuick.Controls 2.2 -import QtWebChannel 1.0 -import controls 1.0 -import hifi.toolbars 1.0 -import QtGraphicalEffects 1.0 -import controlsUit 1.0 as HifiControls -import stylesUit 1.0 - -TabBar { - id: editTabView - width: parent.width - contentWidth: parent.width - padding: 0 - spacing: 0 - - readonly property QtObject tabIndex: QtObject { - readonly property int create: 0 - readonly property int properties: 1 - readonly property int grid: 2 - } - - readonly property HifiConstants hifi: HifiConstants {} - - EditTabButton { - title: "CREATE" - active: true - enabled: true - property string originalUrl: "" - - property Component visualItem: Component { - - Rectangle { - color: "#404040" - id: container - - Flickable { - height: parent.height - width: parent.width - clip: true - - contentHeight: createEntitiesFlow.height + importButton.height + assetServerButton.height + - header.anchors.topMargin + createEntitiesFlow.anchors.topMargin + - assetServerButton.anchors.topMargin + importButton.anchors.topMargin + - header.paintedHeight - - contentWidth: width - - ScrollBar.vertical : ScrollBar { - visible: parent.contentHeight > parent.height - width: 20 - background: Rectangle { - color: hifi.colors.tableScrollBackgroundDark - } - } - - Text { - id: header - color: "#ffffff" - text: "Choose an Entity Type to Create:" - font.pixelSize: 14 - font.bold: true - anchors.top: parent.top - anchors.topMargin: 28 - anchors.left: parent.left - anchors.leftMargin: 28 - } - - Flow { - id: createEntitiesFlow - spacing: 35 - anchors.right: parent.right - anchors.rightMargin: 55 - anchors.left: parent.left - anchors.leftMargin: 55 - anchors.top: parent.top - anchors.topMargin: 70 - - - NewEntityButton { - icon: "create-icons/94-model-01.svg" - text: "MODEL" - onClicked: { - editRoot.sendToScript({ - method: "newEntityButtonClicked", - params: { buttonName: "newModelButton" } - }); - editTabView.currentIndex = tabIndex.properties - } - } - - NewEntityButton { - icon: "create-icons/21-cube-01.svg" - text: "SHAPE" - onClicked: { - editRoot.sendToScript({ - method: "newEntityButtonClicked", - params: { buttonName: "newShapeButton" } - }); - editTabView.currentIndex = tabIndex.properties - } - } - - NewEntityButton { - icon: "create-icons/24-light-01.svg" - text: "LIGHT" - onClicked: { - editRoot.sendToScript({ - method: "newEntityButtonClicked", - params: { buttonName: "newLightButton" } - }); - editTabView.currentIndex = tabIndex.properties - } - } - - NewEntityButton { - icon: "create-icons/20-text-01.svg" - text: "TEXT" - onClicked: { - editRoot.sendToScript({ - method: "newEntityButtonClicked", - params: { buttonName: "newTextButton" } - }); - editTabView.currentIndex = tabIndex.properties - } - } - - NewEntityButton { - icon: "create-icons/image.svg" - text: "IMAGE" - onClicked: { - editRoot.sendToScript({ - method: "newEntityButtonClicked", - params: { buttonName: "newImageButton" } - }); - editTabView.currentIndex = tabIndex.properties - } - } - - NewEntityButton { - icon: "create-icons/25-web-1-01.svg" - text: "WEB" - onClicked: { - editRoot.sendToScript({ - method: "newEntityButtonClicked", - params: { buttonName: "newWebButton" } - }); - editTabView.currentIndex = tabIndex.properties - } - } - - NewEntityButton { - icon: "create-icons/23-zone-01.svg" - text: "ZONE" - onClicked: { - editRoot.sendToScript({ - method: "newEntityButtonClicked", - params: { buttonName: "newZoneButton" } - }); - editTabView.currentIndex = tabIndex.properties - } - } - - NewEntityButton { - icon: "create-icons/90-particles-01.svg" - text: "PARTICLE" - onClicked: { - editRoot.sendToScript({ - method: "newEntityButtonClicked", - params: { buttonName: "newParticleButton" } - }); - editTabView.currentIndex = tabIndex.properties - } - } - - NewEntityButton { - icon: "create-icons/126-material-01.svg" - text: "MATERIAL" - onClicked: { - editRoot.sendToScript({ - method: "newEntityButtonClicked", - params: { buttonName: "newMaterialButton" } - }); - editTabView.currentIndex = tabIndex.properties - } - } - } - - HifiControls.Button { - id: assetServerButton - text: "Open This Domain's Asset Server" - color: hifi.buttons.black - colorScheme: hifi.colorSchemes.dark - anchors.right: parent.right - anchors.rightMargin: 55 - anchors.left: parent.left - anchors.leftMargin: 55 - anchors.top: createEntitiesFlow.bottom - anchors.topMargin: 35 - onClicked: { - editRoot.sendToScript({ - method: "newEntityButtonClicked", - params: { buttonName: "openAssetBrowserButton" } - }); - } - } - - HifiControls.Button { - id: importButton - text: "Import Entities (.json)" - color: hifi.buttons.black - colorScheme: hifi.colorSchemes.dark - anchors.right: parent.right - anchors.rightMargin: 55 - anchors.left: parent.left - anchors.leftMargin: 55 - anchors.top: assetServerButton.bottom - anchors.topMargin: 20 - onClicked: { - editRoot.sendToScript({ - method: "newEntityButtonClicked", - params: { buttonName: "importEntitiesButton" } - }); - } - } - } - } // Flickable - } - } - - EditTabButton { - title: "PROPERTIES" - active: true - enabled: true - property string originalUrl: "" - - property Component visualItem: Component { - WebView { - id: entityPropertiesWebView - url: Paths.defaultScripts + "/system/html/entityProperties.html" - enabled: true - blurOnCtrlShift: false - } - } - } - - EditTabButton { - title: "GRID" - active: true - enabled: true - property string originalUrl: "" - - property Component visualItem: Component { - WebView { - id: gridControlsWebView - url: Paths.defaultScripts + "/system/html/gridControls.html" - enabled: true - blurOnCtrlShift: false - } - } - } - - function fromScript(message) { - switch (message.method) { - case 'selectTab': - selectTab(message.params.id); - break; - default: - console.warn('EditToolsTabView.qml: Unrecognized message'); - } - } - - // Changes the current tab based on tab index or title as input - function selectTab(id) { - if (typeof id === 'number') { - if (id >= tabIndex.create && id <= tabIndex.grid) { - editTabView.currentIndex = id; - } else { - console.warn('Attempt to switch to invalid tab:', id); - } - } else if (typeof id === 'string'){ - switch (id.toLowerCase()) { - case 'create': - editTabView.currentIndex = tabIndex.create; - break; - case 'properties': - editTabView.currentIndex = tabIndex.properties; - break; - case 'grid': - editTabView.currentIndex = tabIndex.grid; - break; - default: - console.warn('Attempt to switch to invalid tab:', id); - } - } else { - console.warn('Attempt to switch tabs with invalid input:', JSON.stringify(id)); - } - } -} diff --git a/scripts/simplifiedUI/system/create/EntityList.qml b/scripts/simplifiedUI/system/create/EntityList.qml deleted file mode 100644 index 2f8a8863be..0000000000 --- a/scripts/simplifiedUI/system/create/EntityList.qml +++ /dev/null @@ -1,6 +0,0 @@ -WebView { - id: entityListToolWebView - url: Paths.defaultScripts + "/system/html/entityList.html" - enabled: true - blurOnCtrlShift: false -} diff --git a/scripts/simplifiedUI/system/create/NewEntityButton.qml b/scripts/simplifiedUI/system/create/NewEntityButton.qml deleted file mode 100644 index 9c210ac95a..0000000000 --- a/scripts/simplifiedUI/system/create/NewEntityButton.qml +++ /dev/null @@ -1,155 +0,0 @@ -import QtQuick 2.0 -import QtGraphicalEffects 1.0 -import TabletScriptingInterface 1.0 - -Item { - id: newEntityButton - property var uuid; - property string text: "ENTITY" - property string icon: Path.resources + "icons/edit-icon.svg" - property string activeText: newEntityButton.text - property string activeIcon: newEntityButton.icon - property bool isActive: false - property bool inDebugMode: false - property bool isEntered: false - property double sortOrder: 100 - property int stableOrder: 0 - property var tabletRoot; - width: 100 - height: 100 - - signal clicked() - - function changeProperty(key, value) { - tabletButton[key] = value; - } - - onIsActiveChanged: { - if (tabletButton.isEntered) { - tabletButton.state = (tabletButton.isActive) ? "hover active state" : "hover sate"; - } else { - tabletButton.state = (tabletButton.isActive) ? "active state" : "base sate"; - } - } - - Rectangle { - id: buttonBg - color: "#1c1c1c" - opacity: 1 - radius: 8 - anchors.right: parent.right - anchors.rightMargin: 0 - anchors.left: parent.left - anchors.leftMargin: 0 - anchors.bottom: parent.bottom - anchors.bottomMargin: 0 - anchors.top: parent.top - anchors.topMargin: 0 - } - - Rectangle { - id: buttonOutline - color: "#00000000" - opacity: 0 - radius: 8 - z: 1 - border.width: 2 - border.color: "#ffffff" - anchors.right: parent.right - anchors.rightMargin: 0 - anchors.left: parent.left - anchors.leftMargin: 0 - anchors.bottom: parent.bottom - anchors.bottomMargin: 0 - anchors.top: parent.top - anchors.topMargin: 0 - } - - DropShadow { - id: glow - visible: false - anchors.fill: parent - horizontalOffset: 0 - verticalOffset: 0 - color: "#ffffff" - radius: 20 - z: -1 - samples: 41 - source: buttonOutline - } - - - Image { - id: icon - width: 50 - height: 50 - visible: false - anchors.bottom: text.top - anchors.bottomMargin: 5 - anchors.horizontalCenter: parent.horizontalCenter - fillMode: Image.Stretch - source: newEntityButton.icon - } - - ColorOverlay { - id: iconColorOverlay - anchors.fill: icon - source: icon - color: "#ffffff" - } - - Text { - id: text - color: "#ffffff" - text: newEntityButton.text - font.bold: true - font.pixelSize: 16 - anchors.bottom: parent.bottom - anchors.bottomMargin: 12 - anchors.horizontalCenter: parent.horizontalCenter - horizontalAlignment: Text.AlignHCenter - } - - MouseArea { - anchors.fill: parent - hoverEnabled: true - enabled: true - onClicked: { - Tablet.playSound(TabletEnums.ButtonClick); - newEntityButton.clicked(); - } - onEntered: { - Tablet.playSound(TabletEnums.ButtonHover); - newEntityButton.state = "hover state"; - } - onExited: { - newEntityButton.state = "base state"; - } - } - - states: [ - State { - name: "hover state" - - PropertyChanges { - target: buttonOutline - opacity: 1 - } - - PropertyChanges { - target: glow - visible: true - } - }, - State { - name: "base state" - - PropertyChanges { - target: glow - visible: false - } - } - ] -} - - diff --git a/scripts/simplifiedUI/system/create/NewMaterialDialog.qml b/scripts/simplifiedUI/system/create/NewMaterialDialog.qml deleted file mode 100644 index 75570327e0..0000000000 --- a/scripts/simplifiedUI/system/create/NewMaterialDialog.qml +++ /dev/null @@ -1,178 +0,0 @@ -// -// NewMaterialDialog.qml -// qml/hifi -// -// Created by Sam Gondelman on 1/17/18 -// Copyright 2018 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -import QtQuick 2.7 -import QtQuick.Controls 2.2 -import QtQuick.Dialogs 1.2 as OriginalDialogs - -import stylesUit 1.0 -import controlsUit 1.0 -import dialogs 1.0 - -Rectangle { - id: newMaterialDialog - // width: parent.width - // height: parent.height - HifiConstants { id: hifi } - color: hifi.colors.baseGray; - signal sendToScript(var message); - property bool keyboardEnabled: false - property bool punctuationMode: false - property bool keyboardRasied: false - - function errorMessageBox(message) { - try { - return desktop.messageBox({ - icon: hifi.icons.warning, - defaultButton: OriginalDialogs.StandardButton.Ok, - title: "Error", - text: message - }); - } catch(e) { - Window.alert(message); - } - } - - Item { - id: column1 - anchors.rightMargin: 10 - anchors.leftMargin: 10 - anchors.bottomMargin: 10 - anchors.topMargin: 10 - anchors.top: parent.top - anchors.left: parent.left - anchors.right: parent.right - anchors.bottom: keyboard.top - - Text { - id: text1 - text: qsTr("Material URL") - color: "#ffffff" - font.pixelSize: 12 - } - - TextInput { - id: materialURL - height: 20 - text: qsTr("") - color: "white" - anchors.top: text1.bottom - anchors.topMargin: 5 - anchors.left: parent.left - anchors.leftMargin: 0 - anchors.right: parent.right - anchors.rightMargin: 0 - font.pixelSize: 12 - - onAccepted: { - newMaterialDialog.keyboardEnabled = false; - } - - MouseArea { - anchors.fill: parent - onClicked: { - newMaterialDialog.keyboardEnabled = HMD.active - parent.focus = true; - parent.forceActiveFocus(); - materialURL.cursorPosition = materialURL.positionAt(mouseX, mouseY, TextInput.CursorBetweenCharaters); - } - } - } - - Rectangle { - id: textInputBox - color: "white" - anchors.fill: materialURL - opacity: 0.1 - } - - Row { - id: row1 - height: 400 - spacing: 30 - anchors.top: materialURL.bottom - anchors.topMargin: 5 - anchors.left: parent.left - anchors.leftMargin: 0 - anchors.right: parent.right - anchors.rightMargin: 0 - - Column { - id: column3 - height: 400 - spacing: 10 - - /*Text { - id: text3 - text: qsTr("Material Mode") - color: "#ffffff" - font.pixelSize: 12 - } - - ComboBox { - id: materialMappingMode - property var materialArray: ["UV space material", - "3D projected material"] - - width: 200 - z: 100 - transformOrigin: Item.Center - model: materialArray - }*/ - - Row { - id: row3 - width: 200 - height: 400 - spacing: 5 - - anchors.horizontalCenter: column3.horizontalCenter - anchors.horizontalCenterOffset: 0 - - Button { - id: button1 - text: qsTr("Add") - z: -1 - onClicked: { - newMaterialDialog.sendToScript({ - method: "newMaterialDialogAdd", - params: { - textInput: materialURL.text, - //comboBox: materialMappingMode.currentIndex - } - }); - } - } - - Button { - id: button2 - z: -1 - text: qsTr("Cancel") - onClicked: { - newMaterialDialog.sendToScript({method: "newMaterialDialogCancel"}) - } - } - } - } - } - } - - Keyboard { - id: keyboard - raised: parent.keyboardEnabled - numeric: parent.punctuationMode - anchors { - bottom: parent.bottom - left: parent.left - right: parent.right - } - } -} diff --git a/scripts/simplifiedUI/system/create/NewMaterialWindow.qml b/scripts/simplifiedUI/system/create/NewMaterialWindow.qml deleted file mode 100644 index def816c36e..0000000000 --- a/scripts/simplifiedUI/system/create/NewMaterialWindow.qml +++ /dev/null @@ -1,20 +0,0 @@ -import QtQuick 2.7 -import QtQuick.Controls 2.2 - -StackView { - id: stackView - anchors.fill: parent - anchors.leftMargin: 10 - anchors.rightMargin: 10 - anchors.topMargin: 40 - - signal sendToScript(var message); - - NewMaterialDialog { - id: dialog - anchors.fill: parent - Component.onCompleted:{ - dialog.sendToScript.connect(stackView.sendToScript); - } - } -} diff --git a/scripts/simplifiedUI/system/create/NewModelDialog.qml b/scripts/simplifiedUI/system/create/NewModelDialog.qml deleted file mode 100644 index 1ded00d701..0000000000 --- a/scripts/simplifiedUI/system/create/NewModelDialog.qml +++ /dev/null @@ -1,258 +0,0 @@ -// -// NewModelDialog.qml -// qml/hifi -// -// Created by Seth Alves on 2017-2-10 -// Copyright 2017 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -import QtQuick 2.5 -import QtQuick.Dialogs 1.2 as OriginalDialogs - -import stylesUit 1.0 -import controlsUit 1.0 -import dialogs 1.0 - -Rectangle { - id: newModelDialog - // width: parent.width - // height: parent.height - HifiConstants { id: hifi } - color: hifi.colors.baseGray; - signal sendToScript(var message); - property bool keyboardEnabled: false - property bool keyboardRaised: false - property bool punctuationMode: false - property bool keyboardRasied: false - - function errorMessageBox(message) { - try { - return desktop.messageBox({ - icon: hifi.icons.warning, - defaultButton: OriginalDialogs.StandardButton.Ok, - title: "Error", - text: message - }); - } catch(e) { - Window.alert(message); - } - } - - Item { - id: column1 - anchors.rightMargin: 10 - anchors.leftMargin: 10 - anchors.bottomMargin: 10 - anchors.topMargin: 10 - anchors.top: parent.top - anchors.left: parent.left - anchors.right: parent.right - anchors.bottom: keyboard.top - - Text { - id: text1 - text: qsTr("Model URL") - color: "#ffffff" - font.pixelSize: 12 - } - - TextInput { - id: modelURL - height: 20 - text: qsTr("") - color: "white" - anchors.top: text1.bottom - anchors.topMargin: 5 - anchors.left: parent.left - anchors.leftMargin: 0 - anchors.right: parent.right - anchors.rightMargin: 0 - font.pixelSize: 12 - - onAccepted: { - newModelDialog.keyboardEnabled = false; - } - - onTextChanged : { - if (modelURL.text.length === 0){ - button1.enabled = false; - } else { - button1.enabled = true; - } - } - - MouseArea { - anchors.fill: parent - onClicked: { - newModelDialog.keyboardEnabled = HMD.active - parent.focus = true; - parent.forceActiveFocus(); - modelURL.cursorPosition = modelURL.positionAt(mouseX, mouseY, TextInput.CursorBetweenCharaters); - } - } - } - - Rectangle { - id: textInputBox - color: "white" - anchors.fill: modelURL - opacity: 0.1 - } - - Row { - id: row1 - height: 400 - spacing: 30 - anchors.top: modelURL.top - anchors.topMargin: 25 - anchors.left: parent.left - anchors.leftMargin: 0 - anchors.right: parent.right - anchors.rightMargin: 0 - - Column { - id: column2 - width: 200 - height: 600 - spacing: 10 - - CheckBox { - id: grabbable - text: qsTr("Grabbable") - } - - CheckBox { - id: dynamic - text: qsTr("Dynamic") - } - - Row { - id: row2 - width: 200 - height: 400 - spacing: 20 - - Image { - id: image1 - width: 30 - height: 30 - source: "qrc:/qtquickplugin/images/template_image.png" - } - - Text { - id: text2 - width: 160 - x: dynamic.width / 2 - color: "#ffffff" - text: qsTr("Models with automatic collisions set to 'Exact' cannot be dynamic, and should not be used as floors") - wrapMode: Text.WordWrap - font.pixelSize: 12 - } - } - } - - Column { - id: column3 - height: 400 - spacing: 10 - - Text { - id: text3 - text: qsTr("Automatic Collisions") - color: "#ffffff" - font.pixelSize: 12 - } - - ComboBox { - id: collisionType - - property int priorIndex: 0 - property string staticMeshCollisionText: "Exact - All polygons" - property var collisionArray: ["No Collision", - "Basic - Whole model", - "Good - Sub-meshes", - staticMeshCollisionText, - "Box", - "Sphere"] - - width: 200 - z: 100 - transformOrigin: Item.Center - model: collisionArray - - onCurrentIndexChanged: { - if (collisionArray[currentIndex] === staticMeshCollisionText) { - - if (dynamic.checked) { - currentIndex = priorIndex; - - errorMessageBox("Models with Automatic Collisions set to \"" - + staticMeshCollisionText + "\" cannot be dynamic."); - //--EARLY EXIT--( Can't have a static mesh model that's dynamic ) - return; - } - - dynamic.enabled = false; - } else { - dynamic.enabled = true; - } - - priorIndex = currentIndex; - } - } - - Row { - id: row3 - width: 200 - height: 400 - spacing: 5 - - anchors.horizontalCenter: column3.horizontalCenter - anchors.horizontalCenterOffset: -20 - - Button { - id: button1 - text: qsTr("Add") - z: -1 - enabled: false - onClicked: { - newModelDialog.sendToScript({ - method: "newModelDialogAdd", - params: { - url: modelURL.text, - dynamic: dynamic.checked, - collisionShapeIndex: collisionType.currentIndex, - grabbable: grabbable.checked - } - }); - } - } - - Button { - id: button2 - z: -1 - text: qsTr("Cancel") - onClicked: { - newModelDialog.sendToScript({method: "newModelDialogCancel"}) - } - } - } - } - } - } - - Keyboard { - id: keyboard - raised: parent.keyboardEnabled && parent.keyboardRaised - numeric: parent.punctuationMode - anchors { - bottom: parent.bottom - bottomMargin: 40 - left: parent.left - right: parent.right - } - } -} diff --git a/scripts/simplifiedUI/system/create/NewModelWindow.qml b/scripts/simplifiedUI/system/create/NewModelWindow.qml deleted file mode 100644 index 616a44ab7a..0000000000 --- a/scripts/simplifiedUI/system/create/NewModelWindow.qml +++ /dev/null @@ -1,20 +0,0 @@ -import QtQuick 2.7 -import QtQuick.Controls 2.2 - -StackView { - id: stackView - anchors.fill: parent - anchors.leftMargin: 10 - anchors.rightMargin: 10 - anchors.topMargin: 40 - - signal sendToScript(var message); - - NewModelDialog { - id: dialog - anchors.fill: parent - Component.onCompleted:{ - dialog.sendToScript.connect(stackView.sendToScript); - } - } -} diff --git a/scripts/simplifiedUI/system/create/create-icons/126-material-01.svg b/scripts/simplifiedUI/system/create/create-icons/126-material-01.svg deleted file mode 100644 index 9b6d92505f..0000000000 --- a/scripts/simplifiedUI/system/create/create-icons/126-material-01.svg +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - diff --git a/scripts/simplifiedUI/system/create/create-icons/20-text-01.svg b/scripts/simplifiedUI/system/create/create-icons/20-text-01.svg deleted file mode 100644 index 337f3b70e3..0000000000 --- a/scripts/simplifiedUI/system/create/create-icons/20-text-01.svg +++ /dev/null @@ -1,26 +0,0 @@ - - - - - - - - - - - - diff --git a/scripts/simplifiedUI/system/create/create-icons/21-cube-01.svg b/scripts/simplifiedUI/system/create/create-icons/21-cube-01.svg deleted file mode 100644 index 21a980ca35..0000000000 --- a/scripts/simplifiedUI/system/create/create-icons/21-cube-01.svg +++ /dev/null @@ -1,17 +0,0 @@ - - - - - - - - diff --git a/scripts/simplifiedUI/system/create/create-icons/22-sphere-01.svg b/scripts/simplifiedUI/system/create/create-icons/22-sphere-01.svg deleted file mode 100644 index 5080a16e78..0000000000 --- a/scripts/simplifiedUI/system/create/create-icons/22-sphere-01.svg +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - - - diff --git a/scripts/simplifiedUI/system/create/create-icons/23-zone-01.svg b/scripts/simplifiedUI/system/create/create-icons/23-zone-01.svg deleted file mode 100644 index 5428257893..0000000000 --- a/scripts/simplifiedUI/system/create/create-icons/23-zone-01.svg +++ /dev/null @@ -1,38 +0,0 @@ - - - - - - - - - - - - - - diff --git a/scripts/simplifiedUI/system/create/create-icons/24-light-01.svg b/scripts/simplifiedUI/system/create/create-icons/24-light-01.svg deleted file mode 100644 index 028ea22793..0000000000 --- a/scripts/simplifiedUI/system/create/create-icons/24-light-01.svg +++ /dev/null @@ -1,34 +0,0 @@ - - - - - - - - - - - - - - - - - diff --git a/scripts/simplifiedUI/system/create/create-icons/25-web-1-01.svg b/scripts/simplifiedUI/system/create/create-icons/25-web-1-01.svg deleted file mode 100644 index 4f0eccc11e..0000000000 --- a/scripts/simplifiedUI/system/create/create-icons/25-web-1-01.svg +++ /dev/null @@ -1,30 +0,0 @@ - - - - - - - - - - - - - diff --git a/scripts/simplifiedUI/system/create/create-icons/90-particles-01.svg b/scripts/simplifiedUI/system/create/create-icons/90-particles-01.svg deleted file mode 100644 index 5e0105d7cd..0000000000 --- a/scripts/simplifiedUI/system/create/create-icons/90-particles-01.svg +++ /dev/null @@ -1,29 +0,0 @@ - - - - - - - - - - - - - - - - diff --git a/scripts/simplifiedUI/system/create/create-icons/94-model-01.svg b/scripts/simplifiedUI/system/create/create-icons/94-model-01.svg deleted file mode 100644 index 5d8c4c5eca..0000000000 --- a/scripts/simplifiedUI/system/create/create-icons/94-model-01.svg +++ /dev/null @@ -1,20 +0,0 @@ - - - - - diff --git a/scripts/simplifiedUI/system/create/create-icons/image.svg b/scripts/simplifiedUI/system/create/create-icons/image.svg deleted file mode 100644 index 08a6c1aad2..0000000000 --- a/scripts/simplifiedUI/system/create/create-icons/image.svg +++ /dev/null @@ -1,23 +0,0 @@ - - - - - - - - - diff --git a/scripts/simplifiedUI/system/dialTone.js b/scripts/simplifiedUI/system/dialTone.js deleted file mode 100644 index 7c0a5b250d..0000000000 --- a/scripts/simplifiedUI/system/dialTone.js +++ /dev/null @@ -1,36 +0,0 @@ -"use strict"; - -// -// dialTone.js -// examples -// -// Created by Stephen Birarda on 06/08/15. -// Added disconnect HRS 6/11/15. -// Copyright 2015 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -(function() { // BEGIN LOCAL_SCOPE - -// setup the local sound we're going to use -var connectSound = SoundCache.getSound(Script.resolvePath("assets/sounds/hello.wav")); -var disconnectSound = SoundCache.getSound(Script.resolvePath("assets/sounds/goodbye.wav")); -var micMutedSound = SoundCache.getSound(Script.resolvePath("assets/sounds/goodbye.wav")); - -// setup the options needed for that sound -var soundOptions = { - localOnly: true -}; - -// play the sound locally once we get the first audio packet from a mixer -Audio.receivedFirstPacket.connect(function(){ - Audio.playSound(connectSound, soundOptions); -}); - -Audio.disconnected.connect(function(){ - Audio.playSound(disconnectSound, soundOptions); -}); - -}()); // END LOCAL_SCOPE diff --git a/scripts/simplifiedUI/system/directory.js b/scripts/simplifiedUI/system/directory.js deleted file mode 100644 index f84429ab95..0000000000 --- a/scripts/simplifiedUI/system/directory.js +++ /dev/null @@ -1,134 +0,0 @@ -// -// directory.js -// examples -// -// Created by David Rowe on 8 Jun 2015 -// Copyright 2015 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -Script.include([ - "libraries/toolBars.js", -]); - -var toolIconUrl = Script.resolvePath("assets/images/tools/"); - -var DIRECTORY_WINDOW_URL = Account.metaverseServerURL + "/directory"; -var directoryWindow = new OverlayWebWindow({ - title: 'Directory', - source: "about:blank", - width: 900, - height: 700, - visible: false -}); - -var toolHeight = 50; -var toolWidth = 50; -var TOOLBAR_MARGIN_Y = 0; - - -function showDirectory() { - directoryWindow.setURL(DIRECTORY_WINDOW_URL); - directoryWindow.setVisible(true); -} - -function hideDirectory() { - directoryWindow.setVisible(false); - directoryWindow.setURL("about:blank"); -} - -function toggleDirectory() { - if (directoryWindow.visible) { - hideDirectory(); - } else { - showDirectory(); - } -} - -var toolBar = (function() { - var that = {}, - toolBar, - browseDirectoryButton; - - function initialize() { - toolBar = new ToolBar(0, 0, ToolBar.HORIZONTAL, "highfidelity.directory.toolbar", function(windowDimensions, toolbar) { - return { - x: windowDimensions.x / 2, - y: windowDimensions.y - }; - }, { - x: -2 * toolWidth, - y: -TOOLBAR_MARGIN_Y - toolHeight - }); - browseDirectoryButton = toolBar.addTool({ - imageURL: toolIconUrl + "directory.svg", - subImage: { - x: 0, - y: Tool.IMAGE_WIDTH, - width: Tool.IMAGE_WIDTH, - height: Tool.IMAGE_HEIGHT - }, - width: toolWidth, - height: toolHeight, - alpha: 0.9, - visible: true - }); - - toolBar.showTool(browseDirectoryButton, true); - } - - var browseDirectoryButtonDown = false; - that.mousePressEvent = function(event) { - var clickedOverlay, - url, - file; - - if (!event.isLeftButton) { - // if another mouse button than left is pressed ignore it - return false; - } - - clickedOverlay = Overlays.getOverlayAtPoint({ - x: event.x, - y: event.y - }); - - - - if (browseDirectoryButton === toolBar.clicked(clickedOverlay)) { - toggleDirectory(); - return true; - } - - return false; - }; - - that.mouseReleaseEvent = function(event) { - var handled = false; - - - if (browseDirectoryButtonDown) { - var clickedOverlay = Overlays.getOverlayAtPoint({ - x: event.x, - y: event.y - }); - } - - newModelButtonDown = false; - browseDirectoryButtonDown = false; - - return handled; - } - - that.cleanup = function() { - toolBar.cleanup(); - }; - - initialize(); - return that; -}()); - -Controller.mousePressEvent.connect(toolBar.mousePressEvent) -Script.scriptEnding.connect(toolBar.cleanup); diff --git a/scripts/simplifiedUI/system/emote.js b/scripts/simplifiedUI/system/emote.js deleted file mode 100644 index 6dfd1ae1ef..0000000000 --- a/scripts/simplifiedUI/system/emote.js +++ /dev/null @@ -1,179 +0,0 @@ -"use strict"; - -// -// emote.js -// scripts/system/ -// -// Created by Brad Hefta-Gaub on 7 Jan 2018 -// Copyright 2018 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// -/* globals Script, Tablet */ -/* eslint indent: ["error", 4, { "outerIIFEBody": 0 }] */ - -(function() { // BEGIN LOCAL_SCOPE - - -var EMOTE_ANIMATIONS = - ['Crying', 'Surprised', 'Dancing', 'Cheering', 'Waving', 'Fall', 'Pointing', 'Clapping', 'Sit1', 'Sit2', 'Sit3', 'Love']; -var ANIMATIONS = Array(); - -var eventMappingName = "io.highfidelity.away"; // restoreAnimation on hand controller button events, too -var eventMapping = Controller.newMapping(eventMappingName); - -EMOTE_ANIMATIONS.forEach(function (name) { - var animationURL = Script.resolvePath("assets/animations/" + name + ".fbx"); - var resource = AnimationCache.prefetch(animationURL); - var animation = AnimationCache.getAnimation(animationURL); - ANIMATIONS[name] = { url: animationURL, animation: animation, resource: resource}; -}); - - -var EMOTE_APP_BASE = "html/EmoteApp.html"; -var EMOTE_APP_URL = Script.resolvePath(EMOTE_APP_BASE); -var EMOTE_LABEL = "EMOTE"; -var EMOTE_APP_SORT_ORDER = 12; -var FPS = 60; -var MSEC_PER_SEC = 1000; -var FINISHED = 3; // see ScriptableResource::State - -var onEmoteScreen = false; -var button; -var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); -var activeTimer = false; // Used to cancel active timer if a user plays an animation while another animation is playing -var activeEmote = false; // To keep track of the currently playing emote - -button = tablet.addButton({ - icon: "icons/tablet-icons/emote-i.svg", - activeIcon: "icons/tablet-icons/emote-a.svg", - text: EMOTE_LABEL, - sortOrder: EMOTE_APP_SORT_ORDER -}); - -function onClicked() { - if (onEmoteScreen) { - tablet.gotoHomeScreen(); - } else { - onEmoteScreen = true; - tablet.gotoWebScreen(EMOTE_APP_URL); - } -} - -function onScreenChanged(type, url) { - onEmoteScreen = type === "Web" && (url.indexOf(EMOTE_APP_BASE) === url.length - EMOTE_APP_BASE.length); - button.editProperties({ isActive: onEmoteScreen }); -} - -// Handle the events we're receiving from the web UI -function onWebEventReceived(event) { - - // Converts the event to a JavasScript Object - if (typeof event === "string") { - event = JSON.parse(event); - } - - if (event.type === "click") { - - // Allow for a random sitting animation when a user selects sit - var randSit = Math.floor(Math.random() * 3) + 1; - - var emoteName = event.data; - - if (emoteName === "Sit"){ - emoteName = event.data + randSit; // Sit1, Sit2, Sit3 - } - - if (ANIMATIONS[emoteName].resource.state === FINISHED) { - - if (activeTimer !== false) { - Script.clearTimeout(activeTimer); - } - - // If the activeEmote is different from the chosen emote, then play the new emote - // This is a second click on the same emote as the activeEmote, and we will just stop it - if (activeEmote !== emoteName) { - activeEmote = emoteName; - - - // Sit is the only animation currently that plays and then ends at the last frame - if (emoteName.match(/^Sit.*$/)) { - - // If user provides input during a sit, the avatar animation state should be restored - Controller.keyPressEvent.connect(restoreAnimation); - Controller.enableMapping(eventMappingName); - MyAvatar.overrideAnimation(ANIMATIONS[emoteName].url, FPS, false, 0, frameCount); - - } else { - - activeEmote = emoteName; - var frameCount = ANIMATIONS[emoteName].animation.frames.length; - MyAvatar.overrideAnimation(ANIMATIONS[emoteName].url, FPS, false, 0, frameCount); - - var timeOut = MSEC_PER_SEC * frameCount / FPS; - activeTimer = Script.setTimeout(function () { - MyAvatar.restoreAnimation(); - activeTimer = false; - activeEmote = false; - }, timeOut); - - } - - } else { - activeEmote = false; - MyAvatar.restoreAnimation(); - } - } - } -} - -// Restore the navigation animation states (idle, walk, run) -function restoreAnimation() { - MyAvatar.restoreAnimation(); - - // Make sure the input is disconnected after animations are restored so it doesn't affect any emotes other than sit - Controller.keyPressEvent.disconnect(restoreAnimation); - Controller.disableMapping(eventMappingName); -} - -// Note peek() so as to not interfere with other mappings. -eventMapping.from(Controller.Standard.LeftPrimaryThumb).peek().to(restoreAnimation); -eventMapping.from(Controller.Standard.RightPrimaryThumb).peek().to(restoreAnimation); -eventMapping.from(Controller.Standard.LeftSecondaryThumb).peek().to(restoreAnimation); -eventMapping.from(Controller.Standard.RightSecondaryThumb).peek().to(restoreAnimation); -eventMapping.from(Controller.Standard.LB).peek().to(restoreAnimation); -eventMapping.from(Controller.Standard.LS).peek().to(restoreAnimation); -eventMapping.from(Controller.Standard.RY).peek().to(restoreAnimation); -eventMapping.from(Controller.Standard.RX).peek().to(restoreAnimation); -eventMapping.from(Controller.Standard.LY).peek().to(restoreAnimation); -eventMapping.from(Controller.Standard.LX).peek().to(restoreAnimation); -eventMapping.from(Controller.Standard.LeftGrip).peek().to(restoreAnimation); -eventMapping.from(Controller.Standard.RB).peek().to(restoreAnimation); -eventMapping.from(Controller.Standard.RS).peek().to(restoreAnimation); -eventMapping.from(Controller.Standard.RightGrip).peek().to(restoreAnimation); -eventMapping.from(Controller.Standard.Back).peek().to(restoreAnimation); -eventMapping.from(Controller.Standard.Start).peek().to(restoreAnimation); - - -button.clicked.connect(onClicked); -tablet.screenChanged.connect(onScreenChanged); -tablet.webEventReceived.connect(onWebEventReceived); - -Script.scriptEnding.connect(function () { - if (onEmoteScreen) { - tablet.gotoHomeScreen(); - } - button.clicked.disconnect(onClicked); - tablet.screenChanged.disconnect(onScreenChanged); - if (tablet) { - tablet.removeButton(button); - } - if (activeTimer !== false) { - Script.clearTimeout(activeTimer); - MyAvatar.restoreAnimation(); - } -}); - - -}()); // END LOCAL_SCOPE diff --git a/scripts/simplifiedUI/system/fingerPaint.js b/scripts/simplifiedUI/system/fingerPaint.js deleted file mode 100644 index 88245503e8..0000000000 --- a/scripts/simplifiedUI/system/fingerPaint.js +++ /dev/null @@ -1,465 +0,0 @@ -// -// fingerPaint.js -// -// Created by David Rowe on 15 Feb 2017 -// Copyright 2017 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -(function () { - var tablet, - button, - BUTTON_NAME = "PAINT", - isFingerPainting = false, - shouldPointFingers = false, - leftHand = null, - rightHand = null, - leftBrush = null, - rightBrush = null, - CONTROLLER_MAPPING_NAME = "com.highfidelity.fingerPaint", - isTabletDisplayed = false, - HIFI_POINT_INDEX_MESSAGE_CHANNEL = "Hifi-Point-Index", - HIFI_GRAB_DISABLE_MESSAGE_CHANNEL = "Hifi-Grab-Disable", - HIFI_POINTER_DISABLE_MESSAGE_CHANNEL = "Hifi-Pointer-Disable"; - HOW_TO_EXIT_MESSAGE = "Press B on your controller to exit FingerPainting mode"; - - function paintBrush(name) { - // Paints in 3D. - var brushName = name, - STROKE_COLOR = { red: 250, green: 0, blue: 0 }, - ERASE_SEARCH_RADIUS = 0.1, // m - isDrawingLine = false, - entityID, - basePosition, - strokePoints, - strokeNormals, - strokeWidths, - timeOfLastPoint, - MIN_STROKE_LENGTH = 0.005, // m - MIN_STROKE_INTERVAL = 66, // ms - MAX_POINTS_PER_LINE = 70; // Hard-coded limit in PolyLineEntityItem.h. - - function strokeNormal() { - return Vec3.multiplyQbyV(Camera.getOrientation(), Vec3.UNIT_NEG_Z); - } - - function startLine(position, width) { - // Start drawing a polyline. - - if (isDrawingLine) { - print("ERROR: startLine() called when already drawing line"); - // Nevertheless, continue on and start a new line. - } - - basePosition = position; - - strokePoints = [Vec3.ZERO]; - strokeNormals = [strokeNormal()]; - strokeWidths = [width]; - timeOfLastPoint = Date.now(); - - entityID = Entities.addEntity({ - type: "PolyLine", - name: "fingerPainting", - color: STROKE_COLOR, - position: position, - linePoints: strokePoints, - normals: strokeNormals, - strokeWidths: strokeWidths, - dimensions: { x: 10, y: 10, z: 10 } - }); - - isDrawingLine = true; - } - - function drawLine(position, width) { - // Add a stroke to the polyline if stroke is a sufficient length. - var localPosition, - distanceToPrevious, - MAX_DISTANCE_TO_PREVIOUS = 1.0; - - if (!isDrawingLine) { - print("ERROR: drawLine() called when not drawing line"); - return; - } - - localPosition = Vec3.subtract(position, basePosition); - distanceToPrevious = Vec3.distance(localPosition, strokePoints[strokePoints.length - 1]); - - if (distanceToPrevious > MAX_DISTANCE_TO_PREVIOUS) { - // Ignore occasional spurious finger tip positions. - return; - } - - if (distanceToPrevious >= MIN_STROKE_LENGTH - && (Date.now() - timeOfLastPoint) >= MIN_STROKE_INTERVAL - && strokePoints.length < MAX_POINTS_PER_LINE) { - strokePoints.push(localPosition); - strokeNormals.push(strokeNormal()); - strokeWidths.push(width); - timeOfLastPoint = Date.now(); - - Entities.editEntity(entityID, { - linePoints: strokePoints, - normals: strokeNormals, - strokeWidths: strokeWidths - }); - } - } - - function finishLine(position, width) { - // Finish drawing polyline; delete if it has only 1 point. - - if (!isDrawingLine) { - print("ERROR: finishLine() called when not drawing line"); - return; - } - - if (strokePoints.length === 1) { - // Delete "empty" line. - Entities.deleteEntity(entityID); - } - - isDrawingLine = false; - } - - function cancelLine() { - // Cancel any line being drawn. - if (isDrawingLine) { - Entities.deleteEntity(entityID); - isDrawingLine = false; - } - } - - function eraseClosestLine(position) { - // Erase closest line that is within search radius of finger tip. - var entities, - entitiesLength, - properties, - i, - pointsLength, - j, - distance, - found = false, - foundID, - foundDistance = ERASE_SEARCH_RADIUS; - - // Find entities with bounding box within search radius. - entities = Entities.findEntities(position, ERASE_SEARCH_RADIUS); - - // Fine polyline entity with closest point within search radius. - for (i = 0, entitiesLength = entities.length; i < entitiesLength; i += 1) { - properties = Entities.getEntityProperties(entities[i], ["type", "position", "linePoints"]); - if (properties.type === "PolyLine") { - basePosition = properties.position; - for (j = 0, pointsLength = properties.linePoints.length; j < pointsLength; j += 1) { - distance = Vec3.distance(position, Vec3.sum(basePosition, properties.linePoints[j])); - if (distance <= foundDistance) { - found = true; - foundID = entities[i]; - foundDistance = distance; - } - } - } - } - - // Delete found entity. - if (found) { - Entities.deleteEntity(foundID); - } - } - - function tearDown() { - cancelLine(); - } - - return { - startLine: startLine, - drawLine: drawLine, - finishLine: finishLine, - cancelLine: cancelLine, - eraseClosestLine: eraseClosestLine, - tearDown: tearDown - }; - } - - function handController(name) { - // Translates controller data into application events. - var handName = name, - - triggerPressedCallback, - triggerPressingCallback, - triggerReleasedCallback, - gripPressedCallback, - - rawTriggerValue = 0.0, - triggerValue = 0.0, - isTriggerPressed = false, - TRIGGER_SMOOTH_RATIO = 0.1, - TRIGGER_OFF = 0.05, - TRIGGER_ON = 0.1, - TRIGGER_START_WIDTH_RAMP = 0.15, - TRIGGER_FINISH_WIDTH_RAMP = 1.0, - TRIGGER_RAMP_WIDTH = TRIGGER_FINISH_WIDTH_RAMP - TRIGGER_START_WIDTH_RAMP, - MIN_LINE_WIDTH = 0.005, - MAX_LINE_WIDTH = 0.03, - RAMP_LINE_WIDTH = MAX_LINE_WIDTH - MIN_LINE_WIDTH, - - rawGripValue = 0.0, - gripValue = 0.0, - isGripPressed = false, - GRIP_SMOOTH_RATIO = 0.1, - GRIP_OFF = 0.05, - GRIP_ON = 0.1; - - function onTriggerPress(value) { - // Controller values are only updated when they change so store latest for use in update. - rawTriggerValue = value; - } - - function updateTriggerPress(value) { - var wasTriggerPressed, - fingerTipPosition, - lineWidth; - - triggerValue = triggerValue * TRIGGER_SMOOTH_RATIO + rawTriggerValue * (1.0 - TRIGGER_SMOOTH_RATIO); - - wasTriggerPressed = isTriggerPressed; - if (isTriggerPressed) { - isTriggerPressed = triggerValue > TRIGGER_OFF; - } else { - isTriggerPressed = triggerValue > TRIGGER_ON; - } - - if (wasTriggerPressed || isTriggerPressed) { - fingerTipPosition = MyAvatar.getJointPosition(handName === "left" ? "LeftHandIndex4" : "RightHandIndex4"); - if (triggerValue < TRIGGER_START_WIDTH_RAMP) { - lineWidth = MIN_LINE_WIDTH; - } else { - lineWidth = MIN_LINE_WIDTH - + (triggerValue - TRIGGER_START_WIDTH_RAMP) / TRIGGER_RAMP_WIDTH * RAMP_LINE_WIDTH; - } - - if (!wasTriggerPressed && isTriggerPressed) { - triggerPressedCallback(fingerTipPosition, lineWidth); - } else if (wasTriggerPressed && isTriggerPressed) { - triggerPressingCallback(fingerTipPosition, lineWidth); - } else { - triggerReleasedCallback(fingerTipPosition, lineWidth); - } - } - } - - function onGripPress(value) { - // Controller values are only updated when they change so store latest for use in update. - rawGripValue = value; - } - - function updateGripPress() { - var fingerTipPosition; - - gripValue = gripValue * GRIP_SMOOTH_RATIO + rawGripValue * (1.0 - GRIP_SMOOTH_RATIO); - - if (isGripPressed) { - isGripPressed = gripValue > GRIP_OFF; - } else { - isGripPressed = gripValue > GRIP_ON; - if (isGripPressed) { - fingerTipPosition = MyAvatar.getJointPosition(handName === "left" ? "LeftHandIndex4" : "RightHandIndex4"); - gripPressedCallback(fingerTipPosition); - } - } - } - - function onUpdate() { - updateTriggerPress(); - updateGripPress(); - } - - function setUp(onTriggerPressed, onTriggerPressing, onTriggerReleased, onGripPressed) { - triggerPressedCallback = onTriggerPressed; - triggerPressingCallback = onTriggerPressing; - triggerReleasedCallback = onTriggerReleased; - gripPressedCallback = onGripPressed; - } - - function tearDown() { - // Nothing to do. - } - - return { - onTriggerPress: onTriggerPress, - onGripPress: onGripPress, - onUpdate: onUpdate, - setUp: setUp, - tearDown: tearDown - }; - } - - function updateHandFunctions() { - // Update other scripts' hand functions. - var enabled = !isFingerPainting || isTabletDisplayed; - - Messages.sendMessage(HIFI_GRAB_DISABLE_MESSAGE_CHANNEL, JSON.stringify({ - holdEnabled: enabled, - nearGrabEnabled: enabled, - farGrabEnabled: enabled - }), true); - Messages.sendMessage(HIFI_POINTER_DISABLE_MESSAGE_CHANNEL, JSON.stringify({ - pointerEnabled: enabled - }), true); - - var newShouldPointFingers = !enabled; - if (newShouldPointFingers !== shouldPointFingers) { - Messages.sendMessage(HIFI_POINT_INDEX_MESSAGE_CHANNEL, JSON.stringify({ - pointIndex: newShouldPointFingers - }), true); - shouldPointFingers = newShouldPointFingers; - } - } - - function howToExitTutorial() { - HMD.requestShowHandControllers(); - setControllerPartLayer('button_b', 'highlight'); - messageWindow = Window.alert(HOW_TO_EXIT_MESSAGE); - setControllerPartLayer('button_b', 'blank'); - HMD.requestHideHandControllers(); - Settings.setValue("FingerPaintTutorialComplete", true); - } - - function enableProcessing() { - // Connect controller API to handController objects. - leftHand = handController("left"); - rightHand = handController("right"); - var controllerMapping = Controller.newMapping(CONTROLLER_MAPPING_NAME); - controllerMapping.from(Controller.Standard.LT).to(leftHand.onTriggerPress); - controllerMapping.from(Controller.Standard.LeftGrip).to(leftHand.onGripPress); - controllerMapping.from(Controller.Standard.RT).to(rightHand.onTriggerPress); - controllerMapping.from(Controller.Standard.RightGrip).to(rightHand.onGripPress); - controllerMapping.from(Controller.Standard.B).to(onButtonClicked); - Controller.enableMapping(CONTROLLER_MAPPING_NAME); - - if (!Settings.getValue("FingerPaintTutorialComplete")) { - howToExitTutorial(); - } - - // Connect handController outputs to paintBrush objects. - leftBrush = paintBrush("left"); - leftHand.setUp(leftBrush.startLine, leftBrush.drawLine, leftBrush.finishLine, leftBrush.eraseClosestLine); - rightBrush = paintBrush("right"); - rightHand.setUp(rightBrush.startLine, rightBrush.drawLine, rightBrush.finishLine, rightBrush.eraseClosestLine); - - // Messages channels for enabling/disabling other scripts' functions. - Messages.subscribe(HIFI_POINT_INDEX_MESSAGE_CHANNEL); - Messages.subscribe(HIFI_GRAB_DISABLE_MESSAGE_CHANNEL); - Messages.subscribe(HIFI_POINTER_DISABLE_MESSAGE_CHANNEL); - - // Update hand controls. - Script.update.connect(leftHand.onUpdate); - Script.update.connect(rightHand.onUpdate); - } - - function disableProcessing() { - Script.update.disconnect(leftHand.onUpdate); - Script.update.disconnect(rightHand.onUpdate); - - Controller.disableMapping(CONTROLLER_MAPPING_NAME); - - leftBrush.tearDown(); - leftBrush = null; - leftHand.tearDown(); - leftHand = null; - - rightBrush.tearDown(); - rightBrush = null; - rightHand.tearDown(); - rightHand = null; - - Messages.unsubscribe(HIFI_POINT_INDEX_MESSAGE_CHANNEL); - Messages.unsubscribe(HIFI_GRAB_DISABLE_MESSAGE_CHANNEL); - Messages.unsubscribe(HIFI_POINTER_DISABLE_MESSAGE_CHANNEL); - } - - function onButtonClicked() { - var wasFingerPainting = isFingerPainting; - - isFingerPainting = !isFingerPainting; - button.editProperties({ isActive: isFingerPainting }); - - print("Finger painting: " + isFingerPainting ? "on" : "off"); - - if (wasFingerPainting) { - leftBrush.cancelLine(); - rightBrush.cancelLine(); - } - - if (isFingerPainting) { - enableProcessing(); - } - - updateHandFunctions(); - - if (!isFingerPainting) { - disableProcessing(); - } - } - - function onTabletScreenChanged(type, url) { - var TABLET_SCREEN_CLOSED = "Closed"; - - isTabletDisplayed = type !== TABLET_SCREEN_CLOSED; - updateHandFunctions(); - } - - function setUp() { - tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); - if (!tablet) { - return; - } - - // Tablet button. - button = tablet.addButton({ - icon: "icons/tablet-icons/finger-paint-i.svg", - activeIcon: "icons/tablet-icons/finger-paint-a.svg", - text: BUTTON_NAME, - isActive: isFingerPainting - }); - button.clicked.connect(onButtonClicked); - - // Track whether tablet is displayed or not. - tablet.screenChanged.connect(onTabletScreenChanged); - } - - function tearDown() { - if (!tablet) { - return; - } - - if (isFingerPainting) { - isFingerPainting = false; - updateHandFunctions(); - disableProcessing(); - } - - tablet.screenChanged.disconnect(onTabletScreenChanged); - - button.clicked.disconnect(onButtonClicked); - tablet.removeButton(button); - } - - /** - * A controller is made up of parts, and each part can have multiple "layers," - * which are really just different texures. For example, the "trigger" part - * has "normal" and "highlight" layers. - */ - function setControllerPartLayer(part, layer) { - data = {}; - data[part] = layer; - Messages.sendLocalMessage('Controller-Set-Part-Layer', JSON.stringify(data)); - } - - setUp(); - Script.scriptEnding.connect(tearDown); -}()); diff --git a/scripts/simplifiedUI/system/firstPersonHMD.js b/scripts/simplifiedUI/system/firstPersonHMD.js deleted file mode 100644 index 5fdee1b7b5..0000000000 --- a/scripts/simplifiedUI/system/firstPersonHMD.js +++ /dev/null @@ -1,23 +0,0 @@ -"use strict"; - -// -// firstPersonHMD.js -// system -// -// Created by Zander Otavka on 6/24/16 -// Copyright 2016 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -(function() { // BEGIN LOCAL_SCOPE - -// Automatically enter first person mode when entering HMD mode -HMD.displayModeChanged.connect(function(isHMDMode) { - if (isHMDMode) { - Camera.setModeString("first person"); - } -}); - -}()); // END LOCAL_SCOPE diff --git a/scripts/simplifiedUI/system/generalSettings.js b/scripts/simplifiedUI/system/generalSettings.js deleted file mode 100644 index d3848da7d0..0000000000 --- a/scripts/simplifiedUI/system/generalSettings.js +++ /dev/null @@ -1,56 +0,0 @@ -"use strict"; - -// -// generalSettings.js -// scripts/system/ -// -// Created by Dante Ruiz on 9 Feb 2017 -// Copyright 2016 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// -/* globals Tablet, Toolbars, Script, HMD, DialogsManager */ - -(function() { // BEGIN LOCAL_SCOPE - - var button; - var buttonName = "Settings"; - var toolBar = null; - var tablet = null; - var settings = "hifi/tablet/TabletGeneralPreferences.qml" - function onClicked(){ - if (tablet) { - tablet.loadQMLSource(settings); - } - } - - if (Settings.getValue("HUDUIEnabled")) { - toolBar = Toolbars.getToolbar("com.highfidelity.interface.toolbar.system"); - button = toolBar.addButton({ - objectName: buttonName, - imageURL: Script.resolvePath("assets/images/tools/directory.svg"), - visible: true, - alpha: 0.9 - }); - } else { - tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); - button = tablet.addButton({ - icon: "icons/tablet-icons/goto-i.svg", - text: buttonName - }); - } - - button.clicked.connect(onClicked); - - Script.scriptEnding.connect(function () { - button.clicked.disconnect(onClicked); - if (tablet) { - tablet.removeButton(button); - } - if (toolBar) { - toolBar.removeButton(buttonName); - } - }); - -}()); // END LOCAL_SCOPE diff --git a/scripts/simplifiedUI/system/goto.js b/scripts/simplifiedUI/system/goto.js deleted file mode 100644 index 5cc5bad844..0000000000 --- a/scripts/simplifiedUI/system/goto.js +++ /dev/null @@ -1,65 +0,0 @@ -"use strict"; - -// -// goto.js -// scripts/system/ -// -// Created by Howard Stearns on 2 Jun 2016 -// Copyright 2016 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// -/* globals Tablet, Toolbars, Script, HMD, DialogsManager */ - -(function() { // BEGIN LOCAL_SCOPE - -var button; -var buttonName = "GOTO"; -var toolBar = null; -var tablet = null; -var onGotoScreen = false; -function onAddressBarShown(visible) { - button.editProperties({isActive: visible}); -} - -function onClicked(){ - DialogsManager.toggleAddressBar(); - onGotoScreen = !onGotoScreen; -} - -if (Settings.getValue("HUDUIEnabled")) { - toolBar = Toolbars.getToolbar("com.highfidelity.interface.toolbar.system"); - button = toolBar.addButton({ - objectName: buttonName, - imageURL: Script.resolvePath("assets/images/tools/directory.svg"), - visible: true, - alpha: 0.9 - }); -} else { - tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); - button = tablet.addButton({ - icon: "icons/tablet-icons/goto-i.svg", - activeIcon: "icons/tablet-icons/goto-a.svg", - text: buttonName - }); -} - -button.clicked.connect(onClicked); -DialogsManager.addressBarShown.connect(onAddressBarShown); - -Script.scriptEnding.connect(function () { - if (onGotoScreen) { - DialogsManager.toggleAddressBar(); - } - button.clicked.disconnect(onClicked); - if (tablet) { - tablet.removeButton(button); - } - if (toolBar) { - toolBar.removeButton(buttonName); - } - DialogsManager.addressBarShown.disconnect(onAddressBarShown); -}); - -}()); // END LOCAL_SCOPE diff --git a/scripts/simplifiedUI/system/help.js b/scripts/simplifiedUI/system/help.js deleted file mode 100644 index 40bbf6dbe2..0000000000 --- a/scripts/simplifiedUI/system/help.js +++ /dev/null @@ -1,29 +0,0 @@ -"use strict"; -/* eslint indent: ["error", 4, { "outerIIFEBody": 0 }] */ -// -// help.js -// scripts/system/ -// -// Created by Howard Stearns on 2 Nov 2016 -// Copyright 2016 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// -/* globals Tablet, Script, HMD, Controller, Menu */ - -(function () { // BEGIN LOCAL_SCOPE -var AppUi = Script.require('appUi'); - -var HELP_URL = Script.resourcesPath() + "html/tabletHelp.html"; -var HELP_BUTTON_NAME = "HELP"; -var ui; -function startup() { - ui = new AppUi({ - buttonName: HELP_BUTTON_NAME, - sortOrder: 6, - home: HELP_URL - }); -} -startup(); -}()); // END LOCAL_SCOPE diff --git a/scripts/simplifiedUI/system/hmd.js b/scripts/simplifiedUI/system/hmd.js deleted file mode 100644 index 858b93ef1e..0000000000 --- a/scripts/simplifiedUI/system/hmd.js +++ /dev/null @@ -1,92 +0,0 @@ -"use strict"; - -// -// hmd.js -// scripts/system/ -// -// Created by Howard Stearns on 2 Jun 2016 -// Copyright 2016 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// -/* globals HMD, Script, Menu, Tablet, Camera */ -/* eslint indent: ["error", 4, { "outerIIFEBody": 0 }] */ - -(function() { // BEGIN LOCAL_SCOPE - -var headset; // The preferred headset. Default to the first one found in the following list. -var displayMenuName = "Display"; -var desktopMenuItemName = "Desktop"; -['HTC Vive', 'Oculus Rift', 'WindowMS'].forEach(function (name) { - if (!headset && Menu.menuItemExists(displayMenuName, name)) { - headset = name; - } -}); - -var controllerDisplay = false; -function updateControllerDisplay() { - if (HMD.active && Menu.isOptionChecked("Third Person")) { - if (!controllerDisplay) { - HMD.requestShowHandControllers(); - controllerDisplay = true; - } - } else if (controllerDisplay) { - HMD.requestHideHandControllers(); - controllerDisplay = false; - } -} - -var button; -var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); - -var switchToVR = "ENTER VR"; -var switchToDesktop = "EXIT VR"; - -function onHmdChanged(isHmd) { - HMD.closeTablet(); - if (isHmd) { - button.editProperties({ - icon: "icons/tablet-icons/switch-desk-i.svg", - text: switchToDesktop - }); - } else { - button.editProperties({ - icon: "icons/tablet-icons/switch-vr-i.svg", - text: switchToVR - }); - } - updateControllerDisplay(); -} - -function onClicked() { - var isDesktop = Menu.isOptionChecked(desktopMenuItemName); - Menu.setIsOptionChecked(isDesktop ? headset : desktopMenuItemName, true); - if (!isDesktop) { - UserActivityLogger.logAction("exit_vr"); - } -} - -if (headset) { - button = tablet.addButton({ - icon: HMD.active ? "icons/tablet-icons/switch-desk-i.svg" : "icons/tablet-icons/switch-vr-i.svg", - text: HMD.active ? switchToDesktop : switchToVR, - sortOrder: 2 - }); - onHmdChanged(HMD.active); - - button.clicked.connect(onClicked); - HMD.displayModeChanged.connect(onHmdChanged); - Camera.modeUpdated.connect(updateControllerDisplay); - - Script.scriptEnding.connect(function () { - button.clicked.disconnect(onClicked); - if (tablet) { - tablet.removeButton(button); - } - HMD.displayModeChanged.disconnect(onHmdChanged); - Camera.modeUpdated.disconnect(updateControllerDisplay); - }); -} - -}()); // END LOCAL_SCOPE diff --git a/scripts/simplifiedUI/system/html/ChatPage.html b/scripts/simplifiedUI/system/html/ChatPage.html deleted file mode 100644 index 9606eeab3e..0000000000 --- a/scripts/simplifiedUI/system/html/ChatPage.html +++ /dev/null @@ -1,511 +0,0 @@ - - - - Chat - - - - - - - - -
- -
- Chat -
- -
- -
- -
- -
- - - - - - diff --git a/scripts/simplifiedUI/system/html/EmoteApp.html b/scripts/simplifiedUI/system/html/EmoteApp.html deleted file mode 100644 index 6b42fb8dc8..0000000000 --- a/scripts/simplifiedUI/system/html/EmoteApp.html +++ /dev/null @@ -1,138 +0,0 @@ - - - - Emote App - - - - - - -
-

Emote App

-
-
-

Choose an emote:

-

-

-

-

-

-

-

-

-

-

-
- - - - - \ No newline at end of file diff --git a/scripts/simplifiedUI/system/html/SnapshotReview.html b/scripts/simplifiedUI/system/html/SnapshotReview.html deleted file mode 100644 index f080cd204a..0000000000 --- a/scripts/simplifiedUI/system/html/SnapshotReview.html +++ /dev/null @@ -1,38 +0,0 @@ - - - Share - - - - - - - -
- - - -
-
-
-
-
-
-
-
-
-
- -
- -
-
- -
- -
-
- - diff --git a/scripts/simplifiedUI/system/html/css/SnapshotReview.css b/scripts/simplifiedUI/system/html/css/SnapshotReview.css deleted file mode 100644 index 54d39aaad3..0000000000 --- a/scripts/simplifiedUI/system/html/css/SnapshotReview.css +++ /dev/null @@ -1,346 +0,0 @@ -/* -// SnapshotReview.css -// -// Created by Howard Stearns for David Rowe 8/22/2016. -// Copyright 2016 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -*/ - -/* -// START styling of top bar and its contents -*/ - -.title { - padding: 6px 10px; - text-align: left; - height: 26px; - line-height: 26px; - clear: both; -} - -.title label { - position: relative; - font-size: 18px; - float: left; -} - -#snapshotSettings { - position: relative; - float: right; -} -#settingsLabel { - position: relative; - float: right; - font-family: Raleway-SemiBold; - font-size: 14px; -} -.hifi-glyph { - font-size: 30px; - top: -4px; -} -input[type=button].naked { - color: #afafaf; - background: none; -} -input[type=button].naked:hover { - color: #ffffff; -} -input[type=button].naked:active { - color: #afafaf; -} -/* -// END styling of top bar and its contents -*/ - -/* -// START styling of snapshot instructions panel -*/ -.snapshotInstructions { - font-family: Raleway-Regular; - margin: 0 20px; - width: 100%; - height: 50%; -} -/* -// END styling of snapshot instructions panel -*/ - -/* -// START styling of snapshot pane and its contents -*/ -#snapshot-pane { - width: 100%; - height: 560px; - display: flex; - justify-content: center; - align-items: center; -} - -#snapshot-images { - width: 100%; - display: flex; - justify-content: center; - flex-direction: column; -} - -#snapshot-images img { - max-width: 100%; - max-height: 100%; -} - -.gifLabel { - position:absolute; - left: 15px; - top: 10px; - font-family: Raleway-SemiBold; - font-size: 18px; - color: white; - text-shadow: 2px 2px 3px #000000; -} -/* -// END styling of snapshot pane and its contents -*/ - -/* -// START styling of share overlay -*/ -.shareControls { - display: flex; - justify-content: space-between; - flex-direction: row; - align-items: center; - height: 65px; - line-height: 65px; - width: calc(100% - 8px); - position: absolute; - bottom: 4px; - left: 4px; - right: 4px; -} -.showShareButtonsButtonDiv { - display: inline-flex; - align-items: center; - font-family: Raleway-SemiBold; - font-size: 14px; - color: white; - width: 75px; - height: 100%; - margin-bottom: 0px; -} -.showShareButtonsButtonDiv.active:hover { - background-color: rgba(0, 0, 0, 0.45); - background-size: 2px; -} -.showShareButtonsButtonDiv > label { - text-shadow: 2px 2px 3px #000000; - margin-bottom: -14px; - margin-left: 12px; -} -.showShareButtonsButtonDiv:hover > label { - text-shadow: none; -} -.showShareButtonDots { - display: block; - width: 40px; - height: 40px; - font-family: HiFi-Glyphs; - font-size: 60px; - position: absolute; - left: 6px; - bottom: 32px; - color: white; - pointer-events: none; -} -.shareButtons { - display: flex; - align-items: flex-end; - height: 40px; - width: calc(100% - 60px); - margin-bottom: -24px; - margin-left: 0; -} -.shareButtons img { - width: 40px; - height: 40px; -} -.shareButton { - width: 40px; - height: 40px; - display: inline-block; -} -.shareButton.disabled { - background-color: #000000; - opacity: 0.5; -} -.shareControlsHelp { - height: 25px; - line-height: 25px; - position: absolute; - bottom: 40px; - left: 73px; - right: 0; - font-family: Raleway-Regular; - font-weight: 500; - font-size: 16px; - padding-left: 8px; - color: white; -} -.helpTextDiv { - width: 350px; - height: 65px; - margin-right: 15px; - line-height: 65px; - position: absolute; - bottom: 0; - right: 0; - font-family: Raleway-Regular; - font-weight: 500; - font-size: 16px; - color: white; -} -/* -// END styling of share overlay -*/ - -/* -// START styling of confirmation message -*/ -.confirmationMessageContainer { - width: 100%; - height: 100%; - position: absolute; - background-color: rgba(0, 0, 0, 0.45); - text-align: center; - left: 0; - top: 0; - pointer-events: none; - color: white; - font-weight: bold; - font-size: 16px; -} -.confirmationMessage { - width: 130px; - height: 130px; - margin: 50px auto 0 auto; -} -.confirmationMessage > img { - width: 72px; - height: 72px; - display: block; - margin: 0 auto; - padding: 10px 0 0 0; -} -/* -// END styling of uploading message -*/ - -/* -// START styling of snapshot controls (bottom panel) and its contents -*/ -#snapshot-controls { - width: 100%; - position: absolute; - left: 0; - overflow: hidden; - display: flex; - justify-content: center; -} -#snap-settings { - display: inline; - width: 150px; - margin: 2px auto 0 auto; -} -#snap-settings form input { - margin-bottom: 5px; -} - -#snap-button { - width: 72px; - height: 72px; - padding: 0; - border-radius: 50%; - background: #EA4C5F; - border: 3px solid white; - margin: 2px auto 0 auto; - box-sizing: content-box; - display: inline; - outline:none; -} -#snap-button:disabled { - background: gray; -} -#snap-button:hover:enabled { - background: #C62147; -} -#snap-button:active:enabled { - background: #EA4C5F; -} -#snap-settings-right { - display: inline; - width: 150px; - margin: auto; -} -/* -// END styling of snapshot controls (bottom panel) and its contents -*/ - - -/* -// START polaroid styling -*/ - -#print-button { - width: 72px; - height: 72px; - margin-left: 30px; - margin-top: -10px; - box-sizing: content-box; - display: inline; - outline:none; -} - -.print-icon { - margin: auto; -} - -.print-icon-default { - background: url(../img/button-snap-print.svg) no-repeat; - margin-right: -1px; - width: 64px; - height: 64px; -} - -.print-icon-loading { - background: url(../img/loader.gif) no-repeat; - width: 32px; - height: 32px; -} - -/* -// END polaroid styling -*/ - - -/* -// START misc styling -*/ -body { - padding: 0; - margin: 0; - overflow: hidden; -} -p { - margin: 2px 0; -} -h4 { - margin: 14px 0 0 0; -} -.centeredImage { - margin: 0 auto; - display: block; -} -/* -// END misc styling -*/ diff --git a/scripts/simplifiedUI/system/html/css/colpick.css b/scripts/simplifiedUI/system/html/css/colpick.css deleted file mode 100644 index fc50c4b3fb..0000000000 --- a/scripts/simplifiedUI/system/html/css/colpick.css +++ /dev/null @@ -1,433 +0,0 @@ -/* -colpick Color Picker / colpick.com -*/ - -/*Main container*/ -.colpick { - position: absolute; - width: 346px; - height: 170px; - overflow: hidden; - display: none; - font-family: Arial, Helvetica, sans-serif; - background:#ebebeb; - border: 1px solid #bbb; - -webkit-border-radius: 5px; - -moz-border-radius: 5px; - border-radius: 5px; - - /*Prevents selecting text when dragging the selectors*/ - -webkit-user-select: none; - -moz-user-select: none; - -ms-user-select: none; - -o-user-select: none; - user-select: none; -} -/*Color selection box with gradients*/ -.colpick_color { - position: absolute; - touch-action: none; - left: 7px; - top: 7px; - width: 156px; - height: 156px; - overflow: hidden; - outline: 1px solid #aaa; - cursor: crosshair; -} -.colpick_color_overlay1 { - position: absolute; - left:0; - top:0; - width: 156px; - height: 156px; - -ms-filter: "progid:DXImageTransform.Microsoft.gradient(GradientType=1,startColorstr='#ffffff', endColorstr='#00ffffff')"; /* IE8 */ - background: -moz-linear-gradient(left, rgba(255,255,255,1) 0%, rgba(255,255,255,0) 100%); /* FF3.6+ */ - background: -webkit-gradient(linear, left top, right top, color-stop(0%,rgba(255,255,255,1)), color-stop(100%,rgba(255,255,255,0))); /* Chrome,Safari4+ */ - background: -webkit-linear-gradient(left, rgba(255,255,255,1) 0%,rgba(255,255,255,0) 100%); /* Chrome10+,Safari5.1+ */ - background: -o-linear-gradient(left, rgba(255,255,255,1) 0%,rgba(255,255,255,0) 100%); /* Opera 11.10+ */ - background: -ms-linear-gradient(left, rgba(255,255,255,1) 0%,rgba(255,255,255,0) 100%); /* IE10+ */ - background: linear-gradient(to right, rgba(255,255,255,1) 0%, rgba(255,255,255,0) 100%); - filter: progid:DXImageTransform.Microsoft.gradient(GradientType=1,startColorstr='#ffffff', endColorstr='#00ffffff'); /* IE6 & IE7 */ -} -.colpick_color_overlay2 { - position: absolute; - left:0; - top:0; - width: 156px; - height: 156px; - -ms-filter: "progid:DXImageTransform.Microsoft.gradient(GradientType=0,startColorstr='#00000000', endColorstr='#000000')"; /* IE8 */ - background: -moz-linear-gradient(top, rgba(0,0,0,0) 0%, rgba(0,0,0,1) 100%); /* FF3.6+ */ - background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,rgba(0,0,0,0)), color-stop(100%,rgba(0,0,0,1))); /* Chrome,Safari4+ */ - background: -webkit-linear-gradient(top, rgba(0,0,0,0) 0%,rgba(0,0,0,1) 100%); /* Chrome10+,Safari5.1+ */ - background: -o-linear-gradient(top, rgba(0,0,0,0) 0%,rgba(0,0,0,1) 100%); /* Opera 11.10+ */ - background: -ms-linear-gradient(top, rgba(0,0,0,0) 0%,rgba(0,0,0,1) 100%); /* IE10+ */ - background: linear-gradient(to bottom, rgba(0,0,0,0) 0%,rgba(0,0,0,1) 100%); /* W3C */ - filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#00000000', endColorstr='#000000',GradientType=0 ); /* IE6-9 */ -} -/*Circular color selector*/ -.colpick_selector_outer { - background:none; - position: absolute; - width: 11px; - height: 11px; - margin: -6px 0 0 -6px; - border: 1px solid black; - border-radius: 50%; -} -.colpick_selector_inner{ - position: absolute; - width: 9px; - height: 9px; - border: 1px solid white; - border-radius: 50%; -} -/*Vertical hue bar*/ -.colpick_hue { - position: absolute; - touch-action: none; - top: 6px; - left: 175px; - width: 19px; - height: 156px; - border: 1px solid #aaa; - cursor: n-resize; -} -/*Hue bar sliding indicator*/ -.colpick_hue_arrs { - position: absolute; - touch-action: none; - left: -8px; - width: 35px; - height: 7px; - margin: -7px 0 0 0; -} -.colpick_hue_larr { - position:absolute; - touch-action: none; - width: 0; - height: 0; - border-top: 6px solid transparent; - border-bottom: 6px solid transparent; - border-left: 7px solid #858585; -} -.colpick_hue_rarr { - position:absolute; - touch-action: none; - right:0; - width: 0; - height: 0; - border-top: 6px solid transparent; - border-bottom: 6px solid transparent; - border-right: 7px solid #858585; -} -/*New color box*/ -.colpick_new_color { - position: absolute; - touch-action: none; - left: 207px; - top: 6px; - width: 60px; - height: 27px; - background: #f00; - border: 1px solid #8f8f8f; -} -/*Current color box*/ -.colpick_current_color { - position: absolute; - touch-action: none; - left: 277px; - top: 6px; - width: 60px; - height: 27px; - background: #f00; - border: 1px solid #8f8f8f; -} -/*Input field containers*/ -.colpick_field, .colpick_hex_field { - position: absolute; - touch-action: none; - height: 20px; - width: 60px; - overflow:hidden; - background:#f3f3f3; - color:#b8b8b8; - font-size:12px; - border:1px solid #bdbdbd; - -webkit-border-radius: 3px; - -moz-border-radius: 3px; - border-radius: 3px; -} -.colpick_rgb_r { - top: 40px; - left: 207px; -} -.colpick_rgb_g { - top: 67px; - left: 207px; -} -.colpick_rgb_b { - top: 94px; - left: 207px; -} -.colpick_hsb_h { - top: 40px; - left: 277px; -} -.colpick_hsb_s { - top: 67px; - left: 277px; -} -.colpick_hsb_b { - top: 94px; - left: 277px; -} -.colpick_hex_field { - width: 68px; - left: 207px; - top: 121px; -} -/*Text field container on focus*/ -.colpick_focus { - border-color: #999; -} -/*Field label container*/ -.colpick_field_letter { - position: absolute; - width: 12px; - height: 20px; - line-height: 20px; - padding-left: 4px; - background: #efefef; - border-right: 1px solid #bdbdbd; - font-weight: bold; - color:#777; -} -/*Text inputs*/ -.colpick_field input, .colpick_hex_field input { - position: absolute; - touch-action: none; - right: 11px; - margin: 0; - padding: 0; - height: 20px; - line-height: 20px; - background: transparent; - border: none; - font-size: 12px; - font-family: Arial, Helvetica, sans-serif; - color: #555; - text-align: right; - outline: none; -} -.colpick_hex_field input { - right: 4px; -} -/*Field up/down arrows*/ -.colpick_field_arrs { - position: absolute; - touch-action: none; - top: 0; - right: 0; - width: 9px; - height: 21px; - cursor: n-resize; -} -.colpick_field_uarr { - position: absolute; - touch-action: none; - top: 5px; - width: 0; - height: 0; - border-left: 4px solid transparent; - border-right: 4px solid transparent; - border-bottom: 4px solid #959595; -} -.colpick_field_darr { - position: absolute; - touch-action: none; - bottom:5px; - width: 0; - height: 0; - border-left: 4px solid transparent; - border-right: 4px solid transparent; - border-top: 4px solid #959595; -} -/*Submit/Select button*/ -.colpick_submit { - position: absolute; - touch-action: none; - left: 207px; - top: 149px; - width: 130px; - height: 22px; - line-height:22px; - background: #efefef; - text-align: center; - color: #555; - font-size: 12px; - font-weight:bold; - border: 1px solid #bdbdbd; - -webkit-border-radius: 3px; - -moz-border-radius: 3px; - border-radius: 3px; -} -.colpick_submit:hover { - background:#f3f3f3; - border-color:#999; - cursor: pointer; -} - -/*full layout with no submit button*/ -.colpick_full_ns .colpick_submit { - display:none; -} -.colpick_full_ns .colpick_new_color { - width: 130px; - height: 25px; -} -.colpick_full_ns .colpick_rgb_r, .colpick_full_ns .colpick_hsb_h { - top: 42px; -} -.colpick_full_ns .colpick_rgb_g, .colpick_full_ns .colpick_hsb_s { - top: 73px; -} -.colpick_full_ns .colpick_rgb_b, .colpick_full_ns .colpick_hsb_b { - top: 104px; -} -.colpick_full_ns .colpick_hex_field { - top: 135px; -} - -/*rgbhex layout*/ -.colpick_rgbhex .colpick_hsb_h, .colpick_rgbhex .colpick_hsb_s, .colpick_rgbhex .colpick_hsb_b { - display:none; -} -.colpick_rgbhex { - width:282px; -} -.colpick_rgbhex .colpick_field, .colpick_rgbhex .colpick_submit { - width:68px; -} -.colpick_rgbhex .colpick_new_color { - width:34px; - border-right:none; -} -.colpick_rgbhex .colpick_current_color { - width:34px; - left:240px; - border-left:none; -} - -/*rgbhex layout, no submit button*/ -.colpick_rgbhex_ns .colpick_submit { - display:none; -} -.colpick_rgbhex_ns .colpick_new_color{ - width:34px; - border: 1px solid #8f8f8f; -} -.colpick_rgbhex_ns .colpick_rgb_r { - top: 42px; -} -.colpick_rgbhex_ns .colpick_rgb_g { - top: 73px; -} -.colpick_rgbhex_ns .colpick_rgb_b { - top: 104px; -} -.colpick_rgbhex_ns .colpick_hex_field { - top: 135px; -} - -/*hex layout*/ -.colpick_hex .colpick_hsb_h, .colpick_hex .colpick_hsb_s, .colpick_hex .colpick_hsb_b, .colpick_hex .colpick_rgb_r, .colpick_hex .colpick_rgb_g, .colpick_hex .colpick_rgb_b { - display:none; -} -.colpick_hex { - width:206px; - height:201px; -} -.colpick_hex .colpick_hex_field { - width:72px; - height:25px; - top:168px; - left:80px; -} -.colpick_hex .colpick_hex_field div, .colpick_hex .colpick_hex_field input { - height: 25px; - line-height: 25px; -} -.colpick_hex .colpick_new_color { - left:9px; - top:168px; - width:30px; - border-right:none; -} -.colpick_hex .colpick_current_color { - left:39px; - top:168px; - width:30px; - border-left:none; -} -.colpick_hex .colpick_submit { - left:164px; - top: 168px; - width:30px; - height:25px; - line-height: 25px; -} - -/*hex layout, no submit button*/ -.colpick_hex_ns .colpick_submit { - display:none; -} -.colpick_hex_ns .colpick_hex_field { - width:80px; -} -.colpick_hex_ns .colpick_new_color{ - width:60px; - border: 1px solid #8f8f8f; -} - -/*Dark color scheme*/ -.colpick_dark { - background: #161616; - border-color: #2a2a2a; -} -.colpick_dark .colpick_color { - outline-color: #333; -} -.colpick_dark .colpick_hue { - border-color: #555; -} -.colpick_dark .colpick_field, .colpick_dark .colpick_hex_field { - background: #101010; - border-color: #2d2d2d; -} -.colpick_dark .colpick_field_letter { - background: #131313; - border-color: #2d2d2d; - color: #696969; -} -.colpick_dark .colpick_field input, .colpick_dark .colpick_hex_field input { - color: #7a7a7a; -} -.colpick_dark .colpick_field_uarr { - border-bottom-color:#696969; -} -.colpick_dark .colpick_field_darr { - border-top-color:#696969; -} -.colpick_dark .colpick_focus { - border-color:#444; -} -.colpick_dark .colpick_submit { - background: #131313; - border-color:#2d2d2d; - color:#7a7a7a; -} -.colpick_dark .colpick_submit:hover { - background-color:#101010; - border-color:#444; -} \ No newline at end of file diff --git a/scripts/simplifiedUI/system/html/css/edit-style.css b/scripts/simplifiedUI/system/html/css/edit-style.css deleted file mode 100644 index 470e57ad6d..0000000000 --- a/scripts/simplifiedUI/system/html/css/edit-style.css +++ /dev/null @@ -1,1796 +0,0 @@ -/* -// edit-style.css -// -// Created by Ryan Huffman on 13 Nov 2014 -// Copyright 2014 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -*/ - -@font-face { - font-family: Raleway-Regular; - src: url(../../../../resources/fonts/Raleway-Regular.ttf), /* Windows production */ - url(../../../../fonts/Raleway-Regular.ttf), /* OSX production */ - url(../../../../interface/resources/fonts/Raleway-Regular.ttf), /* Development, running script in /HiFi/examples */ - url(../fonts/Raleway-Regular.ttf); /* Marketplace script */ -} - -@font-face { - font-family: Raleway-Light; - src: url(../../../../resources/fonts/Raleway-Light.ttf), - url(../../../../fonts/Raleway-Light.ttf), - url(../../../../interface/resources/fonts/Raleway-Light.ttf), - url(../fonts/Raleway-Light.ttf); -} - -@font-face { - font-family: Raleway-Bold; - src: url(../../../../resources/fonts/Raleway-Bold.ttf), - url(../../../../fonts/Raleway-Bold.ttf), - url(../../../../interface/resources/fonts/Raleway-Bold.ttf), - url(../fonts/Raleway-Bold.ttf); -} - -@font-face { - font-family: Raleway-SemiBold; - src: url(../../../../resources/fonts/Raleway-SemiBold.ttf), - url(../../../../fonts/Raleway-SemiBold.ttf), - url(../../../../interface/resources/fonts/Raleway-SemiBold.ttf), - url(../fonts/Raleway-SemiBold.ttf); -} - -@font-face { - font-family: FiraSans-SemiBold; - src: url(../../../../resources/fonts/FiraSans-SemiBold.ttf), - url(../../../../fonts/FiraSans-SemiBold.ttf), - url(../../../../interface/resources/fonts/FiraSans-SemiBold.ttf), - url(../fonts/FiraSans-SemiBold.ttf); -} - -@font-face { - font-family: AnonymousPro-Regular; - src: url(../../../../resources/fonts/AnonymousPro-Regular.ttf), - url(../../../../fonts/AnonymousPro-Regular.ttf), - url(../../../../interface/resources/fonts/AnonymousPro-Regular.ttf), - url(../fonts/AnonymousPro-Regular.ttf); -} - -@font-face { - font-family: HiFi-Glyphs; - src: url(../../../../resources/fonts/hifi-glyphs.ttf), - url(../../../../fonts/hifi-glyphs.ttf), - url(../../../../interface/resources/fonts/hifi-glyphs.ttf), - url(../fonts/hifi-glyphs.ttf); -} - -* { - margin: 0; - padding: 0; -} - -body { - - color: #afafaf; - background-color: #404040; - font-family: Raleway-Regular; - font-size: 12px; - - -webkit-touch-callout: none; - -webkit-user-select: none; - -khtml-user-select: none; - -moz-user-select: none; - -ms-user-select: none; - user-select: none; - - overflow-x: hidden; - overflow-y: auto; -} - -table { - font-family: FiraSans-SemiBold; - font-size: 15px; - color: #afafaf; - border-collapse: collapse; - width: 100%; - border: 2px solid #575757; - border-radius: 7px; -} - -thead { - font-family: Raleway-Regular; - font-size: 12px; - text-transform: uppercase; - background-color: #1c1c1c; - padding: 1px 0; - border-bottom: 1px solid #575757; - width: 100%; -} - -tbody { - width: 100%; - display: block; -} - -tfoot { - font-family: Raleway-Light; - font-size: 13px; - background-color: #1c1c1c; - border-top: 1px solid #575757; - width: 100%; -} - -tfoot tr { - background-color: #1c1cff; -} - -thead tr { - height: 26px; /* 28px with thead padding */ -} - -thead th { - height: 26px; - background-color: #1c1c1c; - border-right: 1px solid #575757; -} - -thead th:last-child { - border: none; -} - -tbody td { - height: 26px; -} - -tfoot td { - height: 18px; - width: 100%; - background-color: #1c1c1c; - margin-left: 12px; -} - -tr { - width: 100%; - cursor: pointer; -} - -tr:nth-child(odd) { - background-color: #2e2e2e; -} - -tr:nth-child(even) { - background-color: #1c1c1c; -} - -tr:focus { - outline: none; -} - -tr.selected { - color: #000000; - background-color: #00b4ef; -} - -tr.selected + tr.selected { - border-top: 1px solid #2e2e2e; -} - -th { - text-align: center; - word-wrap: nowrap; - white-space: nowrap; - padding-left: 12px; - padding-right: 12px; -} - -td { - overflow: hidden; - text-overflow: clip; - white-space: nowrap; - word-wrap: nowrap; - padding-left: 12px; - padding-right: 12px; -} - -td.hidden { - padding-left: 0; - padding-right: 0; -} - -td.url { - white-space: nowrap; - overflow: hidden; -} - - -input[type="text"], input[type="search"], input[type="number"], textarea { - margin: 0; - padding: 0 12px; - color: #afafaf; - background-color: #252525; - border: none; - font-family: FiraSans-SemiBold; - font-size: 15px; -} - -textarea { - font-family: AnonymousPro-Regular; - font-size: 16px; - padding-top: 5px; - padding-bottom: 5px; - min-height: 64px; - width: 100%; - resize: vertical; -} - -input::-webkit-input-placeholder { - font-style: italic; -} - -input:focus, textarea:focus, button:focus { - color: #fff; - background-color: #000; - outline: 1px solid #00b4ef; - outline-offset: -1px; -} - -input::selection, textarea::selection { - color: #000000; - background-color: #00b4ef; -} - -input.search { - border-radius: 14px; -} - -input.search:focus { - outline: none; - box-sizing: border-box; - height: 26px; - margin-top: 1px; - margin-bottom: 1px; - box-shadow: 0 0 0 1px #00b4ef; -} - -input:disabled, textarea:disabled, .draggable-number.text[disabled="disabled"] { - background-color: #383838; - color: #afafaf; -} - -input[type="text"] { - height: 28px; - width: 100%; -} - -input.multi-diff:not(:focus) + span.multi-diff, -textarea.multi-diff:not(:focus) + span.multi-diff, -.draggable-number.multi-diff>input:not(:focus)+span.multi-diff, -dl>dt.multi-diff:not(:focus) + span.multi-diff { - visibility: visible; - position: absolute; - display: inline-block; - z-index: 2; - top: 7.5px; - left: 20px; - max-width: 50px; - min-width: 10px; - width: 50%; - height: 13px; - background-image: linear-gradient(transparent 0%, transparent 10%, #afafaf 10%, #afafaf 20%, transparent 20%, transparent 45%, #afafaf 45%, #afafaf 55%, transparent 55%, transparent 80%, #afafaf 80%, #afafaf 90%, transparent 90%, transparent 100%); - background-repeat: no-repeat; - pointer-events: none; -} - -input.multi-diff:not(:focus)::-webkit-input-placeholder, input.multi-diff:not(:focus) { - color: transparent; -} - -.draggable-number.multi-diff .text { - color: transparent; -} - -.dropdown > span.multi-diff { - top: 5px; - left: 10px; -} - -.text, .url, .texture, .textarea { - position: relative; -} - -input[type="search"] { - height: 28px; - width: 100%; -} -input[type="search"]::-webkit-search-cancel-button { - -webkit-appearance: none; - height: 20px; - width: 20px; - background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAACXBIWXMAAC4jAAAuIwF4pT92AAAAB3RJTUUH4goNAQIFbBwsbwAAABl0RVh0Q29tbWVudABDcmVhdGVkIHdpdGggR0lNUFeBDhcAAAZfSURBVDgRAVQGq/kAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA9PT0YAwMDBgAAAAD8/Pz5+vr67MrKyv0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAA+Pj4KAgICQgAAAE3///9RAQEBFQAAAAD////pAQEBu/39/ab+/v7BxcXF9gAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAADs7OzMEBASIAQEBRAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP8AAACm+/v7cMXFxewAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAPT09OwEBAagBAQEcAQEBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD///8AAAAA2f///2XCwsLDAAAAAAAAAAABAAAAAAAAAAA9PT0KAwMDt////z4AAAAAAAAAAAEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEBAcIBAQFJvr6+9gAAAAACAAAAAAAAAAAAAABg////PgEBAQAAAAAAS0tLADg4OAAAAAAAAAAAAP///wADAwMAQEBAACEhIQD///8A////AP7+/j76+vpWAAAAAAAAAAACAAAAAD09PQ8CAgJkAQEBAP///wD///8ACgoKAFhYWAAyMjIAAAAAAAICAgBGRkYAT09PABEREQAAAAAAAAAAAAAAAAACAgJwOjo6EAAAAAAEAAAAAAICAg8BAQExAAAAAAEBAQABAQEAsrKyAAoKCgBaWloA9/f3ABsbGwBISEgAtra2AM7OzgACAgIA////AP///wABAQEuBQUFDgAAAPAEAAAAAPz8/BkEBAQAAQEBAAAAAAAAAAAA+vr6AKioqAALCwsAZWVlAAcHBwC/v78Au7u7AAEBAQD///8AAAAAAAAAAAAAAAABAAAAAAAAAAACAAAAAAQEBOgBAQEAAQEBAAEBAQABAQEAAQEBAPz8/ADT09MADg4OAP39/QDQ0NAA/v7+AP///wAAAAAAAAAAAAEBAQABAQEAAQEBAAAAAAACAAAAAAAAAP8AAAD/AAAAAAAAAAAAAAAAAAAAACkpKQBQUFAAx8fHAObm5gBfX18AFxcXAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAP39/fz+/v7z////AP///wD///8AJycnAGFhYQDc3NwApaWlAJaWlgD29vYAZmZmABQUFAACAgIAAQEBAAEBAQABAQH1AAAA/AAAAAACAAAAAPr6+ukBAQGkAAAAAAAAAAABAQEAQEBAAObm5gCmpqYA+fn5APPz8wCdnZ0A////ACwsLAD///8AAAAAAAAAAAD///+k9vb26QAAAAABAAAAAAAAAAA+Pj4uAgICxgAAAAsAAAAAEBAQAPr6+gD29vYAAAAAAAAAAAABAQEAAgICAP///wD+/v4AAAAAAAAAAPL8/Pw/xMTE0AAAAAACAAAAAAAAAAD5+fnV////nQICAgABAQEA8fHxAPX19QABAQEAAAAAAAAAAAD///8A/v7+AP7+/gAAAAAAAAAAAP7+/p36+vrSAAAAAAAAAAADAAAAAAAAAADl5eX/ICAgwQAAAA////8q////BgEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD1/f39mAEBAXrGxsb7AAAAAAAAAAADAAAAAAAAAAAAAAAA4eHh/BgYGLsBAQHDBAQEHAAAACP///8AAQEBAAAAAAAAAAAAAAAA+////7QBAQFu+fn5m8bGxvoAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPz8/Cv7+/iUBAQFMAgICEQICAgD8/PzdAwMDs/j4+OvHx8f5AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA8TUnpZ7EwQgAAAABJRU5ErkJggg==') -} - -input[type="number"] { - position: relative; - height: 28px; - width: 124px; -} -input[type=number] { - padding-right: 3px; -} -input[type=number]::-webkit-inner-spin-button { - opacity: 1.0; - display: block; - position: relative; - width: 10px; - height: 90%; - overflow: hidden; - font-family: HiFi-Glyphs; - font-size: 32px; - color: #afafaf; - cursor: pointer; - background-color: #000000; -} -input[type=number]::-webkit-inner-spin-button:before, -input[type=number]::-webkit-inner-spin-button:after { - position:absolute; - left: -19px; - line-height: 8px; - text-align: center; -} -input[type=number]::-webkit-inner-spin-button:before { - content: "6"; - top: 4px; -} -input[type=number]::-webkit-inner-spin-button:after { - content: "5"; - bottom: 4px; -} - -input[type=number].hover-up::-webkit-inner-spin-button:before, -input[type=number].hover-down::-webkit-inner-spin-button:after { - color: #ffffff; -} - -input[type=range] { - -webkit-appearance: none; - background: #2e2e2e; - height: 1.8rem; - border-radius: 1rem; -} -input[type=range]::-webkit-slider-thumb { - -webkit-appearance:none; - width: 0.6rem; - height: 1.8rem; - padding:0; - margin: 0; - background-color: #696969; - border-radius: 1rem; -} -input[type=range]::-webkit-slider-thumb:hover { - background-color: white; -} -input[type=range]:focus { - outline: none; -} - -input.no-spin::-webkit-outer-spin-button, -input.no-spin::-webkit-inner-spin-button { - display: none; - -webkit-appearance: none; - margin: 0; /* <-- Apparently some margin are still there even though it's hidden */ - padding-right: 12px; -} - -input[type=button], button.hifi-edit-button { - font-family: Raleway-Bold; - font-size: 13px; - text-transform: uppercase; - vertical-align: top; - height: 28px; - min-width: 120px; - padding: 0 18px; - margin-right: 6px; - border-radius: 5px; - border: none; - color: #fff; - background-color: #000; - background: linear-gradient(#343434 20%, #000 100%); - cursor: pointer; -} - -input[type=button].glyph, button.hifi-edit-button.glyph { - font-family: HiFi-Glyphs; - font-size: 20px; - text-transform: none; - min-width: 32px; - padding: 0; -} - -input[type=button].red, button.hifi-edit-button.red { - color: #fff; - background-color: #94132e; - background: linear-gradient(#d42043 20%, #94132e 100%); -} -input[type=button].blue, button.hifi-edit-button.blue { - color: #fff; - background-color: #1080b8; - background: linear-gradient(#00b4ef 20%, #1080b8 100%); -} -input[type=button].white, button.hifi-edit-button.white { - color: #121212; - background-color: #afafaf; - background: linear-gradient(#fff 20%, #afafaf 100%); -} - -input[type=button]:enabled:hover, button.hifi-edit-button:enabled:hover { - background: linear-gradient(#000, #000); - border: none; -} -input[type=button].red:enabled:hover, button.hifi-edit-button.red:enabled:hover { - background: linear-gradient(#d42043, #d42043); - border: none; -} -input[type=button].blue:enabled:hover, button.hifi-edit-button.blue:enabled:hover { - background: linear-gradient(#00b4ef, #00b4ef); - border: none; -} -input[type=button].white:enabled:hover, button.hifi-edit-button.white:enabled:hover { - background: linear-gradient(#fff, #fff); - border: none; -} - -input[type=button]:active, button.hifi-edit-button:active { - background: linear-gradient(#343434, #343434); -} -input[type=button].red:active, button.hifi-edit-button.red:active { - background: linear-gradient(#94132e, #94132e); -} -input[type=button].blue:active, button.hifi-edit-button.blue:active { - background: linear-gradient(#1080b8, #1080b8); -} -input[type=button].white:active, button.hifi-edit-button.white:active { - background: linear-gradient(#afafaf, #afafaf); -} - -input[type=button]:disabled, button.hifi-edit-button:disabled { - color: #252525; - background: linear-gradient(#575757 20%, #252525 100%); -} - -input[type=button][pressed=pressed], button.hifi-edit-button[pressed=pressed] { - color: #00b4ef; -} - -input[type=checkbox] { - display: none; -} -input[type=checkbox] + label { - padding-left: 24px; - background-repeat: no-repeat; - background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA4AAAAOCAYAAAAfSC3RAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAACpSURBVDhPY2xoaGD68+dPMSMjY9L////VgTQjAw4AlH8PxLOPHj1azWxjY1MBVNsBFBfBpwkEgNKcQGwtJyfHyATkF0KEiQdAzYlMQEIUyicFyDD9+/ePgRxMvsb///4zkIOZ/v0HmkAGHginYjGNGAzS+BpdkAj8mun/3//92DyPD//993cG88nTJ4+Zm5p/BSZeJYb/DEJADEzNOPF7hn8Mk69cvVIPAHN5pyfo70F5AAAAAElFTkSuQmCC); - cursor: pointer; -} -input[type=checkbox]:enabled + label:hover { - background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA4AAAAOCAYAAAAfSC3RAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAClSURBVDhPY2hoaGD6//9/6b9//64D8T8gGycASr/7+/dv5/79+1kYgIxKqDjRAKiniRFIv2JgYBAFYlLAE0aQ66AckgDjjx8/yNP44cMH8jS+fPmSPI0PHz4kT+PNmzfJ03jp0iXyNJ46dYo8jYcPHyYnAbxm+vnzZz8wLhlIwd+/f5/BrKSkdExCQuLrnz9/lIBpUAiIQekXF34PTGmTT548WQ8AokXg+rhVtPYAAAAASUVORK5CYII=); -} -input[type=checkbox]:checked + label { - background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA4AAAAOCAYAAAAfSC3RAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAFLSURBVDhPjZK9SgNBFIXvbCaQRDQq7mIhQRPBRisJKcwLWOobaCsExEaxcEEQe0trGysfwg0EwWoDsbFIJUaIBJOwus547saNP3FlPzgzzJxzL5edFbZtG77v7wkhtrXWS9gFRQC/DZ07jnOYKJfL+8ie4n7mvyIGdhpay+VyQuK8y5dPZoHuVtbpZcLi4wjJ1x4t316R9dDgBlsSi8mGu7pJjyJFzVaH+r7iqyHSELSQzVADjS0UgjlDKUUsLzVO98+9kSLGV5qaHXhjU0GWNSxk3hCIwnsfeMNCjTArLmHeUBodoLiE+R+jxuHPUZP4elGE3teonx2S/Q7lJzOUlkYQ+A4/xzyegzNhXmJpwTMXry9IFjcoa84O0r+QXpcK1cugCLREZadyoA19Ergxwf96nKjd1KqlYqmLQ540TUNwItUmRWdu3T36AODjwgpY9xqqAAAAAElFTkSuQmCC); -} -input[type=checkbox]:checked + label:hover { - background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA4AAAAOCAYAAAAfSC3RAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAEySURBVDhPnZLPSsNAEMa/XVPBCE0RhNy0OarP4Av4AD6JB0GwVBA8efBBxHsgh4CQswcRoUIpiIpVAm3zZ5M4szFSbQPBH3xkJvNNZskOer2eLIriKM/ze1JOcS1UHmdZduF5ngEKjr/fN4Z6+oKerwA2gxC4HAFPEWVLsAzgZAvYt3Q6Enw6jg7uBAaTFMNwhpnKdbXCkAJdy8ROu4XrXW2HTJIErHcFDD6nC02Mom8PwymeE2gvS0ZRBBaTlsOXEmdlrfLLOI7Bakrl/zWxCT8T/904f9QW/b06qtrCUdtFCqdjYs2Q2jAPX8c2XQd7Kr/wfV8vwIPs4Ga1ixe5Xrr/YFLTYfKIvWzM6ZtwXZdX7lxXG0L+sxXHcW5t254opRzawQ0S72+dPmjTroIgOP0CQSMt5LDn1T8AAAAASUVORK5CYII=); -} -input.multi-diff[type=checkbox] + label { - background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA4AAAAOCAYAAAAfSC3RAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAFbSURBVDhPY2xoaGD68+dPMSMjY9L////VgTQjAw4AlH8PxLOPHj1azWxjY1MBVNsBFBfBpwkEgNKcQGwtJyfHyALkF4IE34gqM9zU9WT4wicG4mIA1l/fGIyOL2EQeP8EZEAiC5AQBUlcMQ5ieMXIwfDo9SeG73/+gRXDAAsTI4Pd9wdgTVAgw/Tv3z8GEP7Jwctw78M3DE0goPr6BoPludVgdTAM1wgCv//9B9PIQOPNDYaAGxtRNIEw03+gYhDGBtSBNgVc3wiWR8dM//4DTQBidKD++jqD//X1YDlsGMWpMKD26jqD79V1GM5DxihOZQWGntqrawy+V9ZiOA0dw21k/f6JwerzHQbvS2swTMeGGfPz8l8BLRP9KizDwP0WHk+EwGum/3//94M8y/nmEdZAwIb//vs7g/nk6ZPHzE3NvwITrxLDfwYhIAamZpz4PcM/hslXrl6pBwAmfz5iaAlAuAAAAABJRU5ErkJggg==); -} -input.multi-diff[type=checkbox] + label:hover { - background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA4AAAAOCAYAAAAfSC3RAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAFPSURBVDhPjZJBSwJBHMXfrG6rWEkl1MFDGOihDn2JIIrqc3QJunbyFhUkRieD+hYepWteuxctXiJ1Q5xmdmZ3bWZTUHezfvAu/3lv3n+HRblcTrbb7fN+v/8eBMFgFpxz13Gcu3q9bqHb7V4M5/9GhatE3cIsy0o99YBKC3jliCWbBK43gK0MoDI9otfTB/vPBC9Uwu4xMC8IzSOSBsFxIYNqMTGcAIYQAlodD3j5/IqENIc5gqt1P/SNZKhaXR0a5E/5BEcrwH1xEHrGZbiuC604DpZ81AoiPJ/WROM4e4sSt3kaaRopNrg7z1FZdSLmcU2saqrX20lTXC5/RFabFmk2m+GLnBnbWJMOThJv4SV/QRqNBjNNM9UiGeQHdDiejZSSG5TSG71zjnVivyVOKlNLlEqlx+xCds7zvU31G6Z938dvEq4QjLMH27ZPvwHFVYQr3h7uHwAAAABJRU5ErkJggg==); -} - -.rgb.fstuple .color-picker.multi-diff:after { - width: 20px; - height: 20px; - content: ' '; - background: darkgray; - display: flex; - clip-path: polygon(0 0, 0 100%, 100% 100%); -} - -.icon-input input { - position: relative; - padding-left: 36px; -} -.icon-input span { - position: absolute; - left: 6px; - top: -2px; - font-family: HiFi-Glyphs; - font-size: 30px; - color: #afafaf; -} -.icon-input input:focus + span { - color: #ffffff; -} - -.icon { - font-family: HiFi-Glyphs; - color: white; -} - -#property-type-icon { - font-size: 50px; -} - -.selectable { - -webkit-touch-callout: text; - -webkit-user-select: text; - -khtml-user-select: text; - -moz-user-select: text; - -ms-user-select: text; - user-select: text; - cursor: text; -} - -.color-box { - display: inline-block; - width: 15pt; - height: 15pt; - border: 0.75pt solid black; - margin: 1.5pt; - cursor: pointer; -} - -.color-box.highlight { - width: 13.5pt; - height: 13.5pt; - border: 1.5pt solid black; -} - -#properties-list { - display: flex; - flex-direction: column; - - margin-top: 16px; -} - -#properties-list .fieldset { - position: relative; - /* 0.1px on the top is to prevent margin collapsing between this and it's first child */ - margin: 0 -21px 21px -21px; - padding: 0.1px 21px 0 21px; - border: none; - border-top: 1px rgb(90,90,90) solid; - box-shadow: 0 -1px 0 rgb(37,37,37); -} - -#properties-list .fieldset.fstuple, #properties-list .fieldset.fsrow { - margin-top: 21px; - border: none; - box-shadow: none; -} - -#properties-list > .fieldset[data-collapsed="true"] + .fieldset { - margin-top: 0; -} - -#properties-list > .fieldset[data-collapsed="true"] > *:not(div.legend) { - display: none !important; -} - -.section-header { - padding: 0 16px; - border-top: 1px rgb(90,90,90) solid; - box-shadow: 1px -1px 0 rgb(37,37,37); - border-bottom: 1px solid rgb(37, 37, 37); -} - -div.section-header, hr { - display: flex; - flex-flow: row nowrap; - padding: 10px 16px; - font-family: Raleway-Regular; - font-size: 12px; - color: #afafaf; - height: 28px; - text-transform: uppercase; - outline: none; - margin-bottom: 10px; - align-items: center; -} - -.section.minor { - margin: 0 21px; - box-shadow: 1px -1px 0 rgb(37,37,37); - border-left: 1px solid #575757; -} - -.container.property { - padding: 0 16px; -} - -.stretch { - width: 100%; -} - -div.section-header .label { - width: 100%; -} - -.section.minor div.section-header { - border-right: 0; -} - -div.section[collapsed="true"] > .container { - display: none; -} - -div.section[collapsed="true"], div.section[collapsed="true"] > .section-header { - margin-bottom: 0; -} - -.section.major { - margin-bottom: 20px; -} - -.section.minor.last { - margin-bottom: 20px; - border-bottom: 1px solid rgb(37,37,37); -} - -.section-header { - background-color: #373737; -} - - -.section-header span { - font-size: 30px; - font-family: HiFi-Glyphs; -} - -.triple-label { - text-transform: uppercase; - text-align: center; - padding: 6px 0; - cursor: default; -} - -.triple-item { - margin-right: 10px; -} - -.triple-item.rgb.fstuple { - display: block !important; -} - -.section-header[collapsed="true"] { - margin-bottom: -21px; -} - -#properties-list .sub-section-header { - border-top: none; - box-shadow: none; - margin-top: 8px; -} - -.sub-section-header + .property { - margin-top: 0; -} - -hr { - border: none; - padding-top: 2px; -} - -.property { - min-height: 28px; -} - -.property.checkbox { - width: auto; -} - -span.indented { - padding-left: 16px; -} - -.property label, .number label { - display: table-cell; - vertical-align: middle; - font-family: Raleway-SemiBold; - font-size: 14px; -} -.property label .unit, .number label .unit { - margin-left: 8px; - font-family: Raleway-Light; - font-size: 13px; -} - -.property div.legend, .number div.legend { - display: table-cell; - vertical-align: middle; - font-family: Raleway-SemiBold; - font-size: 14px; -} -.property div.legend .unit, .number div.legend .unit { - margin-left: 8px; - font-family: Raleway-Light; - font-size: 13px; -} - -.value { - display: block; - min-height: 18px; -} -.value label { - display: inline-block; - vertical-align: top; -} -.value div.legend { - display: inline-block; - vertical-align: top; - width: 48px; -} -.value span { - font-size: 15px; - margin-right: 4px; -} - -#placeholder-property-type { - display: flex; - align-items: center; - width: auto; - margin-right: 20px; -} - -#placeholder-property-locked { - margin-left: 6px; -} - -.checkbox + .checkbox { - margin-top: 0; -} - -.checkbox-sub-props { - margin-top: 18px; -} - -.property .number { - float: left; -} -.property .number + .number { - margin-left: 10px; -} - -.property.range label{ - padding-bottom: 3px; -} -.property.range input[type=number]{ - margin-left: 0.8rem; - width: 5.4rem; - height: 1.8rem; -} - -.dropdown { - position: relative; - margin-bottom: -17px; -} - -.dropdown select { - clear: both; -} - -.dropdown dl { - clear: both; - cursor: pointer; - font-family: FiraSans-SemiBold; - font-size: 15px; - width: 292px; - height: 28px; - padding: 0 28px 0 12px; - color: #afafaf; - background: #575757; - position: relative; - display: flex; - align-items: center; -} - -.dropdown dl[dropped="true"] { - color: #404040; - background: linear-gradient(#afafaf, #afafaf); - z-index: 998; -} - -.dropdown dt { - height: 100%; - box-sizing: border-box; - border-right: 1px solid #121212; - width: 100%; -} -.dropdown dt:hover { - color: #404040; -} -.dropdown dt:focus { - outline: none; -} -.dropdown dt span:first-child { - display: inline-block; - position: relative; - top: 5px; -} -.dropdown dt span:last-child { - font-family: HiFi-Glyphs; - font-size: 42px; - float: right; - margin-right: -48px; - position: relative; - left: -12px; - top: -9px; -} - -.dropdown dd { - position: absolute; - top: 28px; - left: 3px; - display: none; -} -.dropdown dl[dropped="true"] dd { - display: block; -} - -.dropdown li { - list-style-type: none; - padding: 3px 0 1px 12px; - width: 320px; - height: auto; - font-family: FiraSans-SemiBold; - font-size: 15px; - color: #404040; - background-color: #afafaf; - z-index: 999; -} -.dropdown li:hover { - background-color: #00b4ef; -} - -.dropdown dl[disabled="disabled"], .dropdown dl[disabled="disabled"][dropped="true"] { - color: #252525; - background: linear-gradient(#575757 20%, #252525 100%); -} -.dropdown dl[disabled="disabled"] dd { - display: none; -} -.dropdown dl[disabled="disabled"] dt:hover { - color: #252525; -} - -.multiselect-box { - position: absolute; -} -.multiselect-box select { - font-family: FiraSans-SemiBold; - font-size: 15px; - color: #afafaf; - background-color: #252525; - border: none; - text-align-last: center; -} -.over-select { - position: absolute; - left: 0; - right: 0; - top: 0; - bottom: 0; -} -.multiselect-options { - position: absolute; - display: none; - border: none; -} -.multiselect-options span { - font-family: hifi-glyphs; - font-size: 13px; - color: #000000; -} -.multiselect-options label { - z-index: 2; - display: block; - font-family: FiraSans-SemiBold; - font-size: 11px; - color: #000000; - background-color: #afafaf; -} -.multiselect-options label:hover { - background-color: #1e90ff; -} -.multiselect-options input[type=checkbox] + label { - background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACwAAAAsCAYAAAAehFoBAAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAC4jAAAuIwF4pT92AAAAB3RJTUUH4goSADUOYnF4LQAAABl0RVh0Q29tbWVudABDcmVhdGVkIHdpdGggR0lNUFeBDhcAAAIMSURBVFjD7ZmxkqowFIZ/7mwJPen1AezV3t6hFvrQhweAHvrQ8wL2xt4HwD7ppd+tvHOvu0gCYdEZTsmAfpNzzpcTcAB84o3iD94sZuCx4+Pxwvl8dl4JcL1ef84lMQPPwBZDSgkp5XsASylBKUUYhhBCvDbw7XYDpRRKKTRNA8YYOOevC5ymKZRS/13jnHdCTwLMOW8tAc45GGNomuY1gKuq6lxFIQQopdMDXy4X5HmudW8URdMCSynBGNOG3Ww20wHf9dVWl4+wbav7a8CMsW9G+Cm22+1T2F8BzvMc1+u18z5CCJIkseNhKSX2+z2qqjLWl84zhBAURQHXde0A31Oa57nWbqSrLwDwPA9FUcD3fTtb82NKu8QOAHVda+srSRJt2E7gtpQKIXA4HH6csmzpyxj4dDo9TalSCpRS1HX9TV86RujSlxGwlBJpmnY+rJRCGIZ/s2BTX9qnZgBwHAee52mJ/l7nx+PRqr6MVtj3fZRlaVRf/5aGDX0Z17DrusiyrHfqhuqrt9aiKEIcx4OBTfU1aOMIggBlWYIQ0utP+uhr8CyxXC5RFIUxdBAE1srKePgxbcbVamWlnAZNa7rNSAhBlmWv8yLlWTPa0Nco83BbM2ZZZsUIowzwj80YxzEWi8VoB4IPGz9yb0YhBHa73agnGGtHJNd1R4ed9FVV33Awf6ebgd8b+Av9A/rq6s3hjgAAAABJRU5ErkJggg=='); - background-size: 11px 11px; - background-position: top 5px left 14px; -} -.multiselect-options input[type=checkbox]:enabled + label:hover { - background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACwAAAAsCAYAAAAehFoBAAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAC4jAAAuIwF4pT92AAAAB3RJTUUH4goSADUOYnF4LQAAABl0RVh0Q29tbWVudABDcmVhdGVkIHdpdGggR0lNUFeBDhcAAAIMSURBVFjD7ZmxkqowFIZ/7mwJPen1AezV3t6hFvrQhweAHvrQ8wL2xt4HwD7ppd+tvHOvu0gCYdEZTsmAfpNzzpcTcAB84o3iD94sZuCx4+Pxwvl8dl4JcL1ef84lMQPPwBZDSgkp5XsASylBKUUYhhBCvDbw7XYDpRRKKTRNA8YYOOevC5ymKZRS/13jnHdCTwLMOW8tAc45GGNomuY1gKuq6lxFIQQopdMDXy4X5HmudW8URdMCSynBGNOG3Ww20wHf9dVWl4+wbav7a8CMsW9G+Cm22+1T2F8BzvMc1+u18z5CCJIkseNhKSX2+z2qqjLWl84zhBAURQHXde0A31Oa57nWbqSrLwDwPA9FUcD3fTtb82NKu8QOAHVda+srSRJt2E7gtpQKIXA4HH6csmzpyxj4dDo9TalSCpRS1HX9TV86RujSlxGwlBJpmnY+rJRCGIZ/s2BTX9qnZgBwHAee52mJ/l7nx+PRqr6MVtj3fZRlaVRf/5aGDX0Z17DrusiyrHfqhuqrt9aiKEIcx4OBTfU1aOMIggBlWYIQ0utP+uhr8CyxXC5RFIUxdBAE1srKePgxbcbVamWlnAZNa7rNSAhBlmWv8yLlWTPa0Nco83BbM2ZZZsUIowzwj80YxzEWi8VoB4IPGz9yb0YhBHa73agnGGtHJNd1R4ed9FVV33Awf6ebgd8b+Av9A/rq6s3hjgAAAABJRU5ErkJggg=='); -} -.multiselect-options input[type=checkbox]:checked + label { - background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACwAAAAsCAYAAAAehFoBAAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAC4jAAAuIwF4pT92AAAAB3RJTUUH4goSADMveELP9QAAABl0RVh0Q29tbWVudABDcmVhdGVkIHdpdGggR0lNUFeBDhcAAAIqSURBVFjD7ZmxkqowFIb/7GwJPfT6APZib+9QC33o4QGghz70vIC9sfcBsE966bPNWlxnlQTDRWc4JUT4hpPz5SQSAAofFF/4sJiBx47v+wun04m8E+B6vVbzlJiBZ2CLIYRQQgj1EcBCCEUpRRRF4Jyrtwa+Xq+glEJKia7rkKYpGGPqbYHzPFdSyn+uMcZ6oScBZowpzvmje0jTVHVd9x7ATdMoxtjTMZxzUErV5MDn81mVZak1No7jab+wEEKlaaoNGwQBmQz4pq9H8/IeNo5jMmnRpWmKeyP8FZvN5insfwEuy1JdLpfecb7vI8uy3tb2Szelu91ONU1jtP9jjKmmabRgq6qC4zh2VrpbSsuy1FqNdPUFAK7roqoqeJ6ntXH4Mk1pn9gBoG1bbX1lWaYN2wv8KKWcc+z3+z+7LFv6MgY+Ho9PUyqlBKUUbduqe33pGKFPX0bAQgiV53nvj6WUiKIIt2K0qS/tXTMAEELguq6W6H/nOQ6Hg1V9GX1hz/NIXdckCALtB7Vta1VfxnPYcRwURUEeNSGmYaqvwVqL45gkSfIysKm+Xlo4wjAkdV3D9/1BLxmir5d7ieVySaqqMoYOw3CwEV5ufkyLcbVaIUkSq2d1xt2abjH6vo+iKKwfLA5uL58Vow19jdIPPyrGoiisGGGUBv6+GJMkwWKxGO2M+dvGQ36LEZxztd1uRz0Qt7ZFchwHY8NOelQ1NAjm/+lm4M8G/gH2zx33BSr7jAAAAABJRU5ErkJggg=='); -} -.multiselect-options input[type=checkbox]:checked + label:hover { - background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACwAAAAsCAYAAAAehFoBAAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAC4jAAAuIwF4pT92AAAAB3RJTUUH4goSADMveELP9QAAABl0RVh0Q29tbWVudABDcmVhdGVkIHdpdGggR0lNUFeBDhcAAAIqSURBVFjD7ZmxkqowFIb/7GwJPfT6APZib+9QC33o4QGghz70vIC9sfcBsE966bPNWlxnlQTDRWc4JUT4hpPz5SQSAAofFF/4sJiBx47v+wun04m8E+B6vVbzlJiBZ2CLIYRQQgj1EcBCCEUpRRRF4Jyrtwa+Xq+glEJKia7rkKYpGGPqbYHzPFdSyn+uMcZ6oScBZowpzvmje0jTVHVd9x7ATdMoxtjTMZxzUErV5MDn81mVZak1No7jab+wEEKlaaoNGwQBmQz4pq9H8/IeNo5jMmnRpWmKeyP8FZvN5insfwEuy1JdLpfecb7vI8uy3tb2Szelu91ONU1jtP9jjKmmabRgq6qC4zh2VrpbSsuy1FqNdPUFAK7roqoqeJ6ntXH4Mk1pn9gBoG1bbX1lWaYN2wv8KKWcc+z3+z+7LFv6MgY+Ho9PUyqlBKUUbduqe33pGKFPX0bAQgiV53nvj6WUiKIIt2K0qS/tXTMAEELguq6W6H/nOQ6Hg1V9GX1hz/NIXdckCALtB7Vta1VfxnPYcRwURUEeNSGmYaqvwVqL45gkSfIysKm+Xlo4wjAkdV3D9/1BLxmir5d7ieVySaqqMoYOw3CwEV5ufkyLcbVaIUkSq2d1xt2abjH6vo+iKKwfLA5uL58Vow19jdIPPyrGoiisGGGUBv6+GJMkwWKxGO2M+dvGQ36LEZxztd1uRz0Qt7ZFchwHY8NOelQ1NAjm/+lm4M8G/gH2zx33BSr7jAAAAABJRU5ErkJggg=='); -} - -.dynamic-multiselect { - position: relative; - top: 6px; - padding-bottom: 6px; -} - -div.refresh { - box-sizing: border-box; - padding-right: 44px; -} -div.refresh input[type="button"] { - float: right; - margin-right: -44px; - position: relative; - left: 10px; -} - -.color-picker { - box-sizing: border-box; - width: 26px; - height: 26px; - border: 3px solid #2B2B2B; - cursor: pointer; -} -.color-picker:focus { - outline: none; -} -.color-picker[active="true"] { - border-color: #000; -} - -.color-picker[disabled="disabled"] { - border-color: #afafaf; -} - -.colpick { - z-index: 3; -} -.colpick[disabled="disabled"] { - display: none !important; -} - -.rgb label { - float: left; - margin-top: 10px; - margin-left: 21px; -} -.rgb label + * { - clear: both; -} - -.rgb div.legend { - float: left; - margin-top: 10px; - margin-left: 21px; -} -.rgb div.legend + * { - clear: both; -} - -.draggable-number-container { - flex: 0 1 124px; -} -.draggable-number { - position: relative; - height: 28px; - flex: 0 1 124px; - display: flex; - align-items: center; -} - -.draggable-number .text { - position: absolute; - display: inline-block; - color: #afafaf; - background-color: #252525; - font-family: FiraSans-SemiBold; - font-size: 15px; - margin: 0; - padding: 0 16px; - height: 28px; - width: 100%; - line-height: 2; - box-sizing: border-box; - z-index: 1; -} -.draggable-number .text:hover { - cursor: ew-resize; -} -.draggable-number .left-arrow, .draggable-number .right-arrow { - position: absolute; - display: inline-block; - font-family: HiFi-Glyphs; - font-size: 20px; - z-index: 2; -} -.draggable-number span:hover { - cursor: default; -} -.draggable-number .left-arrow { - top: 3px; - left: 0; - transform: rotate(180deg); -} -.draggable-number .right-arrow { - top: 3px; - right: 0; -} -.draggable-number input[type=number] { - position: absolute; - right: 0; - width: 100%; -} -.draggable-number input[type=button] { - position: absolute; - top: 0; -} -.draggable-number input::-webkit-inner-spin-button { - -webkit-appearance: none; - visibility: hidden; -} -.draggable-number.fstuple { - height: 28px; - width: 124px; - left: 12px; -} -.draggable-number.fstuple + .draggable-number.fstuple { - margin-left: 28px; -} -.draggable-number.fstuple input { - right: -10px; -} -.draggable-number.fstuple .sublabel { - position: absolute; - top: 6px; - left: -16px; - font-family: FiraSans-SemiBold; - font-size: 15px; -} - -.rect .rect-row { - margin-bottom: 8px; -} - -.row .property { - width: auto; - display: inline-block; - margin-right: 6px; -} -.row .property:last-child { - margin-right: 0; -} -.row .property input { - clear: both; - float: left; -} - -.property.texture { - display: block; -} -.property.texture input { - margin: 0.4rem 0; -} -.texture-image img { - padding: 0; - margin: 0; - width: 100%; - height: 100%; - display: none; -} -.texture-image { - display: block; - position: relative; - background-repeat: no-repeat; - background-position: center; - background-size: 100% 100%; - margin-top: 0.4rem; - height:128px; - width: 128px; - background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAIAAAACACAYAAADDPmHLAAAACXBIWXMAAAsTAAALEwEAmpwYAAAKT2lDQ1BQaG90b3Nob3AgSUNDIHByb2ZpbGUAAHjanVNnVFPpFj333vRCS4iAlEtvUhUIIFJCi4AUkSYqIQkQSoghodkVUcERRUUEG8igiAOOjoCMFVEsDIoK2AfkIaKOg6OIisr74Xuja9a89+bN/rXXPues852zzwfACAyWSDNRNYAMqUIeEeCDx8TG4eQuQIEKJHAAEAizZCFz/SMBAPh+PDwrIsAHvgABeNMLCADATZvAMByH/w/qQplcAYCEAcB0kThLCIAUAEB6jkKmAEBGAYCdmCZTAKAEAGDLY2LjAFAtAGAnf+bTAICd+Jl7AQBblCEVAaCRACATZYhEAGg7AKzPVopFAFgwABRmS8Q5ANgtADBJV2ZIALC3AMDOEAuyAAgMADBRiIUpAAR7AGDIIyN4AISZABRG8lc88SuuEOcqAAB4mbI8uSQ5RYFbCC1xB1dXLh4ozkkXKxQ2YQJhmkAuwnmZGTKBNA/g88wAAKCRFRHgg/P9eM4Ors7ONo62Dl8t6r8G/yJiYuP+5c+rcEAAAOF0ftH+LC+zGoA7BoBt/qIl7gRoXgugdfeLZrIPQLUAoOnaV/Nw+H48PEWhkLnZ2eXk5NhKxEJbYcpXff5nwl/AV/1s+X48/Pf14L7iJIEyXYFHBPjgwsz0TKUcz5IJhGLc5o9H/LcL//wd0yLESWK5WCoU41EScY5EmozzMqUiiUKSKcUl0v9k4t8s+wM+3zUAsGo+AXuRLahdYwP2SycQWHTA4vcAAPK7b8HUKAgDgGiD4c93/+8//UegJQCAZkmScQAAXkQkLlTKsz/HCAAARKCBKrBBG/TBGCzABhzBBdzBC/xgNoRCJMTCQhBCCmSAHHJgKayCQiiGzbAdKmAv1EAdNMBRaIaTcA4uwlW4Dj1wD/phCJ7BKLyBCQRByAgTYSHaiAFiilgjjggXmYX4IcFIBBKLJCDJiBRRIkuRNUgxUopUIFVIHfI9cgI5h1xGupE7yAAygvyGvEcxlIGyUT3UDLVDuag3GoRGogvQZHQxmo8WoJvQcrQaPYw2oefQq2gP2o8+Q8cwwOgYBzPEbDAuxsNCsTgsCZNjy7EirAyrxhqwVqwDu4n1Y8+xdwQSgUXACTYEd0IgYR5BSFhMWE7YSKggHCQ0EdoJNwkDhFHCJyKTqEu0JroR+cQYYjIxh1hILCPWEo8TLxB7iEPENyQSiUMyJ7mQAkmxpFTSEtJG0m5SI+ksqZs0SBojk8naZGuyBzmULCAryIXkneTD5DPkG+Qh8lsKnWJAcaT4U+IoUspqShnlEOU05QZlmDJBVaOaUt2ooVQRNY9aQq2htlKvUYeoEzR1mjnNgxZJS6WtopXTGmgXaPdpr+h0uhHdlR5Ol9BX0svpR+iX6AP0dwwNhhWDx4hnKBmbGAcYZxl3GK+YTKYZ04sZx1QwNzHrmOeZD5lvVVgqtip8FZHKCpVKlSaVGyovVKmqpqreqgtV81XLVI+pXlN9rkZVM1PjqQnUlqtVqp1Q61MbU2epO6iHqmeob1Q/pH5Z/YkGWcNMw09DpFGgsV/jvMYgC2MZs3gsIWsNq4Z1gTXEJrHN2Xx2KruY/R27iz2qqaE5QzNKM1ezUvOUZj8H45hx+Jx0TgnnKKeX836K3hTvKeIpG6Y0TLkxZVxrqpaXllirSKtRq0frvTau7aedpr1Fu1n7gQ5Bx0onXCdHZ4/OBZ3nU9lT3acKpxZNPTr1ri6qa6UbobtEd79up+6Ynr5egJ5Mb6feeb3n+hx9L/1U/W36p/VHDFgGswwkBtsMzhg8xTVxbzwdL8fb8VFDXcNAQ6VhlWGX4YSRudE8o9VGjUYPjGnGXOMk423GbcajJgYmISZLTepN7ppSTbmmKaY7TDtMx83MzaLN1pk1mz0x1zLnm+eb15vft2BaeFostqi2uGVJsuRaplnutrxuhVo5WaVYVVpds0atna0l1rutu6cRp7lOk06rntZnw7Dxtsm2qbcZsOXYBtuutm22fWFnYhdnt8Wuw+6TvZN9un2N/T0HDYfZDqsdWh1+c7RyFDpWOt6azpzuP33F9JbpL2dYzxDP2DPjthPLKcRpnVOb00dnF2e5c4PziIuJS4LLLpc+Lpsbxt3IveRKdPVxXeF60vWdm7Obwu2o26/uNu5p7ofcn8w0nymeWTNz0MPIQ+BR5dE/C5+VMGvfrH5PQ0+BZ7XnIy9jL5FXrdewt6V3qvdh7xc+9j5yn+M+4zw33jLeWV/MN8C3yLfLT8Nvnl+F30N/I/9k/3r/0QCngCUBZwOJgUGBWwL7+Hp8Ib+OPzrbZfay2e1BjKC5QRVBj4KtguXBrSFoyOyQrSH355jOkc5pDoVQfujW0Adh5mGLw34MJ4WHhVeGP45wiFga0TGXNXfR3ENz30T6RJZE3ptnMU85ry1KNSo+qi5qPNo3ujS6P8YuZlnM1VidWElsSxw5LiquNm5svt/87fOH4p3iC+N7F5gvyF1weaHOwvSFpxapLhIsOpZATIhOOJTwQRAqqBaMJfITdyWOCnnCHcJnIi/RNtGI2ENcKh5O8kgqTXqS7JG8NXkkxTOlLOW5hCepkLxMDUzdmzqeFpp2IG0yPTq9MYOSkZBxQqohTZO2Z+pn5mZ2y6xlhbL+xW6Lty8elQfJa7OQrAVZLQq2QqboVFoo1yoHsmdlV2a/zYnKOZarnivN7cyzytuQN5zvn//tEsIS4ZK2pYZLVy0dWOa9rGo5sjxxedsK4xUFK4ZWBqw8uIq2Km3VT6vtV5eufr0mek1rgV7ByoLBtQFr6wtVCuWFfevc1+1dT1gvWd+1YfqGnRs+FYmKrhTbF5cVf9go3HjlG4dvyr+Z3JS0qavEuWTPZtJm6ebeLZ5bDpaql+aXDm4N2dq0Dd9WtO319kXbL5fNKNu7g7ZDuaO/PLi8ZafJzs07P1SkVPRU+lQ27tLdtWHX+G7R7ht7vPY07NXbW7z3/T7JvttVAVVN1WbVZftJ+7P3P66Jqun4lvttXa1ObXHtxwPSA/0HIw6217nU1R3SPVRSj9Yr60cOxx++/p3vdy0NNg1VjZzG4iNwRHnk6fcJ3/ceDTradox7rOEH0x92HWcdL2pCmvKaRptTmvtbYlu6T8w+0dbq3nr8R9sfD5w0PFl5SvNUyWna6YLTk2fyz4ydlZ19fi753GDborZ752PO32oPb++6EHTh0kX/i+c7vDvOXPK4dPKy2+UTV7hXmq86X23qdOo8/pPTT8e7nLuarrlca7nuer21e2b36RueN87d9L158Rb/1tWeOT3dvfN6b/fF9/XfFt1+cif9zsu72Xcn7q28T7xf9EDtQdlD3YfVP1v+3Njv3H9qwHeg89HcR/cGhYPP/pH1jw9DBY+Zj8uGDYbrnjg+OTniP3L96fynQ89kzyaeF/6i/suuFxYvfvjV69fO0ZjRoZfyl5O/bXyl/erA6xmv28bCxh6+yXgzMV70VvvtwXfcdx3vo98PT+R8IH8o/2j5sfVT0Kf7kxmTk/8EA5jz/GMzLdsAAAAgY0hSTQAAeiUAAICDAAD5/wAAgOkAAHUwAADqYAAAOpgAABdvkl/FRgAABhNJREFUeNrsnVFy4joQRVsSCwAqBMwqsrRsIavMEkICoeAf2+8j1R5ZGDBgpLzoUDVVmTT2dc8It/paOpi3t7faOSciImVZyn6/l6qqRETEWivj8VistYPFd7ud1HUtIiLGGBmPx5JKX0RkMplIzvmPnHNijBERaS7Ef1lrB40bY1oXgH5a/ZH+8P7+LlVVycfHR/MGa60URdGcYOi4MUaKomhGaGx9EZHlcplMP2X+Ly8vPwOgLEtxzklVVVJVVfOznqAsy9YFXhuvqqq5AF/Lj+srtr7+LpV+yvz1mNF+vxcRkdVqJdZaeXp6ap1ws9m0TjibzVoj6lJ8vV6fjJdlKev1ujViU+j7t8tc8p9Op1KWpYw06L9JL0Av0r9l+jXl3nhd11JV1VE8tn5YM3PI3xjzoxVOGvyDU7zQj6s/0tGmI++amtNV087F9Wf/FnVPzRtCXz8RdV1nlb/efUbaJy4Wi0FqzjU1yRgjs9ls0Jp3jb6IyPPzczL9lPkvFot/dwCtB/om/x9oyJoXxps65NW8mPpdNTeX/JtBEtYE/+AUL/Tj6g/qA3TVnD41a6g++Bp9rYOp9FPnH80HOBcvy1I2m81D++BL+o/2AX5r/vgA+AD4AOif8AH8EdpVcy71sX3jWp/8W2AKff/TkUv+Oufr9AF0YuKc66xJ18T7eNP3nP9WfZ0EzufzJPqp8y+KQuq67vYBdETqCDpVU/rEw5oUnr+rD46h73/qUuinzh8fAP22D6AjxznXcqq6akrf+KmaFB6vf4+t7/sAelfIJf/GB9jtdmKMkdVq1dQM3zg4VVNU/NY+1Bgjh8Oh6YM1+dj6X19fzXwgp/wbH0DFtS7oyf0RdKqmhPFr+1RdseKfP7a+Px/IKX98APTbPoDOJrv60L417d54TH3V8lfS5pT/yfUA6/X6qOZcqkm3xrUm6X9CTH3fB0ihnzr/Ix9A/3T1qbfWpGvjMfX9T0UK/dT54wOg/88H8EfGPTVr6D740frhLDmn/Hv5AH1qku9t31KTzh3/aP1LPsBfzr+XDxCO0K6ack/N6qp5MfUv+QB/Of/ePsCQfWmfc6EfV3/kjzZrrRwOh9YtKHSm/LjOH3yrMTzej4c1y//51PHoP0a/tR7AOSdFURw9rz5VU049zw7jl2qWrosP++BY+iI/+wJS6afMv9kXoA6gvimsieHzZr/m6MTp3PPuc3G9SP95OPpx9JtOgT4cHwA+QCJ9+ADwAeADsC+AfQHo/4b1APAB4APAB4APAB8APgB9OD4AfAD4AFFqEnwA+AD4APgA6P86HwA+AHyAZhIBHwA+AHwA+AD04X/eB4APAB8APgB8APgA8AHow/P0AeADwAeADwAfAD4AfAD68Px8APgA8AHgA8AHgA8AH0DO70/v6lHvjaOfVn8U/iLcXx5OUML96X49vRTX3/nPw9FPo9+sB5hMJuKck+VyeVRTrLWtdfNdcf95eldNCuOfn5+tSYy/Pz+2voi0fICc8p/P5z93gJAPEN4+wufN4evaePj99eH+ePTj6p/1Abp60kt9Ksf/v46HDwAfAD6A/6gUPgD7AtgXwPP4DNcDwAeADwAfAD4AfAD4ADyPz289AHyA+Pqp84cPIPAB8AHwAfAB8AHgA7Q+HfAB4APAB4APAB+APjw3HwA+AHwA+ADwAeADwAegD8/TB4APAB8APgB8APgA8AHow/PzAeADwAeADwAfAD4AfACJ//316KfVH/mjLeb31+vx/kWhH0+/tR7AOSdFUUT9/nq9oK4+OJa+iLT25+eUf7MvIOQDxPr+en2F++PRj6PfdAr04fgA8AES6cMHgA8AH4B9AewLQP83rAeADwAfAD4AfAD4APAB6MPxAeADwAeIUpPgA8AHwAfAB0D/1/kA8AHgAzSTCPgA8AHgA8AHoA//8z4AfAD4APAB4APAB4APQB+epw8AHwA+AHwA+ADwAeAD0Ifn5wPAB4APAB8APgB8gBz5AOb19bX2TYLpdNpqQ7bbbctJGjJeVZVst9vWLSu2/vf3t+Sc/yicFIRr0C7Fu76f/lw8XBePflr9/wYAqWwWUSLcO54AAAAASUVORK5CYII='); -} -.texture-image.no-texture { - background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAIAAAACACAYAAADDPmHLAAAACXBIWXMAAAsTAAALEwEAmpwYAAAKT2lDQ1BQaG90b3Nob3AgSUNDIHByb2ZpbGUAAHjanVNnVFPpFj333vRCS4iAlEtvUhUIIFJCi4AUkSYqIQkQSoghodkVUcERRUUEG8igiAOOjoCMFVEsDIoK2AfkIaKOg6OIisr74Xuja9a89+bN/rXXPues852zzwfACAyWSDNRNYAMqUIeEeCDx8TG4eQuQIEKJHAAEAizZCFz/SMBAPh+PDwrIsAHvgABeNMLCADATZvAMByH/w/qQplcAYCEAcB0kThLCIAUAEB6jkKmAEBGAYCdmCZTAKAEAGDLY2LjAFAtAGAnf+bTAICd+Jl7AQBblCEVAaCRACATZYhEAGg7AKzPVopFAFgwABRmS8Q5ANgtADBJV2ZIALC3AMDOEAuyAAgMADBRiIUpAAR7AGDIIyN4AISZABRG8lc88SuuEOcqAAB4mbI8uSQ5RYFbCC1xB1dXLh4ozkkXKxQ2YQJhmkAuwnmZGTKBNA/g88wAAKCRFRHgg/P9eM4Ors7ONo62Dl8t6r8G/yJiYuP+5c+rcEAAAOF0ftH+LC+zGoA7BoBt/qIl7gRoXgugdfeLZrIPQLUAoOnaV/Nw+H48PEWhkLnZ2eXk5NhKxEJbYcpXff5nwl/AV/1s+X48/Pf14L7iJIEyXYFHBPjgwsz0TKUcz5IJhGLc5o9H/LcL//wd0yLESWK5WCoU41EScY5EmozzMqUiiUKSKcUl0v9k4t8s+wM+3zUAsGo+AXuRLahdYwP2SycQWHTA4vcAAPK7b8HUKAgDgGiD4c93/+8//UegJQCAZkmScQAAXkQkLlTKsz/HCAAARKCBKrBBG/TBGCzABhzBBdzBC/xgNoRCJMTCQhBCCmSAHHJgKayCQiiGzbAdKmAv1EAdNMBRaIaTcA4uwlW4Dj1wD/phCJ7BKLyBCQRByAgTYSHaiAFiilgjjggXmYX4IcFIBBKLJCDJiBRRIkuRNUgxUopUIFVIHfI9cgI5h1xGupE7yAAygvyGvEcxlIGyUT3UDLVDuag3GoRGogvQZHQxmo8WoJvQcrQaPYw2oefQq2gP2o8+Q8cwwOgYBzPEbDAuxsNCsTgsCZNjy7EirAyrxhqwVqwDu4n1Y8+xdwQSgUXACTYEd0IgYR5BSFhMWE7YSKggHCQ0EdoJNwkDhFHCJyKTqEu0JroR+cQYYjIxh1hILCPWEo8TLxB7iEPENyQSiUMyJ7mQAkmxpFTSEtJG0m5SI+ksqZs0SBojk8naZGuyBzmULCAryIXkneTD5DPkG+Qh8lsKnWJAcaT4U+IoUspqShnlEOU05QZlmDJBVaOaUt2ooVQRNY9aQq2htlKvUYeoEzR1mjnNgxZJS6WtopXTGmgXaPdpr+h0uhHdlR5Ol9BX0svpR+iX6AP0dwwNhhWDx4hnKBmbGAcYZxl3GK+YTKYZ04sZx1QwNzHrmOeZD5lvVVgqtip8FZHKCpVKlSaVGyovVKmqpqreqgtV81XLVI+pXlN9rkZVM1PjqQnUlqtVqp1Q61MbU2epO6iHqmeob1Q/pH5Z/YkGWcNMw09DpFGgsV/jvMYgC2MZs3gsIWsNq4Z1gTXEJrHN2Xx2KruY/R27iz2qqaE5QzNKM1ezUvOUZj8H45hx+Jx0TgnnKKeX836K3hTvKeIpG6Y0TLkxZVxrqpaXllirSKtRq0frvTau7aedpr1Fu1n7gQ5Bx0onXCdHZ4/OBZ3nU9lT3acKpxZNPTr1ri6qa6UbobtEd79up+6Ynr5egJ5Mb6feeb3n+hx9L/1U/W36p/VHDFgGswwkBtsMzhg8xTVxbzwdL8fb8VFDXcNAQ6VhlWGX4YSRudE8o9VGjUYPjGnGXOMk423GbcajJgYmISZLTepN7ppSTbmmKaY7TDtMx83MzaLN1pk1mz0x1zLnm+eb15vft2BaeFostqi2uGVJsuRaplnutrxuhVo5WaVYVVpds0atna0l1rutu6cRp7lOk06rntZnw7Dxtsm2qbcZsOXYBtuutm22fWFnYhdnt8Wuw+6TvZN9un2N/T0HDYfZDqsdWh1+c7RyFDpWOt6azpzuP33F9JbpL2dYzxDP2DPjthPLKcRpnVOb00dnF2e5c4PziIuJS4LLLpc+Lpsbxt3IveRKdPVxXeF60vWdm7Obwu2o26/uNu5p7ofcn8w0nymeWTNz0MPIQ+BR5dE/C5+VMGvfrH5PQ0+BZ7XnIy9jL5FXrdewt6V3qvdh7xc+9j5yn+M+4zw33jLeWV/MN8C3yLfLT8Nvnl+F30N/I/9k/3r/0QCngCUBZwOJgUGBWwL7+Hp8Ib+OPzrbZfay2e1BjKC5QRVBj4KtguXBrSFoyOyQrSH355jOkc5pDoVQfujW0Adh5mGLw34MJ4WHhVeGP45wiFga0TGXNXfR3ENz30T6RJZE3ptnMU85ry1KNSo+qi5qPNo3ujS6P8YuZlnM1VidWElsSxw5LiquNm5svt/87fOH4p3iC+N7F5gvyF1weaHOwvSFpxapLhIsOpZATIhOOJTwQRAqqBaMJfITdyWOCnnCHcJnIi/RNtGI2ENcKh5O8kgqTXqS7JG8NXkkxTOlLOW5hCepkLxMDUzdmzqeFpp2IG0yPTq9MYOSkZBxQqohTZO2Z+pn5mZ2y6xlhbL+xW6Lty8elQfJa7OQrAVZLQq2QqboVFoo1yoHsmdlV2a/zYnKOZarnivN7cyzytuQN5zvn//tEsIS4ZK2pYZLVy0dWOa9rGo5sjxxedsK4xUFK4ZWBqw8uIq2Km3VT6vtV5eufr0mek1rgV7ByoLBtQFr6wtVCuWFfevc1+1dT1gvWd+1YfqGnRs+FYmKrhTbF5cVf9go3HjlG4dvyr+Z3JS0qavEuWTPZtJm6ebeLZ5bDpaql+aXDm4N2dq0Dd9WtO319kXbL5fNKNu7g7ZDuaO/PLi8ZafJzs07P1SkVPRU+lQ27tLdtWHX+G7R7ht7vPY07NXbW7z3/T7JvttVAVVN1WbVZftJ+7P3P66Jqun4lvttXa1ObXHtxwPSA/0HIw6217nU1R3SPVRSj9Yr60cOxx++/p3vdy0NNg1VjZzG4iNwRHnk6fcJ3/ceDTradox7rOEH0x92HWcdL2pCmvKaRptTmvtbYlu6T8w+0dbq3nr8R9sfD5w0PFl5SvNUyWna6YLTk2fyz4ydlZ19fi753GDborZ752PO32oPb++6EHTh0kX/i+c7vDvOXPK4dPKy2+UTV7hXmq86X23qdOo8/pPTT8e7nLuarrlca7nuer21e2b36RueN87d9L158Rb/1tWeOT3dvfN6b/fF9/XfFt1+cif9zsu72Xcn7q28T7xf9EDtQdlD3YfVP1v+3Njv3H9qwHeg89HcR/cGhYPP/pH1jw9DBY+Zj8uGDYbrnjg+OTniP3L96fynQ89kzyaeF/6i/suuFxYvfvjV69fO0ZjRoZfyl5O/bXyl/erA6xmv28bCxh6+yXgzMV70VvvtwXfcdx3vo98PT+R8IH8o/2j5sfVT0Kf7kxmTk/8EA5jz/GMzLdsAAAAgY0hSTQAAeiUAAICDAAD5/wAAgOkAAHUwAADqYAAAOpgAABdvkl/FRgAAB81JREFUeNrsnTGPm0oXht97FWm2Ch2pTEeHpUihsyvTuXO67Ta/IPkr+Qfp3MWdO7Zad0SKZDo6XIWOrTzV9xVXZ8SygGHXG4/t96lW68GGw8vMmZlzDv98+/btfyBXy780wXXzTv74/fs3rXFFfPz4kT0AoQAoAJqAAiAUAKEACAVAKABCARAKgFAAhAIgFAChAAgFQCgAQgEQCoBQAIQCIBQAoQAIBUAoAHLmvDv3C7i7u4PjOMiyDOv1+mC75XKJoiga2wRBAN/34TgOHMdBWZYoigJpmiLPcwrARhzHAQD4vg/P81pvlLRrwvM8zGYz00ZrbY5xHAe+7yPPc9zf36MsSwrAVmazGX78+DHoGM/zsFgsAAB5nmOz2ZgeQimF8XiMMAxNu+VyaQRCH8Ai8jyH4zgIw7D3MUopzOdzAECaplitVk+GB601kiTBz58/obWG4ziIoohOoI38+vULABCGYWd3X2U6nUIphbIsEcdxa7uiKPDw8GCGGtd1KQDbKMsSWZZBKYXJZNLrGN/3zdN/iDRNTdcvx1EAFqGUwmazeeIQduG6LpRSAIAsy3r9hrRjD2BxL5AkiXEI+8wetNa9PXtp13eIoQBOQJIkxmHrcgjlJkov8JKpJwVgIVpr47CFYdh6g/f7/ZM5/9CehgKwmDRNURQFlFKYTqeNN/rx8dH0AH2faBn7KYAzQKZ1QRCYZd0qf/78MX+PRqNe3ymO5W63owBsR9bwZShoGirEq++zeBQEweBZAwVwYh4eHqC1RhAErQ6jOHVdK3yu65qhJE1TDgHn5BDKTW6auxdFYdYOgiDAYrF40k4phTAM8fnzZyilUBRF54rhOfIOF06SJMYPaPt8v99jOp3C8zx4nget9bPZQ5ZlF3fzL0IAZVke9OLv7+/Njl/brCHLMozHY4xGI3z48MH0EEVRIMuyi40H+EdqBbNS6HXBSqGEAiAUAAVAE1AAhAIgFAChAAgFQCgAQgGQq+Eom0GLxeJgGHYVSdCUhM02yrI0qV5hGGIymaAsy9b0LNd1cXt7CwDYbDa98wOA/zKLVquVSQGr/nYTbe2iKDIh53JtZVmiLEvsdjtst9tn5z7EDmfXA3QFXdaTMbvYbrdm568tgkdueJ7njbt3QwJA+8YJ1tsFQQDXdXFzc2N2E0Uwk8kEX758eXbMEDtY2QOsVqtn//v69SsAYL1eH9xK7dNGgjuiKMJ4PH4WmSN7+QBMFu/3798bn1oAzz47NvVrqmYgz2azRpv1scNV+wDVaN969y6JIEmSWBmyJenlIgZbcgvOzgmUqJxqkmY18ldCvGwkz/MntQcogBcgETrVMV98Aptvfh1JTKEAXsBms4HWGp7nYT6fw3Ec5Hlufbi253lQSkFr3VqmhgLoQVmW2G63ZigQx8/2my/FKCR17WLWAV7LfD5vzOFLkqS1W0/T1HT9RVFY5/jNZjMz3ouvorVGHMet9QheYoer7AGq478Y2LaiDTc3N3Bd90megSwG2YQVPcDQ+a/ccK01ttutWSWsetl/i7bfq16TzP1lGFgul0exw9X2AJLGJV3joRXCl3rnXbUDhmQKl2WJ9XoNrbV1vdXZCUCWWqvVQGR8HFIgqmuaKUiCSJcA+nrzWmvzdA/ZN6EAKlTz/eXmA3iSuXOoNEzfBRsA+PTpU+PnUjxSfnvo9/ZNR6cAakjFj2rqd3VtQJ6u1z5h1e+SdYbqdK5aWHLImC0OoFQgpRN4YPoD/LfRVC8C2TQlkhVC3/dfVDG0/l1xHCOKIvi+b572atJoURSdtYnbfAHxV0aj0TP/oY8dzqYH6OscHXK26tO+rqcujmNTIKqtJkDfc0vTFMvl8smu436/R57niOO4NSbh0HfLkFHtpYbY4dgwOfRKYXIooQAIBUAB0AQUAKEACAVAKABCARAKgFAA5Gp4s93AKIrw/v17ExsnFEWB/X6P3W6HLMtaN0+GJkwOad+W2FlPLq3GHFSRdq85h2PYyGoByG6cvJOnHiEryZJSg7e+s1ZNmOyzSza0ffWYJsIwbMzk7Tp+6Dm81kZWC0BoCnSU7dowDE2K12q1alT60EDJYwVWKqUQRdHgPf9jnfMQG52dDyA5fLKnLlGztiB5Bn1eP3fuNvr31IaWZM9jhHIdEwk5G1Jk4hxtdPJZQJZlJrLWlnBpx3FMmrnrup3RReduIyumgXJxtryRUxw4mQXIO4Yv0UZWCMDWN3I2vX7u0mxk1RtDmp6yoQmTbe27kjK7iOMYt7e3CIIA2+22VyLIWyZ5Hrsnsmol0Jac+fo51QtSXJKNrOgBuvLsTrUOUO8FxAP3ff/gTXiLc3irt5aevAdQSpmpja0vZqq+fm4ymfz18i5vaaOTC0DSvapv8rQRmRY6joPxeHwxNjqpAGSpUwx8ikKJQ5AyNFKb4BJsdBIfwPM8BEFgFjXSNG3debMJSUv7GyuWf8tGby6Aaq2c+qvaJce/a3p2ioTJQ73A3d3di6aBbef8WhtZKQDJ6K1fTJ7neHx8PFjWTcbbvvPePm8QbVtc6ft/+UwKUdfbDT3n19roGDA59EphciihAAgFQAHQBBQAoQAIBUAoAEIBEAqAUACEAiAUAKEACAVAKABCARAKgFAAhAIgFAChAAgFQC4CkxgiceKEPQC5Iv4/APgB2O7x8IXXAAAAAElFTkSuQmCC'); -} -.texture-image.no-preview { - background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAIAAAACACAIAAABMXPacAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAA8sSURBVHhe7Z3rbxXFG8d7B9SWthRabLmIYlHkIEXKJdXYBEXxHtEXprwxxsR3/jG+8PLCaDDGeAkmKsTEoCUVKoVCA6WNtLS2UEUKBSy0tKW/D+eZM9nu7tmz55z+mC2Zz4tl9tk5c2bnO/PMM2dnS+6nn36aYzFH7vvvv6+SFhMoAY4fPy7nljvG448/zjFPTiymsAIYxgpgGCuAYawAhrECGMYKYBgrgGGsAIaxAhjGCmAYK4BhrACGsQIYxgpgGCuAYawAhrECGMYKYBgrgGGsAIaxAhjmLhQgPz+/pKRk3rx56jzaRHFf0ObNmxctWkTi7Nmzp0+fFqNm+/btRUVFP/30kzp3UFtbu27duqVLl+bl3e5Y169f7+rqam1tvXnzpmSIFNHdF1RTU7M6TkNDQ0FBgbImWLVqFZfUSQKyvfzyy88991x1dfXU1NSFCxdGRkbuueeeurq6pqam0tJSlS96RNcFSQvSo9V5IC+88MIDDzwwOjr6448/fvTRR19++eVnn322Z8+ev//+u7i4+M0331ywYIHKGjGiK8Aff/zBMRaL5ebmiiUZjz322MqVK/Ez33333ZkzZxgBYh8eHt67d++lS5do/W3btokxakRXANxIf38/3mPNmjXKlARxpkeOHKGtxaIZHx9vaWkhwfTg9WZRILoCgIQG0r7JKC8vlxm7s7NTLC6YyW/cuFFYWIiPUqYoEWkB+vr6cOJLlizBwyiTB2l9vA0xj1hcTE9PDw4OkiA6EkukiLQAcOzYMY4bN26UUy8LFy7k+O+//8qpL1euXOF43333yWmkiLoATKqEQwSmlZWVyjQTIiWOwZG+npYjSNQFwIG0tbWRqK+vF4sL1r0qlZzJyUmOYXLeeaIuAHR3d+PfmQbE27hgguUY3LgS/0RzHMwBAei/R48ezcvL8x0EOCiOxEJy6osoJ1JFjTkgAHR0dExMTBDLexe0EvsTKQUMgsWLF3OUWChqzA0BGARoQBN7wyHWa6Ojo1x6+OGHlWkmaEOoeuvWrXPnzilTlJgbAgBeiEEQi8W8Pf3kyZMct27d6v0JGsf15JNPkmA5lmyhYJY5IwAenNmYBW1RUZEyJSBMYiYoLi7etWtXWVmZsubkkHPHjh2EsCjX3NysrBFjzggANDSeRJ04wEF9//33rLYqKip27979yiuvNDY2Pvvss2+//TZ+ieBn//79V69eVbkjRv6WLVv4hxW/nEcB+iyuo6ura3x8XJnicIqToV8zGpgSlDXO2NhYZ2cnV+WnIVZtTLxEn+fPn9+3b180p9+qqiqOd9ub8ihH67M8xuPT65mf1YXocXe+KY+PGhoa6unp4Rjl1tfcbQLMOawAhrECGMYKYBgrgGGsAIaxAhjGCmAYK4BhrACGyfy3oNdff72mpkadJLh27Vpvb29LS8vExIRYdu7c6dpLOz09ffPmTXLypadOnVLWnJzGxsZYLKZOPHR0dDQ3N7/33nv5+fkff/yx7/PFBQsWvPPOO5T/4YcfLly4sKmpaXBw8Ntvv5Wr7777bsAOUbINDw+Th5IpX1kTyGcPHz7c2tqqTHG4NW7wzz//9N2tHczs/BY0NjZ2PQFVLy4uXr9+/UsvvaQuJxgfH1eZ4tkKCwsrKiq2b9/u3XbozOkEzaamps6ePUueZHvcsOfl5ZFHtkH4oorzQOFU7MqVKzS0S6fy8nKxeDvckiVLOGbza2u22yW/+eYbOo46ie9Te/XVV5ctW7Z8+fK//vpLWXNyfvjhB2ctaaaGhoYNGzZs3bq1q6tLWeP88ssvdCh14oFLDz30EA3tuxFRhBGRkvHJJ5+olB8XLlxg6NCs/f39ypRo93/++Wfp0qWMP+fuCnna7N2TGp5ZngMQ48iRIyQefPBBsfhy69atgwcPjo6OlpSU+G42SQaicv80tPfBJBbslBwsQDBDQ0McpVk1CMBAx2HyFa79jUhFfeRTmTH7k7DsEky5DxBPffHiRRKytS0kNMTAwAAN4d0tigX7+fPnfaeHkEjlxbFoEIAvlTFRXV0tRhBnNTIy4hwT6TL7Asgz2zBvBUlO/K+chkQc1IoVK+RUI5YzZ87IaWZIX3buMpIJAP+Jroxv5zQgOmW52WL2BZDtyv/995+cJkMeHHJX6T42wcPgZ5gJ1HkCsWTjf4C+TCuXlpZqFyctLl6etpZpIH5F6eScAjNglgVg+n3iiSdIuHoiI/f2S19xamtrN23a9NprrzEVt7W1uSKWtWvXPu2HuhzfHkF/pFfef//9ypSTQxoLPi3lw3dV3Ez4UnU5/nicJpZuBAigvTzfyyU9DWQfAkG2UdCLL76oPeC99947f/58Et3d3cQMYhTk0b8TejGhfXt7uzpPgCfxuhf49ddfVSonp6enhyhr1apVeHyxkOYYxv8QJauUA9yaXpEQCKEH8zAJThGA1pd7lLamM0mCPNhl73vGZDsCGK10FgGffvnyZZYqP//8s7qcgCY7EUemMvz+F198ceDAAaZiyaA5duwYixov6nIcaWhpdEHSfIucBqCKm4m8hSDIBhHp3URoMgHEr9wefHoaYChw71qbjMlWgK+//pp1o/DBBx98/vnnLBfp3epyAmI4ujDs3bv3t99+I/J5/vnnfd++4/7pj17U5TjohzsuKysTL8yRNM5HwqpgVHEzce7KoYlpUynZO83qaYAOxzGbFYCQrQAsXOkXgrc7+4IYuA5WwgHvvaSEVuMoKy859vb23r6QNbQ+zof2Je2cAAQ9DYhCWU4AMPtRUBhko2B9fX1aiwAnEu3IakCOYfxPSFgN4HnwP7h7xHA6GT0NyFScZQgEZgRgimYyKCwsrKurU6Y0weHIbwO0FEfGX5bxuBPp8kR0jAPX22d8EY2Oa6qqqiJt3gVlzKFDhzjGYjFaUCzpgs/BGzQ2NnJkWg7pAMMg8Y/8Wul1Mn19fUiONtl3fzAmAP0XN8IgcM0EGzZs2JkElSOBTAMsLDiGnwBUWR74XpUjvuxiJS/TgK8AdBpUz34CAGMCgPy27hoEdC5Zr3lRORIQ8krYMzExMTAwIMaUqLI8iE/XyCCgj+NnxKLRoWf2/gcyfyBDGDNv3jw6csCP70C0QPvSUq6tzgKelK5EUxJZElazlFMX/PB6efkIJXsD0IKCgsrKSuclmpi1t6S9uBy6lJzMy1My5ae892DExdn/R8wYd+fu6DmHFcAwVgDDWAEMYwUwjBXAMFYAw1gBDGMFMIwVwDBp/xSxZs2aqqqqsbGxw4cPK1PiD2W0t7cne0K9ePHitWvXXr9+Xf4aKFRWVj7yyCMkKIfSxKgpLS1lpT4yMqIrxinGU6dOBf95OGH16tXV1dWuSmrkmbs6iTM5OXnjxo2enh7560Oap+O7MZz7AVzIF6kTPwI+m+FPEbT1+vXrN2/eXFJSokzxfXAYH330UXXuYd26dWRw/uoZi8WwgPPZukYKdO5vJI0FDdR5IL6V1KxYseL2FzvYuHFjQ0NDU1OTa7uRXFUnftTU1EieZKh8yUlPALott3T58mXSiC9GkJ/mA/aDyo1JNsjPz6fdr169OjU15SxnVqioqCgrK/NW0oXefrF///4DBw5QN2r1zDPPFBcXqxyhOXnypBTlReVITnoCyP20tLS4Gq6/v58hvGjRIudfi9HIrqnR0VG9jWfZsmXz58/nnoeGhiQt9llBVxIXFCCA3n7R3d3d0dFBY3EXRUVF4hjTAq8oRXlROZKTtgATExN9fX0DAwMyGsQ+PT0te3V8b1iMztqIpbe3l6JkNIh9VtCVpEGdlUyJPOjnI3J6Z0hDALkZbozuL63pbG6vReMSQFqcEcOACPhUZoj/kUrKPonwhcvTlTDbimeRNASQt1mkp9N5uUPn+y2Dg4M4Ge7f1eOQTR4taf+zcuVKfI6UI5sbli9f7pyfs0GaWwpnmLoqGYxswwr/dHNWSEMA7o37kfdecK+4b+luchUv5NudnS0iiEU/Rmfg5+XlBb/QEZ7gSjoh0CpPwOy1adMmQrVz58653tgJAz1MFTQT79+w8xJWACZSvobeoWN2r9MXAWSfmkb8u8v/UIjuaOk6igCkrYMrqXnqqad2JyAA3bZtG8N037593n2VKamvr1cFzaS2tlblSE5YAeQenLvPpJc57w0ng0thYaL3u0mLcGN6Bwf+p7CwkOmRfiqWixcv4rsIqLP3QmEqqRkeHqZWQK8njMH1U+233nor5FLDCcs3KcpFypckIOz2dLkHhiqrG7EAlZYmlqAb6Oksaoj65W+6iWOhG+pdU1IOGjjLQSGGF5nlD1BmTMhKCq2trXpcAkOT5RuV37Fjx1dffaWs4Whvb3f9DbvwhBoBdE8aiASr5y0O5B0j519MlVvSDt21/iooKBCPxFEVEYcGwhhmwAYgrUwiZSV9YUQeOnQI31VVVZXWe4NZEkoAqT3tyIrRibwQ6Ww4Qho6mvgTmoNG4ZZ0/EO70/cZ7+rzDojc+VTGe3VBur+3kvq/MInnCgINqD+JDLxQxqQWIDc3VzoyHYSB5uT333/HfUtDS2agCYhqWN8CpxKwyiVpI/XhmUhQJBkyQz7rrWRbWxvu3lXJZMhw0RW+A6QWQLoz9+DyoYI3hmFlzxHN+CAJp/+RAMk5SWqyjIXE/ySrJOsyjikLp+OzaiEKohxl+v+TWgCpt2+rgTfOu3TpEoENrQ/OcBP/w0RHyMGUKxYnrAbod84IyheCa/K4YH4KrqSvAK6i6urq3njjDcbu6dOnXTVUOWZCf1KX48opqweZOwNIEQVp/6PXTS7w77SyDHC9C5NeT0RBorOz0+V/5PcWL5OTk0hFkEq2EydOKKsHJlWVcoCjl8KTVVJUd1XStyjmp4MHD6qTBLt27VIpB3v27NEDZUMcSbugbrhBdeJHij9dTDyAvFQrWaMQXyLS+Pj4tWvX9PAn/kV5hgJhJXYxMgLIQDm+u3SBeZgOKJM2/YuhwJSoN+SWlJTQiJTphTZlzRlQSXBWkjUwsan6cBy+iLD9+PHjzc3Nzv22RLQqhwfEphBukx6mTH6wEEn2kOru/NPFc4gMn4hZZhcrgGGsAIaxAhjGCmAYK4BhrACGsQIYxgpgGCuAYawAhrECGMYKYBgrgGGsAIaxAhjGCmAYK4BhrACGsQIYxgpgGCuAYdS2FIsp7AgwSk7O/wCqCi/+JioQYgAAAABJRU5ErkJggg=='); -} - -.two-column { - display: table; - width: 100%; -} -.two-column > div { - display: table-cell; - width: 50%; -} - -#properties-list .fieldset .two-column { - padding-top: 10px; - display: flex; -} - -#properties-list .two-column .fieldset { - width: 50%; - margin: 0; - padding: 0; - border-top: none; - box-shadow: none; -} - -#properties-list .two-column .column { - position: relative; - top: -10px; -} - -#properties-list .two-column .fieldset div.legend { - width: 100%; - margin: 21px -21px 0 -21px; - padding: 16px 0 0 21px; - font-family: Raleway-Regular; - font-size: 12px; - color: #afafaf; - height: 10px; - text-transform: uppercase; - outline: none; -} - -#properties-list .two-column + .property { - margin-top: 6px; -} - -.fieldset .checkbox-sub-props { - margin-top: 0; -} - -.fieldset .checkbox-sub-props .property:first-child { - margin-top: 0; -} - -.column { - vertical-align: top; -} - -.indent { - margin-left: 24px; -} - -::-webkit-scrollbar { - width: 20px; - height: 10px; -} -::-webkit-scrollbar-track { - background-color: #2e2e2e; -} -#entity-table-scroll::-webkit-scrollbar-track { - border-bottom-right-radius: 7px; -} - -::-webkit-scrollbar-thumb { - background-color: #696969; - border: 2px solid #2e2e2e; - border-radius: 8px; -} - -/* FIXME: Revisit textarea resizer/corner when move to Qt 5.6 or later: see if can get resizer/corner to always be visible and -have correct background color with and without scrollbars. */ -textarea:enabled::-webkit-resizer { - background-size: 10px 10px; - background: #252525 url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAIAAAACUFjqAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAXSURBVChTY1RVVWXADZigNA4wMqUZGACS3gCD5UUtKAAAAABJRU5ErkJggg==) no-repeat bottom right; -} -textarea:focus::-webkit-resizer { - background-size: 10px 10px; - background: #000000 url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAYAAACNMs+9AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAACOSURBVChThdC5DQQhDAXQvyRI5LQxFdABARWQElAPogYkiqEWQhLYGe8xxzJaS5a/8AuQHwDG2n+Lvee0hBDQWlO+hRvy3mNZFjDG5vCDOOeIMaL3/guPKISAWiu9n+AVSSlhraXdF86Qcw6tNdoTvEOlFOScd6iUOv3JGEMopYQx9jNvaawnoHnNr8Z4AuRLPOq2gPgnAAAAAElFTkSuQmCC) no-repeat bottom right; -} -textarea:enabled[scrolling="true"]::-webkit-resizer { - background-size: 10px 10px; - background: #2e2e2e url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAYAAACNMs+9AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAACKSURBVChTjdAxDsMgDAXQT4UYuQIzCwsSKxsSJ4YDoByDY7AwUOG2aZMQqX+xhd9gzIwxA3/k8a7LCCFgraX+Fk4UY4RSCoyxNfwgzjlyzhhjXOEvSimhtUbvB3hGUkp472m2wxUKIaD3TnOCd6jWim3bvlBrfdjJOUeolEJoZj/4PMH83bl/BXgCWSs2Z09IjgoAAAAASUVORK5CYII=) no-repeat bottom right; -} - - -div#grid-section, body#entity-list-body { - padding-bottom: 0; - margin: 16px; -} - -#entity-list-header { - margin-bottom: 36px; -} - -#entity-list-header div { - display: inline-block; - width: 65px; - margin-right: 6px; -} - -#entity-list-header div input:first-child { - margin-right: 0; - float: left; - width: 33px; - border-right: 1px solid #808080; - border-top-right-radius: 0; - border-bottom-right-radius: 0; -} -#entity-list-header div input:last-child { - margin-right: 0; - float: right; - border-top-left-radius: 0; - border-bottom-left-radius: 0; -} - -#delete { - float: right; - margin-right: 0; - background-color: #ff0000; -} - -#entity-list { - position: relative; /* New positioning context. */ -} - -#filter-area { - padding-right: 168px; - padding-bottom: 24px; -} - -#filter-type-multiselect-box select { - border-radius: 14.5px; - width: 107px; - height: 28px; -} -#filter-type-options { - position: absolute; - top: 48px; -} -#filter-type-options div { - position: relative; - height: 22px; -} -#filter-type-options span { - position: relative; - top: 3px; - font-family: HiFi-Glyphs; - font-size: 13px; - color: #000000; - padding-left: 6px; - padding-right: 4px; -} -#filter-type-options label { - position: absolute; - top: -20px; - z-index: 2; - height: 22px; - width: 200px; - padding-top: 1px; -} -#filter-type-options-buttons { - top: -22px; - width: 224px; - z-index: 2; - background-color: #afafaf; - padding-bottom: 6px; -} -#filter-type-options input[type=button] { - position: relative; - left: 16px; - z-index: 3; - height: 23px; - min-width: 60px; - font-size: 10px; - color: #000; - background: linear-gradient(#afafaf 20%, #808080 100%); -} -#filter-type-options input[type=button]:enabled:hover { - background: linear-gradient(#afafaf 20%, #575757 100%); -} - -#filter-search-and-icon { - position: relative; - left: 118px; - width: calc(100% - 126px); -} - -#filter-in-view { - position: absolute; - top: 0; - right: 126px; -} - -#filter-radius-and-unit { - position: relative; - float: right; - margin-right: -168px; - top: -45px; -} -#filter-radius-and-unit label { - margin-left: 2px; -} -#filter-radius-and-unit span { - position: relative; - top: 25px; - right: 9px; - z-index: 2; - font-style: italic; -} -#filter-radius-and-unit input { - width: 120px; - border-radius: 14.5px; - font-style: italic; -} -#filter-radius-and-unit input[type=number]::-webkit-inner-spin-button { - display: none; -} - -#entity-list-footer { - padding-top: 9px; -} - -#footer-text { - float: right; - padding-top: 12px; - padding-right: 22px; -} - -input[type=button]#export { - height: 38px; - width: 180px; -} - -#no-entities { - display: none; - position: absolute; - top: 80px; - padding: 12px; - font-family: FiraSans-SemiBold; - font-size: 15px; - font-style: italic; - color: #afafaf; -} - -#entity-table-columns-multiselect { - position: absolute; - top: 51px; - right: 22px; -} -#entity-table-columns-multiselect-box select { - height: 28px; - width: 20px; - background-color: #1c1c1c; - border-top-right-radius: 7px; -} -#entity-table-columns-options { - position: absolute; - top: 50px; - right: 110px; -} -#entity-table-columns-options div { - position: relative; - height: 22px; -} -#entity-table-columns-options label { - position: absolute; - top: -22px; - height: 22px; - width: 100px; - padding-top: 4px; -} -#entity-table-columns-options input[type=checkbox] + label { - padding-left: 30px; -} - -#entity-table-scroll { - /* Height is set by JavaScript. */ - width: 100%; - overflow-x: hidden; - overflow-y: auto; - box-sizing: border-box; - padding-top: 28px; /* Space for header and footer outside of scroll region. */ - margin-top: 28px; - border-left: 2px solid #575757; - border-right: 2px solid #575757; - border-bottom: 2px solid #575757; - border-bottom-left-radius: 7px; - border-bottom-right-radius: 7px; - background-color: #1c1c1c; -} - -#entity-table-scroll .glyph { - font-family: HiFi-Glyphs; - font-size: 15px; -} - -#entity-table { - margin-top: -28px; - margin-bottom: -18px; - table-layout: fixed; - border: none; - background-color: #1c1c1c; -} - -#entity-table thead tr, #entity-table thead tr th { - background: none; -} - -#entity-table .glyph { - margin: 0 -2px 0 -2px; - vertical-align: middle; -} - -#entity-table thead { - box-sizing: border-box; - border: 2px solid #575757; - border-top-left-radius: 7px; - border-top-right-radius: 7px; - border-bottom: 1px solid #575757; - position: absolute; - top: 49px; - left: 0; - width: 100%; - word-wrap: nowrap; - white-space: nowrap; - overflow: hidden; -} - -#entity-table th { - display: inline-block; - box-sizing: border-box; - padding: 5px 0 0 0; - vertical-align: middle; - overflow: hidden; - text-overflow: ellipsis; -} - -#entity-table th:focus { - outline: none; -} - -#entity-table th .glyph { - position: relative; - left: 4px; -} -#entity-table th .glyph + .sort-order { - position: relative; - left: 4px; -} - -#entity-table thead .sort-order { - display: inline-block; - width: 8px; - margin: -5px 0 -3px 0; - vertical-align: middle; -} - -#entity-table thead .resizer { - position: absolute; - top: 1px; - height: 26px; - width: 10px; - cursor: col-resize; -} - -#entity-table .dragging { - background-color: #b3ecff; -} - -#entity-table td { - box-sizing: border-box; -} -#entity-table td.glyph { - text-align: center; - padding: 0; -} - -#properties-base { - border-top: none !important; - box-shadow: none !important; - margin-bottom: 5px !important; -} - -#properties-base #property-type-icon { - font-family: HiFi-Glyphs; - font-size: 31px; - color: #00b4ef; - margin: -4px 12px -4px -2px; - width: auto; - display: none; -} - -#properties-base #property-type { - padding: 5px 24px 5px 0; - border-right: 1px solid #808080; - width: auto; - display: inline-block; -} - -#properties-base .checkbox label span { - font-family: HiFi-Glyphs; - font-size: 20px; - padding-right: 6px; - vertical-align: top; - position: relative; - top: -4px; -} - -#properties-base input[type=checkbox]:checked + label span { - color: #ffffff; -} - -#id label { - width: 24px; -} -#property-id { - display: inline-block; -} -#property-id::selection { - color: #000000; - background-color: #00b4ef; -} - -input#property-scale-button-rescale { - min-width: 50px; - left: 152px; -} -input#property-scale-button-reset { - margin-right: 0; - left: 250px; -} - -#property-userData-static, -#property-materialData-static { - display: none; - z-index: 99; - position: absolute; - width: 96%; - padding-left: 1%; - margin-top: 5px; - margin-bottom: 10px; - background-color: #2e2e2e; -} - -#property-userData-saved, -#property-materialData-saved { - margin-top: 5px; - font-size: 16px; - display: none; -} - - -#div-property-collisionSoundURL[style*="display: none"] + .property { - margin-top: 0; -} - -.context-menu { - display: none; - position: fixed; - color: #000000; - background-color: #afafaf; - padding: 5px 0 5px 0; - cursor: default; -} -.context-menu li { - list-style-type: none; - padding: 4px 18px 4px 18px; - margin: 0; - white-space: nowrap; -} -.context-menu li:hover { - background-color: #e3e3e3; -} -.context-menu li.separator { - border-top: 1px solid #333333; - margin: 5px 5px; - padding: 0 0; -} -.context-menu li.disabled { - color: #333333; -} -.context-menu li.separator:hover, .context-menu li.disabled:hover { - background-color: #afafaf; -} - -input.rename-entity { - height: 100%; - width: 100%; - border: none; - font-family: FiraSans-SemiBold; - font-size: 15px; - /* need this to show the text cursor when the input field is empty */ - padding-left: 2px; -} - -.create-app-tooltip { - z-index: 100; - position: absolute; - background: #6a6a6a; - border: 1px solid black; - width: 258px; - min-height: 20px; - padding: 5px; - z-index: 100; -} - -.create-app-tooltip .create-app-tooltip-description { - font-size: 12px; - font-style: italic; - color: #ffffff; -} - -.create-app-tooltip .create-app-tooltip-js-attribute { - font-family: Raleway-SemiBold; - font-size: 11px; - color: #000000; - bottom: 0; - margin-top: 5px; -} - -#toggle-space-mode::before { - font-family: HiFi-Glyphs; - font-size: 20px; - text-transform: none; - min-width: 32px; - padding-right: 4px; - vertical-align: middle; -} - -#toggle-space-mode.space-mode-local::before { - content: "m"; -} - -#toggle-space-mode.space-mode-world::before { - content: "\e02c"; -} - -.container { - display: flex; - flex-flow: row nowrap; - margin-bottom: 8px; - min-height: 28px; -} - -.container > label { - margin-top: 6px; - width: 160px; - min-width: 160px; - max-width: 160px; -} - -.container > div.checkbox { - padding-top: 6px; -} - -.container > .value { - width: 100%; -} - -.container .row { - display: flex; - flex-flow: row nowrap; -} - -.container.shrink { - width: min-content; -} - -.fstuple { - display: flex; - flex-flow: row; -} -.fstuple input { - margin-left: 4px; - margin-right: 10px; -} -.fstuple label.red, .fstuple label.x, .fstuple label.w { - color: #C62147; -} -.fstuple label.green, .fstuple label.y, .fstuple label.h { - color: #359D85; -} -.fstuple label.blue, .fstuple label.z { - color: #0093C5; -} - -.xyz.fstuple, .pyr.fstuple { - position: relative; - left: -12px; - min-width: 50px; - width: 100px; -} - -.rgb.fstuple .tuple { - display: none; -} - -input.number-slider { - background: #575757; - border-radius: 4px; - color: white; -} - -.fstuple > div { - display: flex; - align-items: center; - justify-content: left; -} - -.flex-row { - display: flex; - flex-flow: row; -} - -.flex-column { - display: flex; - flex-flow: column; -} - -.flex-center { - align-items: center; -} - -.flex-evenly-spaced { - flex: 1; -} - -#property-serverScripts-status { - font-family: Raleway-Light; - font-size: 14px; - margin: 6px 0; - cursor: default; -} - -#property-name, #property-id { - display: flex; - width: 100%; -} - -.spacemode-hidden { - display: none; -} - -#placeholder-property-type { - min-width: 0; -} - -.collapse-icon { - cursor: pointer; -} - -#property-userData-editor.error { - border: 2px solid red; -} - -#property-userData-editorStatus { - color: white; - background-color: red; - padding: 5px; - display: none; - cursor: pointer; -} - -#property-materialData-editor.error { - border: 2px solid red; -} - -#property-materialData-editorStatus { - color: white; - background-color: red; - padding: 5px; - display: none; - cursor: pointer; -} - -input[type=number].hide-spinner::-webkit-inner-spin-button { - -webkit-appearance: none; - visibility: hidden; -} - -div.jsoneditor-menu a.jsoneditor-poweredBy { - display: none; -} diff --git a/scripts/simplifiedUI/system/html/css/hifi-style.css b/scripts/simplifiedUI/system/html/css/hifi-style.css deleted file mode 100644 index 90a5b366c2..0000000000 --- a/scripts/simplifiedUI/system/html/css/hifi-style.css +++ /dev/null @@ -1,175 +0,0 @@ -/* -// hifi-style.css -// -// Created by Zach Fox on 2017-04-18 -// Copyright 2017 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -*/ - -@font-face { - font-family: Raleway-Regular; - src: url(../../../../resources/fonts/Raleway-Regular.ttf), /* Windows production */ - url(../../../../fonts/Raleway-Regular.ttf), /* OSX production */ - url(../../../../interface/resources/fonts/Raleway-Regular.ttf); /* Development, running script in /HiFi/examples */ -} - -@font-face { - font-family: Raleway-Light; - src: url(../../../../resources/fonts/Raleway-Light.ttf), - url(../../../../fonts/Raleway-Light.ttf), - url(../../../../interface/resources/fonts/Raleway-Light.ttf); -} - -@font-face { - font-family: Raleway-Bold; - src: url(../../../../resources/fonts/Raleway-Bold.ttf), - url(../../../../fonts/Raleway-Bold.ttf), - url(../../../../interface/resources/fonts/Raleway-Bold.ttf); -} - -@font-face { - font-family: Raleway-SemiBold; - src: url(../../../../resources/fonts/Raleway-SemiBold.ttf), - url(../../../../fonts/Raleway-SemiBold.ttf), - url(../../../../interface/resources/fonts/Raleway-SemiBold.ttf); -} - -@font-face { - font-family: FiraSans-SemiBold; - src: url(../../../../resources/fonts/FiraSans-SemiBold.ttf), - url(../../../../fonts/FiraSans-SemiBold.ttf), - url(../../../../interface/resources/fonts/FiraSans-SemiBold.ttf); -} - -@font-face { - font-family: AnonymousPro-Regular; - src: url(../../../../resources/fonts/AnonymousPro-Regular.ttf), - url(../../../../fonts/AnonymousPro-Regular.ttf), - url(../../../../interface/resources/fonts/AnonymousPro-Regular.ttf); -} - -@font-face { - font-family: HiFi-Glyphs; - src: url(../../../../resources/fonts/hifi-glyphs.ttf), - url(../../../../fonts/hifi-glyphs.ttf), - url(../../../../interface/resources/fonts/hifi-glyphs.ttf); -} - -body { - color: #afafaf; - background-color: #404040; - font-family: Raleway-Regular; - font-size: 15px; - - -webkit-touch-callout: none; - -webkit-user-select: none; - -khtml-user-select: none; - -moz-user-select: none; - -ms-user-select: none; - user-select: none; - - overflow-x: hidden; - overflow-y: auto; -} - -hr { - border: none; - background: #404040 url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAQAAAAECAYAAACp8Z5+AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAAjSURBVBhXY1RVVf3PgARYjIyMoEwIYHRwcEBRwQSloYCBAQCwjgPMiI7W2QAAAABJRU5ErkJggg==) repeat-x top left; - padding: 1px; - -webkit-margin-before: 0; - -webkit-margin-after: 0; - -webkit-margin-start: 0; - -webkit-margin-end: 0; - width: 100%; - position: absolute; -} - -.hifi-glyph { - font-family: HiFi-Glyphs; - border: none; - //margin: -10px; - padding: 0; -} - -input[type=radio] { - width: 2em; - margin: 0; - padding: 0; - font-size: 1em; - opacity: 0; -} -input[type=radio] + label{ - display: inline-block; - margin-left: -2em; - line-height: 2em; - font-family: Raleway-SemiBold; - font-size: 14px; -} -input[type=radio] + label > span{ - display: inline-block; - width: 20px; - height: 20px; - margin: 5px; - border-radius: 50%; - background: #6B6A6B; - background-image: linear-gradient(#7D7D7D, #6B6A6B); - vertical-align: bottom; -} -input[type=radio]:checked + label > span{ - background-image: linear-gradient(#7D7D7D, #6B6A6B); -} -input[type=radio]:active + label > span, -input[type=radio]:hover + label > span{ - background-image: linear-gradient(#FFFFFF, #AFAFAF); -} -input[type=radio]:checked + label > span > span, -input[type=radio]:active + label > span > span{ - display: block; - width: 10px; - height: 10px; - margin: 3px; - border: 2px solid #36CDFF; - border-radius: 50%; - background: #00B4EF; -} - -.grayButton { - font-family: Raleway-Bold; - font-size: 13px; - color: black; - padding: 0 10px; - border-radius: 3px; - border-width: 0; - background-image: linear-gradient(#FFFFFF, #AFAFAF); - min-height: 30px; -} -.grayButton:hover { - background-image: linear-gradient(#FFFFFF, #FFFFFF); -} -.grayButton:active { - background-image: linear-gradient(#AFAFAF, #AFAFAF); -} -.grayButton:disabled { - background-image: linear-gradient(#FFFFFF, ##AFAFAF); -} -.blueButton { - font-family: Raleway-Bold; - font-size: 13px; - color: white; - padding: 0 10px; - border-radius: 3px; - border-width: 0; - background-image: linear-gradient(#00B4EF, #1080B8); - min-height: 30px; -} -.blueButton:hover { - background-image: linear-gradient(#00B4EF, #00B4EF); -} -.blueButton:active { - background-image: linear-gradient(#1080B8, #1080B8); -} -.blueButton:disabled { - background-image: linear-gradient(#FFFFFF, #AFAFAF); -} diff --git a/scripts/simplifiedUI/system/html/css/img/jsoneditor-icons.svg b/scripts/simplifiedUI/system/html/css/img/jsoneditor-icons.svg deleted file mode 100644 index 1b40068aad..0000000000 --- a/scripts/simplifiedUI/system/html/css/img/jsoneditor-icons.svg +++ /dev/null @@ -1,893 +0,0 @@ - - - JSON Editor Icons - - - - image/svg+xml - - JSON Editor Icons - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/scripts/simplifiedUI/system/html/css/img/mt-expand-hover.svg b/scripts/simplifiedUI/system/html/css/img/mt-expand-hover.svg deleted file mode 100644 index a8e84c42ad..0000000000 --- a/scripts/simplifiedUI/system/html/css/img/mt-expand-hover.svg +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/scripts/simplifiedUI/system/html/css/img/mt-expand-normal.svg b/scripts/simplifiedUI/system/html/css/img/mt-expand-normal.svg deleted file mode 100644 index aac349ebda..0000000000 --- a/scripts/simplifiedUI/system/html/css/img/mt-expand-normal.svg +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/scripts/simplifiedUI/system/html/css/img/mt-goto-hover.svg b/scripts/simplifiedUI/system/html/css/img/mt-goto-hover.svg deleted file mode 100644 index 4cad54331a..0000000000 --- a/scripts/simplifiedUI/system/html/css/img/mt-goto-hover.svg +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/scripts/simplifiedUI/system/html/css/img/mt-goto-normal.svg b/scripts/simplifiedUI/system/html/css/img/mt-goto-normal.svg deleted file mode 100644 index ead63329fb..0000000000 --- a/scripts/simplifiedUI/system/html/css/img/mt-goto-normal.svg +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/scripts/simplifiedUI/system/html/css/img/mt-mute-hover.svg b/scripts/simplifiedUI/system/html/css/img/mt-mute-hover.svg deleted file mode 100644 index 9a18ccd933..0000000000 --- a/scripts/simplifiedUI/system/html/css/img/mt-mute-hover.svg +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/scripts/simplifiedUI/system/html/css/img/mt-mute-normal.svg b/scripts/simplifiedUI/system/html/css/img/mt-mute-normal.svg deleted file mode 100644 index 472f03f138..0000000000 --- a/scripts/simplifiedUI/system/html/css/img/mt-mute-normal.svg +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/scripts/simplifiedUI/system/html/css/jsoneditor.css b/scripts/simplifiedUI/system/html/css/jsoneditor.css deleted file mode 100644 index eedef60a7f..0000000000 --- a/scripts/simplifiedUI/system/html/css/jsoneditor.css +++ /dev/null @@ -1,930 +0,0 @@ -/* reset styling (prevent conflicts with bootstrap, materialize.css, etc.) */ - -div.jsoneditor input { - height: auto; - border: inherit; -} - -div.jsoneditor input:focus { - border: none !important; - box-shadow: none !important; -} - -div.jsoneditor table { - border-collapse: collapse; - width: auto; -} - -div.jsoneditor td, -div.jsoneditor th { - padding: 0; - display: table-cell; - text-align: left; - vertical-align: inherit; - border-radius: inherit; -} - - -div.jsoneditor-field, -div.jsoneditor-value, -div.jsoneditor-readonly { - border: 1px solid transparent; - min-height: 16px; - min-width: 32px; - padding: 2px; - margin: 1px; - word-wrap: break-word; - float: left; -} - -/* adjust margin of p elements inside editable divs, needed for Opera, IE */ - -div.jsoneditor-field p, -div.jsoneditor-value p { - margin: 0; -} - -div.jsoneditor-value { - word-break: break-word; -} - -div.jsoneditor-readonly { - min-width: 16px; - color: red; -} - -div.jsoneditor-empty { - border-color: lightgray; - border-style: dashed; - border-radius: 2px; -} - -div.jsoneditor-field.jsoneditor-empty::after, -div.jsoneditor-value.jsoneditor-empty::after { - pointer-events: none; - color: lightgray; - font-size: 8pt; -} - -div.jsoneditor-field.jsoneditor-empty::after { - content: "field"; -} - -div.jsoneditor-value.jsoneditor-empty::after { - content: "value"; -} - -div.jsoneditor-value.jsoneditor-url, -a.jsoneditor-value.jsoneditor-url { - color: green; - text-decoration: underline; -} - -a.jsoneditor-value.jsoneditor-url { - display: inline-block; - padding: 2px; - margin: 2px; -} - -a.jsoneditor-value.jsoneditor-url:hover, -a.jsoneditor-value.jsoneditor-url:focus { - color: #ee422e; -} - -div.jsoneditor td.jsoneditor-separator { - padding: 3px 0; - vertical-align: top; - color: gray; -} - -div.jsoneditor-field[contenteditable=true]:focus, -div.jsoneditor-field[contenteditable=true]:hover, -div.jsoneditor-value[contenteditable=true]:focus, -div.jsoneditor-value[contenteditable=true]:hover, -div.jsoneditor-field.jsoneditor-highlight, -div.jsoneditor-value.jsoneditor-highlight { - background-color: #FFFFAB; - border: 1px solid yellow; - border-radius: 2px; -} - -div.jsoneditor-field.jsoneditor-highlight-active, -div.jsoneditor-field.jsoneditor-highlight-active:focus, -div.jsoneditor-field.jsoneditor-highlight-active:hover, -div.jsoneditor-value.jsoneditor-highlight-active, -div.jsoneditor-value.jsoneditor-highlight-active:focus, -div.jsoneditor-value.jsoneditor-highlight-active:hover { - background-color: #ffee00; - border: 1px solid #ffc700; - border-radius: 2px; -} - -div.jsoneditor-value.jsoneditor-string { - color: #008000; -} - -div.jsoneditor-value.jsoneditor-object, -div.jsoneditor-value.jsoneditor-array { - min-width: 16px; - color: #808080; -} - -div.jsoneditor-value.jsoneditor-number { - color: #ee422e; -} - -div.jsoneditor-value.jsoneditor-boolean { - color: #ff8c00; -} - -div.jsoneditor-value.jsoneditor-null { - color: #004ED0; -} - -div.jsoneditor-value.jsoneditor-invalid { - color: #000000; -} - -div.jsoneditor-tree button { - width: 24px; - height: 24px; - padding: 0; - margin: 0; - border: none; - cursor: pointer; - background: transparent url("img/jsoneditor-icons.svg"); -} - -div.jsoneditor-mode-view tr.jsoneditor-expandable td.jsoneditor-tree, -div.jsoneditor-mode-form tr.jsoneditor-expandable td.jsoneditor-tree { - cursor: pointer; -} - -div.jsoneditor-tree button.jsoneditor-collapsed { - background-position: 0 -48px; -} - -div.jsoneditor-tree button.jsoneditor-expanded { - background-position: 0 -72px; -} - -div.jsoneditor-tree button.jsoneditor-contextmenu { - background-position: -48px -72px; -} - -div.jsoneditor-tree button.jsoneditor-contextmenu:hover, -div.jsoneditor-tree button.jsoneditor-contextmenu:focus, -div.jsoneditor-tree button.jsoneditor-contextmenu.jsoneditor-selected, -tr.jsoneditor-selected.jsoneditor-first button.jsoneditor-contextmenu { - background-position: -48px -48px; -} - -div.jsoneditor-tree *:focus { - outline: none; -} - -div.jsoneditor-tree button:focus { - /* TODO: nice outline for buttons with focus - outline: #97B0F8 solid 2px; - box-shadow: 0 0 8px #97B0F8; - */ - background-color: #f5f5f5; - outline: #e5e5e5 solid 1px; -} - -div.jsoneditor-tree button.jsoneditor-invisible { - visibility: hidden; - background: none; -} - -#userdata-editor{ - height:100%; -} - -div.jsoneditor { - color: #1A1A1A; - border: 1px solid #2e2e2e; - -moz-box-sizing: border-box; - -webkit-box-sizing: border-box; - box-sizing: border-box; - width: 100%; - overflow: hidden; - position: relative; - padding: 0; - line-height: 100%; -} - -div.jsoneditor-tree table.jsoneditor-tree { - border-collapse: collapse; - border-spacing: 0; - width: 100%; - margin: 0; -} - -div.jsoneditor-outer { - width: 100%; - margin: -35px 0 0 0; - padding: 0 0 0 0; - -moz-box-sizing: border-box; - -webkit-box-sizing: border-box; - box-sizing: border-box; - overflow-y: auto; -} - -.ace-jsoneditor { - min-height: 150px; - height: auto !important; -} - -div.jsoneditor-tree { - width: 100%; - position: relative; -} - -textarea.jsoneditor-text { - width: 100%; - margin: 0; - -moz-box-sizing: border-box; - -webkit-box-sizing: border-box; - box-sizing: border-box; - outline-width: 0; - border: none; - background-color: white; - resize: none; -} - -tr.jsoneditor-highlight, -tr.jsoneditor-selected { - background-color: #e6e6e6; -} - -tr.jsoneditor-selected button.jsoneditor-dragarea, -tr.jsoneditor-selected button.jsoneditor-contextmenu { - visibility: hidden; -} - -tr.jsoneditor-selected.jsoneditor-first button.jsoneditor-dragarea, -tr.jsoneditor-selected.jsoneditor-first button.jsoneditor-contextmenu { - visibility: visible; -} - -div.jsoneditor-tree button.jsoneditor-dragarea { - background: url("img/jsoneditor-icons.svg") -72px -72px; - cursor: move; -} - -div.jsoneditor-tree button.jsoneditor-dragarea:hover, -div.jsoneditor-tree button.jsoneditor-dragarea:focus, -tr.jsoneditor-selected.jsoneditor-first button.jsoneditor-dragarea { - background-position: -72px -48px; -} - -div.jsoneditor tr, -div.jsoneditor th, -div.jsoneditor td { - padding: 0; - margin: 0; - overflow: visible; -} - -div.jsoneditor td { - vertical-align: top; -} - -div.jsoneditor td.jsoneditor-tree { - vertical-align: top; -} - -div.jsoneditor-field, -div.jsoneditor-value, -div.jsoneditor td, -div.jsoneditor th, -div.jsoneditor textarea, -.jsoneditor-schema-error { - font-family: droid sans mono, consolas, monospace, courier new, courier, sans-serif; - font-size: 10pt; - color: grey; -} - -/* popover */ - -.jsoneditor-schema-error { - cursor: default; - display: inline-block; - /*font-family: arial, sans-serif;*/ - height: 24px; - line-height: 24px; - position: relative; - text-align: center; - width: 24px; -} - -div.jsoneditor-tree .jsoneditor-schema-error { - width: 24px; - height: 24px; - padding: 0; - margin: 0 4px 0 0; - background: url("img/jsoneditor-icons.svg") -168px -48px; -} - -.jsoneditor-schema-error .jsoneditor-popover { - background-color: #4c4c4c; - border-radius: 3px; - box-shadow: 0 0 5px rgba(0,0,0,0.4); - color: #fff; - display: none; - padding: 7px 10px; - position: absolute; - width: 200px; - z-index: 4; -} - -.jsoneditor-schema-error .jsoneditor-popover.jsoneditor-above { - bottom: 32px; - left: -98px; -} - -.jsoneditor-schema-error .jsoneditor-popover.jsoneditor-below { - top: 32px; - left: -98px; -} - -.jsoneditor-schema-error .jsoneditor-popover.jsoneditor-left { - top: -7px; - right: 32px; -} - -.jsoneditor-schema-error .jsoneditor-popover.jsoneditor-right { - top: -7px; - left: 32px; -} - -.jsoneditor-schema-error .jsoneditor-popover:before { - border-right: 7px solid transparent; - border-left: 7px solid transparent; - content: ''; - display: block; - left: 50%; - margin-left: -7px; - position: absolute; -} - -.jsoneditor-schema-error .jsoneditor-popover.jsoneditor-above:before { - border-top: 7px solid #4c4c4c; - bottom: -7px; -} - -.jsoneditor-schema-error .jsoneditor-popover.jsoneditor-below:before { - border-bottom: 7px solid #4c4c4c; - top: -7px; -} - -.jsoneditor-schema-error .jsoneditor-popover.jsoneditor-left:before { - border-left: 7px solid #4c4c4c; - border-top: 7px solid transparent; - border-bottom: 7px solid transparent; - content: ''; - top: 19px; - right: -14px; - left: inherit; - margin-left: inherit; - margin-top: -7px; - position: absolute; -} - -.jsoneditor-schema-error .jsoneditor-popover.jsoneditor-right:before { - border-right: 7px solid #4c4c4c; - border-top: 7px solid transparent; - border-bottom: 7px solid transparent; - content: ''; - top: 19px; - left: -14px; - margin-left: inherit; - margin-top: -7px; - position: absolute; -} - -.jsoneditor-schema-error:hover .jsoneditor-popover, -.jsoneditor-schema-error:focus .jsoneditor-popover { - display: block; - -webkit-animation: fade-in .3s linear 1, move-up .3s linear 1; - -moz-animation: fade-in .3s linear 1, move-up .3s linear 1; - -ms-animation: fade-in .3s linear 1, move-up .3s linear 1; -} - -@-webkit-keyframes fade-in { - from { - opacity: 0; - } - - to { - opacity: 1; - } -} - -@-moz-keyframes fade-in { - from { - opacity: 0; - } - - to { - opacity: 1; - } -} - -@-ms-keyframes fade-in { - from { - opacity: 0; - } - - to { - opacity: 1; - } -} - -/*@-webkit-keyframes move-up {*/ - -/*from { bottom: 24px; }*/ - -/*to { bottom: 32px; }*/ - -/*}*/ - -/*@-moz-keyframes move-up {*/ - -/*from { bottom: 24px; }*/ - -/*to { bottom: 32px; }*/ - -/*}*/ - -/*@-ms-keyframes move-up {*/ - -/*from { bottom: 24px; }*/ - -/*to { bottom: 32px; }*/ - -/*}*/ - -/* JSON schema errors displayed at the bottom of the editor in mode text and code */ - -.jsoneditor .jsoneditor-text-errors { - width: 100%; - border-collapse: collapse; - background-color: #ffef8b; - border-top: 1px solid #ffd700; -} - -.jsoneditor .jsoneditor-text-errors td { - padding: 3px 6px; - vertical-align: middle; -} - -.jsoneditor-text-errors .jsoneditor-schema-error { - border: none; - width: 24px; - height: 24px; - padding: 0; - margin: 0 4px 0 0; - background: url("img/jsoneditor-icons.svg") -168px -48px; -} -/* ContextMenu - main menu */ - -div.jsoneditor-contextmenu-root { - position: relative; - width: 0; - height: 0; -} - -div.jsoneditor-contextmenu { - position: absolute; - box-sizing: content-box; - z-index: 998; -} - -div.jsoneditor-contextmenu ul, -div.jsoneditor-contextmenu li { - box-sizing: content-box; -} - -div.jsoneditor-contextmenu ul { - position: relative; - left: 0; - top: 0; - width: 124px; - background: white; - border: 1px solid #d3d3d3; - box-shadow: 2px 2px 12px rgba(128, 128, 128, 0.3); - list-style: none; - margin: 0; - padding: 0; -} - -div.jsoneditor-contextmenu ul li button { - padding: 0; - margin: 0; - width: 124px; - height: 24px; - border: none; - cursor: pointer; - color: #4d4d4d; - background: transparent; - font-size: 10pt; - font-family: arial, sans-serif; - box-sizing: border-box; - line-height: 26px; - text-align: left; -} - -/* Fix button padding in firefox */ - -div.jsoneditor-contextmenu ul li button::-moz-focus-inner { - padding: 0; - border: 0; -} - -div.jsoneditor-contextmenu ul li button:hover, -div.jsoneditor-contextmenu ul li button:focus { - color: #1a1a1a; - background-color: #f5f5f5; - outline: none; -} - -div.jsoneditor-contextmenu ul li button.jsoneditor-default { - width: 92px; -} - -div.jsoneditor-contextmenu ul li button.jsoneditor-expand { - float: right; - width: 32px; - height: 24px; - border-left: 1px solid #e5e5e5; -} - -div.jsoneditor-contextmenu div.jsoneditor-icon { - float: left; - width: 24px; - height: 24px; - border: none; - padding: 0; - margin: 0; - background-image: url("img/jsoneditor-icons.svg"); -} - -div.jsoneditor-contextmenu ul li button div.jsoneditor-expand { - float: right; - width: 24px; - height: 24px; - padding: 0; - margin: 0 4px 0 0; - background: url("img/jsoneditor-icons.svg") 0 -72px; - opacity: 0.4; -} - -div.jsoneditor-contextmenu ul li button:hover div.jsoneditor-expand, -div.jsoneditor-contextmenu ul li button:focus div.jsoneditor-expand, -div.jsoneditor-contextmenu ul li.jsoneditor-selected div.jsoneditor-expand, -div.jsoneditor-contextmenu ul li button.jsoneditor-expand:hover div.jsoneditor-expand, -div.jsoneditor-contextmenu ul li button.jsoneditor-expand:focus div.jsoneditor-expand { - opacity: 1; -} - -div.jsoneditor-contextmenu div.jsoneditor-separator { - height: 0; - border-top: 1px solid #e5e5e5; - padding-top: 5px; - margin-top: 5px; -} - -div.jsoneditor-contextmenu button.jsoneditor-remove > div.jsoneditor-icon { - background-position: -24px -24px; -} - -div.jsoneditor-contextmenu button.jsoneditor-remove:hover > div.jsoneditor-icon, -div.jsoneditor-contextmenu button.jsoneditor-remove:focus > div.jsoneditor-icon { - background-position: -24px 0; -} - -div.jsoneditor-contextmenu button.jsoneditor-append > div.jsoneditor-icon { - background-position: 0 -24px; -} - -div.jsoneditor-contextmenu button.jsoneditor-append:hover > div.jsoneditor-icon, -div.jsoneditor-contextmenu button.jsoneditor-append:focus > div.jsoneditor-icon { - background-position: 0 0; -} - -div.jsoneditor-contextmenu button.jsoneditor-insert > div.jsoneditor-icon { - background-position: 0 -24px; -} - -div.jsoneditor-contextmenu button.jsoneditor-insert:hover > div.jsoneditor-icon, -div.jsoneditor-contextmenu button.jsoneditor-insert:focus > div.jsoneditor-icon { - background-position: 0 0; -} - -div.jsoneditor-contextmenu button.jsoneditor-duplicate > div.jsoneditor-icon { - background-position: -48px -24px; -} - -div.jsoneditor-contextmenu button.jsoneditor-duplicate:hover > div.jsoneditor-icon, -div.jsoneditor-contextmenu button.jsoneditor-duplicate:focus > div.jsoneditor-icon { - background-position: -48px 0; -} - -div.jsoneditor-contextmenu button.jsoneditor-sort-asc > div.jsoneditor-icon { - background-position: -168px -24px; -} - -div.jsoneditor-contextmenu button.jsoneditor-sort-asc:hover > div.jsoneditor-icon, -div.jsoneditor-contextmenu button.jsoneditor-sort-asc:focus > div.jsoneditor-icon { - background-position: -168px 0; -} - -div.jsoneditor-contextmenu button.jsoneditor-sort-desc > div.jsoneditor-icon { - background-position: -192px -24px; -} - -div.jsoneditor-contextmenu button.jsoneditor-sort-desc:hover > div.jsoneditor-icon, -div.jsoneditor-contextmenu button.jsoneditor-sort-desc:focus > div.jsoneditor-icon { - background-position: -192px 0; -} - -/* ContextMenu - sub menu */ - -div.jsoneditor-contextmenu ul li button.jsoneditor-selected, -div.jsoneditor-contextmenu ul li button.jsoneditor-selected:hover, -div.jsoneditor-contextmenu ul li button.jsoneditor-selected:focus { - color: white; - background-color: #ee422e; -} - -div.jsoneditor-contextmenu ul li { - overflow: hidden; -} - -div.jsoneditor-contextmenu ul li ul { - display: none; - position: relative; - left: -10px; - top: 0; - border: none; - box-shadow: inset 0 0 10px rgba(128, 128, 128, 0.5); - padding: 0 10px; - /* TODO: transition is not supported on IE8-9 */ - -webkit-transition: all 0.3s ease-out; - -moz-transition: all 0.3s ease-out; - -o-transition: all 0.3s ease-out; - transition: all 0.3s ease-out; -} - - - -div.jsoneditor-contextmenu ul li ul li button { - padding-left: 24px; - animation: all ease-in-out 1s; -} - -div.jsoneditor-contextmenu ul li ul li button:hover, -div.jsoneditor-contextmenu ul li ul li button:focus { - background-color: #f5f5f5; -} - -div.jsoneditor-contextmenu button.jsoneditor-type-string > div.jsoneditor-icon { - background-position: -144px -24px; -} - -div.jsoneditor-contextmenu button.jsoneditor-type-string:hover > div.jsoneditor-icon, -div.jsoneditor-contextmenu button.jsoneditor-type-string:focus > div.jsoneditor-icon, -div.jsoneditor-contextmenu button.jsoneditor-type-string.jsoneditor-selected > div.jsoneditor-icon { - background-position: -144px 0; -} - -div.jsoneditor-contextmenu button.jsoneditor-type-auto > div.jsoneditor-icon { - background-position: -120px -24px; -} - -div.jsoneditor-contextmenu button.jsoneditor-type-auto:hover > div.jsoneditor-icon, -div.jsoneditor-contextmenu button.jsoneditor-type-auto:focus > div.jsoneditor-icon, -div.jsoneditor-contextmenu button.jsoneditor-type-auto.jsoneditor-selected > div.jsoneditor-icon { - background-position: -120px 0; -} - -div.jsoneditor-contextmenu button.jsoneditor-type-object > div.jsoneditor-icon { - background-position: -72px -24px; -} - -div.jsoneditor-contextmenu button.jsoneditor-type-object:hover > div.jsoneditor-icon, -div.jsoneditor-contextmenu button.jsoneditor-type-object:focus > div.jsoneditor-icon, -div.jsoneditor-contextmenu button.jsoneditor-type-object.jsoneditor-selected > div.jsoneditor-icon { - background-position: -72px 0; -} - -div.jsoneditor-contextmenu button.jsoneditor-type-array > div.jsoneditor-icon { - background-position: -96px -24px; -} - -div.jsoneditor-contextmenu button.jsoneditor-type-array:hover > div.jsoneditor-icon, -div.jsoneditor-contextmenu button.jsoneditor-type-array:focus > div.jsoneditor-icon, -div.jsoneditor-contextmenu button.jsoneditor-type-array.jsoneditor-selected > div.jsoneditor-icon { - background-position: -96px 0; -} - -div.jsoneditor-contextmenu button.jsoneditor-type-modes > div.jsoneditor-icon { - background-image: none; - width: 6px; -} -div.jsoneditor-menu { - width: 100%; - height: 35px; - padding: 2px; - margin: 0; - -moz-box-sizing: border-box; - -webkit-box-sizing: border-box; - box-sizing: border-box; - color: white; - background-color: #2e2e2e; - border-bottom: 1px solid #2e2e2e; -} - -div.jsoneditor-menu > button, -div.jsoneditor-menu > div.jsoneditor-modes > button { - width: 26px; - height: 26px; - margin: 2px; - padding: 0; - border-radius: 2px; - border: 1px solid transparent; - background: transparent url("img/jsoneditor-icons.svg"); - color: white; - opacity: 0.8; - font-family: arial, sans-serif; - font-size: 10pt; - float: left; -} - -div.jsoneditor-menu > button:hover, -div.jsoneditor-menu > div.jsoneditor-modes > button:hover { - background-color: rgba(255,255,255,0.2); - border: 1px solid rgba(255,255,255,0.4); -} - -div.jsoneditor-menu > button:focus, -div.jsoneditor-menu > button:active, -div.jsoneditor-menu > div.jsoneditor-modes > button:focus, -div.jsoneditor-menu > div.jsoneditor-modes > button:active { - background-color: rgba(255,255,255,0.3); -} - -div.jsoneditor-menu > button:disabled, -div.jsoneditor-menu > div.jsoneditor-modes > button:disabled { - opacity: 0.5; -} - -div.jsoneditor-menu > button.jsoneditor-collapse-all { - background-position: 0 -96px; -} - -div.jsoneditor-menu > button.jsoneditor-expand-all { - background-position: 0 -120px; -} - -div.jsoneditor-menu > button.jsoneditor-undo { - background-position: -24px -96px; -} - -div.jsoneditor-menu > button.jsoneditor-undo:disabled { - background-position: -24px -120px; -} - -div.jsoneditor-menu > button.jsoneditor-redo { - background-position: -48px -96px; -} - -div.jsoneditor-menu > button.jsoneditor-redo:disabled { - background-position: -48px -120px; -} - -div.jsoneditor-menu > button.jsoneditor-compact { - background-position: -72px -96px; -} - -div.jsoneditor-menu > button.jsoneditor-format { - background-position: -72px -120px; -} - -div.jsoneditor-menu > div.jsoneditor-modes { - display: inline-block; - float: left; -} - -div.jsoneditor-menu > div.jsoneditor-modes > button { - background-image: none; - width: auto; - padding-left: 6px; - padding-right: 6px; -} - -div.jsoneditor-menu > button.jsoneditor-separator, -div.jsoneditor-menu > div.jsoneditor-modes > button.jsoneditor-separator { - margin-left: 10px; -} - -div.jsoneditor-menu a { - font-family: arial, sans-serif; - font-size: 10pt; - color: white; - opacity: 0.8; - vertical-align: middle; -} - -div.jsoneditor-menu a:hover { - opacity: 1; -} - -div.jsoneditor-menu a.jsoneditor-poweredBy { - font-size: 8pt; - position: absolute; - right: 0; - top: 0; - padding: 10px; -} -table.jsoneditor-search input, -table.jsoneditor-search div.jsoneditor-results { - font-family: arial, sans-serif; - font-size: 10pt; - color: #1A1A1A; - background: transparent; - /* For Firefox */ -} - -table.jsoneditor-search div.jsoneditor-results { - color: white; - padding-right: 5px; - line-height: 24px; -} - -table.jsoneditor-search { - position: absolute; - right: 4px; - top: 4px; - border-collapse: collapse; - border-spacing: 0; -} - -table.jsoneditor-search div.jsoneditor-frame { - border: 1px solid transparent; - background-color: white; - padding: 0 2px; - margin: 0; -} - -table.jsoneditor-search div.jsoneditor-frame table { - border-collapse: collapse; -} - -table.jsoneditor-search input { - width: 120px; - border: none; - outline: none; - margin: 1px; - line-height: 20px; -} - -table.jsoneditor-search button { - width: 16px; - height: 24px; - padding: 0; - margin: 0; - border: none; - background: url("img/jsoneditor-icons.svg"); - vertical-align: top; -} - -table.jsoneditor-search button:hover { - background-color: transparent; -} - -table.jsoneditor-search button.jsoneditor-refresh { - width: 18px; - background-position: -99px -73px; -} - -table.jsoneditor-search button.jsoneditor-next { - cursor: pointer; - background-position: -124px -73px; -} - -table.jsoneditor-search button.jsoneditor-next:hover { - background-position: -124px -49px; -} - -table.jsoneditor-search button.jsoneditor-previous { - cursor: pointer; - background-position: -148px -73px; - margin-right: 2px; -} - -table.jsoneditor-search button.jsoneditor-previous:hover { - background-position: -148px -49px; -} diff --git a/scripts/simplifiedUI/system/html/css/marketplaces.css b/scripts/simplifiedUI/system/html/css/marketplaces.css deleted file mode 100644 index 04c132eab1..0000000000 --- a/scripts/simplifiedUI/system/html/css/marketplaces.css +++ /dev/null @@ -1,224 +0,0 @@ -/* -// -// Copyright 2016 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -*/ - -/* - CSS rules copied from edit-style.css. - Edit-style.css is not used in its entirety because don't want custom scrollbars; default scrollbar styling is used in order - to match other marketplace pages. -*/ - -@font-face { - font-family: Raleway-Regular; - src: url(../../../../resources/fonts/Raleway-Regular.ttf), /* Windows production */ - url(../../../../fonts/Raleway-Regular.ttf), /* OSX production */ - url(../../../../interface/resources/fonts/Raleway-Regular.ttf); /* Development, running script in /HiFi/examples */ -} - -@font-face { - font-family: Raleway-Bold; - src: url(../../../../resources/fonts/Raleway-Bold.ttf), - url(../../../../fonts/Raleway-Bold.ttf), - url(../../../../interface/resources/fonts/Raleway-Bold.ttf); -} - -@font-face { - font-family: Raleway-SemiBold; - src: url(../../../../resources/fonts/Raleway-SemiBold.ttf), - url(../../../../fonts/Raleway-SemiBold.ttf), - url(../../../../interface/resources/fonts/Raleway-SemiBold.ttf); -} - -@font-face { - font-family: FiraSans-SemiBold; - src: url(../../../../resources/fonts/FiraSans-SemiBold.ttf), - url(../../../../fonts/FiraSans-SemiBold.ttf), - url(../../../../interface/resources/fonts/FiraSans-SemiBold.ttf); -} - -* { - margin: 0; - padding: 0; -} - -body { - padding: 21px 21px 21px 21px; - - color: #afafaf; - background-color: #404040; - font-family: Raleway-Regular; - font-size: 15px; - - -webkit-touch-callout: none; - -webkit-user-select: none; - -khtml-user-select: none; - -moz-user-select: none; - -ms-user-select: none; - user-select: none; - - overflow-x: hidden; - overflow-y: auto; -} - -input[type=button] { - font-family: Raleway-Bold; - font-size: 13px; - text-transform: uppercase; - vertical-align: top; - height: 28px; - min-width: 120px; - padding: 0px 18px; - margin-right: 6px; - border-radius: 5px; - border: none; - color: #fff; - background-color: #000; - background: linear-gradient(#343434 20%, #000 100%); - cursor: pointer; -} - -input[type=button].blue { - color: #fff; - background-color: #1080b8; - background: linear-gradient(#00b4ef 20%, #1080b8 100%); -} - - -/* - Marketplaces-specific CSS. -*/ - -body { - background: white; - padding: 0 0 0 0; - font-family:Raleway-SemiBold; -} -.marketplaces-container { - display: inline-block; - color: black; - width: 94%; - margin-left: 3%; - height: 100%; -} -.marketplaces-title { - margin-top: 45px; - margin-bottom: 20px; -} -.marketplaces-intro-text { - margin-bottom: 30px; -} -.marketplace-tile { - float:left; - width: 100%; - margin-bottom: 25px; -} -.marketplace-tile-first-column { - text-align: center; - float: left; - width: 33%; -} -.marketplace-tile-second-column { - float: left; - margin-left:4%; - width: 62%; -} -.exploreButton { - font-size: 16px !important; - width: 200px !important; - height: 45px !important; - margin-top: 20px; - margin-bottom: 30px; -} -.tile-divider { - width: 100%; - margin-left: 0%; - display: block; - height: 1px; - border: 0; - border-top: 1px solid lightgrey; - margin: 1em 0; - padding: 0; - margin-bottom: 30px; -} -.marketplace-tile-description { - margin-top: 15px; - margin-bottom: 30px; -} -.marketplace-tile-image { - margin-top:15px; - max-width: 256px; - height: 128px; - margin-bottom:60px; - -webkit-box-shadow: -1px 4px 16px 0px rgba(0, 0, 0, 0.48); - -moz-box-shadow: -1px 4px 16px 0px rgba(0, 0, 0, 0.48); - box-shadow: -1px 4px 16px 0px rgba(0, 0, 0, 0.48); -} -.marketplace-clara-steps { - padding-left: 15px; -} -.marketplace-clara-steps > li { - margin-top: 5px; -} - -#marketplace-navigation { - width: 100%; - height: 50px; - background: #00b4ef; - position: fixed; - bottom: 0; -} -#marketplace-navigation .glyph { - /* - // Target look but can't use font in injected script. - font-family: HiFi-Glyphs; - font-size: 40px; - margin-left: 20px; - */ - font-family: sans-serif; - font-size: 24px; - margin-left: 20px; - margin-right: 3px; - color: #fff; - line-height: 50px; -} -#marketplace-navigation .text { - color: #fff; - font-size: 18px; - line-height: 50px; - vertical-align: top; - position: relative; - top: 1px; -} -#marketplace-navigation input { - position: absolute; - right: 20px; - margin-top: 12px; - padding-left: 15px; - padding-right: 15px; -} - -@media (max-width:768px) { - .marketplace-tile-first-column { - float: left; - width: 100%; - } - .marketplace-tile-second-column { - float: left; - width: 100%; - } - .exploreButton-holder { - width:100%; - text-align:center; - } - .tile-divider { - width: 100%; - margin-left: 0; - } - .marketplace-tile-image { - margin-bottom: 15px; - } -} diff --git a/scripts/simplifiedUI/system/html/css/miniTablet.css b/scripts/simplifiedUI/system/html/css/miniTablet.css deleted file mode 100644 index 7598332d28..0000000000 --- a/scripts/simplifiedUI/system/html/css/miniTablet.css +++ /dev/null @@ -1,92 +0,0 @@ -/* -miniTablet.css - -Created by David Rowe on 20 Aug 2018. -Copyright 2018 High Fidelity, Inc. - -Distributed under the Apache License, Version 2.0. -See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -*/ - -* { - box-sizing: border-box; - padding: 0; - margin: 0; - user-select: none; -} - -html { - background-color: #404040; -} - -body { - height: 100%; -} - -section { - background-color: #404040; - position: relative; - padding: 16px 16px; -} - -.button { - width: 116px; - height: 84px; - margin-top: 16px; - text-align: center; -} - - .button:first-child { - margin-top: 0; - } - -img { - width: 40px; -} - -#mute { - padding-top: 19px; - background-size: 100% 100%; - background-image: url("./img/mt-mute-normal.svg"); -} - - #mute:hover { - background-image: url("./img/mt-mute-hover.svg"); - } - -#goto { - padding-top: 19px; - background-size: 100% 100%; - background-image: url("./img/mt-goto-normal.svg"); -} - - #goto:hover { - background-image: url("./img/mt-goto-hover.svg"); - } - - #goto:hover.unhover { - background-image: url("./img/mt-goto-normal.svg"); - } - -#expand { - position: absolute; - right: 1px; - bottom: -1px; - width: 50px; - height: 50px; - background-size: 100% 100%; - background-image: url("./img/mt-expand-normal.svg"); -} - - #expand:hover { - background-image: url("./img/mt-expand-hover.svg"); - } - - #expand:hover.unhover { - background-image: url("./img/mt-expand-normal.svg"); - } - - #expand img { - width:34px; - margin-top: 7px; - } diff --git a/scripts/simplifiedUI/system/html/gridControls.html b/scripts/simplifiedUI/system/html/gridControls.html deleted file mode 100644 index 8d6ee34bc0..0000000000 --- a/scripts/simplifiedUI/system/html/gridControls.html +++ /dev/null @@ -1,71 +0,0 @@ - - - - - - - - - - - - - - -
-
- -
- - -
-
-
- -
- - -
-
-
- -
- -
-
-
- -
- -
-
-
- -
- -
-
-
- -
-
-
-
-
- -
- - -
-
-
- - diff --git a/scripts/simplifiedUI/system/html/img/blast_icon.svg b/scripts/simplifiedUI/system/html/img/blast_icon.svg deleted file mode 100644 index 31df8e7f53..0000000000 --- a/scripts/simplifiedUI/system/html/img/blast_icon.svg +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - - diff --git a/scripts/simplifiedUI/system/html/img/blocks-tile.png b/scripts/simplifiedUI/system/html/img/blocks-tile.png deleted file mode 100644 index 49de535c1c..0000000000 Binary files a/scripts/simplifiedUI/system/html/img/blocks-tile.png and /dev/null differ diff --git a/scripts/simplifiedUI/system/html/img/button-snap-print.svg b/scripts/simplifiedUI/system/html/img/button-snap-print.svg deleted file mode 100644 index d1570711d7..0000000000 --- a/scripts/simplifiedUI/system/html/img/button-snap-print.svg +++ /dev/null @@ -1,25 +0,0 @@ - - - - - - - - - - - - - - - - - - - - diff --git a/scripts/simplifiedUI/system/html/img/clara-tile.png b/scripts/simplifiedUI/system/html/img/clara-tile.png deleted file mode 100644 index ae431dd510..0000000000 Binary files a/scripts/simplifiedUI/system/html/img/clara-tile.png and /dev/null differ diff --git a/scripts/simplifiedUI/system/html/img/expand.svg b/scripts/simplifiedUI/system/html/img/expand.svg deleted file mode 100644 index f57e624374..0000000000 --- a/scripts/simplifiedUI/system/html/img/expand.svg +++ /dev/null @@ -1,85 +0,0 @@ - - - -image/svg+xml - - - - - - - - - \ No newline at end of file diff --git a/scripts/simplifiedUI/system/html/img/fb_icon.svg b/scripts/simplifiedUI/system/html/img/fb_icon.svg deleted file mode 100644 index 6d67d17bb2..0000000000 --- a/scripts/simplifiedUI/system/html/img/fb_icon.svg +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - diff --git a/scripts/simplifiedUI/system/html/img/hifi-marketplace-tile.png b/scripts/simplifiedUI/system/html/img/hifi-marketplace-tile.png deleted file mode 100644 index 9a95c081a0..0000000000 Binary files a/scripts/simplifiedUI/system/html/img/hifi-marketplace-tile.png and /dev/null differ diff --git a/scripts/simplifiedUI/system/html/img/hifi_icon.svg b/scripts/simplifiedUI/system/html/img/hifi_icon.svg deleted file mode 100644 index acbb98a3b3..0000000000 --- a/scripts/simplifiedUI/system/html/img/hifi_icon.svg +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - - diff --git a/scripts/simplifiedUI/system/html/img/loader.gif b/scripts/simplifiedUI/system/html/img/loader.gif deleted file mode 100644 index c464703c84..0000000000 Binary files a/scripts/simplifiedUI/system/html/img/loader.gif and /dev/null differ diff --git a/scripts/simplifiedUI/system/html/img/snapshotIcon.png b/scripts/simplifiedUI/system/html/img/snapshotIcon.png deleted file mode 100644 index 5cb2742a32..0000000000 Binary files a/scripts/simplifiedUI/system/html/img/snapshotIcon.png and /dev/null differ diff --git a/scripts/simplifiedUI/system/html/img/twitter_icon.svg b/scripts/simplifiedUI/system/html/img/twitter_icon.svg deleted file mode 100644 index 0393d963f2..0000000000 --- a/scripts/simplifiedUI/system/html/img/twitter_icon.svg +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - diff --git a/scripts/simplifiedUI/system/html/js/SnapshotReview.js b/scripts/simplifiedUI/system/html/js/SnapshotReview.js deleted file mode 100644 index 1e8be9d644..0000000000 --- a/scripts/simplifiedUI/system/html/js/SnapshotReview.js +++ /dev/null @@ -1,814 +0,0 @@ -/*jslint browser:true */ -/*jslint maxlen: 180*/ -"use strict"; -// -// SnapshotReview.js -// scripts/system/html/js/ -// -// Created by Howard Stearns 8/22/2016 -// Copyright 2016 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -var paths = []; -var idCounter = 0; -var imageCount = 0; -var blastShareText = "Blast to my Connections", - blastAlreadySharedText = "Already Blasted to Connections", - hifiShareText = "Share to Snaps Feed", - hifiAlreadySharedText = "Already Shared to Snaps Feed", - facebookShareText = "Share to Facebook", - twitterShareText = "Share to Twitter", - shareButtonLabelTextActive = "SHARE:", - shareButtonLabelTextInactive = "SHARE"; - -function fileExtensionMatches(filePath, extension) { - return filePath.split('.').pop().toLowerCase() === extension; -} - -function showSetupInstructions() { - var snapshotImagesDiv = document.getElementById("snapshot-images"); - snapshotImagesDiv.className = "snapshotInstructions"; - snapshotImagesDiv.innerHTML = 'Snapshot Instructions' + - '
' + - '

Take and share snaps and GIFs with people in High Fidelity, Facebook, and Twitter.

' + - "

Setup Instructions

" + - "

Before you can begin taking snaps, please choose where you'd like to save snaps on your computer:

" + - '
' + - '
' + - '' + - '
'; - document.getElementById("snap-button").disabled = true; -} -function showSetupComplete() { - var snapshotImagesDiv = document.getElementById("snapshot-images"); - snapshotImagesDiv.className = "snapshotInstructions"; - snapshotImagesDiv.innerHTML = 'Snapshot Instructions' + - '
' + - '
' + - '

Snapshot location set.

' + - '

Press the big red button to take a snap!

' + - '
'; - document.getElementById("snap-button").disabled = false; -} -function showSnapshotInstructions() { - var snapshotImagesDiv = document.getElementById("snapshot-images"); - snapshotImagesDiv.className = "snapshotInstructions"; - snapshotImagesDiv.innerHTML = 'Snapshot Instructions' + - '
' + - '

Take and share snaps and GIFs with people in High Fidelity, Facebook, and Twitter.

' + - '
' + - '
' + - '

Press the big red button to take a snap!

' + - '
'; -} -function chooseSnapshotLocation() { - EventBridge.emitWebEvent(JSON.stringify({ - type: "snapshot", - action: "chooseSnapshotLocation" - })); -} -function login() { - EventBridge.emitWebEvent(JSON.stringify({ - type: "snapshot", - action: "login" - })); -} -function clearImages() { - var snapshotImagesDiv = document.getElementById("snapshot-images"); - snapshotImagesDiv.classList.remove("snapshotInstructions"); - while (snapshotImagesDiv.hasChildNodes()) { - snapshotImagesDiv.removeChild(snapshotImagesDiv.lastChild); - } - paths = []; - imageCount = 0; - idCounter = 0; -} - -function selectImageWithHelpText(selectedID, isSelected) { - if (selectedID.id) { - selectedID = selectedID.id; // sometimes (?), `selectedID` is passed as an HTML object to these functions; we just want the ID - } - var imageContainer = document.getElementById(selectedID), - image = document.getElementById(selectedID + 'img'), - shareBar = document.getElementById(selectedID + "shareBar"), - helpTextDiv = document.getElementById(selectedID + "helpTextDiv"), - showShareButtonsButtonDiv = document.getElementById(selectedID + "showShareButtonsButtonDiv"), - itr, - containers = document.getElementsByClassName("shareControls"); - - if (isSelected) { - showShareButtonsButtonDiv.onclick = function () { selectImageWithHelpText(selectedID, false); }; - showShareButtonsButtonDiv.classList.remove("inactive"); - showShareButtonsButtonDiv.classList.add("active"); - - image.onclick = function () { selectImageWithHelpText(selectedID, false); }; - imageContainer.style.outline = "4px solid #00b4ef"; - imageContainer.style.outlineOffset = "-4px"; - - shareBar.style.backgroundColor = "rgba(0, 0, 0, 0.45)"; - shareBar.style.pointerEvents = "initial"; - - helpTextDiv.style.visibility = "visible"; - - for (itr = 0; itr < containers.length; itr += 1) { - var parentID = containers[itr].id.slice(0, 2); - if (parentID !== selectedID) { - selectImageWithHelpText(parentID, false); - } - } - } else { - showShareButtonsButtonDiv.onclick = function () { selectImageWithHelpText(selectedID, true); }; - showShareButtonsButtonDiv.classList.remove("active"); - showShareButtonsButtonDiv.classList.add("inactive"); - - image.onclick = function () { selectImageWithHelpText(selectedID, true); }; - imageContainer.style.outline = "none"; - - shareBar.style.backgroundColor = "rgba(0, 0, 0, 0.0)"; - shareBar.style.pointerEvents = "none"; - - helpTextDiv.style.visibility = "hidden"; - } -} -function selectImageToShare(selectedID, isSelected) { - if (selectedID.id) { - selectedID = selectedID.id; // sometimes (?), `selectedID` is passed as an HTML object to these functions; we just want the ID - } - var imageContainer = document.getElementById(selectedID), - image = document.getElementById(selectedID + 'img'), - shareBar = document.getElementById(selectedID + "shareBar"), - showShareButtonsDots = document.getElementById(selectedID + "showShareButtonsDots"), - showShareButtonsLabel = document.getElementById(selectedID + "showShareButtonsLabel"), - shareButtonsDiv = document.getElementById(selectedID + "shareButtonsDiv"), - shareBarHelp = document.getElementById(selectedID + "shareBarHelp"), - showShareButtonsButtonDiv = document.getElementById(selectedID + "showShareButtonsButtonDiv"), - itr, - containers = document.getElementsByClassName("shareControls"); - - if (isSelected) { - showShareButtonsButtonDiv.onclick = function () { selectImageToShare(selectedID, false); }; - showShareButtonsButtonDiv.classList.remove("inactive"); - showShareButtonsButtonDiv.classList.add("active"); - - image.onclick = function () { selectImageToShare(selectedID, false); }; - imageContainer.style.outline = "4px solid #00b4ef"; - imageContainer.style.outlineOffset = "-4px"; - - shareBar.style.backgroundColor = "rgba(0, 0, 0, 0.45)"; - shareBar.style.pointerEvents = "initial"; - - showShareButtonsDots.style.visibility = "hidden"; - showShareButtonsLabel.innerHTML = shareButtonLabelTextActive; - - shareButtonsDiv.style.visibility = "visible"; - shareBarHelp.style.visibility = "visible"; - - for (itr = 0; itr < containers.length; itr += 1) { - var parentID = containers[itr].id.slice(0, 2); - if (parentID !== selectedID) { - selectImageToShare(parentID, false); - } - } - } else { - showShareButtonsButtonDiv.onclick = function () { selectImageToShare(selectedID, true); }; - showShareButtonsButtonDiv.classList.remove("active"); - showShareButtonsButtonDiv.classList.add("inactive"); - - image.onclick = function () { selectImageToShare(selectedID, true); }; - imageContainer.style.outline = "none"; - - shareBar.style.backgroundColor = "rgba(0, 0, 0, 0.0)"; - shareBar.style.pointerEvents = "none"; - - showShareButtonsDots.style.visibility = "visible"; - showShareButtonsLabel.innerHTML = shareButtonLabelTextInactive; - - shareButtonsDiv.style.visibility = "hidden"; - shareBarHelp.style.visibility = "hidden"; - } -} -function createShareBar(parentID, isLoggedIn, canShare, isGif, blastButtonDisabled, hifiButtonDisabled, canBlast) { - var shareBar = document.createElement("div"), - shareBarHelpID = parentID + "shareBarHelp", - shareButtonsDivID = parentID + "shareButtonsDiv", - showShareButtonsButtonDivID = parentID + "showShareButtonsButtonDiv", - showShareButtonsDotsID = parentID + "showShareButtonsDots", - showShareButtonsLabelID = parentID + "showShareButtonsLabel", - blastToConnectionsButtonID = parentID + "blastToConnectionsButton", - shareWithEveryoneButtonID = parentID + "shareWithEveryoneButton", - facebookButtonID = parentID + "facebookButton", - twitterButtonID = parentID + "twitterButton", - shareBarInnerHTML = ''; - - shareBar.id = parentID + "shareBar"; - shareBar.className = "shareControls"; - - if (isLoggedIn) { - if (canShare) { - shareBarInnerHTML = '' + - '
' + - '' + - '' + - '' + - '
' + - '' + - ''; - - // Add onclick handler to parent DIV's img to toggle share buttons - document.getElementById(parentID + 'img').onclick = function () { selectImageToShare(parentID, true); }; - } else { - shareBarInnerHTML = '
' + - '' + - '' + - '' + - '
' + - '' + - ''; - // Add onclick handler to parent DIV's img to toggle share buttons - document.getElementById(parentID + 'img').onclick = function () { selectImageWithHelpText(parentID, true); }; - } - } else { - shareBarInnerHTML = '
' + - '' + - '' + - '' + - '
' + - '' + - ''; - // Add onclick handler to parent DIV's img to toggle share buttons - document.getElementById(parentID + 'img').onclick = function () { selectImageWithHelpText(parentID, true); }; - } - - shareBar.innerHTML = shareBarInnerHTML; - - return shareBar; -} -function appendShareBar(divID, isLoggedIn, canShare, isGif, blastButtonDisabled, hifiButtonDisabled, canBlast) { - if (divID.id) { - divID = divID.id; // sometimes (?), `containerID` is passed as an HTML object to these functions; we just want the ID - } - document.getElementById(divID).appendChild(createShareBar(divID, isLoggedIn, canShare, isGif, blastButtonDisabled, hifiButtonDisabled, canBlast)); - if (divID === "p0") { - if (isLoggedIn) { - if (canShare) { - selectImageToShare(divID, true); - } else { - selectImageWithHelpText(divID, true); - } - } else { - selectImageWithHelpText(divID, true); - } - } - if (isLoggedIn && canShare) { - if (canBlast) { - shareButtonHovered('blast', divID, false); - } else { - shareButtonHovered('hifi', divID, false); - } - } -} -function shareForUrl(selectedID) { - EventBridge.emitWebEvent(JSON.stringify({ - type: "snapshot", - action: "shareSnapshotForUrl", - data: paths[parseInt(selectedID.substring(1), 10)] - })); -} -function addImage(image_data, isLoggedIn, canShare, isGifLoading, isShowingPreviousImages, blastButtonDisabled, hifiButtonDisabled, canBlast) { - if (!image_data.localPath) { - return; - } - var imageContainer = document.createElement("DIV"), - img = document.createElement("IMG"), - isGif = fileExtensionMatches(image_data.localPath, "gif"), - id = "p" + (isGif ? "1" : "0"); - imageContainer.id = id; - imageContainer.style.width = "95%"; - imageContainer.style.height = "240px"; - imageContainer.style.margin = "5px auto"; - imageContainer.style.display = "flex"; - imageContainer.style.justifyContent = "center"; - imageContainer.style.alignItems = "center"; - imageContainer.style.position = "relative"; - img.id = id + "img"; - img.src = image_data.localPath; - imageContainer.appendChild(img); - document.getElementById("snapshot-images").appendChild(imageContainer); - paths.push(image_data.localPath); - img.onload = function () { - if (isGif) { - imageContainer.innerHTML += 'GIF'; - } - if (!isGifLoading) { - appendShareBar(id, isLoggedIn, canShare, isGif, blastButtonDisabled, hifiButtonDisabled, canBlast); - } - if ((!isShowingPreviousImages && ((isGif && !isGifLoading) || !isGif)) || (isShowingPreviousImages && !image_data.story_id)) { - shareForUrl(id); - } - if (isShowingPreviousImages && isLoggedIn && image_data.story_id) { - updateShareInfo(id, image_data.story_id); - } - if (isShowingPreviousImages) { - requestPrintButtonUpdate(); - } - }; - img.onerror = function () { - img.onload = null; - img.src = image_data.errorPath; - EventBridge.emitWebEvent(JSON.stringify({ - type: "snapshot", - action: "alertSnapshotLoadFailed" - })); - }; -} -function showConfirmationMessage(selectedID, destination) { - if (selectedID.id) { - selectedID = selectedID.id; // sometimes (?), `containerID` is passed as an HTML object to these functions; we just want the ID - } - - var opacity = 2.0, - fadeRate = 0.05, - timeBetweenFadesMS = 50, - confirmationMessageContainer = document.createElement("div"), - confirmationMessage = document.createElement("div"); - confirmationMessageContainer.className = "confirmationMessageContainer"; - - confirmationMessage.className = "confirmationMessage"; - - var socialIcon = document.createElement("img"); - switch (destination) { - case 'blast': - socialIcon.src = "img/blast_icon.svg"; - confirmationMessage.appendChild(socialIcon); - confirmationMessage.innerHTML += 'Blast Sent!'; - confirmationMessage.style.backgroundColor = "#EA4C5F"; - break; - case 'hifi': - socialIcon.src = "img/hifi_icon.svg"; - confirmationMessage.appendChild(socialIcon); - confirmationMessage.innerHTML += 'Snap Shared!'; - confirmationMessage.style.backgroundColor = "#1FC6A6"; - break; - } - - confirmationMessageContainer.appendChild(confirmationMessage); - document.getElementById(selectedID).appendChild(confirmationMessageContainer); - - setInterval(function () { - if (opacity <= fadeRate) { - confirmationMessageContainer.remove(); - } - opacity -= fadeRate; - confirmationMessageContainer.style.opacity = opacity; - }, timeBetweenFadesMS); -} -function showUploadingMessage(selectedID, destination) { - if (selectedID.id) { - selectedID = selectedID.id; // sometimes (?), `containerID` is passed as an HTML object to these functions; we just want the ID - } - - var shareBarHelp = document.getElementById(selectedID + "shareBarHelp"); - - shareBarHelp.innerHTML = 'Preparing to Share'; - shareBarHelp.classList.add("uploading"); - shareBarHelp.setAttribute("data-destination", destination); -} -function hideUploadingMessageAndMaybeShare(selectedID, storyID) { - if (selectedID.id) { - selectedID = selectedID.id; // sometimes (?), `containerID` is passed as an HTML object to these functions; we just want the ID - } - - var shareBarHelp = document.getElementById(selectedID + "shareBarHelp"), - shareBarHelpDestination = shareBarHelp.getAttribute("data-destination"); - - shareBarHelp.classList.remove("uploading"); - if (shareBarHelpDestination) { - switch (shareBarHelpDestination) { - case 'blast': - blastToConnections(selectedID, selectedID === "p1"); - shareBarHelp.innerHTML = blastAlreadySharedText; - break; - case 'hifi': - shareWithEveryone(selectedID, selectedID === "p1"); - shareBarHelp.innerHTML = hifiAlreadySharedText; - break; - case 'facebook': - var facebookButton = document.getElementById(selectedID + "facebookButton"); - window.open(facebookButton.getAttribute("href"), "_blank"); - shareBarHelp.innerHTML = facebookShareText; - // This emitWebEvent() call isn't necessary in the "hifi" and "blast" cases - // because the "removeFromStoryIDsToMaybeDelete()" call happens - // in snapshot.js when sharing with that method. - EventBridge.emitWebEvent(JSON.stringify({ - type: "snapshot", - action: "removeFromStoryIDsToMaybeDelete", - story_id: storyID - })); - break; - case 'twitter': - var twitterButton = document.getElementById(selectedID + "twitterButton"); - window.open(twitterButton.getAttribute("href"), "_blank"); - shareBarHelp.innerHTML = twitterShareText; - EventBridge.emitWebEvent(JSON.stringify({ - type: "snapshot", - action: "removeFromStoryIDsToMaybeDelete", - story_id: storyID - })); - break; - } - - shareBarHelp.setAttribute("data-destination", ""); - } -} -function updateShareInfo(containerID, storyID) { - if (containerID.id) { - containerID = containerID.id; // sometimes (?), `containerID` is passed as an HTML object to these functions; we just want the ID - } - var shareBar = document.getElementById(containerID + "shareBar"), - parentDiv = document.getElementById(containerID), - shareURL = "https://highfidelity.com/user_stories/" + storyID, - facebookButton = document.getElementById(containerID + "facebookButton"), - twitterButton = document.getElementById(containerID + "twitterButton"); - - parentDiv.setAttribute('data-story-id', storyID); - - facebookButton.setAttribute("target", "_blank"); - facebookButton.setAttribute("href", 'https://www.facebook.com/dialog/feed?app_id=1585088821786423&link=' + shareURL); - - twitterButton.setAttribute("target", "_blank"); - twitterButton.setAttribute("href", 'https://twitter.com/intent/tweet?text=I%20just%20took%20a%20snapshot!&url=' + shareURL + '&via=highfidelityVR&hashtags=VR,HiFi'); - - hideUploadingMessageAndMaybeShare(containerID, storyID); -} -function blastToConnections(selectedID, isGif) { - if (selectedID.id) { - selectedID = selectedID.id; // sometimes (?), `selectedID` is passed as an HTML object to these functions; we just want the ID - } - - var blastToConnectionsButton = document.getElementById(selectedID + "blastToConnectionsButton"), - shareBar = document.getElementById(selectedID + "shareBar"), - shareBarHelp = document.getElementById(selectedID + "shareBarHelp"); - blastToConnectionsButton.onclick = function () { }; - - var storyID = document.getElementById(selectedID).getAttribute("data-story-id"); - - if (storyID) { - EventBridge.emitWebEvent(JSON.stringify({ - type: "snapshot", - action: "blastToConnections", - story_id: storyID, - isGif: isGif - })); - showConfirmationMessage(selectedID, 'blast'); - blastToConnectionsButton.classList.add("disabled"); - blastToConnectionsButton.style.backgroundColor = "#000000"; - blastToConnectionsButton.style.opacity = "0.5"; - shareBarHelp.style.backgroundColor = "#000000"; - shareBarHelp.style.opacity = "0.5"; - } else { - showUploadingMessage(selectedID, 'blast'); - } -} -function shareWithEveryone(selectedID, isGif) { - if (selectedID.id) { - selectedID = selectedID.id; // sometimes (?), `selectedID` is passed as an HTML object to these functions; we just want the ID - } - - var shareWithEveryoneButton = document.getElementById(selectedID + "shareWithEveryoneButton"), - shareBar = document.getElementById(selectedID + "shareBar"), - shareBarHelp = document.getElementById(selectedID + "shareBarHelp"); - shareWithEveryoneButton.onclick = function () { }; - - var storyID = document.getElementById(selectedID).getAttribute("data-story-id"); - - if (storyID) { - EventBridge.emitWebEvent(JSON.stringify({ - type: "snapshot", - action: "shareSnapshotWithEveryone", - story_id: storyID, - isGif: isGif - })); - showConfirmationMessage(selectedID, 'hifi'); - shareWithEveryoneButton.classList.add("disabled"); - shareWithEveryoneButton.style.backgroundColor = "#000000"; - shareWithEveryoneButton.style.opacity = "0.5"; - shareBarHelp.style.backgroundColor = "#000000"; - shareBarHelp.style.opacity = "0.5"; - } else { - showUploadingMessage(selectedID, 'hifi'); - } -} -function shareButtonHovered(destination, selectedID, shouldAlsoModifyOther) { - if (selectedID.id) { - selectedID = selectedID.id; // sometimes (?), `selectedID` is passed as an HTML object to these functions; we just want the ID - } - var shareBarHelp = document.getElementById(selectedID + "shareBarHelp"), - shareButtonsDiv = document.getElementById(selectedID + "shareButtonsDiv").childNodes, - itr; - - if (!shareBarHelp.classList.contains("uploading")) { - for (itr = 0; itr < shareButtonsDiv.length; itr += 1) { - shareButtonsDiv[itr].style.backgroundColor = "rgba(0, 0, 0, 0)"; - } - shareBarHelp.style.opacity = "1.0"; - switch (destination) { - case 'blast': - var blastToConnectionsButton = document.getElementById(selectedID + "blastToConnectionsButton"); - if (!blastToConnectionsButton.classList.contains("disabled")) { - shareBarHelp.style.backgroundColor = "#EA4C5F"; - shareBarHelp.style.opacity = "1.0"; - blastToConnectionsButton.style.backgroundColor = "#EA4C5F"; - blastToConnectionsButton.style.opacity = "1.0"; - shareBarHelp.innerHTML = blastShareText; - } else { - shareBarHelp.style.backgroundColor = "#000000"; - shareBarHelp.style.opacity = "0.5"; - blastToConnectionsButton.style.backgroundColor = "#000000"; - blastToConnectionsButton.style.opacity = "0.5"; - shareBarHelp.innerHTML = blastAlreadySharedText; - } - break; - case 'hifi': - var shareWithEveryoneButton = document.getElementById(selectedID + "shareWithEveryoneButton"); - if (!shareWithEveryoneButton.classList.contains("disabled")) { - shareBarHelp.style.backgroundColor = "#1FC6A6"; - shareBarHelp.style.opacity = "1.0"; - shareWithEveryoneButton.style.backgroundColor = "#1FC6A6"; - shareWithEveryoneButton.style.opacity = "1.0"; - shareBarHelp.innerHTML = hifiShareText; - } else { - shareBarHelp.style.backgroundColor = "#000000"; - shareBarHelp.style.opacity = "0.5"; - shareWithEveryoneButton.style.backgroundColor = "#000000"; - shareWithEveryoneButton.style.opacity = "0.5"; - shareBarHelp.innerHTML = hifiAlreadySharedText; - } - break; - case 'facebook': - shareBarHelp.style.backgroundColor = "#3C58A0"; - shareBarHelp.innerHTML = facebookShareText; - document.getElementById(selectedID + "facebookButton").style.backgroundColor = "#3C58A0"; - break; - case 'twitter': - shareBarHelp.style.backgroundColor = "#00B4EE"; - shareBarHelp.innerHTML = twitterShareText; - document.getElementById(selectedID + "twitterButton").style.backgroundColor = "#00B4EE"; - break; - } - } - - if (shouldAlsoModifyOther && imageCount > 1) { - if (selectedID === "p0" && !document.getElementById("p1").classList.contains("processingGif")) { - shareButtonHovered(destination, "p1", false); - } else if (selectedID === "p1") { - shareButtonHovered(destination, "p0", false); - } - } -} -function shareButtonClicked(destination, selectedID) { - if (selectedID.id) { - selectedID = selectedID.id; // sometimes (?), `selectedID` is passed as an HTML object to these functions; we just want the ID - } - var storyID = document.getElementById(selectedID).getAttribute("data-story-id"); - - if (!storyID) { - showUploadingMessage(selectedID, destination); - } else { - EventBridge.emitWebEvent(JSON.stringify({ - type: "snapshot", - action: "removeFromStoryIDsToMaybeDelete", - story_id: storyID - })); - } -} - -function handleCaptureSetting(setting) { - var stillAndGif = document.getElementById('stillAndGif'), - stillOnly = document.getElementById('stillOnly'); - - stillAndGif.checked = setting; - stillOnly.checked = !setting; - - stillAndGif.onclick = function () { - EventBridge.emitWebEvent(JSON.stringify({ - type: "snapshot", - action: "captureStillAndGif" - })); - }; - - stillOnly.onclick = function () { - EventBridge.emitWebEvent(JSON.stringify({ - type: "snapshot", - action: "captureStillOnly" - })); - }; - -} -window.onload = function () { - // Uncomment the line below to test functionality in a browser. - // See definition of "testInBrowser()" to modify tests. - //testInBrowser(4); - openEventBridge(function () { - // Set up a handler for receiving the data, and tell the .js we are ready to receive it. - EventBridge.scriptEventReceived.connect(function (message) { - - message = JSON.parse(message); - - if (message.type !== "snapshot") { - return; - } - - var messageOptions = message.options; - - switch (message.action) { - case 'showSetupInstructions': - showSetupInstructions(); - break; - case 'snapshotLocationChosen': - clearImages(); - showSetupComplete(); - break; - case 'clearPreviousImages': - clearImages(); - break; - case 'showPreviousImages': - clearImages(); - imageCount = message.image_data.length; - if (imageCount > 0) { - message.image_data.forEach(function (element, idx) { - addImage(element, messageOptions.isLoggedIn, message.canShare, false, true, message.image_data[idx].blastButtonDisabled, message.image_data[idx].hifiButtonDisabled, messageOptions.canBlast); - }); - } else { - showSnapshotInstructions(); - } - break; - case 'addImages': - // The last element of the message contents list contains a bunch of options, - // including whether or not we can share stuff - // The other elements of the list contain image paths. - if (messageOptions.containsGif === true) { - if (messageOptions.processingGif === true) { - imageCount = message.image_data.length + 1; // "+1" for the GIF that'll finish processing soon - message.image_data.push({ localPath: messageOptions.loadingGifPath }); - message.image_data.forEach(function (element, idx) { - addImage(element, messageOptions.isLoggedIn, idx === 0 && messageOptions.canShare, idx === 1, false, false, false, true); - }); - document.getElementById("p1").classList.add("processingGif"); - document.getElementById("snap-button").disabled = true; - } else { - var gifPath = message.image_data[0].localPath, - p1img = document.getElementById('p1img'); - p1img.src = gifPath; - - paths[1] = gifPath; - shareForUrl("p1"); - appendShareBar("p1", messageOptions.isLoggedIn, messageOptions.canShare, true, false, false, messageOptions.canBlast); - document.getElementById("p1").classList.remove("processingGif"); - document.getElementById("snap-button").disabled = false; - } - } else { - imageCount = message.image_data.length; - message.image_data.forEach(function (element) { - addImage(element, messageOptions.isLoggedIn, messageOptions.canShare, false, false, false, false, true); - }); - document.getElementById("snap-button").disabled = false; - } - break; - case 'captureSettings': - handleCaptureSetting(message.setting); - break; - case 'setPrintButtonEnabled': - setPrintButtonEnabled(); - break; - case 'setPrintButtonLoading': - setPrintButtonLoading(); - break; - case 'setPrintButtonDisabled': - setPrintButtonDisabled(); - break; - case 'snapshotUploadComplete': - var isGif = fileExtensionMatches(message.image_url, "gif"); - updateShareInfo(isGif ? "p1" : "p0", message.story_id); - if (isPrintProcessing()) { - setPrintButtonEnabled(); - } - break; - default: - console.log("Unknown message action received in SnapshotReview.js."); - break; - } - }); - - EventBridge.emitWebEvent(JSON.stringify({ - type: "snapshot", - action: "ready" - })); - });; -}; -function snapshotSettings() { - EventBridge.emitWebEvent(JSON.stringify({ - type: "snapshot", - action: "openSettings" - })); -} -function takeSnapshot() { - document.getElementById("snap-button").disabled = true; - EventBridge.emitWebEvent(JSON.stringify({ - type: "snapshot", - action: "takeSnapshot" - })); -} - -function isPrintDisabled() { - var printElement = document.getElementById('print-icon'); - - return printElement.classList.contains("print-icon") && - printElement.classList.contains("print-icon-default") && - document.getElementById('print-button').disabled; -} -function isPrintProcessing() { - var printElement = document.getElementById('print-icon'); - - return printElement.classList.contains("print-icon") && - printElement.classList.contains("print-icon-loading") && - document.getElementById('print-button').disabled; -} -function isPrintEnabled() { - var printElement = document.getElementById('print-icon'); - - return printElement.classList.contains("print-icon") && - printElement.classList.contains("print-icon-default") && - !document.getElementById('print-button').disabled; -} - -function setPrintButtonLoading() { - document.getElementById('print-icon').className = "print-icon print-icon-loading"; - document.getElementById('print-button').disabled = true; -} -function setPrintButtonDisabled() { - document.getElementById('print-icon').className = "print-icon print-icon-default"; - document.getElementById('print-button').disabled = true; -} -function setPrintButtonEnabled() { - document.getElementById('print-button').disabled = false; - document.getElementById('print-icon').className = "print-icon print-icon-default"; -} - -function requestPrintButtonUpdate() { - EventBridge.emitWebEvent(JSON.stringify({ - type: "snapshot", - action: "requestPrintButtonUpdate" - })); -} - -function printToPolaroid() { - if (isPrintEnabled()) { - EventBridge.emitWebEvent(JSON.stringify({ - type: "snapshot", - action: "printToPolaroid" - })); - } else { - setPrintButtonLoading(); - } -} - -function testInBrowser(test) { - if (test === 0) { - showSetupInstructions(); - } else if (test === 1) { - imageCount = 2; - //addImage({ localPath: 'http://lorempixel.com/553/255' }); - addImage({ localPath: 'D:/Dropbox/Screenshots/High Fidelity Snapshots/hifi-snap-by-zfox-on-2017-05-01_13-28-58.jpg', story_id: 1338 }, true, true, false, true, false, false, true); - addImage({ localPath: 'D:/Dropbox/Screenshots/High Fidelity Snapshots/hifi-snap-by-zfox-on-2017-05-01_13-28-58.gif', story_id: 1337 }, true, true, false, true, false, false, true); - } else if (test === 2) { - addImage({ localPath: 'D:/Dropbox/Screenshots/High Fidelity Snapshots/hifi-snap-by-zfox-on-2017-05-01_13-28-58.jpg', story_id: 1338 }, true, true, false, true, false, false, true); - addImage({ localPath: 'D:/Dropbox/Screenshots/High Fidelity Snapshots/hifi-snap-by-zfox-on-2017-05-01_13-28-58.gif', story_id: 1337 }, true, true, false, true, false, false, true); - showConfirmationMessage("p0", 'blast'); - showConfirmationMessage("p1", 'hifi'); - } else if (test === 3) { - imageCount = 2; - //addImage({ localPath: 'http://lorempixel.com/553/255' }); - addImage({ localPath: 'D:/Dropbox/Screenshots/High Fidelity Snapshots/hifi-snap-by-zfox-on-2017-05-01_13-28-58.jpg', story_id: 1338 }, true, true, false, true, false, false, true); - addImage({ localPath: 'D:/Dropbox/Screenshots/High Fidelity Snapshots/hifi-snap-by-zfox-on-2017-05-01_13-28-58.gif', story_id: 1337 }, true, true, false, true, false, false, true); - showUploadingMessage("p0", 'hifi'); - } else if (test === 4) { - imageCount = 2; - //addImage({ localPath: 'http://lorempixel.com/553/255' }); - addImage({ localPath: 'D:/Dropbox/Screenshots/High Fidelity Snapshots/hifi-snap-by-zfox-on-2017-05-01_13-28-58.jpg', story_id: 1338 }, false, true, false, true, false, false, true); - addImage({ localPath: 'D:/Dropbox/Screenshots/High Fidelity Snapshots/hifi-snap-by-zfox-on-2017-05-01_13-28-58.gif', story_id: 1337 }, false, true, false, true, false, false, true); -} -} diff --git a/scripts/simplifiedUI/system/html/js/colpick.js b/scripts/simplifiedUI/system/html/js/colpick.js deleted file mode 100644 index e4ad65dfb6..0000000000 --- a/scripts/simplifiedUI/system/html/js/colpick.js +++ /dev/null @@ -1,616 +0,0 @@ -/* -colpick Color Picker -Copyright 2013 Jose Vargas. Licensed under GPL license. Based on Stefan Petre's Color Picker www.eyecon.ro, dual licensed -under the MIT and GPL licenses - -For usage and examples: colpick.com/plugin - */ - -/* global console, document, Element, EventBridge, jQuery, navigator, window, _ $ */ - -(function ($) { - var colpick = function () { - var - tpl = '
' + - '
' + - '
' + - '
' + - '
' + - '
#
' + - '
' + - '
R
' + - '
' + - '
' + - '
G
' + - '
' + - '
B
' + - '
' + - '
' + - '
H
' + - '
' + - '
' + - '
S
' + - '
' + - '
' + - '
B
' + - '
' + - '
' + - '
', - defaults = { - showEvent: 'click', - onShow: function () {}, - onBeforeShow: function(){}, - onHide: function () {}, - onChange: function () {}, - onSubmit: function () {}, - colorScheme: 'light', - color: '3289c7', - livePreview: true, - flat: false, - layout: 'full', - submit: 1, - submitText: 'OK', - height: 156 - }, - // Fill the inputs of the plugin - fillRGBFields = function (hsb, cal) { - var rgb = hsbToRgb(hsb); - $(cal).data('colpick').fields - .eq(1).val(rgb.r).end() - .eq(2).val(rgb.g).end() - .eq(3).val(rgb.b).end(); - }, - fillHSBFields = function (hsb, cal) { - $(cal).data('colpick').fields - .eq(4).val(Math.round(hsb.h)).end() - .eq(5).val(Math.round(hsb.s)).end() - .eq(6).val(Math.round(hsb.b)).end(); - }, - fillHexFields = function (hsb, cal) { - $(cal).data('colpick').fields.eq(0).val(hsbToHex(hsb)); - }, - // Set the round selector position - setSelector = function (hsb, cal) { - $(cal).data('colpick').selector.css('backgroundColor', '#' + hsbToHex({h: hsb.h, s: 100, b: 100})); - $(cal).data('colpick').selectorIndic.css({ - left: parseInt($(cal).data('colpick').height * hsb.s/100, 10), - top: parseInt($(cal).data('colpick').height * (100-hsb.b)/100, 10) - }); - }, - // Set the hue selector position - setHue = function (hsb, cal) { - $(cal).data('colpick').hue.css('top', - parseInt($(cal).data('colpick').height - $(cal).data('colpick').height * hsb.h / 360, 10)); - }, - // Set current and new colors - setCurrentColor = function (hsb, cal) { - $(cal).data('colpick').currentColor.css('backgroundColor', '#' + hsbToHex(hsb)); - }, - setNewColor = function (hsb, cal) { - $(cal).data('colpick').newColor.css('backgroundColor', '#' + hsbToHex(hsb)); - }, - // Called when the new color is changed - change = function (ev) { - var cal = $(this).parent().parent(), col; - if (this.parentNode.className.indexOf('_hex') > 0) { - cal.data('colpick').color = col = hexToHsb(fixHex(this.value)); - fillRGBFields(col, cal.get(0)); - fillHSBFields(col, cal.get(0)); - fillHexFields(col, cal.get(0)); - } else if (this.parentNode.className.indexOf('_hsb') > 0) { - cal.data('colpick').color = col = fixHSB({ - h: parseInt(cal.data('colpick').fields.eq(4).val(), 10), - s: parseInt(cal.data('colpick').fields.eq(5).val(), 10), - b: parseInt(cal.data('colpick').fields.eq(6).val(), 10) - }); - fillRGBFields(col, cal.get(0)); - fillHexFields(col, cal.get(0)); - fillHSBFields(col, cal.get(0)); - } else { - cal.data('colpick').color = col = rgbToHsb(fixRGB({ - r: parseInt(cal.data('colpick').fields.eq(1).val(), 10), - g: parseInt(cal.data('colpick').fields.eq(2).val(), 10), - b: parseInt(cal.data('colpick').fields.eq(3).val(), 10) - })); - fillHexFields(col, cal.get(0)); - fillHSBFields(col, cal.get(0)); - fillRGBFields(col, cal.get(0)); - } - setSelector(col, cal.get(0)); - setHue(col, cal.get(0)); - setNewColor(col, cal.get(0)); - cal.data('colpick').onChange.apply(cal.parent(), - [col, hsbToHex(col), hsbToRgb(col), cal.data('colpick').el, 0]); - }, - // Change style on blur and on focus of inputs - blur = function (ev) { - $(this).parent().removeClass('colpick_focus'); - }, - focus = function () { - $(this).parent().parent().data('colpick').fields.parent().removeClass('colpick_focus'); - $(this).parent().addClass('colpick_focus'); - }, - // Increment/decrement arrows functions - downIncrement = function (ev) { - ev.preventDefault ? ev.preventDefault() : ev.returnValue = false; - var field = $(this).parent().find('input').focus(); - var current = { - el: $(this).parent().addClass('colpick_slider'), - max: this.parentNode.className.indexOf('_hsb_h') > 0 ? 360 : - (this.parentNode.className.indexOf('_hsb') > 0 ? 100 : 255), - y: ev.pageY, - field: field, - val: parseInt(field.val(), 10), - preview: $(this).parent().parent().data('colpick').livePreview - }; - $(document).mouseup(current, upIncrement); - $(document).mousemove(current, moveIncrement); - }, - moveIncrement = function (ev) { - ev.data.field.val(Math.max(0, Math.min(ev.data.max, parseInt(ev.data.val - ev.pageY + ev.data.y, 10)))); - if (ev.data.preview) { - change.apply(ev.data.field.get(0), [true]); - } - return false; - }, - upIncrement = function (ev) { - change.apply(ev.data.field.get(0), [true]); - ev.data.el.removeClass('colpick_slider').find('input').focus(); - $(document).off('mouseup', upIncrement); - $(document).off('mousemove', moveIncrement); - return false; - }, - // Hue slider functions - downHue = function (ev) { - ev.preventDefault ? ev.preventDefault() : ev.returnValue = false; - var current = { - cal: $(this).parent(), - y: $(this).offset().top - }; - $(document).on('mouseup touchend',current,upHue); - $(document).on('mousemove touchmove',current,moveHue); - - var pageY = ((ev.type === 'touchstart') ? ev.originalEvent.changedTouches[0].pageY : ev.pageY ); - change.apply( - current.cal.data('colpick') - .fields.eq(4).val(parseInt(360 * (current.cal.data('colpick').height - - (pageY - current.y)) / current.cal.data('colpick').height, 10)) - .get(0), - [current.cal.data('colpick').livePreview] - ); - return false; - }, - moveHue = function (ev) { - var pageY = ((ev.type === 'touchmove') ? ev.originalEvent.changedTouches[0].pageY : ev.pageY ); - change.apply( - ev.data.cal.data('colpick') - .fields.eq(4).val(parseInt(360 * (ev.data.cal.data('colpick').height - - Math.max(0, Math.min(ev.data.cal.data('colpick').height, (pageY - ev.data.y)))) / - ev.data.cal.data('colpick').height, 10)) - .get(0), - [ev.data.preview] - ); - return false; - }, - upHue = function (ev) { - fillRGBFields(ev.data.cal.data('colpick').color, ev.data.cal.get(0)); - fillHexFields(ev.data.cal.data('colpick').color, ev.data.cal.get(0)); - $(document).off('mouseup touchend',upHue); - $(document).off('mousemove touchmove',moveHue); - return false; - }, - // Color selector functions - downSelector = function (ev) { - ev.preventDefault ? ev.preventDefault() : ev.returnValue = false; - var current = { - cal: $(this).parent(), - pos: $(this).offset() - }; - current.preview = current.cal.data('colpick').livePreview; - - $(document).on('mouseup touchend',current,upSelector); - $(document).on('mousemove touchmove',current,moveSelector); - - var pageX,pageY; - if (ev.type === 'touchstart') { - pageX = ev.originalEvent.changedTouches[0].pageX, - pageY = ev.originalEvent.changedTouches[0].pageY; - } else { - pageX = ev.pageX; - pageY = ev.pageY; - } - - change.apply( - current.cal.data('colpick').fields - .eq(6).val(parseInt(100 * (current.cal.data('colpick').height - (pageY - current.pos.top)) / - current.cal.data('colpick').height, 10)).end() - .eq(5).val(parseInt(100*(pageX - current.pos.left)/current.cal.data('colpick').height, 10)) - .get(0), - [current.preview] - ); - return false; - }, - moveSelector = function (ev) { - var pageX,pageY; - if (ev.type === 'touchmove') { - pageX = ev.originalEvent.changedTouches[0].pageX, - pageY = ev.originalEvent.changedTouches[0].pageY; - } else { - pageX = ev.pageX; - pageY = ev.pageY; - } - - change.apply( - ev.data.cal.data('colpick').fields - .eq(6).val(parseInt(100 * (ev.data.cal.data('colpick').height - - Math.max(0, Math.min(ev.data.cal.data('colpick').height, (pageY - ev.data.pos.top)))) / - ev.data.cal.data('colpick').height, 10)).end() - .eq(5).val(parseInt(100 * (Math.max(0, Math.min(ev.data.cal.data('colpick').height, - (pageX - ev.data.pos.left)))) / ev.data.cal.data('colpick').height, 10)) - .get(0), - [ev.data.preview] - ); - return false; - }, - upSelector = function (ev) { - fillRGBFields(ev.data.cal.data('colpick').color, ev.data.cal.get(0)); - fillHexFields(ev.data.cal.data('colpick').color, ev.data.cal.get(0)); - $(document).off('mouseup touchend',upSelector); - $(document).off('mousemove touchmove',moveSelector); - return false; - }, - // Submit button - clickSubmit = function (ev) { - var cal = $(this).parent(); - var col = cal.data('colpick').color; - cal.data('colpick').origColor = col; - setCurrentColor(col, cal.get(0)); - cal.data('colpick').onSubmit(col, hsbToHex(col), hsbToRgb(col), cal.data('colpick').el); - }, - // Show/hide the color picker - show = function (ev) { - if ($(this).attr('disabled')) { - return; - } - // Prevent the trigger of any direct parent - ev.stopPropagation(); - var cal = $('#' + $(this).data('colpickId')); - cal.data('colpick').onBeforeShow.apply(this, [cal.get(0)]); - var pos = $(this).offset(); - var top = pos.top + this.offsetHeight; - var left = pos.left; - var viewPort = getViewport(); - var calW = cal.width(); - if (left + calW > viewPort.l + viewPort.w) { - left -= calW; - } - cal.css({left: left + 'px', top: top + 'px'}); - if (cal.data('colpick').onShow.apply(this, [cal.get(0)]) !== false) { - cal.show(); - } - // Hide when user clicks outside - $('html').mousedown({cal:cal}, hide); - cal.mousedown(function(ev){ - ev.stopPropagation(); - }); - }, - hide = function (ev) { - if (ev.data.cal.data('colpick').onHide.apply(this, [ev.data.cal.get(0)]) !== false) { - ev.data.cal.hide(); - } - $('html').off('mousedown', hide); - }, - getViewport = function () { - var m = document.compatMode === 'CSS1Compat'; - return { - l : window.pageXOffset || (m ? document.documentElement.scrollLeft : document.body.scrollLeft), - w : window.innerWidth || (m ? document.documentElement.clientWidth : document.body.clientWidth) - }; - }, - // Fix the values if the user enters a negative or high value - fixHSB = function (hsb) { - hsb.h = isNaN(hsb.h) ? 0 : hsb.h; - hsb.s = isNaN(hsb.s) ? 0 : hsb.s; - hsb.b = isNaN(hsb.b) ? 0 : hsb.b; - return { - h: Math.min(360, Math.max(0, hsb.h)), - s: Math.min(100, Math.max(0, hsb.s)), - b: Math.min(100, Math.max(0, hsb.b)) - }; - }, - fixRGB = function (rgb) { - rgb.r = isNaN(rgb.r) ? 0 : rgb.r; - rgb.g = isNaN(rgb.g) ? 0 : rgb.g; - rgb.b = isNaN(rgb.b) ? 0 : rgb.b; - return { - r: Math.min(255, Math.max(0, rgb.r)), - g: Math.min(255, Math.max(0, rgb.g)), - b: Math.min(255, Math.max(0, rgb.b)) - }; - }, - fixHex = function (hex) { - var len = 6 - hex.length; - if (len > 0) { - var o = []; - for (var i=0; i').attr('style', - 'height:8.333333%; filter:progid:' + - 'DXImageTransform.Microsoft.gradient(GradientType=0,startColorstr=' + stops[i] + - ', endColorstr=' + stops[i + 1] + - '); -ms-filter: "progid:DXImageTransform.Microsoft.gradient(GradientType=0,startColorstr=' + - stops[i] + ', endColorstr=' + stops[i + 1] + ')";'); - huebar.append(div); - } - } else { - var stopList = stops.join(','); - huebar.attr('style', 'background:-webkit-linear-gradient(top,' + stopList + - '); background: -o-linear-gradient(top,' + stopList + - '); background: -ms-linear-gradient(top,' + stopList + - '); background:-moz-linear-gradient(top,' + stopList + - '); -webkit-linear-gradient(top,' + stopList + - '); background:linear-gradient(to bottom,' + stopList + '); '); - } - cal.find('div.colpick_hue').on('mousedown touchstart',downHue); - options.newColor = cal.find('div.colpick_new_color'); - options.currentColor = cal.find('div.colpick_current_color'); - // Store options and fill with default color - cal.data('colpick', options); - fillRGBFields(options.color, cal.get(0)); - fillHSBFields(options.color, cal.get(0)); - fillHexFields(options.color, cal.get(0)); - setHue(options.color, cal.get(0)); - setSelector(options.color, cal.get(0)); - setCurrentColor(options.color, cal.get(0)); - setNewColor(options.color, cal.get(0)); - // Append to body if flat=false, else show in place - if (options.flat) { - cal.appendTo(this).show(); - cal.css({ - position: 'relative', - display: 'block' - }); - } else { - cal.appendTo(document.body); - $(this).on(options.showEvent, show); - cal.css({ - position:'absolute' - }); - } - } - }); - }, - // Shows the picker - showPicker: function() { - return this.each( function () { - if ($(this).data('colpickId')) { - show.apply(this); - } - }); - }, - // Hides the picker - hidePicker: function() { - return this.each( function () { - if ($(this).data('colpickId')) { - $('#' + $(this).data('colpickId')).hide(); - } - }); - }, - // Sets a color as new and current (default) - setColor: function(col, setCurrent) { - setCurrent = (typeof setCurrent === "undefined") ? 1 : setCurrent; - if (typeof col === 'string') { - col = hexToHsb(col); - } else if (col.r !== undefined && col.g !== undefined && col.b !== undefined) { - col = rgbToHsb(col); - } else if (col.h !== undefined && col.s !== undefined && col.b !== undefined) { - col = fixHSB(col); - } else { - return this; - } - return this.each(function(){ - if ($(this).data('colpickId')) { - var cal = $('#' + $(this).data('colpickId')); - cal.data('colpick').color = col; - cal.data('colpick').origColor = col; - fillRGBFields(col, cal.get(0)); - fillHSBFields(col, cal.get(0)); - fillHexFields(col, cal.get(0)); - setHue(col, cal.get(0)); - setSelector(col, cal.get(0)); - - setNewColor(col, cal.get(0)); - cal.data('colpick').onChange.apply(cal.parent(), - [col, hsbToHex(col), hsbToRgb(col), cal.data('colpick').el, 1]); - if (setCurrent) { - setCurrentColor(col, cal.get(0)); - } - } - }); - } - }; - }(); - // Color space convertions - var hexToRgb = function (hexString) { - if (typeof hexString !== "string") { - print("Error - ColPick.js::hexToRgb expects string object."); - return; - } - - var hexNumber = parseInt(((hexString.indexOf('#') > -1) ? hexString.substring(1) : hexString), 16); - return { r: hexNumber >> 16, g: (hexNumber & 0x00FF00) >> 8, b: (hexNumber & 0x0000FF)}; - }; - var hexToHsb = function (hexString) { - if (typeof hexString !== "string") { - print("Error - ColPick.js::hexToHsb expects string object."); - return; - } - - return rgbToHsb(hexToRgb(hexString)); - }; - var rgbToHsb = function (rgb) { - var hsb = {h: 0, s: 0, b: 0}; - var min = Math.min(rgb.r, rgb.g, rgb.b); - var max = Math.max(rgb.r, rgb.g, rgb.b); - var delta = max - min; - hsb.b = max; - hsb.s = max != 0 ? 255 * delta / max : 0; // eslint-disable-line eqeqeq - if (hsb.s != 0) { // eslint-disable-line eqeqeq - if (rgb.r == max) { // eslint-disable-line eqeqeq - hsb.h = (rgb.g - rgb.b) / delta; - } else if (rgb.g == max) { // eslint-disable-line eqeqeq - hsb.h = 2 + (rgb.b - rgb.r) / delta; - } else { - hsb.h = 4 + (rgb.r - rgb.g) / delta; - } - } else { - hsb.h = -1; - } - hsb.h *= 60; - if (hsb.h < 0) { - hsb.h += 360; - } - hsb.s *= 100/255; - hsb.b *= 100/255; - return hsb; - }; - var hsbToRgb = function (hsb) { - var rgb = {}; - var h = hsb.h; - var s = hsb.s*255/100; - var v = hsb.b*255/100; - if (s == 0) { // eslint-disable-line eqeqeq - rgb.r = rgb.g = rgb.b = v; - } else { - var t1 = v; - var t2 = (255-s)*v/255; - var t3 = (t1-t2)*(h%60)/60; - if (h==360) { // eslint-disable-line eqeqeq - h = 0; - } - if (h<60) { - rgb.r=t1; rgb.b=t2; rgb.g=t2+t3; - } else if (h<120) { - rgb.g=t1; rgb.b=t2; rgb.r=t1-t3; - } else if (h<180) { - rgb.g=t1; rgb.r=t2; rgb.b=t2+t3; - } else if (h<240) { - rgb.b=t1; rgb.r=t2; rgb.g=t1-t3; - } else if (h<300) { - rgb.b=t1; rgb.g=t2; rgb.r=t2+t3; - } else if (h<360) { - rgb.r=t1; rgb.g=t2; rgb.b=t1-t3; - } else { - rgb.r=0; rgb.g=0; rgb.b=0; - } - } - return {r:Math.round(rgb.r), g:Math.round(rgb.g), b:Math.round(rgb.b)}; - }; - var rgbToHex = function (rgb) { - var hex = [ - rgb.r.toString(16), - rgb.g.toString(16), - rgb.b.toString(16) - ]; - $.each(hex, function (nr, val) { - if (val.length == 1) { // eslint-disable-line eqeqeq - hex[nr] = '0' + val; - } - }); - return hex.join(''); - }; - var hsbToHex = function (hsb) { - return rgbToHex(hsbToRgb(hsb)); - }; - $.fn.extend({ - colpick: colpick.init, - colpickHide: colpick.hidePicker, - colpickShow: colpick.showPicker, - colpickSetColor: colpick.setColor - }); - $.extend({ - colpick:{ - rgbToHex: rgbToHex, - rgbToHsb: rgbToHsb, - hsbToHex: hsbToHex, - hsbToRgb: hsbToRgb, - hexToHsb: hexToHsb, - hexToRgb: hexToRgb - } - }); -})(jQuery); - diff --git a/scripts/simplifiedUI/system/html/js/draggableNumber.js b/scripts/simplifiedUI/system/html/js/draggableNumber.js deleted file mode 100644 index 3c7b74290c..0000000000 --- a/scripts/simplifiedUI/system/html/js/draggableNumber.js +++ /dev/null @@ -1,268 +0,0 @@ -// draggableNumber.js -// -// Created by David Back on 7 Nov 2018 -// Copyright 2018 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html - -const DELTA_X_FOCUS_THRESHOLD = 1; -const ENTER_KEY = 13; - -function DraggableNumber(min, max, step, decimals, dragStart, dragEnd) { - this.min = min; - this.max = max; - this.step = step !== undefined ? step : 1; - this.multiDiffModeEnabled = false; - this.decimals = decimals; - this.dragStartFunction = dragStart; - this.dragEndFunction = dragEnd; - this.dragging = false; - this.initialMouseEvent = null; - this.lastMouseEvent = null; - this.valueChangeFunction = null; - this.multiDiffStepFunction = null; - this.initialize(); -} - -DraggableNumber.prototype = { - showInput: function() { - this.elText.style.visibility = "hidden"; - this.elLeftArrow.style.visibility = "hidden"; - this.elRightArrow.style.visibility = "hidden"; - this.elInput.style.opacity = 1; - }, - - hideInput: function() { - this.elText.style.visibility = "visible"; - this.elLeftArrow.style.visibility = "visible"; - this.elRightArrow.style.visibility = "visible"; - this.elInput.style.opacity = 0; - }, - - mouseDown: function(event) { - if (event.target === this.elText && !this.isDisabled()) { - this.initialMouseEvent = event; - this.lastMouseEvent = event; - document.addEventListener("mousemove", this.onDocumentMouseMove); - document.addEventListener("mouseup", this.onDocumentMouseUp); - } - }, - - mouseUp: function(event) { - if (!this.dragging && event.target === this.elText && this.initialMouseEvent) { - let dx = event.clientX - this.initialMouseEvent.clientX; - if (Math.abs(dx) <= DELTA_X_FOCUS_THRESHOLD) { - this.showInput(); - this.elInput.focus(); - } - this.initialMouseEvent = null; - } - }, - - documentMouseMove: function(event) { - if (!this.dragging && this.initialMouseEvent) { - let dxFromInitial = event.clientX - this.initialMouseEvent.clientX; - if (Math.abs(dxFromInitial) > DELTA_X_FOCUS_THRESHOLD) { - if (this.dragStartFunction) { - this.dragStartFunction(); - } - this.dragging = true; - } - this.lastMouseEvent = event; - } - if (this.dragging && this.lastMouseEvent) { - let dragDelta = event.clientX - this.lastMouseEvent.clientX; - if (dragDelta !== 0) { - if (this.multiDiffModeEnabled) { - if (this.multiDiffStepFunction) { - this.multiDiffStepFunction(dragDelta * this.step); - } - } else { - if (dragDelta > 0) { - this.elInput.stepUp(dragDelta); - } else { - this.elInput.stepDown(-dragDelta); - } - this.inputChange(); - if (this.valueChangeFunction) { - this.valueChangeFunction(); - } - } - } - this.lastMouseEvent = event; - } - }, - - documentMouseUp: function(event) { - if (this.dragging) { - if (this.dragEndFunction) { - this.dragEndFunction(); - } - this.dragging = false; - } - this.lastMouseEvent = null; - document.removeEventListener("mousemove", this.onDocumentMouseMove); - document.removeEventListener("mouseup", this.onDocumentMouseUp); - }, - - stepUp: function() { - if (!this.isDisabled()) { - if (this.multiDiffModeEnabled) { - if (this.multiDiffStepFunction) { - this.multiDiffStepFunction(this.step, true); - } - } else { - this.elInput.value = parseFloat(this.elInput.value) + this.step; - this.inputChange(); - if (this.valueChangeFunction) { - this.valueChangeFunction(); - } - } - } - }, - - stepDown: function() { - if (!this.isDisabled()) { - if (this.multiDiffModeEnabled) { - if (this.multiDiffStepFunction) { - this.multiDiffStepFunction(-this.step, true); - } - } else { - this.elInput.value = parseFloat(this.elInput.value) - this.step; - this.inputChange(); - if (this.valueChangeFunction) { - this.valueChangeFunction(); - } - } - } - }, - - setValue: function(newValue, isMultiDiff) { - if (isMultiDiff !== undefined) { - this.setMultiDiff(isMultiDiff); - } - - if (isNaN(newValue)) { - console.error("DraggableNumber.setValue() > " + newValue + " is not a number."); - return; - } - - if (newValue !== "" && this.decimals !== undefined) { - this.elInput.value = parseFloat(newValue).toFixed(this.decimals); - } else { - this.elInput.value = newValue; - } - this.elText.firstChild.data = this.elInput.value; - }, - - setMultiDiff: function(isMultiDiff) { - this.multiDiffModeEnabled = isMultiDiff; - if (isMultiDiff) { - this.elDiv.classList.add('multi-diff'); - } else { - this.elDiv.classList.remove('multi-diff'); - } - }, - - setValueChangeFunction: function(valueChangeFunction) { - this.valueChangeFunction = valueChangeFunction.bind(this.elInput); - this.elInput.addEventListener("change", this.valueChangeFunction); - }, - - setMultiDiffStepFunction: function (multiDiffStepFunction) { - this.multiDiffStepFunction = multiDiffStepFunction; - }, - - inputChange: function() { - let value = this.elInput.value; - if (this.max !== undefined) { - value = Math.min(this.max, value); - } - if (this.min !== undefined) { - value = Math.max(this.min, value); - } - this.setValue(value); - }, - - inputBlur: function(ev) { - this.hideInput(); - }, - - keyPress: function(event) { - if (event.keyCode === ENTER_KEY) { - if (this.valueChangeFunction) { - this.valueChangeFunction(); - } - this.inputBlur(); - } - }, - - isDisabled: function() { - return this.elText.getAttribute("disabled") === "disabled"; - }, - - updateMinMax: function(min, max) { - this.min = min; - this.max = max; - if (this.min !== undefined) { - this.elInput.setAttribute("min", this.min); - } - if (this.max !== undefined) { - this.elInput.setAttribute("max", this.max); - } - }, - - initialize: function() { - this.onMouseDown = this.mouseDown.bind(this); - this.onMouseUp = this.mouseUp.bind(this); - this.onDocumentMouseMove = this.documentMouseMove.bind(this); - this.onDocumentMouseUp = this.documentMouseUp.bind(this); - this.onStepUp = this.stepUp.bind(this); - this.onStepDown = this.stepDown.bind(this); - this.onInputChange = this.inputChange.bind(this); - this.onInputBlur = this.inputBlur.bind(this); - this.onKeyPress = this.keyPress.bind(this); - - this.elDiv = document.createElement('div'); - this.elDiv.className = "draggable-number"; - - this.elText = document.createElement('span'); - this.elText.className = "text"; - this.elText.innerText = " "; - this.elText.style.visibility = "visible"; - this.elText.addEventListener("mousedown", this.onMouseDown); - this.elText.addEventListener("mouseup", this.onMouseUp); - - this.elLeftArrow = document.createElement('span'); - this.elRightArrow = document.createElement('span'); - this.elLeftArrow.className = 'left-arrow'; - this.elLeftArrow.innerHTML = 'D'; - this.elLeftArrow.addEventListener("click", this.onStepDown); - this.elRightArrow.className = 'right-arrow'; - this.elRightArrow.innerHTML = 'D'; - this.elRightArrow.addEventListener("click", this.onStepUp); - - this.elMultiDiff = document.createElement('span'); - this.elMultiDiff.className = 'multi-diff'; - - this.elInput = document.createElement('input'); - this.elInput.className = "input"; - this.elInput.setAttribute("type", "number"); - this.updateMinMax(this.min, this.max); - if (this.step !== undefined) { - this.elInput.setAttribute("step", this.step); - } - this.elInput.style.opacity = 0; - this.elInput.addEventListener("change", this.onInputChange); - this.elInput.addEventListener("blur", this.onInputBlur); - this.elInput.addEventListener("keypress", this.onKeyPress); - this.elInput.addEventListener("focus", this.showInput.bind(this)); - - this.elDiv.appendChild(this.elLeftArrow); - this.elDiv.appendChild(this.elText); - this.elDiv.appendChild(this.elInput); - this.elDiv.appendChild(this.elMultiDiff); - this.elDiv.appendChild(this.elRightArrow); - } -}; diff --git a/scripts/simplifiedUI/system/html/js/entityList.js b/scripts/simplifiedUI/system/html/js/entityList.js deleted file mode 100644 index b15c4e6703..0000000000 --- a/scripts/simplifiedUI/system/html/js/entityList.js +++ /dev/null @@ -1,1426 +0,0 @@ -// entityList.js -// -// Created by Ryan Huffman on 19 Nov 2014 -// Copyright 2014 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html - -const ASCENDING_SORT = 1; -const DESCENDING_SORT = -1; -const ASCENDING_STRING = '▴'; -const DESCENDING_STRING = '▾'; -const BYTES_PER_MEGABYTE = 1024 * 1024; -const COLLAPSE_EXTRA_INFO = "E"; -const EXPAND_EXTRA_INFO = "D"; -const FILTER_IN_VIEW_ATTRIBUTE = "pressed"; -const WINDOW_NONVARIABLE_HEIGHT = 227; -const EMPTY_ENTITY_ID = "0"; -const MAX_LENGTH_RADIUS = 9; -const MINIMUM_COLUMN_WIDTH = 24; -const SCROLLBAR_WIDTH = 20; -const RESIZER_WIDTH = 10; -const DELTA_X_MOVE_COLUMNS_THRESHOLD = 2; -const DELTA_X_COLUMN_SWAP_POSITION = 5; -const CERTIFIED_PLACEHOLDER = "** Certified **"; - -function decimalMegabytes(number) { - return number ? (number / BYTES_PER_MEGABYTE).toFixed(1) : ""; -} - -function displayIfNonZero(number) { - return number ? number : ""; -} - -function getFilename(url) { - let urlParts = url.split('/'); - return urlParts[urlParts.length - 1]; -} - -const COLUMNS = { - type: { - columnHeader: "Type", - propertyID: "type", - initialWidth: 0.16, - initiallyShown: true, - alwaysShown: true, - defaultSortOrder: ASCENDING_SORT, - }, - name: { - columnHeader: "Name", - propertyID: "name", - initialWidth: 0.34, - initiallyShown: true, - alwaysShown: true, - defaultSortOrder: ASCENDING_SORT, - }, - url: { - columnHeader: "File", - dropdownLabel: "File", - propertyID: "url", - initialWidth: 0.34, - initiallyShown: true, - defaultSortOrder: ASCENDING_SORT, - }, - locked: { - columnHeader: "", - glyph: true, - propertyID: "locked", - initialWidth: 0.08, - initiallyShown: true, - alwaysShown: true, - defaultSortOrder: DESCENDING_SORT, - }, - visible: { - columnHeader: "", - glyph: true, - propertyID: "visible", - initialWidth: 0.08, - initiallyShown: true, - alwaysShown: true, - defaultSortOrder: DESCENDING_SORT, - }, - verticesCount: { - columnHeader: "Verts", - dropdownLabel: "Vertices", - propertyID: "verticesCount", - initialWidth: 0.08, - defaultSortOrder: DESCENDING_SORT, - }, - texturesCount: { - columnHeader: "Texts", - dropdownLabel: "Textures", - propertyID: "texturesCount", - initialWidth: 0.08, - defaultSortOrder: DESCENDING_SORT, - }, - texturesSize: { - columnHeader: "Text MB", - dropdownLabel: "Texture Size", - propertyID: "texturesSize", - initialWidth: 0.10, - format: decimalMegabytes, - defaultSortOrder: DESCENDING_SORT, - }, - hasTransparent: { - columnHeader: "", - glyph: true, - dropdownLabel: "Transparency", - propertyID: "hasTransparent", - initialWidth: 0.04, - defaultSortOrder: DESCENDING_SORT, - }, - isBaked: { - columnHeader: "", - glyph: true, - dropdownLabel: "Baked", - propertyID: "isBaked", - initialWidth: 0.08, - defaultSortOrder: DESCENDING_SORT, - }, - drawCalls: { - columnHeader: "Draws", - dropdownLabel: "Draws", - propertyID: "drawCalls", - initialWidth: 0.08, - defaultSortOrder: DESCENDING_SORT, - }, - hasScript: { - columnHeader: "k", - glyph: true, - dropdownLabel: "Script", - propertyID: "hasScript", - initialWidth: 0.06, - defaultSortOrder: DESCENDING_SORT, - }, -}; - -const FILTER_TYPES = [ - "Shape", - "Model", - "Image", - "Light", - "Zone", - "Web", - "Material", - "ParticleEffect", - "PolyLine", - "PolyVox", - "Text", - "Grid", -]; - -const DOUBLE_CLICK_TIMEOUT = 300; // ms -const RENAME_COOLDOWN = 400; // ms - -// List of all entities -let entities = []; -// List of all entities, indexed by Entity ID -let entitiesByID = {}; -// The filtered and sorted list of entities passed to ListView -let visibleEntities = []; -// List of all entities that are currently selected -let selectedEntities = []; - -let entityList = null; // The ListView - -/** - * @type EntityListContextMenu - */ -let entityListContextMenu = null; - -let currentSortColumnID = 'type'; -let currentSortOrder = ASCENDING_SORT; -let elSortOrders = {}; -let typeFilters = []; -let isFilterInView = false; - -let columns = []; -let columnsByID = {}; -let lastResizeEvent = null; -let resizeColumnIndex = 0; -let elTargetTh = null; -let elTargetSpan = null; -let targetColumnIndex = 0; -let lastColumnSwapPosition = -1; -let initialThEvent = null; -let renameTimeout = null; -let renameLastBlur = null; -let renameLastEntityID = null; -let isRenameFieldBeingMoved = false; -let elFilterTypeInputs = {}; - -let elEntityTable, - elEntityTableHeader, - elEntityTableBody, - elEntityTableScroll, - elEntityTableHeaderRow, - elRefresh, - elToggleLocked, - elToggleVisible, - elDelete, - elFilterTypeMultiselectBox, - elFilterTypeText, - elFilterTypeOptions, - elFilterTypeOptionsButtons, - elFilterTypeSelectAll, - elFilterTypeClearAll, - elFilterSearch, - elFilterInView, - elFilterRadius, - elExport, - elPal, - elSelectedEntitiesCount, - elVisibleEntitiesCount, - elNoEntitiesMessage, - elColumnsMultiselectBox, - elColumnsOptions, - elToggleSpaceMode, - elRenameInput; - -const ENABLE_PROFILING = false; -let profileIndent = ''; -const PROFILE_NOOP = function(_name, fn, args) { - fn.apply(this, args); -} ; -const PROFILE = !ENABLE_PROFILING ? PROFILE_NOOP : function(name, fn, args) { - console.log("PROFILE-Web " + profileIndent + "(" + name + ") Begin"); - let previousIndent = profileIndent; - profileIndent += ' '; - let before = Date.now(); - fn.apply(this, args); - let delta = Date.now() - before; - profileIndent = previousIndent; - console.log("PROFILE-Web " + profileIndent + "(" + name + ") End " + delta + "ms"); -}; - -function loaded() { - openEventBridge(function() { - elEntityTable = document.getElementById("entity-table"); - elEntityTableHeader = document.getElementById("entity-table-header"); - elEntityTableBody = document.getElementById("entity-table-body"); - elEntityTableScroll = document.getElementById("entity-table-scroll"); - elRefresh = document.getElementById("refresh"); - elToggleLocked = document.getElementById("locked"); - elToggleVisible = document.getElementById("visible"); - elDelete = document.getElementById("delete"); - elFilterTypeMultiselectBox = document.getElementById("filter-type-multiselect-box"); - elFilterTypeText = document.getElementById("filter-type-text"); - elFilterTypeOptions = document.getElementById("filter-type-options"); - elFilterTypeOptionsButtons = document.getElementById("filter-type-options-buttons"); - elFilterTypeSelectAll = document.getElementById('filter-type-select-all'); - elFilterTypeClearAll = document.getElementById('filter-type-clear-all'); - elFilterSearch = document.getElementById("filter-search"); - elFilterInView = document.getElementById("filter-in-view"); - elFilterRadius = document.getElementById("filter-radius"); - elExport = document.getElementById("export"); - elPal = document.getElementById("pal"); - elSelectedEntitiesCount = document.getElementById("selected-entities-count"); - elVisibleEntitiesCount = document.getElementById("visible-entities-count"); - elNoEntitiesMessage = document.getElementById("no-entities"); - elColumnsMultiselectBox = document.getElementById("entity-table-columns-multiselect-box"); - elColumnsOptions = document.getElementById("entity-table-columns-options"); - elToggleSpaceMode = document.getElementById('toggle-space-mode'); - - document.body.onclick = onBodyClick; - elToggleLocked.onclick = function() { - EventBridge.emitWebEvent(JSON.stringify({ type: 'toggleLocked' })); - }; - elToggleVisible.onclick = function() { - EventBridge.emitWebEvent(JSON.stringify({ type: 'toggleVisible' })); - }; - elExport.onclick = function() { - EventBridge.emitWebEvent(JSON.stringify({ type: 'export'})); - }; - elPal.onclick = function() { - EventBridge.emitWebEvent(JSON.stringify({ type: 'pal' })); - }; - elDelete.onclick = function() { - EventBridge.emitWebEvent(JSON.stringify({ type: 'delete' })); - }; - elToggleSpaceMode.onclick = function() { - EventBridge.emitWebEvent(JSON.stringify({ type: 'toggleSpaceMode' })); - }; - elRefresh.onclick = refreshEntities; - elFilterTypeMultiselectBox.onclick = onToggleTypeDropdown; - elFilterTypeSelectAll.onclick = onSelectAllTypes; - elFilterTypeClearAll.onclick = onClearAllTypes; - elFilterSearch.onkeyup = refreshEntityList; - elFilterSearch.onsearch = refreshEntityList; - elFilterInView.onclick = onToggleFilterInView; - elFilterRadius.onkeyup = onRadiusChange; - elFilterRadius.onchange = onRadiusChange; - elColumnsMultiselectBox.onclick = onToggleColumnsDropdown; - - // create filter type dropdown checkboxes with label and icon for each type - for (let i = 0; i < FILTER_TYPES.length; ++i) { - let type = FILTER_TYPES[i]; - let typeFilterID = "filter-type-" + type; - - let elDiv = document.createElement('div'); - elDiv.onclick = onToggleTypeFilter; - elFilterTypeOptions.insertBefore(elDiv, elFilterTypeOptionsButtons); - - let elInput = document.createElement('input'); - elInput.setAttribute("type", "checkbox"); - elInput.setAttribute("id", typeFilterID); - elInput.setAttribute("filterType", type); - elInput.checked = true; // all types are checked initially - elFilterTypeInputs[type] = elInput; - elDiv.appendChild(elInput); - - let elLabel = document.createElement('label'); - elLabel.setAttribute("for", typeFilterID); - elLabel.innerText = type; - elDiv.appendChild(elLabel); - - let elSpan = document.createElement('span'); - elSpan.setAttribute("class", "typeIcon"); - elSpan.innerHTML = ENTITY_TYPE_ICON[type]; - - elLabel.insertBefore(elSpan, elLabel.childNodes[0]); - - toggleTypeFilter(elInput, false); // add all types to the initial types filter - } - - // create columns - elHeaderTr = document.createElement("tr"); - elEntityTableHeader.appendChild(elHeaderTr); - let columnIndex = 0; - for (let columnID in COLUMNS) { - let columnData = COLUMNS[columnID]; - - let elTh = document.createElement("th"); - let thID = "entity-" + columnID; - elTh.setAttribute("id", thID); - elTh.setAttribute("columnIndex", columnIndex); - elTh.setAttribute("columnID", columnID); - if (columnData.glyph) { - let elGlyph = document.createElement("span"); - elGlyph.className = "glyph"; - elGlyph.innerHTML = columnData.columnHeader; - elTh.appendChild(elGlyph); - } else { - elTh.innerText = columnData.columnHeader; - } - elTh.onmousedown = function(event) { - if (event.target.nodeName === 'TH') { - elTargetTh = event.target; - targetColumnIndex = parseInt(elTargetTh.getAttribute("columnIndex")); - lastColumnSwapPosition = event.clientX; - } else if (event.target.nodeName === 'SPAN') { - elTargetSpan = event.target; - } - initialThEvent = event; - }; - - let elResizer = document.createElement("span"); - elResizer.className = "resizer"; - elResizer.innerHTML = " "; - elResizer.onmousedown = onStartResize; - elTh.appendChild(elResizer); - - let elSortOrder = document.createElement("span"); - elSortOrder.className = "sort-order"; - elTh.appendChild(elSortOrder); - elHeaderTr.appendChild(elTh); - - elSortOrders[columnID] = elSortOrder; - - // add column to columns dropdown if it is not set to be always shown - if (columnData.alwaysShown !== true) { - let columnDropdownID = "entity-table-column-" + columnID; - - let elDiv = document.createElement('div'); - elDiv.onclick = onToggleColumn; - elColumnsOptions.appendChild(elDiv); - - let elInput = document.createElement('input'); - elInput.setAttribute("type", "checkbox"); - elInput.setAttribute("id", columnDropdownID); - elInput.setAttribute("columnID", columnID); - elInput.checked = columnData.initiallyShown === true; - elDiv.appendChild(elInput); - - let elLabel = document.createElement('label'); - elLabel.setAttribute("for", columnDropdownID); - elLabel.innerText = columnData.dropdownLabel; - elDiv.appendChild(elLabel); - } - - let initialWidth = columnData.initiallyShown === true ? columnData.initialWidth : 0; - columns.push({ - columnID: columnID, - elTh: elTh, - elResizer: elResizer, - width: initialWidth, - data: columnData - }); - columnsByID[columnID] = columns[columnIndex]; - - ++columnIndex; - } - - elEntityTableHeaderRow = document.querySelectorAll("#entity-table thead th"); - - entityList = new ListView(elEntityTableBody, elEntityTableScroll, elEntityTableHeaderRow, createRow, updateRow, - clearRow, preRefresh, postRefresh, preRefresh, WINDOW_NONVARIABLE_HEIGHT); - - entityListContextMenu = new EntityListContextMenu(); - - function startRenamingEntity(entityID) { - renameLastEntityID = entityID; - let entity = entitiesByID[entityID]; - if (!entity || entity.locked || !entity.elRow) { - return; - } - - let elCell = entity.elRow.childNodes[getColumnIndex("name")]; - elRenameInput = document.createElement("input"); - elRenameInput.setAttribute('class', 'rename-entity'); - elRenameInput.value = entity.name; - let ignoreClicks = function(event) { - event.stopPropagation(); - }; - elRenameInput.onclick = ignoreClicks; - elRenameInput.ondblclick = ignoreClicks; - elRenameInput.onkeyup = function(keyEvent) { - if (keyEvent.key === "Enter") { - elRenameInput.blur(); - } - }; - - elRenameInput.onblur = function(event) { - if (isRenameFieldBeingMoved) { - return; - } - let value = elRenameInput.value; - EventBridge.emitWebEvent(JSON.stringify({ - type: 'rename', - entityID: entityID, - name: value - })); - entity.name = value; - elRenameInput.parentElement.innerText = value; - - renameLastBlur = Date.now(); - elRenameInput = null; - }; - - elCell.innerHTML = ""; - elCell.appendChild(elRenameInput); - - elRenameInput.select(); - } - - function preRefresh() { - // move the rename input to the body - if (!isRenameFieldBeingMoved && elRenameInput) { - isRenameFieldBeingMoved = true; - document.body.appendChild(elRenameInput); - // keep the focus - elRenameInput.focus(); - } - } - - function postRefresh() { - if (!elRenameInput || !isRenameFieldBeingMoved) { - return; - } - let entity = entitiesByID[renameLastEntityID]; - if (!entity || entity.locked || !entity.elRow) { - return; - } - let elCell = entity.elRow.childNodes[getColumnIndex("name")]; - elCell.innerHTML = ""; - elCell.appendChild(elRenameInput); - // keep the focus - elRenameInput.focus(); - isRenameFieldBeingMoved = false; - } - - entityListContextMenu.setOnSelectedCallback(function(optionName, selectedEntityID) { - switch (optionName) { - case "Cut": - EventBridge.emitWebEvent(JSON.stringify({ type: 'cut' })); - break; - case "Copy": - EventBridge.emitWebEvent(JSON.stringify({ type: 'copy' })); - break; - case "Paste": - EventBridge.emitWebEvent(JSON.stringify({ type: 'paste' })); - break; - case "Rename": - startRenamingEntity(selectedEntityID); - break; - case "Duplicate": - EventBridge.emitWebEvent(JSON.stringify({ type: 'duplicate' })); - break; - case "Delete": - EventBridge.emitWebEvent(JSON.stringify({ type: 'delete' })); - break; - } - }); - - function onRowContextMenu(clickEvent) { - if (elRenameInput) { - // disallow the context menu from popping up while renaming - return; - } - - let entityID = this.dataset.entityID; - - if (!selectedEntities.includes(entityID)) { - let selection = [entityID]; - updateSelectedEntities(selection); - - EventBridge.emitWebEvent(JSON.stringify({ - type: "selectionUpdate", - focus: false, - entityIds: selection, - })); - } - - let enabledContextMenuItems = ['Copy', 'Paste', 'Duplicate']; - if (entitiesByID[entityID] && !entitiesByID[entityID].locked) { - enabledContextMenuItems.push('Cut'); - enabledContextMenuItems.push('Rename'); - enabledContextMenuItems.push('Delete'); - } - - entityListContextMenu.open(clickEvent, entityID, enabledContextMenuItems); - } - - let clearRenameTimeout = () => { - if (renameTimeout !== null) { - window.clearTimeout(renameTimeout); - renameTimeout = null; - } - }; - - function onRowClicked(clickEvent) { - let entityID = this.dataset.entityID; - let selection = [entityID]; - - if (clickEvent.ctrlKey) { - let selectedIndex = selectedEntities.indexOf(entityID); - if (selectedIndex >= 0) { - selection = []; - selection = selection.concat(selectedEntities); - selection.splice(selectedIndex, 1); - } else { - selection = selection.concat(selectedEntities); - } - } else if (clickEvent.shiftKey && selectedEntities.length > 0) { - let previousItemFound = -1; - let clickedItemFound = -1; - for (let i = 0, len = visibleEntities.length; i < len; ++i) { - let entity = visibleEntities[i]; - if (clickedItemFound === -1 && entityID === entity.id) { - clickedItemFound = i; - } else if (previousItemFound === -1 && selectedEntities[0] === entity.id) { - previousItemFound = i; - } - } - if (previousItemFound !== -1 && clickedItemFound !== -1) { - selection = []; - let toItem = Math.max(previousItemFound, clickedItemFound); - for (let i = Math.min(previousItemFound, clickedItemFound); i <= toItem; i++) { - selection.push(visibleEntities[i].id); - } - if (previousItemFound > clickedItemFound) { - // always make sure that we add the items in the right order - selection.reverse(); - } - } - } else if (!clickEvent.ctrlKey && !clickEvent.shiftKey && selectedEntities.length === 1) { - // if reselecting the same entity then start renaming it - if (selectedEntities[0] === entityID) { - if (renameLastBlur && renameLastEntityID === entityID && (Date.now() - renameLastBlur) < RENAME_COOLDOWN) { - - return; - } - clearRenameTimeout(); - renameTimeout = window.setTimeout(() => { - renameTimeout = null; - startRenamingEntity(entityID); - }, DOUBLE_CLICK_TIMEOUT); - } - } - - updateSelectedEntities(selection, false); - - EventBridge.emitWebEvent(JSON.stringify({ - type: "selectionUpdate", - focus: false, - entityIds: selection, - })); - } - - function onRowDoubleClicked() { - clearRenameTimeout(); - - let selection = [this.dataset.entityID]; - updateSelectedEntities(selection, false); - - EventBridge.emitWebEvent(JSON.stringify({ - type: "selectionUpdate", - focus: true, - entityIds: selection, - })); - } - - function updateEntityData(entityData) { - entities = []; - entitiesByID = {}; - visibleEntities.length = 0; // maintains itemData reference in ListView - - PROFILE("map-data", function() { - entityData.forEach(function(entity) { - let type = entity.type; - let filename = getFilename(entity.url); - - let entityData = { - id: entity.id, - name: entity.name, - type: type, - url: entity.certificateID === "" ? filename : "" + CERTIFIED_PLACEHOLDER + "", - fullUrl: entity.certificateID === "" ? filename : CERTIFIED_PLACEHOLDER, - locked: entity.locked, - visible: entity.visible, - certificateID: entity.certificateID, - verticesCount: displayIfNonZero(entity.verticesCount), - texturesCount: displayIfNonZero(entity.texturesCount), - texturesSize: entity.texturesSize, - hasTransparent: entity.hasTransparent, - isBaked: entity.isBaked, - drawCalls: displayIfNonZero(entity.drawCalls), - hasScript: entity.hasScript, - elRow: null, // if this entity has a visible row element assigned to it - selected: false // if this entity is selected for edit regardless of having a visible row - }; - - entities.push(entityData); - entitiesByID[entityData.id] = entityData; - }); - }); - - refreshEntityList(); - } - - const isNullOrEmpty = function(value) { - return value === undefined || value === null || value === ""; - }; - - function refreshEntityList() { - PROFILE("refresh-entity-list", function() { - PROFILE("filter", function() { - let searchTerm = elFilterSearch.value.toLowerCase(); - visibleEntities = entities.filter(function(e) { - let type = e.type === "Box" || e.type === "Sphere" ? "Shape" : e.type; - let typeFilter = typeFilters.indexOf(type) > -1; - let searchFilter = searchTerm === '' || (e.name.toLowerCase().indexOf(searchTerm) > -1 || - e.type.toLowerCase().indexOf(searchTerm) > -1 || - e.fullUrl.toLowerCase().indexOf(searchTerm) > -1 || - e.id.toLowerCase().indexOf(searchTerm) > -1); - return typeFilter && searchFilter; - }); - }); - - PROFILE("sort", function() { - let isAscendingSort = currentSortOrder === ASCENDING_SORT; - let isDefaultSort = currentSortOrder === COLUMNS[currentSortColumnID].defaultSortOrder; - visibleEntities.sort((entityA, entityB) => { - /** - * If the default sort is ascending, empty should be considered largest. - * If the default sort is descending, empty should be considered smallest. - */ - if (!isAscendingSort) { - [entityA, entityB] = [entityB, entityA]; - } - let valueA = entityA[currentSortColumnID]; - let valueB = entityB[currentSortColumnID]; - - if (valueA === valueB) { - return entityA.id < entityB.id ? -1 : 1; - } - - if (isNullOrEmpty(valueA)) { - return (isDefaultSort ? 1 : -1) * (isAscendingSort ? 1 : -1); - } - if (isNullOrEmpty(valueB)) { - return (isDefaultSort ? -1 : 1) * (isAscendingSort ? 1 : -1); - } - if (typeof(valueA) === "string") { - return valueA.localeCompare(valueB); - } - return valueA < valueB ? -1 : 1; - }); - }); - - PROFILE("update-dom", function() { - entityList.itemData = visibleEntities; - entityList.refresh(); - updateColumnWidths(); - }); - - refreshFooter(); - refreshNoEntitiesMessage(); - }); - } - - function removeEntities(deletedIDs) { - // Loop from the back so we can pop items off while iterating - - // delete any entities matching deletedIDs list from entities and entitiesByID lists - // if the entity had an associated row element then ensure row is unselected and clear it's entity - for (let j = entities.length - 1; j >= 0; --j) { - let id = entities[j].id; - for (let i = 0, length = deletedIDs.length; i < length; ++i) { - if (id === deletedIDs[i]) { - let elRow = entities[j].elRow; - if (elRow) { - elRow.className = ''; - elRow.dataset.entityID = EMPTY_ENTITY_ID; - } - entities.splice(j, 1); - delete entitiesByID[id]; - break; - } - } - } - - // delete any entities matching deletedIDs list from selectedEntities list - for (let j = selectedEntities.length - 1; j >= 0; --j) { - let id = selectedEntities[j].id; - for (let i = 0, length = deletedIDs.length; i < length; ++i) { - if (id === deletedIDs[i]) { - selectedEntities.splice(j, 1); - break; - } - } - } - - // delete any entities matching deletedIDs list from visibleEntities list - // if this was a row that was above our current row offset (a hidden top row in the top buffer), - // then decrease row offset accordingly - let firstVisibleRow = entityList.getFirstVisibleRowIndex(); - for (let j = visibleEntities.length - 1; j >= 0; --j) { - let id = visibleEntities[j].id; - for (let i = 0, length = deletedIDs.length; i < length; ++i) { - if (id === deletedIDs[i]) { - if (j < firstVisibleRow && entityList.rowOffset > 0) { - entityList.rowOffset--; - } - visibleEntities.splice(j, 1); - break; - } - } - } - - entityList.refresh(); - - refreshFooter(); - refreshNoEntitiesMessage(); - } - - function clearEntities() { - // clear the associated entity ID from all visible row elements - let firstVisibleRow = entityList.getFirstVisibleRowIndex(); - let lastVisibleRow = entityList.getLastVisibleRowIndex(); - for (let i = firstVisibleRow; i <= lastVisibleRow && i < visibleEntities.length; i++) { - let entity = visibleEntities[i]; - entity.elRow.dataset.entityID = EMPTY_ENTITY_ID; - } - - entities = []; - entitiesByID = {}; - visibleEntities.length = 0; // maintains itemData reference in ListView - - entityList.resetToTop(); - entityList.clear(); - - refreshFooter(); - refreshNoEntitiesMessage(); - } - - function setSortColumn(columnID) { - PROFILE("set-sort-column", function() { - if (currentSortColumnID === columnID) { - currentSortOrder *= -1; - } else { - elSortOrders[currentSortColumnID].innerHTML = ""; - currentSortColumnID = columnID; - currentSortOrder = COLUMNS[currentSortColumnID].defaultSortOrder; - } - refreshSortOrder(); - refreshEntityList(); - }); - } - - function refreshSortOrder() { - elSortOrders[currentSortColumnID].innerHTML = currentSortOrder === ASCENDING_SORT ? ASCENDING_STRING : DESCENDING_STRING; - } - - function refreshEntities() { - EventBridge.emitWebEvent(JSON.stringify({ type: 'refresh' })); - } - - function refreshFooter() { - elSelectedEntitiesCount.innerText = selectedEntities.length; - elVisibleEntitiesCount.innerText = visibleEntities.length; - } - - function refreshNoEntitiesMessage() { - if (visibleEntities.length > 0) { - elNoEntitiesMessage.style.display = "none"; - } else { - elNoEntitiesMessage.style.display = "block"; - } - } - - function updateSelectedEntities(selectedIDs, autoScroll) { - let notFound = false; - - // reset all currently selected entities and their rows first - selectedEntities.forEach(function(id) { - let entity = entitiesByID[id]; - if (entity !== undefined) { - entity.selected = false; - if (entity.elRow) { - entity.elRow.className = ''; - } - } - }); - - // then reset selected entities list with newly selected entities and set them selected - selectedEntities = []; - selectedIDs.forEach(function(id) { - selectedEntities.push(id); - let entity = entitiesByID[id]; - if (entity !== undefined) { - entity.selected = true; - if (entity.elRow) { - entity.elRow.className = 'selected'; - } - } else { - notFound = true; - } - }); - - if (autoScroll && selectedIDs.length > 0) { - let firstItem = Number.MAX_VALUE; - let lastItem = -1; - let itemFound = false; - visibleEntities.forEach(function(entity, index) { - if (selectedIDs.indexOf(entity.id) !== -1) { - if (firstItem > index) { - firstItem = index; - } - if (lastItem < index) { - lastItem = index; - } - itemFound = true; - } - }); - if (itemFound) { - entityList.scrollToRow(firstItem, lastItem); - } - } - - elToggleSpaceMode.disabled = selectedIDs.length > 1; - - refreshFooter(); - - return notFound; - } - - function createRow() { - let elRow = document.createElement("tr"); - columns.forEach(function(column) { - let elRowColumn = document.createElement("td"); - elRowColumn.className = createColumnClassName(column.columnID); - elRow.appendChild(elRowColumn); - }); - elRow.oncontextmenu = onRowContextMenu; - elRow.onclick = onRowClicked; - elRow.ondblclick = onRowDoubleClicked; - return elRow; - } - - function updateRow(elRow, itemData) { - // update all column texts and glyphs to this entity's data - for (let i = 0; i < columns.length; ++i) { - let column = columns[i]; - let elCell = elRow.childNodes[i]; - if (column.data.glyph) { - elCell.innerHTML = itemData[column.data.propertyID] ? column.data.columnHeader : null; - } else { - let value = itemData[column.data.propertyID]; - if (column.data.format) { - value = column.data.format(value); - } - elCell.innerHTML = value; - } - elCell.style = "min-width:" + column.widthPx + "px;" + "max-width:" + column.widthPx + "px;"; - elCell.className = createColumnClassName(column.columnID); - } - - // if this entity was previously selected flag it's row as selected - if (itemData.selected) { - elRow.className = 'selected'; - } else { - elRow.className = ''; - } - - // if this row previously had an associated entity ID that wasn't the new entity ID then clear - // the ID from the row and the row element from the previous entity's data, then set the new - // entity ID to the row and the row element to the new entity's data - let prevEntityID = elRow.dataset.entityID; - let newEntityID = itemData.id; - let validPrevItemID = prevEntityID !== undefined && prevEntityID !== EMPTY_ENTITY_ID; - if (validPrevItemID && prevEntityID !== newEntityID && entitiesByID[prevEntityID].elRow === elRow) { - elRow.dataset.entityID = EMPTY_ENTITY_ID; - entitiesByID[prevEntityID].elRow = null; - } - if (!validPrevItemID || prevEntityID !== newEntityID) { - elRow.dataset.entityID = newEntityID; - entitiesByID[newEntityID].elRow = elRow; - } - } - - function clearRow(elRow) { - // reset all texts and glyphs for each of the row's columns - for (let i = 0; i < columns.length; ++i) { - let cell = elRow.childNodes[i]; - if (columns[i].data.glyph) { - cell.innerHTML = ""; - } else { - cell.innerText = ""; - } - } - - // clear the row from any associated entity - let entityID = elRow.dataset.entityID; - if (entityID && entitiesByID[entityID]) { - entitiesByID[entityID].elRow = null; - } - - // reset the row to hidden and clear the entity from the row - elRow.className = ''; - elRow.dataset.entityID = EMPTY_ENTITY_ID; - } - - function onToggleFilterInView() { - isFilterInView = !isFilterInView; - if (isFilterInView) { - elFilterInView.setAttribute(FILTER_IN_VIEW_ATTRIBUTE, FILTER_IN_VIEW_ATTRIBUTE); - } else { - elFilterInView.removeAttribute(FILTER_IN_VIEW_ATTRIBUTE); - } - EventBridge.emitWebEvent(JSON.stringify({ type: "filterInView", filterInView: isFilterInView })); - refreshEntities(); - } - - function onRadiusChange() { - elFilterRadius.value = elFilterRadius.value.replace(/[^0-9]/g, ''); - elFilterRadius.value = Math.max(elFilterRadius.value, 0); - EventBridge.emitWebEvent(JSON.stringify({ type: 'radius', radius: elFilterRadius.value })); - refreshEntities(); - } - - function getColumnIndex(columnID) { - for (let i = 0; i < columns.length; ++i) { - if (columns[i].columnID === columnID) { - return i; - } - } - return -1; - } - - function createColumnClassName(columnID) { - let column = columnsByID[columnID]; - let visible = column.elTh.style.visibility !== "hidden"; - let className = column.data.glyph ? "glyph" : ""; - className += visible ? "" : " hidden"; - return className; - } - - function isColumnsDropdownVisible() { - return elColumnsOptions.style.display === "block"; - } - - function toggleColumnsDropdown() { - elColumnsOptions.style.display = isColumnsDropdownVisible() ? "none" : "block"; - } - - function onToggleColumnsDropdown(event) { - toggleColumnsDropdown(); - if (isTypeDropdownVisible()) { - toggleTypeDropdown(); - } - event.stopPropagation(); - } - - function toggleColumn(elInput, refresh) { - let columnID = elInput.getAttribute("columnID"); - let columnChecked = elInput.checked; - - if (columnChecked) { - let widthNeeded = columnsByID[columnID].data.initialWidth; - - let numberVisibleColumns = 0; - for (let i = 0; i < columns.length; ++i) { - let column = columns[i]; - if (column.columnID === columnID) { - column.width = widthNeeded; - } else if (column.width > 0) { - ++numberVisibleColumns; - } - } - - for (let i = 0; i < columns.length; ++i) { - let column = columns[i]; - if (column.columnID !== columnID && column.width > 0) { - column.width -= column.width * widthNeeded; - } - } - } else { - let widthLoss = 0; - - let numberVisibleColumns = 0; - for (let i = 0; i < columns.length; ++i) { - let column = columns[i]; - if (column.columnID === columnID) { - widthLoss = column.width; - column.width = 0; - } else if (column.width > 0) { - ++numberVisibleColumns; - } - } - - for (let i = 0; i < columns.length; ++i) { - let column = columns[i]; - if (column.columnID !== columnID && column.width > 0) { - let newTotalWidth = (1 - widthLoss); - column.width += (column.width / newTotalWidth) * widthLoss; - } - } - } - - updateColumnWidths(); - } - - function onToggleColumn(event) { - let elTarget = event.target; - if (elTarget instanceof HTMLInputElement) { - toggleColumn(elTarget, true); - } - event.stopPropagation(); - } - - function isTypeDropdownVisible() { - return elFilterTypeOptions.style.display === "block"; - } - - function toggleTypeDropdown() { - elFilterTypeOptions.style.display = isTypeDropdownVisible() ? "none" : "block"; - } - - function onToggleTypeDropdown(event) { - toggleTypeDropdown(); - if (isColumnsDropdownVisible()) { - toggleColumnsDropdown(); - } - event.stopPropagation(); - } - - function refreshTypeFilter(refreshList) { - if (typeFilters.length === 0) { - elFilterTypeText.innerText = "No Types"; - } else if (typeFilters.length === FILTER_TYPES.length) { - elFilterTypeText.innerText = "All Types"; - } else { - elFilterTypeText.innerText = "Types..."; - } - - if (refreshList) { - refreshEntityList(); - } - } - - function toggleTypeFilter(elInput, refreshList) { - let type = elInput.getAttribute("filterType"); - let typeChecked = elInput.checked; - - let typeFilterIndex = typeFilters.indexOf(type); - if (!typeChecked && typeFilterIndex > -1) { - typeFilters.splice(typeFilterIndex, 1); - } else if (typeChecked && typeFilterIndex === -1) { - typeFilters.push(type); - } - - refreshTypeFilter(refreshList); - } - - function onToggleTypeFilter(event) { - let elTarget = event.target; - if (elTarget instanceof HTMLInputElement) { - toggleTypeFilter(elTarget, true); - } - event.stopPropagation(); - } - - function onSelectAllTypes(event) { - for (let type in elFilterTypeInputs) { - elFilterTypeInputs[type].checked = true; - } - typeFilters = FILTER_TYPES; - refreshTypeFilter(true); - event.stopPropagation(); - } - - function onClearAllTypes(event) { - for (let type in elFilterTypeInputs) { - elFilterTypeInputs[type].checked = false; - } - typeFilters = []; - refreshTypeFilter(true); - event.stopPropagation(); - } - - function onBodyClick(event) { - // if clicking anywhere outside of the multiselect dropdowns (since click event bubbled up to onBodyClick and - // propagation wasn't stopped in the toggle type/column callbacks) and the dropdown is open then close it - if (isTypeDropdownVisible()) { - toggleTypeDropdown(); - } - if (isColumnsDropdownVisible()) { - toggleColumnsDropdown(); - } - } - - function onStartResize(event) { - lastResizeEvent = event; - resizeColumnIndex = parseInt(this.parentNode.getAttribute("columnIndex")); - event.stopPropagation(); - } - - function updateColumnWidths() { - let fullWidth = elEntityTableBody.offsetWidth; - let remainingWidth = fullWidth; - let scrollbarVisible = elEntityTableScroll.scrollHeight > elEntityTableScroll.clientHeight; - let resizerRight = scrollbarVisible ? SCROLLBAR_WIDTH - RESIZER_WIDTH/2 : -RESIZER_WIDTH/2; - let visibleColumns = 0; - - for (let i = columns.length - 1; i > 0; --i) { - let column = columns[i]; - column.widthPx = Math.ceil(column.width * fullWidth); - column.elTh.style = "min-width:" + column.widthPx + "px;" + "max-width:" + column.widthPx + "px;"; - let columnVisible = column.width > 0; - column.elTh.style.visibility = columnVisible ? "visible" : "hidden"; - if (column.elResizer) { - column.elResizer.style = "right:" + resizerRight + "px;"; - column.elResizer.style.visibility = columnVisible && visibleColumns > 0 ? "visible" : "hidden"; - } - resizerRight += column.widthPx; - remainingWidth -= column.widthPx; - if (columnVisible) { - ++visibleColumns; - } - } - - // assign all remaining space to the first column - let column = columns[0]; - column.widthPx = remainingWidth; - column.width = remainingWidth / fullWidth; - column.elTh.style = "min-width:" + column.widthPx + "px;" + "max-width:" + column.widthPx + "px;"; - let columnVisible = column.width > 0; - column.elTh.style.visibility = columnVisible ? "visible" : "hidden"; - if (column.elResizer) { - column.elResizer.style = "right:" + resizerRight + "px;"; - column.elResizer.style.visibility = columnVisible && visibleColumns > 0 ? "visible" : "hidden"; - } - - entityList.refresh(); - } - - function swapColumns(columnAIndex, columnBIndex) { - let columnA = columns[columnAIndex]; - let columnB = columns[columnBIndex]; - let columnATh = columns[columnAIndex].elTh; - let columnBTh = columns[columnBIndex].elTh; - let columnThParent = columnATh.parentNode; - columnThParent.removeChild(columnBTh); - columnThParent.insertBefore(columnBTh, columnATh); - columnATh.setAttribute("columnIndex", columnBIndex); - columnBTh.setAttribute("columnIndex", columnAIndex); - columnA.elResizer.setAttribute("columnIndex", columnBIndex); - columnB.elResizer.setAttribute("columnIndex", columnAIndex); - - for (let i = 0; i < visibleEntities.length; ++i) { - let elRow = visibleEntities[i].elRow; - if (elRow) { - let columnACell = elRow.childNodes[columnAIndex]; - let columnBCell = elRow.childNodes[columnBIndex]; - elRow.removeChild(columnBCell); - elRow.insertBefore(columnBCell, columnACell); - } - } - - columns[columnAIndex] = columnB; - columns[columnBIndex] = columnA; - - updateColumnWidths(); - } - - document.onmousemove = function(event) { - if (lastResizeEvent) { - startTh = null; - - let column = columns[resizeColumnIndex]; - - let nextColumnIndex = resizeColumnIndex + 1; - let nextColumn = columns[nextColumnIndex]; - while (nextColumn.width === 0) { - nextColumn = columns[++nextColumnIndex]; - } - - let fullWidth = elEntityTableBody.offsetWidth; - let dx = event.clientX - lastResizeEvent.clientX; - let dPct = dx / fullWidth; - - let newColWidth = column.width + dPct; - let newNextColWidth = nextColumn.width - dPct; - - if (newColWidth * fullWidth >= MINIMUM_COLUMN_WIDTH && newNextColWidth * fullWidth >= MINIMUM_COLUMN_WIDTH) { - column.width += dPct; - nextColumn.width -= dPct; - updateColumnWidths(); - lastResizeEvent = event; - } - } else if (elTargetTh) { - let dxFromInitial = event.clientX - initialThEvent.clientX; - if (Math.abs(dxFromInitial) >= DELTA_X_MOVE_COLUMNS_THRESHOLD) { - elTargetTh.className = "dragging"; - } - if (targetColumnIndex < columns.length - 1) { - let nextColumnIndex = targetColumnIndex + 1; - let nextColumnTh = columns[nextColumnIndex].elTh; - let nextColumnStartX = nextColumnTh.getBoundingClientRect().left; - if (event.clientX >= nextColumnStartX && event.clientX - lastColumnSwapPosition >= DELTA_X_COLUMN_SWAP_POSITION) { - swapColumns(targetColumnIndex, nextColumnIndex); - targetColumnIndex = nextColumnIndex; - lastColumnSwapPosition = event.clientX; - } - } - if (targetColumnIndex >= 1) { - let prevColumnIndex = targetColumnIndex - 1; - let prevColumnTh = columns[prevColumnIndex].elTh; - let prevColumnEndX = prevColumnTh.getBoundingClientRect().right; - if (event.clientX <= prevColumnEndX && lastColumnSwapPosition - event.clientX >= DELTA_X_COLUMN_SWAP_POSITION) { - swapColumns(prevColumnIndex, targetColumnIndex); - targetColumnIndex = prevColumnIndex; - lastColumnSwapPosition = event.clientX; - } - } - } else if (elTargetSpan) { - let dxFromInitial = event.clientX - initialThEvent.clientX; - if (Math.abs(dxFromInitial) >= DELTA_X_MOVE_COLUMNS_THRESHOLD) { - elTargetTh = elTargetSpan.parentNode; - elTargetTh.className = "dragging"; - targetColumnIndex = parseInt(elTargetTh.getAttribute("columnIndex")); - lastColumnSwapPosition = event.clientX; - elTargetSpan = null; - } - } - }; - - document.onmouseup = function(event) { - if (elTargetTh) { - if (elTargetTh.className !== "dragging" && elTargetTh === event.target) { - let columnID = elTargetTh.getAttribute("columnID"); - setSortColumn(columnID); - } - elTargetTh.className = ""; - } else if (elTargetSpan) { - let columnID = elTargetSpan.parentNode.getAttribute("columnID"); - setSortColumn(columnID); - } - lastResizeEvent = null; - elTargetTh = null; - elTargetSpan = null; - initialThEvent = null; - }; - - function setSpaceMode(spaceMode) { - if (spaceMode === "local") { - elToggleSpaceMode.className = "space-mode-local hifi-edit-button"; - elToggleSpaceMode.innerText = "Local"; - } else { - elToggleSpaceMode.className = "space-mode-world hifi-edit-button"; - elToggleSpaceMode.innerText = "World"; - } - } - - const KEY_CODES = { - BACKSPACE: 8, - DELETE: 46 - }; - - document.addEventListener("keyup", function (keyUpEvent) { - const FILTERED_NODE_NAMES = ["INPUT", "TEXTAREA"]; - if (FILTERED_NODE_NAMES.includes(keyUpEvent.target.nodeName)) { - return; - } - - let {code, key, keyCode, altKey, ctrlKey, metaKey, shiftKey} = keyUpEvent; - - let controlKey = window.navigator.platform.startsWith("Mac") ? metaKey : ctrlKey; - - let keyCodeString; - switch (keyCode) { - case KEY_CODES.DELETE: - keyCodeString = "Delete"; - break; - case KEY_CODES.BACKSPACE: - keyCodeString = "Backspace"; - break; - default: - keyCodeString = String.fromCharCode(keyUpEvent.keyCode); - break; - } - - if (controlKey && keyCodeString === "A") { - let visibleEntityIDs = visibleEntities.map(visibleEntity => visibleEntity.id); - let selectionIncludesAllVisibleEntityIDs = visibleEntityIDs.every(visibleEntityID => { - return selectedEntities.includes(visibleEntityID); - }); - - let selection = []; - - if (!selectionIncludesAllVisibleEntityIDs) { - selection = visibleEntityIDs; - } - - updateSelectedEntities(selection); - - EventBridge.emitWebEvent(JSON.stringify({ - type: "selectionUpdate", - focus: false, - entityIds: selection, - })); - - return; - } - - - EventBridge.emitWebEvent(JSON.stringify({ - type: 'keyUpEvent', - keyUpEvent: { - code, - key, - keyCode, - keyCodeString, - altKey, - controlKey, - shiftKey, - } - })); - }, false); - - if (window.EventBridge !== undefined) { - EventBridge.scriptEventReceived.connect(function(data) { - data = JSON.parse(data); - if (data.type === "clearEntityList") { - clearEntities(); - } else if (data.type === "selectionUpdate") { - let notFound = updateSelectedEntities(data.selectedIDs, true); - if (notFound) { - refreshEntities(); - } - } else if (data.type === "update" && data.selectedIDs !== undefined) { - PROFILE("update", function() { - let newEntities = data.entities; - if (newEntities) { - if (newEntities.length === 0) { - clearEntities(); - } else { - updateEntityData(newEntities); - updateSelectedEntities(data.selectedIDs, true); - } - } - setSpaceMode(data.spaceMode); - }); - } else if (data.type === "removeEntities" && data.deletedIDs !== undefined && data.selectedIDs !== undefined) { - removeEntities(data.deletedIDs); - updateSelectedEntities(data.selectedIDs, true); - } else if (data.type === "deleted" && data.ids) { - removeEntities(data.ids); - } else if (data.type === "setSpaceMode") { - setSpaceMode(data.spaceMode); - } - }); - } - - refreshSortOrder(); - refreshEntities(); - - window.addEventListener("resize", updateColumnWidths); - }); - - augmentSpinButtons(); - disableDragDrop(); - - document.addEventListener("contextmenu", function(event) { - entityListContextMenu.close(); - - // Disable default right-click context menu which is not visible in the HMD and makes it seem like the app has locked - event.preventDefault(); - }, false); - - // close context menu when switching focus to another window - $(window).blur(function() { - entityListContextMenu.close(); - }); -} diff --git a/scripts/simplifiedUI/system/html/js/entityListContextMenu.js b/scripts/simplifiedUI/system/html/js/entityListContextMenu.js deleted file mode 100644 index d71719f252..0000000000 --- a/scripts/simplifiedUI/system/html/js/entityListContextMenu.js +++ /dev/null @@ -1,163 +0,0 @@ -// -// entityListContextMenu.js -// -// exampleContextMenus.js was originally created by David Rowe on 22 Aug 2018. -// Modified to entityListContextMenu.js by Thijs Wenker on 10 Oct 2018 -// Copyright 2018 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -/* eslint-env browser */ -const CONTEXT_MENU_CLASS = "context-menu"; - -/** - * ContextMenu class for EntityList - * @constructor - */ -function EntityListContextMenu() { - this._elContextMenu = null; - this._onSelectedCallback = null; - this._listItems = []; - this._initialize(); -} - -EntityListContextMenu.prototype = { - - /** - * @private - */ - _elContextMenu: null, - - /** - * @private - */ - _onSelectedCallback: null, - - /** - * @private - */ - _selectedEntityID: null, - - /** - * @private - */ - _listItems: null, - - /** - * Close the context menu - */ - close: function() { - if (this.isContextMenuOpen()) { - this._elContextMenu.style.display = "none"; - } - }, - - isContextMenuOpen: function() { - return this._elContextMenu.style.display === "block"; - }, - - /** - * Open the context menu - * @param clickEvent - * @param selectedEntityID - * @param enabledOptions - */ - open: function(clickEvent, selectedEntityID, enabledOptions) { - this._selectedEntityID = selectedEntityID; - - this._listItems.forEach(function(listItem) { - let enabled = enabledOptions.includes(listItem.label); - listItem.enabled = enabled; - listItem.element.setAttribute('class', enabled ? '' : 'disabled'); - }); - - this._elContextMenu.style.display = "block"; - this._elContextMenu.style.left - = Math.min(clickEvent.pageX, document.body.offsetWidth - this._elContextMenu.offsetWidth).toString() + "px"; - this._elContextMenu.style.top - = Math.min(clickEvent.pageY, document.body.clientHeight - this._elContextMenu.offsetHeight).toString() + "px"; - clickEvent.stopPropagation(); - }, - - /** - * Set the callback for when a menu item is selected - * @param onSelectedCallback - */ - setOnSelectedCallback: function(onSelectedCallback) { - this._onSelectedCallback = onSelectedCallback; - }, - - /** - * Add a labeled item to the context menu - * @param itemLabel - * @private - */ - _addListItem: function(itemLabel) { - let elListItem = document.createElement("li"); - elListItem.innerText = itemLabel; - - let listItem = { - label: itemLabel, - element: elListItem, - enabled: false - }; - - elListItem.addEventListener("click", function () { - if (listItem.enabled && this._onSelectedCallback) { - this._onSelectedCallback.call(this, itemLabel, this._selectedEntityID); - } - }.bind(this), false); - - elListItem.setAttribute('class', 'disabled'); - - this._listItems.push(listItem); - this._elContextMenu.appendChild(elListItem); - }, - - /** - * Add a separator item to the context menu - * @private - */ - _addListSeparator: function() { - let elListItem = document.createElement("li"); - elListItem.setAttribute('class', 'separator'); - this._elContextMenu.appendChild(elListItem); - }, - - /** - * Initialize the context menu. - * @private - */ - _initialize: function() { - this._elContextMenu = document.createElement("ul"); - this._elContextMenu.setAttribute("class", CONTEXT_MENU_CLASS); - document.body.appendChild(this._elContextMenu); - - this._addListItem("Cut"); - this._addListItem("Copy"); - this._addListItem("Paste"); - this._addListSeparator(); - this._addListItem("Rename"); - this._addListItem("Duplicate"); - this._addListItem("Delete"); - - // Ignore clicks on context menu background or separator. - this._elContextMenu.addEventListener("click", function(event) { - // Sink clicks on context menu background or separator but let context menu item clicks through. - if (event.target.classList.contains(CONTEXT_MENU_CLASS)) { - event.stopPropagation(); - } - }); - - // Provide means to close context menu without clicking menu item. - document.body.addEventListener("click", this.close.bind(this)); - document.body.addEventListener("keydown", function(event) { - // Close context menu with Esc key. - if (this.isContextMenuOpen() && event.key === "Escape") { - this.close(); - } - }.bind(this)); - } -}; diff --git a/scripts/simplifiedUI/system/html/js/entityProperties.js b/scripts/simplifiedUI/system/html/js/entityProperties.js deleted file mode 100644 index e64543d41f..0000000000 --- a/scripts/simplifiedUI/system/html/js/entityProperties.js +++ /dev/null @@ -1,4419 +0,0 @@ -// entityProperties.js -// -// Created by Ryan Huffman on 13 Nov 2014 -// Modified by David Back on 19 Oct 2018 -// Copyright 2014 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html - -/* global alert, augmentSpinButtons, clearTimeout, console, document, Element, - EventBridge, JSONEditor, openEventBridge, setTimeout, window, _, $ */ - -const DEGREES_TO_RADIANS = Math.PI / 180.0; - -const NO_SELECTION = ","; - -const PROPERTY_SPACE_MODE = Object.freeze({ - ALL: 0, - LOCAL: 1, - WORLD: 2 -}); - -const PROPERTY_SELECTION_VISIBILITY = Object.freeze({ - SINGLE_SELECTION: 1, - MULTIPLE_SELECTIONS: 2, - MULTI_DIFF_SELECTIONS: 4, - ANY_SELECTIONS: 7, /* SINGLE_SELECTION | MULTIPLE_SELECTIONS | MULTI_DIFF_SELECTIONS */ -}); - -// Multiple-selection behavior -const PROPERTY_MULTI_DISPLAY_MODE = Object.freeze({ - DEFAULT: 0, - /** - * Comma separated values - * Limited for properties with type "string" or "textarea" and readOnly enabled - */ - COMMA_SEPARATED_VALUES: 1, -}); - -const GROUPS = [ - { - id: "base", - properties: [ - { - label: NO_SELECTION, - type: "icon", - icons: ENTITY_TYPE_ICON, - propertyID: "type", - replaceID: "placeholder-property-type", - }, - { - label: "Name", - type: "string", - propertyID: "name", - placeholder: "Name", - replaceID: "placeholder-property-name", - }, - { - label: "ID", - type: "string", - propertyID: "id", - placeholder: "ID", - readOnly: true, - replaceID: "placeholder-property-id", - multiDisplayMode: PROPERTY_MULTI_DISPLAY_MODE.COMMA_SEPARATED_VALUES, - }, - { - label: "Description", - type: "string", - propertyID: "description", - }, - { - label: "Parent", - type: "string", - propertyID: "parentID", - onChange: parentIDChanged, - }, - { - label: "Parent Joint Index", - type: "number", - propertyID: "parentJointIndex", - }, - { - label: "", - glyph: "", - type: "bool", - propertyID: "locked", - replaceID: "placeholder-property-locked", - }, - { - label: "", - glyph: "", - type: "bool", - propertyID: "visible", - replaceID: "placeholder-property-visible", - }, - { - label: "Render Layer", - type: "dropdown", - options: { - world: "World", - front: "Front", - hud: "HUD" - }, - propertyID: "renderLayer", - }, - { - label: "Primitive Mode", - type: "dropdown", - options: { - solid: "Solid", - lines: "Wireframe", - }, - propertyID: "primitiveMode", - }, - ] - }, - { - id: "shape", - addToGroup: "base", - properties: [ - { - label: "Shape", - type: "dropdown", - options: { Cube: "Box", Sphere: "Sphere", Tetrahedron: "Tetrahedron", Octahedron: "Octahedron", - Icosahedron: "Icosahedron", Dodecahedron: "Dodecahedron", Hexagon: "Hexagon", - Triangle: "Triangle", Octagon: "Octagon", Cylinder: "Cylinder", Cone: "Cone", - Circle: "Circle", Quad: "Quad" }, - propertyID: "shape", - }, - { - label: "Color", - type: "color", - propertyID: "color", - }, - ] - }, - { - id: "text", - addToGroup: "base", - properties: [ - { - label: "Text", - type: "string", - propertyID: "text", - }, - { - label: "Text Color", - type: "color", - propertyID: "textColor", - }, - { - label: "Text Alpha", - type: "number-draggable", - min: 0, - max: 1, - step: 0.01, - decimals: 2, - propertyID: "textAlpha", - }, - { - label: "Background Color", - type: "color", - propertyID: "backgroundColor", - }, - { - label: "Background Alpha", - type: "number-draggable", - min: 0, - max: 1, - step: 0.01, - decimals: 2, - propertyID: "backgroundAlpha", - }, - { - label: "Line Height", - type: "number-draggable", - min: 0, - step: 0.001, - decimals: 4, - unit: "m", - propertyID: "lineHeight", - }, - { - label: "Billboard Mode", - type: "dropdown", - options: { none: "None", yaw: "Yaw", full: "Full"}, - propertyID: "textBillboardMode", - propertyName: "billboardMode", // actual entity property name - }, - { - label: "Top Margin", - type: "number-draggable", - step: 0.01, - decimals: 2, - propertyID: "topMargin", - }, - { - label: "Right Margin", - type: "number-draggable", - step: 0.01, - decimals: 2, - propertyID: "rightMargin", - }, - { - label: "Bottom Margin", - type: "number-draggable", - step: 0.01, - decimals: 2, - propertyID: "bottomMargin", - }, - { - label: "Left Margin", - type: "number-draggable", - step: 0.01, - decimals: 2, - propertyID: "leftMargin", - }, - ] - }, - { - id: "zone", - addToGroup: "base", - properties: [ - { - label: "Shape Type", - type: "dropdown", - options: { "box": "Box", "sphere": "Sphere", "ellipsoid": "Ellipsoid", - "cylinder-y": "Cylinder", "compound": "Use Compound Shape URL" }, - propertyID: "zoneShapeType", - propertyName: "shapeType", // actual entity property name - }, - { - label: "Compound Shape URL", - type: "string", - propertyID: "zoneCompoundShapeURL", - propertyName: "compoundShapeURL", // actual entity property name - }, - { - label: "Flying Allowed", - type: "bool", - propertyID: "flyingAllowed", - }, - { - label: "Ghosting Allowed", - type: "bool", - propertyID: "ghostingAllowed", - }, - { - label: "Filter", - type: "string", - propertyID: "filterURL", - }, - { - label: "Key Light", - type: "dropdown", - options: { inherit: "Inherit", disabled: "Off", enabled: "On" }, - propertyID: "keyLightMode", - - }, - { - label: "Key Light Color", - type: "color", - propertyID: "keyLight.color", - showPropertyRule: { "keyLightMode": "enabled" }, - }, - { - label: "Light Intensity", - type: "number-draggable", - min: 0, - max: 40, - step: 0.01, - decimals: 2, - propertyID: "keyLight.intensity", - showPropertyRule: { "keyLightMode": "enabled" }, - }, - { - label: "Light Horizontal Angle", - type: "number-draggable", - step: 0.1, - multiplier: DEGREES_TO_RADIANS, - decimals: 2, - unit: "deg", - propertyID: "keyLight.direction.y", - showPropertyRule: { "keyLightMode": "enabled" }, - }, - { - label: "Light Vertical Angle", - type: "number-draggable", - step: 0.1, - multiplier: DEGREES_TO_RADIANS, - decimals: 2, - unit: "deg", - propertyID: "keyLight.direction.x", - showPropertyRule: { "keyLightMode": "enabled" }, - }, - { - label: "Cast Shadows", - type: "bool", - propertyID: "keyLight.castShadows", - showPropertyRule: { "keyLightMode": "enabled" }, - }, - { - label: "Skybox", - type: "dropdown", - options: { inherit: "Inherit", disabled: "Off", enabled: "On" }, - propertyID: "skyboxMode", - }, - { - label: "Skybox Color", - type: "color", - propertyID: "skybox.color", - showPropertyRule: { "skyboxMode": "enabled" }, - }, - { - label: "Skybox Source", - type: "string", - propertyID: "skybox.url", - showPropertyRule: { "skyboxMode": "enabled" }, - }, - { - label: "Ambient Light", - type: "dropdown", - options: { inherit: "Inherit", disabled: "Off", enabled: "On" }, - propertyID: "ambientLightMode", - }, - { - label: "Ambient Intensity", - type: "number-draggable", - min: 0, - max: 200, - step: 0.1, - decimals: 2, - propertyID: "ambientLight.ambientIntensity", - showPropertyRule: { "ambientLightMode": "enabled" }, - }, - { - label: "Ambient Source", - type: "string", - propertyID: "ambientLight.ambientURL", - showPropertyRule: { "ambientLightMode": "enabled" }, - }, - { - type: "buttons", - buttons: [ { id: "copy", label: "Copy from Skybox", - className: "black", onClick: copySkyboxURLToAmbientURL } ], - propertyID: "copyURLToAmbient", - showPropertyRule: { "ambientLightMode": "enabled" }, - }, - { - label: "Haze", - type: "dropdown", - options: { inherit: "Inherit", disabled: "Off", enabled: "On" }, - propertyID: "hazeMode", - }, - { - label: "Range", - type: "number-draggable", - min: 1, - max: 10000, - step: 1, - decimals: 0, - unit: "m", - propertyID: "haze.hazeRange", - showPropertyRule: { "hazeMode": "enabled" }, - }, - { - label: "Use Altitude", - type: "bool", - propertyID: "haze.hazeAltitudeEffect", - showPropertyRule: { "hazeMode": "enabled" }, - }, - { - label: "Base", - type: "number-draggable", - min: -1000, - max: 1000, - step: 1, - decimals: 0, - unit: "m", - propertyID: "haze.hazeBaseRef", - showPropertyRule: { "hazeMode": "enabled" }, - }, - { - label: "Ceiling", - type: "number-draggable", - min: -1000, - max: 5000, - step: 1, - decimals: 0, - unit: "m", - propertyID: "haze.hazeCeiling", - showPropertyRule: { "hazeMode": "enabled" }, - }, - { - label: "Haze Color", - type: "color", - propertyID: "haze.hazeColor", - showPropertyRule: { "hazeMode": "enabled" }, - }, - { - label: "Background Blend", - type: "number-draggable", - min: 0, - max: 1, - step: 0.001, - decimals: 3, - propertyID: "haze.hazeBackgroundBlend", - showPropertyRule: { "hazeMode": "enabled" }, - }, - { - label: "Enable Glare", - type: "bool", - propertyID: "haze.hazeEnableGlare", - showPropertyRule: { "hazeMode": "enabled" }, - }, - { - label: "Glare Color", - type: "color", - propertyID: "haze.hazeGlareColor", - showPropertyRule: { "hazeMode": "enabled" }, - }, - { - label: "Glare Angle", - type: "number-draggable", - min: 0, - max: 180, - step: 1, - decimals: 0, - propertyID: "haze.hazeGlareAngle", - showPropertyRule: { "hazeMode": "enabled" }, - }, - { - label: "Bloom", - type: "dropdown", - options: { inherit: "Inherit", disabled: "Off", enabled: "On" }, - propertyID: "bloomMode", - }, - { - label: "Bloom Intensity", - type: "number-draggable", - min: 0, - max: 1, - step: 0.001, - decimals: 3, - propertyID: "bloom.bloomIntensity", - showPropertyRule: { "bloomMode": "enabled" }, - }, - { - label: "Bloom Threshold", - type: "number-draggable", - min: 0, - max: 1, - step: 0.001, - decimals: 3, - propertyID: "bloom.bloomThreshold", - showPropertyRule: { "bloomMode": "enabled" }, - }, - { - label: "Bloom Size", - type: "number-draggable", - min: 0, - max: 2, - step: 0.001, - decimals: 3, - propertyID: "bloom.bloomSize", - showPropertyRule: { "bloomMode": "enabled" }, - }, - { - label: "Avatar Priority", - type: "dropdown", - options: { inherit: "Inherit", crowd: "Crowd", hero: "Hero" }, - propertyID: "avatarPriority", - }, - - ] - }, - { - id: "model", - addToGroup: "base", - properties: [ - { - label: "Model", - type: "string", - placeholder: "URL", - propertyID: "modelURL", - hideIfCertified: true, - }, - { - label: "Collision Shape", - type: "dropdown", - options: { "none": "No Collision", "box": "Box", "sphere": "Sphere", "compound": "Compound" , - "simple-hull": "Basic - Whole model", "simple-compound": "Good - Sub-meshes" , - "static-mesh": "Exact - All polygons (non-dynamic only)" }, - propertyID: "shapeType", - }, - { - label: "Compound Shape", - type: "string", - propertyID: "compoundShapeURL", - hideIfCertified: true, - }, - { - label: "Animation", - type: "string", - propertyID: "animation.url", - hideIfCertified: true, - }, - { - label: "Play Automatically", - type: "bool", - propertyID: "animation.running", - }, - { - label: "Loop", - type: "bool", - propertyID: "animation.loop", - }, - { - label: "Allow Transition", - type: "bool", - propertyID: "animation.allowTranslation", - }, - { - label: "Hold", - type: "bool", - propertyID: "animation.hold", - }, - { - label: "Animation Frame", - type: "number-draggable", - propertyID: "animation.currentFrame", - }, - { - label: "First Frame", - type: "number-draggable", - propertyID: "animation.firstFrame", - }, - { - label: "Last Frame", - type: "number-draggable", - propertyID: "animation.lastFrame", - }, - { - label: "Animation FPS", - type: "number-draggable", - propertyID: "animation.fps", - }, - { - label: "Texture", - type: "textarea", - propertyID: "textures", - }, - { - label: "Original Texture", - type: "textarea", - propertyID: "originalTextures", - readOnly: true, - hideIfCertified: true, - }, - { - label: "Group Culled", - type: "bool", - propertyID: "groupCulled", - }, - ] - }, - { - id: "image", - addToGroup: "base", - properties: [ - { - label: "Image", - type: "string", - placeholder: "URL", - propertyID: "imageURL", - }, - { - label: "Color", - type: "color", - propertyID: "imageColor", - propertyName: "color", // actual entity property name - }, - { - label: "Emissive", - type: "bool", - propertyID: "emissive", - }, - { - label: "Sub Image", - type: "rect", - min: 0, - step: 1, - subLabels: [ "x", "y", "w", "h" ], - propertyID: "subImage", - }, - { - label: "Billboard Mode", - type: "dropdown", - options: { none: "None", yaw: "Yaw", full: "Full"}, - propertyID: "imageBillboardMode", - propertyName: "billboardMode", // actual entity property name - }, - { - label: "Keep Aspect Ratio", - type: "bool", - propertyID: "keepAspectRatio", - }, - ] - }, - { - id: "web", - addToGroup: "base", - properties: [ - { - label: "Source", - type: "string", - propertyID: "sourceUrl", - }, - { - label: "Source Resolution", - type: "number-draggable", - propertyID: "dpi", - }, - { - label: "Web Color", - type: "color", - propertyID: "webColor", - propertyName: "color", // actual entity property name - }, - { - label: "Web Alpha", - type: "number-draggable", - step: 0.001, - decimals: 3, - propertyID: "webAlpha", - propertyName: "alpha", - min: 0, - max: 1, - }, - { - label: "Max FPS", - type: "number-draggable", - step: 1, - decimals: 0, - propertyID: "maxFPS", - }, - { - label: "Script URL", - type: "string", - propertyID: "scriptURL", - placeholder: "URL", - }, - ] - }, - { - id: "light", - addToGroup: "base", - properties: [ - { - label: "Light Color", - type: "color", - propertyID: "lightColor", - propertyName: "color", // actual entity property name - }, - { - label: "Intensity", - type: "number-draggable", - min: 0, - max: 10000, - step: 0.1, - decimals: 2, - propertyID: "intensity", - }, - { - label: "Fall-Off Radius", - type: "number-draggable", - min: 0, - max: 10000, - step: 0.1, - decimals: 2, - unit: "m", - propertyID: "falloffRadius", - }, - { - label: "Spotlight", - type: "bool", - propertyID: "isSpotlight", - }, - { - label: "Spotlight Exponent", - type: "number-draggable", - min: 0, - step: 0.01, - decimals: 2, - propertyID: "exponent", - }, - { - label: "Spotlight Cut-Off", - type: "number-draggable", - step: 0.01, - decimals: 2, - propertyID: "cutoff", - }, - ] - }, - { - id: "material", - addToGroup: "base", - properties: [ - { - label: "Material URL", - type: "string", - propertyID: "materialURL", - }, - { - label: "Material Data", - type: "textarea", - buttons: [ { id: "clear", label: "Clear Material Data", className: "red", onClick: clearMaterialData }, - { id: "edit", label: "Edit as JSON", className: "blue", onClick: newJSONMaterialEditor }, - { id: "save", label: "Save Material Data", className: "black", onClick: saveMaterialData } ], - propertyID: "materialData", - }, - { - label: "Material Target", - type: "dynamic-multiselect", - propertyUpdate: materialTargetPropertyUpdate, - propertyID: "parentMaterialName", - selectionVisibility: PROPERTY_SELECTION_VISIBILITY.SINGLE_SELECTION, - }, - { - label: "Priority", - type: "number-draggable", - min: 0, - propertyID: "priority", - }, - { - label: "Material Mapping Mode", - type: "dropdown", - options: { - uv: "UV space", projected: "3D projected" - }, - propertyID: "materialMappingMode", - }, - { - label: "Material Position", - type: "vec2", - vec2Type: "xyz", - min: 0, - max: 1, - step: 0.1, - decimals: 4, - subLabels: [ "x", "y" ], - propertyID: "materialMappingPos", - }, - { - label: "Material Scale", - type: "vec2", - vec2Type: "xyz", - min: 0, - step: 0.1, - decimals: 4, - subLabels: [ "x", "y" ], - propertyID: "materialMappingScale", - }, - { - label: "Material Rotation", - type: "number-draggable", - step: 0.1, - decimals: 2, - unit: "deg", - propertyID: "materialMappingRot", - }, - { - label: "Material Repeat", - type: "bool", - propertyID: "materialRepeat", - }, - ] - }, - { - id: "grid", - addToGroup: "base", - properties: [ - { - label: "Color", - type: "color", - propertyID: "gridColor", - propertyName: "color", // actual entity property name - }, - { - label: "Follow Camera", - type: "bool", - propertyID: "followCamera", - }, - { - label: "Major Grid Every", - type: "number-draggable", - min: 0, - step: 1, - decimals: 0, - propertyID: "majorGridEvery", - }, - { - label: "Minor Grid Every", - type: "number-draggable", - min: 0, - step: 0.01, - decimals: 2, - propertyID: "minorGridEvery", - }, - ] - }, - { - id: "particles", - addToGroup: "base", - properties: [ - { - label: "Emit", - type: "bool", - propertyID: "isEmitting", - }, - { - label: "Lifespan", - type: "number-draggable", - unit: "s", - step: 0.01, - decimals: 2, - propertyID: "lifespan", - }, - { - label: "Max Particles", - type: "number-draggable", - step: 1, - propertyID: "maxParticles", - }, - { - label: "Texture", - type: "texture", - propertyID: "particleTextures", - propertyName: "textures", // actual entity property name - }, - ] - }, - { - id: "particles_emit", - label: "EMIT", - isMinor: true, - properties: [ - { - label: "Emit Rate", - type: "number-draggable", - step: 1, - propertyID: "emitRate", - }, - { - label: "Emit Speed", - type: "number-draggable", - step: 0.1, - decimals: 2, - propertyID: "emitSpeed", - }, - { - label: "Speed Spread", - type: "number-draggable", - step: 0.1, - decimals: 2, - propertyID: "speedSpread", - }, - { - label: "Shape Type", - type: "dropdown", - options: { "box": "Box", "ellipsoid": "Ellipsoid", - "cylinder-y": "Cylinder", "circle": "Circle", "plane": "Plane", - "compound": "Use Compound Shape URL" }, - propertyID: "particleShapeType", - propertyName: "shapeType", - }, - { - label: "Compound Shape URL", - type: "string", - propertyID: "particleCompoundShapeURL", - propertyName: "compoundShapeURL", - }, - { - label: "Emit Dimensions", - type: "vec3", - vec3Type: "xyz", - step: 0.01, - round: 100, - subLabels: [ "x", "y", "z" ], - propertyID: "emitDimensions", - }, - { - label: "Emit Radius Start", - type: "number-draggable", - step: 0.001, - decimals: 3, - propertyID: "emitRadiusStart" - }, - { - label: "Emit Orientation", - type: "vec3", - vec3Type: "pyr", - step: 0.01, - round: 100, - subLabels: [ "x", "y", "z" ], - unit: "deg", - propertyID: "emitOrientation", - }, - { - label: "Trails", - type: "bool", - propertyID: "emitterShouldTrail", - }, - ] - }, - { - id: "particles_size", - label: "SIZE", - isMinor: true, - properties: [ - { - type: "triple", - label: "Size", - propertyID: "particleRadiusTriple", - properties: [ - { - label: "Start", - type: "number-draggable", - step: 0.01, - decimals: 2, - propertyID: "radiusStart", - fallbackProperty: "particleRadius", - }, - { - label: "Middle", - type: "number-draggable", - step: 0.01, - decimals: 2, - propertyID: "particleRadius", - }, - { - label: "Finish", - type: "number-draggable", - step: 0.01, - decimals: 2, - propertyID: "radiusFinish", - fallbackProperty: "particleRadius", - }, - ] - }, - { - label: "Size Spread", - type: "number-draggable", - step: 0.01, - decimals: 2, - propertyID: "radiusSpread", - }, - ] - }, - { - id: "particles_color", - label: "COLOR", - isMinor: true, - properties: [ - { - type: "triple", - label: "Color", - propertyID: "particleColorTriple", - properties: [ - { - label: "Start", - type: "color", - propertyID: "colorStart", - fallbackProperty: "color", - }, - { - label: "Middle", - type: "color", - propertyID: "particleColor", - propertyName: "color", // actual entity property name - }, - { - label: "Finish", - type: "color", - propertyID: "colorFinish", - fallbackProperty: "color", - }, - ] - }, - { - label: "Color Spread", - type: "color", - propertyID: "colorSpread", - }, - ] - }, - { - id: "particles_alpha", - label: "ALPHA", - isMinor: true, - properties: [ - { - type: "triple", - label: "Alpha", - propertyID: "particleAlphaTriple", - properties: [ - { - label: "Start", - type: "number-draggable", - step: 0.001, - decimals: 3, - propertyID: "alphaStart", - fallbackProperty: "alpha", - }, - { - label: "Middle", - type: "number-draggable", - step: 0.001, - decimals: 3, - propertyID: "alpha", - }, - { - label: "Finish", - type: "number-draggable", - step: 0.001, - decimals: 3, - propertyID: "alphaFinish", - fallbackProperty: "alpha", - }, - ] - }, - { - label: "Alpha Spread", - type: "number-draggable", - step: 0.001, - decimals: 3, - propertyID: "alphaSpread", - }, - ] - }, - { - id: "particles_acceleration", - label: "ACCELERATION", - isMinor: true, - properties: [ - { - label: "Emit Acceleration", - type: "vec3", - vec3Type: "xyz", - step: 0.01, - round: 100, - subLabels: [ "x", "y", "z" ], - propertyID: "emitAcceleration", - }, - { - label: "Acceleration Spread", - type: "vec3", - vec3Type: "xyz", - step: 0.01, - round: 100, - subLabels: [ "x", "y", "z" ], - propertyID: "accelerationSpread", - }, - ] - }, - { - id: "particles_spin", - label: "SPIN", - isMinor: true, - properties: [ - { - type: "triple", - label: "Spin", - propertyID: "particleSpinTriple", - properties: [ - { - label: "Start", - type: "number-draggable", - step: 0.1, - decimals: 2, - multiplier: DEGREES_TO_RADIANS, - unit: "deg", - propertyID: "spinStart", - fallbackProperty: "particleSpin", - }, - { - label: "Middle", - type: "number-draggable", - step: 0.1, - decimals: 2, - multiplier: DEGREES_TO_RADIANS, - unit: "deg", - propertyID: "particleSpin", - }, - { - label: "Finish", - type: "number-draggable", - step: 0.1, - decimals: 2, - multiplier: DEGREES_TO_RADIANS, - unit: "deg", - propertyID: "spinFinish", - fallbackProperty: "particleSpin", - }, - ] - }, - { - label: "Spin Spread", - type: "number-draggable", - step: 0.1, - decimals: 2, - multiplier: DEGREES_TO_RADIANS, - unit: "deg", - propertyID: "spinSpread", - }, - { - label: "Rotate with Entity", - type: "bool", - propertyID: "rotateWithEntity", - }, - ] - }, - { - id: "particles_constraints", - label: "CONSTRAINTS", - isMinor: true, - properties: [ - { - type: "triple", - label: "Horizontal Angle", - propertyID: "particlePolarTriple", - properties: [ - { - label: "Start", - type: "number-draggable", - step: 0.1, - decimals: 2, - multiplier: DEGREES_TO_RADIANS, - unit: "deg", - propertyID: "polarStart", - }, - { - label: "Finish", - type: "number-draggable", - step: 0.1, - decimals: 2, - multiplier: DEGREES_TO_RADIANS, - unit: "deg", - propertyID: "polarFinish", - }, - ], - }, - { - type: "triple", - label: "Vertical Angle", - propertyID: "particleAzimuthTriple", - properties: [ - { - label: "Start", - type: "number-draggable", - step: 0.1, - decimals: 2, - multiplier: DEGREES_TO_RADIANS, - unit: "deg", - propertyID: "azimuthStart", - }, - { - label: "Finish", - type: "number-draggable", - step: 0.1, - decimals: 2, - multiplier: DEGREES_TO_RADIANS, - unit: "deg", - propertyID: "azimuthFinish", - }, - ] - } - ] - }, - { - id: "spatial", - label: "SPATIAL", - properties: [ - { - label: "Position", - type: "vec3", - vec3Type: "xyz", - step: 0.1, - decimals: 4, - subLabels: [ "x", "y", "z" ], - unit: "m", - propertyID: "position", - spaceMode: PROPERTY_SPACE_MODE.WORLD, - }, - { - label: "Local Position", - type: "vec3", - vec3Type: "xyz", - step: 0.1, - decimals: 4, - subLabels: [ "x", "y", "z" ], - unit: "m", - propertyID: "localPosition", - spaceMode: PROPERTY_SPACE_MODE.LOCAL, - }, - { - label: "Rotation", - type: "vec3", - vec3Type: "pyr", - step: 0.1, - decimals: 4, - subLabels: [ "x", "y", "z" ], - unit: "deg", - propertyID: "rotation", - spaceMode: PROPERTY_SPACE_MODE.WORLD, - }, - { - label: "Local Rotation", - type: "vec3", - vec3Type: "pyr", - step: 0.1, - decimals: 4, - subLabels: [ "x", "y", "z" ], - unit: "deg", - propertyID: "localRotation", - spaceMode: PROPERTY_SPACE_MODE.LOCAL, - }, - { - label: "Dimensions", - type: "vec3", - vec3Type: "xyz", - step: 0.01, - decimals: 4, - subLabels: [ "x", "y", "z" ], - unit: "m", - propertyID: "dimensions", - spaceMode: PROPERTY_SPACE_MODE.WORLD, - }, - { - label: "Local Dimensions", - type: "vec3", - vec3Type: "xyz", - step: 0.01, - decimals: 4, - subLabels: [ "x", "y", "z" ], - unit: "m", - propertyID: "localDimensions", - spaceMode: PROPERTY_SPACE_MODE.LOCAL, - }, - { - label: "Scale", - type: "number-draggable", - defaultValue: 100, - unit: "%", - buttons: [ { id: "rescale", label: "Rescale", className: "blue", onClick: rescaleDimensions }, - { id: "reset", label: "Reset Dimensions", className: "red", onClick: resetToNaturalDimensions } ], - propertyID: "scale", - }, - { - label: "Pivot", - type: "vec3", - vec3Type: "xyz", - step: 0.001, - decimals: 4, - subLabels: [ "x", "y", "z" ], - unit: "(ratio of dimension)", - propertyID: "registrationPoint", - }, - { - label: "Align", - type: "buttons", - buttons: [ { id: "selection", label: "Selection to Grid", className: "black", onClick: moveSelectionToGrid }, - { id: "all", label: "All to Grid", className: "black", onClick: moveAllToGrid } ], - propertyID: "alignToGrid", - }, - ] - }, - { - id: "behavior", - label: "BEHAVIOR", - properties: [ - { - label: "Grabbable", - type: "bool", - propertyID: "grab.grabbable", - }, - { - label: "Cloneable", - type: "bool", - propertyID: "cloneable", - }, - { - label: "Clone Lifetime", - type: "number-draggable", - min: -1, - unit: "s", - propertyID: "cloneLifetime", - showPropertyRule: { "cloneable": "true" }, - }, - { - label: "Clone Limit", - type: "number-draggable", - min: 0, - propertyID: "cloneLimit", - showPropertyRule: { "cloneable": "true" }, - }, - { - label: "Clone Dynamic", - type: "bool", - propertyID: "cloneDynamic", - showPropertyRule: { "cloneable": "true" }, - }, - { - label: "Clone Avatar Entity", - type: "bool", - propertyID: "cloneAvatarEntity", - showPropertyRule: { "cloneable": "true" }, - }, - { - label: "Triggerable", - type: "bool", - propertyID: "grab.triggerable", - }, - { - label: "Follow Controller", - type: "bool", - propertyID: "grab.grabFollowsController", - }, - { - label: "Cast Shadows", - type: "bool", - propertyID: "canCastShadow", - }, - { - label: "Link", - type: "string", - propertyID: "href", - placeholder: "URL", - }, - { - label: "Ignore Pick Intersection", - type: "bool", - propertyID: "ignorePickIntersection", - }, - { - label: "Script", - type: "string", - buttons: [ { id: "reload", label: "F", className: "glyph", onClick: reloadScripts } ], - propertyID: "script", - placeholder: "URL", - hideIfCertified: true, - }, - { - label: "Server Script", - type: "string", - buttons: [ { id: "reload", label: "F", className: "glyph", onClick: reloadServerScripts } ], - propertyID: "serverScripts", - placeholder: "URL", - }, - { - label: "Server Script Status", - type: "placeholder", - indentedLabel: true, - propertyID: "serverScriptStatus", - selectionVisibility: PROPERTY_SELECTION_VISIBILITY.SINGLE_SELECTION, - }, - { - label: "Lifetime", - type: "number", - unit: "s", - propertyID: "lifetime", - }, - { - label: "User Data", - type: "textarea", - buttons: [ { id: "clear", label: "Clear User Data", className: "red", onClick: clearUserData }, - { id: "edit", label: "Edit as JSON", className: "blue", onClick: newJSONEditor }, - { id: "save", label: "Save User Data", className: "black", onClick: saveUserData } ], - propertyID: "userData", - }, - ] - }, - { - id: "collision", - label: "COLLISION", - properties: [ - { - label: "Collides", - type: "bool", - inverse: true, - propertyID: "collisionless", - }, - { - label: "Static Entities", - type: "bool", - propertyID: "collidesWithStatic", - propertyName: "static", // actual subProperty name - subPropertyOf: "collidesWith", - showPropertyRule: { "collisionless": "false" }, - }, - { - label: "Kinematic Entities", - type: "bool", - propertyID: "collidesWithKinematic", - propertyName: "kinematic", // actual subProperty name - subPropertyOf: "collidesWith", - showPropertyRule: { "collisionless": "false" }, - }, - { - label: "Dynamic Entities", - type: "bool", - propertyID: "collidesWithDynamic", - propertyName: "dynamic", // actual subProperty name - subPropertyOf: "collidesWith", - showPropertyRule: { "collisionless": "false" }, - }, - { - label: "My Avatar", - type: "bool", - propertyID: "collidesWithMyAvatar", - propertyName: "myAvatar", // actual subProperty name - subPropertyOf: "collidesWith", - showPropertyRule: { "collisionless": "false" }, - }, - { - label: "Other Avatars", - type: "bool", - propertyID: "collidesWithOtherAvatar", - propertyName: "otherAvatar", // actual subProperty name - subPropertyOf: "collidesWith", - showPropertyRule: { "collisionless": "false" }, - }, - { - label: "Collision Sound", - type: "string", - placeholder: "URL", - propertyID: "collisionSoundURL", - showPropertyRule: { "collisionless": "false" }, - hideIfCertified: true, - }, - { - label: "Dynamic", - type: "bool", - propertyID: "dynamic", - }, - ] - }, - { - id: "physics", - label: "PHYSICS", - properties: [ - { - label: "Linear Velocity", - type: "vec3", - vec3Type: "xyz", - step: 0.01, - decimals: 4, - subLabels: [ "x", "y", "z" ], - unit: "m/s", - propertyID: "localVelocity", - }, - { - label: "Linear Damping", - type: "number-draggable", - min: 0, - max: 1, - step: 0.001, - decimals: 4, - propertyID: "damping", - }, - { - label: "Angular Velocity", - type: "vec3", - vec3Type: "pyr", - multiplier: DEGREES_TO_RADIANS, - decimals: 4, - subLabels: [ "x", "y", "z" ], - unit: "deg/s", - propertyID: "localAngularVelocity", - }, - { - label: "Angular Damping", - type: "number-draggable", - min: 0, - max: 1, - step: 0.001, - decimals: 4, - propertyID: "angularDamping", - }, - { - label: "Bounciness", - type: "number-draggable", - step: 0.001, - decimals: 4, - propertyID: "restitution", - }, - { - label: "Friction", - type: "number-draggable", - step: 0.01, - decimals: 4, - propertyID: "friction", - }, - { - label: "Density", - type: "number-draggable", - step: 1, - decimals: 4, - propertyID: "density", - }, - { - label: "Gravity", - type: "vec3", - vec3Type: "xyz", - subLabels: [ "x", "y", "z" ], - step: 0.1, - decimals: 4, - unit: "m/s2", - propertyID: "gravity", - }, - { - label: "Acceleration", - type: "vec3", - vec3Type: "xyz", - subLabels: [ "x", "y", "z" ], - step: 0.1, - decimals: 4, - unit: "m/s2", - propertyID: "acceleration", - }, - ] - }, -]; - -const GROUPS_PER_TYPE = { - None: [ 'base', 'spatial', 'behavior', 'collision', 'physics' ], - Shape: [ 'base', 'shape', 'spatial', 'behavior', 'collision', 'physics' ], - Text: [ 'base', 'text', 'spatial', 'behavior', 'collision', 'physics' ], - Zone: [ 'base', 'zone', 'spatial', 'behavior', 'physics' ], - Model: [ 'base', 'model', 'spatial', 'behavior', 'collision', 'physics' ], - Image: [ 'base', 'image', 'spatial', 'behavior', 'collision', 'physics' ], - Web: [ 'base', 'web', 'spatial', 'behavior', 'collision', 'physics' ], - Light: [ 'base', 'light', 'spatial', 'behavior', 'collision', 'physics' ], - Material: [ 'base', 'material', 'spatial', 'behavior' ], - ParticleEffect: [ 'base', 'particles', 'particles_emit', 'particles_size', 'particles_color', 'particles_alpha', - 'particles_acceleration', 'particles_spin', 'particles_constraints', 'spatial', 'behavior', 'physics' ], - PolyLine: [ 'base', 'spatial', 'behavior', 'collision', 'physics' ], - PolyVox: [ 'base', 'spatial', 'behavior', 'collision', 'physics' ], - Grid: [ 'base', 'grid', 'spatial', 'behavior', 'physics' ], - Multiple: [ 'base', 'spatial', 'behavior', 'collision', 'physics' ], -}; - -const EDITOR_TIMEOUT_DURATION = 1500; -const DEBOUNCE_TIMEOUT = 125; - -const COLOR_MIN = 0; -const COLOR_MAX = 255; -const COLOR_STEP = 1; - -const MATERIAL_PREFIX_STRING = "mat::"; - -const PENDING_SCRIPT_STATUS = "[ Fetching status ]"; -const NOT_RUNNING_SCRIPT_STATUS = "Not running"; -const ENTITY_SCRIPT_STATUS = { - pending: "Pending", - loading: "Loading", - error_loading_script: "Error loading script", // eslint-disable-line camelcase - error_running_script: "Error running script", // eslint-disable-line camelcase - running: "Running", - unloaded: "Unloaded" -}; - -const ENABLE_DISABLE_SELECTOR = "input, textarea, span, .dropdown dl, .color-picker"; - -const PROPERTY_NAME_DIVISION = { - GROUP: 0, - PROPERTY: 1, - SUB_PROPERTY: 2, -}; - -const RECT_ELEMENTS = { - X_NUMBER: 0, - Y_NUMBER: 1, - WIDTH_NUMBER: 2, - HEIGHT_NUMBER: 3, -}; - -const VECTOR_ELEMENTS = { - X_NUMBER: 0, - Y_NUMBER: 1, - Z_NUMBER: 2, -}; - -const COLOR_ELEMENTS = { - COLOR_PICKER: 0, - RED_NUMBER: 1, - GREEN_NUMBER: 2, - BLUE_NUMBER: 3, -}; - -const TEXTURE_ELEMENTS = { - IMAGE: 0, - TEXT_INPUT: 1, -}; - -const JSON_EDITOR_ROW_DIV_INDEX = 2; - -let elGroups = {}; -let properties = {}; -let propertyRangeRequests = []; -let colorPickers = {}; -let particlePropertyUpdates = {}; -let selectedEntityIDs = new Set(); -let currentSelections = []; -let createAppTooltip = new CreateAppTooltip(); -let currentSpaceMode = PROPERTY_SPACE_MODE.LOCAL; - - -function createElementFromHTML(htmlString) { - let elTemplate = document.createElement('template'); - elTemplate.innerHTML = htmlString.trim(); - return elTemplate.content.firstChild; -} - -function isFlagSet(value, flag) { - return (value & flag) === flag; -} - -/** - * GENERAL PROPERTY/GROUP FUNCTIONS - */ - -function getPropertyInputElement(propertyID) { - let property = properties[propertyID]; - switch (property.data.type) { - case 'string': - case 'number': - case 'bool': - case 'dropdown': - case 'textarea': - case 'texture': - return property.elInput; - case 'number-draggable': - return property.elNumber.elInput; - case 'rect': - return { - x: property.elNumberX.elInput, - y: property.elNumberY.elInput, - width: property.elNumberWidth.elInput, - height: property.elNumberHeight.elInput - }; - case 'vec3': - case 'vec2': - return { x: property.elNumberX.elInput, y: property.elNumberY.elInput, z: property.elNumberZ.elInput }; - case 'color': - return { red: property.elNumberR.elInput, green: property.elNumberG.elInput, blue: property.elNumberB.elInput }; - case 'icon': - return property.elLabel; - case 'dynamic-multiselect': - return property.elDivOptions; - default: - return undefined; - } -} - -function enableChildren(el, selector) { - let elSelectors = el.querySelectorAll(selector); - for (let selectorIndex = 0; selectorIndex < elSelectors.length; ++selectorIndex) { - elSelectors[selectorIndex].removeAttribute('disabled'); - } -} - -function disableChildren(el, selector) { - let elSelectors = el.querySelectorAll(selector); - for (let selectorIndex = 0; selectorIndex < elSelectors.length; ++selectorIndex) { - elSelectors[selectorIndex].setAttribute('disabled', 'disabled'); - } -} - -function enableProperties() { - enableChildren(document.getElementById("properties-list"), ENABLE_DISABLE_SELECTOR); - enableChildren(document, ".colpick"); - - let elLocked = getPropertyInputElement("locked"); - if (elLocked.checked === false) { - removeStaticUserData(); - removeStaticMaterialData(); - } -} - -function disableProperties() { - disableChildren(document.getElementById("properties-list"), ENABLE_DISABLE_SELECTOR); - disableChildren(document, ".colpick"); - for (let pickKey in colorPickers) { - colorPickers[pickKey].colpickHide(); - } - - let elLocked = getPropertyInputElement("locked"); - if (elLocked.checked === true) { - if ($('#property-userData-editor').css('display') === "block") { - showStaticUserData(); - } - if ($('#property-materialData-editor').css('display') === "block") { - showStaticMaterialData(); - } - } -} - -function showPropertyElement(propertyID, show) { - setPropertyVisibility(properties[propertyID], show); -} - -function setPropertyVisibility(property, visible) { - property.elContainer.style.display = visible ? null : "none"; -} - -function resetProperties() { - for (let propertyID in properties) { - let property = properties[propertyID]; - let propertyData = property.data; - - switch (propertyData.type) { - case 'number': - case 'string': { - property.elInput.classList.remove('multi-diff'); - if (propertyData.defaultValue !== undefined) { - property.elInput.value = propertyData.defaultValue; - } else { - property.elInput.value = ""; - } - break; - } - case 'bool': { - property.elInput.classList.remove('multi-diff'); - property.elInput.checked = false; - break; - } - case 'number-draggable': { - if (propertyData.defaultValue !== undefined) { - property.elNumber.setValue(propertyData.defaultValue, false); - } else { - property.elNumber.setValue("", false); - } - break; - } - case 'rect': { - property.elNumberX.setValue("", false); - property.elNumberY.setValue("", false); - property.elNumberWidth.setValue("", false); - property.elNumberHeight.setValue("", false); - break; - } - case 'vec3': - case 'vec2': { - property.elNumberX.setValue("", false); - property.elNumberY.setValue("", false); - if (property.elNumberZ !== undefined) { - property.elNumberZ.setValue("", false); - } - break; - } - case 'color': { - property.elColorPicker.style.backgroundColor = "rgb(" + 0 + "," + 0 + "," + 0 + ")"; - property.elNumberR.setValue("", false); - property.elNumberG.setValue("", false); - property.elNumberB.setValue("", false); - break; - } - case 'dropdown': { - property.elInput.classList.remove('multi-diff'); - property.elInput.value = ""; - setDropdownText(property.elInput); - break; - } - case 'textarea': { - property.elInput.classList.remove('multi-diff'); - property.elInput.value = ""; - setTextareaScrolling(property.elInput); - break; - } - case 'icon': { - property.elSpan.style.display = "none"; - break; - } - case 'texture': { - property.elInput.classList.remove('multi-diff'); - property.elInput.value = ""; - property.elInput.imageLoad(property.elInput.value); - break; - } - case 'dynamic-multiselect': { - resetDynamicMultiselectProperty(property.elDivOptions); - break; - } - } - - let showPropertyRules = properties[propertyID].showPropertyRules; - if (showPropertyRules !== undefined) { - for (let propertyToHide in showPropertyRules) { - showPropertyElement(propertyToHide, false); - } - } - } - - resetServerScriptStatus(); -} - -function resetServerScriptStatus() { - let elServerScriptError = document.getElementById("property-serverScripts-error"); - let elServerScriptStatus = document.getElementById("property-serverScripts-status"); - elServerScriptError.parentElement.style.display = "none"; - elServerScriptStatus.innerText = NOT_RUNNING_SCRIPT_STATUS; -} - -function showGroupsForType(type) { - if (type === "Box" || type === "Sphere") { - showGroupsForTypes(["Shape"]); - return; - } - showGroupsForTypes([type]); -} - -function getGroupsForTypes(types) { - return Object.keys(elGroups).filter((groupKey) => { - return types.map(type => GROUPS_PER_TYPE[type].includes(groupKey)).every(function (hasGroup) { - return hasGroup; - }); - }); -} - -function showGroupsForTypes(types) { - Object.entries(elGroups).forEach(([groupKey, elGroup]) => { - if (types.map(type => GROUPS_PER_TYPE[type].includes(groupKey)).every(function (hasGroup) { return hasGroup; })) { - elGroup.style.display = "block"; - } else { - elGroup.style.display = "none"; - } - }); -} - -function getFirstSelectedID() { - if (selectedEntityIDs.size === 0) { - return null; - } - return selectedEntityIDs.values().next().value; -} - -/** - * Returns true when the user is currently dragging the numeric slider control of the property - * @param propertyName - name of property - * @returns {boolean} currentlyDragging - */ -function isCurrentlyDraggingProperty(propertyName) { - return properties[propertyName] && properties[propertyName].dragging === true; -} - -const SUPPORTED_FALLBACK_TYPES = ['number', 'number-draggable', 'rect', 'vec3', 'vec2', 'color']; - -function getMultiplePropertyValue(originalPropertyName) { - // if this is a compound property name (i.e. animation.running) - // then split it by . up to 3 times to find property value - - let propertyData = null; - if (properties[originalPropertyName] !== undefined) { - propertyData = properties[originalPropertyName].data; - } - - let propertyValues = []; - let splitPropertyName = originalPropertyName.split('.'); - if (splitPropertyName.length > 1) { - let propertyGroupName = splitPropertyName[PROPERTY_NAME_DIVISION.GROUP]; - let propertyName = splitPropertyName[PROPERTY_NAME_DIVISION.PROPERTY]; - propertyValues = currentSelections.map(selection => { - let groupProperties = selection.properties[propertyGroupName]; - if (groupProperties === undefined || groupProperties[propertyName] === undefined) { - return undefined; - } - if (splitPropertyName.length === PROPERTY_NAME_DIVISION.SUB_PROPERTY + 1) { - let subPropertyName = splitPropertyName[PROPERTY_NAME_DIVISION.SUB_PROPERTY]; - return groupProperties[propertyName][subPropertyName]; - } else { - return groupProperties[propertyName]; - } - }); - } else { - propertyValues = currentSelections.map(selection => selection.properties[originalPropertyName]); - } - - if (propertyData !== null && propertyData.fallbackProperty !== undefined && - SUPPORTED_FALLBACK_TYPES.includes(propertyData.type)) { - - let fallbackMultiValue = null; - - for (let i = 0; i < propertyValues.length; ++i) { - let isPropertyNotNumber = false; - let propertyValue = propertyValues[i]; - if (propertyValue === undefined) { - continue; - } - switch (propertyData.type) { - case 'number': - case 'number-draggable': - isPropertyNotNumber = isNaN(propertyValue) || propertyValue === null; - break; - case 'rect': - case 'vec3': - case 'vec2': - isPropertyNotNumber = isNaN(propertyValue.x) || propertyValue.x === null; - break; - case 'color': - isPropertyNotNumber = isNaN(propertyValue.red) || propertyValue.red === null; - break; - } - if (isPropertyNotNumber) { - if (fallbackMultiValue === null) { - fallbackMultiValue = getMultiplePropertyValue(propertyData.fallbackProperty); - } - propertyValues[i] = fallbackMultiValue.values[i]; - } - } - } - - const firstValue = propertyValues[0]; - const isMultiDiffValue = !propertyValues.every((x) => deepEqual(firstValue, x)); - - if (isMultiDiffValue) { - return { - value: undefined, - values: propertyValues, - isMultiDiffValue: true - } - } - - return { - value: propertyValues[0], - values: propertyValues, - isMultiDiffValue: false - }; -} - -/** - * Retrieve more detailed info for differing Numeric MultiplePropertyValue - * @param multiplePropertyValue - input multiplePropertyValue - * @param propertyData - * @returns {{keys: *[], propertyComponentDiff, averagePerPropertyComponent}} - */ -function getDetailedNumberMPVDiff(multiplePropertyValue, propertyData) { - let detailedValues = {}; - // Fixed numbers can't be easily averaged since they're strings, so lets keep an array of unmodified numbers - let unmodifiedValues = {}; - const DEFAULT_KEY = 0; - let uniqueKeys = new Set([]); - multiplePropertyValue.values.forEach(function(propertyValue) { - if (typeof propertyValue === "object") { - Object.entries(propertyValue).forEach(function([key, value]) { - if (!uniqueKeys.has(key)) { - uniqueKeys.add(key); - detailedValues[key] = []; - unmodifiedValues[key] = []; - } - detailedValues[key].push(applyInputNumberPropertyModifiers(value, propertyData)); - unmodifiedValues[key].push(value); - }); - } else { - if (!uniqueKeys.has(DEFAULT_KEY)) { - uniqueKeys.add(DEFAULT_KEY); - detailedValues[DEFAULT_KEY] = []; - unmodifiedValues[DEFAULT_KEY] = []; - } - detailedValues[DEFAULT_KEY].push(applyInputNumberPropertyModifiers(propertyValue, propertyData)); - unmodifiedValues[DEFAULT_KEY].push(propertyValue); - } - }); - let keys = [...uniqueKeys]; - - let propertyComponentDiff = {}; - Object.entries(detailedValues).forEach(function([key, value]) { - propertyComponentDiff[key] = [...new Set(value)].length > 1; - }); - - let averagePerPropertyComponent = {}; - Object.entries(unmodifiedValues).forEach(function([key, value]) { - let average = value.reduce((a, b) => a + b) / value.length; - averagePerPropertyComponent[key] = applyInputNumberPropertyModifiers(average, propertyData); - }); - - return { - keys, - propertyComponentDiff, - averagePerPropertyComponent, - }; -} - -function getDetailedSubPropertyMPVDiff(multiplePropertyValue, subPropertyName) { - let isChecked = false; - let checkedValues = multiplePropertyValue.values.map((value) => value.split(",").includes(subPropertyName)); - let isMultiDiff = !checkedValues.every(value => value === checkedValues[0]); - if (!isMultiDiff) { - isChecked = checkedValues[0]; - } - return { - isChecked, - isMultiDiff - } -} - -function updateVisibleSpaceModeProperties() { - for (let propertyID in properties) { - if (properties.hasOwnProperty(propertyID)) { - let property = properties[propertyID]; - let propertySpaceMode = property.spaceMode; - let elProperty = properties[propertyID].elContainer; - if (propertySpaceMode !== PROPERTY_SPACE_MODE.ALL && propertySpaceMode !== currentSpaceMode) { - elProperty.classList.add('spacemode-hidden'); - } else { - elProperty.classList.remove('spacemode-hidden'); - } - } - } -} - -/** - * PROPERTY UPDATE FUNCTIONS - */ - -function createPropertyUpdateObject(originalPropertyName, propertyValue) { - let propertyUpdate = {}; - // if this is a compound property name (i.e. animation.running) then split it by . up to 3 times - let splitPropertyName = originalPropertyName.split('.'); - if (splitPropertyName.length > 1) { - let propertyGroupName = splitPropertyName[PROPERTY_NAME_DIVISION.GROUP]; - let propertyName = splitPropertyName[PROPERTY_NAME_DIVISION.PROPERTY]; - propertyUpdate[propertyGroupName] = {}; - if (splitPropertyName.length === PROPERTY_NAME_DIVISION.SUB_PROPERTY + 1) { - let subPropertyName = splitPropertyName[PROPERTY_NAME_DIVISION.SUB_PROPERTY]; - propertyUpdate[propertyGroupName][propertyName] = {}; - propertyUpdate[propertyGroupName][propertyName][subPropertyName] = propertyValue; - } else { - propertyUpdate[propertyGroupName][propertyName] = propertyValue; - } - } else { - propertyUpdate[originalPropertyName] = propertyValue; - } - return propertyUpdate; -} - -function updateProperty(originalPropertyName, propertyValue, isParticleProperty) { - let propertyUpdate = createPropertyUpdateObject(originalPropertyName, propertyValue); - - // queue up particle property changes with the debounced sync to avoid - // causing particle emitting to reset excessively with each value change - if (isParticleProperty) { - Object.keys(propertyUpdate).forEach(function (propertyUpdateKey) { - particlePropertyUpdates[propertyUpdateKey] = propertyUpdate[propertyUpdateKey]; - }); - particleSyncDebounce(); - } else { - // only update the entity property value itself if in the middle of dragging - // prevent undo command push, saving new property values, and property update - // callback until drag is complete (additional update sent via dragEnd callback) - let onlyUpdateEntity = isCurrentlyDraggingProperty(originalPropertyName); - updateProperties(propertyUpdate, onlyUpdateEntity); - } -} - -let particleSyncDebounce = _.debounce(function () { - updateProperties(particlePropertyUpdates); - particlePropertyUpdates = {}; -}, DEBOUNCE_TIMEOUT); - -function updateProperties(propertiesToUpdate, onlyUpdateEntity) { - if (onlyUpdateEntity === undefined) { - onlyUpdateEntity = false; - } - EventBridge.emitWebEvent(JSON.stringify({ - ids: [...selectedEntityIDs], - type: "update", - properties: propertiesToUpdate, - onlyUpdateEntities: onlyUpdateEntity - })); -} - -function updateMultiDiffProperties(propertiesMapToUpdate, onlyUpdateEntity) { - if (onlyUpdateEntity === undefined) { - onlyUpdateEntity = false; - } - EventBridge.emitWebEvent(JSON.stringify({ - type: "update", - propertiesMap: propertiesMapToUpdate, - onlyUpdateEntities: onlyUpdateEntity - })); -} - -function createEmitTextPropertyUpdateFunction(property) { - return function() { - property.elInput.classList.remove('multi-diff'); - updateProperty(property.name, this.value, property.isParticleProperty); - }; -} - -function createEmitCheckedPropertyUpdateFunction(property) { - return function() { - updateProperty(property.name, property.data.inverse ? !this.checked : this.checked, property.isParticleProperty); - }; -} - -function createDragStartFunction(property) { - return function() { - property.dragging = true; - }; -} - -function createDragEndFunction(property) { - return function() { - property.dragging = false; - - if (this.multiDiffModeEnabled) { - let propertyMultiValue = getMultiplePropertyValue(property.name); - let updateObjects = []; - const selectedEntityIDsArray = [...selectedEntityIDs]; - - for (let i = 0; i < selectedEntityIDsArray.length; ++i) { - let entityID = selectedEntityIDsArray[i]; - updateObjects.push({ - entityIDs: [entityID], - properties: createPropertyUpdateObject(property.name, propertyMultiValue.values[i]), - }); - } - - // send a full updateMultiDiff post-dragging to count as an action in the undo stack - updateMultiDiffProperties(updateObjects); - } else { - // send an additional update post-dragging to consider whole property change from dragStart to dragEnd to be 1 action - this.valueChangeFunction(); - } - }; -} - -function createEmitNumberPropertyUpdateFunction(property) { - return function() { - let value = parseFloat(applyOutputNumberPropertyModifiers(parseFloat(this.value), property.data)); - updateProperty(property.name, value, property.isParticleProperty); - }; -} - -function createEmitNumberPropertyComponentUpdateFunction(property, propertyComponent) { - return function() { - let propertyMultiValue = getMultiplePropertyValue(property.name); - let value = parseFloat(applyOutputNumberPropertyModifiers(parseFloat(this.value), property.data)); - - if (propertyMultiValue.isMultiDiffValue) { - let updateObjects = []; - const selectedEntityIDsArray = [...selectedEntityIDs]; - - for (let i = 0; i < selectedEntityIDsArray.length; ++i) { - let entityID = selectedEntityIDsArray[i]; - - let propertyObject = propertyMultiValue.values[i]; - propertyObject[propertyComponent] = value; - - let updateObject = createPropertyUpdateObject(property.name, propertyObject); - updateObjects.push({ - entityIDs: [entityID], - properties: updateObject, - }); - - mergeDeep(currentSelections[i].properties, updateObject); - } - - // only update the entity property value itself if in the middle of dragging - // prevent undo command push, saving new property values, and property update - // callback until drag is complete (additional update sent via dragEnd callback) - let onlyUpdateEntity = isCurrentlyDraggingProperty(property.name); - updateMultiDiffProperties(updateObjects, onlyUpdateEntity); - } else { - let propertyValue = propertyMultiValue.value; - propertyValue[propertyComponent] = value; - updateProperty(property.name, propertyValue, property.isParticleProperty); - } - }; -} - -function createEmitColorPropertyUpdateFunction(property) { - return function() { - emitColorPropertyUpdate(property.name, property.elNumberR.elInput.value, property.elNumberG.elInput.value, - property.elNumberB.elInput.value, property.isParticleProperty); - }; -} - -function emitColorPropertyUpdate(propertyName, red, green, blue, isParticleProperty) { - let newValue = { - red: red, - green: green, - blue: blue - }; - updateProperty(propertyName, newValue, isParticleProperty); -} - -function toggleBooleanCSV(inputCSV, property, enable) { - let values = inputCSV.split(","); - if (enable && !values.includes(property)) { - values.push(property); - } else if (!enable && values.includes(property)) { - values = values.filter(value => value !== property); - } - return values.join(","); -} - -function updateCheckedSubProperty(propertyName, propertyMultiValue, subPropertyElement, subPropertyString, isParticleProperty) { - if (propertyMultiValue.isMultiDiffValue) { - let updateObjects = []; - const selectedEntityIDsArray = [...selectedEntityIDs]; - - for (let i = 0; i < selectedEntityIDsArray.length; ++i) { - let newValue = toggleBooleanCSV(propertyMultiValue.values[i], subPropertyString, subPropertyElement.checked); - updateObjects.push({ - entityIDs: [selectedEntityIDsArray[i]], - properties: createPropertyUpdateObject(propertyName, newValue), - }); - } - - updateMultiDiffProperties(updateObjects); - } else { - updateProperty(propertyName, toggleBooleanCSV(propertyMultiValue.value, subPropertyString, subPropertyElement.checked), - isParticleProperty); - } -} - -/** - * PROPERTY ELEMENT CREATION FUNCTIONS - */ - -function createStringProperty(property, elProperty) { - let elementID = property.elementID; - let propertyData = property.data; - - elProperty.className = "text"; - - let elInput = createElementFromHTML(` - - `); - - - elInput.addEventListener('change', createEmitTextPropertyUpdateFunction(property)); - if (propertyData.onChange !== undefined) { - elInput.addEventListener('change', propertyData.onChange); - } - - - let elMultiDiff = document.createElement('span'); - elMultiDiff.className = "multi-diff"; - - elProperty.appendChild(elInput); - elProperty.appendChild(elMultiDiff); - - if (propertyData.buttons !== undefined) { - addButtons(elProperty, elementID, propertyData.buttons, false); - } - - return elInput; -} - -function createBoolProperty(property, elProperty) { - let propertyName = property.name; - let elementID = property.elementID; - let propertyData = property.data; - - elProperty.className = "checkbox"; - - if (propertyData.glyph !== undefined) { - let elSpan = document.createElement('span'); - elSpan.innerHTML = propertyData.glyph; - elSpan.className = 'icon'; - elProperty.appendChild(elSpan); - } - - let elInput = document.createElement('input'); - elInput.setAttribute("id", elementID); - elInput.setAttribute("type", "checkbox"); - - elProperty.appendChild(elInput); - elProperty.appendChild(createElementFromHTML(``)); - - let subPropertyOf = propertyData.subPropertyOf; - if (subPropertyOf !== undefined) { - elInput.addEventListener('change', function() { - let subPropertyMultiValue = getMultiplePropertyValue(subPropertyOf); - - updateCheckedSubProperty(subPropertyOf, - subPropertyMultiValue, - elInput, propertyName, property.isParticleProperty); - }); - } else { - elInput.addEventListener('change', createEmitCheckedPropertyUpdateFunction(property)); - } - - return elInput; -} - -function createNumberProperty(property, elProperty) { - let elementID = property.elementID; - let propertyData = property.data; - - elProperty.className = "text"; - - let elInput = createElementFromHTML(` - - `); - - if (propertyData.min !== undefined) { - elInput.setAttribute("min", propertyData.min); - } - if (propertyData.max !== undefined) { - elInput.setAttribute("max", propertyData.max); - } - if (propertyData.step !== undefined) { - elInput.setAttribute("step", propertyData.step); - } - if (propertyData.defaultValue !== undefined) { - elInput.value = propertyData.defaultValue; - } - - elInput.addEventListener('change', createEmitNumberPropertyUpdateFunction(property)); - - let elMultiDiff = document.createElement('span'); - elMultiDiff.className = "multi-diff"; - - elProperty.appendChild(elInput); - elProperty.appendChild(elMultiDiff); - - if (propertyData.buttons !== undefined) { - addButtons(elProperty, elementID, propertyData.buttons, false); - } - - return elInput; -} - -function updateNumberMinMax(property) { - let elInput = property.elInput; - let min = property.data.min; - let max = property.data.max; - if (min !== undefined) { - elInput.setAttribute("min", min); - } - if (max !== undefined) { - elInput.setAttribute("max", max); - } -} - -/** - * - * @param {object} property - property update on step - * @param {string} [propertyComponent] - propertyComponent to update on step (e.g. enter 'x' to just update position.x) - * @returns {Function} - */ -function createMultiDiffStepFunction(property, propertyComponent) { - return function(step, shouldAddToUndoHistory) { - if (shouldAddToUndoHistory === undefined) { - shouldAddToUndoHistory = false; - } - - let propertyMultiValue = getMultiplePropertyValue(property.name); - if (!propertyMultiValue.isMultiDiffValue) { - console.log("setMultiDiffStepFunction is only supposed to be called in MultiDiff mode."); - return; - } - - let multiplier = property.data.multiplier !== undefined ? property.data.multiplier : 1; - - let applyDelta = step * multiplier; - - if (selectedEntityIDs.size !== propertyMultiValue.values.length) { - console.log("selectedEntityIDs and propertyMultiValue got out of sync."); - return; - } - let updateObjects = []; - const selectedEntityIDsArray = [...selectedEntityIDs]; - - for (let i = 0; i < selectedEntityIDsArray.length; ++i) { - let entityID = selectedEntityIDsArray[i]; - - let updatedValue; - if (propertyComponent !== undefined) { - let objectToUpdate = propertyMultiValue.values[i]; - objectToUpdate[propertyComponent] += applyDelta; - updatedValue = objectToUpdate; - } else { - updatedValue = propertyMultiValue.values[i] + applyDelta; - } - let propertiesUpdate = createPropertyUpdateObject(property.name, updatedValue); - updateObjects.push({ - entityIDs: [entityID], - properties: propertiesUpdate - }); - // We need to store these so that we can send a full update on the dragEnd - mergeDeep(currentSelections[i].properties, propertiesUpdate); - } - - updateMultiDiffProperties(updateObjects, !shouldAddToUndoHistory); - } -} - -function createNumberDraggableProperty(property, elProperty) { - let elementID = property.elementID; - let propertyData = property.data; - - elProperty.className += " draggable-number-container"; - - let dragStartFunction = createDragStartFunction(property); - let dragEndFunction = createDragEndFunction(property); - let elDraggableNumber = new DraggableNumber(propertyData.min, propertyData.max, propertyData.step, - propertyData.decimals, dragStartFunction, dragEndFunction); - - let defaultValue = propertyData.defaultValue; - if (defaultValue !== undefined) { - elDraggableNumber.elInput.value = defaultValue; - } - - let valueChangeFunction = createEmitNumberPropertyUpdateFunction(property); - elDraggableNumber.setValueChangeFunction(valueChangeFunction); - - elDraggableNumber.setMultiDiffStepFunction(createMultiDiffStepFunction(property)); - - elDraggableNumber.elInput.setAttribute("id", elementID); - elProperty.appendChild(elDraggableNumber.elDiv); - - if (propertyData.buttons !== undefined) { - addButtons(elDraggableNumber.elDiv, elementID, propertyData.buttons, false); - } - - return elDraggableNumber; -} - -function updateNumberDraggableMinMax(property) { - let propertyData = property.data; - property.elNumber.updateMinMax(propertyData.min, propertyData.max); -} - -function createRectProperty(property, elProperty) { - let propertyData = property.data; - - elProperty.className = "rect"; - - let elXYRow = document.createElement('div'); - elXYRow.className = "rect-row fstuple"; - elProperty.appendChild(elXYRow); - - let elWidthHeightRow = document.createElement('div'); - elWidthHeightRow.className = "rect-row fstuple"; - elProperty.appendChild(elWidthHeightRow); - - - let elNumberX = createTupleNumberInput(property, propertyData.subLabels[RECT_ELEMENTS.X_NUMBER]); - let elNumberY = createTupleNumberInput(property, propertyData.subLabels[RECT_ELEMENTS.Y_NUMBER]); - let elNumberWidth = createTupleNumberInput(property, propertyData.subLabels[RECT_ELEMENTS.WIDTH_NUMBER]); - let elNumberHeight = createTupleNumberInput(property, propertyData.subLabels[RECT_ELEMENTS.HEIGHT_NUMBER]); - - elXYRow.appendChild(elNumberX.elDiv); - elXYRow.appendChild(elNumberY.elDiv); - elWidthHeightRow.appendChild(elNumberWidth.elDiv); - elWidthHeightRow.appendChild(elNumberHeight.elDiv); - - elNumberX.setValueChangeFunction(createEmitNumberPropertyComponentUpdateFunction(property, 'x')); - elNumberY.setValueChangeFunction(createEmitNumberPropertyComponentUpdateFunction(property, 'y')); - elNumberWidth.setValueChangeFunction(createEmitNumberPropertyComponentUpdateFunction(property, 'width')); - elNumberHeight.setValueChangeFunction(createEmitNumberPropertyComponentUpdateFunction(property, 'height')); - - elNumberX.setMultiDiffStepFunction(createMultiDiffStepFunction(property, 'x')); - elNumberY.setMultiDiffStepFunction(createMultiDiffStepFunction(property, 'y')); - elNumberX.setMultiDiffStepFunction(createMultiDiffStepFunction(property, 'width')); - elNumberY.setMultiDiffStepFunction(createMultiDiffStepFunction(property, 'height')); - - let elResult = []; - elResult[RECT_ELEMENTS.X_NUMBER] = elNumberX; - elResult[RECT_ELEMENTS.Y_NUMBER] = elNumberY; - elResult[RECT_ELEMENTS.WIDTH_NUMBER] = elNumberWidth; - elResult[RECT_ELEMENTS.HEIGHT_NUMBER] = elNumberHeight; - return elResult; -} - -function updateRectMinMax(property) { - let min = property.data.min; - let max = property.data.max; - property.elNumberX.updateMinMax(min, max); - property.elNumberY.updateMinMax(min, max); - property.elNumberWidth.updateMinMax(min, max); - property.elNumberHeight.updateMinMax(min, max); -} - -function createVec3Property(property, elProperty) { - let propertyData = property.data; - - elProperty.className = propertyData.vec3Type + " fstuple"; - - let elNumberX = createTupleNumberInput(property, propertyData.subLabels[VECTOR_ELEMENTS.X_NUMBER]); - let elNumberY = createTupleNumberInput(property, propertyData.subLabels[VECTOR_ELEMENTS.Y_NUMBER]); - let elNumberZ = createTupleNumberInput(property, propertyData.subLabels[VECTOR_ELEMENTS.Z_NUMBER]); - elProperty.appendChild(elNumberX.elDiv); - elProperty.appendChild(elNumberY.elDiv); - elProperty.appendChild(elNumberZ.elDiv); - - elNumberX.setValueChangeFunction(createEmitNumberPropertyComponentUpdateFunction(property, 'x')); - elNumberY.setValueChangeFunction(createEmitNumberPropertyComponentUpdateFunction(property, 'y')); - elNumberZ.setValueChangeFunction(createEmitNumberPropertyComponentUpdateFunction(property, 'z')); - - elNumberX.setMultiDiffStepFunction(createMultiDiffStepFunction(property, 'x')); - elNumberY.setMultiDiffStepFunction(createMultiDiffStepFunction(property, 'y')); - elNumberZ.setMultiDiffStepFunction(createMultiDiffStepFunction(property, 'z')); - - let elResult = []; - elResult[VECTOR_ELEMENTS.X_NUMBER] = elNumberX; - elResult[VECTOR_ELEMENTS.Y_NUMBER] = elNumberY; - elResult[VECTOR_ELEMENTS.Z_NUMBER] = elNumberZ; - return elResult; -} - -function createVec2Property(property, elProperty) { - let propertyData = property.data; - - elProperty.className = propertyData.vec2Type + " fstuple"; - - let elTuple = document.createElement('div'); - elTuple.className = "tuple"; - - elProperty.appendChild(elTuple); - - let elNumberX = createTupleNumberInput(property, propertyData.subLabels[VECTOR_ELEMENTS.X_NUMBER]); - let elNumberY = createTupleNumberInput(property, propertyData.subLabels[VECTOR_ELEMENTS.Y_NUMBER]); - elProperty.appendChild(elNumberX.elDiv); - elProperty.appendChild(elNumberY.elDiv); - - elNumberX.setValueChangeFunction(createEmitNumberPropertyComponentUpdateFunction(property, 'x')); - elNumberY.setValueChangeFunction(createEmitNumberPropertyComponentUpdateFunction(property, 'y')); - - elNumberX.setMultiDiffStepFunction(createMultiDiffStepFunction(property, 'x')); - elNumberY.setMultiDiffStepFunction(createMultiDiffStepFunction(property, 'y')); - - let elResult = []; - elResult[VECTOR_ELEMENTS.X_NUMBER] = elNumberX; - elResult[VECTOR_ELEMENTS.Y_NUMBER] = elNumberY; - return elResult; -} - -function updateVectorMinMax(property) { - let min = property.data.min; - let max = property.data.max; - property.elNumberX.updateMinMax(min, max); - property.elNumberY.updateMinMax(min, max); - if (property.elNumberZ) { - property.elNumberZ.updateMinMax(min, max); - } -} - -function createColorProperty(property, elProperty) { - let propertyName = property.name; - let elementID = property.elementID; - let propertyData = property.data; - - elProperty.className += " rgb fstuple"; - - let elColorPicker = document.createElement('div'); - elColorPicker.className = "color-picker"; - elColorPicker.setAttribute("id", elementID); - - let elTuple = document.createElement('div'); - elTuple.className = "tuple"; - - elProperty.appendChild(elColorPicker); - elProperty.appendChild(elTuple); - - if (propertyData.min === undefined) { - propertyData.min = COLOR_MIN; - } - if (propertyData.max === undefined) { - propertyData.max = COLOR_MAX; - } - if (propertyData.step === undefined) { - propertyData.step = COLOR_STEP; - } - - let elNumberR = createTupleNumberInput(property, "red"); - let elNumberG = createTupleNumberInput(property, "green"); - let elNumberB = createTupleNumberInput(property, "blue"); - elTuple.appendChild(elNumberR.elDiv); - elTuple.appendChild(elNumberG.elDiv); - elTuple.appendChild(elNumberB.elDiv); - - let valueChangeFunction = createEmitColorPropertyUpdateFunction(property); - elNumberR.setValueChangeFunction(valueChangeFunction); - elNumberG.setValueChangeFunction(valueChangeFunction); - elNumberB.setValueChangeFunction(valueChangeFunction); - - let colorPickerID = "#" + elementID; - colorPickers[colorPickerID] = $(colorPickerID).colpick({ - colorScheme: 'dark', - layout: 'rgbhex', - color: '000000', - submit: false, // We don't want to have a submission button - onShow: function(colpick) { - // The original color preview within the picker needs to be updated on show because - // prior to the picker being shown we don't have access to the selections' starting color. - colorPickers[colorPickerID].colpickSetColor({ - "r": elNumberR.elInput.value, - "g": elNumberG.elInput.value, - "b": elNumberB.elInput.value - }); - - // Set the color picker active after setting the color, otherwise an update will be sent on open. - $(colorPickerID).attr('active', 'true'); - }, - onHide: function(colpick) { - $(colorPickerID).attr('active', 'false'); - }, - onChange: function(hsb, hex, rgb, el) { - $(el).css('background-color', '#' + hex); - if ($(colorPickerID).attr('active') === 'true') { - emitColorPropertyUpdate(propertyName, rgb.r, rgb.g, rgb.b); - } - } - }); - - let elResult = []; - elResult[COLOR_ELEMENTS.COLOR_PICKER] = elColorPicker; - elResult[COLOR_ELEMENTS.RED_NUMBER] = elNumberR; - elResult[COLOR_ELEMENTS.GREEN_NUMBER] = elNumberG; - elResult[COLOR_ELEMENTS.BLUE_NUMBER] = elNumberB; - return elResult; -} - -function createDropdownProperty(property, propertyID, elProperty) { - let elementID = property.elementID; - let propertyData = property.data; - - elProperty.className = "dropdown"; - - let elInput = document.createElement('select'); - elInput.setAttribute("id", elementID); - elInput.setAttribute("propertyID", propertyID); - - for (let optionKey in propertyData.options) { - let option = document.createElement('option'); - option.value = optionKey; - option.text = propertyData.options[optionKey]; - elInput.add(option); - } - - elInput.addEventListener('change', createEmitTextPropertyUpdateFunction(property)); - - elProperty.appendChild(elInput); - - return elInput; -} - -function createTextareaProperty(property, elProperty) { - let elementID = property.elementID; - let propertyData = property.data; - - elProperty.className = "textarea"; - - let elInput = document.createElement('textarea'); - elInput.setAttribute("id", elementID); - if (propertyData.readOnly) { - elInput.readOnly = true; - } - - elInput.addEventListener('change', createEmitTextPropertyUpdateFunction(property)); - - let elMultiDiff = document.createElement('span'); - elMultiDiff.className = "multi-diff"; - - elProperty.appendChild(elInput); - elProperty.appendChild(elMultiDiff); - - if (propertyData.buttons !== undefined) { - addButtons(elProperty, elementID, propertyData.buttons, true); - } - - return elInput; -} - -function createIconProperty(property, elProperty) { - let elementID = property.elementID; - - elProperty.className = "value"; - - let elSpan = document.createElement('span'); - elSpan.setAttribute("id", elementID + "-icon"); - elSpan.className = 'icon'; - - elProperty.appendChild(elSpan); - - return elSpan; -} - -function createTextureProperty(property, elProperty) { - let elementID = property.elementID; - - elProperty.className = "texture"; - - let elDiv = document.createElement("div"); - let elImage = document.createElement("img"); - elDiv.className = "texture-image no-texture"; - elDiv.appendChild(elImage); - - let elInput = document.createElement('input'); - elInput.setAttribute("id", elementID); - elInput.setAttribute("type", "text"); - - let imageLoad = function(url) { - elDiv.style.display = null; - if (url.slice(0, 5).toLowerCase() === "atp:/") { - elImage.src = ""; - elImage.style.display = "none"; - elDiv.classList.remove("with-texture"); - elDiv.classList.remove("no-texture"); - elDiv.classList.add("no-preview"); - } else if (url.length > 0) { - elDiv.classList.remove("no-texture"); - elDiv.classList.remove("no-preview"); - elDiv.classList.add("with-texture"); - elImage.src = url; - elImage.style.display = "block"; - } else { - elImage.src = ""; - elImage.style.display = "none"; - elDiv.classList.remove("with-texture"); - elDiv.classList.remove("no-preview"); - elDiv.classList.add("no-texture"); - } - }; - elInput.imageLoad = imageLoad; - elInput.setMultipleValues = function() { - elDiv.style.display = "none"; - }; - elInput.addEventListener('change', createEmitTextPropertyUpdateFunction(property)); - elInput.addEventListener('change', function(ev) { - imageLoad(ev.target.value); - }); - - elProperty.appendChild(elInput); - let elMultiDiff = document.createElement('span'); - elMultiDiff.className = "multi-diff"; - elProperty.appendChild(elMultiDiff); - elProperty.appendChild(elDiv); - - let elResult = []; - elResult[TEXTURE_ELEMENTS.IMAGE] = elImage; - elResult[TEXTURE_ELEMENTS.TEXT_INPUT] = elInput; - return elResult; -} - -function createButtonsProperty(property, elProperty) { - let elementID = property.elementID; - let propertyData = property.data; - - elProperty.className = "text"; - - if (propertyData.buttons !== undefined) { - addButtons(elProperty, elementID, propertyData.buttons, false); - } - - return elProperty; -} - -function createDynamicMultiselectProperty(property, elProperty) { - let elementID = property.elementID; - let propertyData = property.data; - - elProperty.className = "dynamic-multiselect"; - - let elDivOptions = document.createElement('div'); - elDivOptions.setAttribute("id", elementID + "-options"); - elDivOptions.style = "overflow-y:scroll;max-height:160px;"; - - let elDivButtons = document.createElement('div'); - elDivButtons.setAttribute("id", elDivOptions.getAttribute("id") + "-buttons"); - - let elLabel = document.createElement('label'); - elLabel.innerText = "No Options"; - elDivOptions.appendChild(elLabel); - - let buttons = [ { id: "selectAll", label: "Select All", className: "black", onClick: selectAllMaterialTarget }, - { id: "clearAll", label: "Clear All", className: "black", onClick: clearAllMaterialTarget } ]; - addButtons(elDivButtons, elementID, buttons, false); - - elProperty.appendChild(elDivOptions); - elProperty.appendChild(elDivButtons); - - return elDivOptions; -} - -function resetDynamicMultiselectProperty(elDivOptions) { - let elInputs = elDivOptions.getElementsByTagName("input"); - while (elInputs.length > 0) { - let elDivOption = elInputs[0].parentNode; - elDivOption.parentNode.removeChild(elDivOption); - } - elDivOptions.firstChild.style.display = null; // show "No Options" text - elDivOptions.parentNode.lastChild.style.display = "none"; // hide Select/Clear all buttons -} - -function createTupleNumberInput(property, subLabel) { - let propertyElementID = property.elementID; - let propertyData = property.data; - let elementID = propertyElementID + "-" + subLabel.toLowerCase(); - - let elLabel = document.createElement('label'); - elLabel.className = "sublabel " + subLabel; - elLabel.innerText = subLabel[0].toUpperCase() + subLabel.slice(1); - elLabel.setAttribute("for", elementID); - elLabel.style.visibility = "visible"; - - let dragStartFunction = createDragStartFunction(property); - let dragEndFunction = createDragEndFunction(property); - let elDraggableNumber = new DraggableNumber(propertyData.min, propertyData.max, propertyData.step, - propertyData.decimals, dragStartFunction, dragEndFunction); - elDraggableNumber.elInput.setAttribute("id", elementID); - elDraggableNumber.elDiv.className += " fstuple"; - elDraggableNumber.elDiv.insertBefore(elLabel, elDraggableNumber.elLeftArrow); - - return elDraggableNumber; -} - -function addButtons(elProperty, propertyID, buttons, newRow) { - let elDiv = document.createElement('div'); - elDiv.className = "row"; - - buttons.forEach(function(button) { - let elButton = document.createElement('input'); - elButton.className = button.className; - elButton.setAttribute("type", "button"); - elButton.setAttribute("id", propertyID + "-button-" + button.id); - elButton.setAttribute("value", button.label); - elButton.addEventListener("click", button.onClick); - if (newRow) { - elDiv.appendChild(elButton); - } else { - elProperty.appendChild(elButton); - } - }); - - if (newRow) { - elProperty.appendChild(document.createElement('br')); - elProperty.appendChild(elDiv); - } -} - -function createProperty(propertyData, propertyElementID, propertyName, propertyID, elProperty) { - let property = { - data: propertyData, - elementID: propertyElementID, - name: propertyName, - elProperty: elProperty, - }; - let propertyType = propertyData.type; - - switch (propertyType) { - case 'string': { - property.elInput = createStringProperty(property, elProperty); - break; - } - case 'bool': { - property.elInput = createBoolProperty(property, elProperty); - break; - } - case 'number': { - property.elInput = createNumberProperty(property, elProperty); - break; - } - case 'number-draggable': { - property.elNumber = createNumberDraggableProperty(property, elProperty); - break; - } - case 'rect': { - let elRect = createRectProperty(property, elProperty); - property.elNumberX = elRect[RECT_ELEMENTS.X_NUMBER]; - property.elNumberY = elRect[RECT_ELEMENTS.Y_NUMBER]; - property.elNumberWidth = elRect[RECT_ELEMENTS.WIDTH_NUMBER]; - property.elNumberHeight = elRect[RECT_ELEMENTS.HEIGHT_NUMBER]; - break; - } - case 'vec3': { - let elVec3 = createVec3Property(property, elProperty); - property.elNumberX = elVec3[VECTOR_ELEMENTS.X_NUMBER]; - property.elNumberY = elVec3[VECTOR_ELEMENTS.Y_NUMBER]; - property.elNumberZ = elVec3[VECTOR_ELEMENTS.Z_NUMBER]; - break; - } - case 'vec2': { - let elVec2 = createVec2Property(property, elProperty); - property.elNumberX = elVec2[VECTOR_ELEMENTS.X_NUMBER]; - property.elNumberY = elVec2[VECTOR_ELEMENTS.Y_NUMBER]; - break; - } - case 'color': { - let elColor = createColorProperty(property, elProperty); - property.elColorPicker = elColor[COLOR_ELEMENTS.COLOR_PICKER]; - property.elNumberR = elColor[COLOR_ELEMENTS.RED_NUMBER]; - property.elNumberG = elColor[COLOR_ELEMENTS.GREEN_NUMBER]; - property.elNumberB = elColor[COLOR_ELEMENTS.BLUE_NUMBER]; - break; - } - case 'dropdown': { - property.elInput = createDropdownProperty(property, propertyID, elProperty); - break; - } - case 'textarea': { - property.elInput = createTextareaProperty(property, elProperty); - break; - } - case 'icon': { - property.elSpan = createIconProperty(property, elProperty); - break; - } - case 'texture': { - let elTexture = createTextureProperty(property, elProperty); - property.elImage = elTexture[TEXTURE_ELEMENTS.IMAGE]; - property.elInput = elTexture[TEXTURE_ELEMENTS.TEXT_INPUT]; - break; - } - case 'buttons': { - property.elProperty = createButtonsProperty(property, elProperty); - break; - } - case 'dynamic-multiselect': { - property.elDivOptions = createDynamicMultiselectProperty(property, elProperty); - break; - } - case 'placeholder': - case 'sub-header': { - break; - } - default: { - console.log("EntityProperties - Unknown property type " + - propertyType + " set to property " + propertyID); - break; - } - } - - return property; -} - - -/** - * PROPERTY-SPECIFIC CALLBACKS - */ - -function parentIDChanged() { - if (currentSelections.length === 1 && currentSelections[0].properties.type === "Material") { - requestMaterialTarget(); - } -} - - -/** - * BUTTON CALLBACKS - */ - -function rescaleDimensions() { - EventBridge.emitWebEvent(JSON.stringify({ - type: "action", - action: "rescaleDimensions", - percentage: parseFloat(document.getElementById("property-scale").value) - })); -} - -function moveSelectionToGrid() { - EventBridge.emitWebEvent(JSON.stringify({ - type: "action", - action: "moveSelectionToGrid" - })); -} - -function moveAllToGrid() { - EventBridge.emitWebEvent(JSON.stringify({ - type: "action", - action: "moveAllToGrid" - })); -} - -function resetToNaturalDimensions() { - EventBridge.emitWebEvent(JSON.stringify({ - type: "action", - action: "resetToNaturalDimensions" - })); -} - -function reloadScripts() { - EventBridge.emitWebEvent(JSON.stringify({ - type: "action", - action: "reloadClientScripts" - })); -} - -function reloadServerScripts() { - // invalidate the current status (so that same-same updates can still be observed visually) - document.getElementById("property-serverScripts-status").innerText = PENDING_SCRIPT_STATUS; - EventBridge.emitWebEvent(JSON.stringify({ - type: "action", - action: "reloadServerScripts" - })); -} - -function copySkyboxURLToAmbientURL() { - let skyboxURL = getPropertyInputElement("skybox.url").value; - getPropertyInputElement("ambientLight.ambientURL").value = skyboxURL; - updateProperty("ambientLight.ambientURL", skyboxURL, false); -} - - -/** - * USER DATA FUNCTIONS - */ - -function clearUserData() { - let elUserData = getPropertyInputElement("userData"); - deleteJSONEditor(); - elUserData.value = ""; - showUserDataTextArea(); - showNewJSONEditorButton(); - hideSaveUserDataButton(); - updateProperty('userData', elUserData.value, false); -} - -function newJSONEditor() { - getPropertyInputElement("userData").classList.remove('multi-diff'); - deleteJSONEditor(); - createJSONEditor(); - let data = {}; - setEditorJSON(data); - hideUserDataTextArea(); - hideNewJSONEditorButton(); - showSaveUserDataButton(); -} - -/** - * @param {Set.} [entityIDsToUpdate] Entity IDs to update userData for. - */ -function saveUserData(entityIDsToUpdate) { - saveJSONUserData(true, entityIDsToUpdate); -} - -function setJSONError(property, isError) { - $("#property-"+ property + "-editor").toggleClass('error', isError); - let $propertyUserDataEditorStatus = $("#property-"+ property + "-editorStatus"); - $propertyUserDataEditorStatus.css('display', isError ? 'block' : 'none'); - $propertyUserDataEditorStatus.text(isError ? 'Invalid JSON code - look for red X in your code' : ''); -} - -/** - * @param {boolean} noUpdate - don't update the UI, but do send a property update. - * @param {Set.} [entityIDsToUpdate] - Entity IDs to update userData for. - */ -function setUserDataFromEditor(noUpdate, entityIDsToUpdate) { - let errorFound = false; - try { - editor.get(); - } catch (e) { - errorFound = true; - } - - setJSONError('userData', errorFound); - - if (errorFound) { - return; - } - - let text = editor.getText(); - if (noUpdate) { - EventBridge.emitWebEvent( - JSON.stringify({ - ids: [...entityIDsToUpdate], - type: "saveUserData", - properties: { - userData: text - } - }) - ); - } else { - updateProperty('userData', text, false); - } -} - -let editor = null; - -function createJSONEditor() { - let container = document.getElementById("property-userData-editor"); - let options = { - search: false, - mode: 'tree', - modes: ['code', 'tree'], - name: 'userData', - onError: function(e) { - alert('JSON editor:' + e); - }, - onChange: function() { - let currentJSONString = editor.getText(); - - if (currentJSONString === '{"":""}') { - return; - } - $('#property-userData-button-save').attr('disabled', false); - } - }; - editor = new JSONEditor(container, options); -} - -function showSaveUserDataButton() { - $('#property-userData-button-save').show(); -} - -function hideSaveUserDataButton() { - $('#property-userData-button-save').hide(); -} - -function disableSaveUserDataButton() { - $('#property-userData-button-save').attr('disabled', true); -} - -function showNewJSONEditorButton() { - $('#property-userData-button-edit').show(); -} - -function hideNewJSONEditorButton() { - $('#property-userData-button-edit').hide(); -} - -function showUserDataTextArea() { - $('#property-userData').show(); -} - -function hideUserDataTextArea() { - $('#property-userData').hide(); -} - -function hideUserDataSaved() { - $('#property-userData-saved').hide(); -} - -function showStaticUserData() { - if (editor !== null) { - let $propertyUserDataStatic = $('#property-userData-static'); - $propertyUserDataStatic.show(); - $propertyUserDataStatic.css('height', $('#property-userData-editor').height()); - $propertyUserDataStatic.text(editor.getText()); - } -} - -function removeStaticUserData() { - $('#property-userData-static').hide(); -} - -function setEditorJSON(json) { - editor.set(json); - if (editor.hasOwnProperty('expandAll')) { - editor.expandAll(); - } -} - -function deleteJSONEditor() { - if (editor !== null) { - setJSONError('userData', false); - editor.destroy(); - editor = null; - } -} - -let savedJSONTimer = null; - -/** - * @param {boolean} noUpdate - don't update the UI, but do send a property update. - * @param {Set.} [entityIDsToUpdate] Entity IDs to update userData for - */ -function saveJSONUserData(noUpdate, entityIDsToUpdate) { - setUserDataFromEditor(noUpdate, entityIDsToUpdate ? entityIDsToUpdate : selectedEntityIDs); - $('#property-userData-saved').show(); - $('#property-userData-button-save').attr('disabled', true); - if (savedJSONTimer !== null) { - clearTimeout(savedJSONTimer); - } - savedJSONTimer = setTimeout(function() { - hideUserDataSaved(); - }, EDITOR_TIMEOUT_DURATION); -} - - -/** - * MATERIAL DATA FUNCTIONS - */ - -function clearMaterialData() { - let elMaterialData = getPropertyInputElement("materialData"); - deleteJSONMaterialEditor(); - elMaterialData.value = ""; - showMaterialDataTextArea(); - showNewJSONMaterialEditorButton(); - hideSaveMaterialDataButton(); - updateProperty('materialData', elMaterialData.value, false); -} - -function newJSONMaterialEditor() { - getPropertyInputElement("materialData").classList.remove('multi-diff'); - deleteJSONMaterialEditor(); - createJSONMaterialEditor(); - let data = {}; - setMaterialEditorJSON(data); - hideMaterialDataTextArea(); - hideNewJSONMaterialEditorButton(); - showSaveMaterialDataButton(); -} - -function saveMaterialData() { - saveJSONMaterialData(true); -} - -/** - * @param {boolean} noUpdate - don't update the UI, but do send a property update. - * @param {Set.} [entityIDsToUpdate] - Entity IDs to update materialData for. - */ -function setMaterialDataFromEditor(noUpdate, entityIDsToUpdate) { - let errorFound = false; - try { - materialEditor.get(); - } catch (e) { - errorFound = true; - } - - setJSONError('materialData', errorFound); - - if (errorFound) { - return; - } - let text = materialEditor.getText(); - if (noUpdate) { - EventBridge.emitWebEvent( - JSON.stringify({ - ids: [...entityIDsToUpdate], - type: "saveMaterialData", - properties: { - materialData: text - } - }) - ); - } else { - updateProperty('materialData', text, false); - } -} - -let materialEditor = null; - -function createJSONMaterialEditor() { - let container = document.getElementById("property-materialData-editor"); - let options = { - search: false, - mode: 'tree', - modes: ['code', 'tree'], - name: 'materialData', - onError: function(e) { - alert('JSON editor:' + e); - }, - onChange: function() { - let currentJSONString = materialEditor.getText(); - - if (currentJSONString === '{"":""}') { - return; - } - $('#property-materialData-button-save').attr('disabled', false); - } - }; - materialEditor = new JSONEditor(container, options); -} - -function showSaveMaterialDataButton() { - $('#property-materialData-button-save').show(); -} - -function hideSaveMaterialDataButton() { - $('#property-materialData-button-save').hide(); -} - -function disableSaveMaterialDataButton() { - $('#property-materialData-button-save').attr('disabled', true); -} - -function showNewJSONMaterialEditorButton() { - $('#property-materialData-button-edit').show(); -} - -function hideNewJSONMaterialEditorButton() { - $('#property-materialData-button-edit').hide(); -} - -function showMaterialDataTextArea() { - $('#property-materialData').show(); -} - -function hideMaterialDataTextArea() { - $('#property-materialData').hide(); -} - -function hideMaterialDataSaved() { - $('#property-materialData-saved').hide(); -} - -function showStaticMaterialData() { - if (materialEditor !== null) { - let $propertyMaterialDataStatic = $('#property-materialData-static'); - $propertyMaterialDataStatic.show(); - $propertyMaterialDataStatic.css('height', $('#property-materialData-editor').height()); - $propertyMaterialDataStatic.text(materialEditor.getText()); - } -} - -function removeStaticMaterialData() { - $('#property-materialData-static').hide(); -} - -function setMaterialEditorJSON(json) { - materialEditor.set(json); - if (materialEditor.hasOwnProperty('expandAll')) { - materialEditor.expandAll(); - } -} - -function deleteJSONMaterialEditor() { - if (materialEditor !== null) { - setJSONError('materialData', false); - materialEditor.destroy(); - materialEditor = null; - } -} - -let savedMaterialJSONTimer = null; - -/** - * @param {boolean} noUpdate - don't update the UI, but do send a property update. - * @param {Set.} [entityIDsToUpdate] - Entity IDs to update materialData for. - */ -function saveJSONMaterialData(noUpdate, entityIDsToUpdate) { - setMaterialDataFromEditor(noUpdate, entityIDsToUpdate ? entityIDsToUpdate : selectedEntityIDs); - $('#property-materialData-saved').show(); - $('#property-materialData-button-save').attr('disabled', true); - if (savedMaterialJSONTimer !== null) { - clearTimeout(savedMaterialJSONTimer); - } - savedMaterialJSONTimer = setTimeout(function() { - hideMaterialDataSaved(); - }, EDITOR_TIMEOUT_DURATION); -} - -function bindAllNonJSONEditorElements() { - let inputs = $('input'); - let i; - for (i = 0; i < inputs.length; ++i) { - let input = inputs[i]; - let field = $(input); - // TODO FIXME: (JSHint) Functions declared within loops referencing - // an outer scoped variable may lead to confusing semantics. - field.on('focus', function(e) { - if (e.target.id === "property-userData-button-edit" || e.target.id === "property-userData-button-clear" || - e.target.id === "property-materialData-button-edit" || e.target.id === "property-materialData-button-clear") { - return; - } - if ($('#property-userData-editor').css('height') !== "0px") { - saveUserData(); - } - if ($('#property-materialData-editor').css('height') !== "0px") { - saveMaterialData(); - } - }); - } -} - - -/** - * DROPDOWN FUNCTIONS - */ - -function setDropdownText(dropdown) { - let lis = dropdown.parentNode.getElementsByTagName("li"); - let text = ""; - for (let i = 0; i < lis.length; ++i) { - if (String(lis[i].getAttribute("value")) === String(dropdown.value)) { - text = lis[i].textContent; - } - } - dropdown.firstChild.textContent = text; -} - -function toggleDropdown(event) { - let element = event.target; - if (element.nodeName !== "DT") { - element = element.parentNode; - } - element = element.parentNode; - let isDropped = element.getAttribute("dropped"); - element.setAttribute("dropped", isDropped !== "true" ? "true" : "false"); -} - -function closeAllDropdowns() { - let elDropdowns = document.querySelectorAll("div.dropdown > dl"); - for (let i = 0; i < elDropdowns.length; ++i) { - elDropdowns[i].setAttribute('dropped', 'false'); - } -} - -function setDropdownValue(event) { - let dt = event.target.parentNode.parentNode.previousSibling.previousSibling; - dt.value = event.target.getAttribute("value"); - dt.firstChild.textContent = event.target.textContent; - - dt.parentNode.setAttribute("dropped", "false"); - - let evt = document.createEvent("HTMLEvents"); - evt.initEvent("change", true, true); - dt.dispatchEvent(evt); -} - - -/** - * TEXTAREA FUNCTIONS - */ - -function setTextareaScrolling(element) { - let isScrolling = element.scrollHeight > element.offsetHeight; - element.setAttribute("scrolling", isScrolling ? "true" : "false"); -} - - -/** - * MATERIAL TARGET FUNCTIONS - */ - -function requestMaterialTarget() { - EventBridge.emitWebEvent(JSON.stringify({ - type: 'materialTargetRequest', - entityID: getFirstSelectedID(), - })); -} - -function setMaterialTargetData(materialTargetData) { - let elDivOptions = getPropertyInputElement("parentMaterialName"); - resetDynamicMultiselectProperty(elDivOptions); - - if (materialTargetData === undefined) { - return; - } - - elDivOptions.firstChild.style.display = "none"; // hide "No Options" text - elDivOptions.parentNode.lastChild.style.display = null; // show Select/Clear all buttons - - let numMeshes = materialTargetData.numMeshes; - for (let i = 0; i < numMeshes; ++i) { - addMaterialTarget(elDivOptions, i, false); - } - - let materialNames = materialTargetData.materialNames; - let materialNamesAdded = []; - for (let i = 0; i < materialNames.length; ++i) { - let materialName = materialNames[i]; - if (materialNamesAdded.indexOf(materialName) === -1) { - addMaterialTarget(elDivOptions, materialName, true); - materialNamesAdded.push(materialName); - } - } - - materialTargetPropertyUpdate(elDivOptions.propertyValue); -} - -function addMaterialTarget(elDivOptions, targetID, isMaterialName) { - let elementID = elDivOptions.getAttribute("id"); - elementID += isMaterialName ? "-material-" : "-mesh-"; - elementID += targetID; - - let elDiv = document.createElement('div'); - elDiv.className = "materialTargetDiv"; - elDiv.onclick = onToggleMaterialTarget; - elDivOptions.appendChild(elDiv); - - let elInput = document.createElement('input'); - elInput.className = "materialTargetInput"; - elInput.setAttribute("type", "checkbox"); - elInput.setAttribute("id", elementID); - elInput.setAttribute("targetID", targetID); - elInput.setAttribute("isMaterialName", isMaterialName); - elDiv.appendChild(elInput); - - let elLabel = document.createElement('label'); - elLabel.setAttribute("for", elementID); - elLabel.innerText = isMaterialName ? "Material " + targetID : "Mesh Index " + targetID; - elDiv.appendChild(elLabel); - - return elDiv; -} - -function onToggleMaterialTarget(event) { - let elTarget = event.target; - if (elTarget instanceof HTMLInputElement) { - sendMaterialTargetProperty(); - } - event.stopPropagation(); -} - -function setAllMaterialTargetInputs(checked) { - let elDivOptions = getPropertyInputElement("parentMaterialName"); - let elInputs = elDivOptions.getElementsByClassName("materialTargetInput"); - for (let i = 0; i < elInputs.length; ++i) { - elInputs[i].checked = checked; - } -} - -function selectAllMaterialTarget() { - setAllMaterialTargetInputs(true); - sendMaterialTargetProperty(); -} - -function clearAllMaterialTarget() { - setAllMaterialTargetInputs(false); - sendMaterialTargetProperty(); -} - -function sendMaterialTargetProperty() { - let elDivOptions = getPropertyInputElement("parentMaterialName"); - let elInputs = elDivOptions.getElementsByClassName("materialTargetInput"); - - let materialTargetList = []; - for (let i = 0; i < elInputs.length; ++i) { - let elInput = elInputs[i]; - if (elInput.checked) { - let targetID = elInput.getAttribute("targetID"); - if (elInput.getAttribute("isMaterialName") === "true") { - materialTargetList.push(MATERIAL_PREFIX_STRING + targetID); - } else { - materialTargetList.push(targetID); - } - } - } - - let propertyValue = materialTargetList.join(","); - if (propertyValue.length > 1) { - propertyValue = "[" + propertyValue + "]"; - } - - updateProperty("parentMaterialName", propertyValue, false); -} - -function materialTargetPropertyUpdate(propertyValue) { - let elDivOptions = getPropertyInputElement("parentMaterialName"); - let elInputs = elDivOptions.getElementsByClassName("materialTargetInput"); - - if (propertyValue.startsWith('[')) { - propertyValue = propertyValue.substring(1, propertyValue.length); - } - if (propertyValue.endsWith(']')) { - propertyValue = propertyValue.substring(0, propertyValue.length - 1); - } - - let materialTargets = propertyValue.split(","); - for (let i = 0; i < elInputs.length; ++i) { - let elInput = elInputs[i]; - let targetID = elInput.getAttribute("targetID"); - let materialTargetName = targetID; - if (elInput.getAttribute("isMaterialName") === "true") { - materialTargetName = MATERIAL_PREFIX_STRING + targetID; - } - elInput.checked = materialTargets.indexOf(materialTargetName) >= 0; - } - - elDivOptions.propertyValue = propertyValue; -} - -function roundAndFixNumber(number, propertyData) { - let result = number; - if (propertyData.round !== undefined) { - result = Math.round(result * propertyData.round) / propertyData.round; - } - if (propertyData.decimals !== undefined) { - return result.toFixed(propertyData.decimals) - } - return result; -} - -function applyInputNumberPropertyModifiers(number, propertyData) { - const multiplier = propertyData.multiplier !== undefined ? propertyData.multiplier : 1; - return roundAndFixNumber(number / multiplier, propertyData); -} - -function applyOutputNumberPropertyModifiers(number, propertyData) { - const multiplier = propertyData.multiplier !== undefined ? propertyData.multiplier : 1; - return roundAndFixNumber(number * multiplier, propertyData); -} - -const areSetsEqual = (a, b) => a.size === b.size && [...a].every(value => b.has(value)); - - -function handleEntitySelectionUpdate(selections, isPropertiesToolUpdate) { - const previouslySelectedEntityIDs = selectedEntityIDs; - currentSelections = selections; - selectedEntityIDs = new Set(selections.map(selection => selection.id)); - const multipleSelections = currentSelections.length > 1; - const hasSelectedEntityChanged = !areSetsEqual(selectedEntityIDs, previouslySelectedEntityIDs); - - if (selections.length === 0) { - deleteJSONEditor(); - deleteJSONMaterialEditor(); - - resetProperties(); - showGroupsForType("None"); - - let elIcon = properties.type.elSpan; - elIcon.innerText = NO_SELECTION; - elIcon.style.display = 'inline-block'; - - getPropertyInputElement("userData").value = ""; - showUserDataTextArea(); - showSaveUserDataButton(); - showNewJSONEditorButton(); - - getPropertyInputElement("materialData").value = ""; - showMaterialDataTextArea(); - showSaveMaterialDataButton(); - showNewJSONMaterialEditorButton(); - - disableProperties(); - } else { - if (!isPropertiesToolUpdate && !hasSelectedEntityChanged && document.hasFocus()) { - // in case the selection has not changed and we still have focus on the properties page, - // we will ignore the event. - return; - } - - if (hasSelectedEntityChanged) { - if (!multipleSelections) { - resetServerScriptStatus(); - } - } - - const doSelectElement = !hasSelectedEntityChanged; - - // Get unique entity types, and convert the types Sphere and Box to Shape - const shapeTypes = ["Sphere", "Box"]; - const entityTypes = [...new Set(currentSelections.map(a => - shapeTypes.includes(a.properties.type) ? "Shape" : a.properties.type))]; - - const shownGroups = getGroupsForTypes(entityTypes); - showGroupsForTypes(entityTypes); - - const lockedMultiValue = getMultiplePropertyValue('locked'); - - if (lockedMultiValue.isMultiDiffValue || lockedMultiValue.value) { - disableProperties(); - getPropertyInputElement('locked').removeAttribute('disabled'); - } else { - enableProperties(); - disableSaveUserDataButton(); - disableSaveMaterialDataButton() - } - - const certificateIDMultiValue = getMultiplePropertyValue('certificateID'); - const hasCertifiedInSelection = certificateIDMultiValue.isMultiDiffValue || certificateIDMultiValue.value !== ""; - - Object.entries(properties).forEach(function([propertyID, property]) { - const propertyData = property.data; - const propertyName = property.name; - let propertyMultiValue = getMultiplePropertyValue(propertyName); - let isMultiDiffValue = propertyMultiValue.isMultiDiffValue; - let propertyValue = propertyMultiValue.value; - - if (propertyData.selectionVisibility !== undefined) { - let visibility = propertyData.selectionVisibility; - let propertyVisible = true; - if (!multipleSelections) { - propertyVisible = isFlagSet(visibility, PROPERTY_SELECTION_VISIBILITY.SINGLE_SELECTION); - } else if (isMultiDiffValue) { - propertyVisible = isFlagSet(visibility, PROPERTY_SELECTION_VISIBILITY.MULTI_DIFF_SELECTIONS); - } else { - propertyVisible = isFlagSet(visibility, PROPERTY_SELECTION_VISIBILITY.MULTIPLE_SELECTIONS); - } - setPropertyVisibility(property, propertyVisible); - } - - const isSubProperty = propertyData.subPropertyOf !== undefined; - if (propertyValue === undefined && !isMultiDiffValue && !isSubProperty) { - return; - } - - if (!shownGroups.includes(property.group_id)) { - const WANT_DEBUG_SHOW_HIDDEN_FROM_GROUPS = false; - if (WANT_DEBUG_SHOW_HIDDEN_FROM_GROUPS) { - console.log("Skipping property " + property.data.label + " [" + property.name + - "] from hidden group " + property.group_id); - } - return; - } - - if (propertyData.hideIfCertified && hasCertifiedInSelection) { - propertyValue = "** Certified **"; - property.elInput.disabled = true; - } - - if (propertyName === "type") { - propertyValue = entityTypes.length > 1 ? "Multiple" : propertyMultiValue.values[0]; - } - - switch (propertyData.type) { - case 'string': { - if (isMultiDiffValue) { - if (propertyData.readOnly && propertyData.multiDisplayMode - && propertyData.multiDisplayMode === PROPERTY_MULTI_DISPLAY_MODE.COMMA_SEPARATED_VALUES) { - property.elInput.value = propertyMultiValue.values.join(", "); - } else { - property.elInput.classList.add('multi-diff'); - property.elInput.value = ""; - } - } else { - property.elInput.classList.remove('multi-diff'); - property.elInput.value = propertyValue; - } - break; - } - case 'bool': { - const inverse = propertyData.inverse !== undefined ? propertyData.inverse : false; - if (isSubProperty) { - let subPropertyMultiValue = getMultiplePropertyValue(propertyData.subPropertyOf); - let propertyValue = subPropertyMultiValue.value; - isMultiDiffValue = subPropertyMultiValue.isMultiDiffValue; - if (isMultiDiffValue) { - let detailedSubProperty = getDetailedSubPropertyMPVDiff(subPropertyMultiValue, propertyName); - property.elInput.checked = detailedSubProperty.isChecked; - property.elInput.classList.toggle('multi-diff', detailedSubProperty.isMultiDiff); - } else { - let subProperties = propertyValue.split(","); - let subPropertyValue = subProperties.indexOf(propertyName) > -1; - property.elInput.checked = inverse ? !subPropertyValue : subPropertyValue; - property.elInput.classList.remove('multi-diff'); - } - - } else { - if (isMultiDiffValue) { - property.elInput.checked = false; - } else { - property.elInput.checked = inverse ? !propertyValue : propertyValue; - } - property.elInput.classList.toggle('multi-diff', isMultiDiffValue); - } - - break; - } - case 'number': { - property.elInput.value = isMultiDiffValue ? "" : propertyValue; - property.elInput.classList.toggle('multi-diff', isMultiDiffValue); - break; - } - case 'number-draggable': { - let detailedNumberDiff = getDetailedNumberMPVDiff(propertyMultiValue, propertyData); - property.elNumber.setValue(detailedNumberDiff.averagePerPropertyComponent[0], detailedNumberDiff.propertyComponentDiff[0]); - break; - } - case 'rect': { - let detailedNumberDiff = getDetailedNumberMPVDiff(propertyMultiValue, propertyData); - property.elNumberX.setValue(detailedNumberDiff.averagePerPropertyComponent.x, detailedNumberDiff.propertyComponentDiff.x); - property.elNumberY.setValue(detailedNumberDiff.averagePerPropertyComponent.y, detailedNumberDiff.propertyComponentDiff.y); - property.elNumberWidth.setValue(detailedNumberDiff.averagePerPropertyComponent.width, detailedNumberDiff.propertyComponentDiff.width); - property.elNumberHeight.setValue(detailedNumberDiff.averagePerPropertyComponent.height, detailedNumberDiff.propertyComponentDiff.height); - break; - } - case 'vec3': - case 'vec2': { - let detailedNumberDiff = getDetailedNumberMPVDiff(propertyMultiValue, propertyData); - property.elNumberX.setValue(detailedNumberDiff.averagePerPropertyComponent.x, detailedNumberDiff.propertyComponentDiff.x); - property.elNumberY.setValue(detailedNumberDiff.averagePerPropertyComponent.y, detailedNumberDiff.propertyComponentDiff.y); - if (property.elNumberZ !== undefined) { - property.elNumberZ.setValue(detailedNumberDiff.averagePerPropertyComponent.z, detailedNumberDiff.propertyComponentDiff.z); - } - break; - } - case 'color': { - let displayColor = propertyMultiValue.isMultiDiffValue ? propertyMultiValue.values[0] : propertyValue; - property.elColorPicker.style.backgroundColor = "rgb(" + displayColor.red + "," + - displayColor.green + "," + - displayColor.blue + ")"; - property.elColorPicker.classList.toggle('multi-diff', propertyMultiValue.isMultiDiffValue); - - if (hasSelectedEntityChanged && $(property.elColorPicker).attr('active') === 'true') { - // Set the color picker inactive before setting the color, - // otherwise an update will be sent directly after setting it here. - $(property.elColorPicker).attr('active', 'false'); - colorPickers['#' + property.elementID].colpickSetColor({ - "r": displayColor.red, - "g": displayColor.green, - "b": displayColor.blue - }); - $(property.elColorPicker).attr('active', 'true'); - } - - property.elNumberR.setValue(displayColor.red); - property.elNumberG.setValue(displayColor.green); - property.elNumberB.setValue(displayColor.blue); - break; - } - case 'dropdown': { - property.elInput.classList.toggle('multi-diff', isMultiDiffValue); - property.elInput.value = isMultiDiffValue ? "" : propertyValue; - setDropdownText(property.elInput); - break; - } - case 'textarea': { - property.elInput.value = propertyValue; - setTextareaScrolling(property.elInput); - break; - } - case 'icon': { - property.elSpan.innerHTML = propertyData.icons[propertyValue]; - property.elSpan.style.display = "inline-block"; - break; - } - case 'texture': { - property.elInput.value = isMultiDiffValue ? "" : propertyValue; - property.elInput.classList.toggle('multi-diff', isMultiDiffValue); - if (isMultiDiffValue) { - property.elInput.setMultipleValues(); - } else { - property.elInput.imageLoad(property.elInput.value); - } - break; - } - case 'dynamic-multiselect': { - if (!isMultiDiffValue && property.data.propertyUpdate) { - property.data.propertyUpdate(propertyValue); - } - break; - } - } - - let showPropertyRules = property.showPropertyRules; - if (showPropertyRules !== undefined) { - for (let propertyToShow in showPropertyRules) { - let showIfThisPropertyValue = showPropertyRules[propertyToShow]; - let show = String(propertyValue) === String(showIfThisPropertyValue); - showPropertyElement(propertyToShow, show); - } - } - }); - - updateVisibleSpaceModeProperties(); - - let userDataMultiValue = getMultiplePropertyValue("userData"); - let userDataTextArea = getPropertyInputElement("userData"); - let json = null; - if (!userDataMultiValue.isMultiDiffValue) { - try { - json = JSON.parse(userDataMultiValue.value); - } catch (e) { - - } - } - if (json !== null) { - if (editor === null) { - createJSONEditor(); - } - userDataTextArea.classList.remove('multi-diff'); - setEditorJSON(json); - showSaveUserDataButton(); - hideUserDataTextArea(); - hideNewJSONEditorButton(); - hideUserDataSaved(); - } else { - // normal text - deleteJSONEditor(); - userDataTextArea.classList.toggle('multi-diff', userDataMultiValue.isMultiDiffValue); - userDataTextArea.value = userDataMultiValue.isMultiDiffValue ? "" : userDataMultiValue.value; - - showUserDataTextArea(); - showNewJSONEditorButton(); - hideSaveUserDataButton(); - hideUserDataSaved(); - } - - let materialDataMultiValue = getMultiplePropertyValue("materialData"); - let materialDataTextArea = getPropertyInputElement("materialData"); - let materialJson = null; - if (!materialDataMultiValue.isMultiDiffValue) { - try { - materialJson = JSON.parse(materialDataMultiValue.value); - } catch (e) { - - } - } - if (materialJson !== null) { - if (materialEditor === null) { - createJSONMaterialEditor(); - } - materialDataTextArea.classList.remove('multi-diff'); - setMaterialEditorJSON(materialJson); - showSaveMaterialDataButton(); - hideMaterialDataTextArea(); - hideNewJSONMaterialEditorButton(); - hideMaterialDataSaved(); - } else { - // normal text - deleteJSONMaterialEditor(); - materialDataTextArea.classList.toggle('multi-diff', materialDataMultiValue.isMultiDiffValue); - materialDataTextArea.value = materialDataMultiValue.isMultiDiffValue ? "" : materialDataMultiValue.value; - showMaterialDataTextArea(); - showNewJSONMaterialEditorButton(); - hideSaveMaterialDataButton(); - hideMaterialDataSaved(); - } - - if (hasSelectedEntityChanged && selections.length === 1 && entityTypes[0] === "Material") { - requestMaterialTarget(); - } - - let activeElement = document.activeElement; - if (doSelectElement && typeof activeElement.select !== "undefined") { - activeElement.select(); - } - } -} - -function loaded() { - openEventBridge(function() { - let elPropertiesList = document.getElementById("properties-list"); - - GROUPS.forEach(function(group) { - let elGroup; - if (group.addToGroup !== undefined) { - let fieldset = document.getElementById("properties-" + group.addToGroup); - elGroup = document.createElement('div'); - fieldset.appendChild(elGroup); - } else { - elGroup = document.createElement('div'); - elGroup.className = 'section ' + (group.isMinor ? "minor" : "major"); - elGroup.setAttribute("id", "properties-" + group.id); - elPropertiesList.appendChild(elGroup); - } - - if (group.label !== undefined) { - let elLegend = document.createElement('div'); - elLegend.className = "section-header"; - - elLegend.appendChild(createElementFromHTML(`
${group.label}
`)); - - let elSpan = document.createElement('span'); - elSpan.className = "collapse-icon"; - elSpan.innerText = "M"; - elLegend.appendChild(elSpan); - elGroup.appendChild(elLegend); - } - - group.properties.forEach(function(propertyData) { - let propertyType = propertyData.type; - let propertyID = propertyData.propertyID; - let propertyName = propertyData.propertyName !== undefined ? propertyData.propertyName : propertyID; - let propertySpaceMode = propertyData.spaceMode !== undefined ? propertyData.spaceMode : PROPERTY_SPACE_MODE.ALL; - let propertyElementID = "property-" + propertyID; - propertyElementID = propertyElementID.replace('.', '-'); - - let elContainer, elLabel; - - if (propertyData.replaceID === undefined) { - // Create subheader, or create new property and append it. - if (propertyType === "sub-header") { - elContainer = createElementFromHTML( - `
${propertyData.label}
`); - } else { - elContainer = document.createElement('div'); - elContainer.setAttribute("id", "div-" + propertyElementID); - elContainer.className = 'property container'; - } - - if (group.twoColumn && propertyData.column !== undefined && propertyData.column !== -1) { - let columnName = group.id + "column" + propertyData.column; - let elColumn = document.getElementById(columnName); - if (!elColumn) { - let columnDivName = group.id + "columnDiv"; - let elColumnDiv = document.getElementById(columnDivName); - if (!elColumnDiv) { - elColumnDiv = document.createElement('div'); - elColumnDiv.className = "two-column"; - elColumnDiv.setAttribute("id", group.id + "columnDiv"); - elGroup.appendChild(elColumnDiv); - } - elColumn = document.createElement('fieldset'); - elColumn.className = "column"; - elColumn.setAttribute("id", columnName); - elColumnDiv.appendChild(elColumn); - } - elColumn.appendChild(elContainer); - } else { - elGroup.appendChild(elContainer); - } - - let labelText = propertyData.label !== undefined ? propertyData.label : ""; - let className = ''; - if (propertyData.indentedLabel || propertyData.showPropertyRule !== undefined) { - className = 'indented'; - } - elLabel = createElementFromHTML( - ``); - elContainer.appendChild(elLabel); - } else { - elContainer = document.getElementById(propertyData.replaceID); - } - - if (elLabel) { - createAppTooltip.registerTooltipElement(elLabel.childNodes[0], propertyID, propertyName); - } - - let elProperty = createElementFromHTML('
'); - elContainer.appendChild(elProperty); - - if (propertyType === 'triple') { - elProperty.className = 'flex-row'; - for (let i = 0; i < propertyData.properties.length; ++i) { - let innerPropertyData = propertyData.properties[i]; - - let elWrapper = createElementFromHTML('
'); - elProperty.appendChild(elWrapper); - - let propertyID = innerPropertyData.propertyID; - let propertyName = innerPropertyData.propertyName !== undefined ? innerPropertyData.propertyName : propertyID; - let propertyElementID = "property-" + propertyID; - propertyElementID = propertyElementID.replace('.', '-'); - - let property = createProperty(innerPropertyData, propertyElementID, propertyName, propertyID, elWrapper); - property.isParticleProperty = group.id.includes("particles"); - property.elContainer = elContainer; - property.spaceMode = propertySpaceMode; - property.group_id = group.id; - - let elLabel = createElementFromHTML(`
${innerPropertyData.label}
`); - createAppTooltip.registerTooltipElement(elLabel, propertyID, propertyName); - - elWrapper.appendChild(elLabel); - - if (property.type !== 'placeholder') { - properties[propertyID] = property; - } - if (innerPropertyData.type === 'number' || innerPropertyData.type === 'number-draggable') { - propertyRangeRequests.push(propertyID); - } - } - } else { - let property = createProperty(propertyData, propertyElementID, propertyName, propertyID, elProperty); - property.isParticleProperty = group.id.includes("particles"); - property.elContainer = elContainer; - property.spaceMode = propertySpaceMode; - property.group_id = group.id; - - if (property.type !== 'placeholder') { - properties[propertyID] = property; - } - if (propertyData.type === 'number' || propertyData.type === 'number-draggable' || - propertyData.type === 'vec2' || propertyData.type === 'vec3' || propertyData.type === 'rect') { - propertyRangeRequests.push(propertyID); - } - - let showPropertyRule = propertyData.showPropertyRule; - if (showPropertyRule !== undefined) { - let dependentProperty = Object.keys(showPropertyRule)[0]; - let dependentPropertyValue = showPropertyRule[dependentProperty]; - if (properties[dependentProperty] === undefined) { - properties[dependentProperty] = {}; - } - if (properties[dependentProperty].showPropertyRules === undefined) { - properties[dependentProperty].showPropertyRules = {}; - } - properties[dependentProperty].showPropertyRules[propertyID] = dependentPropertyValue; - } - } - }); - - elGroups[group.id] = elGroup; - }); - - let minorSections = document.querySelectorAll(".section.minor"); - minorSections[minorSections.length - 1].className += " last"; - - updateVisibleSpaceModeProperties(); - - if (window.EventBridge !== undefined) { - EventBridge.scriptEventReceived.connect(function(data) { - data = JSON.parse(data); - if (data.type === "server_script_status" && selectedEntityIDs.size === 1) { - let elServerScriptError = document.getElementById("property-serverScripts-error"); - let elServerScriptStatus = document.getElementById("property-serverScripts-status"); - elServerScriptError.value = data.errorInfo; - // If we just set elServerScriptError's display to block or none, we still end up with - // it's parent contributing 21px bottom padding even when elServerScriptError is display:none. - // So set it's parent to block or none - elServerScriptError.parentElement.style.display = data.errorInfo ? "block" : "none"; - if (data.statusRetrieved === false) { - elServerScriptStatus.innerText = "Failed to retrieve status"; - } else if (data.isRunning) { - elServerScriptStatus.innerText = ENTITY_SCRIPT_STATUS[data.status] || data.status; - } else { - elServerScriptStatus.innerText = NOT_RUNNING_SCRIPT_STATUS; - } - } else if (data.type === "update" && data.selections) { - if (data.spaceMode !== undefined) { - currentSpaceMode = data.spaceMode === "local" ? PROPERTY_SPACE_MODE.LOCAL : PROPERTY_SPACE_MODE.WORLD; - } - handleEntitySelectionUpdate(data.selections, data.isPropertiesToolUpdate); - } else if (data.type === 'tooltipsReply') { - createAppTooltip.setIsEnabled(!data.hmdActive); - createAppTooltip.setTooltipData(data.tooltips); - } else if (data.type === 'hmdActiveChanged') { - createAppTooltip.setIsEnabled(!data.hmdActive); - } else if (data.type === 'setSpaceMode') { - currentSpaceMode = data.spaceMode === "local" ? PROPERTY_SPACE_MODE.LOCAL : PROPERTY_SPACE_MODE.WORLD; - updateVisibleSpaceModeProperties(); - } else if (data.type === 'propertyRangeReply') { - let propertyRanges = data.propertyRanges; - for (let property in propertyRanges) { - let propertyRange = propertyRanges[property]; - if (propertyRange !== undefined) { - let propertyData = properties[property].data; - let multiplier = propertyData.multiplier; - if (propertyData.min === undefined && propertyRange.minimum !== "") { - propertyData.min = propertyRange.minimum; - if (multiplier !== undefined) { - propertyData.min /= multiplier; - } - } - if (propertyData.max === undefined && propertyRange.maximum !== "") { - propertyData.max = propertyRange.maximum; - if (multiplier !== undefined) { - propertyData.max /= multiplier; - } - } - switch (propertyData.type) { - case 'number': - updateNumberMinMax(properties[property]); - break; - case 'number-draggable': - updateNumberDraggableMinMax(properties[property]); - break; - case 'vec3': - case 'vec2': - updateVectorMinMax(properties[property]); - break; - case 'rect': - updateRectMinMax(properties[property]); - break; - } - } - } - } else if (data.type === 'materialTargetReply') { - if (data.entityID === getFirstSelectedID()) { - setMaterialTargetData(data.materialTargetData); - } - } - }); - - // Request tooltips and property ranges as soon as we can process a reply: - EventBridge.emitWebEvent(JSON.stringify({ type: 'tooltipsRequest' })); - EventBridge.emitWebEvent(JSON.stringify({ type: 'propertyRangeRequest', properties: propertyRangeRequests })); - } - - // Server Script Status - let elServerScriptStatusOuter = document.getElementById('div-property-serverScriptStatus'); - let elServerScriptStatusContainer = document.getElementById('div-property-serverScriptStatus').childNodes[1]; - let serverScriptStatusElementID = 'property-serverScripts-status'; - createAppTooltip.registerTooltipElement(elServerScriptStatusOuter.childNodes[0], "serverScriptsStatus"); - let elServerScriptStatus = document.createElement('div'); - elServerScriptStatus.setAttribute("id", serverScriptStatusElementID); - elServerScriptStatusContainer.appendChild(elServerScriptStatus); - - // Server Script Error - let elServerScripts = getPropertyInputElement("serverScripts"); - let elDiv = document.createElement('div'); - elDiv.className = "property"; - let elServerScriptError = document.createElement('textarea'); - let serverScriptErrorElementID = 'property-serverScripts-error'; - elServerScriptError.setAttribute("id", serverScriptErrorElementID); - elDiv.appendChild(elServerScriptError); - elServerScriptStatusContainer.appendChild(elDiv); - - let elScript = getPropertyInputElement("script"); - elScript.parentNode.className = "url refresh"; - elServerScripts.parentNode.className = "url refresh"; - - // User Data - let userDataProperty = properties["userData"]; - let elUserData = userDataProperty.elInput; - let userDataElementID = userDataProperty.elementID; - elDiv = elUserData.parentNode; - let elStaticUserData = document.createElement('div'); - elStaticUserData.setAttribute("id", userDataElementID + "-static"); - let elUserDataEditor = document.createElement('div'); - elUserDataEditor.setAttribute("id", userDataElementID + "-editor"); - let elUserDataEditorStatus = document.createElement('div'); - elUserDataEditorStatus.setAttribute("id", userDataElementID + "-editorStatus"); - let elUserDataSaved = document.createElement('span'); - elUserDataSaved.setAttribute("id", userDataElementID + "-saved"); - elUserDataSaved.innerText = "Saved!"; - elDiv.childNodes[JSON_EDITOR_ROW_DIV_INDEX].appendChild(elUserDataSaved); - elDiv.insertBefore(elStaticUserData, elUserData); - elDiv.insertBefore(elUserDataEditor, elUserData); - elDiv.insertBefore(elUserDataEditorStatus, elUserData); - - // Material Data - let materialDataProperty = properties["materialData"]; - let elMaterialData = materialDataProperty.elInput; - let materialDataElementID = materialDataProperty.elementID; - elDiv = elMaterialData.parentNode; - let elStaticMaterialData = document.createElement('div'); - elStaticMaterialData.setAttribute("id", materialDataElementID + "-static"); - let elMaterialDataEditor = document.createElement('div'); - elMaterialDataEditor.setAttribute("id", materialDataElementID + "-editor"); - let elMaterialDataEditorStatus = document.createElement('div'); - elMaterialDataEditorStatus.setAttribute("id", materialDataElementID + "-editorStatus"); - let elMaterialDataSaved = document.createElement('span'); - elMaterialDataSaved.setAttribute("id", materialDataElementID + "-saved"); - elMaterialDataSaved.innerText = "Saved!"; - elDiv.childNodes[JSON_EDITOR_ROW_DIV_INDEX].appendChild(elMaterialDataSaved); - elDiv.insertBefore(elStaticMaterialData, elMaterialData); - elDiv.insertBefore(elMaterialDataEditor, elMaterialData); - elDiv.insertBefore(elMaterialDataEditorStatus, elMaterialData); - - // Collapsible sections - let elCollapsible = document.getElementsByClassName("collapse-icon"); - - let toggleCollapsedEvent = function(event) { - let element = this.parentNode.parentNode; - let isCollapsed = element.dataset.collapsed !== "true"; - element.dataset.collapsed = isCollapsed ? "true" : false; - element.setAttribute("collapsed", isCollapsed ? "true" : "false"); - this.textContent = isCollapsed ? "L" : "M"; - }; - - for (let collapseIndex = 0, numCollapsibles = elCollapsible.length; collapseIndex < numCollapsibles; ++collapseIndex) { - let curCollapsibleElement = elCollapsible[collapseIndex]; - curCollapsibleElement.addEventListener("click", toggleCollapsedEvent, true); - } - - // Textarea scrollbars - let elTextareas = document.getElementsByTagName("TEXTAREA"); - - let textareaOnChangeEvent = function(event) { - setTextareaScrolling(event.target); - }; - - for (let textAreaIndex = 0, numTextAreas = elTextareas.length; textAreaIndex < numTextAreas; ++textAreaIndex) { - let curTextAreaElement = elTextareas[textAreaIndex]; - setTextareaScrolling(curTextAreaElement); - curTextAreaElement.addEventListener("input", textareaOnChangeEvent, false); - curTextAreaElement.addEventListener("change", textareaOnChangeEvent, false); - /* FIXME: Detect and update textarea scrolling attribute on resize. Unfortunately textarea doesn't have a resize - event; mouseup is a partial stand-in but doesn't handle resizing if mouse moves outside textarea rectangle. */ - curTextAreaElement.addEventListener("mouseup", textareaOnChangeEvent, false); - } - - // Dropdowns - // For each dropdown the following replacement is created in place of the original dropdown... - // Structure created: - //
- //
display textcarat
- //
- //
    - //
  • 0) { - let el = elDropdowns[0]; - el.parentNode.removeChild(el); - elDropdowns = document.getElementsByTagName("select"); - } - - const KEY_CODES = { - BACKSPACE: 8, - DELETE: 46 - }; - - document.addEventListener("keyup", function (keyUpEvent) { - const FILTERED_NODE_NAMES = ["INPUT", "TEXTAREA"]; - if (FILTERED_NODE_NAMES.includes(keyUpEvent.target.nodeName)) { - return; - } - - if (elUserDataEditor.contains(keyUpEvent.target) || elMaterialDataEditor.contains(keyUpEvent.target)) { - return; - } - - let {code, key, keyCode, altKey, ctrlKey, metaKey, shiftKey} = keyUpEvent; - - let controlKey = window.navigator.platform.startsWith("Mac") ? metaKey : ctrlKey; - - let keyCodeString; - switch (keyCode) { - case KEY_CODES.DELETE: - keyCodeString = "Delete"; - break; - case KEY_CODES.BACKSPACE: - keyCodeString = "Backspace"; - break; - default: - keyCodeString = String.fromCharCode(keyUpEvent.keyCode); - break; - } - - EventBridge.emitWebEvent(JSON.stringify({ - type: 'keyUpEvent', - keyUpEvent: { - code, - key, - keyCode, - keyCodeString, - altKey, - controlKey, - shiftKey, - } - })); - }, false); - - window.onblur = function() { - // Fake a change event - let ev = document.createEvent("HTMLEvents"); - ev.initEvent("change", true, true); - document.activeElement.dispatchEvent(ev); - }; - - // For input and textarea elements, select all of the text on focus - let els = document.querySelectorAll("input, textarea"); - for (let i = 0; i < els.length; ++i) { - els[i].onfocus = function (e) { - e.target.select(); - }; - } - - bindAllNonJSONEditorElements(); - - showGroupsForType("None"); - resetProperties(); - disableProperties(); - }); - - augmentSpinButtons(); - disableDragDrop(); - - // Disable right-click context menu which is not visible in the HMD and makes it seem like the app has locked - document.addEventListener("contextmenu", function(event) { - event.preventDefault(); - }, false); - - setTimeout(function() { - EventBridge.emitWebEvent(JSON.stringify({ type: 'propertiesPageReady' })); - }, 1000); -} diff --git a/scripts/simplifiedUI/system/html/js/eventBridgeLoader.js b/scripts/simplifiedUI/system/html/js/eventBridgeLoader.js deleted file mode 100644 index 411780853b..0000000000 --- a/scripts/simplifiedUI/system/html/js/eventBridgeLoader.js +++ /dev/null @@ -1,19 +0,0 @@ - -//public slots: -// void emitWebEvent(const QString& data); -// void emitScriptEvent(const QString& data); -// -//signals: -// void webEventReceived(const QString& data); -// void scriptEventReceived(const QString& data); -// - -var EventBridge; -var WebChannel; - -openEventBridge = function(callback) { - WebChannel = new QWebChannel(qt.webChannelTransport, function (channel) { - EventBridge = WebChannel.objects.eventBridge; - callback(EventBridge); - }); -} diff --git a/scripts/simplifiedUI/system/html/js/gridControls.js b/scripts/simplifiedUI/system/html/js/gridControls.js deleted file mode 100644 index e27dac522b..0000000000 --- a/scripts/simplifiedUI/system/html/js/gridControls.js +++ /dev/null @@ -1,161 +0,0 @@ -// gridControls.js -// -// Created by Ryan Huffman on 6 Nov 2014 -// Copyright 2014 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html - -function loaded() { - openEventBridge(function() { - elPosY = document.getElementById("horiz-y"); - elMinorSpacing = document.getElementById("minor-spacing"); - elMajorSpacing = document.getElementById("major-spacing"); - elSnapToGrid = document.getElementById("snap-to-grid"); - elHorizontalGridVisible = document.getElementById("horiz-grid-visible"); - elMoveToSelection = document.getElementById("move-to-selection"); - elMoveToAvatar = document.getElementById("move-to-avatar"); - - if (window.EventBridge !== undefined) { - EventBridge.scriptEventReceived.connect(function(data) { - data = JSON.parse(data); - - if (data.origin) { - var origin = data.origin; - elPosY.value = origin.y; - } - - if (data.minorGridEvery !== undefined) { - elMinorSpacing.value = data.minorGridEvery; - } - - if (data.majorGridEvery !== undefined) { - elMajorSpacing.value = data.majorGridEvery; - } - - if (data.gridColor) { - gridColor = data.gridColor; - } - - if (data.snapToGrid !== undefined) { - elSnapToGrid.checked = data.snapToGrid == true; - } - - if (data.visible !== undefined) { - elHorizontalGridVisible.checked = data.visible == true; - } - }); - - function emitUpdate() { - EventBridge.emitWebEvent(JSON.stringify({ - type: "update", - origin: { - y: elPosY.value, - }, - minorGridEvery: elMinorSpacing.value, - majorGridEvery: elMajorSpacing.value, - gridColor: gridColor, - snapToGrid: elSnapToGrid.checked, - visible: elHorizontalGridVisible.checked, - })); - } - - } - - elPosY.addEventListener("change", emitUpdate); - elMinorSpacing.addEventListener("change", emitUpdate); - elMajorSpacing.addEventListener("change", emitUpdate); - elSnapToGrid.addEventListener("change", emitUpdate); - elHorizontalGridVisible.addEventListener("change", emitUpdate); - - elMoveToAvatar.addEventListener("click", function() { - EventBridge.emitWebEvent(JSON.stringify({ - type: "action", - action: "moveToAvatar", - })); - }); - elMoveToSelection.addEventListener("click", function() { - EventBridge.emitWebEvent(JSON.stringify({ - type: "action", - action: "moveToSelection", - })); - }); - - var gridColor = { red: 255, green: 255, blue: 255 }; - var elColor = document.getElementById("grid-color"); - elColor.style.backgroundColor = "rgb(" + gridColor.red + "," + gridColor.green + "," + gridColor.blue + ")"; - - var colorPickFunction = function (red, green, blue) { - gridColor = { red: red, green: green, blue: blue }; - emitUpdate(); - }; - - $('#grid-color').colpick({ - colorScheme: 'dark', - layout: 'rgbhex', - color: { r: gridColor.red, g: gridColor.green, b: gridColor.blue }, - submit: false, - onShow: function (colpick) { - $('#grid-color').attr('active', 'true'); - }, - onHide: function (colpick) { - $('#grid-color').attr('active', 'false'); - }, - onChange: function (hsb, hex, rgb, el) { - $(el).css('background-color', '#' + hex); - colorPickFunction(rgb.r, rgb.g, rgb.b); - } - }); - - augmentSpinButtons(); - disableDragDrop(); - - EventBridge.emitWebEvent(JSON.stringify({ type: 'init' })); - }); - - const KEY_CODES = { - BACKSPACE: 8, - DELETE: 46 - }; - - document.addEventListener("keyup", function (keyUpEvent) { - const FILTERED_NODE_NAMES = ["INPUT", "TEXTAREA"]; - if (FILTERED_NODE_NAMES.includes(keyUpEvent.target.nodeName)) { - return; - } - let {code, key, keyCode, altKey, ctrlKey, metaKey, shiftKey} = keyUpEvent; - - let controlKey = window.navigator.platform.startsWith("Mac") ? metaKey : ctrlKey; - - let keyCodeString; - switch (keyCode) { - case KEY_CODES.DELETE: - keyCodeString = "Delete"; - break; - case KEY_CODES.BACKSPACE: - keyCodeString = "Backspace"; - break; - default: - keyCodeString = String.fromCharCode(keyUpEvent.keyCode); - break; - } - - EventBridge.emitWebEvent(JSON.stringify({ - type: 'keyUpEvent', - keyUpEvent: { - code, - key, - keyCode, - keyCodeString, - altKey, - controlKey, - shiftKey, - } - })); - }, false); - - // Disable right-click context menu which is not visible in the HMD and makes it seem like the app has locked - document.addEventListener("contextmenu", function (event) { - event.preventDefault(); - }, false); -} diff --git a/scripts/simplifiedUI/system/html/js/includes.js b/scripts/simplifiedUI/system/html/js/includes.js deleted file mode 100644 index c604115f91..0000000000 --- a/scripts/simplifiedUI/system/html/js/includes.js +++ /dev/null @@ -1,27 +0,0 @@ -// -// includes.js -// -// Created by David Back on 3 Jan 2019 -// Copyright 2016 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -const ENTITY_TYPE_ICON = { - Box: "m", - Grid: "", - Image: "", - Light: "p", - Material: "", - Model: "", - ParticleEffect: "", - PolyVox: "", - PolyLine: "", - Shape: "n", - Sphere: "n", - Text: "l", - Web: "q", - Zone: "o", - Multiple: "", -}; diff --git a/scripts/simplifiedUI/system/html/js/jquery-2.1.4.min.js b/scripts/simplifiedUI/system/html/js/jquery-2.1.4.min.js deleted file mode 100644 index 49990d6e14..0000000000 --- a/scripts/simplifiedUI/system/html/js/jquery-2.1.4.min.js +++ /dev/null @@ -1,4 +0,0 @@ -/*! jQuery v2.1.4 | (c) 2005, 2015 jQuery Foundation, Inc. | jquery.org/license */ -!function(a,b){"object"==typeof module&&"object"==typeof module.exports?module.exports=a.document?b(a,!0):function(a){if(!a.document)throw new Error("jQuery requires a window with a document");return b(a)}:b(a)}("undefined"!=typeof window?window:this,function(a,b){var c=[],d=c.slice,e=c.concat,f=c.push,g=c.indexOf,h={},i=h.toString,j=h.hasOwnProperty,k={},l=a.document,m="2.1.4",n=function(a,b){return new n.fn.init(a,b)},o=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,p=/^-ms-/,q=/-([\da-z])/gi,r=function(a,b){return b.toUpperCase()};n.fn=n.prototype={jquery:m,constructor:n,selector:"",length:0,toArray:function(){return d.call(this)},get:function(a){return null!=a?0>a?this[a+this.length]:this[a]:d.call(this)},pushStack:function(a){var b=n.merge(this.constructor(),a);return b.prevObject=this,b.context=this.context,b},each:function(a,b){return n.each(this,a,b)},map:function(a){return this.pushStack(n.map(this,function(b,c){return a.call(b,c,b)}))},slice:function(){return this.pushStack(d.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(a){var b=this.length,c=+a+(0>a?b:0);return this.pushStack(c>=0&&b>c?[this[c]]:[])},end:function(){return this.prevObject||this.constructor(null)},push:f,sort:c.sort,splice:c.splice},n.extend=n.fn.extend=function(){var a,b,c,d,e,f,g=arguments[0]||{},h=1,i=arguments.length,j=!1;for("boolean"==typeof g&&(j=g,g=arguments[h]||{},h++),"object"==typeof g||n.isFunction(g)||(g={}),h===i&&(g=this,h--);i>h;h++)if(null!=(a=arguments[h]))for(b in a)c=g[b],d=a[b],g!==d&&(j&&d&&(n.isPlainObject(d)||(e=n.isArray(d)))?(e?(e=!1,f=c&&n.isArray(c)?c:[]):f=c&&n.isPlainObject(c)?c:{},g[b]=n.extend(j,f,d)):void 0!==d&&(g[b]=d));return g},n.extend({expando:"jQuery"+(m+Math.random()).replace(/\D/g,""),isReady:!0,error:function(a){throw new Error(a)},noop:function(){},isFunction:function(a){return"function"===n.type(a)},isArray:Array.isArray,isWindow:function(a){return null!=a&&a===a.window},isNumeric:function(a){return!n.isArray(a)&&a-parseFloat(a)+1>=0},isPlainObject:function(a){return"object"!==n.type(a)||a.nodeType||n.isWindow(a)?!1:a.constructor&&!j.call(a.constructor.prototype,"isPrototypeOf")?!1:!0},isEmptyObject:function(a){var b;for(b in a)return!1;return!0},type:function(a){return null==a?a+"":"object"==typeof a||"function"==typeof a?h[i.call(a)]||"object":typeof a},globalEval:function(a){var b,c=eval;a=n.trim(a),a&&(1===a.indexOf("use strict")?(b=l.createElement("script"),b.text=a,l.head.appendChild(b).parentNode.removeChild(b)):c(a))},camelCase:function(a){return a.replace(p,"ms-").replace(q,r)},nodeName:function(a,b){return a.nodeName&&a.nodeName.toLowerCase()===b.toLowerCase()},each:function(a,b,c){var d,e=0,f=a.length,g=s(a);if(c){if(g){for(;f>e;e++)if(d=b.apply(a[e],c),d===!1)break}else for(e in a)if(d=b.apply(a[e],c),d===!1)break}else if(g){for(;f>e;e++)if(d=b.call(a[e],e,a[e]),d===!1)break}else for(e in a)if(d=b.call(a[e],e,a[e]),d===!1)break;return a},trim:function(a){return null==a?"":(a+"").replace(o,"")},makeArray:function(a,b){var c=b||[];return null!=a&&(s(Object(a))?n.merge(c,"string"==typeof a?[a]:a):f.call(c,a)),c},inArray:function(a,b,c){return null==b?-1:g.call(b,a,c)},merge:function(a,b){for(var c=+b.length,d=0,e=a.length;c>d;d++)a[e++]=b[d];return a.length=e,a},grep:function(a,b,c){for(var d,e=[],f=0,g=a.length,h=!c;g>f;f++)d=!b(a[f],f),d!==h&&e.push(a[f]);return e},map:function(a,b,c){var d,f=0,g=a.length,h=s(a),i=[];if(h)for(;g>f;f++)d=b(a[f],f,c),null!=d&&i.push(d);else for(f in a)d=b(a[f],f,c),null!=d&&i.push(d);return e.apply([],i)},guid:1,proxy:function(a,b){var c,e,f;return"string"==typeof b&&(c=a[b],b=a,a=c),n.isFunction(a)?(e=d.call(arguments,2),f=function(){return a.apply(b||this,e.concat(d.call(arguments)))},f.guid=a.guid=a.guid||n.guid++,f):void 0},now:Date.now,support:k}),n.each("Boolean Number String Function Array Date RegExp Object Error".split(" "),function(a,b){h["[object "+b+"]"]=b.toLowerCase()});function s(a){var b="length"in a&&a.length,c=n.type(a);return"function"===c||n.isWindow(a)?!1:1===a.nodeType&&b?!0:"array"===c||0===b||"number"==typeof b&&b>0&&b-1 in a}var t=function(a){var b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u="sizzle"+1*new Date,v=a.document,w=0,x=0,y=ha(),z=ha(),A=ha(),B=function(a,b){return a===b&&(l=!0),0},C=1<<31,D={}.hasOwnProperty,E=[],F=E.pop,G=E.push,H=E.push,I=E.slice,J=function(a,b){for(var c=0,d=a.length;d>c;c++)if(a[c]===b)return c;return-1},K="checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",L="[\\x20\\t\\r\\n\\f]",M="(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",N=M.replace("w","w#"),O="\\["+L+"*("+M+")(?:"+L+"*([*^$|!~]?=)"+L+"*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|("+N+"))|)"+L+"*\\]",P=":("+M+")(?:\\((('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|((?:\\\\.|[^\\\\()[\\]]|"+O+")*)|.*)\\)|)",Q=new RegExp(L+"+","g"),R=new RegExp("^"+L+"+|((?:^|[^\\\\])(?:\\\\.)*)"+L+"+$","g"),S=new RegExp("^"+L+"*,"+L+"*"),T=new RegExp("^"+L+"*([>+~]|"+L+")"+L+"*"),U=new RegExp("="+L+"*([^\\]'\"]*?)"+L+"*\\]","g"),V=new RegExp(P),W=new RegExp("^"+N+"$"),X={ID:new RegExp("^#("+M+")"),CLASS:new RegExp("^\\.("+M+")"),TAG:new RegExp("^("+M.replace("w","w*")+")"),ATTR:new RegExp("^"+O),PSEUDO:new RegExp("^"+P),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+L+"*(even|odd|(([+-]|)(\\d*)n|)"+L+"*(?:([+-]|)"+L+"*(\\d+)|))"+L+"*\\)|)","i"),bool:new RegExp("^(?:"+K+")$","i"),needsContext:new RegExp("^"+L+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+L+"*((?:-\\d)?\\d*)"+L+"*\\)|)(?=[^-]|$)","i")},Y=/^(?:input|select|textarea|button)$/i,Z=/^h\d$/i,$=/^[^{]+\{\s*\[native \w/,_=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,aa=/[+~]/,ba=/'|\\/g,ca=new RegExp("\\\\([\\da-f]{1,6}"+L+"?|("+L+")|.)","ig"),da=function(a,b,c){var d="0x"+b-65536;return d!==d||c?b:0>d?String.fromCharCode(d+65536):String.fromCharCode(d>>10|55296,1023&d|56320)},ea=function(){m()};try{H.apply(E=I.call(v.childNodes),v.childNodes),E[v.childNodes.length].nodeType}catch(fa){H={apply:E.length?function(a,b){G.apply(a,I.call(b))}:function(a,b){var c=a.length,d=0;while(a[c++]=b[d++]);a.length=c-1}}}function ga(a,b,d,e){var f,h,j,k,l,o,r,s,w,x;if((b?b.ownerDocument||b:v)!==n&&m(b),b=b||n,d=d||[],k=b.nodeType,"string"!=typeof a||!a||1!==k&&9!==k&&11!==k)return d;if(!e&&p){if(11!==k&&(f=_.exec(a)))if(j=f[1]){if(9===k){if(h=b.getElementById(j),!h||!h.parentNode)return d;if(h.id===j)return d.push(h),d}else if(b.ownerDocument&&(h=b.ownerDocument.getElementById(j))&&t(b,h)&&h.id===j)return d.push(h),d}else{if(f[2])return H.apply(d,b.getElementsByTagName(a)),d;if((j=f[3])&&c.getElementsByClassName)return H.apply(d,b.getElementsByClassName(j)),d}if(c.qsa&&(!q||!q.test(a))){if(s=r=u,w=b,x=1!==k&&a,1===k&&"object"!==b.nodeName.toLowerCase()){o=g(a),(r=b.getAttribute("id"))?s=r.replace(ba,"\\$&"):b.setAttribute("id",s),s="[id='"+s+"'] ",l=o.length;while(l--)o[l]=s+ra(o[l]);w=aa.test(a)&&pa(b.parentNode)||b,x=o.join(",")}if(x)try{return H.apply(d,w.querySelectorAll(x)),d}catch(y){}finally{r||b.removeAttribute("id")}}}return i(a.replace(R,"$1"),b,d,e)}function ha(){var a=[];function b(c,e){return a.push(c+" ")>d.cacheLength&&delete b[a.shift()],b[c+" "]=e}return b}function ia(a){return a[u]=!0,a}function ja(a){var b=n.createElement("div");try{return!!a(b)}catch(c){return!1}finally{b.parentNode&&b.parentNode.removeChild(b),b=null}}function ka(a,b){var c=a.split("|"),e=a.length;while(e--)d.attrHandle[c[e]]=b}function la(a,b){var c=b&&a,d=c&&1===a.nodeType&&1===b.nodeType&&(~b.sourceIndex||C)-(~a.sourceIndex||C);if(d)return d;if(c)while(c=c.nextSibling)if(c===b)return-1;return a?1:-1}function ma(a){return function(b){var c=b.nodeName.toLowerCase();return"input"===c&&b.type===a}}function na(a){return function(b){var c=b.nodeName.toLowerCase();return("input"===c||"button"===c)&&b.type===a}}function oa(a){return ia(function(b){return b=+b,ia(function(c,d){var e,f=a([],c.length,b),g=f.length;while(g--)c[e=f[g]]&&(c[e]=!(d[e]=c[e]))})})}function pa(a){return a&&"undefined"!=typeof a.getElementsByTagName&&a}c=ga.support={},f=ga.isXML=function(a){var b=a&&(a.ownerDocument||a).documentElement;return b?"HTML"!==b.nodeName:!1},m=ga.setDocument=function(a){var b,e,g=a?a.ownerDocument||a:v;return g!==n&&9===g.nodeType&&g.documentElement?(n=g,o=g.documentElement,e=g.defaultView,e&&e!==e.top&&(e.addEventListener?e.addEventListener("unload",ea,!1):e.attachEvent&&e.attachEvent("onunload",ea)),p=!f(g),c.attributes=ja(function(a){return a.className="i",!a.getAttribute("className")}),c.getElementsByTagName=ja(function(a){return a.appendChild(g.createComment("")),!a.getElementsByTagName("*").length}),c.getElementsByClassName=$.test(g.getElementsByClassName),c.getById=ja(function(a){return o.appendChild(a).id=u,!g.getElementsByName||!g.getElementsByName(u).length}),c.getById?(d.find.ID=function(a,b){if("undefined"!=typeof b.getElementById&&p){var c=b.getElementById(a);return c&&c.parentNode?[c]:[]}},d.filter.ID=function(a){var b=a.replace(ca,da);return function(a){return a.getAttribute("id")===b}}):(delete d.find.ID,d.filter.ID=function(a){var b=a.replace(ca,da);return function(a){var c="undefined"!=typeof a.getAttributeNode&&a.getAttributeNode("id");return c&&c.value===b}}),d.find.TAG=c.getElementsByTagName?function(a,b){return"undefined"!=typeof b.getElementsByTagName?b.getElementsByTagName(a):c.qsa?b.querySelectorAll(a):void 0}:function(a,b){var c,d=[],e=0,f=b.getElementsByTagName(a);if("*"===a){while(c=f[e++])1===c.nodeType&&d.push(c);return d}return f},d.find.CLASS=c.getElementsByClassName&&function(a,b){return p?b.getElementsByClassName(a):void 0},r=[],q=[],(c.qsa=$.test(g.querySelectorAll))&&(ja(function(a){o.appendChild(a).innerHTML="",a.querySelectorAll("[msallowcapture^='']").length&&q.push("[*^$]="+L+"*(?:''|\"\")"),a.querySelectorAll("[selected]").length||q.push("\\["+L+"*(?:value|"+K+")"),a.querySelectorAll("[id~="+u+"-]").length||q.push("~="),a.querySelectorAll(":checked").length||q.push(":checked"),a.querySelectorAll("a#"+u+"+*").length||q.push(".#.+[+~]")}),ja(function(a){var b=g.createElement("input");b.setAttribute("type","hidden"),a.appendChild(b).setAttribute("name","D"),a.querySelectorAll("[name=d]").length&&q.push("name"+L+"*[*^$|!~]?="),a.querySelectorAll(":enabled").length||q.push(":enabled",":disabled"),a.querySelectorAll("*,:x"),q.push(",.*:")})),(c.matchesSelector=$.test(s=o.matches||o.webkitMatchesSelector||o.mozMatchesSelector||o.oMatchesSelector||o.msMatchesSelector))&&ja(function(a){c.disconnectedMatch=s.call(a,"div"),s.call(a,"[s!='']:x"),r.push("!=",P)}),q=q.length&&new RegExp(q.join("|")),r=r.length&&new RegExp(r.join("|")),b=$.test(o.compareDocumentPosition),t=b||$.test(o.contains)?function(a,b){var c=9===a.nodeType?a.documentElement:a,d=b&&b.parentNode;return a===d||!(!d||1!==d.nodeType||!(c.contains?c.contains(d):a.compareDocumentPosition&&16&a.compareDocumentPosition(d)))}:function(a,b){if(b)while(b=b.parentNode)if(b===a)return!0;return!1},B=b?function(a,b){if(a===b)return l=!0,0;var d=!a.compareDocumentPosition-!b.compareDocumentPosition;return d?d:(d=(a.ownerDocument||a)===(b.ownerDocument||b)?a.compareDocumentPosition(b):1,1&d||!c.sortDetached&&b.compareDocumentPosition(a)===d?a===g||a.ownerDocument===v&&t(v,a)?-1:b===g||b.ownerDocument===v&&t(v,b)?1:k?J(k,a)-J(k,b):0:4&d?-1:1)}:function(a,b){if(a===b)return l=!0,0;var c,d=0,e=a.parentNode,f=b.parentNode,h=[a],i=[b];if(!e||!f)return a===g?-1:b===g?1:e?-1:f?1:k?J(k,a)-J(k,b):0;if(e===f)return la(a,b);c=a;while(c=c.parentNode)h.unshift(c);c=b;while(c=c.parentNode)i.unshift(c);while(h[d]===i[d])d++;return d?la(h[d],i[d]):h[d]===v?-1:i[d]===v?1:0},g):n},ga.matches=function(a,b){return ga(a,null,null,b)},ga.matchesSelector=function(a,b){if((a.ownerDocument||a)!==n&&m(a),b=b.replace(U,"='$1']"),!(!c.matchesSelector||!p||r&&r.test(b)||q&&q.test(b)))try{var d=s.call(a,b);if(d||c.disconnectedMatch||a.document&&11!==a.document.nodeType)return d}catch(e){}return ga(b,n,null,[a]).length>0},ga.contains=function(a,b){return(a.ownerDocument||a)!==n&&m(a),t(a,b)},ga.attr=function(a,b){(a.ownerDocument||a)!==n&&m(a);var e=d.attrHandle[b.toLowerCase()],f=e&&D.call(d.attrHandle,b.toLowerCase())?e(a,b,!p):void 0;return void 0!==f?f:c.attributes||!p?a.getAttribute(b):(f=a.getAttributeNode(b))&&f.specified?f.value:null},ga.error=function(a){throw new Error("Syntax error, unrecognized expression: "+a)},ga.uniqueSort=function(a){var b,d=[],e=0,f=0;if(l=!c.detectDuplicates,k=!c.sortStable&&a.slice(0),a.sort(B),l){while(b=a[f++])b===a[f]&&(e=d.push(f));while(e--)a.splice(d[e],1)}return k=null,a},e=ga.getText=function(a){var b,c="",d=0,f=a.nodeType;if(f){if(1===f||9===f||11===f){if("string"==typeof a.textContent)return a.textContent;for(a=a.firstChild;a;a=a.nextSibling)c+=e(a)}else if(3===f||4===f)return a.nodeValue}else while(b=a[d++])c+=e(b);return c},d=ga.selectors={cacheLength:50,createPseudo:ia,match:X,attrHandle:{},find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(a){return a[1]=a[1].replace(ca,da),a[3]=(a[3]||a[4]||a[5]||"").replace(ca,da),"~="===a[2]&&(a[3]=" "+a[3]+" "),a.slice(0,4)},CHILD:function(a){return a[1]=a[1].toLowerCase(),"nth"===a[1].slice(0,3)?(a[3]||ga.error(a[0]),a[4]=+(a[4]?a[5]+(a[6]||1):2*("even"===a[3]||"odd"===a[3])),a[5]=+(a[7]+a[8]||"odd"===a[3])):a[3]&&ga.error(a[0]),a},PSEUDO:function(a){var b,c=!a[6]&&a[2];return X.CHILD.test(a[0])?null:(a[3]?a[2]=a[4]||a[5]||"":c&&V.test(c)&&(b=g(c,!0))&&(b=c.indexOf(")",c.length-b)-c.length)&&(a[0]=a[0].slice(0,b),a[2]=c.slice(0,b)),a.slice(0,3))}},filter:{TAG:function(a){var b=a.replace(ca,da).toLowerCase();return"*"===a?function(){return!0}:function(a){return a.nodeName&&a.nodeName.toLowerCase()===b}},CLASS:function(a){var b=y[a+" "];return b||(b=new RegExp("(^|"+L+")"+a+"("+L+"|$)"))&&y(a,function(a){return b.test("string"==typeof a.className&&a.className||"undefined"!=typeof a.getAttribute&&a.getAttribute("class")||"")})},ATTR:function(a,b,c){return function(d){var e=ga.attr(d,a);return null==e?"!="===b:b?(e+="","="===b?e===c:"!="===b?e!==c:"^="===b?c&&0===e.indexOf(c):"*="===b?c&&e.indexOf(c)>-1:"$="===b?c&&e.slice(-c.length)===c:"~="===b?(" "+e.replace(Q," ")+" ").indexOf(c)>-1:"|="===b?e===c||e.slice(0,c.length+1)===c+"-":!1):!0}},CHILD:function(a,b,c,d,e){var f="nth"!==a.slice(0,3),g="last"!==a.slice(-4),h="of-type"===b;return 1===d&&0===e?function(a){return!!a.parentNode}:function(b,c,i){var j,k,l,m,n,o,p=f!==g?"nextSibling":"previousSibling",q=b.parentNode,r=h&&b.nodeName.toLowerCase(),s=!i&&!h;if(q){if(f){while(p){l=b;while(l=l[p])if(h?l.nodeName.toLowerCase()===r:1===l.nodeType)return!1;o=p="only"===a&&!o&&"nextSibling"}return!0}if(o=[g?q.firstChild:q.lastChild],g&&s){k=q[u]||(q[u]={}),j=k[a]||[],n=j[0]===w&&j[1],m=j[0]===w&&j[2],l=n&&q.childNodes[n];while(l=++n&&l&&l[p]||(m=n=0)||o.pop())if(1===l.nodeType&&++m&&l===b){k[a]=[w,n,m];break}}else if(s&&(j=(b[u]||(b[u]={}))[a])&&j[0]===w)m=j[1];else while(l=++n&&l&&l[p]||(m=n=0)||o.pop())if((h?l.nodeName.toLowerCase()===r:1===l.nodeType)&&++m&&(s&&((l[u]||(l[u]={}))[a]=[w,m]),l===b))break;return m-=e,m===d||m%d===0&&m/d>=0}}},PSEUDO:function(a,b){var c,e=d.pseudos[a]||d.setFilters[a.toLowerCase()]||ga.error("unsupported pseudo: "+a);return e[u]?e(b):e.length>1?(c=[a,a,"",b],d.setFilters.hasOwnProperty(a.toLowerCase())?ia(function(a,c){var d,f=e(a,b),g=f.length;while(g--)d=J(a,f[g]),a[d]=!(c[d]=f[g])}):function(a){return e(a,0,c)}):e}},pseudos:{not:ia(function(a){var b=[],c=[],d=h(a.replace(R,"$1"));return d[u]?ia(function(a,b,c,e){var f,g=d(a,null,e,[]),h=a.length;while(h--)(f=g[h])&&(a[h]=!(b[h]=f))}):function(a,e,f){return b[0]=a,d(b,null,f,c),b[0]=null,!c.pop()}}),has:ia(function(a){return function(b){return ga(a,b).length>0}}),contains:ia(function(a){return a=a.replace(ca,da),function(b){return(b.textContent||b.innerText||e(b)).indexOf(a)>-1}}),lang:ia(function(a){return W.test(a||"")||ga.error("unsupported lang: "+a),a=a.replace(ca,da).toLowerCase(),function(b){var c;do if(c=p?b.lang:b.getAttribute("xml:lang")||b.getAttribute("lang"))return c=c.toLowerCase(),c===a||0===c.indexOf(a+"-");while((b=b.parentNode)&&1===b.nodeType);return!1}}),target:function(b){var c=a.location&&a.location.hash;return c&&c.slice(1)===b.id},root:function(a){return a===o},focus:function(a){return a===n.activeElement&&(!n.hasFocus||n.hasFocus())&&!!(a.type||a.href||~a.tabIndex)},enabled:function(a){return a.disabled===!1},disabled:function(a){return a.disabled===!0},checked:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&!!a.checked||"option"===b&&!!a.selected},selected:function(a){return a.parentNode&&a.parentNode.selectedIndex,a.selected===!0},empty:function(a){for(a=a.firstChild;a;a=a.nextSibling)if(a.nodeType<6)return!1;return!0},parent:function(a){return!d.pseudos.empty(a)},header:function(a){return Z.test(a.nodeName)},input:function(a){return Y.test(a.nodeName)},button:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&"button"===a.type||"button"===b},text:function(a){var b;return"input"===a.nodeName.toLowerCase()&&"text"===a.type&&(null==(b=a.getAttribute("type"))||"text"===b.toLowerCase())},first:oa(function(){return[0]}),last:oa(function(a,b){return[b-1]}),eq:oa(function(a,b,c){return[0>c?c+b:c]}),even:oa(function(a,b){for(var c=0;b>c;c+=2)a.push(c);return a}),odd:oa(function(a,b){for(var c=1;b>c;c+=2)a.push(c);return a}),lt:oa(function(a,b,c){for(var d=0>c?c+b:c;--d>=0;)a.push(d);return a}),gt:oa(function(a,b,c){for(var d=0>c?c+b:c;++db;b++)d+=a[b].value;return d}function sa(a,b,c){var d=b.dir,e=c&&"parentNode"===d,f=x++;return b.first?function(b,c,f){while(b=b[d])if(1===b.nodeType||e)return a(b,c,f)}:function(b,c,g){var h,i,j=[w,f];if(g){while(b=b[d])if((1===b.nodeType||e)&&a(b,c,g))return!0}else while(b=b[d])if(1===b.nodeType||e){if(i=b[u]||(b[u]={}),(h=i[d])&&h[0]===w&&h[1]===f)return j[2]=h[2];if(i[d]=j,j[2]=a(b,c,g))return!0}}}function ta(a){return a.length>1?function(b,c,d){var e=a.length;while(e--)if(!a[e](b,c,d))return!1;return!0}:a[0]}function ua(a,b,c){for(var d=0,e=b.length;e>d;d++)ga(a,b[d],c);return c}function va(a,b,c,d,e){for(var f,g=[],h=0,i=a.length,j=null!=b;i>h;h++)(f=a[h])&&(!c||c(f,d,e))&&(g.push(f),j&&b.push(h));return g}function wa(a,b,c,d,e,f){return d&&!d[u]&&(d=wa(d)),e&&!e[u]&&(e=wa(e,f)),ia(function(f,g,h,i){var j,k,l,m=[],n=[],o=g.length,p=f||ua(b||"*",h.nodeType?[h]:h,[]),q=!a||!f&&b?p:va(p,m,a,h,i),r=c?e||(f?a:o||d)?[]:g:q;if(c&&c(q,r,h,i),d){j=va(r,n),d(j,[],h,i),k=j.length;while(k--)(l=j[k])&&(r[n[k]]=!(q[n[k]]=l))}if(f){if(e||a){if(e){j=[],k=r.length;while(k--)(l=r[k])&&j.push(q[k]=l);e(null,r=[],j,i)}k=r.length;while(k--)(l=r[k])&&(j=e?J(f,l):m[k])>-1&&(f[j]=!(g[j]=l))}}else r=va(r===g?r.splice(o,r.length):r),e?e(null,g,r,i):H.apply(g,r)})}function xa(a){for(var b,c,e,f=a.length,g=d.relative[a[0].type],h=g||d.relative[" "],i=g?1:0,k=sa(function(a){return a===b},h,!0),l=sa(function(a){return J(b,a)>-1},h,!0),m=[function(a,c,d){var e=!g&&(d||c!==j)||((b=c).nodeType?k(a,c,d):l(a,c,d));return b=null,e}];f>i;i++)if(c=d.relative[a[i].type])m=[sa(ta(m),c)];else{if(c=d.filter[a[i].type].apply(null,a[i].matches),c[u]){for(e=++i;f>e;e++)if(d.relative[a[e].type])break;return wa(i>1&&ta(m),i>1&&ra(a.slice(0,i-1).concat({value:" "===a[i-2].type?"*":""})).replace(R,"$1"),c,e>i&&xa(a.slice(i,e)),f>e&&xa(a=a.slice(e)),f>e&&ra(a))}m.push(c)}return ta(m)}function ya(a,b){var c=b.length>0,e=a.length>0,f=function(f,g,h,i,k){var l,m,o,p=0,q="0",r=f&&[],s=[],t=j,u=f||e&&d.find.TAG("*",k),v=w+=null==t?1:Math.random()||.1,x=u.length;for(k&&(j=g!==n&&g);q!==x&&null!=(l=u[q]);q++){if(e&&l){m=0;while(o=a[m++])if(o(l,g,h)){i.push(l);break}k&&(w=v)}c&&((l=!o&&l)&&p--,f&&r.push(l))}if(p+=q,c&&q!==p){m=0;while(o=b[m++])o(r,s,g,h);if(f){if(p>0)while(q--)r[q]||s[q]||(s[q]=F.call(i));s=va(s)}H.apply(i,s),k&&!f&&s.length>0&&p+b.length>1&&ga.uniqueSort(i)}return k&&(w=v,j=t),r};return c?ia(f):f}return h=ga.compile=function(a,b){var c,d=[],e=[],f=A[a+" "];if(!f){b||(b=g(a)),c=b.length;while(c--)f=xa(b[c]),f[u]?d.push(f):e.push(f);f=A(a,ya(e,d)),f.selector=a}return f},i=ga.select=function(a,b,e,f){var i,j,k,l,m,n="function"==typeof a&&a,o=!f&&g(a=n.selector||a);if(e=e||[],1===o.length){if(j=o[0]=o[0].slice(0),j.length>2&&"ID"===(k=j[0]).type&&c.getById&&9===b.nodeType&&p&&d.relative[j[1].type]){if(b=(d.find.ID(k.matches[0].replace(ca,da),b)||[])[0],!b)return e;n&&(b=b.parentNode),a=a.slice(j.shift().value.length)}i=X.needsContext.test(a)?0:j.length;while(i--){if(k=j[i],d.relative[l=k.type])break;if((m=d.find[l])&&(f=m(k.matches[0].replace(ca,da),aa.test(j[0].type)&&pa(b.parentNode)||b))){if(j.splice(i,1),a=f.length&&ra(j),!a)return H.apply(e,f),e;break}}}return(n||h(a,o))(f,b,!p,e,aa.test(a)&&pa(b.parentNode)||b),e},c.sortStable=u.split("").sort(B).join("")===u,c.detectDuplicates=!!l,m(),c.sortDetached=ja(function(a){return 1&a.compareDocumentPosition(n.createElement("div"))}),ja(function(a){return a.innerHTML="","#"===a.firstChild.getAttribute("href")})||ka("type|href|height|width",function(a,b,c){return c?void 0:a.getAttribute(b,"type"===b.toLowerCase()?1:2)}),c.attributes&&ja(function(a){return a.innerHTML="",a.firstChild.setAttribute("value",""),""===a.firstChild.getAttribute("value")})||ka("value",function(a,b,c){return c||"input"!==a.nodeName.toLowerCase()?void 0:a.defaultValue}),ja(function(a){return null==a.getAttribute("disabled")})||ka(K,function(a,b,c){var d;return c?void 0:a[b]===!0?b.toLowerCase():(d=a.getAttributeNode(b))&&d.specified?d.value:null}),ga}(a);n.find=t,n.expr=t.selectors,n.expr[":"]=n.expr.pseudos,n.unique=t.uniqueSort,n.text=t.getText,n.isXMLDoc=t.isXML,n.contains=t.contains;var u=n.expr.match.needsContext,v=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,w=/^.[^:#\[\.,]*$/;function x(a,b,c){if(n.isFunction(b))return n.grep(a,function(a,d){return!!b.call(a,d,a)!==c});if(b.nodeType)return n.grep(a,function(a){return a===b!==c});if("string"==typeof b){if(w.test(b))return n.filter(b,a,c);b=n.filter(b,a)}return n.grep(a,function(a){return g.call(b,a)>=0!==c})}n.filter=function(a,b,c){var d=b[0];return c&&(a=":not("+a+")"),1===b.length&&1===d.nodeType?n.find.matchesSelector(d,a)?[d]:[]:n.find.matches(a,n.grep(b,function(a){return 1===a.nodeType}))},n.fn.extend({find:function(a){var b,c=this.length,d=[],e=this;if("string"!=typeof a)return this.pushStack(n(a).filter(function(){for(b=0;c>b;b++)if(n.contains(e[b],this))return!0}));for(b=0;c>b;b++)n.find(a,e[b],d);return d=this.pushStack(c>1?n.unique(d):d),d.selector=this.selector?this.selector+" "+a:a,d},filter:function(a){return this.pushStack(x(this,a||[],!1))},not:function(a){return this.pushStack(x(this,a||[],!0))},is:function(a){return!!x(this,"string"==typeof a&&u.test(a)?n(a):a||[],!1).length}});var y,z=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/,A=n.fn.init=function(a,b){var c,d;if(!a)return this;if("string"==typeof a){if(c="<"===a[0]&&">"===a[a.length-1]&&a.length>=3?[null,a,null]:z.exec(a),!c||!c[1]&&b)return!b||b.jquery?(b||y).find(a):this.constructor(b).find(a);if(c[1]){if(b=b instanceof n?b[0]:b,n.merge(this,n.parseHTML(c[1],b&&b.nodeType?b.ownerDocument||b:l,!0)),v.test(c[1])&&n.isPlainObject(b))for(c in b)n.isFunction(this[c])?this[c](b[c]):this.attr(c,b[c]);return this}return d=l.getElementById(c[2]),d&&d.parentNode&&(this.length=1,this[0]=d),this.context=l,this.selector=a,this}return a.nodeType?(this.context=this[0]=a,this.length=1,this):n.isFunction(a)?"undefined"!=typeof y.ready?y.ready(a):a(n):(void 0!==a.selector&&(this.selector=a.selector,this.context=a.context),n.makeArray(a,this))};A.prototype=n.fn,y=n(l);var B=/^(?:parents|prev(?:Until|All))/,C={children:!0,contents:!0,next:!0,prev:!0};n.extend({dir:function(a,b,c){var d=[],e=void 0!==c;while((a=a[b])&&9!==a.nodeType)if(1===a.nodeType){if(e&&n(a).is(c))break;d.push(a)}return d},sibling:function(a,b){for(var c=[];a;a=a.nextSibling)1===a.nodeType&&a!==b&&c.push(a);return c}}),n.fn.extend({has:function(a){var b=n(a,this),c=b.length;return this.filter(function(){for(var a=0;c>a;a++)if(n.contains(this,b[a]))return!0})},closest:function(a,b){for(var c,d=0,e=this.length,f=[],g=u.test(a)||"string"!=typeof a?n(a,b||this.context):0;e>d;d++)for(c=this[d];c&&c!==b;c=c.parentNode)if(c.nodeType<11&&(g?g.index(c)>-1:1===c.nodeType&&n.find.matchesSelector(c,a))){f.push(c);break}return this.pushStack(f.length>1?n.unique(f):f)},index:function(a){return a?"string"==typeof a?g.call(n(a),this[0]):g.call(this,a.jquery?a[0]:a):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(a,b){return this.pushStack(n.unique(n.merge(this.get(),n(a,b))))},addBack:function(a){return this.add(null==a?this.prevObject:this.prevObject.filter(a))}});function D(a,b){while((a=a[b])&&1!==a.nodeType);return a}n.each({parent:function(a){var b=a.parentNode;return b&&11!==b.nodeType?b:null},parents:function(a){return n.dir(a,"parentNode")},parentsUntil:function(a,b,c){return n.dir(a,"parentNode",c)},next:function(a){return D(a,"nextSibling")},prev:function(a){return D(a,"previousSibling")},nextAll:function(a){return n.dir(a,"nextSibling")},prevAll:function(a){return n.dir(a,"previousSibling")},nextUntil:function(a,b,c){return n.dir(a,"nextSibling",c)},prevUntil:function(a,b,c){return n.dir(a,"previousSibling",c)},siblings:function(a){return n.sibling((a.parentNode||{}).firstChild,a)},children:function(a){return n.sibling(a.firstChild)},contents:function(a){return a.contentDocument||n.merge([],a.childNodes)}},function(a,b){n.fn[a]=function(c,d){var e=n.map(this,b,c);return"Until"!==a.slice(-5)&&(d=c),d&&"string"==typeof d&&(e=n.filter(d,e)),this.length>1&&(C[a]||n.unique(e),B.test(a)&&e.reverse()),this.pushStack(e)}});var E=/\S+/g,F={};function G(a){var b=F[a]={};return n.each(a.match(E)||[],function(a,c){b[c]=!0}),b}n.Callbacks=function(a){a="string"==typeof a?F[a]||G(a):n.extend({},a);var b,c,d,e,f,g,h=[],i=!a.once&&[],j=function(l){for(b=a.memory&&l,c=!0,g=e||0,e=0,f=h.length,d=!0;h&&f>g;g++)if(h[g].apply(l[0],l[1])===!1&&a.stopOnFalse){b=!1;break}d=!1,h&&(i?i.length&&j(i.shift()):b?h=[]:k.disable())},k={add:function(){if(h){var c=h.length;!function g(b){n.each(b,function(b,c){var d=n.type(c);"function"===d?a.unique&&k.has(c)||h.push(c):c&&c.length&&"string"!==d&&g(c)})}(arguments),d?f=h.length:b&&(e=c,j(b))}return this},remove:function(){return h&&n.each(arguments,function(a,b){var c;while((c=n.inArray(b,h,c))>-1)h.splice(c,1),d&&(f>=c&&f--,g>=c&&g--)}),this},has:function(a){return a?n.inArray(a,h)>-1:!(!h||!h.length)},empty:function(){return h=[],f=0,this},disable:function(){return h=i=b=void 0,this},disabled:function(){return!h},lock:function(){return i=void 0,b||k.disable(),this},locked:function(){return!i},fireWith:function(a,b){return!h||c&&!i||(b=b||[],b=[a,b.slice?b.slice():b],d?i.push(b):j(b)),this},fire:function(){return k.fireWith(this,arguments),this},fired:function(){return!!c}};return k},n.extend({Deferred:function(a){var b=[["resolve","done",n.Callbacks("once memory"),"resolved"],["reject","fail",n.Callbacks("once memory"),"rejected"],["notify","progress",n.Callbacks("memory")]],c="pending",d={state:function(){return c},always:function(){return e.done(arguments).fail(arguments),this},then:function(){var a=arguments;return n.Deferred(function(c){n.each(b,function(b,f){var g=n.isFunction(a[b])&&a[b];e[f[1]](function(){var a=g&&g.apply(this,arguments);a&&n.isFunction(a.promise)?a.promise().done(c.resolve).fail(c.reject).progress(c.notify):c[f[0]+"With"](this===d?c.promise():this,g?[a]:arguments)})}),a=null}).promise()},promise:function(a){return null!=a?n.extend(a,d):d}},e={};return d.pipe=d.then,n.each(b,function(a,f){var g=f[2],h=f[3];d[f[1]]=g.add,h&&g.add(function(){c=h},b[1^a][2].disable,b[2][2].lock),e[f[0]]=function(){return e[f[0]+"With"](this===e?d:this,arguments),this},e[f[0]+"With"]=g.fireWith}),d.promise(e),a&&a.call(e,e),e},when:function(a){var b=0,c=d.call(arguments),e=c.length,f=1!==e||a&&n.isFunction(a.promise)?e:0,g=1===f?a:n.Deferred(),h=function(a,b,c){return function(e){b[a]=this,c[a]=arguments.length>1?d.call(arguments):e,c===i?g.notifyWith(b,c):--f||g.resolveWith(b,c)}},i,j,k;if(e>1)for(i=new Array(e),j=new Array(e),k=new Array(e);e>b;b++)c[b]&&n.isFunction(c[b].promise)?c[b].promise().done(h(b,k,c)).fail(g.reject).progress(h(b,j,i)):--f;return f||g.resolveWith(k,c),g.promise()}});var H;n.fn.ready=function(a){return n.ready.promise().done(a),this},n.extend({isReady:!1,readyWait:1,holdReady:function(a){a?n.readyWait++:n.ready(!0)},ready:function(a){(a===!0?--n.readyWait:n.isReady)||(n.isReady=!0,a!==!0&&--n.readyWait>0||(H.resolveWith(l,[n]),n.fn.triggerHandler&&(n(l).triggerHandler("ready"),n(l).off("ready"))))}});function I(){l.removeEventListener("DOMContentLoaded",I,!1),a.removeEventListener("load",I,!1),n.ready()}n.ready.promise=function(b){return H||(H=n.Deferred(),"complete"===l.readyState?setTimeout(n.ready):(l.addEventListener("DOMContentLoaded",I,!1),a.addEventListener("load",I,!1))),H.promise(b)},n.ready.promise();var J=n.access=function(a,b,c,d,e,f,g){var h=0,i=a.length,j=null==c;if("object"===n.type(c)){e=!0;for(h in c)n.access(a,b,h,c[h],!0,f,g)}else if(void 0!==d&&(e=!0,n.isFunction(d)||(g=!0),j&&(g?(b.call(a,d),b=null):(j=b,b=function(a,b,c){return j.call(n(a),c)})),b))for(;i>h;h++)b(a[h],c,g?d:d.call(a[h],h,b(a[h],c)));return e?a:j?b.call(a):i?b(a[0],c):f};n.acceptData=function(a){return 1===a.nodeType||9===a.nodeType||!+a.nodeType};function K(){Object.defineProperty(this.cache={},0,{get:function(){return{}}}),this.expando=n.expando+K.uid++}K.uid=1,K.accepts=n.acceptData,K.prototype={key:function(a){if(!K.accepts(a))return 0;var b={},c=a[this.expando];if(!c){c=K.uid++;try{b[this.expando]={value:c},Object.defineProperties(a,b)}catch(d){b[this.expando]=c,n.extend(a,b)}}return this.cache[c]||(this.cache[c]={}),c},set:function(a,b,c){var d,e=this.key(a),f=this.cache[e];if("string"==typeof b)f[b]=c;else if(n.isEmptyObject(f))n.extend(this.cache[e],b);else for(d in b)f[d]=b[d];return f},get:function(a,b){var c=this.cache[this.key(a)];return void 0===b?c:c[b]},access:function(a,b,c){var d;return void 0===b||b&&"string"==typeof b&&void 0===c?(d=this.get(a,b),void 0!==d?d:this.get(a,n.camelCase(b))):(this.set(a,b,c),void 0!==c?c:b)},remove:function(a,b){var c,d,e,f=this.key(a),g=this.cache[f];if(void 0===b)this.cache[f]={};else{n.isArray(b)?d=b.concat(b.map(n.camelCase)):(e=n.camelCase(b),b in g?d=[b,e]:(d=e,d=d in g?[d]:d.match(E)||[])),c=d.length;while(c--)delete g[d[c]]}},hasData:function(a){return!n.isEmptyObject(this.cache[a[this.expando]]||{})},discard:function(a){a[this.expando]&&delete this.cache[a[this.expando]]}};var L=new K,M=new K,N=/^(?:\{[\w\W]*\}|\[[\w\W]*\])$/,O=/([A-Z])/g;function P(a,b,c){var d;if(void 0===c&&1===a.nodeType)if(d="data-"+b.replace(O,"-$1").toLowerCase(),c=a.getAttribute(d),"string"==typeof c){try{c="true"===c?!0:"false"===c?!1:"null"===c?null:+c+""===c?+c:N.test(c)?n.parseJSON(c):c}catch(e){}M.set(a,b,c)}else c=void 0;return c}n.extend({hasData:function(a){return M.hasData(a)||L.hasData(a)},data:function(a,b,c){ -return M.access(a,b,c)},removeData:function(a,b){M.remove(a,b)},_data:function(a,b,c){return L.access(a,b,c)},_removeData:function(a,b){L.remove(a,b)}}),n.fn.extend({data:function(a,b){var c,d,e,f=this[0],g=f&&f.attributes;if(void 0===a){if(this.length&&(e=M.get(f),1===f.nodeType&&!L.get(f,"hasDataAttrs"))){c=g.length;while(c--)g[c]&&(d=g[c].name,0===d.indexOf("data-")&&(d=n.camelCase(d.slice(5)),P(f,d,e[d])));L.set(f,"hasDataAttrs",!0)}return e}return"object"==typeof a?this.each(function(){M.set(this,a)}):J(this,function(b){var c,d=n.camelCase(a);if(f&&void 0===b){if(c=M.get(f,a),void 0!==c)return c;if(c=M.get(f,d),void 0!==c)return c;if(c=P(f,d,void 0),void 0!==c)return c}else this.each(function(){var c=M.get(this,d);M.set(this,d,b),-1!==a.indexOf("-")&&void 0!==c&&M.set(this,a,b)})},null,b,arguments.length>1,null,!0)},removeData:function(a){return this.each(function(){M.remove(this,a)})}}),n.extend({queue:function(a,b,c){var d;return a?(b=(b||"fx")+"queue",d=L.get(a,b),c&&(!d||n.isArray(c)?d=L.access(a,b,n.makeArray(c)):d.push(c)),d||[]):void 0},dequeue:function(a,b){b=b||"fx";var c=n.queue(a,b),d=c.length,e=c.shift(),f=n._queueHooks(a,b),g=function(){n.dequeue(a,b)};"inprogress"===e&&(e=c.shift(),d--),e&&("fx"===b&&c.unshift("inprogress"),delete f.stop,e.call(a,g,f)),!d&&f&&f.empty.fire()},_queueHooks:function(a,b){var c=b+"queueHooks";return L.get(a,c)||L.access(a,c,{empty:n.Callbacks("once memory").add(function(){L.remove(a,[b+"queue",c])})})}}),n.fn.extend({queue:function(a,b){var c=2;return"string"!=typeof a&&(b=a,a="fx",c--),arguments.lengthx",k.noCloneChecked=!!b.cloneNode(!0).lastChild.defaultValue}();var U="undefined";k.focusinBubbles="onfocusin"in a;var V=/^key/,W=/^(?:mouse|pointer|contextmenu)|click/,X=/^(?:focusinfocus|focusoutblur)$/,Y=/^([^.]*)(?:\.(.+)|)$/;function Z(){return!0}function $(){return!1}function _(){try{return l.activeElement}catch(a){}}n.event={global:{},add:function(a,b,c,d,e){var f,g,h,i,j,k,l,m,o,p,q,r=L.get(a);if(r){c.handler&&(f=c,c=f.handler,e=f.selector),c.guid||(c.guid=n.guid++),(i=r.events)||(i=r.events={}),(g=r.handle)||(g=r.handle=function(b){return typeof n!==U&&n.event.triggered!==b.type?n.event.dispatch.apply(a,arguments):void 0}),b=(b||"").match(E)||[""],j=b.length;while(j--)h=Y.exec(b[j])||[],o=q=h[1],p=(h[2]||"").split(".").sort(),o&&(l=n.event.special[o]||{},o=(e?l.delegateType:l.bindType)||o,l=n.event.special[o]||{},k=n.extend({type:o,origType:q,data:d,handler:c,guid:c.guid,selector:e,needsContext:e&&n.expr.match.needsContext.test(e),namespace:p.join(".")},f),(m=i[o])||(m=i[o]=[],m.delegateCount=0,l.setup&&l.setup.call(a,d,p,g)!==!1||a.addEventListener&&a.addEventListener(o,g,!1)),l.add&&(l.add.call(a,k),k.handler.guid||(k.handler.guid=c.guid)),e?m.splice(m.delegateCount++,0,k):m.push(k),n.event.global[o]=!0)}},remove:function(a,b,c,d,e){var f,g,h,i,j,k,l,m,o,p,q,r=L.hasData(a)&&L.get(a);if(r&&(i=r.events)){b=(b||"").match(E)||[""],j=b.length;while(j--)if(h=Y.exec(b[j])||[],o=q=h[1],p=(h[2]||"").split(".").sort(),o){l=n.event.special[o]||{},o=(d?l.delegateType:l.bindType)||o,m=i[o]||[],h=h[2]&&new RegExp("(^|\\.)"+p.join("\\.(?:.*\\.|)")+"(\\.|$)"),g=f=m.length;while(f--)k=m[f],!e&&q!==k.origType||c&&c.guid!==k.guid||h&&!h.test(k.namespace)||d&&d!==k.selector&&("**"!==d||!k.selector)||(m.splice(f,1),k.selector&&m.delegateCount--,l.remove&&l.remove.call(a,k));g&&!m.length&&(l.teardown&&l.teardown.call(a,p,r.handle)!==!1||n.removeEvent(a,o,r.handle),delete i[o])}else for(o in i)n.event.remove(a,o+b[j],c,d,!0);n.isEmptyObject(i)&&(delete r.handle,L.remove(a,"events"))}},trigger:function(b,c,d,e){var f,g,h,i,k,m,o,p=[d||l],q=j.call(b,"type")?b.type:b,r=j.call(b,"namespace")?b.namespace.split("."):[];if(g=h=d=d||l,3!==d.nodeType&&8!==d.nodeType&&!X.test(q+n.event.triggered)&&(q.indexOf(".")>=0&&(r=q.split("."),q=r.shift(),r.sort()),k=q.indexOf(":")<0&&"on"+q,b=b[n.expando]?b:new n.Event(q,"object"==typeof b&&b),b.isTrigger=e?2:3,b.namespace=r.join("."),b.namespace_re=b.namespace?new RegExp("(^|\\.)"+r.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,b.result=void 0,b.target||(b.target=d),c=null==c?[b]:n.makeArray(c,[b]),o=n.event.special[q]||{},e||!o.trigger||o.trigger.apply(d,c)!==!1)){if(!e&&!o.noBubble&&!n.isWindow(d)){for(i=o.delegateType||q,X.test(i+q)||(g=g.parentNode);g;g=g.parentNode)p.push(g),h=g;h===(d.ownerDocument||l)&&p.push(h.defaultView||h.parentWindow||a)}f=0;while((g=p[f++])&&!b.isPropagationStopped())b.type=f>1?i:o.bindType||q,m=(L.get(g,"events")||{})[b.type]&&L.get(g,"handle"),m&&m.apply(g,c),m=k&&g[k],m&&m.apply&&n.acceptData(g)&&(b.result=m.apply(g,c),b.result===!1&&b.preventDefault());return b.type=q,e||b.isDefaultPrevented()||o._default&&o._default.apply(p.pop(),c)!==!1||!n.acceptData(d)||k&&n.isFunction(d[q])&&!n.isWindow(d)&&(h=d[k],h&&(d[k]=null),n.event.triggered=q,d[q](),n.event.triggered=void 0,h&&(d[k]=h)),b.result}},dispatch:function(a){a=n.event.fix(a);var b,c,e,f,g,h=[],i=d.call(arguments),j=(L.get(this,"events")||{})[a.type]||[],k=n.event.special[a.type]||{};if(i[0]=a,a.delegateTarget=this,!k.preDispatch||k.preDispatch.call(this,a)!==!1){h=n.event.handlers.call(this,a,j),b=0;while((f=h[b++])&&!a.isPropagationStopped()){a.currentTarget=f.elem,c=0;while((g=f.handlers[c++])&&!a.isImmediatePropagationStopped())(!a.namespace_re||a.namespace_re.test(g.namespace))&&(a.handleObj=g,a.data=g.data,e=((n.event.special[g.origType]||{}).handle||g.handler).apply(f.elem,i),void 0!==e&&(a.result=e)===!1&&(a.preventDefault(),a.stopPropagation()))}return k.postDispatch&&k.postDispatch.call(this,a),a.result}},handlers:function(a,b){var c,d,e,f,g=[],h=b.delegateCount,i=a.target;if(h&&i.nodeType&&(!a.button||"click"!==a.type))for(;i!==this;i=i.parentNode||this)if(i.disabled!==!0||"click"!==a.type){for(d=[],c=0;h>c;c++)f=b[c],e=f.selector+" ",void 0===d[e]&&(d[e]=f.needsContext?n(e,this).index(i)>=0:n.find(e,this,null,[i]).length),d[e]&&d.push(f);d.length&&g.push({elem:i,handlers:d})}return h]*)\/>/gi,ba=/<([\w:]+)/,ca=/<|&#?\w+;/,da=/<(?:script|style|link)/i,ea=/checked\s*(?:[^=]|=\s*.checked.)/i,fa=/^$|\/(?:java|ecma)script/i,ga=/^true\/(.*)/,ha=/^\s*\s*$/g,ia={option:[1,""],thead:[1,"","
    "],col:[2,"","
    "],tr:[2,"","
    "],td:[3,"","
    "],_default:[0,"",""]};ia.optgroup=ia.option,ia.tbody=ia.tfoot=ia.colgroup=ia.caption=ia.thead,ia.th=ia.td;function ja(a,b){return n.nodeName(a,"table")&&n.nodeName(11!==b.nodeType?b:b.firstChild,"tr")?a.getElementsByTagName("tbody")[0]||a.appendChild(a.ownerDocument.createElement("tbody")):a}function ka(a){return a.type=(null!==a.getAttribute("type"))+"/"+a.type,a}function la(a){var b=ga.exec(a.type);return b?a.type=b[1]:a.removeAttribute("type"),a}function ma(a,b){for(var c=0,d=a.length;d>c;c++)L.set(a[c],"globalEval",!b||L.get(b[c],"globalEval"))}function na(a,b){var c,d,e,f,g,h,i,j;if(1===b.nodeType){if(L.hasData(a)&&(f=L.access(a),g=L.set(b,f),j=f.events)){delete g.handle,g.events={};for(e in j)for(c=0,d=j[e].length;d>c;c++)n.event.add(b,e,j[e][c])}M.hasData(a)&&(h=M.access(a),i=n.extend({},h),M.set(b,i))}}function oa(a,b){var c=a.getElementsByTagName?a.getElementsByTagName(b||"*"):a.querySelectorAll?a.querySelectorAll(b||"*"):[];return void 0===b||b&&n.nodeName(a,b)?n.merge([a],c):c}function pa(a,b){var c=b.nodeName.toLowerCase();"input"===c&&T.test(a.type)?b.checked=a.checked:("input"===c||"textarea"===c)&&(b.defaultValue=a.defaultValue)}n.extend({clone:function(a,b,c){var d,e,f,g,h=a.cloneNode(!0),i=n.contains(a.ownerDocument,a);if(!(k.noCloneChecked||1!==a.nodeType&&11!==a.nodeType||n.isXMLDoc(a)))for(g=oa(h),f=oa(a),d=0,e=f.length;e>d;d++)pa(f[d],g[d]);if(b)if(c)for(f=f||oa(a),g=g||oa(h),d=0,e=f.length;e>d;d++)na(f[d],g[d]);else na(a,h);return g=oa(h,"script"),g.length>0&&ma(g,!i&&oa(a,"script")),h},buildFragment:function(a,b,c,d){for(var e,f,g,h,i,j,k=b.createDocumentFragment(),l=[],m=0,o=a.length;o>m;m++)if(e=a[m],e||0===e)if("object"===n.type(e))n.merge(l,e.nodeType?[e]:e);else if(ca.test(e)){f=f||k.appendChild(b.createElement("div")),g=(ba.exec(e)||["",""])[1].toLowerCase(),h=ia[g]||ia._default,f.innerHTML=h[1]+e.replace(aa,"<$1>")+h[2],j=h[0];while(j--)f=f.lastChild;n.merge(l,f.childNodes),f=k.firstChild,f.textContent=""}else l.push(b.createTextNode(e));k.textContent="",m=0;while(e=l[m++])if((!d||-1===n.inArray(e,d))&&(i=n.contains(e.ownerDocument,e),f=oa(k.appendChild(e),"script"),i&&ma(f),c)){j=0;while(e=f[j++])fa.test(e.type||"")&&c.push(e)}return k},cleanData:function(a){for(var b,c,d,e,f=n.event.special,g=0;void 0!==(c=a[g]);g++){if(n.acceptData(c)&&(e=c[L.expando],e&&(b=L.cache[e]))){if(b.events)for(d in b.events)f[d]?n.event.remove(c,d):n.removeEvent(c,d,b.handle);L.cache[e]&&delete L.cache[e]}delete M.cache[c[M.expando]]}}}),n.fn.extend({text:function(a){return J(this,function(a){return void 0===a?n.text(this):this.empty().each(function(){(1===this.nodeType||11===this.nodeType||9===this.nodeType)&&(this.textContent=a)})},null,a,arguments.length)},append:function(){return this.domManip(arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=ja(this,a);b.appendChild(a)}})},prepend:function(){return this.domManip(arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=ja(this,a);b.insertBefore(a,b.firstChild)}})},before:function(){return this.domManip(arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this)})},after:function(){return this.domManip(arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this.nextSibling)})},remove:function(a,b){for(var c,d=a?n.filter(a,this):this,e=0;null!=(c=d[e]);e++)b||1!==c.nodeType||n.cleanData(oa(c)),c.parentNode&&(b&&n.contains(c.ownerDocument,c)&&ma(oa(c,"script")),c.parentNode.removeChild(c));return this},empty:function(){for(var a,b=0;null!=(a=this[b]);b++)1===a.nodeType&&(n.cleanData(oa(a,!1)),a.textContent="");return this},clone:function(a,b){return a=null==a?!1:a,b=null==b?a:b,this.map(function(){return n.clone(this,a,b)})},html:function(a){return J(this,function(a){var b=this[0]||{},c=0,d=this.length;if(void 0===a&&1===b.nodeType)return b.innerHTML;if("string"==typeof a&&!da.test(a)&&!ia[(ba.exec(a)||["",""])[1].toLowerCase()]){a=a.replace(aa,"<$1>");try{for(;d>c;c++)b=this[c]||{},1===b.nodeType&&(n.cleanData(oa(b,!1)),b.innerHTML=a);b=0}catch(e){}}b&&this.empty().append(a)},null,a,arguments.length)},replaceWith:function(){var a=arguments[0];return this.domManip(arguments,function(b){a=this.parentNode,n.cleanData(oa(this)),a&&a.replaceChild(b,this)}),a&&(a.length||a.nodeType)?this:this.remove()},detach:function(a){return this.remove(a,!0)},domManip:function(a,b){a=e.apply([],a);var c,d,f,g,h,i,j=0,l=this.length,m=this,o=l-1,p=a[0],q=n.isFunction(p);if(q||l>1&&"string"==typeof p&&!k.checkClone&&ea.test(p))return this.each(function(c){var d=m.eq(c);q&&(a[0]=p.call(this,c,d.html())),d.domManip(a,b)});if(l&&(c=n.buildFragment(a,this[0].ownerDocument,!1,this),d=c.firstChild,1===c.childNodes.length&&(c=d),d)){for(f=n.map(oa(c,"script"),ka),g=f.length;l>j;j++)h=c,j!==o&&(h=n.clone(h,!0,!0),g&&n.merge(f,oa(h,"script"))),b.call(this[j],h,j);if(g)for(i=f[f.length-1].ownerDocument,n.map(f,la),j=0;g>j;j++)h=f[j],fa.test(h.type||"")&&!L.access(h,"globalEval")&&n.contains(i,h)&&(h.src?n._evalUrl&&n._evalUrl(h.src):n.globalEval(h.textContent.replace(ha,"")))}return this}}),n.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){n.fn[a]=function(a){for(var c,d=[],e=n(a),g=e.length-1,h=0;g>=h;h++)c=h===g?this:this.clone(!0),n(e[h])[b](c),f.apply(d,c.get());return this.pushStack(d)}});var qa,ra={};function sa(b,c){var d,e=n(c.createElement(b)).appendTo(c.body),f=a.getDefaultComputedStyle&&(d=a.getDefaultComputedStyle(e[0]))?d.display:n.css(e[0],"display");return e.detach(),f}function ta(a){var b=l,c=ra[a];return c||(c=sa(a,b),"none"!==c&&c||(qa=(qa||n("