From 27d3b493fa9f0fc281945f06d65489a1c77c1738 Mon Sep 17 00:00:00 2001 From: Simon Walton Date: Wed, 20 Nov 2019 16:15:39 -0800 Subject: [PATCH 01/97] Initial Linux GHA build --- .github/workflows/cmake.yml | 39 +++++++++++++++++++++++++++ CMakeLists.txt | 4 ++- assignment-client/CMakeLists.txt | 30 +++++++++++---------- tools/ci-scripts/linux-gha/Dockerfile | 30 +++++++++++++++++++++ 4 files changed, 88 insertions(+), 15 deletions(-) create mode 100644 tools/ci-scripts/linux-gha/Dockerfile diff --git a/.github/workflows/cmake.yml b/.github/workflows/cmake.yml index 1d49cd8ae7..db677f60cb 100644 --- a/.github/workflows/cmake.yml +++ b/.github/workflows/cmake.yml @@ -246,3 +246,42 @@ jobs: AWS_SECRET_ACCESS_KEY: ${{ secrets.aws_secret_access_key }} ARTIFACT_PATTERN: HighFidelity-Beta-PR${{ github.event.number }}-*.exe run: python "$GITHUB_WORKSPACE\tools\ci-scripts\upload.py" + build_full_linux: + runs-on: ubuntu-latest + if: github.event.action != 'labeled' || github.event.label.name == 'rebuild-win' || github.event.label.name == 'rebuild' + env: + DOCKER_IMAGE_NAME: "linux-hifi-gha:${{ github.event.number }}" + steps: + - uses: actions/checkout@v1 + with: + submodules: true + fetch-depth: 1 + - name: Install python modules + run: pip install awscli boto3 PyGithub + - name: Install apt packages + # libglu1-mesa-dev needed for oven, npm for server-console + run: sudo apt install -y mesa-common-dev libegl1 libglvnd-dev libdouble-conversion1 libpulse0 + - name: Create Build Environment + run: cmake -E make_directory ${{runner.workspace}}/build + - name: Configure CMake (Linux) + shell: bash + working-directory: ${{runner.workspace}}/build + run: cmake $GITHUB_WORKSPACE -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DBUILD_TOOLS:BOOLEAN=false + - name: Build + shell: bash + working-directory: ${{runner.workspace}}/build + # Parallel make: + run: cmake --build . -- -j3 + - name: Build Ubuntu Docker + shell: bash + working-directory: ${{runner.workspace}}/build + run: docker build -t $DOCKER_IMAGE_NAME -f $GITHUB_WORKSPACE/tools/ci-scripts/linux-gha/Dockerfile ./ + - name: Upload Docker image + shell: bash + env: + # TODO: upload to correct location + AWS_ACCESS_KEY_ID: ${{ secrets.AWS_KEY_ID }} + AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_KEY }} + run: | + docker save -o ${{runner.workspace}}/build/hifi_docker_image.tar $DOCKER_IMAGE_NAME + aws s3 cp ${{runner.workspace}}/build/hifi_docker_image.tar s3://hifi-public/simon/builds/hifi_docker_image.$GIT_PR_COMMIT_SHORT.tar diff --git a/CMakeLists.txt b/CMakeLists.txt index 8b8faed73c..6a18094e54 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -274,7 +274,9 @@ endif() if (BUILD_CLIENT OR BUILD_SERVER) add_subdirectory(plugins) - add_subdirectory(server-console) + if (NOT (${CMAKE_SYSTEM_NAME} STREQUAL "Linux" AND "$ENV{CI_BUILD}" STREQUAL "Github")) + add_subdirectory(server-console) + endif() endif() # BUILD_TOOLS option will be handled inside the tools's CMakeLists.txt because 'scribe' tool is required for build anyway diff --git a/assignment-client/CMakeLists.txt b/assignment-client/CMakeLists.txt index b4042cf294..31d8c9e5a8 100644 --- a/assignment-client/CMakeLists.txt +++ b/assignment-client/CMakeLists.txt @@ -18,21 +18,23 @@ link_hifi_libraries( ) include_hifi_library_headers(procedural) -add_dependencies(${TARGET_NAME} oven) +if (BUILD_TOOLS) + add_dependencies(${TARGET_NAME} oven) -if (WIN32) - add_custom_command( - TARGET ${TARGET_NAME} POST_BUILD - COMMAND ${CMAKE_COMMAND} -E copy_directory - $ - $) -else() - add_custom_command( - TARGET ${TARGET_NAME} POST_BUILD - COMMAND ${CMAKE_COMMAND} -E create_symlink - $ - $/oven) -endif() + if (WIN32) + add_custom_command( + TARGET ${TARGET_NAME} POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy_directory + $ + $) + else() + add_custom_command( + TARGET ${TARGET_NAME} POST_BUILD + COMMAND ${CMAKE_COMMAND} -E create_symlink + $ + $/oven) + endif() +endif (BUILD_TOOLS) if (WIN32) package_libraries_for_deployment() diff --git a/tools/ci-scripts/linux-gha/Dockerfile b/tools/ci-scripts/linux-gha/Dockerfile new file mode 100644 index 0000000000..8a1ade1d58 --- /dev/null +++ b/tools/ci-scripts/linux-gha/Dockerfile @@ -0,0 +1,30 @@ +FROM simonwalton1/hifi_base_ubuntu:1.0 +MAINTAINER DevOps Team (devops@highfidelity.io) + +EXPOSE 40100 40101 40102 +EXPOSE 40100/udp 40101/udp 40102/udp +EXPOSE 48000/udp 48001/udp 48002/udp 48003/udp 48004/udp 48005/udp 48006/udp + +RUN mkdir -p /etc/hifi/server/plugins /etc/hifi/server/resources /etc/hifi/server/imageformats/ && \ + ln -s /usr/local/Qt5.12.3/5.12.3/gcc_64/plugins/imageformats/* /etc/hifi/server/imageformats/ +COPY ./assignment-client /etc/hifi/server/ +#COPY ./oven /etc/hifi/server/ +COPY ./domain-server /etc/hifi/server/ +COPY ./plugins/hifiCodec/libhifiCodec.so /etc/hifi/server/plugins/ +COPY ./plugins/pcmCodec/libpcmCodec.so /etc/hifi/server/plugins/ +# Dummy statement +RUN true +COPY ./*.so /lib/ +RUN ln -sf /lib/libquazip5.so /lib/libquazip5.so.1 +#COPY ./resources/ /etc/hifi/server/resources/ +#COPY ./supervisor/hifi.conf /etc/supervisor/conf.d/hifi.conf +RUN for fn in /usr/local/Qt5.12.3/5.12.3/gcc_64/plugins/imageformats/*.so; do \ + if [ ! -x $fn ]; then ln -s $fn /etc/hifi/server/imageformats; fi; done +RUN chmod +x /etc/hifi/server/domain-server +RUN chmod +x /etc/hifi/server/assignment-client + +# Ensure `domain-server` and `assignment-client` execute. +RUN /etc/hifi/server/domain-server --version > /etc/hifi/server/version && \ + /etc/hifi/server/assignment-client --version >> /etc/hifi/server/version + +CMD ["/usr/bin/supervisord", "-c", "/etc/supervisor/conf.d/hifi.conf"] From 51cf9fab8e1484aa8a2c58f5284ee7922490337d Mon Sep 17 00:00:00 2001 From: Simon Walton Date: Wed, 20 Nov 2019 23:51:21 -0800 Subject: [PATCH 02/97] Take out .so copy --- tools/ci-scripts/linux-gha/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/ci-scripts/linux-gha/Dockerfile b/tools/ci-scripts/linux-gha/Dockerfile index 8a1ade1d58..4f8fe4f4e3 100644 --- a/tools/ci-scripts/linux-gha/Dockerfile +++ b/tools/ci-scripts/linux-gha/Dockerfile @@ -14,7 +14,7 @@ COPY ./plugins/hifiCodec/libhifiCodec.so /etc/hifi/server/plugins/ COPY ./plugins/pcmCodec/libpcmCodec.so /etc/hifi/server/plugins/ # Dummy statement RUN true -COPY ./*.so /lib/ +#COPY ./*.so /lib/ RUN ln -sf /lib/libquazip5.so /lib/libquazip5.so.1 #COPY ./resources/ /etc/hifi/server/resources/ #COPY ./supervisor/hifi.conf /etc/supervisor/conf.d/hifi.conf From 9e5c0a7afc2fa817461b022402d61821c79bab92 Mon Sep 17 00:00:00 2001 From: Simon Walton Date: Thu, 21 Nov 2019 15:02:08 -0800 Subject: [PATCH 03/97] Copy quazip lib to build dir; built server-console --- CMakeLists.txt | 4 +--- cmake/macros/TargetQuazip.cmake | 10 +++++++++- tools/ci-scripts/linux-gha/Dockerfile | 2 +- 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 6a18094e54..8b8faed73c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -274,9 +274,7 @@ endif() if (BUILD_CLIENT OR BUILD_SERVER) add_subdirectory(plugins) - if (NOT (${CMAKE_SYSTEM_NAME} STREQUAL "Linux" AND "$ENV{CI_BUILD}" STREQUAL "Github")) - add_subdirectory(server-console) - endif() + add_subdirectory(server-console) endif() # BUILD_TOOLS option will be handled inside the tools's CMakeLists.txt because 'scribe' tool is required for build anyway diff --git a/cmake/macros/TargetQuazip.cmake b/cmake/macros/TargetQuazip.cmake index ee57fb4af3..af89686ff6 100644 --- a/cmake/macros/TargetQuazip.cmake +++ b/cmake/macros/TargetQuazip.cmake @@ -10,4 +10,12 @@ macro(TARGET_QUAZIP) find_library(QUAZIP_LIBRARY_DEBUG quazip5 PATHS ${VCPKG_INSTALL_ROOT}/debug/lib NO_DEFAULT_PATH) select_library_configurations(QUAZIP) target_link_libraries(${TARGET_NAME} ${QUAZIP_LIBRARIES}) -endmacro() \ No newline at end of file + if (${CMAKE_SYSTEM_NAME} STREQUAL "Linux") + add_custom_command( + TARGET ${TARGET_NAME} + POST_BUILD + COMMAND cp + ARGS -d ${QUAZIP_LIBRARIES}* ${CMAKE_BINARY_DIR} + ) + endif() +endmacro() diff --git a/tools/ci-scripts/linux-gha/Dockerfile b/tools/ci-scripts/linux-gha/Dockerfile index 4f8fe4f4e3..8a1ade1d58 100644 --- a/tools/ci-scripts/linux-gha/Dockerfile +++ b/tools/ci-scripts/linux-gha/Dockerfile @@ -14,7 +14,7 @@ COPY ./plugins/hifiCodec/libhifiCodec.so /etc/hifi/server/plugins/ COPY ./plugins/pcmCodec/libpcmCodec.so /etc/hifi/server/plugins/ # Dummy statement RUN true -#COPY ./*.so /lib/ +COPY ./*.so /lib/ RUN ln -sf /lib/libquazip5.so /lib/libquazip5.so.1 #COPY ./resources/ /etc/hifi/server/resources/ #COPY ./supervisor/hifi.conf /etc/supervisor/conf.d/hifi.conf From e7091245b3b19e3ad44e3ff9420951bc4877e0f2 Mon Sep 17 00:00:00 2001 From: Zach Date: Thu, 21 Nov 2019 15:38:28 -0800 Subject: [PATCH 04/97] Fix screenshare on MacOS DEBUG builds; fix z-fighting on smartboard in screenshare mode --- interface/src/scripting/ScreenshareScriptingInterface.cpp | 4 ++-- interface/src/scripting/ScreenshareScriptingInterface.h | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/interface/src/scripting/ScreenshareScriptingInterface.cpp b/interface/src/scripting/ScreenshareScriptingInterface.cpp index 89f5ee6970..5cf4d1939a 100644 --- a/interface/src/scripting/ScreenshareScriptingInterface.cpp +++ b/interface/src/scripting/ScreenshareScriptingInterface.cpp @@ -90,7 +90,7 @@ static const EntityTypes::EntityType LOCAL_SCREENSHARE_WEB_ENTITY_TYPE = EntityT static const uint8_t LOCAL_SCREENSHARE_WEB_ENTITY_FPS = 30; // This is going to be a good amount of work to make this work dynamically for any screensize. // V1 will have only hardcoded values. -static const glm::vec3 LOCAL_SCREENSHARE_WEB_ENTITY_LOCAL_POSITION(0.0128f, -0.0918f, 0.0771f); +static const glm::vec3 LOCAL_SCREENSHARE_WEB_ENTITY_LOCAL_POSITION(0.0128f, -0.0918f, 0.0711f); static const glm::vec3 LOCAL_SCREENSHARE_WEB_ENTITY_DIMENSIONS(3.6790f, 2.0990f, 0.0100f); static const QString LOCAL_SCREENSHARE_WEB_ENTITY_URL = "https://content.highfidelity.com/Experiences/Releases/usefulUtilities/smartBoard/screenshareViewer/screenshareClient.html"; @@ -124,7 +124,7 @@ void ScreenshareScriptingInterface::startScreenshare(const QUuid& screenshareZon // Ensure that the screenshare executable exists where we expect it to. // Error out and reset the screen share state machine if the executable doesn't exist. QFileInfo screenshareExecutable(SCREENSHARE_EXE_PATH); - if (!screenshareExecutable.exists() || !screenshareExecutable.isFile()) { + if (!screenshareExecutable.exists() || !(screenshareExecutable.isFile() || screenshareExecutable.isBundle())) { qDebug() << "Screenshare executable doesn't exist at" << SCREENSHARE_EXE_PATH; stopScreenshare(); emit screenshareError(); diff --git a/interface/src/scripting/ScreenshareScriptingInterface.h b/interface/src/scripting/ScreenshareScriptingInterface.h index 22a65e169e..9dc828c13b 100644 --- a/interface/src/scripting/ScreenshareScriptingInterface.h +++ b/interface/src/scripting/ScreenshareScriptingInterface.h @@ -43,10 +43,10 @@ private: #ifdef Q_OS_WIN const QString SCREENSHARE_EXE_PATH{ PathUtils::projectRootPath() + "/screenshare/hifi-screenshare-win32-x64/hifi-screenshare.exe" }; #elif defined(Q_OS_MAC) - const QString SCREENSHARE_EXE_PATH{ PathUtils::projectRootPath() + "/screenshare/screenshare-darwin-x64/hifi-screenshare.app" }; + const QString SCREENSHARE_EXE_PATH{ PathUtils::projectRootPath() + "/build/screenshare/hifi-screenshare-darwin-x64/hifi-screenshare.app" }; #else // This path won't exist on other platforms, so the Screenshare Scripting Interface will exit early when invoked. - const QString SCREENSHARE_EXE_PATH{ PathUtils::projectRootPath() + "/screenshare/screenshare-other-os/hifi-screenshare" }; + const QString SCREENSHARE_EXE_PATH{ PathUtils::projectRootPath() + "/screenshare/hifi-screenshare-other-os/hifi-screenshare" }; #endif #else #ifdef Q_OS_WIN From 2f887228cfa9ec7da9dbae36618f57b0dfd731f8 Mon Sep 17 00:00:00 2001 From: luiscuenca Date: Fri, 22 Nov 2019 14:51:37 -0700 Subject: [PATCH 05/97] Fix camera pitch by mouse pitch --- .../input-plugins/src/input-plugins/KeyboardMouseDevice.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/input-plugins/src/input-plugins/KeyboardMouseDevice.cpp b/libraries/input-plugins/src/input-plugins/KeyboardMouseDevice.cpp index f17caf22db..ea948a929b 100755 --- a/libraries/input-plugins/src/input-plugins/KeyboardMouseDevice.cpp +++ b/libraries/input-plugins/src/input-plugins/KeyboardMouseDevice.cpp @@ -146,7 +146,7 @@ bool KeyboardMouseDevice::isWheelByTouchPad(QWheelEvent* event) { } else { _wheelDeltaRepeatCount.setX(0); } - return deltaValueX != COMMON_WHEEL_DELTA_VALUE && _wheelDeltaRepeatCount.x() < MAX_WHEEL_DELTA_REPEAT; + return deltaValueX < COMMON_WHEEL_DELTA_VALUE && _wheelDeltaRepeatCount.x() < MAX_WHEEL_DELTA_REPEAT; } if (deltaValueY != 0) { if (abs(_lastWheelDelta.y()) == deltaValueY) { @@ -154,7 +154,7 @@ bool KeyboardMouseDevice::isWheelByTouchPad(QWheelEvent* event) { } else { _wheelDeltaRepeatCount.setY(0); } - return deltaValueY != COMMON_WHEEL_DELTA_VALUE && _wheelDeltaRepeatCount.y() < MAX_WHEEL_DELTA_REPEAT; + return deltaValueY < COMMON_WHEEL_DELTA_VALUE && _wheelDeltaRepeatCount.y() < MAX_WHEEL_DELTA_REPEAT; } return false; } From 167dfab539edaf2e7608b5a34265d76b249b9109 Mon Sep 17 00:00:00 2001 From: Simon Walton Date: Fri, 22 Nov 2019 15:17:23 -0800 Subject: [PATCH 06/97] Copy PolyVox libs to build directory; don't try to upload docker image --- .github/workflows/cmake.yml | 15 ++++++--------- cmake/macros/TargetPolyvox.cmake | 18 ++++++++++++++++++ cmake/macros/TargetQuazip.cmake | 8 -------- cmake/ports/quazip/portfile.cmake | 4 ++++ 4 files changed, 28 insertions(+), 17 deletions(-) diff --git a/.github/workflows/cmake.yml b/.github/workflows/cmake.yml index db677f60cb..df3fbd0e13 100644 --- a/.github/workflows/cmake.yml +++ b/.github/workflows/cmake.yml @@ -259,7 +259,7 @@ jobs: - name: Install python modules run: pip install awscli boto3 PyGithub - name: Install apt packages - # libglu1-mesa-dev needed for oven, npm for server-console + # libglu1-mesa-dev needed for oven run: sudo apt install -y mesa-common-dev libegl1 libglvnd-dev libdouble-conversion1 libpulse0 - name: Create Build Environment run: cmake -E make_directory ${{runner.workspace}}/build @@ -276,12 +276,9 @@ jobs: shell: bash working-directory: ${{runner.workspace}}/build run: docker build -t $DOCKER_IMAGE_NAME -f $GITHUB_WORKSPACE/tools/ci-scripts/linux-gha/Dockerfile ./ - - name: Upload Docker image + - name: Export Docker image shell: bash - env: - # TODO: upload to correct location - AWS_ACCESS_KEY_ID: ${{ secrets.AWS_KEY_ID }} - AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_KEY }} - run: | - docker save -o ${{runner.workspace}}/build/hifi_docker_image.tar $DOCKER_IMAGE_NAME - aws s3 cp ${{runner.workspace}}/build/hifi_docker_image.tar s3://hifi-public/simon/builds/hifi_docker_image.$GIT_PR_COMMIT_SHORT.tar + working-directory: ${{runner.workspace}}/build + run: docker save -o ${{runner.workspace}}/build/hifi_docker_image.tar $DOCKER_IMAGE_NAME + + diff --git a/cmake/macros/TargetPolyvox.cmake b/cmake/macros/TargetPolyvox.cmake index 576b454f57..ae31254af2 100644 --- a/cmake/macros/TargetPolyvox.cmake +++ b/cmake/macros/TargetPolyvox.cmake @@ -21,6 +21,24 @@ macro(TARGET_POLYVOX) list(APPEND POLYVOX_LIBRARY_DEBUG ${POLYVOX_UTIL_LIBRARY_DEBUG}) select_library_configurations(POLYVOX) list(APPEND POLYVOX_INCLUDE_DIRS ${VCPKG_INSTALL_ROOT}/include) + if (${CMAKE_SYSTEM_NAME} STREQUAL "Linux") + set(_LIB_GLOBS) + if(${CMAKE_BUILD_TYPE} STREQUAL "Debug") + set(_PV_LIBRARIES ${POLYVOX_LIBRARY_DEBUG}) + else() + set(_PV_LIBRARIES ${POLYVOX_LIBRARY_RELEASE}) + endif() + foreach(_lib ${_PV_LIBRARIES}) + list(APPEND _LIB_GLOBS ${_lib}*) + endforeach() + message("_LIB_GLOBS=" ${_LIB_GLOBS}) + add_custom_command( + TARGET ${TARGET_NAME} + POST_BUILD + COMMAND cp + ARGS -d ${_LIB_GLOBS} ${CMAKE_BINARY_DIR} + ) + endif() endif() target_link_libraries(${TARGET_NAME} ${POLYVOX_LIBRARIES}) target_include_directories(${TARGET_NAME} PUBLIC ${POLYVOX_INCLUDE_DIRS}) diff --git a/cmake/macros/TargetQuazip.cmake b/cmake/macros/TargetQuazip.cmake index af89686ff6..fa05ec55eb 100644 --- a/cmake/macros/TargetQuazip.cmake +++ b/cmake/macros/TargetQuazip.cmake @@ -10,12 +10,4 @@ macro(TARGET_QUAZIP) find_library(QUAZIP_LIBRARY_DEBUG quazip5 PATHS ${VCPKG_INSTALL_ROOT}/debug/lib NO_DEFAULT_PATH) select_library_configurations(QUAZIP) target_link_libraries(${TARGET_NAME} ${QUAZIP_LIBRARIES}) - if (${CMAKE_SYSTEM_NAME} STREQUAL "Linux") - add_custom_command( - TARGET ${TARGET_NAME} - POST_BUILD - COMMAND cp - ARGS -d ${QUAZIP_LIBRARIES}* ${CMAKE_BINARY_DIR} - ) - endif() endmacro() diff --git a/cmake/ports/quazip/portfile.cmake b/cmake/ports/quazip/portfile.cmake index 021c176ab6..66326319f7 100644 --- a/cmake/ports/quazip/portfile.cmake +++ b/cmake/ports/quazip/portfile.cmake @@ -26,6 +26,10 @@ if (WIN32) file(RENAME ${CURRENT_PACKAGES_DIR}/lib/quazip5.dll ${CURRENT_PACKAGES_DIR}/bin/quazip5.dll) file(MAKE_DIRECTORY ${CURRENT_PACKAGES_DIR}/debug/bin) file(RENAME ${CURRENT_PACKAGES_DIR}/debug/lib/quazip5d.dll ${CURRENT_PACKAGES_DIR}/debug/bin/quazip5.dll) +elseif(DEFINED VCPKG_TARGET_IS_LINUX) + # We only want static libs. + file(GLOB QUAZIP5_DYNAMIC_LIBS ${CURRENT_PACKAGES_DIR}/lib/libquazip5.so* ${CURRENT_PACKAGES_DIR}/debug/lib/libquazip5d.so*) + file(REMOVE ${QUAZIP5_DYNAMIC_LIBS}) endif() file(INSTALL ${SOURCE_PATH}/COPYING DESTINATION ${CURRENT_PACKAGES_DIR}/share/quazip RENAME copyright) file(REMOVE_RECURSE ${CURRENT_PACKAGES_DIR}/debug/include) From 320095f765e31bb51699caf01b0ecabccfe5751a Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Fri, 22 Nov 2019 15:40:44 -0800 Subject: [PATCH 07/97] Added animedit avatar-animation.json graph editor tool --- tools/animedit/.gitignore | 1 + tools/animedit/LICENCE | 4 + tools/animedit/README.md | 14 + tools/animedit/animedit.pro | 35 ++ tools/animedit/deploy.bat | 3 + tools/animedit/main.cpp | 37 ++ tools/animedit/qml.qrc | 26 ++ tools/animedit/qml/TreeDelegate.qml | 10 + tools/animedit/qml/fields/BooleanField.qml | 44 ++ tools/animedit/qml/fields/IdField.qml | 41 ++ tools/animedit/qml/fields/JSONField.qml | 52 +++ .../animedit/qml/fields/NumberArrayField.qml | 54 +++ tools/animedit/qml/fields/NumberField.qml | 45 ++ tools/animedit/qml/fields/StringField.qml | 44 ++ tools/animedit/qml/fields/TypeField.qml | 67 +++ tools/animedit/qml/main.qml | 262 +++++++++++ tools/animedit/qml/nodes/BlendDirectional.qml | 129 ++++++ tools/animedit/qml/nodes/BlendLinear.qml | 73 +++ tools/animedit/qml/nodes/BlendLinearMove.qml | 85 ++++ tools/animedit/qml/nodes/ClipData.qml | 148 +++++++ tools/animedit/qml/nodes/DefaultPose.qml | 53 +++ .../animedit/qml/nodes/InverseKinematics.qml | 71 +++ tools/animedit/qml/nodes/Manipulator.qml | 72 +++ tools/animedit/qml/nodes/Overlay.qml | 80 ++++ tools/animedit/qml/nodes/PoleVector.qml | 96 ++++ .../animedit/qml/nodes/RandomStateMachine.qml | 109 +++++ tools/animedit/qml/nodes/SplineIK.qml | 139 ++++++ tools/animedit/qml/nodes/StateMachine.qml | 65 +++ tools/animedit/qml/nodes/TwoBoneIK.qml | 120 +++++ tools/animedit/treeitem.cpp | 91 ++++ tools/animedit/treeitem.h | 45 ++ tools/animedit/treemodel.cpp | 418 ++++++++++++++++++ tools/animedit/treemodel.h | 79 ++++ 33 files changed, 2612 insertions(+) create mode 100644 tools/animedit/.gitignore create mode 100644 tools/animedit/LICENCE create mode 100644 tools/animedit/README.md create mode 100644 tools/animedit/animedit.pro create mode 100644 tools/animedit/deploy.bat create mode 100644 tools/animedit/main.cpp create mode 100644 tools/animedit/qml.qrc create mode 100644 tools/animedit/qml/TreeDelegate.qml create mode 100644 tools/animedit/qml/fields/BooleanField.qml create mode 100644 tools/animedit/qml/fields/IdField.qml create mode 100644 tools/animedit/qml/fields/JSONField.qml create mode 100644 tools/animedit/qml/fields/NumberArrayField.qml create mode 100644 tools/animedit/qml/fields/NumberField.qml create mode 100644 tools/animedit/qml/fields/StringField.qml create mode 100644 tools/animedit/qml/fields/TypeField.qml create mode 100644 tools/animedit/qml/main.qml create mode 100644 tools/animedit/qml/nodes/BlendDirectional.qml create mode 100644 tools/animedit/qml/nodes/BlendLinear.qml create mode 100644 tools/animedit/qml/nodes/BlendLinearMove.qml create mode 100644 tools/animedit/qml/nodes/ClipData.qml create mode 100644 tools/animedit/qml/nodes/DefaultPose.qml create mode 100644 tools/animedit/qml/nodes/InverseKinematics.qml create mode 100644 tools/animedit/qml/nodes/Manipulator.qml create mode 100644 tools/animedit/qml/nodes/Overlay.qml create mode 100644 tools/animedit/qml/nodes/PoleVector.qml create mode 100644 tools/animedit/qml/nodes/RandomStateMachine.qml create mode 100644 tools/animedit/qml/nodes/SplineIK.qml create mode 100644 tools/animedit/qml/nodes/StateMachine.qml create mode 100644 tools/animedit/qml/nodes/TwoBoneIK.qml create mode 100644 tools/animedit/treeitem.cpp create mode 100644 tools/animedit/treeitem.h create mode 100644 tools/animedit/treemodel.cpp create mode 100644 tools/animedit/treemodel.h diff --git a/tools/animedit/.gitignore b/tools/animedit/.gitignore new file mode 100644 index 0000000000..86a9657caa --- /dev/null +++ b/tools/animedit/.gitignore @@ -0,0 +1 @@ +*.pro.user \ No newline at end of file diff --git a/tools/animedit/LICENCE b/tools/animedit/LICENCE new file mode 100644 index 0000000000..fb888fd1b7 --- /dev/null +++ b/tools/animedit/LICENCE @@ -0,0 +1,4 @@ +Copyright (c) 2019 High Fidelity, Inc. All rights reserved. + +Distributed under the Apache License, Version 2.0. +See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html diff --git a/tools/animedit/README.md b/tools/animedit/README.md new file mode 100644 index 0000000000..f314b4e5b7 --- /dev/null +++ b/tools/animedit/README.md @@ -0,0 +1,14 @@ +animedit +------------- +avatar-animation.json editor for High Fidelity. + +Use QtCreator to build. + +Known issues: + +* When switching node types, clear old types fields & set new fields to default values. +* Name field does not change when it has focus and leftHandPane selection is changed. + + + + diff --git a/tools/animedit/animedit.pro b/tools/animedit/animedit.pro new file mode 100644 index 0000000000..0e55ac5d1e --- /dev/null +++ b/tools/animedit/animedit.pro @@ -0,0 +1,35 @@ +QT += quick +CONFIG += c++11 + +# The following define makes your compiler emit warnings if you use +# any Qt feature that has been marked deprecated (the exact warnings +# depend on your compiler). Refer to the documentation for the +# deprecated API to know how to port your code away from it. +DEFINES += QT_DEPRECATED_WARNINGS + +# You can also make your code fail to compile if it uses deprecated APIs. +# In order to do so, uncomment the following line. +# You can also select to disable deprecated APIs only up to a certain version of Qt. +#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 + +SOURCES += \ + main.cpp \ + treeitem.cpp \ + treemodel.cpp + +RESOURCES += qml.qrc + +# Additional import path used to resolve QML modules in Qt Creator's code model +QML_IMPORT_PATH = + +# Additional import path used to resolve QML modules just for Qt Quick Designer +QML_DESIGNER_IMPORT_PATH = + +# Default rules for deployment. +qnx: target.path = /tmp/$${TARGET}/bin +else: unix:!android: target.path = /opt/$${TARGET}/bin +!isEmpty(target.path): INSTALLS += target + +HEADERS += \ + treeitem.h \ + treemodel.h diff --git a/tools/animedit/deploy.bat b/tools/animedit/deploy.bat new file mode 100644 index 0000000000..e788d9d204 --- /dev/null +++ b/tools/animedit/deploy.bat @@ -0,0 +1,3 @@ +mkdir C:\Users\ajthy\Documents\animedit\bin +copy C:\Users\ajthy\Documents\build-animedit-Desktop_Qt_5_12_3_MSVC2015_64bit-Release\release\animedit.exe C:\Users\ajthy\Documents\animedit\bin +C:\Qt\5.12.3\msvc2015_64\bin\windeployqt.exe -qmldir C:\Users\ajthy\Documents\animedit\qml C:\Users\ajthy\Documents\animedit\bin\animedit.exe \ No newline at end of file diff --git a/tools/animedit/main.cpp b/tools/animedit/main.cpp new file mode 100644 index 0000000000..4c7ea4de68 --- /dev/null +++ b/tools/animedit/main.cpp @@ -0,0 +1,37 @@ +// +// Copyright (c) 2019 High Fidelity, Inc. All rights reserved. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include +#include +#include + +#include "treemodel.h" + +int main(int argc, char *argv[]) +{ + QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling); + + QGuiApplication app(argc, argv); + + QQmlApplicationEngine engine; + + // expose model + TreeModel model; + engine.rootContext()->setContextProperty("theModel", &model); + + const QUrl url(QStringLiteral("qrc:/qml/main.qml")); + QObject::connect(&engine, &QQmlApplicationEngine::objectCreated, &app, [url](QObject *obj, const QUrl &objUrl) { + if (!obj && url == objUrl) { + QCoreApplication::exit(-1); + } else { + ; + } + }, Qt::QueuedConnection); + engine.load(url); + + return app.exec(); +} diff --git a/tools/animedit/qml.qrc b/tools/animedit/qml.qrc new file mode 100644 index 0000000000..25fab138aa --- /dev/null +++ b/tools/animedit/qml.qrc @@ -0,0 +1,26 @@ + + + qml/main.qml + qml/TreeDelegate.qml + qml/fields/BooleanField.qml + qml/fields/IdField.qml + qml/fields/JSONField.qml + qml/fields/NumberArrayField.qml + qml/fields/NumberField.qml + qml/fields/StringField.qml + qml/fields/TypeField.qml + qml/nodes/BlendDirectional.qml + qml/nodes/BlendLinear.qml + qml/nodes/BlendLinearMove.qml + qml/nodes/ClipData.qml + qml/nodes/DefaultPose.qml + qml/nodes/InverseKinematics.qml + qml/nodes/Manipulator.qml + qml/nodes/Overlay.qml + qml/nodes/PoleVector.qml + qml/nodes/RandomStateMachine.qml + qml/nodes/StateMachine.qml + qml/nodes/SplineIK.qml + qml/nodes/TwoBoneIK.qml + + diff --git a/tools/animedit/qml/TreeDelegate.qml b/tools/animedit/qml/TreeDelegate.qml new file mode 100644 index 0000000000..f4f21591c9 --- /dev/null +++ b/tools/animedit/qml/TreeDelegate.qml @@ -0,0 +1,10 @@ +import QtQuick 2.0 + +Item { + Text { + anchors.fill: parent + color: styleData.textColor + elide: styleData.elideMode + text: styleData.value + } +} diff --git a/tools/animedit/qml/fields/BooleanField.qml b/tools/animedit/qml/fields/BooleanField.qml new file mode 100644 index 0000000000..8ba2b93855 --- /dev/null +++ b/tools/animedit/qml/fields/BooleanField.qml @@ -0,0 +1,44 @@ +import QtQuick 2.12 +import QtQuick.Window 2.12 +import QtQuick.Controls 1.6 +import QtQuick.Layouts 1.3 +import QtQuick.Dialogs 1.0 + + +Row { + id: row + height: 20 + width: 300 + anchors.left: parent.left + anchors.leftMargin: 0 + anchors.right: parent.right + anchors.rightMargin: 0 + + property string key + property bool value + property bool optional + + function setValue(newValue) { + parent.fieldChanged(key, newValue); + } + + Text { + id: keyText + y: 5 + width: 100 + text: key + ":" + font.pixelSize: 12 + color: optional ? "blue" : "black" + } + + CheckBox { + id: valueCheckBox + x: 100 + y: 5 + width: 200 + checked: value ? Qt.Checked : Qt.Unchecked + onCheckedChanged: { + setValue(checked); + } + } +} diff --git a/tools/animedit/qml/fields/IdField.qml b/tools/animedit/qml/fields/IdField.qml new file mode 100644 index 0000000000..b3ee5b6ac9 --- /dev/null +++ b/tools/animedit/qml/fields/IdField.qml @@ -0,0 +1,41 @@ +import QtQuick 2.12 +import QtQuick.Window 2.12 +import QtQuick.Controls 1.6 +import QtQuick.Layouts 1.3 +import QtQuick.Dialogs 1.0 + +Row { + id: row + x: 0 + y: 0 + height: 20 + anchors.left: parent.left + anchors.leftMargin: 0 + anchors.right: parent.right + anchors.rightMargin: 0 + + property string theValue + + function setValue(newValue) { + var ROLE_NAME = 0x0101; + theModel.setData(leftHandPane.currentIndex, newValue, ROLE_NAME); + } + + Text { + id: element + y: 5 + width: 100 + text: qsTr("Id:") + font.pixelSize: 12 + } + + TextField { + id: textField + x: 100 + width: 200 + text: theValue + onEditingFinished: { + setValue(text); + } + } +} diff --git a/tools/animedit/qml/fields/JSONField.qml b/tools/animedit/qml/fields/JSONField.qml new file mode 100644 index 0000000000..f7b16b82cd --- /dev/null +++ b/tools/animedit/qml/fields/JSONField.qml @@ -0,0 +1,52 @@ +import QtQuick 2.12 +import QtQuick.Window 2.12 +import QtQuick.Controls 1.6 +import QtQuick.Layouts 1.3 +import QtQuick.Dialogs 1.0 + + +Column { + id: row + width: parent.width + height: parent.height + anchors.left: parent.left + anchors.leftMargin: 0 + anchors.right: parent.right + anchors.rightMargin: 0 + + property string key + property var value + property bool optional + + spacing: 5 + + function setValue(newValue) { + parent.fieldChanged(key, newValue); + } + + Text { + id: keyText + y: 5 + width: row.width + text: key + ":" + font.pixelSize: 12 + color: optional ? "blue" : "black" + } + + TextArea { + id: valueTextField + x: 0 + width: (keyText.width - 20) + height: (parent.height - 120) + wrapMode: TextEdit.NoWrap + + // TODO: validate + + text: JSON.stringify(value, null, 4) + + onEditingFinished: { + value = JSON.parse(text); + setValue(value); + } + } +} diff --git a/tools/animedit/qml/fields/NumberArrayField.qml b/tools/animedit/qml/fields/NumberArrayField.qml new file mode 100644 index 0000000000..dd393dc259 --- /dev/null +++ b/tools/animedit/qml/fields/NumberArrayField.qml @@ -0,0 +1,54 @@ +import QtQuick 2.12 +import QtQuick.Window 2.12 +import QtQuick.Controls 1.6 +import QtQuick.Layouts 1.3 +import QtQuick.Dialogs 1.0 + + +Row { + id: row + height: 20 + width: 300 + anchors.left: parent.left + anchors.leftMargin: 0 + anchors.right: parent.right + anchors.rightMargin: 0 + + property string key + property var value + property bool optional + + function setValue(newValue) { + parent.fieldChanged(key, newValue); + } + + Text { + id: keyText + y: 5 + width: 100 + text: key + ":" + font.pixelSize: 12 + color: optional ? "blue" : "black" + } + + TextField { + id: valueTextField + x: 100 + width: 200 + + // first start with a regex for an array of numbers + // ^\[\s*(\d+)(\s*,\s*(\d+))*\]$|\[\s*\] + // then a regex for a floating point number + // \d+\.?\d* + // then substitue the second into the \d+ of the first, yeilding this monstrocity. + // ^\[\s*(\d+\.?\d*)(\s*,\s*(\d+\.?\d*))*\]$|\[\s*\] + + //validator: RegExpValidator { regExp: /^\[\s*(\d+\.?\d*)(\s*,\s*(\d+\.?\d*))*\]$|\[\s*\]/ } + + text: JSON.stringify(value) + onEditingFinished: { + value = JSON.parse(text); + setValue(value); + } + } +} diff --git a/tools/animedit/qml/fields/NumberField.qml b/tools/animedit/qml/fields/NumberField.qml new file mode 100644 index 0000000000..88c952d205 --- /dev/null +++ b/tools/animedit/qml/fields/NumberField.qml @@ -0,0 +1,45 @@ +import QtQuick 2.12 +import QtQuick.Window 2.12 +import QtQuick.Controls 1.6 +import QtQuick.Layouts 1.3 +import QtQuick.Dialogs 1.0 + + +Row { + id: row + height: 20 + width: 300 + anchors.left: parent.left + anchors.leftMargin: 0 + anchors.right: parent.right + anchors.rightMargin: 0 + + property string key + property real value + property bool optional + + function setValue(newValue) { + parent.fieldChanged(key, newValue); + } + + Text { + id: keyText + y: 5 + width: 100 + text: key + ":" + font.pixelSize: 12 + color: optional ? "blue" : "black" + } + + TextField { + id: valueTextField + x: 100 + width: 200 + inputMethodHints: Qt.ImhFormattedNumbersOnly + text: value + onEditingFinished: { + value = text; + setValue(parseInt(text, 10)); + } + } +} diff --git a/tools/animedit/qml/fields/StringField.qml b/tools/animedit/qml/fields/StringField.qml new file mode 100644 index 0000000000..7ce5cd4c6c --- /dev/null +++ b/tools/animedit/qml/fields/StringField.qml @@ -0,0 +1,44 @@ +import QtQuick 2.12 +import QtQuick.Window 2.12 +import QtQuick.Controls 1.6 +import QtQuick.Layouts 1.3 +import QtQuick.Dialogs 1.0 + + +Row { + id: row + height: 20 + width: 300 + anchors.left: parent.left + anchors.leftMargin: 0 + anchors.right: parent.right + anchors.rightMargin: 0 + + property string key + property string value + property bool optional + + function setValue(newValue) { + parent.fieldChanged(key, newValue); + } + + Text { + id: keyText + y: 5 + width: 100 + text: key + ":" + font.pixelSize: 12 + color: optional ? "blue" : "black" + } + + TextField { + id: valueTextField + x: 100 + width: 200 + text: value + onEditingFinished: { + value = text; + setValue(text); + } + } +} diff --git a/tools/animedit/qml/fields/TypeField.qml b/tools/animedit/qml/fields/TypeField.qml new file mode 100644 index 0000000000..0a9a711074 --- /dev/null +++ b/tools/animedit/qml/fields/TypeField.qml @@ -0,0 +1,67 @@ +import QtQuick 2.12 +import QtQuick.Window 2.12 +import QtQuick.Controls 1.6 +import QtQuick.Layouts 1.3 +import QtQuick.Dialogs 1.0 + +Row { + id: row + + function getTypes() { + return [ + "clip", + "blendDirectional", + "blendLinear", + "overlay", + "stateMachine", + "randomSwitchStateMachine", + "manipulator", + "inverseKinematics", + "defaultPose", + "twoBoneIK", + "splineIK", + "poleVectorConstraint" + ]; + } + + function indexFromString(str) { + var index = getTypes().indexOf(str); + return (index === -1) ? 0 : index; + } + + x: 0 + y: 0 + height: 20 + anchors.left: parent.left + anchors.leftMargin: 0 + anchors.right: parent.right + anchors.rightMargin: 0 + + property string theValue: "clip" + property int theIndex: indexFromString(theValue) + + function setValue(newValue) { + var ROLE_TYPE = 0x0102; + theModel.setData(leftHandPane.currentIndex, newValue, ROLE_TYPE); + rightHandPane.reset(); + } + + Text { + id: element + y: 5 + width: 100 + text: qsTr("Type:") + font.pixelSize: 12 + } + + ComboBox { + id: comboBox + x: 100 + width: 200 + model: getTypes() + currentIndex: theIndex + onActivated: { + setValue(currentText); + } + } +} diff --git a/tools/animedit/qml/main.qml b/tools/animedit/qml/main.qml new file mode 100644 index 0000000000..2d0c277132 --- /dev/null +++ b/tools/animedit/qml/main.qml @@ -0,0 +1,262 @@ +import QtQuick 2.12 +import QtQuick.Window 2.12 +import QtQuick.Controls 1.6 +import QtQuick.Layouts 1.3 +import QtQuick.Dialogs 1.0 +import "fields" +import "nodes" + +ApplicationWindow { + id: root + visible: true + width: 1600 + height: 1000 + color: "#ffffff" + opacity: 1 + title: qsTr("AnimEdit") + menuBar: appMenuBar + + SplitView { + id: splitView + anchors.fill: parent + + TreeView { + id: leftHandPane + width: 1000 + anchors.bottom: parent.bottom + anchors.left: parent.left + anchors.top: parent.top + model: theModel + itemDelegate: TreeDelegate {} + + TableViewColumn { + role: "name" + title: "Name" + width: 500 + } + + TableViewColumn { + role: "type" + title: "Type" + } + + onClicked: { + rightHandPane.setIndex(index); + } + + function expandTreeView() { + function expandAll(index) { + leftHandPane.expand(index); + var children = theModel.getChildrenModelIndices(index); + for (var i = 0; i < children.length; i++) { + leftHandPane.expand(children[i]); + expandAll(children[i]); + } + } + + var index = theModel.index(0, 0); + expandAll(index); + } + } + + Rectangle { + id: rightHandPane + color: "#adadad" + height: parent.height + width: 500 + anchors.left: leftHandPane.right + anchors.leftMargin: 0 + anchors.right: parent.right + anchors.rightMargin: 0 + anchors.top: parent.top + anchors.topMargin: 0 + anchors.bottom: parent.bottom + anchors.bottomMargin: 0 + + function createCustomData(qml, index) { + var component = Qt.createComponent(qml, Component.PreferSynchronous); + if (component.status === Component.Ready) { + var obj = component.createObject(rightHandPaneColumn); + obj.setIndex(index); + } else if (component.status === Component.Error) { + console.log("ERROR: " + component.errorString()); + } else if (component.status === Component.Loading) { + console.log("ERROR: NOT READY"); + } + } + + function reset() { + setIndex(leftHandPane.currentIndex); + } + + function setIndex(index) { + var ROLE_NAME = 0x0101; + var ROLE_TYPE = 0x0102; + var ROLE_DATA = 0x0103; + + var idValue = theModel.data(index, ROLE_NAME); + var typeValue = theModel.data(index, ROLE_TYPE); + + idField.theValue = idValue; + typeField.theValue = typeValue; + + // delete previous custom data obj, if present + var orig = rightHandPaneColumn.children[2]; + if (orig) { + orig.destroy(); + } + + if (typeValue === "clip") { + createCustomData("nodes/ClipData.qml", index); + } else if (typeValue === "blendDirectional") { + createCustomData("nodes/BlendDirectional.qml", index); + } else if (typeValue === "blendLinear") { + createCustomData("nodes/BlendLinear.qml", index); + } else if (typeValue === "blendLinearMove") { + createCustomData("nodes/BlendLinearMove.qml", index); + } else if (typeValue === "overlay") { + createCustomData("nodes/Overlay.qml", index); + } else if (typeValue === "stateMachine") { + createCustomData("nodes/StateMachine.qml", index); + } else if (typeValue === "randomSwitchStateMachine") { + createCustomData("nodes/RandomStateMachine.qml", index); + } else if (typeValue === "inverseKinematics") { + createCustomData("nodes/InverseKinematics.qml", index); + } else if (typeValue === "twoBoneIK") { + createCustomData("nodes/TwoBoneIK.qml", index); + } else if (typeValue === "defaultPose") { + createCustomData("nodes/DefaultPose.qml", index); + } else if (typeValue === "manipulator") { + createCustomData("nodes/Manipulator.qml", index); + } else if (typeValue === "splineIK") { + createCustomData("nodes/SplineIK.qml", index); + } else if (typeValue === "poleVectorConstraint") { + createCustomData("nodes/PoleVector.qml", index); + } + } + + Column { + id: rightHandPaneColumn + + anchors.right: parent.right + anchors.rightMargin: 0 + anchors.left: parent.left + anchors.leftMargin: 10 + anchors.bottom: parent.bottom + anchors.bottomMargin: 0 + anchors.top: parent.top + anchors.topMargin: 0 + + spacing: 6 + + IdField { + id: idField + } + + TypeField { + id: typeField + } + } + } + } + + MenuBar { + id: appMenuBar + Menu { + title: "File" + MenuItem { + text: "Open..." + onTriggered: openFileDialog.open() + } + MenuItem { + text: "Save As..." + onTriggered: saveAsFileDialog.open() + } + } + Menu { + title: "Edit" + MenuItem { + text: "Add New Node as Child" + onTriggered: { + theModel.newNode(leftHandPane.currentIndex); + } + } + MenuItem { + text: "Delete Selected" + onTriggered: { + theModel.deleteNode(leftHandPane.currentIndex); + } + } + MenuItem { + text: "Insert New Node Above" + onTriggered: { + theModel.insertNodeAbove(leftHandPane.currentIndex); + } + } + MenuItem { + text: "Copy Node Only" + onTriggered: { + theModel.copyNode(leftHandPane.currentIndex); + } + } + MenuItem { + text: "Copy Node And Children" + onTriggered: { + theModel.copyNodeAndChildren(leftHandPane.currentIndex); + } + } + MenuItem { + text: "Paste Over" + onTriggered: { + theModel.pasteOver(leftHandPane.currentIndex); + } + } + MenuItem { + text: "Paste As Child" + onTriggered: { + theModel.pasteAsChild(leftHandPane.currentIndex); + } + } + } + } + + FileDialog { + id: openFileDialog + title: "Open an animation json file" + folder: shortcuts.home + nameFilters: ["Json files (*.json)"] + onAccepted: { + var path = openFileDialog.fileUrl.toString(); + // remove prefixed "file:///" + path = path.replace(/^(file:\/{3})/,""); + // unescape html codes like '%23' for '#' + var cleanPath = decodeURIComponent(path); + console.log("You chose: " + cleanPath); + theModel.loadFromFile(cleanPath); + leftHandPane.expandTreeView(); + } + onRejected: { + console.log("Canceled"); + } + } + + FileDialog { + id: saveAsFileDialog + title: "Save an animation json file" + folder: shortcuts.home + nameFilters: ["Json files (*.json)"] + selectExisting: false + onAccepted: { + var path = saveAsFileDialog.fileUrl.toString(); + // remove prefixed "file:///" + path = path.replace(/^(file:\/{3})/,""); + // unescape html codes like '%23' for '#' + var cleanPath = decodeURIComponent(path); + console.log("You chose: " + cleanPath); + theModel.saveToFile(cleanPath); + } + onRejected: { + console.log("Canceled"); + } + } +} diff --git a/tools/animedit/qml/nodes/BlendDirectional.qml b/tools/animedit/qml/nodes/BlendDirectional.qml new file mode 100644 index 0000000000..efdea74662 --- /dev/null +++ b/tools/animedit/qml/nodes/BlendDirectional.qml @@ -0,0 +1,129 @@ +import QtQuick 2.12 +import QtQuick.Window 2.12 +import QtQuick.Controls 1.6 +import QtQuick.Layouts 1.3 +import QtQuick.Dialogs 1.0 +import "../fields" + +Column { + id: column + x: 0 + y: 0 + height: 50 + width: 200 + spacing: 6 + property var modelIndex + + signal fieldChanged(string key, var newValue) + + // called by each field when its value is changed. + function fieldChangedMethod(key, newValue) { + var ROLE_DATA = 0x0103; + var dataValue = theModel.data(modelIndex, ROLE_DATA); + dataValue[key] = newValue; + + // copy the new value into the model. + theModel.setData(modelIndex, dataValue, ROLE_DATA); + } + + // called when a new model is loaded + function setIndex(index) { + modelIndex = index; + + var ROLE_DATA = 0x0103; + var dataValue = theModel.data(modelIndex, ROLE_DATA); + + var fields = ["alpha", "alphaVar", "centerId", "upId", "downId", "leftId", "rightId", "upLeftId", "upRightId", "downLeftId", "downRightId"]; + + // copy data from theModel into each field. + var l = fields.length; + for (var i = 0; i < l; i++) { + var val = dataValue[fields[i]]; + if (val) { + column.children[i].value = val; + } + } + } + + Component.onCompleted: { + // this signal is fired from each data field when values are changed. + column.fieldChanged.connect(fieldChangedMethod) + } + + NumberArrayField { + id: alphaField + key: "alpha" + value: [0, 0, 0] + } + + StringField { + id: alphaVarField + key: "alphaVar" + value: "" + optional: true + } + + StringField { + id: centerIdField + key: "centerId" + value: "" + optional: true + } + + StringField { + id: upIdField + key: "upId" + value: "" + optional: true + } + + StringField { + id: downIdField + key: "downId" + value: "" + optional: true + } + + StringField { + id: leftIdField + key: "leftId" + value: "" + optional: true + } + + StringField { + id: rightIdField + key: "rightId" + value: "" + optional: true + } + + StringField { + id: upLeftIdField + key: "upLeftId" + value: "" + optional: true + } + + StringField { + id: upRightIdField + key: "upRightId" + value: "" + optional: true + } + + StringField { + id: downLeftIdField + key: "downLeftId" + value: "" + optional: true + } + + StringField { + id: downRightIdField + key: "downRightId" + value: "" + optional: true + } +} + diff --git a/tools/animedit/qml/nodes/BlendLinear.qml b/tools/animedit/qml/nodes/BlendLinear.qml new file mode 100644 index 0000000000..5ed15d9ea7 --- /dev/null +++ b/tools/animedit/qml/nodes/BlendLinear.qml @@ -0,0 +1,73 @@ +import QtQuick 2.12 +import QtQuick.Window 2.12 +import QtQuick.Controls 1.6 +import QtQuick.Layouts 1.3 +import QtQuick.Dialogs 1.0 +import "../fields" + +Column { + id: column + x: 0 + y: 0 + height: 50 + width: 200 + spacing: 6 + property var modelIndex + + signal fieldChanged(string key, var newValue) + + // called by each field when its value is changed. + function fieldChangedMethod(key, newValue) { + var ROLE_DATA = 0x0103; + var dataValue = theModel.data(modelIndex, ROLE_DATA); + dataValue[key] = newValue; + + // copy the new value into the model. + theModel.setData(modelIndex, dataValue, ROLE_DATA); + } + + // called when a new model is loaded + function setIndex(index) { + modelIndex = index; + + var ROLE_DATA = 0x0103; + var dataValue = theModel.data(modelIndex, ROLE_DATA); + + var fields = ["alpha", "blendType", "alphaVar"]; + + // copy data from theModel into each field. + var l = fields.length; + for (var i = 0; i < l; i++) { + var val = dataValue[fields[i]]; + if (val) { + column.children[i].value = val; + } + } + } + + Component.onCompleted: { + // this signal is fired from each data field when values are changed. + column.fieldChanged.connect(fieldChangedMethod) + } + + NumberField { + id: alphaField + key: "alpha" + value: 0.0 + } + + StringField { + id: blendTypeField + key: "blendType" + value: "" + optional: true + } + + StringField { + id: alphaVarField + key: "alphaVar" + value: "" + optional: true + } +} + diff --git a/tools/animedit/qml/nodes/BlendLinearMove.qml b/tools/animedit/qml/nodes/BlendLinearMove.qml new file mode 100644 index 0000000000..cde0c83fd7 --- /dev/null +++ b/tools/animedit/qml/nodes/BlendLinearMove.qml @@ -0,0 +1,85 @@ +import QtQuick 2.12 +import QtQuick.Window 2.12 +import QtQuick.Controls 1.6 +import QtQuick.Layouts 1.3 +import QtQuick.Dialogs 1.0 +import "../fields" + +Column { + id: column + x: 0 + y: 0 + height: 50 + width: 200 + spacing: 6 + property var modelIndex + + signal fieldChanged(string key, var newValue) + + // called by each field when its value is changed. + function fieldChangedMethod(key, newValue) { + var ROLE_DATA = 0x0103; + var dataValue = theModel.data(modelIndex, ROLE_DATA); + dataValue[key] = newValue; + + // copy the new value into the model. + theModel.setData(modelIndex, dataValue, ROLE_DATA); + } + + // called when a new model is loaded + function setIndex(index) { + modelIndex = index; + + var ROLE_DATA = 0x0103; + var dataValue = theModel.data(modelIndex, ROLE_DATA); + + var fields = ["alpha", "desiredSpeed", "characteristicSpeeds", "alphaVar", "desiredSpeedVar"]; + + // copy data from theModel into each field. + var l = fields.length; + for (var i = 0; i < l; i++) { + var val = dataValue[fields[i]]; + if (val) { + column.children[i].value = val; + } + } + } + + Component.onCompleted: { + // this signal is fired from each data field when values are changed. + column.fieldChanged.connect(fieldChangedMethod) + } + + NumberField { + id: alphaField + key: "alpha" + value: 0.0 + } + + NumberField { + id: desiredSpeedField + key: "desiredSpeed" + value: 0.0 + } + + NumberArrayField { + id: characteristicSpeedsField + key: "characteristicSpeeds" + value: [] + } + + StringField { + id: alphaVarField + key: "alphaVar" + value: "" + optional: true + } + + StringField { + id: desiredSpeedVarField + key: "desiredSpeedVar" + value: "" + optional: true + } +} + diff --git a/tools/animedit/qml/nodes/ClipData.qml b/tools/animedit/qml/nodes/ClipData.qml new file mode 100644 index 0000000000..9949064393 --- /dev/null +++ b/tools/animedit/qml/nodes/ClipData.qml @@ -0,0 +1,148 @@ +import QtQuick 2.12 +import QtQuick.Window 2.12 +import QtQuick.Controls 1.6 +import QtQuick.Layouts 1.3 +import QtQuick.Dialogs 1.0 +import "../fields" + +Column { + id: column + x: 0 + y: 0 + height: 50 + width: 200 + spacing: 6 + property var modelIndex + + signal fieldChanged(string key, var newValue) + + // called by each field when its value is changed. + function fieldChangedMethod(key, newValue) { + var ROLE_DATA = 0x0103; + var dataValue = theModel.data(modelIndex, ROLE_DATA); + dataValue[key] = newValue; + + // copy the new value into the model. + theModel.setData(modelIndex, dataValue, ROLE_DATA); + } + + // called when a new model is loaded + function setIndex(index) { + modelIndex = index; + + var ROLE_DATA = 0x0103; + var dataValue = theModel.data(modelIndex, ROLE_DATA); + + var fields = ["url", "startFrame", "endFrame", "timeScale", "loopFlag", "mirrorFlag", + "blendType", "baseURL", "baseFrame", "startFrameVar", "endFrameVar", + "timeScaleVar", "loopFlagVar", "mirrorFlagVar"]; + + // copy data from theModel into each field. + var l = fields.length; + for (var i = 0; i < l; i++) { + var val = dataValue[fields[i]]; + if (val) { + column.children[i].value = val; + } + } + } + + Component.onCompleted: { + // this signal is fired from each data field when values are changed. + column.fieldChanged.connect(fieldChangedMethod) + } + + StringField { + id: urlField + key: "url" + value: "qrc:///avatar/animations/idle.fbx" + } + + NumberField { + id: startFrameField + key: "startFrame" + value: 0.0 + } + + NumberField { + id: endFrameField + key: "endFrame" + value: 0.0 + } + + NumberField { + id: timeScaleField + key: "timeScale" + value: 0.0 + } + + BooleanField { + id: loopFlagField + key: "loopFlag" + value: false + } + + BooleanField { + id: mirrorFlagField + key: "mirrorFlag" + value: false + optional: true + } + + StringField { + id: blendTypeField + key: "blendType" + value: "" + optional: true + } + + StringField { + id: baseURLField + key: "baseURL" + value: "" + optional: true + } + + NumberField { + id: baseFrameField + key: "baseFrame" + value: 0.0 + optional: true + } + + StringField { + id: startFrameVarField + key: "startFrameVar" + value: "" + optional: true + } + + StringField { + id: endFrameVarField + key: "endFrameVar" + value: "" + optional: true + } + + StringField { + id: timeScaleVarField + key: "timeScaleVar" + value: "" + optional: true + } + + StringField { + id: loopFlagVarField + key: "loopFlagVar" + value: "" + optional: true + } + + StringField { + id: mirrorFlagVarField + key: "mirrorFlagVar" + value: "" + optional: true + } +} + diff --git a/tools/animedit/qml/nodes/DefaultPose.qml b/tools/animedit/qml/nodes/DefaultPose.qml new file mode 100644 index 0000000000..eb16dfb0c0 --- /dev/null +++ b/tools/animedit/qml/nodes/DefaultPose.qml @@ -0,0 +1,53 @@ +import QtQuick 2.12 +import QtQuick.Window 2.12 +import QtQuick.Controls 1.6 +import QtQuick.Layouts 1.3 +import QtQuick.Dialogs 1.0 +import "../fields" + +Column { + id: column + x: 0 + y: 0 + height: 50 + width: 200 + spacing: 6 + property var modelIndex + + signal fieldChanged(string key, var newValue) + + // called by each field when its value is changed. + function fieldChangedMethod(key, newValue) { + var ROLE_DATA = 0x0103; + var dataValue = theModel.data(modelIndex, ROLE_DATA); + dataValue[key] = newValue; + + // copy the new value into the model. + theModel.setData(modelIndex, dataValue, ROLE_DATA); + } + + // called when a new model is loaded + function setIndex(index) { + modelIndex = index; + + var ROLE_DATA = 0x0103; + var dataValue = theModel.data(modelIndex, ROLE_DATA); + + var fields = []; // This node has no data values + + // copy data from theModel into each field. + var l = fields.length; + for (var i = 0; i < l; i++) { + var val = dataValue[fields[i]]; + if (val) { + column.children[i].value = val; + } + } + } + + Component.onCompleted: { + // this signal is fired from each data field when values are changed. + column.fieldChanged.connect(fieldChangedMethod) + } +} + diff --git a/tools/animedit/qml/nodes/InverseKinematics.qml b/tools/animedit/qml/nodes/InverseKinematics.qml new file mode 100644 index 0000000000..b401869c32 --- /dev/null +++ b/tools/animedit/qml/nodes/InverseKinematics.qml @@ -0,0 +1,71 @@ +import QtQuick 2.12 +import QtQuick.Window 2.12 +import QtQuick.Controls 1.6 +import QtQuick.Layouts 1.3 +import QtQuick.Dialogs 1.0 +import "../fields" + +Column { + id: column + x: 0 + y: 0 + width: parent.width + height: (parent.height - 50) + spacing: 6 + property var modelIndex + + signal fieldChanged(string key, var newValue) + + // called by each field when its value is changed. + function fieldChangedMethod(key, newValue) { + var ROLE_DATA = 0x0103; + var dataValue = theModel.data(modelIndex, ROLE_DATA); + dataValue[key] = newValue; + + // copy the new value into the model. + theModel.setData(modelIndex, dataValue, ROLE_DATA); + } + + // called when a new model is loaded + function setIndex(index) { + modelIndex = index; + + var ROLE_DATA = 0x0103; + var dataValue = theModel.data(modelIndex, ROLE_DATA); + + var fields = ["solutionSource", "solutionSourceVar", "targets"]; + + // copy data from theModel into each field. + var l = fields.length; + for (var i = 0; i < l; i++) { + var val = dataValue[fields[i]]; + if (val) { + column.children[i].value = val; + } + } + } + + Component.onCompleted: { + // this signal is fired from each data field when values are changed. + column.fieldChanged.connect(fieldChangedMethod) + } + + StringField { + id: solutionSourceField + key: "solutionSource" + value: "relaxToUnderPoses" + } + + StringField { + id: solutionSourceVarField + key: "solutionSourceVar" + value: "solutionSource" + } + + JSONField { + id: statesField + key: "targets" + value: {} + } +} + diff --git a/tools/animedit/qml/nodes/Manipulator.qml b/tools/animedit/qml/nodes/Manipulator.qml new file mode 100644 index 0000000000..6a651ae73b --- /dev/null +++ b/tools/animedit/qml/nodes/Manipulator.qml @@ -0,0 +1,72 @@ +import QtQuick 2.12 +import QtQuick.Window 2.12 +import QtQuick.Controls 1.6 +import QtQuick.Layouts 1.3 +import QtQuick.Dialogs 1.0 +import "../fields" + +Column { + id: column + x: 0 + y: 0 + width: parent.width + height: parent.height + spacing: 6 + property var modelIndex + + signal fieldChanged(string key, var newValue) + + // called by each field when its value is changed. + function fieldChangedMethod(key, newValue) { + var ROLE_DATA = 0x0103; + var dataValue = theModel.data(modelIndex, ROLE_DATA); + dataValue[key] = newValue; + + // copy the new value into the model. + theModel.setData(modelIndex, dataValue, ROLE_DATA); + } + + // called when a new model is loaded + function setIndex(index) { + modelIndex = index; + + var ROLE_DATA = 0x0103; + var dataValue = theModel.data(modelIndex, ROLE_DATA); + + var fields = ["alpha", "joints", "alphaVar"]; + + // copy data from theModel into each field. + var l = fields.length; + for (var i = 0; i < l; i++) { + var val = dataValue[fields[i]]; + if (val) { + column.children[i].value = val; + } + } + } + + Component.onCompleted: { + // this signal is fired from each data field when values are changed. + column.fieldChanged.connect(fieldChangedMethod) + } + + NumberField { + id: alphaField + key: "alpha" + value: 1.0 + } + + JSONField { + id: statesField + key: "joints" + value: {} + } + + StringField { + optional: true + id: alphaVarField + key: "alphaVar" + value: "" + } +} + diff --git a/tools/animedit/qml/nodes/Overlay.qml b/tools/animedit/qml/nodes/Overlay.qml new file mode 100644 index 0000000000..96c974d6e5 --- /dev/null +++ b/tools/animedit/qml/nodes/Overlay.qml @@ -0,0 +1,80 @@ +import QtQuick 2.12 +import QtQuick.Window 2.12 +import QtQuick.Controls 1.6 +import QtQuick.Layouts 1.3 +import QtQuick.Dialogs 1.0 +import "../fields" + +Column { + id: column + x: 0 + y: 0 + height: 50 + width: 200 + spacing: 6 + property var modelIndex + + signal fieldChanged(string key, var newValue) + + // called by each field when its value is changed. + function fieldChangedMethod(key, newValue) { + var ROLE_DATA = 0x0103; + var dataValue = theModel.data(modelIndex, ROLE_DATA); + dataValue[key] = newValue; + + // copy the new value into the model. + theModel.setData(modelIndex, dataValue, ROLE_DATA); + } + + // called when a new model is loaded + function setIndex(index) { + modelIndex = index; + + var ROLE_DATA = 0x0103; + var dataValue = theModel.data(modelIndex, ROLE_DATA); + + var fields = ["boneSet", "alpha", "boneSetVar", "alphaVar"]; + + // copy data from theModel into each field. + var l = fields.length; + for (var i = 0; i < l; i++) { + var val = dataValue[fields[i]]; + if (val) { + column.children[i].value = val; + } + } + } + + Component.onCompleted: { + // this signal is fired from each data field when values are changed. + column.fieldChanged.connect(fieldChangedMethod) + } + + StringField { + id: boneSetField + key: "boneSet" + value: "fullBody" + optional: true + } + + NumberField { + id: alphaField + key: "alpha" + value: 0.0 + } + + StringField { + id: boneSetVarField + key: "boneSetVar" + value: "" + optional: true + } + + StringField { + id: alphaVarField + key: "alphaVar" + value: "" + optional: true + } +} + diff --git a/tools/animedit/qml/nodes/PoleVector.qml b/tools/animedit/qml/nodes/PoleVector.qml new file mode 100644 index 0000000000..bbf5e96a2f --- /dev/null +++ b/tools/animedit/qml/nodes/PoleVector.qml @@ -0,0 +1,96 @@ +import QtQuick 2.12 +import QtQuick.Window 2.12 +import QtQuick.Controls 1.6 +import QtQuick.Layouts 1.3 +import QtQuick.Dialogs 1.0 +import "../fields" + +Column { + id: column + x: 0 + y: 0 + height: 50 + width: 200 + spacing: 6 + property var modelIndex + + signal fieldChanged(string key, var newValue) + + // called by each field when its value is changed. + function fieldChangedMethod(key, newValue) { + var ROLE_DATA = 0x0103; + var dataValue = theModel.data(modelIndex, ROLE_DATA); + dataValue[key] = newValue; + + // copy the new value into the model. + theModel.setData(modelIndex, dataValue, ROLE_DATA); + } + + // called when a new model is loaded + function setIndex(index) { + modelIndex = index; + + var ROLE_DATA = 0x0103; + var dataValue = theModel.data(modelIndex, ROLE_DATA); + + var fields = ["referenceVector", "enabled", "baseJointName", "midJointName", "tipJointName", + "enabledVar", "poleVectorVar"]; + + // copy data from theModel into each field. + var l = fields.length; + for (var i = 0; i < l; i++) { + var val = dataValue[fields[i]]; + if (val) { + column.children[i].value = val; + } + } + } + + Component.onCompleted: { + // this signal is fired from each data field when values are changed. + column.fieldChanged.connect(fieldChangedMethod) + } + + NumberArrayField { + id: referenceVectorField + key: "referenceVector" + value: [1, 0, 0] + } + + BooleanField { + id: enabledField + key: "enabled" + value: false + } + + StringField { + id: baseJointNameField + key: "baseJointName" + value: "" + } + + StringField { + id: midJointNameField + key: "midJointName" + value: "" + } + + StringField { + id: tipJointNameField + key: "tipJointName" + value: "" + } + + StringField { + id: enabledVarField + key: "enabledVar" + value: "" + } + + StringField { + id: poleVectorVarField + key: "poleVectorVar" + value: "" + } +} + diff --git a/tools/animedit/qml/nodes/RandomStateMachine.qml b/tools/animedit/qml/nodes/RandomStateMachine.qml new file mode 100644 index 0000000000..357fc4b2bf --- /dev/null +++ b/tools/animedit/qml/nodes/RandomStateMachine.qml @@ -0,0 +1,109 @@ +import QtQuick 2.12 +import QtQuick.Window 2.12 +import QtQuick.Controls 1.6 +import QtQuick.Layouts 1.3 +import QtQuick.Dialogs 1.0 +import "../fields" + +Column { + id: column + x: 0 + y: 0 + width: parent.width + height: (parent.height - 150) + spacing: 6 + property var modelIndex + + signal fieldChanged(string key, var newValue) + + // called by each field when its value is changed. + function fieldChangedMethod(key, newValue) { + + var ROLE_DATA = 0x0103; + var dataValue = theModel.data(modelIndex, ROLE_DATA); + dataValue[key] = newValue; + + // copy the new value into the model. + theModel.setData(modelIndex, dataValue, ROLE_DATA); + } + + // called when a new model is loaded + function setIndex(index) { + modelIndex = index; + + var ROLE_DATA = 0x0103; + var dataValue = theModel.data(modelIndex, ROLE_DATA); + + var fields = ["currentState", "randomSwitchTimeMin", "randomSwitchTimeMax", "triggerRandomSwitch", + "triggerTimeMin", "triggerTimeMax", "transitionVar", "states"]; + + // copy data from theModel into each field. + var l = fields.length; + for (var i = 0; i < l; i++) { + var val = dataValue[fields[i]]; + if (val) { + column.children[i].value = val; + } + } + } + + Component.onCompleted: { + // this signal is fired from each data field when values are changed. + column.fieldChanged.connect(fieldChangedMethod) + } + + StringField { + id: currentStateField + key: "currentState" + value: "" + } + + NumberField { + id: randomSwitchTimeMinField + key: "randomSwitchTimeMin" + value: 1.0 + optional: true + } + + NumberField { + id: randomSwitchTimeMaxField + key: "randomSwitchTimeMax" + value: 10.0 + optional: true + } + + StringField { + id: triggerRandomSwitchField + key: "triggerRandomSwitch" + value: "" + optional: true + } + + NumberField { + id: triggerTimeMinField + key: "triggerTimeMin" + value: 1.0 + optional: true + } + + NumberField { + id: triggerTimeMaxField + key: "triggerTimeMax" + value: 10.0 + optional: true + } + + StringField { + id: transitionVarField + key: "transitionVar" + value: "" + optional: true + } + + JSONField { + id: statesField + key: "states" + value: {} + } +} + diff --git a/tools/animedit/qml/nodes/SplineIK.qml b/tools/animedit/qml/nodes/SplineIK.qml new file mode 100644 index 0000000000..df1c8931a3 --- /dev/null +++ b/tools/animedit/qml/nodes/SplineIK.qml @@ -0,0 +1,139 @@ +import QtQuick 2.12 +import QtQuick.Window 2.12 +import QtQuick.Controls 1.6 +import QtQuick.Layouts 1.3 +import QtQuick.Dialogs 1.0 +import "../fields" + +Column { + id: column + x: 0 + y: 0 + height: 50 + width: 200 + spacing: 6 + property var modelIndex + + signal fieldChanged(string key, var newValue) + + // called by each field when its value is changed. + function fieldChangedMethod(key, newValue) { + var ROLE_DATA = 0x0103; + var dataValue = theModel.data(modelIndex, ROLE_DATA); + dataValue[key] = newValue; + + // copy the new value into the model. + theModel.setData(modelIndex, dataValue, ROLE_DATA); + } + + // called when a new model is loaded + function setIndex(index) { + modelIndex = index; + + var ROLE_DATA = 0x0103; + var dataValue = theModel.data(modelIndex, ROLE_DATA); + + var fields = ["alpha", "enabled", "interpDuration", "baseJointName", "midJointName", "tipJointName", + "basePositionVar", "baseRotationVar", "midPositionVar", "midRotationVar", "tipPositionVar", "tipRotationVar", + "alphaVar", "enabledVar"]; + + // copy data from theModel into each field. + var l = fields.length; + for (var i = 0; i < l; i++) { + var val = dataValue[fields[i]]; + if (val) { + column.children[i].value = val; + } + } + } + + Component.onCompleted: { + // this signal is fired from each data field when values are changed. + column.fieldChanged.connect(fieldChangedMethod) + } + + NumberField { + id: alphaField + key: "alpha" + value: 1.0 + } + + BooleanField { + id: enabledField + key: "enabled" + value: false + } + + NumberField { + id: interpDurationField + key: "interpDuration" + value: 15.0 + } + + StringField { + id: baseJointNameField + key: "baseJointName" + value: "" + } + + StringField { + id: midJointNameField + key: "midJointName" + value: "" + } + + StringField { + id: tipJointNameField + key: "tipJointName" + value: "" + } + + StringField { + id: basePositionVarField + key: "basePositionVar" + value: "" + } + + StringField { + id: baseRotationVarField + key: "baseRotationVar" + value: "" + } + + StringField { + id: midPositionVarField + key: "midPositionVar" + value: "" + } + + StringField { + id: midRotationVarField + key: "midRotationVar" + value: "" + } + + StringField { + id: tipPositionVarField + key: "tipPositionVar" + value: "" + } + + StringField { + id: tipRotationVarField + key: "tipRotationVar" + value: "" + } + + StringField { + id: alphaVarField + key: "alphaVar" + value: "" + } + + StringField { + id: enabledVarField + key: "enabledVar" + value: "" + } +} + diff --git a/tools/animedit/qml/nodes/StateMachine.qml b/tools/animedit/qml/nodes/StateMachine.qml new file mode 100644 index 0000000000..aec4c30d27 --- /dev/null +++ b/tools/animedit/qml/nodes/StateMachine.qml @@ -0,0 +1,65 @@ +import QtQuick 2.12 +import QtQuick.Window 2.12 +import QtQuick.Controls 1.6 +import QtQuick.Layouts 1.3 +import QtQuick.Dialogs 1.0 +import "../fields" + +Column { + id: column + x: 0 + y: 0 + height: parent.height + width: parent.width + spacing: 6 + property var modelIndex + + signal fieldChanged(string key, var newValue) + + // called by each field when its value is changed. + function fieldChangedMethod(key, newValue) { + var ROLE_DATA = 0x0103; + var dataValue = theModel.data(modelIndex, ROLE_DATA); + dataValue[key] = newValue; + + // copy the new value into the model. + theModel.setData(modelIndex, dataValue, ROLE_DATA); + } + + // called when a new model is loaded + function setIndex(index) { + modelIndex = index; + + var ROLE_DATA = 0x0103; + var dataValue = theModel.data(modelIndex, ROLE_DATA); + + var fields = ["currentState", "states"]; + + // copy data from theModel into each field. + var l = fields.length; + for (var i = 0; i < l; i++) { + var val = dataValue[fields[i]]; + if (val) { + column.children[i].value = val; + } + } + } + + Component.onCompleted: { + // this signal is fired from each data field when values are changed. + column.fieldChanged.connect(fieldChangedMethod) + } + + StringField { + id: currentStateField + key: "currentState" + value: "default" + } + + JSONField { + id: statesField + key: "states" + value: {} + } +} + diff --git a/tools/animedit/qml/nodes/TwoBoneIK.qml b/tools/animedit/qml/nodes/TwoBoneIK.qml new file mode 100644 index 0000000000..6bdae5c1be --- /dev/null +++ b/tools/animedit/qml/nodes/TwoBoneIK.qml @@ -0,0 +1,120 @@ +import QtQuick 2.12 +import QtQuick.Window 2.12 +import QtQuick.Controls 1.6 +import QtQuick.Layouts 1.3 +import QtQuick.Dialogs 1.0 +import "../fields" + +Column { + id: column + x: 0 + y: 0 + height: 50 + width: 200 + spacing: 6 + property var modelIndex + + signal fieldChanged(string key, var newValue) + + // called by each field when its value is changed. + function fieldChangedMethod(key, newValue) { + var ROLE_DATA = 0x0103; + var dataValue = theModel.data(modelIndex, ROLE_DATA); + dataValue[key] = newValue; + + // copy the new value into the model. + theModel.setData(modelIndex, dataValue, ROLE_DATA); + } + + // called when a new model is loaded + function setIndex(index) { + modelIndex = index; + + var ROLE_DATA = 0x0103; + var dataValue = theModel.data(modelIndex, ROLE_DATA); + + var fields = ["alpha", "enabled", "interpDuration", "baseJointName", "midJointName", "tipJointName", "midHingeAxis", + "alphaVar", "enabledVar", "endEffectorRotationVarVar", "endEffectorPositionVarVar"]; + + // copy data from theModel into each field. + var l = fields.length; + for (var i = 0; i < l; i++) { + var val = dataValue[fields[i]]; + if (val) { + column.children[i].value = val; + } + } + } + + Component.onCompleted: { + // this signal is fired from each data field when values are changed. + column.fieldChanged.connect(fieldChangedMethod) + } + + NumberField { + id: alphaField + key: "alpha" + value: 1.0 + } + + BooleanField { + id: enabledField + key: "enabled" + value: false + } + + NumberField { + id: interpDurationField + key: "interpDuration" + value: 15.0 + } + + StringField { + id: baseJointNameField + key: "baseJointName" + value: "" + } + + StringField { + id: midJointNameField + key: "midJointName" + value: "" + } + + StringField { + id: tipJointNameField + key: "tipJointName" + value: "" + } + + NumberArrayField { + id: midHingeAxisField + key: "midHingeAxis" + value: [1, 0, 0] + } + + StringField { + id: alphaVarField + key: "alphaVar" + value: "" + } + + StringField { + id: enabledVarField + key: "enabledVar" + value: "" + } + + StringField { + id: endEffectorRotationVarVarField + key: "endEffectorRotationVarVar" + value: "" + } + + StringField { + id: endEffectorPositionVarVarField + key: "endEffectorPositionVarVar" + value: "" + } +} + diff --git a/tools/animedit/treeitem.cpp b/tools/animedit/treeitem.cpp new file mode 100644 index 0000000000..172f78a280 --- /dev/null +++ b/tools/animedit/treeitem.cpp @@ -0,0 +1,91 @@ +// +// TreeItem +// +// Created by Anthony Thibault on 6/5/2019 +// 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 +// + +#include "treeitem.h" +#include +#include + +TreeItem::TreeItem(const QList& data) { + m_parentItem = nullptr; + m_itemData = data; +} + +TreeItem::~TreeItem() { + qDeleteAll(m_childItems); +} + +void TreeItem::appendChild(TreeItem *item) { + item->m_parentItem = this; + m_childItems.append(item); +} + +int TreeItem::findChild(TreeItem* child) { + for (int i = 0; i < m_childItems.size(); i++) { + if (m_childItems[i] == child) { + return i; + } + } + return -1; +} + +void TreeItem::removeChild(int index) { + // TODO: delete TreeItem + m_childItems.removeAt(index); +} + +void TreeItem::insertChild(int index, TreeItem* child) { + child->m_parentItem = this; + m_childItems.insert(index, child); +} + +TreeItem* TreeItem::child(int row) { + return m_childItems.value(row); +} + +int TreeItem::childCount() const { + return m_childItems.count(); +} + +int TreeItem::columnCount() const { + return m_itemData.count(); +} + +QVariant TreeItem::data(int column) const { + return m_itemData.value(column); +} + +bool TreeItem::setData(int column, const QVariant& value) { + m_itemData[column] = QVariant(value); + return true; +} + +TreeItem* TreeItem::parentItem() { + return m_parentItem; +} + +int TreeItem::row() const { + if (m_parentItem) { + return m_parentItem->m_childItems.indexOf(const_cast(this)); + } + + return 0; +} + +TreeItem* TreeItem::cloneNode() const { + return new TreeItem(m_itemData); +} + +TreeItem* TreeItem::cloneNodeAndChildren() const { + TreeItem* newNode = new TreeItem(m_itemData); + for (int i = 0; i < m_childItems.size(); ++i) { + newNode->appendChild(m_childItems[i]->cloneNodeAndChildren()); + } + return newNode; +} diff --git a/tools/animedit/treeitem.h b/tools/animedit/treeitem.h new file mode 100644 index 0000000000..bc7afb455a --- /dev/null +++ b/tools/animedit/treeitem.h @@ -0,0 +1,45 @@ +// +// TreeItem +// +// Created by Anthony Thibault on 6/5/2019 +// 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 +// + +#ifndef hifi_TreeItem_h +#define hifi_TreeItem_h + +#include +#include + +class TreeItem +{ +public: + explicit TreeItem(const QList& data); + ~TreeItem(); + + void appendChild(TreeItem* child); + int findChild(TreeItem* child); + void removeChild(int index); + void insertChild(int index, TreeItem* child); + + TreeItem* child(int row); + int childCount() const; + int columnCount() const; + QVariant data(int column) const; + bool setData(int column, const QVariant& value); + int row() const; + TreeItem* parentItem(); + + TreeItem* cloneNode() const; + TreeItem* cloneNodeAndChildren() const; + +private: + QList m_childItems; + QList m_itemData; + TreeItem* m_parentItem; +}; + +#endif diff --git a/tools/animedit/treemodel.cpp b/tools/animedit/treemodel.cpp new file mode 100644 index 0000000000..28c6101f78 --- /dev/null +++ b/tools/animedit/treemodel.cpp @@ -0,0 +1,418 @@ +// +// TreeModel +// +// Created by Anthony Thibault on 6/5/2019 +// 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 +// + +#include "treeitem.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "treemodel.h" + +static TreeItem* newBlankTreeItem() { + QList columnData; + columnData << "newNode"; + columnData << "clip"; + columnData << QJsonObject(); // blank + return new TreeItem(columnData); +} + +TreeModel::TreeModel(QObject* parent) : QAbstractItemModel(parent) { + _roleNameMapping[TreeModelRoleName] = "name"; + _roleNameMapping[TreeModelRoleType] = "type"; + _roleNameMapping[TreeModelRoleData] = "data"; + + QList rootData; + rootData << "Name" << "Type" << "Data"; + _rootItem = new TreeItem(rootData); + _clipboard = nullptr; +} + +TreeModel::~TreeModel() { + delete _rootItem; +} + +QHash TreeModel::roleNames() const { + return _roleNameMapping; +} + +Qt::ItemFlags TreeModel::flags(const QModelIndex& index) const { + if (!index.isValid()) { + return Qt::NoItemFlags; + } + + return QAbstractItemModel::flags(index); +} + +QVariant TreeModel::data(const QModelIndex& index, int role) const { + TreeItem* item = getItem(index); + return item->data(role - Qt::UserRole - 1); +} + +QVariant TreeModel::headerData(int section, Qt::Orientation orientation, int role) const { + if (orientation == Qt::Horizontal && role == Qt::DisplayRole) { + return _rootItem->data(section); + } + + return QVariant(); +} + +QModelIndex TreeModel::index(int row, int column, const QModelIndex& parent) const { + if (!hasIndex(row, column, parent)) { + return QModelIndex(); + } + + TreeItem *parentItem; + + if (!parent.isValid()) { + parentItem = _rootItem; + } else { + parentItem = static_cast(parent.internalPointer()); + } + + TreeItem *childItem = parentItem->child(row); + if (childItem) { + return createIndex(row, column, childItem); + } else { + return QModelIndex(); + } +} + +QModelIndex TreeModel::parent(const QModelIndex& index) const { + if (!index.isValid()) { + return QModelIndex(); + } + + TreeItem *childItem = static_cast(index.internalPointer()); + TreeItem *parentItem = childItem->parentItem(); + + if (parentItem == _rootItem) { + return QModelIndex(); + } + + return createIndex(parentItem->row(), 0, parentItem); +} + +int TreeModel::rowCount(const QModelIndex& parent) const { + TreeItem* parentItem = getItem(parent); + return parentItem->childCount(); +} + +int TreeModel::columnCount(const QModelIndex& parent) const { + return _rootItem->columnCount(); +} + +bool TreeModel::setData(const QModelIndex& index, const QVariant& value, int role) { + TreeItem* item = getItem(index); + + bool returnValue = item->setData(role - Qt::UserRole - 1, value); + + emit dataChanged(index, index); + + return returnValue; +} + +bool TreeModel::setHeaderData(int section, Qt::Orientation orientation, const QVariant& value, int role) { + return false; +} + +bool TreeModel::insertColumns(int position, int columns, const QModelIndex& parent) { + return false; +} + +bool TreeModel::removeColumns(int position, int columns, const QModelIndex& parent) { + return false; +} + +bool TreeModel::insertRows(int position, int rows, const QModelIndex& parent) { + return false; +} + +bool TreeModel::removeRows(int position, int rows, const QModelIndex& parent) { + return false; +} + +void TreeModel::loadFromFile(const QString& filename) { + + beginResetModel(); + + QFile file(filename); + if (!file.exists()) { + qCritical() << "TreeModel::loadFromFile, failed to open file" << filename; + } else if (!file.open(QIODevice::ReadOnly)) { + qCritical() << "TreeModel::loadFromFile, failed to open file" << filename; + } else { + qDebug() << "TreeModel::loadFromFile, success opening file" << filename; + QByteArray contents = file.readAll(); + QJsonParseError error; + auto doc = QJsonDocument::fromJson(contents, &error); + if (error.error != QJsonParseError::NoError) { + qCritical() << "TreeModel::loadFromFile, failed to parse json, error" << error.errorString(); + } else { + QJsonObject obj = doc.object(); + + // version + QJsonValue versionVal = obj.value("version"); + if (!versionVal.isString()) { + qCritical() << "TreeModel::loadFromFile, bad string \"version\""; + return; + } + QString version = versionVal.toString(); + + // check version + if (version != "1.0" && version != "1.1") { + qCritical() << "TreeModel::loadFromFile, bad version number" << version << "expected \"1.0\" or \"1.1\""; + return; + } + + // root + QJsonValue rootVal = obj.value("root"); + if (!rootVal.isObject()) { + qCritical() << "TreeModel::loadFromFile, bad object \"root\""; + return; + } + + QList columnData; + columnData << QString("root"); + columnData << QString("root"); + columnData << QString("root"); + + // create root item + _rootItem = new TreeItem(columnData); + _rootItem->appendChild(loadNode(rootVal.toObject())); + } + } + + endResetModel(); +} + +void TreeModel::saveToFile(const QString& filename) { + + QJsonObject obj; + obj.insert("version", "1.1"); + + const int FIRST_CHILD = 0; + obj.insert("root", jsonFromItem(_rootItem->child(FIRST_CHILD))); + + QJsonDocument doc(obj); + QByteArray byteArray = doc.toJson(QJsonDocument::Indented); + + QFile file(filename); + if (!file.open(QIODevice::WriteOnly)) { + qCritical() << "TreeModel::safeToFile, failed to open file" << filename; + } else { + file.write(byteArray); + } +} + +void TreeModel::newNode(const QModelIndex& parent) { + TreeItem* parentItem = _rootItem; + if (parent.isValid()) { + parentItem = static_cast(parent.internalPointer()); + } + + beginInsertRows(parent, parentItem->childCount(), parentItem->childCount()); + TreeItem* childItem = newBlankTreeItem(); + parentItem->appendChild(childItem); + + endInsertRows(); +} + +void TreeModel::deleteNode(const QModelIndex& index) { + TreeItem* item = static_cast(index.internalPointer()); + TreeItem* parentItem = item->parentItem(); + int childNum = parentItem->findChild(item); + + if (childNum >= 0) { + beginRemoveRows(createIndex(0, 0, reinterpret_cast(parentItem)), childNum, childNum); + parentItem->removeChild(childNum); + endRemoveRows(); + } +} + +void TreeModel::insertNodeAbove(const QModelIndex& index) { + TreeItem* item = static_cast(index.internalPointer()); + TreeItem* parentItem = item->parentItem(); + int childNum = parentItem->findChild(item); + + if (childNum >= 0) { + TreeItem* newItem = newBlankTreeItem(); + QModelIndex parentIndex = createIndex(0, 0, reinterpret_cast(parentItem)); + + // remove item + beginRemoveRows(parentIndex, childNum, childNum); + parentItem->removeChild(childNum); + endRemoveRows(); + + // append item to newItem + newItem->appendChild(item); + + // then insert newItem + beginInsertRows(parentIndex, childNum, childNum); + parentItem->insertChild(childNum, newItem); + endInsertRows(); + } +} + +QVariantList TreeModel::getChildrenModelIndices(const QModelIndex& index) { + QVariantList indices; + + TreeItem* parent = static_cast(index.internalPointer()); + for (int i = 0; i < parent->childCount(); ++i) { + TreeItem* child = parent->child(i); + indices.push_back(createIndex(i, 0, reinterpret_cast(child))); + } + return indices; +} + +void TreeModel::copyNode(const QModelIndex& index) { + TreeItem* item = static_cast(index.internalPointer()); + // TODO: delete previous clipboard + _clipboard = item->cloneNode(); +} + +void TreeModel::copyNodeAndChildren(const QModelIndex& index) { + TreeItem* item = static_cast(index.internalPointer()); + // TODO: delete previous clipboard + _clipboard = item->cloneNodeAndChildren(); +} + +void TreeModel::pasteOver(const QModelIndex& index) { + if (_clipboard) { + TreeItem* item = static_cast(index.internalPointer()); + TreeItem* parentItem = item->parentItem(); + int childNum = parentItem->findChild(item); + + if (childNum >= 0) { + QModelIndex parentIndex = createIndex(0, 0, reinterpret_cast(parentItem)); + + // remove item + beginRemoveRows(parentIndex, childNum, childNum); + parentItem->removeChild(childNum); + endRemoveRows(); + + // then insert clone of _clipboard + beginInsertRows(parentIndex, childNum, childNum); + parentItem->insertChild(childNum, _clipboard->cloneNodeAndChildren()); + endInsertRows(); + } + } +} + +void TreeModel::pasteAsChild(const QModelIndex& index) { + if (_clipboard) { + TreeItem* parentItem = _rootItem; + if (index.isValid()) { + parentItem = static_cast(index.internalPointer()); + } + + beginInsertRows(index, parentItem->childCount(), parentItem->childCount()); + parentItem->appendChild(_clipboard->cloneNodeAndChildren()); + + endInsertRows(); + } +} + +TreeItem* TreeModel::loadNode(const QJsonObject& jsonObj) { + + // id + auto idVal = jsonObj.value("id"); + if (!idVal.isString()) { + qCritical() << "loadNode, bad string \"id\""; + return nullptr; + } + QString id = idVal.toString(); + + // type + auto typeVal = jsonObj.value("type"); + if (!typeVal.isString()) { + qCritical() << "loadNode, bad object \"type\", id =" << id; + return nullptr; + } + QString typeStr = typeVal.toString(); + + // data + auto dataValue = jsonObj.value("data"); + if (!dataValue.isObject()) { + qCritical() << "AnimNodeLoader, bad string \"data\", id =" << id; + return nullptr; + } + + QList columnData; + columnData << id; + columnData << typeStr; + columnData << dataValue.toVariant(); + + // create node + TreeItem* node = new TreeItem(columnData); + + // children + auto childrenValue = jsonObj.value("children"); + if (!childrenValue.isArray()) { + qCritical() << "AnimNodeLoader, bad array \"children\", id =" << id; + return nullptr; + } + auto childrenArray = childrenValue.toArray(); + for (const auto& childValue : childrenArray) { + if (!childValue.isObject()) { + qCritical() << "AnimNodeLoader, bad object in \"children\", id =" << id; + return nullptr; + } + TreeItem* child = loadNode(childValue.toObject()); + if (child) { + node->appendChild(child); + } else { + return nullptr; + } + } + + return node; +} + +TreeItem* TreeModel::getItem(const QModelIndex& index) const { + if (index.isValid()) { + TreeItem *item = static_cast(index.internalPointer()); + if (item) { + return item; + } + } + return _rootItem; +} + +QJsonObject TreeModel::jsonFromItem(TreeItem* treeItem) { + QJsonObject obj; + + const int ID_COLUMN = 0; + obj.insert("id", treeItem->data(ID_COLUMN).toJsonValue()); + + const int TYPE_COLUMN = 1; + obj.insert("type", treeItem->data(TYPE_COLUMN).toJsonValue()); + + const int DATA_COLUMN = 2; + QVariant data = treeItem->data(DATA_COLUMN); + if (data.canConvert()) { + obj.insert("data", data.value().toVariant().toJsonValue()); + } else { + obj.insert("data", data.toJsonValue()); + } + + QJsonArray children; + for (int i = 0; i < treeItem->childCount(); i++) { + children.push_back(jsonFromItem(treeItem->child(i))); + } + obj.insert("children", children); + + return obj; +} diff --git a/tools/animedit/treemodel.h b/tools/animedit/treemodel.h new file mode 100644 index 0000000000..3e18f24395 --- /dev/null +++ b/tools/animedit/treemodel.h @@ -0,0 +1,79 @@ +// +// TreeModel +// +// Created by Anthony Thibault on 6/5/2019 +// 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 +// + +#ifndef hifi_TreeModel_h +#define hifi_TreeModel_h + +#include +#include +#include +#include +#include +#include + +class TreeItem; + +class TreeModel : public QAbstractItemModel { + Q_OBJECT + +public: + enum TreeModelRoles + { + TreeModelRoleName = Qt::UserRole + 1, + TreeModelRoleType, + TreeModelRoleData + }; + + explicit TreeModel(QObject* parent = nullptr); + ~TreeModel() override; + + // QAbstractItemModel interface + QHash roleNames() const override; + Qt::ItemFlags flags(const QModelIndex& index) const override; + + // read methods + QVariant data(const QModelIndex& index, int role) const override; + QVariant headerData(int section, Qt::Orientation orientation, int role = TreeModelRoleName) const override; + QModelIndex index(int row, int column, const QModelIndex& parent = QModelIndex()) const override; + QModelIndex parent(const QModelIndex& index) const override; + int rowCount(const QModelIndex& parent = QModelIndex()) const override; + int columnCount(const QModelIndex& parent = QModelIndex()) const override; + + // write methods + bool setData(const QModelIndex& index, const QVariant& value, int role = TreeModelRoleName) override; + bool setHeaderData(int section, Qt::Orientation orientation, const QVariant& value, int role = TreeModelRoleName) override; + bool insertColumns(int position, int columns, const QModelIndex& parent = QModelIndex()) override; + bool removeColumns(int position, int columns, const QModelIndex& parent = QModelIndex()) override; + bool insertRows(int position, int rows, const QModelIndex& parent = QModelIndex()) override; + bool removeRows(int position, int rows, const QModelIndex& parent = QModelIndex()) override; + + // invokable from qml + Q_INVOKABLE void loadFromFile(const QString& filename); + Q_INVOKABLE void saveToFile(const QString& filename); + Q_INVOKABLE void newNode(const QModelIndex& parent); + Q_INVOKABLE void deleteNode(const QModelIndex& index); + Q_INVOKABLE void insertNodeAbove(const QModelIndex& index); + Q_INVOKABLE QVariantList getChildrenModelIndices(const QModelIndex& index); + Q_INVOKABLE void copyNode(const QModelIndex& index); + Q_INVOKABLE void copyNodeAndChildren(const QModelIndex& index); + Q_INVOKABLE void pasteOver(const QModelIndex& index); + Q_INVOKABLE void pasteAsChild(const QModelIndex& index); + +private: + TreeItem* loadNode(const QJsonObject& jsonObj); + TreeItem* getItem(const QModelIndex& index) const; + QJsonObject jsonFromItem(TreeItem* treeItem); + + TreeItem* _rootItem; + QHash _roleNameMapping; + TreeItem* _clipboard; +}; + +#endif From 69a063a7008811140ddd2cbda7e57d0d96c9cbfe Mon Sep 17 00:00:00 2001 From: luiscuenca Date: Mon, 25 Nov 2019 10:19:54 -0700 Subject: [PATCH 08/97] Better mouse wheel detection and attenuated touchpad X axis --- .../src/input-plugins/KeyboardMouseDevice.cpp | 38 +++++++++++-------- 1 file changed, 22 insertions(+), 16 deletions(-) diff --git a/libraries/input-plugins/src/input-plugins/KeyboardMouseDevice.cpp b/libraries/input-plugins/src/input-plugins/KeyboardMouseDevice.cpp index ea948a929b..b1b8875804 100755 --- a/libraries/input-plugins/src/input-plugins/KeyboardMouseDevice.cpp +++ b/libraries/input-plugins/src/input-plugins/KeyboardMouseDevice.cpp @@ -138,23 +138,28 @@ bool KeyboardMouseDevice::isWheelByTouchPad(QWheelEvent* event) { QPoint delta = event->angleDelta(); int deltaValueX = abs(delta.x()); int deltaValueY = abs(delta.y()); - const int MAX_WHEEL_DELTA_REPEAT = 20; const int COMMON_WHEEL_DELTA_VALUE = 120; - if (deltaValueX != 0) { - if (abs(_lastWheelDelta.x()) == deltaValueX) { - _wheelDeltaRepeatCount.setX(_wheelDeltaRepeatCount.x() + 1); - } else { - _wheelDeltaRepeatCount.setX(0); + // If deltaValueX or deltaValueY are multiple of 120 they are triggered by a mouse wheel + bool isMouseWheel = (deltaValueX + deltaValueY) % COMMON_WHEEL_DELTA_VALUE == 0; + if (!isMouseWheel) { + // We track repetition in wheel values to detect non-standard mouse wheels + const int MAX_WHEEL_DELTA_REPEAT = 10; + if (deltaValueX != 0) { + if (abs(_lastWheelDelta.x()) == deltaValueX) { + _wheelDeltaRepeatCount.setX(_wheelDeltaRepeatCount.x() + 1); + } else { + _wheelDeltaRepeatCount.setX(0); + } + return _wheelDeltaRepeatCount.x() < MAX_WHEEL_DELTA_REPEAT; } - return deltaValueX < COMMON_WHEEL_DELTA_VALUE && _wheelDeltaRepeatCount.x() < MAX_WHEEL_DELTA_REPEAT; - } - if (deltaValueY != 0) { - if (abs(_lastWheelDelta.y()) == deltaValueY) { - _wheelDeltaRepeatCount.setY(_wheelDeltaRepeatCount.y() + 1); - } else { - _wheelDeltaRepeatCount.setY(0); + if (deltaValueY != 0) { + if (abs(_lastWheelDelta.y()) == deltaValueY) { + _wheelDeltaRepeatCount.setY(_wheelDeltaRepeatCount.y() + 1); + } else { + _wheelDeltaRepeatCount.setY(0); + } + return _wheelDeltaRepeatCount.y() < MAX_WHEEL_DELTA_REPEAT; } - return deltaValueY < COMMON_WHEEL_DELTA_VALUE && _wheelDeltaRepeatCount.y() < MAX_WHEEL_DELTA_REPEAT; } return false; } @@ -166,8 +171,9 @@ void KeyboardMouseDevice::wheelEvent(QWheelEvent* event) { QPoint delta = event->angleDelta(); float deltaX = (float)delta.x(); float deltaY = (float)delta.y(); - _inputDevice->_axisStateMap[_inputDevice->makeInput(TOUCH_AXIS_X_POS).getChannel()].value = (deltaX > 0 ? deltaX : 0.0f); - _inputDevice->_axisStateMap[_inputDevice->makeInput(TOUCH_AXIS_X_NEG).getChannel()].value = (deltaX < 0 ? -deltaX : 0.0f); + const float WHEEL_X_ATTENUATION = 0.3f; + _inputDevice->_axisStateMap[_inputDevice->makeInput(TOUCH_AXIS_X_POS).getChannel()].value = (deltaX > 0 ? WHEEL_X_ATTENUATION * deltaX : 0.0f); + _inputDevice->_axisStateMap[_inputDevice->makeInput(TOUCH_AXIS_X_NEG).getChannel()].value = (deltaX < 0 ? -WHEEL_X_ATTENUATION * deltaX : 0.0f); // Y mouse is inverted positive is pointing up the screen const float WHEEL_Y_ATTENUATION = 0.02f; _inputDevice->_axisStateMap[_inputDevice->makeInput(TOUCH_AXIS_Y_POS).getChannel()].value = (deltaY < 0 ? -WHEEL_Y_ATTENUATION * deltaY : 0.0f); From 6e23924ed9e4ae536685d57325a80eb0959ecd1a Mon Sep 17 00:00:00 2001 From: Simon Walton Date: Mon, 25 Nov 2019 13:22:35 -0800 Subject: [PATCH 09/97] Add screenshare zone-property - WIP --- .../entities/src/EntityItemProperties.cpp | 23 +++++++++++++++++++ libraries/entities/src/EntityItemProperties.h | 3 +++ libraries/entities/src/EntityPropertyFlags.h | 3 +++ libraries/entities/src/ZoneEntityItem.cpp | 5 ++++ libraries/entities/src/ZoneEntityItem.h | 6 +++++ libraries/networking/src/udt/PacketHeaders.h | 1 + .../create/assets/data/createAppTooltips.json | 3 +++ scripts/system/create/edit.js | 3 ++- .../html/js/entityProperties.js | 6 +++++ 9 files changed, 52 insertions(+), 1 deletion(-) diff --git a/libraries/entities/src/EntityItemProperties.cpp b/libraries/entities/src/EntityItemProperties.cpp index 319dfc922f..a3bb72fa51 100644 --- a/libraries/entities/src/EntityItemProperties.cpp +++ b/libraries/entities/src/EntityItemProperties.cpp @@ -299,6 +299,16 @@ void EntityItemProperties::setAvatarPriorityFromString(const QString& mode) { } } +QString EntityItemProperties::getScreenshareAsString() const { return getComponentModeAsString(_screenshare); } +void EntityItemProperties::setScreenshareFromString(const QString& mode) { + auto modeItr = stringToComponentMode.find(mode.toLower()); + if (modeItr != stringToComponentMode.end()) { + _screenshare = modeItr.value(); + _screenshareChanged = true; + } +} + + inline void addTextEffect(QHash& lookup, TextEffect effect) { lookup[TextEffectHelpers::getNameForTextEffect(effect)] = effect; } const QHash stringToTextEffectLookup = [] { QHash toReturn; @@ -566,6 +576,7 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const { CHECK_PROPERTY_CHANGE(PROP_HAZE_MODE, hazeMode); CHECK_PROPERTY_CHANGE(PROP_BLOOM_MODE, bloomMode); CHECK_PROPERTY_CHANGE(PROP_AVATAR_PRIORITY, avatarPriority); + CHECK_PROPERTY_CHANGE(PROP_SCREENSHARE, screenshare); // Polyvox CHECK_PROPERTY_CHANGE(PROP_VOXEL_VOLUME_SIZE, voxelVolumeSize); @@ -1429,6 +1440,8 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const { * @property {Entities.AvatarPriorityMode} avatarPriority="inherit" - Configures the priority of updates from avatars in the * zone to other clients. * + * @property {Entities.ScreenshareMode} screenshare="inherit" - Configures a zone for screen-sharing. + * * @example Create a zone that casts a red key light along the x-axis. * var zone = Entities.addEntity({ * type: "Zone", @@ -1779,6 +1792,7 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(PROP_HAZE_MODE, hazeMode, getHazeModeAsString()); COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(PROP_BLOOM_MODE, bloomMode, getBloomModeAsString()); COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(PROP_AVATAR_PRIORITY, avatarPriority, getAvatarPriorityAsString()); + COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(PROP_SCREENSHARE, screenshare, getScreenshareAsString()); } // Web only @@ -2150,6 +2164,7 @@ void EntityItemProperties::copyFromScriptValue(const QScriptValue& object, bool COPY_PROPERTY_FROM_QSCRIPTVALUE_ENUM(hazeMode, HazeMode); COPY_PROPERTY_FROM_QSCRIPTVALUE_ENUM(bloomMode, BloomMode); COPY_PROPERTY_FROM_QSCRIPTVALUE_ENUM(avatarPriority, AvatarPriority); + COPY_PROPERTY_FROM_QSCRIPTVALUE_ENUM(screenshare, Screenshare); // Polyvox COPY_PROPERTY_FROM_QSCRIPTVALUE(voxelVolumeSize, vec3, setVoxelVolumeSize); @@ -2438,6 +2453,7 @@ void EntityItemProperties::merge(const EntityItemProperties& other) { COPY_PROPERTY_IF_CHANGED(hazeMode); COPY_PROPERTY_IF_CHANGED(bloomMode); COPY_PROPERTY_IF_CHANGED(avatarPriority); + COPY_PROPERTY_IF_CHANGED(screenshare); // Polyvox COPY_PROPERTY_IF_CHANGED(voxelVolumeSize); @@ -2834,6 +2850,7 @@ bool EntityItemProperties::getPropertyInfo(const QString& propertyName, EntityPr ADD_PROPERTY_TO_MAP(PROP_HAZE_MODE, HazeMode, hazeMode, uint32_t); ADD_PROPERTY_TO_MAP(PROP_BLOOM_MODE, BloomMode, bloomMode, uint32_t); ADD_PROPERTY_TO_MAP(PROP_AVATAR_PRIORITY, AvatarPriority, avatarPriority, uint32_t); + ADD_PROPERTY_TO_MAP(PROP_SCREENSHARE, Screenshare, screenshare, uint32_t); // Polyvox ADD_PROPERTY_TO_MAP(PROP_VOXEL_VOLUME_SIZE, VoxelVolumeSize, voxelVolumeSize, vec3); @@ -3252,6 +3269,7 @@ OctreeElement::AppendState EntityItemProperties::encodeEntityEditPacket(PacketTy APPEND_ENTITY_PROPERTY(PROP_HAZE_MODE, (uint32_t)properties.getHazeMode()); APPEND_ENTITY_PROPERTY(PROP_BLOOM_MODE, (uint32_t)properties.getBloomMode()); APPEND_ENTITY_PROPERTY(PROP_AVATAR_PRIORITY, (uint32_t)properties.getAvatarPriority()); + APPEND_ENTITY_PROPERTY(PROP_SCREENSHARE, (uint32_t)properties.getScreenshare()); } if (properties.getType() == EntityTypes::PolyVox) { @@ -3726,6 +3744,7 @@ bool EntityItemProperties::decodeEntityEditPacket(const unsigned char* data, int READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_HAZE_MODE, uint32_t, setHazeMode); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_BLOOM_MODE, uint32_t, setBloomMode); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_AVATAR_PRIORITY, uint32_t, setAvatarPriority); + READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_SCREENSHARE, uint32_t, setScreenshare); } if (properties.getType() == EntityTypes::PolyVox) { @@ -4117,6 +4136,7 @@ void EntityItemProperties::markAllChanged() { _hazeModeChanged = true; _bloomModeChanged = true; _avatarPriorityChanged = true; + _screenshareChanged = true; // Polyvox _voxelVolumeSizeChanged = true; @@ -4739,6 +4759,9 @@ QList EntityItemProperties::listChangedProperties() { if (avatarPriorityChanged()) { out += "avatarPriority"; } + if (screenshareChanged()) { + out += "screenshare"; + } // Polyvox if (voxelVolumeSizeChanged()) { diff --git a/libraries/entities/src/EntityItemProperties.h b/libraries/entities/src/EntityItemProperties.h index 63d8183899..fbd941bd85 100644 --- a/libraries/entities/src/EntityItemProperties.h +++ b/libraries/entities/src/EntityItemProperties.h @@ -337,6 +337,7 @@ public: DEFINE_PROPERTY_REF_ENUM(PROP_HAZE_MODE, HazeMode, hazeMode, uint32_t, (uint32_t)COMPONENT_MODE_INHERIT); DEFINE_PROPERTY_REF_ENUM(PROP_BLOOM_MODE, BloomMode, bloomMode, uint32_t, (uint32_t)COMPONENT_MODE_INHERIT); DEFINE_PROPERTY_REF_ENUM(PROP_AVATAR_PRIORITY, AvatarPriority, avatarPriority, uint32_t, (uint32_t)COMPONENT_MODE_INHERIT); + DEFINE_PROPERTY_REF_ENUM(PROP_SCREENSHARE, Screenshare, screenshare, uint32_t, (uint32_t)COMPONENT_MODE_INHERIT); // Polyvox DEFINE_PROPERTY_REF(PROP_VOXEL_VOLUME_SIZE, VoxelVolumeSize, voxelVolumeSize, glm::vec3, PolyVoxEntityItem::DEFAULT_VOXEL_VOLUME_SIZE); @@ -699,6 +700,8 @@ inline QDebug operator<<(QDebug debug, const EntityItemProperties& properties) { DEBUG_PROPERTY_IF_CHANGED(debug, properties, AvatarPriority, avatarPriority, ""); + DEBUG_PROPERTY_IF_CHANGED(debug, properties, Screenshare, screenshare, ""); + DEBUG_PROPERTY_IF_CHANGED(debug, properties, EntityHostTypeAsString, entityHostType, ""); DEBUG_PROPERTY_IF_CHANGED(debug, properties, OwningAvatarID, owningAvatarID, ""); diff --git a/libraries/entities/src/EntityPropertyFlags.h b/libraries/entities/src/EntityPropertyFlags.h index d5af337a7d..1ffd8fdc3c 100644 --- a/libraries/entities/src/EntityPropertyFlags.h +++ b/libraries/entities/src/EntityPropertyFlags.h @@ -161,6 +161,7 @@ enum EntityPropertyList { PROP_DERIVED_31, PROP_DERIVED_32, PROP_DERIVED_33, + PROP_DERIVED_34, PROP_AFTER_LAST_ITEM, @@ -290,6 +291,8 @@ enum EntityPropertyList { PROP_BLOOM_MODE = PROP_DERIVED_32, // Avatar priority PROP_AVATAR_PRIORITY = PROP_DERIVED_33, + // Screen-sharing + PROP_SCREENSHARE = PROP_DERIVED_34, // Polyvox PROP_VOXEL_VOLUME_SIZE = PROP_DERIVED_0, diff --git a/libraries/entities/src/ZoneEntityItem.cpp b/libraries/entities/src/ZoneEntityItem.cpp index d54998e74f..4030291a44 100644 --- a/libraries/entities/src/ZoneEntityItem.cpp +++ b/libraries/entities/src/ZoneEntityItem.cpp @@ -71,6 +71,7 @@ EntityItemProperties ZoneEntityItem::getProperties(const EntityPropertyFlags& de COPY_ENTITY_PROPERTY_TO_PROPERTIES(hazeMode, getHazeMode); COPY_ENTITY_PROPERTY_TO_PROPERTIES(bloomMode, getBloomMode); COPY_ENTITY_PROPERTY_TO_PROPERTIES(avatarPriority, getAvatarPriority); + COPY_ENTITY_PROPERTY_TO_PROPERTIES(screenshare, getScreenshare); return properties; } @@ -118,6 +119,7 @@ bool ZoneEntityItem::setSubClassProperties(const EntityItemProperties& propertie SET_ENTITY_PROPERTY_FROM_PROPERTIES(hazeMode, setHazeMode); SET_ENTITY_PROPERTY_FROM_PROPERTIES(bloomMode, setBloomMode); SET_ENTITY_PROPERTY_FROM_PROPERTIES(avatarPriority, setAvatarPriority); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(screenshare, setScreenshare); somethingChanged = somethingChanged || _keyLightPropertiesChanged || _ambientLightPropertiesChanged || _skyboxPropertiesChanged || _hazePropertiesChanged || _bloomPropertiesChanged; @@ -194,6 +196,7 @@ int ZoneEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data, READ_ENTITY_PROPERTY(PROP_HAZE_MODE, uint32_t, setHazeMode); READ_ENTITY_PROPERTY(PROP_BLOOM_MODE, uint32_t, setBloomMode); READ_ENTITY_PROPERTY(PROP_AVATAR_PRIORITY, uint32_t, setAvatarPriority); + READ_ENTITY_PROPERTY(PROP_SCREENSHARE, uint32_t, setScreenshare); return bytesRead; } @@ -214,6 +217,7 @@ EntityPropertyFlags ZoneEntityItem::getEntityProperties(EncodeBitstreamParams& p requestedProperties += PROP_GHOSTING_ALLOWED; requestedProperties += PROP_FILTER_URL; requestedProperties += PROP_AVATAR_PRIORITY; + requestedProperties += PROP_SCREENSHARE; requestedProperties += PROP_KEY_LIGHT_MODE; requestedProperties += PROP_AMBIENT_LIGHT_MODE; @@ -260,6 +264,7 @@ void ZoneEntityItem::appendSubclassData(OctreePacketData* packetData, EncodeBits APPEND_ENTITY_PROPERTY(PROP_HAZE_MODE, (uint32_t)getHazeMode()); APPEND_ENTITY_PROPERTY(PROP_BLOOM_MODE, (uint32_t)getBloomMode()); APPEND_ENTITY_PROPERTY(PROP_AVATAR_PRIORITY, getAvatarPriority()); + APPEND_ENTITY_PROPERTY(PROP_SCREENSHARE, getScreenshare()); } void ZoneEntityItem::debugDump() const { diff --git a/libraries/entities/src/ZoneEntityItem.h b/libraries/entities/src/ZoneEntityItem.h index d6647e701e..295727d657 100644 --- a/libraries/entities/src/ZoneEntityItem.h +++ b/libraries/entities/src/ZoneEntityItem.h @@ -102,6 +102,9 @@ public: uint32_t getAvatarPriority() const { return _avatarPriority; } void setAvatarPriority(uint32_t value) { _avatarPriority = value; } + uint32_t getScreenshare() const { return _screenshare; } + void setScreenshare(uint32_t value) { _screenshare = value; } + bool keyLightPropertiesChanged() const { return _keyLightPropertiesChanged; } bool ambientLightPropertiesChanged() const { return _ambientLightPropertiesChanged; } bool skyboxPropertiesChanged() const { return _skyboxPropertiesChanged; } @@ -156,6 +159,9 @@ protected: // Avatar-updates priority uint32_t _avatarPriority { COMPONENT_MODE_INHERIT }; + // Screen-sharing zone + uint32_t _screenshare { COMPONENT_MODE_INHERIT }; + // Dirty flags turn true when either keylight properties is changing values. bool _keyLightPropertiesChanged { false }; bool _ambientLightPropertiesChanged { false }; diff --git a/libraries/networking/src/udt/PacketHeaders.h b/libraries/networking/src/udt/PacketHeaders.h index 75904d8122..805e5d3a09 100644 --- a/libraries/networking/src/udt/PacketHeaders.h +++ b/libraries/networking/src/udt/PacketHeaders.h @@ -277,6 +277,7 @@ enum class EntityVersion : PacketVersion { ShadowBiasAndDistance, TextEntityFonts, ScriptServerKinematicMotion, + ScreenshareZone, // Add new versions above here NUM_PACKET_TYPE, diff --git a/scripts/system/create/assets/data/createAppTooltips.json b/scripts/system/create/assets/data/createAppTooltips.json index 8b160e0630..da12d2d503 100644 --- a/scripts/system/create/assets/data/createAppTooltips.json +++ b/scripts/system/create/assets/data/createAppTooltips.json @@ -147,6 +147,9 @@ "avatarPriority": { "tooltip": "Alter Avatars' update priorities." }, + "screenshare": { + "tooltip": "Enable screen-sharing within this zone" + }, "modelURL": { "tooltip": "A mesh model from an FBX or OBJ file." }, diff --git a/scripts/system/create/edit.js b/scripts/system/create/edit.js index 828fd70e6f..ee4a11f91a 100644 --- a/scripts/system/create/edit.js +++ b/scripts/system/create/edit.js @@ -393,7 +393,8 @@ const DEFAULT_ENTITY_PROPERTIES = { }, shapeType: "box", bloomMode: "inherit", - avatarPriority: "inherit" + avatarPriority: "inherit", + screenshare: "inherit", }, Model: { collisionShape: "none", diff --git a/scripts/system/create/entityProperties/html/js/entityProperties.js b/scripts/system/create/entityProperties/html/js/entityProperties.js index b5a9b77bf4..64d44cc270 100644 --- a/scripts/system/create/entityProperties/html/js/entityProperties.js +++ b/scripts/system/create/entityProperties/html/js/entityProperties.js @@ -497,6 +497,12 @@ const GROUPS = [ options: { inherit: "Inherit", crowd: "Crowd", hero: "Hero" }, propertyID: "avatarPriority", }, + { + label: "Screen-share", + type: "dropdown", + options: { inherit: "Inherit", disabled: "Off", enabled: "On" }, + propertyID: "screenshare", + } ] }, From d8ba0564b528ae252391b1e5cb033c42e1769b02 Mon Sep 17 00:00:00 2001 From: Dante Ruiz Date: Fri, 22 Nov 2019 15:55:57 -0800 Subject: [PATCH 10/97] Adding QT Launcher Documention --- launchers/qt/BUILD.md | 11 +++++++++++ launchers/qt/readme.md | 20 ++++++++++++++++++++ 2 files changed, 31 insertions(+) create mode 100644 launchers/qt/BUILD.md create mode 100644 launchers/qt/readme.md diff --git a/launchers/qt/BUILD.md b/launchers/qt/BUILD.md new file mode 100644 index 0000000000..de6b91458c --- /dev/null +++ b/launchers/qt/BUILD.md @@ -0,0 +1,11 @@ +# Dependencies +- [cmake](https://cmake.org/download/): 3.9 + +# Windows +cmake -G "Visual Studio 16 2019" .. + +# OSX +cmake -G Xcode .. + + +if you wish to not use the compiled qml files pass the `-DLAUNCHER_SOURCE_TREE_RESOURCES=On` argument to cmake. \ No newline at end of file diff --git a/launchers/qt/readme.md b/launchers/qt/readme.md new file mode 100644 index 0000000000..fda076340a --- /dev/null +++ b/launchers/qt/readme.md @@ -0,0 +1,20 @@ +# HQ Launcher +Behavior of the HQ Launcher is as follows: +* Launching the user in the current HQ domain +* Update the Interface client to the current version. +* Update the HQ Launcher to the current version + +# directory structure + +## src/ - contains the c++ and objective-c. +* LauncherState - hold majority of the logic of the launcher (signin, config file, updating, running launcher) +* LauncherInstaller_windows - logic of how to install/uninstall HQ Launcher on windows +* Helper - helper functions +* UserSettings - getting the users setting (home location) from metaverse +* BuildsRequest - getting / parsing the build info from thunder api +* LoginRequest - checks the login credentials the user typed in. +* Unzipper - helper class for extracting zip files + +## resources/ +* image/ - Holds the images and icon that are used by the launcher +* qml/ - UI elements - `QML_FILE_FOR_UI_STATE` varible in LauchherState defines what qml files are used by the laucnher. \ No newline at end of file From a38e0007f86e873efda32d87bd7769edf0f9311c Mon Sep 17 00:00:00 2001 From: milad Date: Mon, 25 Nov 2019 13:32:48 -0800 Subject: [PATCH 11/97] trying to go back several directories for the mac build --- interface/src/scripting/ScreenshareScriptingInterface.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/scripting/ScreenshareScriptingInterface.h b/interface/src/scripting/ScreenshareScriptingInterface.h index 9dc828c13b..717f402238 100644 --- a/interface/src/scripting/ScreenshareScriptingInterface.h +++ b/interface/src/scripting/ScreenshareScriptingInterface.h @@ -52,7 +52,7 @@ private: #ifdef Q_OS_WIN const QString SCREENSHARE_EXE_PATH{ QCoreApplication::applicationDirPath() + "/hifi-screenshare/hifi-screenshare.exe" }; #elif defined(Q_OS_MAC) - const QString SCREENSHARE_EXE_PATH{ QCoreApplication::applicationDirPath() + "/hifi-screenshare/hifi-screenshare.app" }; + const QString SCREENSHARE_EXE_PATH{ QCoreApplication::applicationDirPath() + "../../../hifi-screenshare.app" }; #else // This path won't exist on other platforms, so the Screenshare Scripting Interface will exit early when invoked. const QString SCREENSHARE_EXE_PATH{ QCoreApplication::applicationDirPath() + "/hifi-screenshare/hifi-screenshare" }; From 8b6df032e41500c44faee1a1a41da7716f007b97 Mon Sep 17 00:00:00 2001 From: milad Date: Mon, 25 Nov 2019 14:40:38 -0800 Subject: [PATCH 12/97] forgot a slash --- interface/src/scripting/ScreenshareScriptingInterface.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/scripting/ScreenshareScriptingInterface.h b/interface/src/scripting/ScreenshareScriptingInterface.h index 717f402238..c9b389f6c8 100644 --- a/interface/src/scripting/ScreenshareScriptingInterface.h +++ b/interface/src/scripting/ScreenshareScriptingInterface.h @@ -52,7 +52,7 @@ private: #ifdef Q_OS_WIN const QString SCREENSHARE_EXE_PATH{ QCoreApplication::applicationDirPath() + "/hifi-screenshare/hifi-screenshare.exe" }; #elif defined(Q_OS_MAC) - const QString SCREENSHARE_EXE_PATH{ QCoreApplication::applicationDirPath() + "../../../hifi-screenshare.app" }; + const QString SCREENSHARE_EXE_PATH{ QCoreApplication::applicationDirPath() + "/../../../hifi-screenshare.app" }; #else // This path won't exist on other platforms, so the Screenshare Scripting Interface will exit early when invoked. const QString SCREENSHARE_EXE_PATH{ QCoreApplication::applicationDirPath() + "/hifi-screenshare/hifi-screenshare" }; From c08a18c517c0e23c34112f4bb1e0bcded92d4c62 Mon Sep 17 00:00:00 2001 From: danteruiz Date: Mon, 25 Nov 2019 14:50:58 -0800 Subject: [PATCH 13/97] making requested changes --- launchers/qt/BUILD.md | 10 ++++++---- launchers/qt/readme.md | 36 +++++++++++++++++++++++++----------- 2 files changed, 31 insertions(+), 15 deletions(-) diff --git a/launchers/qt/BUILD.md b/launchers/qt/BUILD.md index de6b91458c..d08aa6bfa0 100644 --- a/launchers/qt/BUILD.md +++ b/launchers/qt/BUILD.md @@ -2,10 +2,12 @@ - [cmake](https://cmake.org/download/): 3.9 # Windows -cmake -G "Visual Studio 16 2019" .. +* Download `Visual Studio 2019` +`cmake -G "Visual Studio 16 2019" ..` -# OSX -cmake -G Xcode .. +# MacOS +* Install `Xcode` +`cmake -G Xcode ..` -if you wish to not use the compiled qml files pass the `-DLAUNCHER_SOURCE_TREE_RESOURCES=On` argument to cmake. \ No newline at end of file +If you wish to not use the compiled qml files, pass the `-DLAUNCHER_SOURCE_TREE_RESOURCES=On` argument to cmake. \ No newline at end of file diff --git a/launchers/qt/readme.md b/launchers/qt/readme.md index fda076340a..beaa54eebe 100644 --- a/launchers/qt/readme.md +++ b/launchers/qt/readme.md @@ -1,20 +1,34 @@ # HQ Launcher Behavior of the HQ Launcher is as follows: +* Update the HQ Launcher to the latest version +* Sign up and sign in is the user is not +* Download the latest Interface client * Launching the user in the current HQ domain -* Update the Interface client to the current version. -* Update the HQ Launcher to the current version # directory structure ## src/ - contains the c++ and objective-c. -* LauncherState - hold majority of the logic of the launcher (signin, config file, updating, running launcher) -* LauncherInstaller_windows - logic of how to install/uninstall HQ Launcher on windows -* Helper - helper functions -* UserSettings - getting the users setting (home location) from metaverse -* BuildsRequest - getting / parsing the build info from thunder api -* LoginRequest - checks the login credentials the user typed in. -* Unzipper - helper class for extracting zip files +* `BuildsRequest` - getting / parsing the build info from thunder api +* `CommandlineOptions` - parses and stores commandline arguments +* `Helper` - helper functions +* `Helper_darwin` - objective-c implemention of helper funcions +* `Helper_windows` - helper function that depend on windows api +* `Launcher` - initialized the Launcher Application and resources +* `LauncherInstaller_windows` - logic of how to install/uninstall HQ Launcher on windows +* `LauncherState` - hold majority of the logic of the launcher (signin, config file, updating, running launcher) + * config files hold the following saved data + * logged in + * home location +* `LauncherWindows` - wrapper for `QQuickWindow` that implements drag feature +* `LoginRequest` - checks the login credentials the user typed in. +* `NSTask+NSTaskExecveAddtions` - Extension of NSTask for replacing Launcher process with interface client process +* `PathUtils` - Helper class for getting relative paths for HQ Launcher +* `SignupRequest` - Determines if the users request to signup for a new account succeeded based on the entered credentials +* `Unzipper` - helper class for extracting zip files +* `UserSettingsRequest` - getting the users setting (home location) from metaverse ## resources/ -* image/ - Holds the images and icon that are used by the launcher -* qml/ - UI elements - `QML_FILE_FOR_UI_STATE` varible in LauchherState defines what qml files are used by the laucnher. \ No newline at end of file +* `images/`- Holds the images and icon that are used by the launcher +* `qml/` + * UI elements + * `QML_FILE_FOR_UI_STATE` varible in LauchherState defines what qml files are used by the laucnher. \ No newline at end of file From e0c5edfccd6a4356f80ca0bd1450bf053169052c Mon Sep 17 00:00:00 2001 From: danteruiz Date: Mon, 25 Nov 2019 14:58:40 -0800 Subject: [PATCH 14/97] fix typos --- launchers/qt/readme.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/launchers/qt/readme.md b/launchers/qt/readme.md index beaa54eebe..917c647511 100644 --- a/launchers/qt/readme.md +++ b/launchers/qt/readme.md @@ -21,7 +21,7 @@ Behavior of the HQ Launcher is as follows: * home location * `LauncherWindows` - wrapper for `QQuickWindow` that implements drag feature * `LoginRequest` - checks the login credentials the user typed in. -* `NSTask+NSTaskExecveAddtions` - Extension of NSTask for replacing Launcher process with interface client process +* `NSTask+NSTaskExecveAdditions` - Extension of NSTask for replacing Launcher process with interface client process * `PathUtils` - Helper class for getting relative paths for HQ Launcher * `SignupRequest` - Determines if the users request to signup for a new account succeeded based on the entered credentials * `Unzipper` - helper class for extracting zip files @@ -31,4 +31,4 @@ Behavior of the HQ Launcher is as follows: * `images/`- Holds the images and icon that are used by the launcher * `qml/` * UI elements - * `QML_FILE_FOR_UI_STATE` varible in LauchherState defines what qml files are used by the laucnher. \ No newline at end of file + * `QML_FILE_FOR_UI_STATE` variable in `LauchherState` defines what QML files are used by the Laucnher. \ No newline at end of file From 60140a3aca0fe68e5a493a50e49cbc9dde5ad341 Mon Sep 17 00:00:00 2001 From: danteruiz Date: Mon, 25 Nov 2019 15:22:47 -0800 Subject: [PATCH 15/97] fix more typos --- launchers/qt/readme.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/launchers/qt/readme.md b/launchers/qt/readme.md index 917c647511..ce4e846172 100644 --- a/launchers/qt/readme.md +++ b/launchers/qt/readme.md @@ -1,9 +1,9 @@ # HQ Launcher Behavior of the HQ Launcher is as follows: * Update the HQ Launcher to the latest version -* Sign up and sign in is the user is not +* Sign up or sign in if is the user is not already signed in * Download the latest Interface client -* Launching the user in the current HQ domain +* Launch the user in the current HQ domain # directory structure @@ -31,4 +31,4 @@ Behavior of the HQ Launcher is as follows: * `images/`- Holds the images and icon that are used by the launcher * `qml/` * UI elements - * `QML_FILE_FOR_UI_STATE` variable in `LauchherState` defines what QML files are used by the Laucnher. \ No newline at end of file + * `QML_FILE_FOR_UI_STATE` variable in `LauncherState` defines what QML files are used by the Launcher. \ No newline at end of file From d797e3312382947e557877ad257dc5f78e36423a Mon Sep 17 00:00:00 2001 From: David Rowe Date: Tue, 26 Nov 2019 13:37:04 +1300 Subject: [PATCH 16/97] Stats JSDoc --- interface/src/RefreshRateManager.cpp | 52 + interface/src/ui/Stats.h | 1343 +++++++++++++++++--------- 2 files changed, 915 insertions(+), 480 deletions(-) diff --git a/interface/src/RefreshRateManager.cpp b/interface/src/RefreshRateManager.cpp index e1da1699d7..beb1363aac 100644 --- a/interface/src/RefreshRateManager.cpp +++ b/interface/src/RefreshRateManager.cpp @@ -17,12 +17,64 @@ static const int VR_TARGET_RATE = 90; +/**jsdoc + *

Refresh rate profile.

+ * + * + * + * + * + * + * + * + * + *
Refresh Rate ProfileDescription
"Eco"Low refresh rate, which is reduced when Interface doesn't have focus or is + * minimized.
"Interactive"Medium refresh rate, which is reduced when Interface doesn't have focus or is + * minimized.
"Realtime"High refresh rate, even when Interface doesn't have focus or is minimized. + *
+ * + * @typedef {string} RefreshRateProfile + */ static const std::array REFRESH_RATE_PROFILE_TO_STRING = { { "Eco", "Interactive", "Realtime" } }; +/**jsdoc + *

Interface states that affect the refresh rate.

+ * + * + * + * + * + * + * + * + * + * + * + * + * + *
Refresh Rate RegimeDescription
"FocusActive"Interface has focus and the user is active or is in VR.
"FocusInactive"Interface has focus and the user is inactive.
"Unfocus"Interface doesn't have focus.
"Minimized"Interface is minimized.
"StartUp"Interface is starting up.
"ShutDown"Interface is shutting down.
+ * + * @typedef {string} RefreshRateRegime + */ static const std::array REFRESH_RATE_REGIME_TO_STRING = { { "FocusActive", "FocusInactive", "Unfocus", "Minimized", "StartUp", "ShutDown" } }; +/**jsdoc + *

Interface operates in different modes to provide different user experiences (UX).

+ * + * + * + * + * + * + * + * + * + *
UX ModeDescription
"Desktop"Desktop user experience mode.
"VR"VR user experience mode.
+ * + * @typedef {string} UXMode + */ static const std::array UX_MODE_TO_STRING = { { "Desktop", "VR" } }; diff --git a/interface/src/ui/Stats.h b/interface/src/ui/Stats.h index b87e3a3dbc..f9d53dc29e 100644 --- a/interface/src/ui/Stats.h +++ b/interface/src/ui/Stats.h @@ -24,6 +24,8 @@ private: \ type _##name{ initialValue }; /**jsdoc + * The Stats API provides and statistics on Interface and domain operation, per the statistics overlay. + * * @namespace Stats * * @hifi-interface @@ -32,157 +34,432 @@ private: \ * @hifi-server-entity * @hifi-assignment-client * - * @property {boolean} expanded - * @property {boolean} timingExpanded - Read-only. - * @property {string} monospaceFont - Read-only. + * @property {boolean} expanded - true if the statistics overlay should be in expanded form when the overlay is + * displayed, false if it shouldn't be expanded. + * @property {boolean} timingExpanded - true if timing details should be displayed when the statistics overlay is + * displayed in expanded form, false if timing details should not be displayed. Set by the menu item, + * Developer > Timing > Performance Timer > Display Timing Details. + * Read-only. + * @property {string} monospaceFont - The name of the monospace font used in the statistics overlay. + * Read-only. * - * @property {number} serverCount - Read-only. - * @property {number} renderrate - How often the app is creating new gpu::Frames. Read-only. - * @property {number} presentrate - How often the display plugin is presenting to the device. Read-only. - * @property {number} stutterrate - How often the display device is reprojecting old frames. Read-only. + * @property {number} serverCount - The number of servers that Interface is connected to. + * Read-only. + * @property {number} renderrate - The rate at which new GPU frames are being created, in Hz. + * Read-only. + * @property {number} presentrate - The rate at which the display plugin is presenting to the display device, in Hz. + * Read-only. + * @property {number} stutterrate - The rate at which the display plugin is reprojecting old GPU frames, in Hz. + * Read-only. * - * @property {number} appdropped - Read-only. - * @property {number} longsubmits - Read-only. - * @property {number} longrenders - Read-only. - * @property {number} longframes - Read-only. + * @property {number} appdropped - The number of times a frame has not been provided to the display device in time. + * Read-only. + * @property {number} longsubmits - The number of times the display devices takes longer than 11ms to return after being given + * frame. + * Read-only. + * @property {number} longrenders - The number of times it has taken longer than 11ms to submit a new frame to the display + * device. + * Read-only. + * @property {number} longframes - The number of times longsubmits + longrenders has taken longer than 15ms. + * Read-only. * - * @property {number} presentnewrate - Read-only. - * @property {number} presentdroprate - Read-only. - * @property {number} gameLoopRate - Read-only. - * @property {number} avatarCount - Read-only. - * @property {number} heroAvatarCount - Read-only. - * @property {number} physicsObjectCount - Read-only. - * @property {number} updatedAvatarCount - Read-only. - * @property {number} updatedHeroAvatarCount - Read-only. - * @property {number} notUpdatedAvatarCount - Read-only. - * @property {number} packetInCount - Read-only. - * @property {number} packetOutCount - Read-only. - * @property {number} mbpsIn - Read-only. - * @property {number} mbpsOut - Read-only. - * @property {number} assetMbpsIn - Read-only. - * @property {number} assetMbpsOut - Read-only. - * @property {number} audioPing - Read-only. - * @property {number} avatarPing - Read-only. - * @property {number} entitiesPing - Read-only. - * @property {number} assetPing - Read-only. - * @property {number} messagePing - Read-only. - * @property {Vec3} position - Read-only. - * @property {number} speed - Read-only. - * @property {number} yaw - Read-only. - * @property {number} avatarMixerInKbps - Read-only. - * @property {number} avatarMixerInPps - Read-only. - * @property {number} avatarMixerOutKbps - Read-only. - * @property {number} avatarMixerOutPps - Read-only. - * @property {number} myAvatarSendRate - Read-only. - * - * @property {number} audioMixerInKbps - Read-only. - * @property {number} audioMixerInPps - Read-only. - * @property {number} audioMixerOutKbps - Read-only. - * @property {number} audioMixerOutPps - Read-only. - * @property {number} audioMixerKbps - Read-only. - * @property {number} audioMixerPps - Read-only. - * @property {number} audioOutboundPPS - Read-only. - * @property {number} audioSilentOutboundPPS - Read-only. - * @property {number} audioAudioInboundPPS - Read-only. - * @property {number} audioSilentInboundPPS - Read-only. - * @property {number} audioPacketLoss - Read-only. - * @property {string} audioCodec - Read-only. - * @property {string} audioNoiseGate - Read-only. - * @property {Vec2} audioInjectors - Read-only. - * @property {number} entityPacketsInKbps - Read-only. - * - * @property {number} downloads - Read-only. - * @property {number} downloadLimit - Read-only. - * @property {number} downloadsPending - Read-only. - * @property {string[]} downloadUrls - Read-only. - * @property {number} processing - Read-only. - * @property {number} processingPending - Read-only. - * @property {number} triangles - Read-only. - * @property {number} materialSwitches - Read-only. - * @property {number} itemConsidered - Read-only. - * @property {number} itemOutOfView - Read-only. - * @property {number} itemTooSmall - Read-only. - * @property {number} itemRendered - Read-only. - * @property {number} shadowConsidered - Read-only. - * @property {number} shadowOutOfView - Read-only. - * @property {number} shadowTooSmall - Read-only. - * @property {number} shadowRendered - Read-only. - * @property {string} sendingMode - Read-only. - * @property {string} packetStats - Read-only. - * @property {number} lodAngle - Read-only. - * @property {number} lodTargetFramerate - Read-only. - * @property {string} lodStatus - Read-only. - * @property {string} timingStats - Read-only. - * @property {string} gameUpdateStats - Read-only. - * @property {number} serverElements - Read-only. - * @property {number} serverInternal - Read-only. - * @property {number} serverLeaves - Read-only. - * @property {number} localElements - Read-only. - * @property {number} localInternal - Read-only. - * @property {number} localLeaves - Read-only. - * @property {number} rectifiedTextureCount - Read-only. - * @property {number} decimatedTextureCount - Read-only. - * @property {number} gpuBuffers - Read-only. - * @property {number} gpuBufferMemory - Read-only. - * @property {number} gpuTextures - Read-only. - * @property {number} glContextSwapchainMemory - Read-only. - * @property {number} qmlTextureMemory - Read-only. - * @property {number} texturePendingTransfers - Read-only. - * @property {number} gpuTextureMemory - Read-only. - * @property {number} gpuTextureResidentMemory - Read-only. - * @property {number} gpuTextureFramebufferMemory - Read-only. - * @property {number} gpuTextureResourceMemory - Read-only. - * @property {number} gpuTextureResourceIdealMemory - Read-only. - * @property {number} gpuTextureResourcePopulatedMemory - Read-only. - * @property {number} gpuTextureExternalMemory - Read-only. - * @property {string} gpuTextureMemoryPressureState - Read-only. - * @property {number} gpuFreeMemory - Read-only. - * @property {number} gpuFrameTime - Read-only. - * @property {number} batchFrameTime - Read-only. - * @property {number} engineFrameTime - Read-only. - * @property {number} avatarSimulationTime - Read-only. - * - * - * @property {number} x - * @property {number} y - * @property {number} z - * @property {number} width - * @property {number} height - * - * @property {number} opacity - * @property {boolean} enabled - * @property {boolean} visible - * - * @property {string} state - * @property {object} anchors - Read-only. - * @property {number} baselineOffset - * - * @property {boolean} clip - * - * @property {boolean} focus - * @property {boolean} activeFocus - Read-only. - * @property {boolean} activeFocusOnTab - * - * @property {number} rotation - * @property {number} scale - * @property {number} transformOrigin - * - * @property {boolean} smooth - * @property {boolean} antialiasing - * @property {number} implicitWidth - * @property {number} implicitHeight - * - * @property {object} layer - Read-only. + * @property {number} presentnewrate - The rate at which the display plugin is presenting new GPU frames, in Hz. + * Read-only. + * @property {number} presentdroprate - The rate at which the display plugin is dropping GPU frames, in Hz. + * Read-only. - * @property {number} stylusPicksCount - Read-only. - * @property {number} rayPicksCount - Read-only. - * @property {number} parabolaPicksCount - Read-only. - * @property {number} collisionPicksCount - Read-only. - * @property {Vec3} stylusPicksUpdated - Read-only. - * @property {Vec3} rayPicksUpdated - Read-only. - * @property {Vec3} parabolaPicksUpdated - Read-only. - * @property {Vec3} collisionPicksUpdated - Read-only. - * @property {bool} eventQueueDebuggingOn - Read-only. + * @property {number} gameLoopRate - The rate at which the game loop is running, in Hz. + * Read-only. + * @property {number} refreshRateTarget - The current refresh rate target per the current refreshRateMode and + * refreshRateRegime if in desktop mode; a higher rate if in VR mode. + * Read-only. + + * @property {RefreshRateProfile} refreshRateMode - The current refresh rate profile. + * Read-only. + * @property {RefreshRateRegime} refreshRateRegime - The current refresh rate regime. + * Read-only. + * @property {UXMode} uxMode - The user experience (UX) mode that Interface is running in. + * Read-only. + + * @property {number} avatarCount - The number of avatars in the domain other than the client's. + * Read-only. + * @property {number} heroAvatarCount - The number avatars in a "hero" zone in the domain, other than the client's. + * Read-only. + * @property {number} physicsObjectCount - The number of objects that have collisions enabled. + * Read-only. + * @property {number} updatedAvatarCount - The number of avatars in the domain, other than the client's, that were updated in + * the most recent game loop. + * Read-only. + * @property {number} updatedHeroAvatarCount - The number of avatars in a "hero" zone in the domain, other than the client's, + * that were updated in the most recent game loop. + * Read-only. + * @property {number} notUpdatedAvatarCount - The number of avatars in the domain, other than the client's, that weren't able + * to be updated in the most recent game loop because there wasn't enough time. + * Read-only. + + * @property {number} packetInCount - The number of packets being received from the domain server, in packets per second. + * Read-only. + * @property {number} packetOutCount - The number of packets being sent to the domain server, in packets per second. + * Read-only. + * @property {number} mbpsIn - The amount of data being received from the domain server, in megabits per second. + * Read-only. + * @property {number} mbpsOut - The amount of data being sent to the domain server, in megabits per second. + * Read-only. + + * @property {number} assetMbpsIn - The amount of data being received from the asset server, in megabits per second. + * 0.0 if not connected to an avatar mixer. + * Read-only. + * @property {number} assetMbpsOut - The amount of data being sent to the asset server, in megabits per second. + * 0.0 if not connected to an avatar mixer. + * Read-only. + + * @property {number} audioPing - The ping time to the audio mixer, in ms. + * -1 if not connected to an audio mixer. + * Read-only. + * @property {number} avatarPing - The ping time to the avatar mixer, in ms. + * -1 if not connected to an avatar mixer. + * Read-only. + * @property {number} entitiesPing - The average ping time to the entity servers, in ms. + * -1 if not connected to an entity server. + * Read-only. + * @property {number} assetPing - The ping time to the asset server, in ms. + * -1 if not connected to an asset server. + * Read-only. + * @property {number} messagePing - The ping time to the message mixer, in ms. + * -1 if not connected to a message mixer. + * Read-only. + + * @property {Vec3} position - The position of the user's avatar. + * Read-only. + *

Note: Property not available in the API.

+ * @property {number} speed - The speed of the user's avatar, in m/s. + * Read-only. + * @property {number} yaw - The yaw of the user's avatar body, in degrees. + * Read-only. + + * @property {number} avatarMixerInKbps - The amount of data being received from the avatar mixer, in kilobits per second. + * -1 if not connected to an avatar mixer. + * Read-only. + * @property {number} avatarMixerInPps - The number of packets being received from the avatar mixer, in packets per second. + * -1 if not connected to an avatar mixer. + * Read-only. + * @property {number} avatarMixerOutKbps - The amount of data being sent to the avatar mixer, in kilobits per second. + * -1 if not connected to an avatar mixer. + * Read-only. + * @property {number} avatarMixerOutPps - The number of packets being sent to the avatar mixer, in packets per second. + * -1 if not connected to an avatar mixer. + * Read-only. + + * @property {number} myAvatarSendRate - The number of avatar packets being sent by the user's avatar, in packets per second. + * Read-only. + * + * @property {number} audioMixerInKbps - The amount of data being received from the audio mixer, in kilobits per second. + * -1 if not connected to an audio mixer. + * Read-only. + * @property {number} audioMixerInPps - The number of packets being received from the audio mixer, in packets per second. + * -1 if not connected to an audio mixer. + * Read-only. + * @property {number} audioMixerOutKbps - The amount of data being sent to the audio mixer, in kilobits per second. + * -1 if not connected to an audio mixer. + * Read-only. + * @property {number} audioMixerOutPps - The number of packets being sent to the audio mixer, in packets per second. + * -1 if not connected to an audio mixer. + * Read-only. + * @property {number} audioMixerKbps - The total amount of data being sent to and received from the audio mixer, in kilobits + * per second. + * -1 if not connected to an audio mixer. + * Read-only. + * @property {number} audioMixerPps - The total number of packets being sent to received from the audio mixer, in packets per + * second. + * -1 if not connected to an audio mixer. + * Read-only. + + * @property {number} audioOutboundPPS - The number of non-silent audio packets being sent by the user, in packets per second. + * -1 if not connected to an audio mixer. + * Read-only. + * @property {number} audioSilentOutboundPPS - The number of silent audio packets being sent by the user, in packets per + * second. + * -1 if not connected to an audio mixer. + * Read-only. + * @property {number} audioAudioInboundPPS - The number of non-silent audio packets being received by the user, in packets per + * second. + * -1 if not connected to an audio mixer. + * Read-only. + * @property {number} audioSilentInboundPPS - The number of silent audio packets being received by the user, in packets per + * second. + * -1 if not connected to an audio mixer. + * Read-only. + * @property {number} audioPacketLoss - The number of audio packets being lost being sent to or received from the audio mixer, + * in %. + * -1 if not connected to an audio mixer. + * Read-only. + + * @property {string} audioCodec - The name of the audio codec. + * Read-only. + * @property {string} audioNoiseGate - The status of the audio noise gate: "Open" or "Closed". + * Read-only. + * @property {Vec2} audioInjectors - The number of audio injectors, local and non-local. + * Read-only. + *

Note: Property not available in the API.

+ + * @property {number} entityPacketsInKbps - The average amount of data being received from entity servers, in kilobits per + * second. (Multiply by the number of entity servers to get the total amount of data being received.) + * -1 if not connected to an entity server. + * Read-only. + * + * @property {number} downloads - The number of downloads in progress. + * Read-only. + * @property {number} downloadLimit - The maximum number of concurrent downloads. + * Read-only. + * @property {number} downloadsPending - The number of downloads pending. + * Read-only. + * @property {string[]} downloadUrls - The download URLs. + * Read-only. + *

Note: Property not available in the API.

+ + * @property {number} processing - The number of completed downloads being processed. + * Read-only. + * @property {number} processingPending - The number of completed downloads waiting to be processed. + * Read-only. + + * @property {number} triangles - The number of triangles in the rendered scene. + * Read-only. + * @property {number} drawcalls - The number of draw calls made for the rendered scene. + * Read-only. + * @property {number} materialSwitches - The number of material switches performed for the rendered scene. + * Read-only. + * @property {number} itemConsidered - The number of item considerations made for rendering. + * Read-only. + * @property {number} itemOutOfView - The number of items out of view. + * Read-only. + * @property {number} itemTooSmall - The number of items too small to render. + * Read-only. + * @property {number} itemRendered - The number of items rendered. + * Read-only. + * @property {number} shadowConsidered - The number of shadow considerations made for rendering. + * Read-only. + * @property {number} shadowOutOfView - The number of shadows out of view. + * Read-only. + * @property {number} shadowTooSmall - The number of shadows too small to render. + * Read-only. + * @property {number} shadowRendered - The number of shadows rendered. + * Read-only. + * @property {string} sendingMode - Description of the octree sending mode. + * Read-only. + * @property {string} packetStats - Description of the octree packet processing state. + * Read-only. + * @property {number} lodAngle - The target LOD angle, in degrees. + * Read-only. + * @property {number} lodTargetFramerate - The target LOD frame rate, in Hz. + * Read-only. + * @property {string} lodStatus - Description of the current LOD. + * Read-only. + + * @property {string} timingStats - Details of the average time (ms) spent in and number of calls made to different parts of + * the code. Provided only if timingExpanded is true. Only the top 10 items are provided if + * Developer > Timing > Performance Timer > Only Display Top 10 is enabled. + * Read-only. + * @property {string} gameUpdateStats - Details of the average time (ms) spent in different parts of the game loop. + * Read-only. + + * @property {number} serverElements - The total number of elements in the server octree. + * Read-only. + * @property {number} serverInternal - The number of internal elements in the server octree. + * Read-only. + * @property {number} serverLeaves - The number of leaf elements in the server octree. + * Read-only. + * @property {number} localElements - The total number of elements in the client octree. + * Read-only. + * @property {number} localInternal - The number of internal elements in the client octree. + * Read-only. + * @property {number} localLeaves - The number of leaf elements in the client octree. + * Read-only. + + * @property {number} rectifiedTextureCount - The number of textures that have been resized so that their size is a power of 2 + * if smaller than 128, or a multiple of 128 if greater than 128. + * Read-only. + * @property {number} decimatedTextureCount - The number of textures that have been reduced in size because they were over the + * maximum allowed size of 4096 on desktop or 2048 on mobile. + * Read-only. + + * @property {number} gpuBuffers - The number of OpenGL buffer objects managed by the GPU back-end. + * Read-only. + * @property {number} gpuBufferMemory - The total memory size of the gpuBuffers, in MB. + * Read-only. + * @property {number} gpuTextures - The number of OpenGL textures managed by the GPU back-end. This is the sum of the number of + * textures managed for gpuTextureResidentMemory, gpuTextureResourceMemory, and + * gpuTextureFramebufferMemory. + * Read-only. + * @property {number} gpuTextureMemory - The total memory size of the gpuTextures, in MB. This is the sum of + * gpuTextureResidentMemory, gpuTextureResourceMemory, and + * gpuTextureFramebufferMemory. + * Read-only. + * @property {number} glContextSwapchainMemory - The estimated memory used by the default OpenGL frame buffer, in MB. + * Read-only. + * @property {number} qmlTextureMemory - The memory size of textures managed by the offscreen QML surface, in MB. + * Read-only. + * @property {number} texturePendingTransfers - The memory size of textures pending transfer to the GPU, in MB. + * Read-only. + * @property {number} gpuTextureResidentMemory - The memory size of the "strict" textures that always have their full + * resolution in GPU memory, in MB. + * Read-only. + * @property {number} gpuTextureFramebufferMemory - The memory size of the frame buffer on the GPU, in MB. + * Read-only. + * @property {number} gpuTextureResourceMemory - The amount of GPU memory that has been allocated for "variable" textures, in + * MB. + * Read-only. + * @property {number} gpuTextureResourceIdealMemory - The amount of memory that "variable" textures would take up if they were + * all completely loaded, in MB. + * Read-only. + * @property {number} gpuTextureResourcePopulatedMemory - How much of the GPU memory allocated has actually been populated, in +* MB. + * Read-only. + * @property {string} gpuTextureMemoryPressureState - The stats of the texture transfer engine. + *
    + *
  • "Undersubscribed": There is texture data that can fit in memory but that isn't on the GPU, so more + * GPU texture memory should be allocated.
  • + *
  • "Transfer": More GPU texture memory has been allocated and texture data is being transferred.
  • + *
  • "Idle": Either all texture data has been transferred to the GPU or there is nor more space + * available.
  • + *
+ * Read-only. + * @property {number} gpuFreeMemory - The amount of GPU memory available after all allocations, in MB. + * Read-only. + *

Note: This is not a reliable number because OpenGL doesn't have an official method of getting this + * information.

+ * @property {number} gpuTextureExternalMemory - The estimated amount of memory consumed by textures being used but that are + * not managed by the GPU library, in MB. + * Read-only. + + * @property {Vec2} gpuFrameSize - The dimensions of the frames being rendered. + * Read-only. + *

Note: Property not available in the API.

+ * @property {number} gpuFrameTime - The time the GPU is spending on a frame, in ms. + * Read-only. + * @property {number} gpuFrameTimePerPixel - The time the GPU is spending on a pixel, in ns. + * Read-only. + * @property {number} batchFrameTime - The time being spent batch processing each frame, in ms. + * Read-only. + * @property {number} engineFrameTime - The time being spent in the render engine each frame, in ms. + * Read-only. + * @property {number} avatarSimulationTime - The time being spent simulating avatars each frame, in ms. + * Read-only. + * + * @property {number} stylusPicksCount - The number of stylus picks currently in effect. + * Read-only. + * @property {number} rayPicksCount - The number of ray picks currently in effect. + * Read-only. + * @property {number} parabolaPicksCount - The number of parabola picks currently in effect. + * Read-only. + * @property {number} collisionPicksCount - The number of collision picks currently in effect. + * Read-only. + * @property {Vec3} stylusPicksUpdated - The number of stylus pick intersection that were found in the most recent game loop: + *
    + *
  • x = entity intersections.
  • + *
  • y = avatar intersections.
  • + *
  • z = HUD intersections.
  • + *
+ * Read-only. + *

Note: Property not available in the API.

+ * @property {Vec3} rayPicksUpdated - The number of ray pick intersections that were found in the most recent game loop: + *
    + *
  • x = entity intersections.
  • + *
  • y = avatar intersections.
  • + *
  • z = HUD intersections.
  • + *
+ * Read-only. + *

Note: Property not available in the API.

+ * @property {Vec3} parabolaPicksUpdated - The number of parabola pick intersections that were found in the most recent game + * loop: + *
    + *
  • x = entity intersections.
  • + *
  • y = avatar intersections.
  • + *
  • z = HUD intersections.
  • + *
+ * Read-only. + *

Note: Property not available in the API.

+ * @property {Vec3} collisionPicksUpdated - The number of collision pick intersections that were found in the most recent game + * loop: + *
    + *
  • x = entity intersections.
  • + *
  • y = avatar intersections.
  • + *
  • z = HUD intersections.
  • + *
+ * Read-only. + *

Note: Property not available in the API.

+ * + * @property {boolean} eventQueueDebuggingOn - true if event queue statistics are provided, false if + * they're not. + * Read-only. + * @property {number} mainThreadQueueDepth - The number of events in the main thread's event queue. + * Only provided if eventQueueDebuggingOn is true. + * Read-only. + * @property {number} nodeListThreadQueueDepth - The number of events in the node list thread's event queue. + * Only provided if eventQueueDebuggingOn is true. + * Read-only. + * + * + * @comment The following property is from Stats.qml. It shouldn't be in the API. + * @property {string} bgColor + * Read-only. + *

Deprecated: This property is deprecated and will be removed.

+ * + * @comment The following properties are from QQuickItem. They shouldn't be in the API. + * @property {boolean} activeFocus + * Read-only. + *

Deprecated: This property is deprecated and will be removed.

+ * @property {boolean} activeFocusOnTab + *

Deprecated: This property is deprecated and will be removed.

+ * @property {object} anchors + * Read-only. + *

Deprecated: This property is deprecated and will be removed.

+ * @property {boolean} antialiasing + *

Deprecated: This property is deprecated and will be removed.

+ * @property {number} baselineOffset + *

Deprecated: This property is deprecated and will be removed.

+ * @property {object[]} children + * Read-only. + *

Note: Property not available in the API.

+ *

Deprecated: This property is deprecated and will be removed.

+ * @property {boolean} clip + *

Deprecated: This property is deprecated and will be removed.

+ * @property {object} containmentMask + *

Deprecated: This property is deprecated and will be removed.

+ * @property {boolean} enabled + *

Deprecated: This property is deprecated and will be removed.

+ * @property {boolean} focus + *

Deprecated: This property is deprecated and will be removed.

+ * @property {number} height + *

Deprecated: This property is deprecated and will be removed.

+ * @property {number} implicitHeight + *

Deprecated: This property is deprecated and will be removed.

+ * @property {number} implicitWidth + *

Deprecated: This property is deprecated and will be removed.

+ * @property {object} layer + * Read-only. + *

Deprecated: This property is deprecated and will be removed.

+ * @property {number} opacity + *

Deprecated: This property is deprecated and will be removed.

+ * @property {number} rotation + *

Deprecated: This property is deprecated and will be removed.

+ * @property {number} scale + *

Deprecated: This property is deprecated and will be removed.

+ * @property {boolean} smooth + *

Deprecated: This property is deprecated and will be removed.

+ * @property {string} state + *

Deprecated: This property is deprecated and will be removed.

+ * @property {number} transformOrigin + *

Deprecated: This property is deprecated and will be removed.

+ * @property {boolean} visible + *

Deprecated: This property is deprecated and will be removed.

+ * @property {number} width + *

Deprecated: This property is deprecated and will be removed.

+ * @property {number} x + *

Deprecated: This property is deprecated and will be removed.

+ * @property {number} y + *

Deprecated: This property is deprecated and will be removed.

+ * @property {number} z + *

Deprecated: This property is deprecated and will be removed.

*/ // Properties from x onwards are QQuickItem properties. @@ -287,6 +564,7 @@ class Stats : public QQuickItem { STATS_PROPERTY(int, localLeaves, 0) STATS_PROPERTY(int, rectifiedTextureCount, 0) STATS_PROPERTY(int, decimatedTextureCount, 0) + STATS_PROPERTY(int, gpuBuffers, 0) STATS_PROPERTY(int, gpuBufferMemory, 0) STATS_PROPERTY(int, gpuTextures, 0) @@ -352,37 +630,35 @@ public: QStringList downloadUrls () { return _downloadUrls; } public slots: + + /**jsdoc + * Updates statistics to make current values available to scripts even though the statistics overlay may not be displayed. + * (Many statistics values are normally updated only if the statistics overlay is displayed.) + *

Note: Not all statistics values are updated when the statistics overlay isn't displayed or + * expanded.

+ * @function Stats.forceUpdateStats + * @example Report avatar mixer data and packet rates. + * // The statistics to report. + * var stats = [ + * "avatarMixerInKbps", + * "avatarMixerInPps", + * "avatarMixerOutKbps", + * "avatarMixerOutPps" + * ]; + * + * // update the statistics for the script. + * Stats.forceUpdateStats(); + * + * // Report the statistics. + * for (var i = 0; i < stats.length; i++) { + * print(stats[i], "=", Stats[stats[i]]); + * } + */ void forceUpdateStats() { updateStats(true); } signals: - /**jsdoc - * Triggered when the value of the longsubmits property changes. - * @function Stats.longsubmitsChanged - * @returns {Signal} - */ - void longsubmitsChanged(); - - /**jsdoc - * Triggered when the value of the longrenders property changes. - * @function Stats.longrendersChanged - * @returns {Signal} - */ - void longrendersChanged(); - - /**jsdoc - * Triggered when the value of the longframes property changes. - * @function Stats.longframesChanged - * @returns {Signal} - */ - void longframesChanged(); - - /**jsdoc - * Triggered when the value of the appdropped property changes. - * @function Stats.appdroppedChanged - * @returns {Signal} - */ - void appdroppedChanged(); + // Signals for properties... /**jsdoc * Triggered when the value of the expanded property changes. @@ -419,6 +695,41 @@ signals: */ void presentrateChanged(); + /**jsdoc + * Triggered when the value of the stutterrate property changes. + * @function Stats.stutterrateChanged + * @returns {Signal} + */ + void stutterrateChanged(); + + /**jsdoc + * Triggered when the value of the appdropped property changes. + * @function Stats.appdroppedChanged + * @returns {Signal} + */ + void appdroppedChanged(); + + /**jsdoc + * Triggered when the value of the longsubmits property changes. + * @function Stats.longsubmitsChanged + * @returns {Signal} + */ + void longsubmitsChanged(); + + /**jsdoc + * Triggered when the value of the longrenders property changes. + * @function Stats.longrendersChanged + * @returns {Signal} + */ + void longrendersChanged(); + + /**jsdoc + * Triggered when the value of the longframes property changes. + * @function Stats.longframesChanged + * @returns {Signal} + */ + void longframesChanged(); + /**jsdoc * Triggered when the value of the presentnewrate property changes. * @function Stats.presentnewrateChanged @@ -433,13 +744,6 @@ signals: */ void presentdroprateChanged(); - /**jsdoc - * Triggered when the value of the stutterrate property changes. - * @function Stats.stutterrateChanged - * @returns {Signal} - */ - void stutterrateChanged(); - /**jsdoc * Triggered when the value of the gameLoopRate property changes. * @function Stats.gameLoopRateChanged @@ -447,13 +751,6 @@ signals: */ void gameLoopRateChanged(); - /**jsdoc - * Trigered when - * @function Stats.numPhysicsBodiesChanged - * @returns {Signal} - */ - void physicsObjectCountChanged(); - /**jsdoc * Triggered when the value of the avatarCount property changes. * @function Stats.avatarCountChanged @@ -461,6 +758,34 @@ signals: */ void avatarCountChanged(); + /**jsdoc + * Triggered when the value of the refreshRateTarget property changes. + * @function Stats.refreshRateTargetChanged + * @returns {Signal} + */ + void refreshRateTargetChanged(); + + /**jsdoc + * Triggered when the value of the refreshRateMode property changes. + * @function Stats.refreshRateModeChanged + * @returns {Signal} + */ + void refreshRateModeChanged(); + + /**jsdoc + * Triggered when the value of the refreshRateRegime property changes. + * @function Stats.refreshRateRegimeChanged + * @returns {Signal} + */ + void refreshRateRegimeChanged(); + + /**jsdoc + * Triggered when the value of the uxMode property changes. + * @function Stats.uxModeChanged + * @returns {Signal} + */ + void uxModeChanged(); + /**jsdoc * Triggered when the value of the heroAvatarCount property changes. * @function Stats.heroAvatarCountChanged @@ -468,6 +793,13 @@ signals: */ void heroAvatarCountChanged(); + /**jsdoc + * Triggered when the value of the physicsObjectCount property changes. + * @function Stats.physicsObjectCountChanged + * @returns {Signal} + */ + void physicsObjectCountChanged(); + /**jsdoc * Triggered when the value of the updatedAvatarCount property changes. * @function Stats.updatedAvatarCountChanged @@ -727,7 +1059,6 @@ signals: */ void entityPacketsInKbpsChanged(); - /**jsdoc * Triggered when the value of the downloads property changes. * @function Stats.downloadsChanged @@ -778,11 +1109,10 @@ signals: void trianglesChanged(); /**jsdoc - * Triggered when the value of the drawcalls property changes. - * This - * @function Stats.drawcallsChanged - * @returns {Signal} - */ + * Triggered when the value of the drawcalls property changes. + * @function Stats.drawcallsChanged + * @returns {Signal} + */ void drawcallsChanged(); /**jsdoc @@ -883,6 +1213,20 @@ signals: */ void lodStatusChanged(); + /**jsdoc + * Triggered when the value of the timingStats property changes. + * @function Stats.timingStatsChanged + * @returns {Signal} + */ + void timingStatsChanged(); + + /**jsdoc + * Triggered when the value of the gameUpdateStats property changes. + * @function Stats.gameUpdateStatsChanged + * @returns {Signal} + */ + void gameUpdateStatsChanged(); + /**jsdoc * Triggered when the value of the serverElements property changes. * @function Stats.serverElementsChanged @@ -926,39 +1270,18 @@ signals: void localLeavesChanged(); /**jsdoc - * Triggered when the value of the timingStats property changes. - * @function Stats.timingStatsChanged + * Triggered when the value of the rectifiedTextureCount property changes. + * @function Stats.rectifiedTextureCountChanged * @returns {Signal} */ - void timingStatsChanged(); + void rectifiedTextureCountChanged(); /**jsdoc - * Triggered when the value of the gameUpdateStats property changes. - * @function Stats.gameUpdateStatsChanged + * Triggered when the value of the decimatedTextureCount property changes. + * @function Stats.decimatedTextureCountChanged * @returns {Signal} */ - void gameUpdateStatsChanged(); - - /**jsdoc - * Triggered when the value of the glContextSwapchainMemory property changes. - * @function Stats.glContextSwapchainMemoryChanged - * @returns {Signal} - */ - void glContextSwapchainMemoryChanged(); - - /**jsdoc - * Triggered when the value of the qmlTextureMemory property changes. - * @function Stats.qmlTextureMemoryChanged - * @returns {Signal} - */ - void qmlTextureMemoryChanged(); - - /**jsdoc - * Triggered when the value of the texturePendingTransfers property changes. - * @function Stats.texturePendingTransfersChanged - * @returns {Signal} - */ - void texturePendingTransfersChanged(); + void decimatedTextureCountChanged(); /**jsdoc * Triggered when the value of the gpuBuffers property changes. @@ -981,6 +1304,27 @@ signals: */ void gpuTexturesChanged(); + /**jsdoc + * Triggered when the value of the glContextSwapchainMemory property changes. + * @function Stats.glContextSwapchainMemoryChanged + * @returns {Signal} + */ + void glContextSwapchainMemoryChanged(); + + /**jsdoc + * Triggered when the value of the qmlTextureMemory property changes. + * @function Stats.qmlTextureMemoryChanged + * @returns {Signal} + */ + void qmlTextureMemoryChanged(); + + /**jsdoc + * Triggered when the value of the texturePendingTransfers property changes. + * @function Stats.texturePendingTransfersChanged + * @returns {Signal} + */ + void texturePendingTransfersChanged(); + /**jsdoc * Triggered when the value of the gpuTextureMemory property changes. * @function Stats.gpuTextureMemoryChanged @@ -1045,15 +1389,8 @@ signals: void gpuFreeMemoryChanged(); /**jsdoc - * Triggered when the value of the gpuFrameTime property changes. - * @function Stats.gpuFrameTimeChanged - * @returns {Signal} - */ - void gpuFrameTimeChanged(); - - /**jsdoc - * Triggered when the value of the gpuFrameTime property changes. - * @function Stats.gpuFrameTimeChanged + * Triggered when the value of the gpuFrameSize property changes. + * @function Stats.gpuFrameSizeChanged * @returns {Signal} */ void gpuFrameSizeChanged(); @@ -1063,6 +1400,13 @@ signals: * @function Stats.gpuFrameTimeChanged * @returns {Signal} */ + void gpuFrameTimeChanged(); + + /**jsdoc + * Triggered when the value of the gpuFrameTimePerPixel property changes. + * @function Stats.gpuFrameTimePerPixelChanged + * @returns {Signal} + */ void gpuFrameTimePerPixelChanged(); /**jsdoc @@ -1086,250 +1430,6 @@ signals: */ void avatarSimulationTimeChanged(); - /**jsdoc - * Triggered when the value of the rectifiedTextureCount property changes. - * @function Stats.rectifiedTextureCountChanged - * @returns {Signal} - */ - void rectifiedTextureCountChanged(); - - /**jsdoc - * Triggered when the value of the decimatedTextureCount property changes. - * @function Stats.decimatedTextureCountChanged - * @returns {Signal} - */ - void decimatedTextureCountChanged(); - - - void refreshRateTargetChanged(); - - void refreshRateModeChanged(); - - void refreshRateRegimeChanged(); - - void uxModeChanged(); - - // QQuickItem signals. - - /**jsdoc - * Triggered when the parent item changes. - * @function Stats.parentChanged - * @param {object} parent - * @returns {Signal} - */ - - /**jsdoc - * Triggered when the value of the x property changes. - * @function Stats.xChanged - * @returns {Signal} - */ - - /**jsdoc - * Triggered when the value of the y property changes. - * @function Stats.yChanged - * @returns {Signal} - */ - - /**jsdoc - * Triggered when the value of the z property changes. - * @function Stats.zChanged - * @returns {Signal} - */ - - /**jsdoc - * Triggered when the value of the width property changes. - * @function Stats.widthChanged - * @returns {Signal} - */ - - /**jsdoc - * Triggered when the value of the height property changes. - * @function Stats.heightChanged - * @returns {Signal} - */ - - /**jsdoc - * Triggered when the value of the opacity property changes. - * @function Stats.opacityChanged - * @returns {Signal} - */ - - /**jsdoc - * Triggered when the value of the enabled property changes. - * @function Stats.enabledChanged - * @returns {Signal} - */ - - /**jsdoc - * Triggered when the value of the visibleChanged property changes. - * @function Stats.visibleChanged - * @returns {Signal} - */ - - /**jsdoc - * Triggered when the list of visible children changes. - * @function Stats.visibleChildrenChanged - * @returns {Signal} - */ - - /**jsdoc - * Triggered when the value of the state property changes. - * @function Stats.stateChanged - * @paramm {string} state - * @returns {Signal} - */ - - /**jsdoc - * Triggered when the position and size of the rectangle containing the children changes. - * @function Stats.childrenRectChanged - * @param {Rect} childrenRect - * @returns {Signal} - */ - - /**jsdoc - * Triggered when the value of the baselineOffset property changes. - * @function Stats.baselineOffsetChanged - * @param {number} baselineOffset - * @returns {Signal} - */ - - /**jsdoc - * Triggered when the value of the clip property changes. - * @function Stats.clipChanged - * @param {boolean} clip - * @returns {Signal} - */ - - /**jsdoc - * Triggered when the value of the focus property changes. - * @function Stats.focusChanged - * @param {boolean} focus - * @returns {Signal} - */ - - /**jsdoc - * Triggered when the value of the activeFocus property changes. - * @function Stats.activeFocusChanged - * @param {boolean} activeFocus - * @returns {Signal} - */ - - /**jsdoc - * Triggered when the value of the activeFocusOnTab property changes. - * @function Stats.activeFocusOnTabChanged - * @param {boolean} activeFocusOnTab - * @returns {Signal} - */ - - /**jsdoc - * Triggered when the value of the rotation property changes. - * @function Stats.rotationChanged - * @returns {Signal} - */ - - /**jsdoc - * Triggered when the value of the scaleChanged property changes. - * @function Stats.scaleChanged - * @returns {Signal} - */ - - /**jsdoc - * Triggered when the value of the transformOrigin property changes. - * @function Stats.transformOriginChanged - * @param {number} transformOrigin - * @returns {Signal} - */ - - /**jsdoc - * Triggered when the value of the smooth property changes. - * @function Stats.smoothChanged - * @param {boolean} smooth - * @returns {Signal} - */ - - /**jsdoc - * Triggered when the value of the antialiasing property changes. - * @function Stats.antialiasingChanged - * @param {boolean} antialiasing - * @returns {Signal} - */ - - /**jsdoc - * Triggered when the value of the implicitWidth property changes. - * @function Stats.implicitWidthChanged - * @returns {Signal} - */ - - /**jsdoc - * Triggered when the value of the implicitHeight property changes. - * @function Stats.implicitHeightChanged - * @returns {Signal} - */ - - /**jsdoc - * @function Stats.windowChanged - * @param {object} window - * @returns {Signal} - */ - - - // QQuickItem functions. - - /**jsdoc - * @function Stats.grabToImage - * @param {object} callback - * @param {Size} [targetSize=0,0] - * @returns {boolean} - */ - - /**jsdoc - * @function Stats.contains - * @param {Vec2} point - * @returns {boolean} - */ - - /**jsdoc - * @function Stats.mapFromItem - * @param {object} item - */ - - /**jsdoc - * @function Stats.mapToItem - * @param {object} item - */ - - /**jsdoc - * @function Stats.mapFromGlobal - * @param {object} global - */ - - /**jsdoc - * @function Stats.mapToGlobal - * @param {object} global - */ - - /**jsdoc - * @function Stats.forceActiveFocus - * @param {number} [reason=7] - */ - - /**jsdoc - * @function Stats.nextItemInFocusChain - * @param {boolean} [forward=true] - * @returns {object} - */ - - /**jsdoc - * @function Stats.childAt - * @param {number} x - * @param {number} y - * @returns {object} - */ - - /**jsdoc - * @function Stats.update - */ - /**jsdoc * Triggered when the value of the stylusPicksCount property changes. * @function Stats.stylusPicksCountChanged @@ -1387,11 +1487,11 @@ signals: void collisionPicksUpdatedChanged(); /**jsdoc - * Triggered when the value of the eventQueueDebuggingOn property changes. - * @function Stats.eventQueueDebuggingOn + * Triggered when the value of the mainThreadQueueDepth property changes. + * @function Stats.mainThreadQueueDepthChanged * @returns {Signal} */ - void eventQueueDebuggingOnChanged(); + void mainThreadQueueDepthChanged(); /**jsdoc * Triggered when the value of the nodeListThreadQueueDepth property changes. @@ -1401,11 +1501,294 @@ signals: void nodeListThreadQueueDepthChanged(); /**jsdoc - * Triggered when the value of the nodeListThreadQueueDepth property changes. - * @function Stats.nodeListThreadQueueDepth + * Triggered when the value of the eventQueueDebuggingOn property changes. + * @function Stats.eventQueueDebuggingOnChanged * @returns {Signal} */ - void mainThreadQueueDepthChanged(); + void eventQueueDebuggingOnChanged(); + + + // Stats.qml signals: shouldn't be in the API. + + /**jsdoc + * Triggered when the value of the bgColor property changes. + * @function Stats.bgColorChanged + * @returns {Signal} + * @deprecated This signal is deprecated and will be removed. + */ + + + // QQuickItem signals: shouldn't be in the API. + + /**jsdoc + * Triggered when the value of the activeFocus property changes. + * @function Stats.activeFocusChanged + * @param {boolean} activeFocus - Active focus. + * @returns {Signal} + * @deprecated This signal is deprecated and will be removed. + */ + + /**jsdoc + * Triggered when the value of the activeFocusOnTab property changes. + * @function Stats.activeFocusOnTabChanged + * @param {boolean} activeFocusOnTab - Active focus on tab. + * @returns {Signal} + * @deprecated This signal is deprecated and will be removed. + */ + + /**jsdoc + * Triggered when the value of the antialiasing property changes. + * @function Stats.antialiasingChanged + * @param {boolean} antialiasing - Antialiasing. + * @returns {Signal} + * @deprecated This signal is deprecated and will be removed. + */ + + /**jsdoc + * Triggered when the value of the baselineOffset property changes. + * @function Stats.baselineOffsetChanged + * @param {number} baselineOffset - Baseline offset. + * @returns {Signal} + * @deprecated This signal is deprecated and will be removed. + */ + + /**jsdoc + * Triggered when the value of the children property changes. + * @function Stats.childrenChanged + * @returns {Signal} + * @deprecated This signal is deprecated and will be removed. + */ + + /**jsdoc + * Triggered when the position and size of the rectangle containing the children changes. + * @function Stats.childrenRectChanged + * @param {Rect} childrenRect - Children rect. + * @returns {Signal} + * @deprecated This signal is deprecated and will be removed. + */ + + + /**jsdoc + * Triggered when the value of the clip property changes. + * @function Stats.clipChanged + * @param {boolean} clip - Clip. + * @returns {Signal} + * @deprecated This signal is deprecated and will be removed. + */ + + /**jsdoc + * Triggered when the value of the containmentMask property changes. + * @function Stats.containmentMaskChanged + * @returns {Signal} + * @deprecated This signal is deprecated and will be removed. + */ + + /**jsdoc + * Triggered when the value of the enabled property changes. + * @function Stats.enabledChanged + * @returns {Signal} + * @deprecated This signal is deprecated and will be removed. + */ + + /**jsdoc + * Triggered when the value of the focus property changes. + * @function Stats.focusChanged + * @param {boolean} focus - Focus. + * @returns {Signal} + * @deprecated This signal is deprecated and will be removed. + */ + + /**jsdoc + * Triggered when the value of the height property changes. + * @function Stats.heightChanged + * @returns {Signal} + * @deprecated This signal is deprecated and will be removed. + */ + + /**jsdoc + * Triggered when the value of the implicitHeight property changes. + * @function Stats.implicitHeightChanged + * @returns {Signal} + * @deprecated This signal is deprecated and will be removed. + */ + + /**jsdoc + * Triggered when the value of the implicitWidth property changes. + * @function Stats.implicitWidthChanged + * @returns {Signal} + * @deprecated This signal is deprecated and will be removed. + */ + + /**jsdoc + * Triggered when the value of the opacity property changes. + * @function Stats.opacityChanged + * @returns {Signal} + * @deprecated This signal is deprecated and will be removed. + */ + + /**jsdoc + * Triggered when the parent item changes. + * @function Stats.parentChanged + * @param {object} parent - Parent. + * @returns {Signal} + * @deprecated This signal is deprecated and will be removed. + */ + + /**jsdoc + * Triggered when the value of the rotation property changes. + * @function Stats.rotationChanged + * @returns {Signal} + * @deprecated This signal is deprecated and will be removed. + */ + + /**jsdoc + * Triggered when the value of the scale property changes. + * @function Stats.scaleChanged + * @returns {Signal} + * @deprecated This signal is deprecated and will be removed. + */ + + /**jsdoc + * Triggered when the value of the smooth property changes. + * @function Stats.smoothChanged + * @param {boolean} smooth - Smooth. + * @returns {Signal} + * @deprecated This signal is deprecated and will be removed. + */ + + /**jsdoc + * Triggered when the value of the state property changes. + * @function Stats.stateChanged + * @paramm {string} state - State. + * @returns {Signal} + * @deprecated This signal is deprecated and will be removed. + */ + + /**jsdoc + * Triggered when the value of the transformOrigin property changes. + * @function Stats.transformOriginChanged + * @param {number} transformOrigin - Transformm origin. + * @returns {Signal} + * @deprecated This signal is deprecated and will be removed. + */ + + /**jsdoc + * Triggered when the value of the visibleChanged property changes. + * @function Stats.visibleChanged + * @returns {Signal} + * @deprecated This signal is deprecated and will be removed. + */ + + /**jsdoc + * Triggered when the list of visible children changes. + * @function Stats.visibleChildrenChanged + * @returns {Signal} + * @deprecated This signal is deprecated and will be removed. + */ + + /**jsdoc + * Triggered when the value of the width property changes. + * @function Stats.widthChanged + * @returns {Signal} + * @deprecated This signal is deprecated and will be removed. + */ + + /**jsdoc + * Triggered when the stats window changes. + * @function Stats.windowChanged + * @param {object} window - Window. + * @returns {Signal} + * @deprecated This signal is deprecated and will be removed. + */ + + /**jsdoc + * Triggered when the value of the x property changes. + * @function Stats.xChanged + * @returns {Signal} + * @deprecated This signal is deprecated and will be removed. + */ + + /**jsdoc + * Triggered when the value of the y property changes. + * @function Stats.yChanged + * @returns {Signal} + * @deprecated This signal is deprecated and will be removed. + */ + + /**jsdoc + * Triggered when the value of the z property changes. + * @function Stats.zChanged + * @returns {Signal} + * @deprecated This signal is deprecated and will be removed. + */ + + + // QQuickItem methods: shouldn't be in the API. + + /**jsdoc + * @function Stats.childAt + * @param {number} x - X. + * @param {number} y - Y. + * @returns {object} + * @deprecated This method is deprecated and will be removed. + */ + + /**jsdoc + * @function Stats.contains + * @param {Vec2} point - Point + * @returns {boolean} + * @deprecated This method is deprecated and will be removed. + */ + + /**jsdoc + * @function Stats.forceActiveFocus + * @param {number} [reason=7] - Reason + * @deprecated This method is deprecated and will be removed. + */ + + /**jsdoc + * @function Stats.grabToImage + * @param {object} callback - Callback. + * @param {Size} [targetSize=0,0] - Target size. + * @returns {boolean} + * @deprecated This method is deprecated and will be removed. + */ + + /**jsdoc + * @function Stats.mapFromGlobal + * @param {object} global - Global. + * @deprecated This method is deprecated and will be removed. + */ + + /**jsdoc + * @function Stats.mapFromItem + * @param {object} item - Item. + * @deprecated This method is deprecated and will be removed. + */ + + /**jsdoc + * @function Stats.mapToGlobal + * @param {object} global - Global. + * @deprecated This method is deprecated and will be removed. + */ + + /**jsdoc + * @function Stats.mapToItem + * @param {object} item - Item + * @deprecated This method is deprecated and will be removed. + */ + + /**jsdoc + * @function Stats.nextItemInFocusChain + * @param {boolean} [forward=true] - Forward. + * @returns {object} + * @deprecated This method is deprecated and will be removed. + */ + + /**jsdoc + * @function Stats.update + * @deprecated This method is deprecated and will be removed. + */ private: int _recentMaxPackets{ 0 } ; // recent max incoming voxel packets to process From 46c389f064b0c485ecf0dfec8c3b5fe123c70b2a Mon Sep 17 00:00:00 2001 From: David Rowe Date: Tue, 26 Nov 2019 15:19:54 +1300 Subject: [PATCH 17/97] Tidying --- interface/src/ui/Stats.h | 48 ++++++++++++---------------------------- 1 file changed, 14 insertions(+), 34 deletions(-) diff --git a/interface/src/ui/Stats.h b/interface/src/ui/Stats.h index f9d53dc29e..00b699c3e6 100644 --- a/interface/src/ui/Stats.h +++ b/interface/src/ui/Stats.h @@ -54,8 +54,8 @@ private: \ * * @property {number} appdropped - The number of times a frame has not been provided to the display device in time. * Read-only. - * @property {number} longsubmits - The number of times the display devices takes longer than 11ms to return after being given - * frame. + * @property {number} longsubmits - The number of times the display device has taken longer than 11ms to return after being + * given a frame. * Read-only. * @property {number} longrenders - The number of times it has taken longer than 11ms to submit a new frame to the display * device. @@ -73,14 +73,12 @@ private: \ * @property {number} refreshRateTarget - The current refresh rate target per the current refreshRateMode and * refreshRateRegime if in desktop mode; a higher rate if in VR mode. * Read-only. - * @property {RefreshRateProfile} refreshRateMode - The current refresh rate profile. * Read-only. * @property {RefreshRateRegime} refreshRateRegime - The current refresh rate regime. * Read-only. * @property {UXMode} uxMode - The user experience (UX) mode that Interface is running in. * Read-only. - * @property {number} avatarCount - The number of avatars in the domain other than the client's. * Read-only. * @property {number} heroAvatarCount - The number avatars in a "hero" zone in the domain, other than the client's. @@ -94,9 +92,8 @@ private: \ * that were updated in the most recent game loop. * Read-only. * @property {number} notUpdatedAvatarCount - The number of avatars in the domain, other than the client's, that weren't able - * to be updated in the most recent game loop because there wasn't enough time. + * to be updated in the most recent game loop because there wasn't enough time to. * Read-only. - * @property {number} packetInCount - The number of packets being received from the domain server, in packets per second. * Read-only. * @property {number} packetOutCount - The number of packets being sent to the domain server, in packets per second. @@ -105,14 +102,12 @@ private: \ * Read-only. * @property {number} mbpsOut - The amount of data being sent to the domain server, in megabits per second. * Read-only. - - * @property {number} assetMbpsIn - The amount of data being received from the asset server, in megabits per second. + @property {number} assetMbpsIn - The amount of data being received from the asset server, in megabits per second. * 0.0 if not connected to an avatar mixer. * Read-only. * @property {number} assetMbpsOut - The amount of data being sent to the asset server, in megabits per second. * 0.0 if not connected to an avatar mixer. * Read-only. - * @property {number} audioPing - The ping time to the audio mixer, in ms. * -1 if not connected to an audio mixer. * Read-only. @@ -128,7 +123,6 @@ private: \ * @property {number} messagePing - The ping time to the message mixer, in ms. * -1 if not connected to a message mixer. * Read-only. - * @property {Vec3} position - The position of the user's avatar. * Read-only. *

Note: Property not available in the API.

@@ -136,7 +130,6 @@ private: \ * Read-only. * @property {number} yaw - The yaw of the user's avatar body, in degrees. * Read-only. - * @property {number} avatarMixerInKbps - The amount of data being received from the avatar mixer, in kilobits per second. * -1 if not connected to an avatar mixer. * Read-only. @@ -149,7 +142,6 @@ private: \ * @property {number} avatarMixerOutPps - The number of packets being sent to the avatar mixer, in packets per second. * -1 if not connected to an avatar mixer. * Read-only. - * @property {number} myAvatarSendRate - The number of avatar packets being sent by the user's avatar, in packets per second. * Read-only. * @@ -169,11 +161,10 @@ private: \ * per second. * -1 if not connected to an audio mixer. * Read-only. - * @property {number} audioMixerPps - The total number of packets being sent to received from the audio mixer, in packets per - * second. + * @property {number} audioMixerPps - The total number of packets being sent to and received from the audio mixer, in packets + * per second. * -1 if not connected to an audio mixer. * Read-only. - * @property {number} audioOutboundPPS - The number of non-silent audio packets being sent by the user, in packets per second. * -1 if not connected to an audio mixer. * Read-only. @@ -189,11 +180,9 @@ private: \ * second. * -1 if not connected to an audio mixer. * Read-only. - * @property {number} audioPacketLoss - The number of audio packets being lost being sent to or received from the audio mixer, - * in %. + * @property {number} audioPacketLoss - The number of audio packets being lost, sent to or received from the audio mixer, in %. * -1 if not connected to an audio mixer. * Read-only. - * @property {string} audioCodec - The name of the audio codec. * Read-only. * @property {string} audioNoiseGate - The status of the audio noise gate: "Open" or "Closed". @@ -201,7 +190,6 @@ private: \ * @property {Vec2} audioInjectors - The number of audio injectors, local and non-local. * Read-only. *

Note: Property not available in the API.

- * @property {number} entityPacketsInKbps - The average amount of data being received from entity servers, in kilobits per * second. (Multiply by the number of entity servers to get the total amount of data being received.) * -1 if not connected to an entity server. @@ -216,12 +204,10 @@ private: \ * @property {string[]} downloadUrls - The download URLs. * Read-only. *

Note: Property not available in the API.

- * @property {number} processing - The number of completed downloads being processed. * Read-only. * @property {number} processingPending - The number of completed downloads waiting to be processed. * Read-only. - * @property {number} triangles - The number of triangles in the rendered scene. * Read-only. * @property {number} drawcalls - The number of draw calls made for the rendered scene. @@ -254,14 +240,12 @@ private: \ * Read-only. * @property {string} lodStatus - Description of the current LOD. * Read-only. - * @property {string} timingStats - Details of the average time (ms) spent in and number of calls made to different parts of * the code. Provided only if timingExpanded is true. Only the top 10 items are provided if * Developer > Timing > Performance Timer > Only Display Top 10 is enabled. * Read-only. * @property {string} gameUpdateStats - Details of the average time (ms) spent in different parts of the game loop. * Read-only. - * @property {number} serverElements - The total number of elements in the server octree. * Read-only. * @property {number} serverInternal - The number of internal elements in the server octree. @@ -274,14 +258,12 @@ private: \ * Read-only. * @property {number} localLeaves - The number of leaf elements in the client octree. * Read-only. - - * @property {number} rectifiedTextureCount - The number of textures that have been resized so that their size is a power of 2 - * if smaller than 128, or a multiple of 128 if greater than 128. + * @property {number} rectifiedTextureCount - The number of textures that have been resized so that their dimensions is a power + * of 2 if smaller than 128 pixels, or a multiple of 128 if greater than 128 pixels. * Read-only. * @property {number} decimatedTextureCount - The number of textures that have been reduced in size because they were over the - * maximum allowed size of 4096 on desktop or 2048 on mobile. + * maximum allowed dimensions of 4096 pixels on desktop or 2048 pixels on mobile. * Read-only. - * @property {number} gpuBuffers - The number of OpenGL buffer objects managed by the GPU back-end. * Read-only. * @property {number} gpuBufferMemory - The total memory size of the gpuBuffers, in MB. @@ -305,8 +287,8 @@ private: \ * Read-only. * @property {number} gpuTextureFramebufferMemory - The memory size of the frame buffer on the GPU, in MB. * Read-only. - * @property {number} gpuTextureResourceMemory - The amount of GPU memory that has been allocated for "variable" textures, in - * MB. + * @property {number} gpuTextureResourceMemory - The amount of GPU memory that has been allocated for "variable" textures that + * don't necessarily always have their full resolution in GPU memory, in MB. * Read-only. * @property {number} gpuTextureResourceIdealMemory - The amount of memory that "variable" textures would take up if they were * all completely loaded, in MB. @@ -317,7 +299,7 @@ private: \ * @property {string} gpuTextureMemoryPressureState - The stats of the texture transfer engine. *