mirror of
https://github.com/overte-org/overte.git
synced 2025-04-08 14:32:38 +02:00
Merge branch 'master' into tony/anim-sync-blend
This commit is contained in:
commit
e3e759248f
284 changed files with 10475 additions and 4835 deletions
23
BUILD.md
23
BUILD.md
|
@ -5,25 +5,30 @@
|
|||
* [OpenSSL](https://www.openssl.org/related/binaries.html) ~> 1.0.1m
|
||||
* IMPORTANT: Using the recommended version of OpenSSL is critical to avoid security vulnerabilities.
|
||||
* [VHACD](https://github.com/virneo/v-hacd)(clone this repository)(Optional)
|
||||
* [zlib](http://www.zlib.net/)
|
||||
|
||||
####CMake External Project Dependencies
|
||||
|
||||
* [boostconfig](https://github.com/boostorg/config) ~> 1.58
|
||||
* [Bullet Physics Engine](https://code.google.com/p/bullet/downloads/list) ~> 2.82
|
||||
* [Intel Threading Building Blocks](https://www.threadingbuildingblocks.org/) ~> 4.3
|
||||
* [Faceshift](http://www.faceshift.com/) ~> 4.3
|
||||
* [GLEW](http://glew.sourceforge.net/)
|
||||
* [glm](http://glm.g-truc.net/0.9.5/index.html) ~> 0.9.5.4
|
||||
* [gverb](https://github.com/highfidelity/gverb)
|
||||
|
||||
The following external projects are optional dependencies. You can indicate to CMake that you would like to include them by passing -DGET_$NAME=1 when running a clean CMake build. For example, to get CMake to download and compile SDL2 you would pass -DGET_SDL2=1.
|
||||
|
||||
* [Oculus SDK](https://developer.oculus.com/downloads/) ~> 0.6 (Win32) / 0.5 (Mac / Linux)
|
||||
* [oglplus](http://oglplus.org/) ~> 0.63
|
||||
* [OpenVR](https://github.com/ValveSoftware/openvr) ~> 0.91 (Win32 only)
|
||||
* [Polyvox](http://www.volumesoffun.com/) ~> 0.2.1
|
||||
* [SDL2](https://www.libsdl.org/download-2.0.php) ~> 2.0.3
|
||||
* Enables game controller support in Interface
|
||||
* [soxr](http://soxr.sourceforge.net) ~> 0.1.1
|
||||
* [Intel Threading Building Blocks](https://www.threadingbuildingblocks.org/) ~> 4.3
|
||||
* [Sixense](http://sixense.com/) ~> 071615
|
||||
* [zlib](http://www.zlib.net/) ~> 1.28 (Win32 only)
|
||||
|
||||
The above dependencies will be downloaded, built, linked and included automatically by CMake where we require them. The CMakeLists files that handle grabbing each of the following external dependencies can be found in the [cmake/externals folder](cmake/externals). The resulting downloads, source files and binaries will be placed in the `build/ext` folder in each of the subfolders for each external project.
|
||||
|
||||
These are not placed in your normal build tree when doing an out of source build so that they do not need to be re-downloaded and re-compiled every time the CMake build folder is cleared. Should you want to force a re-download and re-compile of a specific external, you can simply remove that directory from the appropriate subfolder in `build/ext`. Should you want to force a re-download and re-compile of all externals, just remove the `build/ext` folder.
|
||||
|
||||
If you would like to use a specific install of a dependency instead of the version that would be grabbed as a CMake ExternalProject, you can pass -DGET_$NAME=0 (where $NAME is the name of the subfolder in [cmake/externals](cmake/externals)) when you run CMake to tell it not to get that dependency as an external project.
|
||||
If you would like to use a specific install of a dependency instead of the version that would be grabbed as a CMake ExternalProject, you can pass -DUSE_LOCAL_$NAME=0 (where $NAME is the name of the subfolder in [cmake/externals](cmake/externals)) when you run CMake to tell it not to get that dependency as an external project.
|
||||
|
||||
###OS Specific Build Guides
|
||||
* [BUILD_OSX.md](BUILD_OSX.md) - additional instructions for OS X.
|
||||
|
@ -63,7 +68,7 @@ For example, to pass the QT_CMAKE_PREFIX_PATH variable during build file generat
|
|||
|
||||
####Finding Dependencies
|
||||
|
||||
The following applies for dependencies we do not grab via CMake ExternalProject (OpenSSL is an example), or for dependencies you have opted not to grab as a CMake ExternalProject (via -DGET_$NAME=0). The list of dependencies we grab by default as external projects can be found in [the CMake External Project Dependencies section](#cmake-external-project-dependencies).
|
||||
The following applies for dependencies we do not grab via CMake ExternalProject (OpenSSL is an example), or for dependencies you have opted not to grab as a CMake ExternalProject (via -DUSE_LOCAL_$NAME=0). The list of dependencies we grab by default as external projects can be found in [the CMake External Project Dependencies section](#cmake-external-project-dependencies).
|
||||
|
||||
You can point our [Cmake find modules](cmake/modules/) to the correct version of dependencies by setting one of the three following variables to the location of the correct version of the dependency.
|
||||
|
||||
|
@ -77,5 +82,5 @@ In the examples below the variable $NAME would be replaced by the name of the de
|
|||
|
||||
####Devices
|
||||
|
||||
You can support external input/output devices such as Oculus Rift, Leap Motion, Faceshift, MIDI, Razr Hydra and more by adding each individual SDK in the visible building path. Refer to the readme file available in each device folder in [interface/external/](interface/external) for the detailed explanation of the requirements to use the device.
|
||||
You can support external input/output devices such as Leap Motion, MIDI, and more by adding each individual SDK in the visible building path. Refer to the readme file available in each device folder in [interface/external/](interface/external) for the detailed explanation of the requirements to use the device.
|
||||
|
||||
|
|
10
BUILD_WIN.md
10
BUILD_WIN.md
|
@ -75,16 +75,6 @@ To prevent these problems, install OpenSSL yourself. Download the following bina
|
|||
|
||||
Install OpenSSL into the Windows system directory, to make sure that Qt uses the version that you've just installed, and not some other version.
|
||||
|
||||
####zlib
|
||||
|
||||
Install zlib from
|
||||
|
||||
[Zlib for Windows](http://gnuwin32.sourceforge.net/packages/zlib.htm)
|
||||
|
||||
and fix a header file, as described here:
|
||||
|
||||
[zlib zconf.h bug](http://sourceforge.net/p/gnuwin32/bugs/169/)
|
||||
|
||||
###Build High Fidelity using Visual Studio
|
||||
Follow the same build steps from the CMake section of [BUILD.md](BUILD.md), but pass a different generator to CMake.
|
||||
|
||||
|
|
|
@ -185,22 +185,8 @@ set(EXTERNAL_PROJECT_PREFIX "project")
|
|||
set_property(DIRECTORY PROPERTY EP_PREFIX ${EXTERNAL_PROJECT_PREFIX})
|
||||
setup_externals_binary_dir()
|
||||
|
||||
# setup options to grab external project dependencies
|
||||
option(GET_BULLET "Get Bullet library automatically as external project" 1)
|
||||
option(GET_GLM "Get GLM library automatically as external project" 1)
|
||||
option(GET_GVERB "Get Gverb library automatically as external project" 1)
|
||||
option(GET_TBB "Get Threading Building Blocks library automatically as external project" 1)
|
||||
option(GET_LIBOVR "Get LibOVR library automatically as external project" 1)
|
||||
option(GET_VHACD "Get V-HACD library automatically as external project" 1)
|
||||
option(GET_POLYVOX "Get polyvox library automatically as external project" 1)
|
||||
option(GET_OPENVR "Get OpenVR library automatically as external project" 1)
|
||||
option(GET_BOOSTCONFIG "Get Boost-config library automatically as external project" 1)
|
||||
option(GET_OGLPLUS "Get OGLplus library automatically as external project" 1)
|
||||
option(GET_GLEW "Get GLEW library automatically as external project" 1)
|
||||
|
||||
option(USE_NSIGHT "Attempt to find the nSight libraries" 1)
|
||||
|
||||
option(GET_SDL2 "Get SDL2 library automatically as external project" 0)
|
||||
|
||||
if (WIN32)
|
||||
add_paths_to_fixup_libs("${QT_DIR}/bin")
|
||||
|
@ -217,6 +203,7 @@ if (NOT ANDROID)
|
|||
add_subdirectory(interface)
|
||||
set_target_properties(interface PROPERTIES FOLDER "Apps")
|
||||
add_subdirectory(tests)
|
||||
add_subdirectory(plugins)
|
||||
add_subdirectory(tools)
|
||||
endif ()
|
||||
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
set(TARGET_NAME assignment-client)
|
||||
|
||||
setup_hifi_project(Core Gui Network Script Widgets WebSockets)
|
||||
setup_hifi_project(Core Gui Network Script Quick Widgets WebSockets)
|
||||
|
||||
# link in the shared libraries
|
||||
link_hifi_libraries(
|
||||
audio avatars octree environment gpu model fbx entities
|
||||
networking animation shared script-engine embedded-webserver
|
||||
physics
|
||||
controllers physics
|
||||
)
|
||||
|
||||
include_application_version()
|
||||
|
|
|
@ -74,7 +74,7 @@ AssignmentClient::AssignmentClient(Assignment::Type requestAssignmentType, QStri
|
|||
LogHandler::getInstance().setTargetName(ASSIGNMENT_CLIENT_TARGET_NAME);
|
||||
|
||||
// make sure we output process IDs for a child AC otherwise it's insane to parse
|
||||
LogHandler::getInstance().setShouldOutputPID(true);
|
||||
LogHandler::getInstance().setShouldOutputProcessID(true);
|
||||
|
||||
// setup our _requestAssignment member variable from the passed arguments
|
||||
_requestAssignment = Assignment(Assignment::RequestCommand, requestAssignmentType, assignmentPool);
|
||||
|
|
|
@ -44,7 +44,7 @@ AssignmentClientMonitor::AssignmentClientMonitor(const unsigned int numAssignmen
|
|||
LogHandler::getInstance().setTargetName(ASSIGNMENT_CLIENT_MONITOR_TARGET_NAME);
|
||||
|
||||
// make sure we output process IDs for a monitor otherwise it's insane to parse
|
||||
LogHandler::getInstance().setShouldOutputPID(true);
|
||||
LogHandler::getInstance().setShouldOutputProcessID(true);
|
||||
|
||||
// create a NodeList so we can receive stats from children
|
||||
DependencyManager::registerInheritance<LimitedNodeList, NodeList>();
|
||||
|
|
|
@ -254,10 +254,10 @@ void AvatarMixer::broadcastAvatarData() {
|
|||
// potentially update the max full rate distance for this frame
|
||||
maxAvatarDistanceThisFrame = std::max(maxAvatarDistanceThisFrame, distanceToAvatar);
|
||||
|
||||
if (distanceToAvatar != 0.0f
|
||||
if (distanceToAvatar != 0.0f
|
||||
&& distribution(generator) > (nodeData->getFullRateDistance() / distanceToAvatar)) {
|
||||
return;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
AvatarDataSequenceNumber lastSeqToReceiver = nodeData->getLastBroadcastSequenceNumber(otherNode->getUUID());
|
||||
AvatarDataSequenceNumber lastSeqFromSender = otherNodeData->getLastReceivedSequenceNumber();
|
||||
|
|
30
cmake/externals/faceshift/CMakeLists.txt
vendored
Normal file
30
cmake/externals/faceshift/CMakeLists.txt
vendored
Normal file
|
@ -0,0 +1,30 @@
|
|||
set(EXTERNAL_NAME faceshift)
|
||||
|
||||
include(ExternalProject)
|
||||
ExternalProject_Add(
|
||||
${EXTERNAL_NAME}
|
||||
URL https://hifi-public.s3.amazonaws.com/dependencies/faceshift.zip
|
||||
CMAKE_ARGS ${ANDROID_CMAKE_ARGS} -DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR>
|
||||
BINARY_DIR ${EXTERNAL_PROJECT_PREFIX}/build
|
||||
LOG_DOWNLOAD 1
|
||||
LOG_CONFIGURE 1
|
||||
LOG_BUILD 1
|
||||
)
|
||||
|
||||
# URL_MD5 1bdcb8a0b8d5b1ede434cc41efade41d
|
||||
|
||||
# Hide this external target (for ide users)
|
||||
set_target_properties(${EXTERNAL_NAME} PROPERTIES FOLDER "hidden/externals")
|
||||
|
||||
ExternalProject_Get_Property(${EXTERNAL_NAME} INSTALL_DIR)
|
||||
|
||||
string(TOUPPER ${EXTERNAL_NAME} EXTERNAL_NAME_UPPER)
|
||||
set(${EXTERNAL_NAME_UPPER}_INCLUDE_DIRS ${INSTALL_DIR}/include CACHE FILEPATH "Path to Faceshift include directory")
|
||||
|
||||
if (WIN32)
|
||||
set(${EXTERNAL_NAME_UPPER}_LIBRARY_DEBUG ${INSTALL_DIR}/lib/Debug/faceshift.lib CACHE FILEPATH "Faceshift libraries")
|
||||
set(${EXTERNAL_NAME_UPPER}_LIBRARY_RELEASE ${INSTALL_DIR}/lib/Release/faceshift.lib CACHE FILEPATH "Faceshift libraries")
|
||||
elseif (APPLE)
|
||||
set(${EXTERNAL_NAME_UPPER}_LIBRARY_DEBUG ${INSTALL_DIR}/lib/Debug/libfaceshift.a CACHE FILEPATH "Faceshift libraries")
|
||||
set(${EXTERNAL_NAME_UPPER}_LIBRARY_RELEASE ${INSTALL_DIR}/lib/Release/libfaceshift.a CACHE FILEPATH "Faceshift libraries")
|
||||
endif()
|
5
cmake/externals/glew/CMakeLists.txt
vendored
5
cmake/externals/glew/CMakeLists.txt
vendored
|
@ -7,14 +7,15 @@ endif ()
|
|||
include(ExternalProject)
|
||||
ExternalProject_Add(
|
||||
${EXTERNAL_NAME}
|
||||
URL http://hifi-public.s3.amazonaws.com/dependencies/glew_simple.zip
|
||||
URL_MD5 0507dc08337a82a5e7ecbc5417f92cc1
|
||||
URL http://hifi-public.s3.amazonaws.com/dependencies/glew_simple2.zip
|
||||
URL_MD5 f05d858e8203c32b689da208ad8b39db
|
||||
CONFIGURE_COMMAND CMAKE_ARGS ${ANDROID_CMAKE_ARGS} -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} -DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR>
|
||||
LOG_DOWNLOAD 1
|
||||
LOG_CONFIGURE 1
|
||||
LOG_BUILD 1
|
||||
)
|
||||
|
||||
|
||||
# Hide this external target (for ide users)
|
||||
set_target_properties(${EXTERNAL_NAME} PROPERTIES FOLDER "hidden/externals")
|
||||
|
||||
|
|
70
cmake/externals/sdl2/CMakeLists.txt
vendored
70
cmake/externals/sdl2/CMakeLists.txt
vendored
|
@ -2,6 +2,8 @@ set(EXTERNAL_NAME sdl2)
|
|||
|
||||
include(ExternalProject)
|
||||
|
||||
string(TOUPPER ${EXTERNAL_NAME} EXTERNAL_NAME_UPPER)
|
||||
|
||||
if (WIN32)
|
||||
ExternalProject_Add(
|
||||
${EXTERNAL_NAME}
|
||||
|
@ -13,15 +15,33 @@ if (WIN32)
|
|||
LOG_DOWNLOAD 1
|
||||
)
|
||||
elseif (APPLE)
|
||||
ExternalProject_Add(
|
||||
${EXTERNAL_NAME}
|
||||
URL http://hifi-public.s3.amazonaws.com/dependencies/SDL2-2.0.3-OSX.tar.gz
|
||||
URL_MD5 64f888886268bdf1656ef1b4b7d7756d
|
||||
CONFIGURE_COMMAND ""
|
||||
BUILD_COMMAND ""
|
||||
INSTALL_COMMAND ""
|
||||
LOG_DOWNLOAD 1
|
||||
)
|
||||
|
||||
ExternalProject_Add(
|
||||
${EXTERNAL_NAME}
|
||||
URL https://hifi-public.s3.amazonaws.com/dependencies/SDL2-2.0.3.zip
|
||||
CMAKE_ARGS -DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR> -DVIDEO_OPENGL=OFF
|
||||
BINARY_DIR ${EXTERNAL_PROJECT_PREFIX}/build
|
||||
LOG_DOWNLOAD 1
|
||||
LOG_CONFIGURE 1
|
||||
LOG_BUILD 1
|
||||
)
|
||||
|
||||
ExternalProject_Get_Property(${EXTERNAL_NAME} INSTALL_DIR)
|
||||
set(${EXTERNAL_NAME_UPPER}_INCLUDE_DIR ${INSTALL_DIR}/include/SDL2 CACHE PATH "Location of SDL2 include directory")
|
||||
set(${EXTERNAL_NAME_UPPER}_LIBRARY "${INSTALL_DIR}/lib/libSDL2-2.0.dylib" CACHE STRING "Path to SDL2 library")
|
||||
|
||||
set(_SDL2_LIB_DIR "${INSTALL_DIR}/lib")
|
||||
|
||||
ExternalProject_Add_Step(
|
||||
${EXTERNAL_NAME}
|
||||
change-install-name
|
||||
COMMENT "Calling install_name_tool on SDL2 libraries to fix install name for dylib linking"
|
||||
COMMAND ${CMAKE_COMMAND} -DINSTALL_NAME_LIBRARY_DIR=${_SDL2_LIB_DIR} -P ${EXTERNAL_PROJECT_DIR}/OSXInstallNameChange.cmake
|
||||
DEPENDEES install
|
||||
WORKING_DIRECTORY <INSTALL_DIR>
|
||||
LOG 1
|
||||
)
|
||||
|
||||
else ()
|
||||
if (ANDROID)
|
||||
set(ANDROID_CMAKE_ARGS "-DCMAKE_TOOLCHAIN_FILE=${CMAKE_TOOLCHAIN_FILE}" "-DANDROID_NATIVE_API_LEVEL=19")
|
||||
|
@ -41,31 +61,15 @@ endif ()
|
|||
# Hide this external target (for ide users)
|
||||
set_target_properties(${EXTERNAL_NAME} PROPERTIES FOLDER "hidden/externals")
|
||||
|
||||
string(TOUPPER ${EXTERNAL_NAME} EXTERNAL_NAME_UPPER)
|
||||
|
||||
if (APPLE)
|
||||
elseif (WIN32)
|
||||
ExternalProject_Get_Property(${EXTERNAL_NAME} SOURCE_DIR)
|
||||
set(${EXTERNAL_NAME_UPPER}_INCLUDE_DIR ${SOURCE_DIR}/SDL2.framework/Headers CACHE PATH "Location of SDL2 include directory")
|
||||
set(${EXTERNAL_NAME_UPPER}_LIBRARY_TEMP ${SOURCE_DIR}/SDL2.framework/SDL2 CACHE STRING "Path to SDL2 library")
|
||||
set(${EXTERNAL_NAME_UPPER}_INCLUDE_DIR ${SOURCE_DIR}/include CACHE PATH "Location of SDL2 include directory")
|
||||
set(${EXTERNAL_NAME_UPPER}_LIBRARY_TEMP ${SOURCE_DIR}/lib/x86/SDL2.lib CACHE FILEPATH "Path to SDL2 library")
|
||||
set(${EXTERNAL_NAME_UPPER}_DLL_PATH ${SOURCE_DIR}/lib/x86 CACHE PATH "Location of SDL2 DLL")
|
||||
else ()
|
||||
if (WIN32)
|
||||
ExternalProject_Get_Property(${EXTERNAL_NAME} SOURCE_DIR)
|
||||
set(_ROOT_DIR ${SOURCE_DIR})
|
||||
set(_INCLUDE_DIR ${_ROOT_DIR}/include)
|
||||
set(_LIB_DIR "${SOURCE_DIR}/lib/x86")
|
||||
set(_LIB_EXT "lib")
|
||||
|
||||
set(${EXTERNAL_NAME_UPPER}_DLL_PATH ${_LIB_DIR} CACHE PATH "Location of SDL2 DLL")
|
||||
else ()
|
||||
ExternalProject_Get_Property(${EXTERNAL_NAME} INSTALL_DIR)
|
||||
set(_ROOT_DIR ${INSTALL_DIR})
|
||||
set(_INCLUDE_DIR ${_ROOT_DIR}/include/SDL2)
|
||||
|
||||
set(_LIB_DIR ${INSTALL_DIR}/lib)
|
||||
set(_LIB_EXT "so")
|
||||
set(_LIB_PREFIX "lib")
|
||||
endif ()
|
||||
|
||||
set(${EXTERNAL_NAME_UPPER}_INCLUDE_DIR ${_INCLUDE_DIR} CACHE PATH "Location of SDL2 include directory")
|
||||
set(${EXTERNAL_NAME_UPPER}_LIBRARY_TEMP ${_LIB_DIR}/${_LIB_PREFIX}SDL2.${_LIB_EXT} CACHE FILEPATH "Path to SDL2 library")
|
||||
endif ()
|
||||
ExternalProject_Get_Property(${EXTERNAL_NAME} INSTALL_DIR)
|
||||
set(${EXTERNAL_NAME_UPPER}_INCLUDE_DIR ${INSTALL_DIR}/include/SDL2 CACHE PATH "Location of SDL2 include directory")
|
||||
set(${EXTERNAL_NAME_UPPER}_LIBRARY_TEMP ${INSTALL_DIR}/lib/libSDL2.so CACHE FILEPATH "Path to SDL2 library")
|
||||
endif ()
|
||||
|
|
59
cmake/externals/sixense/CMakeLists.txt
vendored
59
cmake/externals/sixense/CMakeLists.txt
vendored
|
@ -1,30 +1,20 @@
|
|||
include(ExternalProject)
|
||||
include(SelectLibraryConfigurations)
|
||||
|
||||
set(EXTERNAL_NAME Sixense)
|
||||
set(EXTERNAL_NAME sixense)
|
||||
|
||||
string(TOUPPER ${EXTERNAL_NAME} EXTERNAL_NAME_UPPER)
|
||||
|
||||
ExternalProject_Add(
|
||||
${EXTERNAL_NAME}
|
||||
URL ./SixenseSDK_062612.zip
|
||||
URL_MD5 10cc8dc470d2ac1244a88cf04bc549cc
|
||||
URL http://hifi-public.s3.amazonaws.com/dependencies/SixenseSDK_071615.zip
|
||||
URL_MD5 752a3901f334124e9cffc2ba4136ef7d
|
||||
CONFIGURE_COMMAND ""
|
||||
BUILD_COMMAND ""
|
||||
INSTALL_COMMAND ""
|
||||
LOG_DOWNLOAD 1
|
||||
)
|
||||
|
||||
if (APPLE)
|
||||
find_library(SIXENSE_LIBRARY_RELEASE lib/osx_x64/release_dll/libsixense_x64.dylib HINTS ${SIXENSE_SEARCH_DIRS})
|
||||
find_library(SIXENSE_LIBRARY_DEBUG lib/osx_x64/debug_dll/libsixensed_x64.dylib HINTS ${SIXENSE_SEARCH_DIRS})
|
||||
elseif (UNIX)
|
||||
find_library(SIXENSE_LIBRARY_RELEASE lib/linux_x64/release/libsixense_x64.so HINTS ${SIXENSE_SEARCH_DIRS})
|
||||
# find_library(SIXENSE_LIBRARY_DEBUG lib/linux_x64/debug/libsixensed_x64.so HINTS ${SIXENSE_SEARCH_DIRS})
|
||||
elseif (WIN32)
|
||||
endif ()
|
||||
|
||||
|
||||
set_target_properties(${EXTERNAL_NAME} PROPERTIES FOLDER "hidden/externals")
|
||||
|
||||
ExternalProject_Get_Property(${EXTERNAL_NAME} SOURCE_DIR)
|
||||
|
||||
|
@ -39,22 +29,41 @@ if (WIN32)
|
|||
set(ARCH_DIR "Win32")
|
||||
set(ARCH_SUFFIX "")
|
||||
endif()
|
||||
|
||||
# FIXME need to account for different architectures
|
||||
set(${EXTERNAL_NAME_UPPER}_LIBRARIES "${SOURCE_DIR}/lib/${ARCH_DIR}/release_dll/sixense${ARCH_SUFFIX}.lib" CACHE TYPE INTERNAL)
|
||||
add_paths_to_fixup_libs(${SOURCE_DIR}/bin/win32)
|
||||
|
||||
set(${EXTERNAL_NAME_UPPER}_LIBRARY_RELEASE "${SOURCE_DIR}/lib/${ARCH_DIR}/VS2013/release_dll/sixense${ARCH_SUFFIX}.lib" CACHE TYPE INTERNAL)
|
||||
add_paths_to_fixup_libs("${SOURCE_DIR}/bin/${ARCH_DIR}/VS2013/release_dll")
|
||||
|
||||
elseif(APPLE)
|
||||
|
||||
# FIXME need to account for different architectures
|
||||
set(${EXTERNAL_NAME_UPPER}_LIBRARIES ${SOURCE_DIR}/lib/osx_x64/release_dll/libsixense_x64.dylib CACHE TYPE INTERNAL)
|
||||
add_paths_to_fixup_libs(${SOURCE_DIR}/bin/osx32)
|
||||
set(${EXTERNAL_NAME_UPPER}_LIBRARY_RELEASE ${SOURCE_DIR}/lib/osx_x64/release_dll/libsixense_x64.dylib CACHE TYPE INTERNAL)
|
||||
set(${EXTERNAL_NAME_UPPER}_LIBRARY_DEBUG ${SOURCE_DIR}/lib/osx_x64/debug_dll/libsixensed_x64.dylib CACHE TYPE INTERNAL)
|
||||
|
||||
set(_SIXENSE_LIB_DIR "${SOURCE_DIR}/lib/osx_x64")
|
||||
ExternalProject_Add_Step(
|
||||
${EXTERNAL_NAME}
|
||||
change-install-name-release
|
||||
COMMENT "Calling install_name_tool on libraries to fix install name for dylib linking"
|
||||
COMMAND ${CMAKE_COMMAND} -DINSTALL_NAME_LIBRARY_DIR=${_SIXENSE_LIB_DIR}/release_dll -P ${EXTERNAL_PROJECT_DIR}/OSXInstallNameChange.cmake
|
||||
DEPENDEES install
|
||||
WORKING_DIRECTORY <SOURCE_DIR>
|
||||
LOG 1
|
||||
)
|
||||
|
||||
set(_SIXENSE_LIB_DIR "${SOURCE_DIR}/lib/osx_x64")
|
||||
ExternalProject_Add_Step(
|
||||
${EXTERNAL_NAME}
|
||||
change-install-name-debug
|
||||
COMMENT "Calling install_name_tool on libraries to fix install name for dylib linking"
|
||||
COMMAND ${CMAKE_COMMAND} -DINSTALL_NAME_LIBRARY_DIR=${_SIXENSE_LIB_DIR}/debug_dll -P ${EXTERNAL_PROJECT_DIR}/OSXInstallNameChange.cmake
|
||||
DEPENDEES install
|
||||
WORKING_DIRECTORY <SOURCE_DIR>
|
||||
LOG 1
|
||||
)
|
||||
|
||||
elseif(NOT ANDROID)
|
||||
|
||||
# FIXME need to account for different architectures
|
||||
set(${EXTERNAL_NAME_UPPER}_LIBRARIES ${SOURCE_DIR}/lib/linux_x64/release/libsixense_x64.so CACHE TYPE INTERNAL)
|
||||
add_paths_to_fixup_libs(${SOURCE_DIR}/bin/linux32)
|
||||
|
||||
# FIXME need to account for different architectures
|
||||
set(${EXTERNAL_NAME_UPPER}_LIBRARY_RELEASE ${SOURCE_DIR}/lib/linux_x64/release/libsixense_x64.so CACHE TYPE INTERNAL)
|
||||
|
||||
endif()
|
||||
|
||||
|
|
49
cmake/externals/zlib/CMakeLists.txt
vendored
49
cmake/externals/zlib/CMakeLists.txt
vendored
|
@ -1,28 +1,31 @@
|
|||
set(EXTERNAL_NAME zlib)
|
||||
string(TOUPPER ${EXTERNAL_NAME} EXTERNAL_NAME_UPPER)
|
||||
|
||||
if (WIN32)
|
||||
set(EXTERNAL_NAME zlib)
|
||||
string(TOUPPER ${EXTERNAL_NAME} EXTERNAL_NAME_UPPER)
|
||||
include(ExternalProject)
|
||||
|
||||
include(ExternalProject)
|
||||
ExternalProject_Add(
|
||||
${EXTERNAL_NAME}
|
||||
URL http://zlib.net/zlib128.zip
|
||||
URL_MD5 126f8676442ffbd97884eb4d6f32afb4
|
||||
INSTALL_COMMAND ""
|
||||
LOG_DOWNLOAD 1
|
||||
)
|
||||
ExternalProject_Add(
|
||||
${EXTERNAL_NAME}
|
||||
URL http://zlib.net/zlib128.zip
|
||||
CMAKE_ARGS -DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR>
|
||||
BINARY_DIR ${EXTERNAL_PROJECT_PREFIX}/build
|
||||
LOG_DOWNLOAD 1
|
||||
LOG_CONFIGURE 1
|
||||
LOG_BUILD 1
|
||||
)
|
||||
|
||||
# Hide this external target (for ide users)
|
||||
set_target_properties(${EXTERNAL_NAME} PROPERTIES FOLDER "hidden/externals")
|
||||
|
||||
# Hide this external target (for ide users)
|
||||
set_target_properties(${EXTERNAL_NAME} PROPERTIES FOLDER "hidden/externals")
|
||||
ExternalProject_Get_Property(${EXTERNAL_NAME} INSTALL_DIR)
|
||||
set(${EXTERNAL_NAME_UPPER}_INCLUDE_DIR ${INSTALL_DIR}/include CACHE PATH "List of zlib include directories")
|
||||
set(${EXTERNAL_NAME_UPPER}_INCLUDE_DIRS ${${EXTERNAL_NAME_UPPER}_INCLUDE_DIR} CACHE PATH "List of zlib include directories")
|
||||
set(${EXTERNAL_NAME_UPPER}_DLL_PATH ${INSTALL_DIR}/bin CACHE FILEPATH "Location of ZLib DLL")
|
||||
set(${EXTERNAL_NAME_UPPER}_LIBRARY_RELEASE ${INSTALL_DIR}/lib/zlib.lib CACHE FILEPATH "Location of zlib release library")
|
||||
set(${EXTERNAL_NAME_UPPER}_LIBRARY_DEBUG ${INSTALL_DIR}/lib/zlibd.lib CACHE FILEPATH "Location of zlib debug library")
|
||||
|
||||
ExternalProject_Get_Property(${EXTERNAL_NAME} SOURCE_DIR)
|
||||
include(SelectLibraryConfigurations)
|
||||
select_library_configurations(${EXTERNAL_NAME_UPPER})
|
||||
|
||||
set(${EXTERNAL_NAME_UPPER}_INCLUDE_DIRS ${SOURCE_DIR}/include CACHE PATH "List of zlib include directories")
|
||||
|
||||
ExternalProject_Get_Property(${EXTERNAL_NAME} BINARY_DIR)
|
||||
|
||||
set(${EXTERNAL_NAME_UPPER}_DLL_PATH ${BINARY_DIR}/Release CACHE FILEPATH "Location of GLEW DLL")
|
||||
set(${EXTERNAL_NAME_UPPER}_LIBRARY_RELEASE ${BINARY_DIR}/Release/zlib.lib CACHE FILEPATH "Location of ZLib release library")
|
||||
set(${EXTERNAL_NAME_UPPER}_LIBRARY_DEBUG "" CACHE FILEPATH "Location of ZLib debug library")
|
||||
|
||||
endif ()
|
||||
# Force selected libraries into the cache
|
||||
set(${EXTERNAL_NAME_UPPER}_LIBRARY ${${EXTERNAL_NAME_UPPER}_LIBRARY} CACHE FILEPATH "Location of zlib libraries")
|
||||
set(${EXTERNAL_NAME_UPPER}_LIBRARIES ${${EXTERNAL_NAME_UPPER}_LIBRARIES} CACHE FILEPATH "Location of zlib libraries")
|
||||
|
|
|
@ -16,7 +16,7 @@ macro(ADD_DEPENDENCY_EXTERNAL_PROJECTS)
|
|||
string(TOUPPER ${_PROJ_NAME} _PROJ_NAME_UPPER)
|
||||
|
||||
# has the user told us they specific don't want this as an external project?
|
||||
if (GET_${_PROJ_NAME_UPPER})
|
||||
if (NOT USE_LOCAL_${_PROJ_NAME_UPPER})
|
||||
# have we already detected we can't have this as external project on this OS?
|
||||
if (NOT DEFINED ${_PROJ_NAME_UPPER}_EXTERNAL_PROJECT OR ${_PROJ_NAME_UPPER}_EXTERNAL_PROJECT)
|
||||
# have we already setup the target?
|
||||
|
|
33
cmake/macros/SetupHifiPlugin.cmake
Normal file
33
cmake/macros/SetupHifiPlugin.cmake
Normal file
|
@ -0,0 +1,33 @@
|
|||
#
|
||||
# Created by Bradley Austin Davis on 2015/10/25
|
||||
# Copyright 2015 High Fidelity, Inc.
|
||||
#
|
||||
# Distributed under the Apache License, Version 2.0.
|
||||
# See the accompanying file LICENSE or http:#www.apache.org/licenses/LICENSE-2.0.html
|
||||
#
|
||||
macro(SETUP_HIFI_PLUGIN)
|
||||
set(${TARGET_NAME}_SHARED 1)
|
||||
setup_hifi_library(${ARGV})
|
||||
add_dependencies(interface ${TARGET_NAME})
|
||||
set_target_properties(${TARGET_NAME} PROPERTIES FOLDER "Plugins")
|
||||
|
||||
if (APPLE)
|
||||
set(PLUGIN_PATH "interface.app/Contents/MacOS/plugins")
|
||||
else()
|
||||
set(PLUGIN_PATH "plugins")
|
||||
endif()
|
||||
|
||||
# create the destination for the plugin binaries
|
||||
add_custom_command(
|
||||
TARGET ${TARGET_NAME} POST_BUILD
|
||||
COMMAND "${CMAKE_COMMAND}" -E make_directory
|
||||
"${CMAKE_BINARY_DIR}/interface/$<CONFIGURATION>/${PLUGIN_PATH}/"
|
||||
)
|
||||
|
||||
add_custom_command(TARGET ${DIR} POST_BUILD
|
||||
COMMAND "${CMAKE_COMMAND}" -E copy
|
||||
"$<TARGET_FILE:${TARGET_NAME}>"
|
||||
"${CMAKE_BINARY_DIR}/interface/$<CONFIGURATION>/${PLUGIN_PATH}/"
|
||||
)
|
||||
|
||||
endmacro()
|
14
cmake/macros/TargetFaceshift.cmake
Normal file
14
cmake/macros/TargetFaceshift.cmake
Normal file
|
@ -0,0 +1,14 @@
|
|||
#
|
||||
# Copyright 2015 High Fidelity, Inc.
|
||||
# Created by Bradley Austin Davis on 2015/10/10
|
||||
#
|
||||
# Distributed under the Apache License, Version 2.0.
|
||||
# See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
#
|
||||
macro(TARGET_FACESHIFT)
|
||||
add_dependency_external_projects(faceshift)
|
||||
find_package(Faceshift REQUIRED)
|
||||
target_include_directories(${TARGET_NAME} PRIVATE ${FACESHIFT_INCLUDE_DIRS})
|
||||
target_link_libraries(${TARGET_NAME} ${FACESHIFT_LIBRARIES})
|
||||
add_definitions(-DHAVE_FACESHIFT)
|
||||
endmacro()
|
14
cmake/macros/TargetSDL2.cmake
Normal file
14
cmake/macros/TargetSDL2.cmake
Normal file
|
@ -0,0 +1,14 @@
|
|||
#
|
||||
# Copyright 2015 High Fidelity, Inc.
|
||||
# Created by Bradley Austin Davis on 2015/10/10
|
||||
#
|
||||
# Distributed under the Apache License, Version 2.0.
|
||||
# See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
#
|
||||
macro(TARGET_SDL2)
|
||||
add_dependency_external_projects(sdl2)
|
||||
find_package(SDL2 REQUIRED)
|
||||
target_include_directories(${TARGET_NAME} SYSTEM PRIVATE ${SDL2_INCLUDE_DIR})
|
||||
target_link_libraries(${TARGET_NAME} ${SDL2_LIBRARY})
|
||||
add_definitions(-DHAVE_SDL2)
|
||||
endmacro()
|
14
cmake/macros/TargetSixense.cmake
Normal file
14
cmake/macros/TargetSixense.cmake
Normal file
|
@ -0,0 +1,14 @@
|
|||
#
|
||||
# Copyright 2015 High Fidelity, Inc.
|
||||
# Created by Bradley Austin Davis on 2015/10/10
|
||||
#
|
||||
# Distributed under the Apache License, Version 2.0.
|
||||
# See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
#
|
||||
macro(TARGET_SIXENSE)
|
||||
add_dependency_external_projects(sixense)
|
||||
find_package(Sixense REQUIRED)
|
||||
target_include_directories(${TARGET_NAME} PRIVATE ${SIXENSE_INCLUDE_DIRS})
|
||||
target_link_libraries(${TARGET_NAME} ${SIXENSE_LIBRARIES})
|
||||
add_definitions(-DHAVE_SIXENSE)
|
||||
endmacro()
|
22
cmake/macros/TargetZlib.cmake
Normal file
22
cmake/macros/TargetZlib.cmake
Normal file
|
@ -0,0 +1,22 @@
|
|||
#
|
||||
# Copyright 2015 High Fidelity, Inc.
|
||||
# Created by Bradley Austin Davis on 2015/10/10
|
||||
#
|
||||
# Distributed under the Apache License, Version 2.0.
|
||||
# See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
#
|
||||
macro(TARGET_ZLIB)
|
||||
|
||||
if (WIN32)
|
||||
add_dependency_external_projects(zlib)
|
||||
endif()
|
||||
|
||||
find_package(ZLIB REQUIRED)
|
||||
|
||||
if (WIN32)
|
||||
add_paths_to_fixup_libs(${ZLIB_DLL_PATH})
|
||||
endif()
|
||||
|
||||
target_include_directories(${TARGET_NAME} SYSTEM PRIVATE ${ZLIB_INCLUDE_DIRS})
|
||||
target_link_libraries(${TARGET_NAME} ${ZLIB_LIBRARIES})
|
||||
endmacro()
|
|
@ -18,32 +18,9 @@
|
|||
# See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
#
|
||||
|
||||
include("${MACRO_DIR}/HifiLibrarySearchHints.cmake")
|
||||
hifi_library_search_hints("faceshift")
|
||||
|
||||
find_path(FACESHIFT_INCLUDE_DIRS fsbinarystream.h PATH_SUFFIXES include HINTS ${FACESHIFT_SEARCH_DIRS})
|
||||
|
||||
if (APPLE)
|
||||
set(ARCH_DIR "MacOS")
|
||||
elseif (UNIX)
|
||||
set(ARCH_DIR "UNIX")
|
||||
elseif (WIN32)
|
||||
if ("${CMAKE_SIZEOF_VOID_P}" EQUAL "8")
|
||||
set(ARCH_DIR "x64")
|
||||
else()
|
||||
set(ARCH_DIR "Win32")
|
||||
endif()
|
||||
endif ()
|
||||
|
||||
find_library(FACESHIFT_LIBRARY_RELEASE NAME faceshift PATH_SUFFIXES lib/${ARCH_DIR} HINTS ${FACESHIFT_SEARCH_DIRS})
|
||||
find_library(FACESHIFT_LIBRARY_DEBUG NAME faceshiftd PATH_SUFFIXES lib/${ARCH_DIR} HINTS ${FACESHIFT_SEARCH_DIRS})
|
||||
|
||||
include(SelectLibraryConfigurations)
|
||||
select_library_configurations(FACESHIFT)
|
||||
|
||||
set(FACESHIFT_LIBRARIES ${FACESHIFT_LIBRARY})
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(Faceshift DEFAULT_MSG FACESHIFT_INCLUDE_DIRS FACESHIFT_LIBRARIES)
|
||||
|
||||
mark_as_advanced(FACESHIFT_INCLUDE_DIRS FACESHIFT_LIBRARIES FACESHIFT_SEARCH_DIRS)
|
|
@ -30,6 +30,4 @@ include(SelectLibraryConfigurations)
|
|||
select_library_configurations(GLEW)
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(GLEW DEFAULT_MSG GLEW_INCLUDE_DIRS GLEW_LIBRARIES)
|
||||
|
||||
message(STATUS "Found GLEW - Assuming that GLEW is static and defining GLEW_STATIC")
|
||||
find_package_handle_standard_args(GLEW DEFAULT_MSG GLEW_INCLUDE_DIRS GLEW_LIBRARIES)
|
|
@ -18,49 +18,10 @@
|
|||
# See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
#
|
||||
|
||||
include("${MACRO_DIR}/HifiLibrarySearchHints.cmake")
|
||||
hifi_library_search_hints("sixense")
|
||||
|
||||
find_path(SIXENSE_INCLUDE_DIRS sixense.h PATH_SUFFIXES include HINTS ${SIXENSE_SEARCH_DIRS})
|
||||
|
||||
if (APPLE)
|
||||
find_library(SIXENSE_LIBRARY_RELEASE lib/osx_x64/release_dll/libsixense_x64.dylib HINTS ${SIXENSE_SEARCH_DIRS})
|
||||
find_library(SIXENSE_LIBRARY_DEBUG lib/osx_x64/debug_dll/libsixensed_x64.dylib HINTS ${SIXENSE_SEARCH_DIRS})
|
||||
elseif (UNIX)
|
||||
find_library(SIXENSE_LIBRARY_RELEASE lib/linux_x64/release/libsixense_x64.so HINTS ${SIXENSE_SEARCH_DIRS})
|
||||
# find_library(SIXENSE_LIBRARY_DEBUG lib/linux_x64/debug/libsixensed_x64.so HINTS ${SIXENSE_SEARCH_DIRS})
|
||||
elseif (WIN32)
|
||||
if ("${CMAKE_SIZEOF_VOID_P}" EQUAL "8")
|
||||
set(ARCH_DIR "x64")
|
||||
set(ARCH_SUFFIX "_x64")
|
||||
else()
|
||||
set(ARCH_DIR "Win32")
|
||||
set(ARCH_SUFFIX "")
|
||||
endif()
|
||||
|
||||
find_library(SIXENSE_LIBRARY_RELEASE "lib/${ARCH_DIR}/release_dll/sixense${ARCH_SUFFIX}.lib" HINTS ${SIXENSE_SEARCH_DIRS})
|
||||
find_library(SIXENSE_LIBRARY_DEBUG "lib/${ARCH_DIR}/debug_dll/sixensed.lib" HINTS ${SIXENSE_SEARCH_DIRS})
|
||||
|
||||
find_path(SIXENSE_DEBUG_DLL_PATH "sixensed${ARCH_SUFFIX}.dll" PATH_SUFFIXES bin/${ARCH_DIR}/debug_dll HINTS ${SIXENSE_SEARCH_DIRS})
|
||||
find_path(SIXENSE_RELEASE_DLL_PATH "sixense${ARCH_SUFFIX}.dll" PATH_SUFFIXES bin/${ARCH_DIR}/release_dll HINTS ${SIXENSE_SEARCH_DIRS})
|
||||
find_path(SIXENSE_DEVICE_DLL_PATH DeviceDLL.dll PATH_SUFFIXES samples/${ARCH_DIR}/sixense_simple3d HINTS ${SIXENSE_SEARCH_DIRS})
|
||||
endif ()
|
||||
|
||||
include(SelectLibraryConfigurations)
|
||||
select_library_configurations(SIXENSE)
|
||||
|
||||
set(SIXENSE_REQUIREMENTS SIXENSE_INCLUDE_DIRS SIXENSE_LIBRARIES)
|
||||
if (WIN32)
|
||||
list(APPEND SIXENSE_REQUIREMENTS SIXENSE_DEBUG_DLL_PATH SIXENSE_RELEASE_DLL_PATH SIXENSE_DEVICE_DLL_PATH)
|
||||
endif ()
|
||||
|
||||
set(SIXENSE_LIBRARIES "${SIXENSE_LIBRARY}")
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(Sixense DEFAULT_MSG ${SIXENSE_REQUIREMENTS})
|
||||
|
||||
if (WIN32)
|
||||
add_paths_to_fixup_libs(${SIXENSE_DEBUG_DLL_PATH} ${SIXENSE_RELEASE_DLL_PATH} ${SIXENSE_DEVICE_DLL_PATH})
|
||||
endif ()
|
||||
|
||||
find_package_handle_standard_args(Sixense DEFAULT_MSG SIXENSE_INCLUDE_DIRS SIXENSE_LIBRARIES)
|
||||
mark_as_advanced(SIXENSE_LIBRARIES SIXENSE_INCLUDE_DIRS SIXENSE_SEARCH_DIRS)
|
||||
|
|
|
@ -21,45 +21,17 @@ if (WIN32)
|
|||
hifi_library_search_hints("iViewHMD")
|
||||
|
||||
find_path(IVIEWHMD_INCLUDE_DIRS iViewHMDAPI.h PATH_SUFFIXES include HINTS ${IVIEWHMD_SEARCH_DIRS})
|
||||
find_library(IVIEWHMD_LIBRARIES NAMES iViewHMDAPI PATH_SUFFIXES libs HINTS ${IVIEWHMD_SEARCH_DIRS})
|
||||
find_path(IVIEWHMD_API_DLL_PATH iViewHMDAPI.dll PATH_SUFFIXES libs HINTS ${IVIEWHMD_SEARCH_DIRS})
|
||||
find_library(IVIEWHMD_LIBRARIES NAMES iViewHMDAPI PATH_SUFFIXES libs/x86 HINTS ${IVIEWHMD_SEARCH_DIRS})
|
||||
find_path(IVIEWHMD_API_DLL_PATH iViewHMDAPI.dll PATH_SUFFIXES libs/x86 HINTS ${IVIEWHMD_SEARCH_DIRS})
|
||||
list(APPEND IVIEWHMD_REQUIREMENTS IVIEWHMD_INCLUDE_DIRS IVIEWHMD_LIBRARIES IVIEWHMD_API_DLL_PATH)
|
||||
|
||||
set(IVIEWHMD_DLLS
|
||||
avcodec-53.dll
|
||||
avformat-53.dll
|
||||
avutil-51.dll
|
||||
libboost_filesystem-mgw45-mt-1_49.dll
|
||||
libboost_system-mgw45-mt-1_49.dll
|
||||
libboost_thread-mgw45-mt-1_49.dll
|
||||
libgcc_s_dw2-1.dll
|
||||
libiViewNG-LibCore.dll
|
||||
libopencv_calib3d244.dll
|
||||
libopencv_core244.dll
|
||||
libopencv_features2d244.dll
|
||||
libopencv_flann244.dll
|
||||
libopencv_highgui244.dll
|
||||
libopencv_imgproc244.dll
|
||||
libopencv_legacy244.dll
|
||||
libopencv_ml244.dll
|
||||
libopencv_video244.dll
|
||||
libstdc++-6.dll
|
||||
opencv_core220.dll
|
||||
opencv_highgui220.dll
|
||||
opencv_imgproc220.dll
|
||||
swscale-2.dll
|
||||
)
|
||||
|
||||
foreach(IVIEWHMD_DLL ${IVIEWHMD_DLLS})
|
||||
find_path(IVIEWHMD_DLL_PATH ${IVIEWHMD_DLL} PATH_SUFFIXES 3rdParty HINTS ${IVIEWHMD_SEARCH_DIRS})
|
||||
list(APPEND IVIEWHMD_REQUIREMENTS IVIEWHMD_DLL_PATH)
|
||||
list(APPEND IVIEWHMD_DLL_PATHS ${IVIEWHMD_DLL_PATH})
|
||||
endforeach()
|
||||
find_path(IVIEWHMD_DLL_PATH_3RD_PARTY libiViewNG.dll PATH_SUFFIXES 3rdParty HINTS ${IVIEWHMD_SEARCH_DIRS})
|
||||
list(APPEND IVIEWHMD_REQUIREMENTS IVIEWHMD_DLL_PATH_3RD_PARTY)
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(IVIEWHMD DEFAULT_MSG ${IVIEWHMD_REQUIREMENTS})
|
||||
|
||||
add_paths_to_fixup_libs(${IVIEWHMD_API_DLL_PATH} ${IVIEWHMD_DLL_PATHS})
|
||||
add_paths_to_fixup_libs(${IVIEWHMD_API_DLL_PATH} ${IVIEWHMD_DLL_PATH_3RD_PARTY})
|
||||
|
||||
mark_as_advanced(IVIEWHMD_INCLUDE_DIRS IVIEWHMD_LIBRARIES IVIEWHMD_SEARCH_DIRS)
|
||||
|
||||
|
|
|
@ -10,5 +10,35 @@
|
|||
#
|
||||
|
||||
include(BundleUtilities)
|
||||
|
||||
|
||||
# replace copy_resolved_item_into_bundle
|
||||
#
|
||||
# The official version of copy_resolved_item_into_bundle will print out a "warning:" when
|
||||
# the resolved item matches the resolved embedded item. This not not really an issue that
|
||||
# should rise to the level of a "warning" so we replace this message with a "status:"
|
||||
#
|
||||
function(copy_resolved_item_into_bundle resolved_item resolved_embedded_item)
|
||||
if(WIN32)
|
||||
# ignore case on Windows
|
||||
string(TOLOWER "${resolved_item}" resolved_item_compare)
|
||||
string(TOLOWER "${resolved_embedded_item}" resolved_embedded_item_compare)
|
||||
else()
|
||||
set(resolved_item_compare "${resolved_item}")
|
||||
set(resolved_embedded_item_compare "${resolved_embedded_item}")
|
||||
endif()
|
||||
|
||||
if("${resolved_item_compare}" STREQUAL "${resolved_embedded_item_compare}")
|
||||
# this is our only change from the original version
|
||||
message(STATUS "status: resolved_item == resolved_embedded_item - not copying...")
|
||||
else()
|
||||
#message(STATUS "copying COMMAND ${CMAKE_COMMAND} -E copy ${resolved_item} ${resolved_embedded_item}")
|
||||
execute_process(COMMAND ${CMAKE_COMMAND} -E copy "${resolved_item}" "${resolved_embedded_item}")
|
||||
if(UNIX AND NOT APPLE)
|
||||
file(RPATH_REMOVE FILE "${resolved_embedded_item}")
|
||||
endif()
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
message(STATUS "FIXUP_LIBS for fixup_bundle called for bundle ${BUNDLE_EXECUTABLE} are @FIXUP_LIBS@")
|
||||
fixup_bundle("${BUNDLE_EXECUTABLE}" "" "@FIXUP_LIBS@")
|
|
@ -71,8 +71,8 @@ function maybePlaySound(deltaTime) {
|
|||
var palm2Position = MyAvatar.getRightPalmPosition();
|
||||
var distanceBetween = Vec3.length(Vec3.subtract(palm1Position, palm2Position));
|
||||
|
||||
var palm1Velocity = Controller.getSpatialControlVelocity(1);
|
||||
var palm2Velocity = Controller.getSpatialControlVelocity(3);
|
||||
var palm1Velocity = Controller.getPoseValue(Controller.Standard.LeftHand).velocity;
|
||||
var palm2Velocity = Controller.getPoseValue(Controller.Standard.RightHand).velocity;
|
||||
var closingVelocity = Vec3.length(Vec3.subtract(palm1Velocity, palm2Velocity));
|
||||
|
||||
const CLAP_SPEED = 0.7;
|
||||
|
|
101
examples/controllers/controllerMappings.js
Normal file
101
examples/controllers/controllerMappings.js
Normal file
|
@ -0,0 +1,101 @@
|
|||
|
||||
//
|
||||
// controllerScriptingExamples.js
|
||||
// examples
|
||||
//
|
||||
// Created by Sam Gondelman on 6/2/15
|
||||
// Copyright 2015 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
// Assumes you only have the default keyboard connected
|
||||
|
||||
/*myFirstMapping = function() {
|
||||
return {
|
||||
"name": "example",
|
||||
"channels": [
|
||||
{ "from": "Keyboard.W", "to": "Actions.LONGITUDINAL_FORWARD" },
|
||||
{ "from": "Keyboard.S", "to": "Actions.LONGITUDINAL_BACKWARD" },
|
||||
|
||||
{ "from": "Keyboard.Left", "to": "Actions.LATERAL_LEFT" },
|
||||
{ "from": "Keyboard.Right", "to": "Actions.LATERAL_RIGHT" },
|
||||
|
||||
{ "from": "Keyboard.A", "to": "Actions.YAW_LEFT" },
|
||||
{ "from": "Keyboard.D", "to": "Actions.YAW_RIGHT" },
|
||||
|
||||
{ "from": "Keyboard.C", "to": "Actions.VERTICAL_DOWN" },
|
||||
{ "from": "Keyboard.E", "to": "Actions.VERTICAL_UP" },
|
||||
{
|
||||
"from": "Standard.LX",
|
||||
"filters": [ {
|
||||
"type": "scale",
|
||||
"params": [2.0],
|
||||
}
|
||||
],
|
||||
"to": "Actions.LATERAL_LEFT",
|
||||
}, {
|
||||
"from": "Keyboard.B",
|
||||
"to": "Actions.Yaw"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
*/
|
||||
mySecondMapping = function() {
|
||||
return {
|
||||
"name": "example2",
|
||||
"channels": [
|
||||
{ "from": "Standard.LY", "to": "Actions.TranslateZ" },
|
||||
{ "from": "Standard.LX", "to": "Actions.Yaw" },
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
//Script.include('mapping-test0.json');
|
||||
/*var myFirstMappingJSON = myFirstMapping();
|
||||
print('myFirstMappingJSON' + JSON.stringify(myFirstMappingJSON));
|
||||
|
||||
var mapping = Controller.parseMapping(JSON.stringify(myFirstMappingJSON));
|
||||
|
||||
|
||||
Controller.enableMapping("example3");
|
||||
|
||||
var mySecondMappingJSON = mySecondMapping();
|
||||
print('mySecondMappingJSON' + JSON.stringify(mySecondMappingJSON));
|
||||
|
||||
var mapping2 = Controller.parseMapping(JSON.stringify(mySecondMappingJSON));
|
||||
mapping2.enable();
|
||||
|
||||
Controller.enableMapping("example2");
|
||||
*/
|
||||
var mapping3 = Controller.loadMapping(Script.resolvePath("example3.json"));
|
||||
Controller.enableMapping("example3");
|
||||
|
||||
/*
|
||||
Object.keys(Controller.Standard).forEach(function (input) {
|
||||
print("Controller.Standard." + input + ":" + Controller.Standard[input]);
|
||||
});
|
||||
|
||||
Object.keys(Controller.Hardware).forEach(function (deviceName) {
|
||||
Object.keys(Controller.Hardware[deviceName]).forEach(function (input) {
|
||||
print("Controller.Hardware." + deviceName + "." + input + ":" + Controller.Hardware[deviceName][input]);
|
||||
});
|
||||
});
|
||||
|
||||
Object.keys(Controller.Actions).forEach(function (actionName) {
|
||||
print("Controller.Actions." + actionName + ":" + Controller.Actions[actionName]);
|
||||
});
|
||||
*/
|
||||
|
||||
|
||||
Controller.hardwareChanged.connect(function () {
|
||||
print("hardwareChanged ---------------------------------------------------");
|
||||
Object.keys(Controller.Hardware).forEach(function (deviceName) {
|
||||
Object.keys(Controller.Hardware[deviceName]).forEach(function (input) {
|
||||
print("Controller.Hardware." + deviceName + "." + input + ":" + Controller.Hardware[deviceName][input]);
|
||||
});
|
||||
});
|
||||
print("-------------------------------------------------------------------");
|
||||
});
|
|
@ -15,13 +15,11 @@
|
|||
Script.include("../libraries/utils.js");
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
//
|
||||
// add lines where the hand ray picking is happening
|
||||
//
|
||||
var WANT_DEBUG = false;
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// these tune time-averaging and "on" value for analog trigger
|
||||
//
|
||||
|
@ -30,7 +28,6 @@ var TRIGGER_SMOOTH_RATIO = 0.1; // 0.0 disables smoothing of trigger value
|
|||
var TRIGGER_ON_VALUE = 0.4;
|
||||
var TRIGGER_OFF_VALUE = 0.15;
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// distant manipulation
|
||||
//
|
||||
|
@ -44,7 +41,6 @@ var LINE_ENTITY_DIMENSIONS = { x: 1000, y: 1000,z: 1000};
|
|||
var LINE_LENGTH = 500;
|
||||
var PICK_MAX_DISTANCE = 500; // max length of pick-ray
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// near grabbing
|
||||
//
|
||||
|
@ -55,8 +51,8 @@ var NEAR_GRABBING_VELOCITY_SMOOTH_RATIO = 1.0; // adjust time-averaging of held
|
|||
var NEAR_PICK_MAX_DISTANCE = 0.3; // max length of pick-ray for close grabbing to be selected
|
||||
var RELEASE_VELOCITY_MULTIPLIER = 1.5; // affects throwing things
|
||||
var PICK_BACKOFF_DISTANCE = 0.2; // helps when hand is intersecting the grabble object
|
||||
var NEAR_GRABBING_KINEMATIC = true; // force objects to be kinematic when near-grabbed
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// other constants
|
||||
//
|
||||
|
@ -79,6 +75,18 @@ var ACTION_TTL_REFRESH = 5;
|
|||
var PICKS_PER_SECOND_PER_HAND = 5;
|
||||
var MSECS_PER_SEC = 1000.0;
|
||||
|
||||
|
||||
var GRABBABLE_DATA_KEY = "grabbableKey"; // shared with grab.js
|
||||
var GRAB_USER_DATA_KEY = "grabKey"; // shared with grab.js
|
||||
|
||||
var DEFAULT_GRABBABLE_DATA = {
|
||||
grabbable: true,
|
||||
invertSolidWhileHeld: false
|
||||
};
|
||||
|
||||
var disabledHand ='none';
|
||||
|
||||
|
||||
// states for the state machine
|
||||
var STATE_OFF = 0;
|
||||
var STATE_SEARCHING = 1;
|
||||
|
@ -92,15 +100,35 @@ var STATE_FAR_GRABBING_NON_COLLIDING = 8;
|
|||
var STATE_CONTINUE_FAR_GRABBING_NON_COLLIDING = 9;
|
||||
var STATE_RELEASE = 10;
|
||||
|
||||
var GRABBABLE_DATA_KEY = "grabbableKey"; // shared with grab.js
|
||||
var GRAB_USER_DATA_KEY = "grabKey"; // shared with grab.js
|
||||
|
||||
var DEFAULT_GRABBABLE_DATA = {
|
||||
grabbable: true,
|
||||
invertSolidWhileHeld: false
|
||||
};
|
||||
function stateToName(state) {
|
||||
switch (state) {
|
||||
case STATE_OFF:
|
||||
return "off";
|
||||
case STATE_SEARCHING:
|
||||
return "searching";
|
||||
case STATE_DISTANCE_HOLDING:
|
||||
return "distance_holding";
|
||||
case STATE_CONTINUE_DISTANCE_HOLDING:
|
||||
return "continue_distance_holding";
|
||||
case STATE_NEAR_GRABBING:
|
||||
return "near_grabbing";
|
||||
case STATE_CONTINUE_NEAR_GRABBING:
|
||||
return "continue_near_grabbing";
|
||||
case STATE_NEAR_GRABBING_NON_COLLIDING:
|
||||
return "near_grabbing_non_colliding";
|
||||
case STATE_CONTINUE_NEAR_GRABBING_NON_COLLIDING:
|
||||
return "continue_near_grabbing_non_colliding";
|
||||
case STATE_FAR_GRABBING_NON_COLLIDING:
|
||||
return "far_grabbing_non_colliding";
|
||||
case STATE_CONTINUE_FAR_GRABBING_NON_COLLIDING:
|
||||
return "continue_far_grabbing_non_colliding";
|
||||
case STATE_RELEASE:
|
||||
return "release";
|
||||
}
|
||||
|
||||
var disabledHand ='none';
|
||||
return "unknown";
|
||||
}
|
||||
|
||||
function getTag() {
|
||||
return "grab-" + MyAvatar.sessionUUID;
|
||||
|
@ -126,7 +154,7 @@ function entityIsGrabbedByOther(entityID) {
|
|||
}
|
||||
|
||||
|
||||
function MyController(hand, triggerAction) {
|
||||
function MyController(hand) {
|
||||
this.hand = hand;
|
||||
if (this.hand === RIGHT_HAND) {
|
||||
this.getHandPosition = MyAvatar.getRightPalmPosition;
|
||||
|
@ -138,7 +166,6 @@ function MyController(hand, triggerAction) {
|
|||
|
||||
var SPATIAL_CONTROLLERS_PER_PALM = 2;
|
||||
var TIP_CONTROLLER_OFFSET = 1;
|
||||
this.triggerAction = triggerAction;
|
||||
this.palm = SPATIAL_CONTROLLERS_PER_PALM * hand;
|
||||
this.tip = SPATIAL_CONTROLLERS_PER_PALM * hand + TIP_CONTROLLER_OFFSET;
|
||||
|
||||
|
@ -148,6 +175,7 @@ function MyController(hand, triggerAction) {
|
|||
this.state = STATE_OFF;
|
||||
this.pointer = null; // entity-id of line object
|
||||
this.triggerValue = 0; // rolling average of trigger value
|
||||
this.rawTriggerValue = 0;
|
||||
|
||||
var _this = this;
|
||||
|
||||
|
@ -195,7 +223,7 @@ function MyController(hand, triggerAction) {
|
|||
|
||||
this.setState = function(newState) {
|
||||
if (WANT_DEBUG) {
|
||||
print("STATE: " + this.state + " --> " + newState);
|
||||
print("STATE: " + stateToName(this.state) + " --> " + stateToName(newState) + ", hand: " + this.hand);
|
||||
}
|
||||
this.state = newState;
|
||||
}
|
||||
|
@ -244,12 +272,16 @@ function MyController(hand, triggerAction) {
|
|||
this.pointer = null;
|
||||
};
|
||||
|
||||
this.updateSmoothedTrigger = function() {
|
||||
var triggerValue = Controller.getActionValue(this.triggerAction);
|
||||
this.eitherTrigger = function (value) {
|
||||
_this.rawTriggerValue = value;
|
||||
};
|
||||
|
||||
this.updateSmoothedTrigger = function () {
|
||||
var triggerValue = this.rawTriggerValue;
|
||||
// smooth out trigger value
|
||||
this.triggerValue = (this.triggerValue * TRIGGER_SMOOTH_RATIO) +
|
||||
(triggerValue * (1.0 - TRIGGER_SMOOTH_RATIO));
|
||||
}
|
||||
};
|
||||
|
||||
this.triggerSmoothedSqueezed = function() {
|
||||
return this.triggerValue > TRIGGER_ON_VALUE;
|
||||
|
@ -259,8 +291,8 @@ function MyController(hand, triggerAction) {
|
|||
return this.triggerValue < TRIGGER_OFF_VALUE;
|
||||
};
|
||||
|
||||
this.triggerSqueezed = function() {
|
||||
var triggerValue = Controller.getActionValue(this.triggerAction);
|
||||
this.triggerSqueezed = function() {
|
||||
var triggerValue = this.rawTriggerValue;
|
||||
return triggerValue > TRIGGER_ON_VALUE;
|
||||
};
|
||||
|
||||
|
@ -347,10 +379,11 @@ function MyController(hand, triggerAction) {
|
|||
}
|
||||
if (intersectionDistance <= NEAR_PICK_MAX_DISTANCE) {
|
||||
// the hand is very close to the intersected object. go into close-grabbing mode.
|
||||
if (intersection.properties.collisionsWillMove === 1) {
|
||||
this.setState(STATE_NEAR_GRABBING);
|
||||
} else {
|
||||
var grabbableData = getEntityCustomData(GRABBABLE_DATA_KEY, this.grabbedEntity, DEFAULT_GRABBABLE_DATA);
|
||||
if (grabbableData.wantsTrigger) {
|
||||
this.setState(STATE_NEAR_GRABBING_NON_COLLIDING);
|
||||
} else {
|
||||
this.setState(STATE_NEAR_GRABBING);
|
||||
}
|
||||
} else {
|
||||
// don't allow two people to distance grab the same object
|
||||
|
@ -391,21 +424,22 @@ function MyController(hand, triggerAction) {
|
|||
}
|
||||
if (this.grabbedEntity === null) {
|
||||
return;
|
||||
} else if (props.locked === 0 && props.collisionsWillMove === 1) {
|
||||
this.setState(STATE_NEAR_GRABBING);
|
||||
} else if (props.collisionsWillMove === 0 && grabbableData.wantsTrigger) {
|
||||
// We have grabbed a non-physical object, so we want to trigger a non-colliding event as opposed to a grab event
|
||||
}
|
||||
if (grabbableData.wantsTrigger) {
|
||||
this.setState(STATE_NEAR_GRABBING_NON_COLLIDING);
|
||||
} else if (props.locked === 0) {
|
||||
this.setState(STATE_NEAR_GRABBING);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
this.distanceHolding = function() {
|
||||
|
||||
var handControllerPosition = Controller.getSpatialControlPosition(this.palm);
|
||||
var handRotation = Quat.multiply(MyAvatar.orientation, Controller.getSpatialControlRawRotation(this.palm));
|
||||
var handControllerPosition = (this.hand === RIGHT_HAND) ? MyAvatar.rightHandPosition : MyAvatar.leftHandPosition;
|
||||
var controllerHandInput = (this.hand === RIGHT_HAND) ? Controller.Standard.RightHand : Controller.Standard.LeftHand;
|
||||
var handRotation = Quat.multiply(MyAvatar.orientation, Controller.getPoseValue(controllerHandInput).rotation);
|
||||
var grabbedProperties = Entities.getEntityProperties(this.grabbedEntity, ["position", "rotation",
|
||||
"gravity", "ignoreForCollisions"]);
|
||||
"gravity", "ignoreForCollisions",
|
||||
"collisionsWillMove"]);
|
||||
var now = Date.now();
|
||||
|
||||
// add the action and initialize some variables
|
||||
|
@ -452,8 +486,9 @@ function MyController(hand, triggerAction) {
|
|||
}
|
||||
|
||||
var handPosition = this.getHandPosition();
|
||||
var handControllerPosition = Controller.getSpatialControlPosition(this.palm);
|
||||
var handRotation = Quat.multiply(MyAvatar.orientation, Controller.getSpatialControlRawRotation(this.palm));
|
||||
var handControllerPosition = (this.hand === RIGHT_HAND) ? MyAvatar.rightHandPosition : MyAvatar.leftHandPosition;
|
||||
var controllerHandInput = (this.hand === RIGHT_HAND) ? Controller.Standard.RightHand : Controller.Standard.LeftHand;
|
||||
var handRotation = Quat.multiply(MyAvatar.orientation, Controller.getPoseValue(controllerHandInput).rotation);
|
||||
var grabbedProperties = Entities.getEntityProperties(this.grabbedEntity, ["position", "rotation"]);
|
||||
|
||||
this.lineOn(handPosition, Vec3.subtract(grabbedProperties.position, handPosition), INTERSECT_COLOR);
|
||||
|
@ -549,8 +584,14 @@ function MyController(hand, triggerAction) {
|
|||
this.lineOff();
|
||||
|
||||
var grabbedProperties = Entities.getEntityProperties(this.grabbedEntity,
|
||||
["position", "rotation", "gravity", "ignoreForCollisions"]);
|
||||
["position", "rotation", "gravity",
|
||||
"ignoreForCollisions", "collisionsWillMove"]);
|
||||
this.activateEntity(this.grabbedEntity, grabbedProperties);
|
||||
if (grabbedProperties.collisionsWillMove && NEAR_GRABBING_KINEMATIC) {
|
||||
Entities.editEntity(this.grabbedEntity, {
|
||||
collisionsWillMove: false
|
||||
});
|
||||
}
|
||||
|
||||
var handRotation = this.getHandRotation();
|
||||
var handPosition = this.getHandPosition();
|
||||
|
@ -579,7 +620,9 @@ function MyController(hand, triggerAction) {
|
|||
timeScale: NEAR_GRABBING_ACTION_TIMEFRAME,
|
||||
relativePosition: this.offsetPosition,
|
||||
relativeRotation: this.offsetRotation,
|
||||
ttl: ACTION_TTL
|
||||
ttl: ACTION_TTL,
|
||||
kinematic: NEAR_GRABBING_KINEMATIC,
|
||||
kinematicSetVelocity: true
|
||||
});
|
||||
if (this.actionID === NULL_ACTION_ID) {
|
||||
this.actionID = null;
|
||||
|
@ -595,7 +638,7 @@ function MyController(hand, triggerAction) {
|
|||
|
||||
}
|
||||
|
||||
this.currentHandControllerTipPosition = Controller.getSpatialControlPosition(this.tip);
|
||||
this.currentHandControllerTipPosition = (this.hand === RIGHT_HAND) ? MyAvatar.rightHandTipPosition : MyAvatar.leftHandTipPosition;;
|
||||
|
||||
this.currentObjectTime = Date.now();
|
||||
};
|
||||
|
@ -613,7 +656,7 @@ function MyController(hand, triggerAction) {
|
|||
// of it's actual offset, let's try imparting a velocity which is at a fixed radius
|
||||
// from the palm.
|
||||
|
||||
var handControllerPosition = Controller.getSpatialControlPosition(this.tip);
|
||||
var handControllerPosition = (this.hand === RIGHT_HAND) ? MyAvatar.rightHandPosition : MyAvatar.leftHandPosition;
|
||||
var now = Date.now();
|
||||
|
||||
var deltaPosition = Vec3.subtract(handControllerPosition, this.currentHandControllerTipPosition); // meters
|
||||
|
@ -631,7 +674,9 @@ function MyController(hand, triggerAction) {
|
|||
timeScale: NEAR_GRABBING_ACTION_TIMEFRAME,
|
||||
relativePosition: this.offsetPosition,
|
||||
relativeRotation: this.offsetRotation,
|
||||
ttl: ACTION_TTL
|
||||
ttl: ACTION_TTL,
|
||||
kinematic: NEAR_GRABBING_KINEMATIC,
|
||||
kinematicSetVelocity: true
|
||||
});
|
||||
this.actionTimeout = now + (ACTION_TTL * MSEC_PER_SEC);
|
||||
}
|
||||
|
@ -800,12 +845,13 @@ function MyController(hand, triggerAction) {
|
|||
Entities.callEntityMethod(this.grabbedEntity, "releaseGrab");
|
||||
}
|
||||
|
||||
this.deactivateEntity(this.grabbedEntity);
|
||||
|
||||
// the action will tend to quickly bring an object's velocity to zero. now that
|
||||
// the action is gone, set the objects velocity to something the holder might expect.
|
||||
Entities.editEntity(this.grabbedEntity, {
|
||||
velocity: this.grabbedVelocity
|
||||
});
|
||||
this.deactivateEntity(this.grabbedEntity);
|
||||
|
||||
this.grabbedVelocity = ZERO_VEC;
|
||||
this.grabbedEntity = null;
|
||||
|
@ -828,6 +874,7 @@ function MyController(hand, triggerAction) {
|
|||
if (data["refCount"] == 1) {
|
||||
data["gravity"] = grabbedProperties.gravity;
|
||||
data["ignoreForCollisions"] = grabbedProperties.ignoreForCollisions;
|
||||
data["collisionsWillMove"] = grabbedProperties.collisionsWillMove;
|
||||
var whileHeldProperties = {gravity: {x:0, y:0, z:0}};
|
||||
if (invertSolidWhileHeld) {
|
||||
whileHeldProperties["ignoreForCollisions"] = ! grabbedProperties.ignoreForCollisions;
|
||||
|
@ -845,7 +892,8 @@ function MyController(hand, triggerAction) {
|
|||
if (data["refCount"] < 1) {
|
||||
Entities.editEntity(entityID, {
|
||||
gravity: data["gravity"],
|
||||
ignoreForCollisions: data["ignoreForCollisions"]
|
||||
ignoreForCollisions: data["ignoreForCollisions"],
|
||||
collisionsWillMove: data["collisionsWillMove"]
|
||||
});
|
||||
data = null;
|
||||
}
|
||||
|
@ -856,8 +904,16 @@ function MyController(hand, triggerAction) {
|
|||
};
|
||||
}
|
||||
|
||||
var rightController = new MyController(RIGHT_HAND, Controller.findAction("RIGHT_HAND_CLICK"));
|
||||
var leftController = new MyController(LEFT_HAND, Controller.findAction("LEFT_HAND_CLICK"));
|
||||
var rightController = new MyController(RIGHT_HAND);
|
||||
var leftController = new MyController(LEFT_HAND);
|
||||
|
||||
var MAPPING_NAME = "com.highfidelity.handControllerGrab";
|
||||
|
||||
var mapping = Controller.newMapping(MAPPING_NAME);
|
||||
mapping.from([Controller.Standard.RB, Controller.Standard.RT]).peek().to(rightController.eitherTrigger);
|
||||
mapping.from([Controller.Standard.LB, Controller.Standard.LT]).peek().to(leftController.eitherTrigger);
|
||||
Controller.enableMapping(MAPPING_NAME);
|
||||
|
||||
|
||||
function update() {
|
||||
rightController.update();
|
||||
|
@ -867,6 +923,7 @@ function update() {
|
|||
function cleanup() {
|
||||
rightController.cleanup();
|
||||
leftController.cleanup();
|
||||
Controller.disableMapping(MAPPING_NAME);
|
||||
}
|
||||
|
||||
Script.scriptEnding.connect(cleanup);
|
||||
|
|
102
examples/controllers/handPosesDebug.js
Normal file
102
examples/controllers/handPosesDebug.js
Normal file
|
@ -0,0 +1,102 @@
|
|||
//
|
||||
// handPosesDebug.js
|
||||
// examples
|
||||
//
|
||||
// Copyright 2015 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
|
||||
|
||||
function makeSphere(color) {
|
||||
var SPHERE_SIZE = 0.05;
|
||||
var sphere = Overlays.addOverlay("sphere", {
|
||||
position: { x: 0, y: 0, z: 0 },
|
||||
size: SPHERE_SIZE,
|
||||
color: color,
|
||||
alpha: 1.0,
|
||||
solid: true,
|
||||
visible: true,
|
||||
});
|
||||
|
||||
return sphere;
|
||||
}
|
||||
|
||||
|
||||
var NUM_HANDS = 2;
|
||||
var NUM_SPHERES_PER_HAND = 2;
|
||||
var LEFT_HAND = 0;
|
||||
var RIGHT_HAND = 1;
|
||||
|
||||
var COLORS = [ { red: 255, green: 0, blue: 0 }, { red: 0, green: 0, blue: 255 } ];
|
||||
|
||||
|
||||
function index(handNum, indexNum) {
|
||||
return handNum * NUM_HANDS + indexNum;
|
||||
}
|
||||
|
||||
var app = {};
|
||||
|
||||
|
||||
function setup() {
|
||||
app.spheres = new Array();
|
||||
|
||||
for (var h = 0; h < NUM_HANDS; h++) {
|
||||
for (var s = 0; s < NUM_SPHERES_PER_HAND; s++) {
|
||||
var i = index(h, s);
|
||||
app.spheres[i] = makeSphere(COLORS[h]);
|
||||
print("Added Sphere num " + i + " = " + JSON.stringify(app.spheres[i]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function updateHand(handNum, deltaTime) {
|
||||
var pose;
|
||||
var handName = "right";
|
||||
if (handNum == LEFT_HAND) {
|
||||
pose = MyAvatar.getLeftHandPose();
|
||||
handName = "left";
|
||||
} else {
|
||||
pose = MyAvatar.getRightHandPose();
|
||||
handName = "right";
|
||||
}
|
||||
|
||||
if (pose.valid) {
|
||||
//print(handName + " hand moving" + JSON.stringify(pose));
|
||||
Overlays.editOverlay(app.spheres[index(handNum, 0)], {
|
||||
position: pose.translation,
|
||||
visible: true,
|
||||
});
|
||||
var vpos = Vec3.sum(Vec3.multiply(10 * deltaTime, pose.velocity), pose.translation);
|
||||
Overlays.editOverlay(app.spheres[index(handNum, 1)], {
|
||||
position: vpos,
|
||||
visible: true,
|
||||
});
|
||||
} else {
|
||||
Overlays.editOverlay(app.spheres[index(handNum, 0)], {
|
||||
visible: false
|
||||
});
|
||||
|
||||
Overlays.editOverlay(app.spheres[index(handNum, 1)], {
|
||||
visible: false
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function update(deltaTime) {
|
||||
updateHand(LEFT_HAND, deltaTime);
|
||||
updateHand(RIGHT_HAND, deltaTime);
|
||||
}
|
||||
|
||||
function scriptEnding() {
|
||||
print("Removing spheres = " + JSON.stringify(app.spheres));
|
||||
for (var i = 0; i < app.spheres.length; i++) {
|
||||
Overlays.deleteOverlay(app.spheres[i]);
|
||||
}
|
||||
}
|
||||
|
||||
setup();
|
||||
Script.update.connect(update);
|
||||
Script.scriptEnding.connect(scriptEnding);
|
|
@ -32,6 +32,8 @@ var guitarModel = HIFI_PUBLIC_BUCKET + "models/attachments/guitar.fst";
|
|||
|
||||
// Load sounds that will be played
|
||||
|
||||
var heyManWave = SoundCache.getSound("https://hifi-public.s3.amazonaws.com/sounds/KenDoll_1%2303.wav");
|
||||
|
||||
var chords = new Array();
|
||||
// Nylon string guitar
|
||||
chords[1] = SoundCache.getSound(HIFI_PUBLIC_BUCKET + "sounds/Guitars/Guitar+-+Nylon+A.raw");
|
||||
|
@ -56,97 +58,128 @@ var NUM_GUITARS = 3;
|
|||
var guitarSelector = NUM_CHORDS;
|
||||
var whichChord = 1;
|
||||
|
||||
var leftHanded = true;
|
||||
var leftHanded = false;
|
||||
var strumHand, chordHand, strumTrigger, chordTrigger;
|
||||
if (leftHanded) {
|
||||
var strumHand = 0;
|
||||
var chordHand = 1;
|
||||
strumHand = Controller.Standard.LeftHand;
|
||||
chordHand = Controller.Standard.RightHand;
|
||||
strumTrigger = Controller.Standard.LT;
|
||||
chordTrigger = Controller.Standard.RT;
|
||||
changeGuitar = Controller.Standard.RB;
|
||||
chord1 = Controller.Standard.X;
|
||||
chord2 = Controller.Standard.Y;
|
||||
chord3 = Controller.Standard.A;
|
||||
chord4 = Controller.Standard.B;
|
||||
} else {
|
||||
var strumHand = 1;
|
||||
var chordHand = 0;
|
||||
strumHand = Controller.Standard.RightHand;
|
||||
chordHand = Controller.Standard.LeftHand;
|
||||
strumTrigger = Controller.Standard.RT;
|
||||
chordTrigger = Controller.Standard.LT;
|
||||
changeGuitar = Controller.Standard.LB;
|
||||
chord1 = Controller.Standard.DU; // these may not be correct, maybe we should map directly to Hydra??
|
||||
chord2 = Controller.Standard.DD;
|
||||
chord3 = Controller.Standard.DL;
|
||||
chord4 = Controller.Standard.DR;
|
||||
}
|
||||
|
||||
var lastPosition = { x: 0.0,
|
||||
y: 0.0,
|
||||
z: 0.0 };
|
||||
|
||||
var soundPlaying = false;
|
||||
var audioInjector = null;
|
||||
var selectorPressed = false;
|
||||
var position;
|
||||
|
||||
MyAvatar.attach(guitarModel, "Hips", {x: -0.2, y: 0.0, z: 0.1}, Quat.fromPitchYawRollDegrees(90, 00, 90), 1.0);
|
||||
MyAvatar.attach(guitarModel, "Hips", {x: leftHanded ? -0.2 : 0.2, y: 0.0, z: 0.1}, Quat.fromPitchYawRollDegrees(90, 00, leftHanded ? 75 : -75), 1.0);
|
||||
|
||||
function checkHands(deltaTime) {
|
||||
for (var palm = 0; palm < 2; palm++) {
|
||||
var palmVelocity = Controller.getSpatialControlVelocity(palm * 2 + 1);
|
||||
var volume = length(palmVelocity) / 5.0;
|
||||
var position = Controller.getSpatialControlPosition(palm * 2 + 1);
|
||||
var myPelvis = MyAvatar.position;
|
||||
var trigger = Controller.getTriggerValue(strumHand);
|
||||
var chord = Controller.getTriggerValue(chordHand);
|
||||
var strumVelocity = Controller.getPoseValue(strumHand).velocity;
|
||||
var volume = length(strumVelocity) / 5.0;
|
||||
|
||||
if (volume > 1.0) volume = 1.0;
|
||||
if ((chord > 0.1) && soundPlaying.isPlaying) {
|
||||
// If chord finger trigger pulled, stop current chord
|
||||
print("stopped sound");
|
||||
soundPlaying.stop();
|
||||
if (volume == 0.0) {
|
||||
volume = 1.0;
|
||||
}
|
||||
|
||||
var strumHandPosition = leftHanded ? MyAvatar.leftHandPosition : MyAvatar.rightHandPosition;
|
||||
var myPelvis = MyAvatar.position;
|
||||
var strumming = Controller.getValue(strumTrigger);
|
||||
var chord = Controller.getValue(chordTrigger);
|
||||
|
||||
if (volume > 1.0) volume = 1.0;
|
||||
if ((chord > 0.1) && audioInjector && audioInjector.isPlaying) {
|
||||
// If chord finger trigger pulled, stop current chord
|
||||
print("stopping chord because cord trigger pulled");
|
||||
audioInjector.stop();
|
||||
}
|
||||
|
||||
// Change guitars if button FWD (5) pressed
|
||||
if (Controller.getValue(changeGuitar)) {
|
||||
if (!selectorPressed) {
|
||||
print("changeGuitar:" + changeGuitar);
|
||||
guitarSelector += NUM_CHORDS;
|
||||
if (guitarSelector >= NUM_CHORDS * NUM_GUITARS) {
|
||||
guitarSelector = 0;
|
||||
}
|
||||
print("new guitarBase: " + guitarSelector);
|
||||
stopAudio(true);
|
||||
selectorPressed = true;
|
||||
}
|
||||
} else {
|
||||
selectorPressed = false;
|
||||
}
|
||||
|
||||
var BUTTON_COUNT = 6;
|
||||
if (Controller.getValue(chord1)) {
|
||||
whichChord = 1;
|
||||
stopAudio(true);
|
||||
} else if (Controller.getValue(chord2)) {
|
||||
whichChord = 2;
|
||||
stopAudio(true);
|
||||
} else if (Controller.getValue(chord3)) {
|
||||
whichChord = 3;
|
||||
stopAudio(true);
|
||||
} else if (Controller.getValue(chord4)) {
|
||||
whichChord = 4;
|
||||
stopAudio(true);
|
||||
}
|
||||
|
||||
// Change guitars if button FWD (5) pressed
|
||||
if (Controller.isButtonPressed(chordHand * BUTTON_COUNT + 5)) {
|
||||
if (!selectorPressed) {
|
||||
guitarSelector += NUM_CHORDS;
|
||||
if (guitarSelector >= NUM_CHORDS * NUM_GUITARS) {
|
||||
guitarSelector = 0;
|
||||
}
|
||||
selectorPressed = true;
|
||||
}
|
||||
} else {
|
||||
selectorPressed = false;
|
||||
}
|
||||
var STRUM_HEIGHT_ABOVE_PELVIS = 0.10;
|
||||
var strummingHeight = myPelvis.y + STRUM_HEIGHT_ABOVE_PELVIS;
|
||||
|
||||
if (Controller.isButtonPressed(chordHand * BUTTON_COUNT + 1)) {
|
||||
whichChord = 1;
|
||||
} else if (Controller.isButtonPressed(chordHand * BUTTON_COUNT + 2)) {
|
||||
whichChord = 2;
|
||||
} else if (Controller.isButtonPressed(chordHand * BUTTON_COUNT + 3)) {
|
||||
whichChord = 3;
|
||||
} else if (Controller.isButtonPressed(chordHand * BUTTON_COUNT + 4)) {
|
||||
whichChord = 4;
|
||||
}
|
||||
var strumNowAbove = strumHandPosition.y > strummingHeight;
|
||||
var strumNowBelow = strumHandPosition.y <= strummingHeight;
|
||||
var strumWasAbove = lastPosition.y > strummingHeight;
|
||||
var strumWasBelow = lastPosition.y <= strummingHeight;
|
||||
var strumUp = strumNowAbove && strumWasBelow;
|
||||
var strumDown = strumNowBelow && strumWasAbove;
|
||||
|
||||
if (palm == strumHand) {
|
||||
if ((strumUp || strumDown) && (strumming > 0.1)) {
|
||||
// If hand passes downward or upward through 'strings', and finger trigger pulled, play
|
||||
playChord(strumHandPosition, volume);
|
||||
}
|
||||
lastPosition = strumHandPosition;
|
||||
}
|
||||
|
||||
var STRUM_HEIGHT_ABOVE_PELVIS = 0.10;
|
||||
var strumTriggerHeight = myPelvis.y + STRUM_HEIGHT_ABOVE_PELVIS;
|
||||
//printVector(position);
|
||||
if ( ( ((position.y < strumTriggerHeight) && (lastPosition.y >= strumTriggerHeight)) ||
|
||||
((position.y > strumTriggerHeight) && (lastPosition.y <= strumTriggerHeight)) ) && (trigger > 0.1) ){
|
||||
// If hand passes downward or upward through 'strings', and finger trigger pulled, play
|
||||
playChord(position, volume);
|
||||
}
|
||||
lastPosition = Controller.getSpatialControlPosition(palm * 2 + 1);
|
||||
}
|
||||
function stopAudio(killInjector) {
|
||||
if (audioInjector && audioInjector.isPlaying) {
|
||||
print("stopped sound");
|
||||
audioInjector.stop();
|
||||
}
|
||||
if (killInjector) {
|
||||
audioInjector = null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function playChord(position, volume) {
|
||||
if (soundPlaying.isPlaying) {
|
||||
print("stopped sound");
|
||||
soundPlaying.stop();
|
||||
stopAudio();
|
||||
print("Played sound: " + whichChord + " at volume " + volume);
|
||||
if (!audioInjector) {
|
||||
var index = guitarSelector + whichChord;
|
||||
var chord = chords[guitarSelector + whichChord];
|
||||
audioInjector = Audio.playSound(chord, { position: position, volume: volume });
|
||||
} else {
|
||||
audioInjector.restart();
|
||||
}
|
||||
|
||||
print("Played sound: " + whichChord + " at volume " + options.volume);
|
||||
if (!soundPlaying) {
|
||||
soundPlaying = Audio.playSound(chords[guitarSelector + whichChord], {
|
||||
position: position,
|
||||
volume: volume
|
||||
});
|
||||
} else {
|
||||
soundPlaying.restart();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function keyPressEvent(event) {
|
||||
|
@ -154,15 +187,19 @@ function keyPressEvent(event) {
|
|||
keyVolume = 0.4;
|
||||
if (event.text == "1") {
|
||||
whichChord = 1;
|
||||
stopAudio(true);
|
||||
playChord(MyAvatar.position, keyVolume);
|
||||
} else if (event.text == "2") {
|
||||
whichChord = 2;
|
||||
stopAudio(true);
|
||||
playChord(MyAvatar.position, keyVolume);
|
||||
} else if (event.text == "3") {
|
||||
whichChord = 3;
|
||||
stopAudio(true);
|
||||
playChord(MyAvatar.position, keyVolume);
|
||||
} else if (event.text == "4") {
|
||||
whichChord = 4;
|
||||
stopAudio(true);
|
||||
playChord(MyAvatar.position, keyVolume);
|
||||
}
|
||||
}
|
||||
|
@ -170,6 +207,7 @@ function keyPressEvent(event) {
|
|||
function scriptEnding() {
|
||||
MyAvatar.detachOne(guitarModel);
|
||||
}
|
||||
|
||||
// Connect a call back that happens every frame
|
||||
Script.update.connect(checkHands);
|
||||
Script.scriptEnding.connect(scriptEnding);
|
||||
|
|
|
@ -43,7 +43,8 @@ strokeSpeed[1] = 0.0;
|
|||
|
||||
function checkSticks(deltaTime) {
|
||||
for (var palm = 0; palm < 2; palm++) {
|
||||
var palmVelocity = Controller.getSpatialControlVelocity(palm * 2 + 1);
|
||||
var handPose = (palm == 0) ? MyAvatar.leftHandPose : MyAvatar.rightHandPose;
|
||||
var palmVelocity = handPose.velocity;
|
||||
var speed = length(palmVelocity);
|
||||
|
||||
const TRIGGER_SPEED = 0.30; // Lower this value to let you 'drum' more gently
|
||||
|
@ -64,7 +65,7 @@ function checkSticks(deltaTime) {
|
|||
if ((palmVelocity.y > 0.0) || (speed < STOP_SPEED)) {
|
||||
state[palm] = 0;
|
||||
|
||||
var options = { position: Controller.getSpatialControlPosition(palm * 2 + 1) };
|
||||
var options = { position: handPose.translation };
|
||||
|
||||
if (strokeSpeed[palm] > 1.0) { strokeSpeed[palm] = 1.0; }
|
||||
options.volume = strokeSpeed[palm];
|
||||
|
|
|
@ -130,29 +130,38 @@ function Hand(name, palm, tip, forwardButton, button3, trigger) {
|
|||
this.trigger = trigger;
|
||||
this.holdingFrisbee = false;
|
||||
this.entity = false;
|
||||
this.palmPosition = function() { return Controller.getSpatialControlPosition(this.palm); }
|
||||
this.palmPosition = function () {
|
||||
return this.palm == LEFT_PALM ? MyAvatar.leftHandPose.translation : MyAvatar.rightHandPose.translation;
|
||||
};
|
||||
|
||||
this.grabButtonPressed = function() {
|
||||
return (
|
||||
Controller.isButtonPressed(this.forwardButton) ||
|
||||
Controller.isButtonPressed(this.button3) ||
|
||||
Controller.getTriggerValue(this.trigger) > 0.5
|
||||
Controller.getValue(this.forwardButton) ||
|
||||
Controller.getValue(this.button3) ||
|
||||
Controller.getValue(this.trigger) > 0.5
|
||||
)
|
||||
};
|
||||
this.holdPosition = function() { return this.palm == LEFT_PALM ? MyAvatar.getLeftPalmPosition() : MyAvatar.getRightPalmPosition(); };
|
||||
this.holdPosition = function () {
|
||||
return this.palm == LEFT_PALM ? MyAvatar.leftHandPose.translation : MyAvatar.rightHandPose.translation;
|
||||
};
|
||||
|
||||
this.holdRotation = function() {
|
||||
var q = Controller.getSpatialControlRawRotation(this.palm);
|
||||
var q = (this.palm == LEFT_PALM) ? Controller.getPoseValue(Controller.Standard.leftHand).rotation
|
||||
: Controller.getPoseValue(Controller.Standard.rightHand).rotation;
|
||||
q = Quat.multiply(MyAvatar.orientation, q);
|
||||
return {x: q.x, y: q.y, z: q.z, w: q.w};
|
||||
};
|
||||
this.tipVelocity = function() { return Controller.getSpatialControlVelocity(this.tip); };
|
||||
this.tipVelocity = function () {
|
||||
return this.tip == LEFT_TIP ? MyAvatar.leftHandTipPose.velocity : MyAvatar.rightHandTipPose.velocity;
|
||||
};
|
||||
}
|
||||
|
||||
function MouseControl(button) {
|
||||
this.button = button;
|
||||
}
|
||||
|
||||
var leftHand = new Hand("LEFT", LEFT_PALM, LEFT_TIP, LEFT_BUTTON_FWD, LEFT_BUTTON_3, 0);
|
||||
var rightHand = new Hand("RIGHT", RIGHT_PALM, RIGHT_TIP, RIGHT_BUTTON_FWD, RIGHT_BUTTON_3, 1);
|
||||
var leftHand = new Hand("LEFT", LEFT_PALM, LEFT_TIP, Controller.Standard.LB, Controller.Standard.LeftPrimaryThumb, Controller.Standard.LT);
|
||||
var rightHand = new Hand("RIGHT", RIGHT_PALM, RIGHT_TIP, Controller.Standard.RB, Controller.Standard.RightPrimaryThumb, Controller.Standard.RT);
|
||||
|
||||
var leftMouseControl = new MouseControl("LEFT");
|
||||
var middleMouseControl = new MouseControl("MIDDLE");
|
||||
|
@ -302,12 +311,7 @@ function initToolBar() {
|
|||
}
|
||||
|
||||
function hydraCheck() {
|
||||
var numberOfButtons = Controller.getNumberOfButtons();
|
||||
var numberOfTriggers = Controller.getNumberOfTriggers();
|
||||
var numberOfSpatialControls = Controller.getNumberOfSpatialControls();
|
||||
var controllersPerTrigger = numberOfSpatialControls / numberOfTriggers;
|
||||
hydrasConnected = (numberOfButtons == 12 && numberOfTriggers == 2 && controllersPerTrigger == 2);
|
||||
return true;//hydrasConnected;
|
||||
return Controller.Hardware.Hydra !== undefined;
|
||||
}
|
||||
|
||||
function checkController(deltaTime) {
|
||||
|
|
|
@ -15,24 +15,64 @@
|
|||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
// FIXME kickback functionality was removed because the joint setting interface in
|
||||
// MyAvatar has apparently changed, breaking it.
|
||||
|
||||
Script.include("../../libraries/utils.js");
|
||||
Script.include("../../libraries/constants.js");
|
||||
Script.include("../../libraries/toolBars.js");
|
||||
|
||||
HIFI_PUBLIC_BUCKET = "http://s3.amazonaws.com/hifi-public/";
|
||||
|
||||
var RED = { red: 255, green: 0, blue: 0 };
|
||||
var LASER_WIDTH = 2;
|
||||
var POSE_CONTROLS = [ Controller.Standard.LeftHand, Controller.Standard.RightHand ];
|
||||
var TRIGGER_CONTROLS = [ Controller.Standard.LT, Controller.Standard.RT ];
|
||||
var MIN_THROWER_DELAY = 1000;
|
||||
var MAX_THROWER_DELAY = 1000;
|
||||
var RELOAD_INTERVAL = 5;
|
||||
var GUN_MODEL = HIFI_PUBLIC_BUCKET + "cozza13/gun/m1911-handgun+1.fbx?v=4";
|
||||
var BULLET_VELOCITY = 10.0;
|
||||
var GUN_OFFSETS = [ {
|
||||
x: -0.04,
|
||||
y: 0.26,
|
||||
z: 0.04
|
||||
}, {
|
||||
x: 0.04,
|
||||
y: 0.26,
|
||||
z: 0.04
|
||||
} ];
|
||||
|
||||
var GUN_ORIENTATIONS = [ Quat.fromPitchYawRollDegrees(0, 90, 90), Quat.fromPitchYawRollDegrees(0, -90, 270) ];
|
||||
|
||||
var BARREL_OFFSETS = [ {
|
||||
x: -0.12,
|
||||
y: 0.12,
|
||||
z: 0.04
|
||||
}, {
|
||||
x: 0.12,
|
||||
y: 0.12,
|
||||
z: 0.04
|
||||
} ];
|
||||
|
||||
var mapping = Controller.newMapping();
|
||||
var validPoses = [ false, false ];
|
||||
var barrelVectors = [ 0, 0 ];
|
||||
var barrelTips = [ 0, 0 ];
|
||||
var pointer = [];
|
||||
|
||||
pointer.push(Overlays.addOverlay("line3d", {
|
||||
start: { x: 0, y: 0, z: 0 },
|
||||
end: { x: 0, y: 0, z: 0 },
|
||||
color: RED,
|
||||
start: ZERO_VECTOR,
|
||||
end: ZERO_VECTOR,
|
||||
color: COLORS.RED,
|
||||
alpha: 1,
|
||||
visible: true,
|
||||
lineWidth: LASER_WIDTH
|
||||
}));
|
||||
|
||||
pointer.push(Overlays.addOverlay("line3d", {
|
||||
start: { x: 0, y: 0, z: 0 },
|
||||
end: { x: 0, y: 0, z: 0 },
|
||||
color: RED,
|
||||
start: ZERO_VECTOR,
|
||||
end: ZERO_VECTOR,
|
||||
color: COLORS.RED,
|
||||
alpha: 1,
|
||||
visible: true,
|
||||
lineWidth: LASER_WIDTH
|
||||
|
@ -42,135 +82,116 @@ function getRandomFloat(min, max) {
|
|||
return Math.random() * (max - min) + min;
|
||||
}
|
||||
|
||||
var lastX = 0;
|
||||
var lastY = 0;
|
||||
var yawFromMouse = 0;
|
||||
var pitchFromMouse = 0;
|
||||
var isMouseDown = false;
|
||||
|
||||
var MIN_THROWER_DELAY = 1000;
|
||||
var MAX_THROWER_DELAY = 1000;
|
||||
var LEFT_BUTTON_3 = 3;
|
||||
var RELOAD_INTERVAL = 5;
|
||||
|
||||
var KICKBACK_ANGLE = 15;
|
||||
var elbowKickAngle = 0.0;
|
||||
var rotationBeforeKickback;
|
||||
|
||||
var showScore = false;
|
||||
|
||||
|
||||
// Load some sound to use for loading and firing
|
||||
// Load some sound to use for loading and firing
|
||||
var fireSound = SoundCache.getSound(HIFI_PUBLIC_BUCKET + "sounds/Guns/GUN-SHOT2.raw");
|
||||
var loadSound = SoundCache.getSound(HIFI_PUBLIC_BUCKET + "sounds/Guns/Gun_Reload_Weapon22.raw");
|
||||
var impactSound = SoundCache.getSound(HIFI_PUBLIC_BUCKET + "sounds/Guns/BulletImpact2.raw");
|
||||
var targetHitSound = SoundCache.getSound(HIFI_PUBLIC_BUCKET + "sounds/Space%20Invaders/hit.raw");
|
||||
var targetLaunchSound = SoundCache.getSound(HIFI_PUBLIC_BUCKET + "sounds/Space%20Invaders/shoot.raw");
|
||||
|
||||
var gunModel = "https://s3.amazonaws.com/hifi-public/cozza13/gun/m1911-handgun+1.fbx?v=4";
|
||||
|
||||
var audioOptions = {
|
||||
volume: 0.9
|
||||
volume: 0.9
|
||||
}
|
||||
|
||||
var shotsFired = 0;
|
||||
var shotTime = new Date();
|
||||
|
||||
var activeControllers = 0;
|
||||
|
||||
// initialize our controller triggers
|
||||
var triggerPulled = new Array();
|
||||
var numberOfTriggers = Controller.getNumberOfTriggers();
|
||||
for (t = 0; t < numberOfTriggers; t++) {
|
||||
triggerPulled[t] = false;
|
||||
}
|
||||
|
||||
var isLaunchButtonPressed = false;
|
||||
var score = 0;
|
||||
var shotTime = new Date();
|
||||
var isLaunchButtonPressed = false;
|
||||
var score = 0;
|
||||
|
||||
var bulletID = false;
|
||||
var targetID = false;
|
||||
|
||||
// Create overlay buttons and reticle
|
||||
|
||||
// Create overlay buttons and reticle
|
||||
var BUTTON_SIZE = 32;
|
||||
var PADDING = 3;
|
||||
var NUM_BUTTONS = 3;
|
||||
|
||||
var screenSize = Controller.getViewportDimensions();
|
||||
var startX = screenSize.x / 2 - (NUM_BUTTONS * (BUTTON_SIZE + PADDING)) / 2;
|
||||
Script.include(["../../libraries/toolBars.js"]);
|
||||
var toolBar = new ToolBar(0, 0, ToolBar.HORIZONTAL, "highfidelity.gun.toolbar", function (screenSize) {
|
||||
var toolBar = new ToolBar(0, 0, ToolBar.HORIZONTAL, "highfidelity.gun.toolbar", function(screenSize) {
|
||||
return {
|
||||
x: startX,
|
||||
y: (screenSize.y - (BUTTON_SIZE + PADDING)),
|
||||
};
|
||||
});
|
||||
var reticle = Overlays.addOverlay("image", {
|
||||
x: screenSize.x / 2 - (BUTTON_SIZE / 2),
|
||||
y: screenSize.y / 2 - (BUTTON_SIZE / 2),
|
||||
width: BUTTON_SIZE,
|
||||
height: BUTTON_SIZE,
|
||||
imageURL: HIFI_PUBLIC_BUCKET + "images/gun/crosshairs.svg",
|
||||
alpha: 1
|
||||
});
|
||||
|
||||
var offButton = toolBar.addOverlay("image", {
|
||||
width: BUTTON_SIZE,
|
||||
height: BUTTON_SIZE,
|
||||
imageURL: HIFI_PUBLIC_BUCKET + "images/gun/close.svg",
|
||||
alpha: 1
|
||||
});
|
||||
width: BUTTON_SIZE,
|
||||
height: BUTTON_SIZE,
|
||||
imageURL: HIFI_PUBLIC_BUCKET + "images/gun/close.svg",
|
||||
alpha: 1
|
||||
});
|
||||
|
||||
startX += BUTTON_SIZE + PADDING;
|
||||
var platformButton = toolBar.addOverlay("image", {
|
||||
x: startX,
|
||||
y: screenSize.y - (BUTTON_SIZE + PADDING),
|
||||
width: BUTTON_SIZE,
|
||||
height: BUTTON_SIZE,
|
||||
imageURL: HIFI_PUBLIC_BUCKET + "images/gun/platform-targets.svg",
|
||||
alpha: 1
|
||||
});
|
||||
x: startX,
|
||||
y: screenSize.y - (BUTTON_SIZE + PADDING),
|
||||
width: BUTTON_SIZE,
|
||||
height: BUTTON_SIZE,
|
||||
imageURL: HIFI_PUBLIC_BUCKET + "images/gun/platform-targets.svg",
|
||||
alpha: 1
|
||||
});
|
||||
|
||||
startX += BUTTON_SIZE + PADDING;
|
||||
var gridButton = toolBar.addOverlay("image", {
|
||||
x: startX,
|
||||
y: screenSize.y - (BUTTON_SIZE + PADDING),
|
||||
width: BUTTON_SIZE,
|
||||
height: BUTTON_SIZE,
|
||||
imageURL: HIFI_PUBLIC_BUCKET + "images/gun/floating-targets.svg",
|
||||
alpha: 1
|
||||
});
|
||||
x: startX,
|
||||
y: screenSize.y - (BUTTON_SIZE + PADDING),
|
||||
width: BUTTON_SIZE,
|
||||
height: BUTTON_SIZE,
|
||||
imageURL: HIFI_PUBLIC_BUCKET + "images/gun/floating-targets.svg",
|
||||
alpha: 1
|
||||
});
|
||||
|
||||
if (showScore) {
|
||||
var text = Overlays.addOverlay("text", {
|
||||
x: screenSize.x / 2 - 100,
|
||||
y: screenSize.y / 2 - 50,
|
||||
width: 150,
|
||||
height: 50,
|
||||
color: { red: 0, green: 0, blue: 0},
|
||||
textColor: { red: 255, green: 0, blue: 0},
|
||||
topMargin: 4,
|
||||
leftMargin: 4,
|
||||
text: "Score: " + score
|
||||
});
|
||||
x: screenSize.x / 2 - 100,
|
||||
y: screenSize.y / 2 - 50,
|
||||
width: 150,
|
||||
height: 50,
|
||||
color: {
|
||||
red: 0,
|
||||
green: 0,
|
||||
blue: 0
|
||||
},
|
||||
textColor: {
|
||||
red: 255,
|
||||
green: 0,
|
||||
blue: 0
|
||||
},
|
||||
topMargin: 4,
|
||||
leftMargin: 4,
|
||||
text: "Score: " + score
|
||||
});
|
||||
}
|
||||
|
||||
var BULLET_VELOCITY = 10.0;
|
||||
|
||||
function entityCollisionWithEntity(entity1, entity2, collision) {
|
||||
if (entity2 === targetID) {
|
||||
score++;
|
||||
if (showScore) {
|
||||
Overlays.editOverlay(text, { text: "Score: " + score } );
|
||||
Overlays.editOverlay(text, {
|
||||
text: "Score: " + score
|
||||
});
|
||||
}
|
||||
|
||||
// We will delete the bullet and target in 1/2 sec, but for now we can see them bounce!
|
||||
// We will delete the bullet and target in 1/2 sec, but for now we can
|
||||
// see them bounce!
|
||||
Script.setTimeout(deleteBulletAndTarget, 500);
|
||||
|
||||
// Turn the target and the bullet white
|
||||
Entities.editEntity(entity1, { color: { red: 255, green: 255, blue: 255 }});
|
||||
Entities.editEntity(entity2, { color: { red: 255, green: 255, blue: 255 }});
|
||||
Entities.editEntity(entity1, {
|
||||
color: {
|
||||
red: 255,
|
||||
green: 255,
|
||||
blue: 255
|
||||
}
|
||||
});
|
||||
Entities.editEntity(entity2, {
|
||||
color: {
|
||||
red: 255,
|
||||
green: 255,
|
||||
blue: 255
|
||||
}
|
||||
});
|
||||
|
||||
// play the sound near the camera so the shooter can hear it
|
||||
audioOptions.position = Vec3.sum(Camera.getPosition(), Quat.getFront(Camera.getOrientation()));
|
||||
|
@ -188,41 +209,45 @@ function shootBullet(position, velocity, grenade) {
|
|||
|
||||
var bVelocity = grenade ? Vec3.multiply(GRENADE_VELOCITY, Vec3.normalize(velocity)) : velocity;
|
||||
var bSize = grenade ? GRENADE_SIZE : BULLET_SIZE;
|
||||
var bGravity = grenade ? GRENADE_GRAVITY : BULLET_GRAVITY;
|
||||
var bGravity = grenade ? GRENADE_GRAVITY : BULLET_GRAVITY;
|
||||
|
||||
bulletID = Entities.addEntity({
|
||||
type: "Sphere",
|
||||
position: position,
|
||||
dimensions: {
|
||||
x: bSize,
|
||||
y: bSize,
|
||||
z: bSize
|
||||
},
|
||||
color: {
|
||||
red: 0,
|
||||
green: 0,
|
||||
blue: 0
|
||||
},
|
||||
velocity: bVelocity,
|
||||
lifetime: BULLET_LIFETIME,
|
||||
gravity: {
|
||||
x: 0,
|
||||
y: bGravity,
|
||||
z: 0
|
||||
},
|
||||
damping: 0.01,
|
||||
density: 8000,
|
||||
ignoreCollisions: false,
|
||||
collisionsWillMove: true
|
||||
});
|
||||
|
||||
bulletID = Entities.addEntity(
|
||||
{ type: "Sphere",
|
||||
position: position,
|
||||
dimensions: { x: bSize, y: bSize, z: bSize },
|
||||
color: { red: 0, green: 0, blue: 0 },
|
||||
velocity: bVelocity,
|
||||
lifetime: BULLET_LIFETIME,
|
||||
gravity: { x: 0, y: bGravity, z: 0 },
|
||||
damping: 0.01,
|
||||
density: 8000,
|
||||
ignoreCollisions: false,
|
||||
collisionsWillMove: true
|
||||
});
|
||||
Script.addEventHandler(bulletID, "collisionWithEntity", entityCollisionWithEntity);
|
||||
|
||||
// Play firing sounds
|
||||
audioOptions.position = position;
|
||||
// Play firing sounds
|
||||
audioOptions.position = position;
|
||||
Audio.playSound(fireSound, audioOptions);
|
||||
shotsFired++;
|
||||
if ((shotsFired % RELOAD_INTERVAL) == 0) {
|
||||
Audio.playSound(loadSound, audioOptions);
|
||||
}
|
||||
|
||||
// Kickback the arm
|
||||
if (elbowKickAngle > 0.0) {
|
||||
MyAvatar.setJointData("LeftForeArm", rotationBeforeKickback);
|
||||
}
|
||||
rotationBeforeKickback = MyAvatar.getJointRotation("LeftForeArm");
|
||||
var armRotation = MyAvatar.getJointRotation("LeftForeArm");
|
||||
armRotation = Quat.multiply(armRotation, Quat.fromPitchYawRollDegrees(0.0, 0.0, KICKBACK_ANGLE));
|
||||
MyAvatar.setJointData("LeftForeArm", armRotation);
|
||||
elbowKickAngle = KICKBACK_ANGLE;
|
||||
}
|
||||
|
||||
function shootTarget() {
|
||||
var TARGET_SIZE = 0.50;
|
||||
var TARGET_GRAVITY = 0.0;
|
||||
|
@ -232,95 +257,152 @@ function shootTarget() {
|
|||
var DISTANCE_TO_LAUNCH_FROM = 5.0;
|
||||
var ANGLE_RANGE_FOR_LAUNCH = 20.0;
|
||||
var camera = Camera.getPosition();
|
||||
|
||||
var targetDirection = Quat.angleAxis(getRandomFloat(-ANGLE_RANGE_FOR_LAUNCH, ANGLE_RANGE_FOR_LAUNCH), { x:0, y:1, z:0 });
|
||||
|
||||
var targetDirection = Quat.angleAxis(getRandomFloat(-ANGLE_RANGE_FOR_LAUNCH, ANGLE_RANGE_FOR_LAUNCH), {
|
||||
x: 0,
|
||||
y: 1,
|
||||
z: 0
|
||||
});
|
||||
targetDirection = Quat.multiply(Camera.getOrientation(), targetDirection);
|
||||
var forwardVector = Quat.getFront(targetDirection);
|
||||
|
||||
|
||||
var newPosition = Vec3.sum(camera, Vec3.multiply(forwardVector, DISTANCE_TO_LAUNCH_FROM));
|
||||
|
||||
var velocity = Vec3.multiply(forwardVector, TARGET_FWD_VELOCITY);
|
||||
velocity.y += TARGET_UP_VELOCITY;
|
||||
|
||||
targetID = Entities.addEntity(
|
||||
{ type: "Box",
|
||||
position: newPosition,
|
||||
dimensions: { x: TARGET_SIZE * (0.5 + Math.random()), y: TARGET_SIZE * (0.5 + Math.random()), z: TARGET_SIZE * (0.5 + Math.random()) / 4.0 },
|
||||
color: { red: Math.random() * 255, green: Math.random() * 255, blue: Math.random() * 255 },
|
||||
velocity: velocity,
|
||||
gravity: { x: 0, y: TARGET_GRAVITY, z: 0 },
|
||||
lifetime: TARGET_LIFETIME,
|
||||
rotation: Camera.getOrientation(),
|
||||
damping: 0.1,
|
||||
density: 100.0,
|
||||
collisionsWillMove: true });
|
||||
targetID = Entities.addEntity({
|
||||
type: "Box",
|
||||
position: newPosition,
|
||||
dimensions: {
|
||||
x: TARGET_SIZE * (0.5 + Math.random()),
|
||||
y: TARGET_SIZE * (0.5 + Math.random()),
|
||||
z: TARGET_SIZE * (0.5 + Math.random()) / 4.0
|
||||
},
|
||||
color: {
|
||||
red: Math.random() * 255,
|
||||
green: Math.random() * 255,
|
||||
blue: Math.random() * 255
|
||||
},
|
||||
velocity: velocity,
|
||||
gravity: {
|
||||
x: 0,
|
||||
y: TARGET_GRAVITY,
|
||||
z: 0
|
||||
},
|
||||
lifetime: TARGET_LIFETIME,
|
||||
rotation: Camera.getOrientation(),
|
||||
damping: 0.1,
|
||||
density: 100.0,
|
||||
collisionsWillMove: true
|
||||
});
|
||||
|
||||
// Record start time
|
||||
// Record start time
|
||||
shotTime = new Date();
|
||||
|
||||
// Play target shoot sound
|
||||
audioOptions.position = newPosition;
|
||||
audioOptions.position = newPosition;
|
||||
Audio.playSound(targetLaunchSound, audioOptions);
|
||||
}
|
||||
|
||||
function makeGrid(type, scale, size) {
|
||||
var separation = scale * 2;
|
||||
var separation = scale * 2;
|
||||
var pos = Vec3.sum(Camera.getPosition(), Vec3.multiply(10.0 * scale * separation, Quat.getFront(Camera.getOrientation())));
|
||||
var x, y, z;
|
||||
var GRID_LIFE = 60.0;
|
||||
var dimensions;
|
||||
var GRID_LIFE = 60.0;
|
||||
var dimensions;
|
||||
|
||||
for (x = 0; x < size; x++) {
|
||||
for (y = 0; y < size; y++) {
|
||||
for (z = 0; z < size; z++) {
|
||||
|
||||
dimensions = { x: separation/2.0 * (0.5 + Math.random()), y: separation/2.0 * (0.5 + Math.random()), z: separation/2.0 * (0.5 + Math.random()) / 4.0 };
|
||||
|
||||
Entities.addEntity(
|
||||
{ type: type,
|
||||
position: { x: pos.x + x * separation, y: pos.y + y * separation, z: pos.z + z * separation },
|
||||
dimensions: dimensions,
|
||||
color: { red: Math.random() * 255, green: Math.random() * 255, blue: Math.random() * 255 },
|
||||
velocity: { x: 0, y: 0, z: 0 },
|
||||
gravity: { x: 0, y: 0, z: 0 },
|
||||
lifetime: GRID_LIFE,
|
||||
rotation: Camera.getOrientation(),
|
||||
damping: 0.1,
|
||||
density: 100.0,
|
||||
collisionsWillMove: true });
|
||||
dimensions = {
|
||||
x: separation / 2.0 * (0.5 + Math.random()),
|
||||
y: separation / 2.0 * (0.5 + Math.random()),
|
||||
z: separation / 2.0 * (0.5 + Math.random()) / 4.0
|
||||
};
|
||||
|
||||
Entities.addEntity({
|
||||
type: type,
|
||||
position: {
|
||||
x: pos.x + x * separation,
|
||||
y: pos.y + y * separation,
|
||||
z: pos.z + z * separation
|
||||
},
|
||||
dimensions: dimensions,
|
||||
color: {
|
||||
red: Math.random() * 255,
|
||||
green: Math.random() * 255,
|
||||
blue: Math.random() * 255
|
||||
},
|
||||
velocity: {
|
||||
x: 0,
|
||||
y: 0,
|
||||
z: 0
|
||||
},
|
||||
gravity: {
|
||||
x: 0,
|
||||
y: 0,
|
||||
z: 0
|
||||
},
|
||||
lifetime: GRID_LIFE,
|
||||
rotation: Camera.getOrientation(),
|
||||
damping: 0.1,
|
||||
density: 100.0,
|
||||
collisionsWillMove: true
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function makePlatform(gravity, scale, size) {
|
||||
var separation = scale * 2;
|
||||
var separation = scale * 2;
|
||||
var pos = Vec3.sum(Camera.getPosition(), Vec3.multiply(10.0 * scale * separation, Quat.getFront(Camera.getOrientation())));
|
||||
pos.y -= separation * size;
|
||||
var x, y, z;
|
||||
var TARGET_LIFE = 60.0;
|
||||
var TARGET_LIFE = 60.0;
|
||||
var INITIAL_GAP = 0.5;
|
||||
var dimensions;
|
||||
var dimensions;
|
||||
|
||||
for (x = 0; x < size; x++) {
|
||||
for (y = 0; y < size; y++) {
|
||||
for (z = 0; z < size; z++) {
|
||||
|
||||
dimensions = { x: separation/2.0, y: separation, z: separation/2.0 };
|
||||
dimensions = {
|
||||
x: separation / 2.0,
|
||||
y: separation,
|
||||
z: separation / 2.0
|
||||
};
|
||||
|
||||
Entities.addEntity(
|
||||
{ type: "Box",
|
||||
position: { x: pos.x - (separation * size / 2.0) + x * separation,
|
||||
y: pos.y + y * (separation + INITIAL_GAP),
|
||||
z: pos.z - (separation * size / 2.0) + z * separation },
|
||||
dimensions: dimensions,
|
||||
color: { red: Math.random() * 255, green: Math.random() * 255, blue: Math.random() * 255 },
|
||||
velocity: { x: 0, y: 0.05, z: 0 },
|
||||
gravity: { x: 0, y: gravity, z: 0 },
|
||||
lifetime: TARGET_LIFE,
|
||||
damping: 0.1,
|
||||
density: 100.0,
|
||||
collisionsWillMove: true });
|
||||
Entities.addEntity({
|
||||
type: "Box",
|
||||
position: {
|
||||
x: pos.x - (separation * size / 2.0) + x * separation,
|
||||
y: pos.y + y * (separation + INITIAL_GAP),
|
||||
z: pos.z - (separation * size / 2.0) + z * separation
|
||||
},
|
||||
dimensions: dimensions,
|
||||
color: {
|
||||
red: Math.random() * 255,
|
||||
green: Math.random() * 255,
|
||||
blue: Math.random() * 255
|
||||
},
|
||||
velocity: {
|
||||
x: 0,
|
||||
y: 0.05,
|
||||
z: 0
|
||||
},
|
||||
gravity: {
|
||||
x: 0,
|
||||
y: gravity,
|
||||
z: 0
|
||||
},
|
||||
lifetime: TARGET_LIFE,
|
||||
damping: 0.1,
|
||||
density: 100.0,
|
||||
collisionsWillMove: true
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -328,9 +410,21 @@ function makePlatform(gravity, scale, size) {
|
|||
// Make a floor for this stuff to fall onto
|
||||
Entities.addEntity({
|
||||
type: "Box",
|
||||
position: { x: pos.x, y: pos.y - separation / 2.0, z: pos.z },
|
||||
dimensions: { x: 2.0 * separation * size, y: separation / 2.0, z: 2.0 * separation * size },
|
||||
color: { red: 100, green: 100, blue: 100 },
|
||||
position: {
|
||||
x: pos.x,
|
||||
y: pos.y - separation / 2.0,
|
||||
z: pos.z
|
||||
},
|
||||
dimensions: {
|
||||
x: 2.0 * separation * size,
|
||||
y: separation / 2.0,
|
||||
z: 2.0 * separation * size
|
||||
},
|
||||
color: {
|
||||
red: 100,
|
||||
green: 100,
|
||||
blue: 100
|
||||
},
|
||||
lifetime: TARGET_LIFE
|
||||
});
|
||||
|
||||
|
@ -340,153 +434,79 @@ function keyPressEvent(event) {
|
|||
// if our tools are off, then don't do anything
|
||||
if (event.text == "t") {
|
||||
var time = MIN_THROWER_DELAY + Math.random() * MAX_THROWER_DELAY;
|
||||
Script.setTimeout(shootTarget, time);
|
||||
Script.setTimeout(shootTarget, time);
|
||||
} else if ((event.text == ".") || (event.text == "SPACE")) {
|
||||
shootFromMouse(false);
|
||||
} else if (event.text == ",") {
|
||||
shootFromMouse(true);
|
||||
} else if (event.text == "r") {
|
||||
playLoadSound();
|
||||
} else if (event.text == "s") {
|
||||
// Hit this key to dump a posture from hydra to log
|
||||
Quat.print("arm = ", MyAvatar.getJointRotation("LeftArm"));
|
||||
Quat.print("forearm = ", MyAvatar.getJointRotation("LeftForeArm"));
|
||||
Quat.print("hand = ", MyAvatar.getJointRotation("LeftHand"));
|
||||
}
|
||||
}
|
||||
|
||||
function playLoadSound() {
|
||||
audioOptions.position = Vec3.sum(Camera.getPosition(), Quat.getFront(Camera.getOrientation()));
|
||||
audioOptions.position = MyAvatar.leftHandPose.translation;
|
||||
Audio.playSound(loadSound, audioOptions);
|
||||
// Raise arm to firing posture
|
||||
takeFiringPose();
|
||||
}
|
||||
|
||||
function clearPose() {
|
||||
MyAvatar.clearJointData("LeftForeArm");
|
||||
MyAvatar.clearJointData("LeftArm");
|
||||
MyAvatar.clearJointData("LeftHand");
|
||||
}
|
||||
|
||||
function deleteBulletAndTarget() {
|
||||
Entities.deleteEntity(bulletID);
|
||||
Entities.deleteEntity(targetID);
|
||||
bulletID = false;
|
||||
targetID = false;
|
||||
bulletID = false;
|
||||
targetID = false;
|
||||
}
|
||||
|
||||
function takeFiringPose() {
|
||||
clearPose();
|
||||
if (Controller.getNumberOfSpatialControls() == 0) {
|
||||
MyAvatar.setJointData("LeftForeArm", {x: -0.251919, y: -0.0415449, z: 0.499487, w: 0.827843});
|
||||
MyAvatar.setJointData("LeftArm", { x: 0.470196, y: -0.132559, z: 0.494033, w: 0.719219});
|
||||
MyAvatar.setJointData("LeftHand", { x: -0.0104815, y: -0.110551, z: -0.352111, w: 0.929333});
|
||||
}
|
||||
}
|
||||
|
||||
MyAvatar.attach(gunModel, "RightHand", {x:0.04, y: 0.22, z: 0.02}, Quat.fromPitchYawRollDegrees(-172, -85, 79), 0.40);
|
||||
MyAvatar.attach(gunModel, "LeftHand", {x:-0.04, y: 0.22, z: 0.02}, Quat.fromPitchYawRollDegrees(-172, 85, -79), 0.40);
|
||||
|
||||
// Give a bit of time to load before playing sound
|
||||
Script.setTimeout(playLoadSound, 2000);
|
||||
|
||||
function update(deltaTime) {
|
||||
if (activeControllers == 0) {
|
||||
if (Controller.getNumberOfSpatialControls() > 0) {
|
||||
activeControllers = Controller.getNumberOfSpatialControls();
|
||||
clearPose();
|
||||
}
|
||||
}
|
||||
// FIXME we should also expose MyAvatar.handPoses[2], MyAvatar.tipPoses[2]
|
||||
var tipPoses = [ MyAvatar.leftHandTipPose, MyAvatar.rightHandTipPose ];
|
||||
|
||||
var KICKBACK_DECAY_RATE = 0.125;
|
||||
if (elbowKickAngle > 0.0) {
|
||||
if (elbowKickAngle > 0.5) {
|
||||
var newAngle = elbowKickAngle * KICKBACK_DECAY_RATE;
|
||||
elbowKickAngle -= newAngle;
|
||||
var armRotation = MyAvatar.getJointRotation("LeftForeArm");
|
||||
armRotation = Quat.multiply(armRotation, Quat.fromPitchYawRollDegrees(0.0, 0.0, -newAngle));
|
||||
MyAvatar.setJointData("LeftForeArm", armRotation);
|
||||
} else {
|
||||
MyAvatar.setJointData("LeftForeArm", rotationBeforeKickback);
|
||||
if (Controller.getNumberOfSpatialControls() > 0) {
|
||||
clearPose();
|
||||
}
|
||||
elbowKickAngle = 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// check for trigger press
|
||||
|
||||
var numberOfTriggers = 2;
|
||||
var controllersPerTrigger = 2;
|
||||
|
||||
if (numberOfTriggers == 2 && controllersPerTrigger == 2) {
|
||||
for (var t = 0; t < 2; t++) {
|
||||
var shootABullet = false;
|
||||
var triggerValue = Controller.getTriggerValue(t);
|
||||
if (triggerPulled[t]) {
|
||||
// must release to at least 0.1
|
||||
if (triggerValue < 0.1) {
|
||||
triggerPulled[t] = false; // unpulled
|
||||
}
|
||||
} else {
|
||||
// must pull to at least
|
||||
if (triggerValue > 0.5) {
|
||||
triggerPulled[t] = true; // pulled
|
||||
shootABullet = true;
|
||||
}
|
||||
}
|
||||
var palmController = t * controllersPerTrigger;
|
||||
var palmPosition = Controller.getSpatialControlPosition(palmController);
|
||||
var fingerTipController = palmController + 1;
|
||||
var fingerTipPosition = Controller.getSpatialControlPosition(fingerTipController);
|
||||
var laserTip = Vec3.sum(Vec3.multiply(100.0, Vec3.subtract(fingerTipPosition, palmPosition)), palmPosition);
|
||||
|
||||
// Update Lasers
|
||||
Overlays.editOverlay(pointer[t], {
|
||||
start: palmPosition,
|
||||
end: laserTip,
|
||||
alpha: 1
|
||||
for (var side = 0; side < 2; side++) {
|
||||
// First check if the controller is valid
|
||||
var controllerPose = Controller.getPoseValue(POSE_CONTROLS[side]);
|
||||
validPoses[side] = controllerPose.valid;
|
||||
if (!controllerPose.valid) {
|
||||
Overlays.editOverlay(pointer[side], {
|
||||
visible: false
|
||||
});
|
||||
|
||||
if (shootABullet) {
|
||||
|
||||
var palmToFingerTipVector =
|
||||
{ x: (fingerTipPosition.x - palmPosition.x),
|
||||
y: (fingerTipPosition.y - palmPosition.y),
|
||||
z: (fingerTipPosition.z - palmPosition.z) };
|
||||
|
||||
// just off the front of the finger tip
|
||||
var position = { x: fingerTipPosition.x + palmToFingerTipVector.x/2,
|
||||
y: fingerTipPosition.y + palmToFingerTipVector.y/2,
|
||||
z: fingerTipPosition.z + palmToFingerTipVector.z/2};
|
||||
|
||||
var velocity = Vec3.multiply(BULLET_VELOCITY, Vec3.normalize(palmToFingerTipVector));
|
||||
|
||||
shootBullet(position, velocity, false);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
// Need to adjust the laser
|
||||
var tipPose = tipPoses[side];
|
||||
var handRotation = tipPoses[side].rotation;
|
||||
var barrelOffset = Vec3.multiplyQbyV(handRotation, BARREL_OFFSETS[side]);
|
||||
barrelTips[side] = Vec3.sum(tipPose.translation, barrelOffset);
|
||||
barrelVectors[side] = Vec3.multiplyQbyV(handRotation, {
|
||||
x: 0,
|
||||
y: 1,
|
||||
z: 0
|
||||
});
|
||||
|
||||
var laserTip = Vec3.sum(Vec3.multiply(100.0, barrelVectors[side]), barrelTips[side]);
|
||||
// Update Lasers
|
||||
Overlays.editOverlay(pointer[side], {
|
||||
start: barrelTips[side],
|
||||
end: laserTip,
|
||||
alpha: 1,
|
||||
visible: true
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function shootFromMouse(grenade) {
|
||||
var DISTANCE_FROM_CAMERA = 1.0;
|
||||
var camera = Camera.getPosition();
|
||||
var forwardVector = Quat.getFront(Camera.getOrientation());
|
||||
var newPosition = Vec3.sum(camera, Vec3.multiply(forwardVector, DISTANCE_FROM_CAMERA));
|
||||
var velocity = Vec3.multiply(forwardVector, BULLET_VELOCITY);
|
||||
shootBullet(newPosition, velocity, grenade);
|
||||
}
|
||||
|
||||
function mouseReleaseEvent(event) {
|
||||
// position
|
||||
isMouseDown = false;
|
||||
function triggerChanged(side, value) {
|
||||
var pressed = (value != 0);
|
||||
if (pressed) {
|
||||
var position = barrelTips[side];
|
||||
var velocity = Vec3.multiply(BULLET_VELOCITY, Vec3.normalize(barrelVectors[side]));
|
||||
shootBullet(position, velocity, false);
|
||||
}
|
||||
}
|
||||
|
||||
function mousePressEvent(event) {
|
||||
var clickedText = false;
|
||||
var clickedOverlay = Overlays.getOverlayAtPoint({x: event.x, y: event.y});
|
||||
var clickedOverlay = Overlays.getOverlayAtPoint({
|
||||
x: event.x,
|
||||
y: event.y
|
||||
});
|
||||
if (clickedOverlay == offButton) {
|
||||
Script.stop();
|
||||
} else if (clickedOverlay == platformButton) {
|
||||
|
@ -494,25 +514,37 @@ function mousePressEvent(event) {
|
|||
makePlatform(-9.8, 1.0, platformSize);
|
||||
} else if (clickedOverlay == gridButton) {
|
||||
makeGrid("Box", 1.0, 3);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function scriptEnding() {
|
||||
Overlays.deleteOverlay(reticle);
|
||||
mapping.disable();
|
||||
toolBar.cleanup();
|
||||
Overlays.deleteOverlay(pointer[0]);
|
||||
Overlays.deleteOverlay(pointer[1]);
|
||||
for (var i = 0; i < pointer.length; ++i) {
|
||||
Overlays.deleteOverlay(pointer[i]);
|
||||
}
|
||||
Overlays.deleteOverlay(text);
|
||||
MyAvatar.detachOne(gunModel);
|
||||
MyAvatar.detachOne(gunModel);
|
||||
MyAvatar.detachOne(GUN_MODEL);
|
||||
MyAvatar.detachOne(GUN_MODEL);
|
||||
clearPose();
|
||||
}
|
||||
|
||||
MyAvatar.attach(GUN_MODEL, "LeftHand", GUN_OFFSETS[0], GUN_ORIENTATIONS[0], 0.40);
|
||||
MyAvatar.attach(GUN_MODEL, "RightHand", GUN_OFFSETS[1], GUN_ORIENTATIONS[1], 0.40);
|
||||
|
||||
// Give a bit of time to load before playing sound
|
||||
Script.setTimeout(playLoadSound, 2000);
|
||||
|
||||
mapping.from(Controller.Standard.LT).hysteresis(0.1, 0.5).to(function(value) {
|
||||
triggerChanged(0, value);
|
||||
});
|
||||
|
||||
mapping.from(Controller.Standard.RT).hysteresis(0.1, 0.5).to(function(value) {
|
||||
triggerChanged(1, value);
|
||||
});
|
||||
mapping.enable();
|
||||
|
||||
Script.scriptEnding.connect(scriptEnding);
|
||||
Script.update.connect(update);
|
||||
Controller.mouseReleaseEvent.connect(mouseReleaseEvent);
|
||||
Controller.mousePressEvent.connect(mousePressEvent);
|
||||
Controller.keyPressEvent.connect(keyPressEvent);
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -1,303 +0,0 @@
|
|||
//
|
||||
// hydraMove.js
|
||||
// examples
|
||||
//
|
||||
// Created by Brad Hefta-Gaub on February 10, 2014
|
||||
// Updated by Philip Rosedale on September 8, 2014
|
||||
//
|
||||
// Copyright 2014 High Fidelity, Inc.
|
||||
//
|
||||
// This is an example script that demonstrates use of the Controller and MyAvatar classes to implement
|
||||
// avatar flying through the hydra/controller joysticks
|
||||
//
|
||||
// The joysticks (on hydra) will drive the avatar much like a playstation controller.
|
||||
//
|
||||
// Pressing the '4' or the 'FWD' button and moving/banking the hand will allow you to move and fly.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
var damping = 0.9;
|
||||
var position = { x: MyAvatar.position.x, y: MyAvatar.position.y, z: MyAvatar.position.z };
|
||||
var joysticksCaptured = false;
|
||||
var THRUST_CONTROLLER = 0;
|
||||
var VIEW_CONTROLLER = 1;
|
||||
var INITIAL_THRUST_MULTIPLIER = 1.0;
|
||||
var THRUST_INCREASE_RATE = 1.05;
|
||||
var MAX_THRUST_MULTIPLIER = 75.0;
|
||||
var thrustMultiplier = INITIAL_THRUST_MULTIPLIER;
|
||||
var grabDelta = { x: 0, y: 0, z: 0};
|
||||
var grabStartPosition = { x: 0, y: 0, z: 0};
|
||||
var grabDeltaVelocity = { x: 0, y: 0, z: 0};
|
||||
var grabStartRotation = { x: 0, y: 0, z: 0, w: 1};
|
||||
var grabCurrentRotation = { x: 0, y: 0, z: 0, w: 1};
|
||||
var grabbingWithRightHand = false;
|
||||
var wasGrabbingWithRightHand = false;
|
||||
var grabbingWithLeftHand = false;
|
||||
var wasGrabbingWithLeftHand = false;
|
||||
|
||||
var EPSILON = 0.000001;
|
||||
var velocity = { x: 0, y: 0, z: 0};
|
||||
var THRUST_MAG_UP = 100.0;
|
||||
var THRUST_MAG_DOWN = 100.0;
|
||||
var THRUST_MAG_FWD = 150.0;
|
||||
var THRUST_MAG_BACK = 100.0;
|
||||
var THRUST_MAG_LATERAL = 150.0;
|
||||
var THRUST_JUMP = 120.0;
|
||||
|
||||
var YAW_MAG = 100.0;
|
||||
var PITCH_MAG = 100.0;
|
||||
var THRUST_MAG_HAND_JETS = THRUST_MAG_FWD;
|
||||
var JOYSTICK_YAW_MAG = YAW_MAG;
|
||||
var JOYSTICK_PITCH_MAG = PITCH_MAG * 0.5;
|
||||
|
||||
|
||||
var LEFT_PALM = 0;
|
||||
var LEFT_BUTTON_4 = 4;
|
||||
var LEFT_BUTTON_FWD = 5;
|
||||
var RIGHT_PALM = 2;
|
||||
var RIGHT_BUTTON_4 = 10;
|
||||
var RIGHT_BUTTON_FWD = 11;
|
||||
|
||||
|
||||
|
||||
function printVector(text, v, decimals) {
|
||||
print(text + " " + v.x.toFixed(decimals) + ", " + v.y.toFixed(decimals) + ", " + v.z.toFixed(decimals));
|
||||
}
|
||||
|
||||
var debug = false;
|
||||
var RED_COLOR = { red: 255, green: 0, blue: 0 };
|
||||
var GRAY_COLOR = { red: 25, green: 25, blue: 25 };
|
||||
var defaultPosition = { x: 0, y: 0, z: 0};
|
||||
var RADIUS = 0.05;
|
||||
var greenSphere = -1;
|
||||
var redSphere = -1;
|
||||
|
||||
function createDebugOverlay() {
|
||||
|
||||
if (greenSphere == -1) {
|
||||
greenSphere = Overlays.addOverlay("sphere", {
|
||||
position: defaultPosition,
|
||||
size: RADIUS,
|
||||
color: GRAY_COLOR,
|
||||
alpha: 0.75,
|
||||
visible: true,
|
||||
solid: true,
|
||||
anchor: "MyAvatar"
|
||||
});
|
||||
redSphere = Overlays.addOverlay("sphere", {
|
||||
position: defaultPosition,
|
||||
size: RADIUS,
|
||||
color: RED_COLOR,
|
||||
alpha: 0.5,
|
||||
visible: true,
|
||||
solid: true,
|
||||
anchor: "MyAvatar"
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function destroyDebugOverlay() {
|
||||
if (greenSphere != -1) {
|
||||
Overlays.deleteOverlay(greenSphere);
|
||||
Overlays.deleteOverlay(redSphere);
|
||||
greenSphere = -1;
|
||||
redSphere = -1;
|
||||
}
|
||||
}
|
||||
|
||||
function displayDebug() {
|
||||
if (!(grabbingWithRightHand || grabbingWithLeftHand)) {
|
||||
if (greenSphere != -1) {
|
||||
destroyDebugOverlay();
|
||||
}
|
||||
} else {
|
||||
// update debug indicator
|
||||
if (greenSphere == -1) {
|
||||
createDebugOverlay();
|
||||
}
|
||||
|
||||
var displayOffset = { x:0, y:0.5, z:-0.5 };
|
||||
|
||||
Overlays.editOverlay(greenSphere, { position: Vec3.sum(grabStartPosition, displayOffset) } );
|
||||
Overlays.editOverlay(redSphere, { position: Vec3.sum(Vec3.sum(grabStartPosition, grabDelta), displayOffset), size: RADIUS + (0.25 * Vec3.length(grabDelta)) } );
|
||||
}
|
||||
}
|
||||
|
||||
function getJoystickPosition(palm) {
|
||||
// returns CONTROLLER_ID position in avatar local frame
|
||||
var invRotation = Quat.inverse(MyAvatar.orientation);
|
||||
var palmWorld = Controller.getSpatialControlPosition(palm);
|
||||
var palmRelative = Vec3.subtract(palmWorld, MyAvatar.position);
|
||||
var palmLocal = Vec3.multiplyQbyV(invRotation, palmRelative);
|
||||
return palmLocal;
|
||||
}
|
||||
|
||||
// Used by handleGrabBehavior() for managing the grab position changes
|
||||
function getAndResetGrabDelta() {
|
||||
var HAND_GRAB_SCALE_DISTANCE = 2.0;
|
||||
var delta = Vec3.multiply(grabDelta, (MyAvatar.scale * HAND_GRAB_SCALE_DISTANCE));
|
||||
grabDelta = { x: 0, y: 0, z: 0};
|
||||
var avatarRotation = MyAvatar.orientation;
|
||||
var result = Vec3.multiplyQbyV(avatarRotation, Vec3.multiply(delta, -1));
|
||||
return result;
|
||||
}
|
||||
|
||||
function getGrabRotation() {
|
||||
var quatDiff = Quat.multiply(grabCurrentRotation, Quat.inverse(grabStartRotation));
|
||||
return quatDiff;
|
||||
}
|
||||
|
||||
// When move button is pressed, process results
|
||||
function handleGrabBehavior(deltaTime) {
|
||||
// check for and handle grab behaviors
|
||||
grabbingWithRightHand = Controller.isButtonPressed(RIGHT_BUTTON_4);
|
||||
grabbingWithLeftHand = Controller.isButtonPressed(LEFT_BUTTON_4);
|
||||
stoppedGrabbingWithLeftHand = false;
|
||||
stoppedGrabbingWithRightHand = false;
|
||||
|
||||
if (grabbingWithRightHand && !wasGrabbingWithRightHand) {
|
||||
// Just starting grab, capture starting rotation
|
||||
grabStartRotation = Controller.getSpatialControlRawRotation(RIGHT_PALM);
|
||||
grabStartPosition = getJoystickPosition(RIGHT_PALM);
|
||||
if (debug) printVector("start position", grabStartPosition, 3);
|
||||
}
|
||||
if (grabbingWithRightHand) {
|
||||
grabDelta = Vec3.subtract(getJoystickPosition(RIGHT_PALM), grabStartPosition);
|
||||
grabCurrentRotation = Controller.getSpatialControlRawRotation(RIGHT_PALM);
|
||||
}
|
||||
if (!grabbingWithRightHand && wasGrabbingWithRightHand) {
|
||||
// Just ending grab, capture velocity
|
||||
grabDeltaVelocity = Controller.getSpatialControlVelocity(RIGHT_PALM);
|
||||
stoppedGrabbingWithRightHand = true;
|
||||
}
|
||||
|
||||
if (grabbingWithLeftHand && !wasGrabbingWithLeftHand) {
|
||||
// Just starting grab, capture starting rotation
|
||||
grabStartRotation = Controller.getSpatialControlRawRotation(LEFT_PALM);
|
||||
grabStartPosition = getJoystickPosition(LEFT_PALM);
|
||||
if (debug) printVector("start position", grabStartPosition, 3);
|
||||
}
|
||||
|
||||
if (grabbingWithLeftHand) {
|
||||
grabDelta = Vec3.subtract(getJoystickPosition(LEFT_PALM), grabStartPosition);
|
||||
grabCurrentRotation = Controller.getSpatialControlRawRotation(LEFT_PALM);
|
||||
}
|
||||
if (!grabbingWithLeftHand && wasGrabbingWithLeftHand) {
|
||||
// Just ending grab, capture velocity
|
||||
grabDeltaVelocity = Controller.getSpatialControlVelocity(LEFT_PALM);
|
||||
stoppedGrabbingWithLeftHand = true;
|
||||
}
|
||||
|
||||
grabbing = grabbingWithRightHand || grabbingWithLeftHand;
|
||||
stoppedGrabbing = stoppedGrabbingWithRightHand || stoppedGrabbingWithLeftHand;
|
||||
|
||||
if (grabbing) {
|
||||
|
||||
var headOrientation = MyAvatar.headOrientation;
|
||||
var front = Quat.getFront(headOrientation);
|
||||
var right = Quat.getRight(headOrientation);
|
||||
var up = Quat.getUp(headOrientation);
|
||||
|
||||
if (debug) {
|
||||
printVector("grabDelta: ", grabDelta, 3);
|
||||
}
|
||||
|
||||
var thrust = Vec3.multiply(grabDelta, Math.abs(Vec3.length(grabDelta)));
|
||||
|
||||
var THRUST_GRAB_SCALING = 100000.0;
|
||||
|
||||
var thrustFront = Vec3.multiply(front, MyAvatar.scale * -thrust.z * THRUST_GRAB_SCALING * deltaTime);
|
||||
MyAvatar.addThrust(thrustFront);
|
||||
var thrustRight = Vec3.multiply(right, MyAvatar.scale * thrust.x * THRUST_GRAB_SCALING * deltaTime);
|
||||
MyAvatar.addThrust(thrustRight);
|
||||
var thrustUp = Vec3.multiply(up, MyAvatar.scale * thrust.y * THRUST_GRAB_SCALING * deltaTime);
|
||||
MyAvatar.addThrust(thrustUp);
|
||||
|
||||
// add some rotation...
|
||||
var deltaRotation = getGrabRotation();
|
||||
var PITCH_SCALING = 2.5;
|
||||
var PITCH_DEAD_ZONE = 2.0;
|
||||
var YAW_SCALING = 2.5;
|
||||
var ROLL_SCALING = 2.0;
|
||||
|
||||
var euler = Quat.safeEulerAngles(deltaRotation);
|
||||
|
||||
// Adjust body yaw by roll from controller
|
||||
var orientation = Quat.multiply(Quat.angleAxis(((euler.y * YAW_SCALING) +
|
||||
(euler.z * ROLL_SCALING)) * deltaTime, {x:0, y: 1, z:0}), MyAvatar.orientation);
|
||||
MyAvatar.orientation = orientation;
|
||||
|
||||
// Adjust head pitch from controller
|
||||
var pitch = 0.0;
|
||||
if (Math.abs(euler.x) > PITCH_DEAD_ZONE) {
|
||||
pitch = (euler.x < 0.0) ? (euler.x + PITCH_DEAD_ZONE) : (euler.x - PITCH_DEAD_ZONE);
|
||||
}
|
||||
MyAvatar.headPitch = MyAvatar.headPitch + (pitch * PITCH_SCALING * deltaTime);
|
||||
|
||||
// TODO: Add some camera roll proportional to the rate of turn (so it feels like an airplane or roller coaster)
|
||||
|
||||
}
|
||||
|
||||
wasGrabbingWithRightHand = grabbingWithRightHand;
|
||||
wasGrabbingWithLeftHand = grabbingWithLeftHand;
|
||||
}
|
||||
|
||||
// Update for joysticks and move button
|
||||
var THRUST_DEAD_ZONE = 0.1;
|
||||
var ROTATE_DEAD_ZONE = 0.1;
|
||||
function flyWithHydra(deltaTime) {
|
||||
var thrustJoystickPosition = Controller.getJoystickPosition(THRUST_CONTROLLER);
|
||||
|
||||
if (Math.abs(thrustJoystickPosition.x) > THRUST_DEAD_ZONE || Math.abs(thrustJoystickPosition.y) > THRUST_DEAD_ZONE) {
|
||||
if (thrustMultiplier < MAX_THRUST_MULTIPLIER) {
|
||||
thrustMultiplier *= 1 + (deltaTime * THRUST_INCREASE_RATE);
|
||||
}
|
||||
var headOrientation = MyAvatar.headOrientation;
|
||||
|
||||
var front = Quat.getFront(headOrientation);
|
||||
var right = Quat.getRight(headOrientation);
|
||||
var up = Quat.getUp(headOrientation);
|
||||
|
||||
var thrustFront = Vec3.multiply(front, MyAvatar.scale * THRUST_MAG_HAND_JETS *
|
||||
thrustJoystickPosition.y * thrustMultiplier * deltaTime);
|
||||
MyAvatar.addThrust(thrustFront);
|
||||
var thrustRight = Vec3.multiply(right, MyAvatar.scale * THRUST_MAG_HAND_JETS *
|
||||
thrustJoystickPosition.x * thrustMultiplier * deltaTime);
|
||||
MyAvatar.addThrust(thrustRight);
|
||||
} else {
|
||||
thrustMultiplier = INITIAL_THRUST_MULTIPLIER;
|
||||
}
|
||||
|
||||
// View Controller
|
||||
var viewJoystickPosition = Controller.getJoystickPosition(VIEW_CONTROLLER);
|
||||
if (Math.abs(viewJoystickPosition.x) > ROTATE_DEAD_ZONE || Math.abs(viewJoystickPosition.y) > ROTATE_DEAD_ZONE) {
|
||||
|
||||
// change the body yaw based on our x controller
|
||||
var orientation = MyAvatar.orientation;
|
||||
var deltaOrientation = Quat.fromPitchYawRollDegrees(0, (-1 * viewJoystickPosition.x * JOYSTICK_YAW_MAG * deltaTime), 0);
|
||||
MyAvatar.orientation = Quat.multiply(orientation, deltaOrientation);
|
||||
|
||||
// change the headPitch based on our x controller
|
||||
var newPitch = MyAvatar.headPitch + (viewJoystickPosition.y * JOYSTICK_PITCH_MAG * deltaTime);
|
||||
MyAvatar.headPitch = newPitch;
|
||||
}
|
||||
handleGrabBehavior(deltaTime);
|
||||
displayDebug();
|
||||
|
||||
}
|
||||
|
||||
Script.update.connect(flyWithHydra);
|
||||
Controller.captureJoystick(THRUST_CONTROLLER);
|
||||
Controller.captureJoystick(VIEW_CONTROLLER);
|
||||
|
||||
// Map keyPress and mouse move events to our callbacks
|
||||
function scriptEnding() {
|
||||
// re-enabled the standard application for touch events
|
||||
Controller.releaseJoystick(THRUST_CONTROLLER);
|
||||
Controller.releaseJoystick(VIEW_CONTROLLER);
|
||||
}
|
||||
Script.scriptEnding.connect(scriptEnding);
|
||||
|
||||
|
|
@ -20,10 +20,11 @@ var BALL_SIZE = 0.08;
|
|||
var PADDLE_SIZE = 0.20;
|
||||
var PADDLE_THICKNESS = 0.06;
|
||||
var PADDLE_COLOR = { red: 184, green: 134, blue: 11 };
|
||||
var BALL_COLOR = { red: 255, green: 0, blue: 0 };
|
||||
var BALL_COLOR = { red: 0, green: 255, blue: 0 };
|
||||
var LINE_COLOR = { red: 255, green: 255, blue: 0 };
|
||||
var PADDLE_BOX_OFFSET = { x: 0.05, y: 0.0, z: 0.0 };
|
||||
|
||||
//probably we need to fix these initial values (offsets and orientation)
|
||||
var HOLD_POSITION_LEFT_OFFSET = { x: -0.15, y: 0.05, z: -0.05 };
|
||||
var HOLD_POSITION_RIGHT_OFFSET = { x: -0.15, y: 0.05, z: 0.05 };
|
||||
var PADDLE_ORIENTATION = Quat.fromPitchYawRollDegrees(0,0,0);
|
||||
|
@ -32,18 +33,7 @@ var SPRING_FORCE = 15.0;
|
|||
var lastSoundTime = 0;
|
||||
var gameOn = false;
|
||||
var leftHanded = true;
|
||||
var controllerID;
|
||||
|
||||
|
||||
function setControllerID() {
|
||||
if (leftHanded) {
|
||||
controllerID = 1;
|
||||
} else {
|
||||
controllerID = 3;
|
||||
}
|
||||
}
|
||||
|
||||
setControllerID();
|
||||
Menu.addMenu("PaddleBall");
|
||||
Menu.addMenuItem({ menuName: "PaddleBall", menuItemName: "Left-Handed", isCheckable: true, isChecked: true });
|
||||
|
||||
|
@ -63,7 +53,7 @@ var ball, paddle, paddleModel, line;
|
|||
function createEntities() {
|
||||
ball = Entities.addEntity(
|
||||
{ type: "Sphere",
|
||||
position: Controller.getSpatialControlPosition(controllerID),
|
||||
position: leftHanded ? MyAvatar.leftHandPose.translation : MyAvatar.rightHandPose.translation,
|
||||
dimensions: { x: BALL_SIZE, y: BALL_SIZE, z: BALL_SIZE },
|
||||
color: BALL_COLOR,
|
||||
gravity: { x: 0, y: GRAVITY, z: 0 },
|
||||
|
@ -73,28 +63,28 @@ function createEntities() {
|
|||
|
||||
paddle = Entities.addEntity(
|
||||
{ type: "Box",
|
||||
position: Controller.getSpatialControlPosition(controllerID),
|
||||
position: leftHanded ? MyAvatar.leftHandPose.translation : MyAvatar.rightHandPose.translation,
|
||||
dimensions: { x: PADDLE_SIZE, y: PADDLE_THICKNESS, z: PADDLE_SIZE * 0.80 },
|
||||
color: PADDLE_COLOR,
|
||||
gravity: { x: 0, y: 0, z: 0 },
|
||||
ignoreCollisions: false,
|
||||
damping: 0.10,
|
||||
visible: false,
|
||||
rotation: Quat.multiply(MyAvatar.orientation, Controller.getSpatialControlRawRotation(controllerID)),
|
||||
collisionsWillMove: false });
|
||||
rotation : leftHanded ? MyAvatar.leftHandPose.rotation : MyAvatar.rightHandPose.rotation,
|
||||
collisionsWillMove: false });
|
||||
|
||||
modelURL = "http://public.highfidelity.io/models/attachments/pong_paddle.fbx";
|
||||
paddleModel = Entities.addEntity(
|
||||
{ type: "Model",
|
||||
position: Vec3.sum(Controller.getSpatialControlPosition(controllerID), PADDLE_BOX_OFFSET),
|
||||
position: Vec3.sum( leftHanded ? MyAvatar.leftHandPose.translation : MyAvatar.rightHandPose.translation, PADDLE_BOX_OFFSET),
|
||||
dimensions: { x: PADDLE_SIZE * 1.5, y: PADDLE_THICKNESS, z: PADDLE_SIZE * 1.25 },
|
||||
color: PADDLE_COLOR,
|
||||
gravity: { x: 0, y: 0, z: 0 },
|
||||
ignoreCollisions: true,
|
||||
modelURL: modelURL,
|
||||
damping: 0.10,
|
||||
rotation: Quat.multiply(MyAvatar.orientation, Controller.getSpatialControlRawRotation(controllerID)),
|
||||
collisionsWillMove: false });
|
||||
rotation : leftHanded ? MyAvatar.leftHandPose.rotation : MyAvatar.rightHandPose.rotation,
|
||||
collisionsWillMove: false });
|
||||
|
||||
line = Overlays.addOverlay("line3d", {
|
||||
start: { x: 0, y: 0, z: 0 },
|
||||
|
@ -118,7 +108,7 @@ function deleteEntities() {
|
|||
}
|
||||
|
||||
function update(deltaTime) {
|
||||
var palmPosition = Controller.getSpatialControlPosition(controllerID);
|
||||
var palmPosition = leftHanded ? MyAvatar.leftHandPose.translation : MyAvatar.rightHandPose.translation;
|
||||
var controllerActive = (Vec3.length(palmPosition) > 0);
|
||||
|
||||
if (!gameOn && controllerActive) {
|
||||
|
@ -133,8 +123,8 @@ function update(deltaTime) {
|
|||
}
|
||||
|
||||
var paddleOrientation = leftHanded ? PADDLE_ORIENTATION : Quat.multiply(PADDLE_ORIENTATION, Quat.fromPitchYawRollDegrees(0, 180, 0));
|
||||
var paddleWorldOrientation = Quat.multiply(Quat.multiply(MyAvatar.orientation, Controller.getSpatialControlRawRotation(controllerID)), paddleOrientation);
|
||||
var holdPosition = Vec3.sum(leftHanded ? MyAvatar.getLeftPalmPosition() : MyAvatar.getRightPalmPosition(),
|
||||
var paddleWorldOrientation = Quat.multiply(leftHanded ? MyAvatar.leftHandPose.rotation : MyAvatar.rightHandPose.rotation, paddleOrientation);
|
||||
var holdPosition = Vec3.sum(leftHanded ? MyAvatar.leftHandPose.translation : MyAvatar.rightHandPose.translation,
|
||||
Vec3.multiplyQbyV(paddleWorldOrientation, leftHanded ? HOLD_POSITION_LEFT_OFFSET : HOLD_POSITION_RIGHT_OFFSET ));
|
||||
|
||||
var props = Entities.getEntityProperties(ball);
|
||||
|
@ -146,10 +136,10 @@ function update(deltaTime) {
|
|||
Entities.editEntity(ball, { velocity: ballVelocity });
|
||||
Overlays.editOverlay(line, { start: props.position, end: holdPosition });
|
||||
Entities.editEntity(paddle, { position: holdPosition,
|
||||
velocity: Controller.getSpatialControlVelocity(controllerID),
|
||||
velocity: leftHanded ? MyAvatar.leftHandPose.velocity : MyAvatar.rightHandPose.velocity,
|
||||
rotation: paddleWorldOrientation });
|
||||
Entities.editEntity(paddleModel, { position: Vec3.sum(holdPosition, Vec3.multiplyQbyV(paddleWorldOrientation, PADDLE_BOX_OFFSET)),
|
||||
velocity: Controller.getSpatialControlVelocity(controllerID),
|
||||
velocity: leftHanded ? MyAvatar.leftHandPose.velocity : MyAvatar.rightHandPose.velocity,
|
||||
rotation: paddleWorldOrientation });
|
||||
|
||||
}
|
||||
|
@ -182,7 +172,6 @@ function menuItemEvent(menuItem) {
|
|||
leftHanded = Menu.isOptionChecked("Left-Handed");
|
||||
}
|
||||
if ((leftHanded != oldHanded) && gameOn) {
|
||||
setControllerID();
|
||||
deleteEntities();
|
||||
createEntities();
|
||||
}
|
||||
|
|
|
@ -19,14 +19,7 @@ HIFI_PUBLIC_BUCKET = "http://s3.amazonaws.com/hifi-public/";
|
|||
|
||||
// maybe we should make these constants...
|
||||
var LEFT_PALM = 0;
|
||||
var LEFT_TIP = 1;
|
||||
var LEFT_BUTTON_FWD = 5;
|
||||
var LEFT_BUTTON_3 = 3;
|
||||
|
||||
var RIGHT_PALM = 2;
|
||||
var RIGHT_TIP = 3;
|
||||
var RIGHT_BUTTON_FWD = 11;
|
||||
var RIGHT_BUTTON_3 = 9;
|
||||
|
||||
var BALL_RADIUS = 0.08;
|
||||
var GRAVITY_STRENGTH = 3.0;
|
||||
|
@ -69,9 +62,6 @@ function getBallHoldPosition(whichSide) {
|
|||
}
|
||||
|
||||
function checkControllerSide(whichSide) {
|
||||
var BUTTON_FWD;
|
||||
var BUTTON_3;
|
||||
var TRIGGER;
|
||||
var palmPosition;
|
||||
var palmRotation;
|
||||
var ballAlreadyInHand;
|
||||
|
@ -79,35 +69,35 @@ function checkControllerSide(whichSide) {
|
|||
var linearVelocity;
|
||||
var angularVelocity;
|
||||
var AVERAGE_FACTOR = 0.33;
|
||||
|
||||
var grabButtonPressed;
|
||||
|
||||
if (whichSide == LEFT_PALM) {
|
||||
BUTTON_FWD = LEFT_BUTTON_FWD;
|
||||
BUTTON_3 = LEFT_BUTTON_3;
|
||||
TRIGGER = 0;
|
||||
palmPosition = Controller.getSpatialControlPosition(LEFT_PALM);
|
||||
palmRotation = Quat.multiply(MyAvatar.orientation, Controller.getSpatialControlRawRotation(LEFT_PALM));
|
||||
palmPosition = MyAvatar.leftHandPose.translation;
|
||||
palmRotation = MyAvatar.leftHandPose.rotation;
|
||||
ballAlreadyInHand = leftBallAlreadyInHand;
|
||||
handMessage = "LEFT";
|
||||
averageLinearVelocity[0] = Vec3.sum(Vec3.multiply(AVERAGE_FACTOR, Controller.getSpatialControlVelocity(LEFT_TIP)),
|
||||
averageLinearVelocity[0] = Vec3.sum(Vec3.multiply(AVERAGE_FACTOR, MyAvatar.leftHandTipPose.velocity),
|
||||
Vec3.multiply(1.0 - AVERAGE_FACTOR, averageLinearVelocity[0]));
|
||||
|
||||
linearVelocity = averageLinearVelocity[0];
|
||||
angularVelocity = Vec3.multiplyQbyV(MyAvatar.orientation, Controller.getSpatialControlRawAngularVelocity(LEFT_TIP));
|
||||
angularVelocity = MyAvatar.leftHandTipPose.angularVelocity;
|
||||
grabButtonPressed = (Controller.getValue(Controller.Standard.LT) > 0.5);
|
||||
|
||||
} else {
|
||||
BUTTON_FWD = RIGHT_BUTTON_FWD;
|
||||
BUTTON_3 = RIGHT_BUTTON_3;
|
||||
TRIGGER = 1;
|
||||
palmPosition = Controller.getSpatialControlPosition(RIGHT_PALM);
|
||||
palmRotation = Quat.multiply(MyAvatar.orientation, Controller.getSpatialControlRawRotation(RIGHT_PALM));
|
||||
palmPosition = MyAvatar.rightHandPose.translation;
|
||||
palmRotation = MyAvatar.rightHandPose.rotation;
|
||||
ballAlreadyInHand = rightBallAlreadyInHand;
|
||||
averageLinearVelocity[1] = Vec3.sum(Vec3.multiply(AVERAGE_FACTOR, Controller.getSpatialControlVelocity(RIGHT_TIP)),
|
||||
averageLinearVelocity[1] = Vec3.sum(Vec3.multiply(AVERAGE_FACTOR, MyAvatar.rightHandTipPose.velocity),
|
||||
Vec3.multiply(1.0 - AVERAGE_FACTOR, averageLinearVelocity[1]));
|
||||
|
||||
linearVelocity = averageLinearVelocity[1];
|
||||
angularVelocity = Vec3.multiplyQbyV(MyAvatar.orientation, Controller.getSpatialControlRawAngularVelocity(RIGHT_TIP));
|
||||
angularVelocity = MyAvatar.rightHandTipPose.angularVelocity;
|
||||
handMessage = "RIGHT";
|
||||
grabButtonPressed = (Controller.getValue(Controller.Standard.RT) > 0.5);
|
||||
|
||||
}
|
||||
|
||||
var grabButtonPressed = (Controller.isButtonPressed(BUTTON_FWD) || Controller.isButtonPressed(BUTTON_3) || (Controller.getTriggerValue(TRIGGER) > 0.5));
|
||||
|
||||
|
||||
// If I don't currently have a ball in my hand, then try to catch closest one
|
||||
if (!ballAlreadyInHand && grabButtonPressed) {
|
||||
var closestEntity = Entities.findClosestEntity(palmPosition, targetRadius);
|
||||
|
@ -187,10 +177,8 @@ function checkControllerSide(whichSide) {
|
|||
if (ballAlreadyInHand) {
|
||||
if (whichSide == LEFT_PALM) {
|
||||
handEntity = leftHandEntity;
|
||||
whichTip = LEFT_TIP;
|
||||
} else {
|
||||
handEntity = rightHandEntity;
|
||||
whichTip = RIGHT_TIP;
|
||||
}
|
||||
|
||||
// If holding the ball keep it in the palm
|
||||
|
@ -231,22 +219,10 @@ function checkControllerSide(whichSide) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function checkController(deltaTime) {
|
||||
var numberOfButtons = Controller.getNumberOfButtons();
|
||||
var numberOfTriggers = Controller.getNumberOfTriggers();
|
||||
var numberOfSpatialControls = Controller.getNumberOfSpatialControls();
|
||||
var controllersPerTrigger = numberOfSpatialControls / numberOfTriggers;
|
||||
|
||||
// this is expected for hydras
|
||||
if (!(numberOfButtons==12 && numberOfTriggers == 2 && controllersPerTrigger == 2)) {
|
||||
debugPrint("total buttons = " + numberOfButtons + ", Triggers = " + numberOfTriggers + ", controllers/trigger = " + controllersPerTrigger);
|
||||
return; // bail if no hydra
|
||||
}
|
||||
|
||||
checkControllerSide(LEFT_PALM);
|
||||
checkControllerSide(RIGHT_PALM);
|
||||
checkControllerSide(LEFT_PALM);
|
||||
checkControllerSide(RIGHT_PALM);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -1510,7 +1510,7 @@ PropertiesTool = function(opts) {
|
|||
if (entity.properties.rotation !== undefined) {
|
||||
entity.properties.rotation = Quat.safeEulerAngles(entity.properties.rotation);
|
||||
}
|
||||
if (entity.properties.keyLight.direction !== undefined) {
|
||||
if (entity.properties.keyLight !== undefined && entity.properties.keyLight.direction !== undefined) {
|
||||
entity.properties.keyLight.direction = Vec3.multiply(RADIANS_TO_DEGREES, Vec3.toPolar(entity.properties.keyLight.direction));
|
||||
entity.properties.keyLight.direction.z = 0.0;
|
||||
}
|
||||
|
@ -1541,7 +1541,7 @@ PropertiesTool = function(opts) {
|
|||
var rotation = data.properties.rotation;
|
||||
data.properties.rotation = Quat.fromPitchYawRollDegrees(rotation.x, rotation.y, rotation.z);
|
||||
}
|
||||
if (data.properties.keyLight.direction !== undefined) {
|
||||
if (data.properties.keyLight !== undefined && data.properties.keyLight.direction !== undefined) {
|
||||
data.properties.keyLight.direction = Vec3.fromPolar(
|
||||
data.properties.keyLight.direction.x * DEGREES_TO_RADIANS, data.properties.keyLight.direction.y * DEGREES_TO_RADIANS);
|
||||
}
|
||||
|
|
|
@ -10,25 +10,19 @@
|
|||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
// initialize our triggers
|
||||
var triggerPulled = new Array();
|
||||
var numberOfTriggers = Controller.getNumberOfTriggers();
|
||||
for (t = 0; t < numberOfTriggers; t++) {
|
||||
var NUMBER_OF_TRIGGERS = 2;
|
||||
for (t = 0; t < NUMBER_OF_TRIGGERS; t++) {
|
||||
triggerPulled[t] = false;
|
||||
}
|
||||
|
||||
var triggers = new Array();
|
||||
triggers[0] = Controller.Standard.LT;
|
||||
triggers[1] = Controller.Standard.RT;
|
||||
function checkController(deltaTime) {
|
||||
var numberOfTriggers = Controller.getNumberOfTriggers();
|
||||
var numberOfSpatialControls = Controller.getNumberOfSpatialControls();
|
||||
var controllersPerTrigger = numberOfSpatialControls / numberOfTriggers;
|
||||
var triggerToggled = false;
|
||||
|
||||
// this is expected for hydras
|
||||
if (numberOfTriggers == 2 && controllersPerTrigger == 2) {
|
||||
for (var t = 0; t < numberOfTriggers; t++) {
|
||||
var triggerValue = Controller.getTriggerValue(t);
|
||||
|
||||
for (var t = 0; t < NUMBER_OF_TRIGGERS; t++) {
|
||||
var triggerValue = Controller.getValue(triggers[t]);
|
||||
if (triggerPulled[t]) {
|
||||
// must release to at least 0.1
|
||||
if (triggerValue < 0.1) {
|
||||
|
@ -41,17 +35,14 @@ function checkController(deltaTime) {
|
|||
triggerToggled = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (triggerToggled) {
|
||||
print("a trigger was toggled");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// register the call back so it fires before each data send
|
||||
Script.update.connect(checkController);
|
||||
|
||||
function printKeyEvent(eventName, event) {
|
||||
print(eventName);
|
||||
print(" event.key=" + event.key);
|
||||
|
@ -64,7 +55,6 @@ function printKeyEvent(eventName, event) {
|
|||
}
|
||||
function keyPressEvent(event) {
|
||||
printKeyEvent("keyPressEvent", event);
|
||||
|
||||
if (event.text == "A") {
|
||||
print("the A key was pressed");
|
||||
}
|
||||
|
@ -72,10 +62,8 @@ function keyPressEvent(event) {
|
|||
print("the <space> key was pressed");
|
||||
}
|
||||
}
|
||||
|
||||
function keyReleaseEvent(event) {
|
||||
printKeyEvent("keyReleaseEvent", event);
|
||||
|
||||
if (event.text == "A") {
|
||||
print("the A key was released");
|
||||
}
|
||||
|
@ -83,11 +71,9 @@ function keyReleaseEvent(event) {
|
|||
print("the <space> key was pressed");
|
||||
}
|
||||
}
|
||||
|
||||
// Map keyPress and mouse move events to our callbacks
|
||||
Controller.keyPressEvent.connect(keyPressEvent);
|
||||
Controller.keyReleaseEvent.connect(keyReleaseEvent);
|
||||
|
||||
// prevent the A key from going through to the application
|
||||
Controller.captureKeyEvents({ text: "A" });
|
||||
Controller.captureKeyEvents({ key: "A".charCodeAt(0) }); // same as above, just another example of how to capture the key
|
||||
|
@ -95,8 +81,6 @@ Controller.captureKeyEvents({ text: " " });
|
|||
Controller.captureKeyEvents({ text: "@", isMeta: true });
|
||||
Controller.captureKeyEvents({ text: "page up" });
|
||||
Controller.captureKeyEvents({ text: "page down" });
|
||||
|
||||
|
||||
function printMouseEvent(eventName, event) {
|
||||
print(eventName);
|
||||
print(" event.x,y=" + event.x + ", " + event.y);
|
||||
|
@ -109,22 +93,18 @@ function printMouseEvent(eventName, event) {
|
|||
print(" event.isMeta=" + event.isMeta);
|
||||
print(" event.isAlt=" + event.isAlt);
|
||||
}
|
||||
|
||||
function mouseMoveEvent(event) {
|
||||
printMouseEvent("mouseMoveEvent", event);
|
||||
}
|
||||
function mousePressEvent(event) {
|
||||
printMouseEvent("mousePressEvent", event);
|
||||
}
|
||||
|
||||
function mouseReleaseEvent(event) {
|
||||
printMouseEvent("mouseReleaseEvent", event);
|
||||
}
|
||||
|
||||
Controller.mouseMoveEvent.connect(mouseMoveEvent);
|
||||
Controller.mousePressEvent.connect(mousePressEvent);
|
||||
Controller.mouseReleaseEvent.connect(mouseReleaseEvent);
|
||||
|
||||
function printTouchEvent(eventName, event) {
|
||||
print(eventName);
|
||||
|
||||
|
@ -143,7 +123,6 @@ function printTouchEvent(eventName, event) {
|
|||
print(" event.radius=" + event.radius);
|
||||
print(" event.isPinching=" + event.isPinching);
|
||||
print(" event.isPinchOpening=" + event.isPinchOpening);
|
||||
|
||||
print(" event.angle=" + event.angle);
|
||||
for (var i = 0; i < event.points.length; i++) {
|
||||
print(" event.angles[" + i + "]:" + event.angles[i]);
|
||||
|
@ -151,15 +130,12 @@ function printTouchEvent(eventName, event) {
|
|||
print(" event.isRotating=" + event.isRotating);
|
||||
print(" event.rotating=" + event.rotating);
|
||||
}
|
||||
|
||||
function touchBeginEvent(event) {
|
||||
printTouchEvent("touchBeginEvent", event);
|
||||
}
|
||||
|
||||
function touchUpdateEvent(event) {
|
||||
printTouchEvent("touchUpdateEvent", event);
|
||||
}
|
||||
|
||||
function touchEndEvent(event) {
|
||||
printTouchEvent("touchEndEvent", event);
|
||||
}
|
||||
|
@ -167,8 +143,6 @@ function touchEndEvent(event) {
|
|||
Controller.touchBeginEvent.connect(touchBeginEvent);
|
||||
Controller.touchUpdateEvent.connect(touchUpdateEvent);
|
||||
Controller.touchEndEvent.connect(touchEndEvent);
|
||||
|
||||
|
||||
function wheelEvent(event) {
|
||||
print("wheelEvent");
|
||||
print(" event.x,y=" + event.x + ", " + event.y);
|
||||
|
@ -182,9 +156,7 @@ function wheelEvent(event) {
|
|||
print(" event.isMeta=" + event.isMeta);
|
||||
print(" event.isAlt=" + event.isAlt);
|
||||
}
|
||||
|
||||
Controller.wheelEvent.connect(wheelEvent);
|
||||
|
||||
function scriptEnding() {
|
||||
// re-enabled the standard application for touch events
|
||||
Controller.releaseKeyEvents({ text: "A" });
|
||||
|
@ -194,5 +166,4 @@ function scriptEnding() {
|
|||
Controller.releaseKeyEvents({ text: "page up" });
|
||||
Controller.releaseKeyEvents({ text: "page down" });
|
||||
}
|
||||
|
||||
Script.scriptEnding.connect(scriptEnding);
|
||||
Script.scriptEnding.connect(scriptEnding);
|
|
@ -59,9 +59,7 @@ function controller(side) {
|
|||
this.triggerHeld = false;
|
||||
this.triggerThreshold = 0.9;
|
||||
this.side = side;
|
||||
this.palm = 2 * side;
|
||||
this.tip = 2 * side + 1;
|
||||
this.trigger = side;
|
||||
this.trigger = side == LEFT ? Controller.Standard.LT : Controller.Standard.RT;
|
||||
this.originalGravity = {
|
||||
x: 0,
|
||||
y: 0,
|
||||
|
@ -150,8 +148,8 @@ function controller(side) {
|
|||
|
||||
|
||||
this.updateControllerState = function() {
|
||||
this.palmPosition = Controller.getSpatialControlPosition(this.palm);
|
||||
this.tipPosition = Controller.getSpatialControlPosition(this.tip);
|
||||
this.palmPosition = this.side == RIGHT ? MyAvatar.rightHandPose.translation : MyAvatar.leftHandPose.translation;
|
||||
this.tipPosition = this.side == RIGHT ? MyAvatar.rightHandTipPose.translation : MyAvatar.leftHandTipPose.translation;
|
||||
this.triggerValue = Controller.getTriggerValue(this.trigger);
|
||||
}
|
||||
|
||||
|
|
|
@ -238,7 +238,7 @@ var inHand = false;
|
|||
|
||||
function isControllerActive() {
|
||||
// I don't think the hydra API provides any reliable way to know whether a particular controller is active. Ask for both.
|
||||
controllerActive = (Vec3.length(Controller.getSpatialControlPosition(3)) > 0) || Vec3.length(Controller.getSpatialControlPosition(4)) > 0;
|
||||
controllerActive = (Vec3.length(MyAvatar.leftHandPose.translation) > 0) || Vec3.length(MyAvatar.rightHandPose.translation) > 0;
|
||||
return controllerActive;
|
||||
}
|
||||
|
||||
|
@ -312,10 +312,10 @@ function grabSword(hand) {
|
|||
}
|
||||
var handRotation;
|
||||
if (hand === "right") {
|
||||
handRotation = MyAvatar.getRightPalmRotation();
|
||||
handRotation = MyAvatar.rightHandPose.rotation;
|
||||
|
||||
} else if (hand === "left") {
|
||||
handRotation = MyAvatar.getLeftPalmRotation();
|
||||
handRotation = MyAvatar.leftHandPose.rotation;
|
||||
}
|
||||
var swordRotation = Entities.getEntityProperties(swordID).rotation;
|
||||
var offsetRotation = Quat.multiply(Quat.inverse(handRotation), swordRotation);
|
||||
|
|
26
examples/example/lineExample.js
Normal file
26
examples/example/lineExample.js
Normal file
|
@ -0,0 +1,26 @@
|
|||
//
|
||||
// lineExample.js
|
||||
// examples/example
|
||||
//
|
||||
// Created by Ryan Huffman on October 27, 2015
|
||||
// Copyright 2015 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
Script.include("../libraries/line.js");
|
||||
|
||||
var basePosition = MyAvatar.position;
|
||||
var color = { red: 128, green: 220, blue: 190 };
|
||||
var strokeWidth = 0.01;
|
||||
var line = new InfiniteLine(basePosition, color, 20);
|
||||
|
||||
for (var i = 0; i < (16 * Math.PI); i += 0.05) {
|
||||
var x = 0
|
||||
var y = 0.25 * Math.sin(i);
|
||||
var z = i / 10;
|
||||
|
||||
var position = Vec3.sum(basePosition, { x: x, y: y, z: z });
|
||||
line.enqueuePoint(position, strokeWidth);
|
||||
}
|
|
@ -1,41 +0,0 @@
|
|||
//
|
||||
// metavoxels.js
|
||||
// examples
|
||||
//
|
||||
// Copyright 2014 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
Script.setInterval(function() {
|
||||
var spanner;
|
||||
if (Math.random() < 0.5) {
|
||||
spanner = new Sphere();
|
||||
} else {
|
||||
spanner = new Cuboid();
|
||||
spanner.aspectX = 0.1 + Math.random() * 1.9;
|
||||
spanner.aspectY = 0.1 + Math.random() * 1.9;
|
||||
}
|
||||
spanner.scale = 0.1 + Math.random() * 1.9;
|
||||
spanner.rotation = Quat.fromPitchYawRollDegrees(Math.random() * 360.0, Math.random() * 360.0, Math.random() * 360.0);
|
||||
spanner.translation = { x: 10.0 + Math.random() * 10.0, y: 10.0 + Math.random() * 10.0, z: 10.0 + Math.random() * 10.0 };
|
||||
|
||||
if (Math.random() < 0.5) {
|
||||
var material = new MaterialObject();
|
||||
if (Math.random() < 0.5) {
|
||||
material.diffuse = "http://www.fungibleinsight.com/faces/grass.jpg";
|
||||
} else {
|
||||
material.diffuse = "http://www.fungibleinsight.com/faces/soil.jpg";
|
||||
}
|
||||
Metavoxels.setVoxelMaterial(spanner, material);
|
||||
|
||||
} else if (Math.random() < 0.5) {
|
||||
Metavoxels.setVoxelColor(spanner, { red: Math.random() * 255.0, green: Math.random() * 255.0,
|
||||
blue: Math.random() * 255.0 });
|
||||
|
||||
} else {
|
||||
Metavoxels.setVoxelColor(spanner, { red: 0, green: 0, blue: 0, alpha: 0 });
|
||||
}
|
||||
}, 1000);
|
||||
|
|
@ -71,10 +71,8 @@ function controller(side, cycleColorButton) {
|
|||
this.triggerHeld = false;
|
||||
this.triggerThreshold = 0.9;
|
||||
this.side = side;
|
||||
this.palm = 2 * side;
|
||||
this.tip = 2 * side + 1;
|
||||
this.trigger = side;
|
||||
this.cycleColorButton = cycleColorButton;
|
||||
this.trigger = side == LEFT ? Controller.Stantard.LT : Controller.Standard.RT;
|
||||
this.cycleColorButton = side == LEFT ? Controller.Stantard.LeftPrimaryThumb : Controller.Standard.RightPrimaryThumb;
|
||||
|
||||
this.points = [];
|
||||
this.normals = [];
|
||||
|
@ -173,11 +171,10 @@ function controller(side, cycleColorButton) {
|
|||
|
||||
|
||||
this.updateControllerState = function() {
|
||||
this.cycleColorButtonPressed = Controller.isButtonPressed(this.cycleColorButton);
|
||||
this.palmPosition = Controller.getSpatialControlPosition(this.palm);
|
||||
this.tipPosition = Controller.getSpatialControlPosition(this.tip);
|
||||
this.palmNormal = Controller.getSpatialControlNormal(this.palm);
|
||||
this.triggerValue = Controller.getTriggerValue(this.trigger);
|
||||
this.cycleColorButtonPressed = Controller.getValue(this.cycleColorButton);
|
||||
this.palmPosition = this.side == RIGHT ? MyAvatar.rightHandPose.translation : MyAvatar.leftHandPose.translation;
|
||||
this.tipPosition = this.side == RIGHT ? MyAvatar.rightHandTipPose.translation : MyAvatar.leftHandTipPose.translation;
|
||||
this.triggerValue = Controller.getValue(this.trigger);
|
||||
|
||||
|
||||
if (this.prevCycleColorButtonPressed === true && this.cycleColorButtonPressed === false) {
|
||||
|
@ -215,8 +212,8 @@ function vectorIsZero(v) {
|
|||
}
|
||||
|
||||
|
||||
var rightController = new controller(RIGHT, RIGHT_BUTTON_4);
|
||||
var leftController = new controller(LEFT, LEFT_BUTTON_4);
|
||||
var rightController = new controller(RIGHT);
|
||||
var leftController = new controller(LEFT);
|
||||
Script.update.connect(update);
|
||||
Script.scriptEnding.connect(scriptEnding);
|
||||
|
||||
|
|
|
@ -11,6 +11,37 @@
|
|||
|
||||
// Assumes you only have the default keyboard connected
|
||||
|
||||
function findAction(name) {
|
||||
var actions = Controller.getAllActions();
|
||||
for (var i = 0; i < actions.length; i++) {
|
||||
if (actions[i].actionName == name) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
// If the action isn't found, it will default to the first available action
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
var hydra = Controller.Hardware.Hydra;
|
||||
if (hydra !== undefined) {
|
||||
print("-----------------------------------");
|
||||
var mapping = Controller.newMapping("Test");
|
||||
var standard = Controller.Standard;
|
||||
print("standard:" + standard);
|
||||
mapping.from(function () { return Math.sin(Date.now() / 250); }).to(function (newValue, oldValue, source) {
|
||||
print("function source newValue:" + newValue + ", oldValue:" + oldValue + ", source:" + source);
|
||||
});
|
||||
mapping.from(hydra.L1).to(standard.A);
|
||||
mapping.from(hydra.L2).to(standard.B);
|
||||
mapping.from(hydra.L3).to(function (newValue, oldValue, source) {
|
||||
print("hydra.L3 newValue:" + newValue + ", oldValue:" + oldValue + ", source:" + source);
|
||||
});
|
||||
Controller.enableMapping("Test");
|
||||
print("-----------------------------------");
|
||||
} else {
|
||||
print("couldn't find hydra");
|
||||
}
|
||||
|
||||
Object.keys(Controller.Standard).forEach(function (input) {
|
||||
print("Controller.Standard." + input + ":" + Controller.Standard[input]);
|
||||
|
@ -32,44 +63,48 @@ Controller.resetAllDeviceBindings();
|
|||
// Query all actions
|
||||
print("All Actions: \n" + Controller.getAllActions());
|
||||
|
||||
var actionId = findAction("YAW_LEFT")
|
||||
|
||||
print("Yaw Left action ID: " + actionId)
|
||||
|
||||
// Each action stores:
|
||||
// action: int representation of enum
|
||||
print("Action 5 int: \n" + Controller.getAllActions()[5].action);
|
||||
print("Action int: \n" + Controller.getAllActions()[actionId].action);
|
||||
|
||||
// actionName: string representation of enum
|
||||
print("Action 5 name: \n" + Controller.getAllActions()[5].actionName);
|
||||
print("Action name: \n" + Controller.getAllActions()[actionId].actionName);
|
||||
|
||||
// inputChannels: list of all inputchannels that control that action
|
||||
print("Action 5 input channels: \n" + Controller.getAllActions()[5].inputChannels + "\n");
|
||||
print("Action input channels: \n" + Controller.getAllActions()[actionId].inputChannels + "\n");
|
||||
|
||||
|
||||
// Each input channel stores:
|
||||
// action: Action that this InputChannel maps to
|
||||
print("Input channel action: \n" + Controller.getAllActions()[5].inputChannels[0].action);
|
||||
print("Input channel action: \n" + Controller.getAllActions()[actionId].inputChannels[0].action);
|
||||
|
||||
// scale: sensitivity of input
|
||||
print("Input channel scale: \n" + Controller.getAllActions()[5].inputChannels[0].scale);
|
||||
print("Input channel scale: \n" + Controller.getAllActions()[actionId].inputChannels[0].scale);
|
||||
|
||||
// input and modifier: Inputs
|
||||
print("Input channel input and modifier: \n" + Controller.getAllActions()[5].inputChannels[0].input + "\n" + Controller.getAllActions()[5].inputChannels[0].modifier + "\n");
|
||||
print("Input channel input and modifier: \n" + Controller.getAllActions()[actionId].inputChannels[0].input + "\n" + Controller.getAllActions()[actionId].inputChannels[0].modifier + "\n");
|
||||
|
||||
|
||||
// Each Input stores:
|
||||
// device: device of input
|
||||
print("Input device: \n" + Controller.getAllActions()[5].inputChannels[0].input.device);
|
||||
print("Input device: \n" + Controller.getAllActions()[actionId].inputChannels[0].input.device);
|
||||
|
||||
// channel: channel of input
|
||||
print("Input channel: \n" + Controller.getAllActions()[5].inputChannels[0].input.channel);
|
||||
print("Input channel: \n" + Controller.getAllActions()[actionId].inputChannels[0].input.channel);
|
||||
|
||||
// type: type of input (Unknown, Button, Axis, Joint)
|
||||
print("Input type: \n" + Controller.getAllActions()[5].inputChannels[0].input.type);
|
||||
print("Input type: \n" + Controller.getAllActions()[actionId].inputChannels[0].input.type);
|
||||
|
||||
// id: id of input
|
||||
print("Input id: \n" + Controller.getAllActions()[5].inputChannels[0].input.id + "\n");
|
||||
print("Input id: \n" + Controller.getAllActions()[actionId].inputChannels[0].input.id + "\n");
|
||||
|
||||
|
||||
// You can get the name of a device from its id
|
||||
print("Device 1 name: \n" + Controller.getDeviceName(Controller.getAllActions()[5].inputChannels[0].input.id));
|
||||
print("Device 1 name: \n" + Controller.getDeviceName(Controller.getAllActions()[actionId].inputChannels[0].input.id));
|
||||
|
||||
// You can also get all of a devices input channels
|
||||
print("Device 1's input channels: \n" + Controller.getAllInputsForDevice(1) + "\n");
|
||||
|
@ -105,7 +140,7 @@ for (i = 0; i < availableInputs.length; i++) {
|
|||
|
||||
// You can modify key bindings by using these avaiable inputs
|
||||
// This will replace e (up) with 6
|
||||
var e = Controller.getAllActions()[5].inputChannels[0];
|
||||
var e = Controller.getAllActions()[actionId].inputChannels[0];
|
||||
Controller.removeInputChannel(e);
|
||||
e.input = availableInputs[6].input;
|
||||
Controller.addInputChannel(e);
|
|
@ -830,7 +830,7 @@
|
|||
elZoneKeyLightColorRed.addEventListener('change', zoneKeyLightColorChangeFunction);
|
||||
elZoneKeyLightColorGreen.addEventListener('change', zoneKeyLightColorChangeFunction);
|
||||
elZoneKeyLightColorBlue.addEventListener('change', zoneKeyLightColorChangeFunction);
|
||||
elZoneKeyLightIntensity.addEventListener('change', createEmitGroupNumberPropertyUpdateFunction('intensity','keyLight'));
|
||||
elZoneKeyLightIntensity.addEventListener('change', createEmitGroupNumberPropertyUpdateFunction('keyLight','intensity'));
|
||||
elZoneKeyLightAmbientIntensity.addEventListener('change', createEmitGroupNumberPropertyUpdateFunction('keyLight','ambientIntensity'));
|
||||
var zoneKeyLightDirectionChangeFunction = createEmitGroupVec3PropertyUpdateFunction('keyLight','direction', elZoneKeyLightDirectionX, elZoneKeyLightDirectionY, elZoneKeyLightDirectionZ);
|
||||
elZoneKeyLightDirectionX.addEventListener('change', zoneKeyLightDirectionChangeFunction);
|
||||
|
@ -1520,7 +1520,7 @@
|
|||
<div class="zone-section keyLight-section property">
|
||||
<div class="label">Ambient URL</div>
|
||||
<div class="value">
|
||||
<input type="text" id="property-zone-skybox-url" class="url">
|
||||
<input type="text" id="property-zone-key-ambient-url" class="url">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
161
examples/libraries/line.js
Normal file
161
examples/libraries/line.js
Normal file
|
@ -0,0 +1,161 @@
|
|||
//
|
||||
// line.js
|
||||
// examples/libraries
|
||||
//
|
||||
// Created by Ryan Huffman on October 27, 2015
|
||||
// Copyright 2015 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
function error(message) {
|
||||
print("[ERROR] " + message);
|
||||
}
|
||||
|
||||
// PolyLine
|
||||
var LINE_DIMENSIONS = { x: 2000, y: 2000, z: 2000 };
|
||||
var MAX_LINE_LENGTH = 40; // This must be 2 or greater;
|
||||
var DEFAULT_STROKE_WIDTH = 0.1;
|
||||
var DEFAULT_LIFETIME = 20;
|
||||
var DEFAULT_COLOR = { red: 255, green: 255, blue: 255 };
|
||||
var PolyLine = function(position, color, lifetime) {
|
||||
this.position = position;
|
||||
this.color = color;
|
||||
this.lifetime = lifetime === undefined ? DEFAULT_LIFETIME : lifetime;
|
||||
this.points = [
|
||||
];
|
||||
this.strokeWidths = [
|
||||
];
|
||||
this.normals = [
|
||||
]
|
||||
this.entityID = Entities.addEntity({
|
||||
type: "PolyLine",
|
||||
position: position,
|
||||
linePoints: this.points,
|
||||
normals: this.normals,
|
||||
strokeWidths: this.strokeWidths,
|
||||
dimensions: LINE_DIMENSIONS,
|
||||
color: color,
|
||||
lifetime: lifetime
|
||||
});
|
||||
};
|
||||
|
||||
PolyLine.prototype.enqueuePoint = function(position, strokeWidth) {
|
||||
if (this.isFull()) {
|
||||
error("Hit max PolyLine size");
|
||||
return;
|
||||
}
|
||||
|
||||
position = Vec3.subtract(position, this.position);
|
||||
this.points.push(position);
|
||||
this.normals.push({ x: 1, y: 0, z: 0 });
|
||||
this.strokeWidths.push(strokeWidth);
|
||||
Entities.editEntity(this.entityID, {
|
||||
linePoints: this.points,
|
||||
normals: this.normals,
|
||||
strokeWidths: this.strokeWidths
|
||||
});
|
||||
};
|
||||
|
||||
PolyLine.prototype.dequeuePoint = function() {
|
||||
if (this.points.length == 0) {
|
||||
error("Hit min PolyLine size");
|
||||
return;
|
||||
}
|
||||
|
||||
this.points = this.points.slice(1);
|
||||
this.normals = this.normals.slice(1);
|
||||
this.strokeWidths = this.strokeWidths.slice(1);
|
||||
|
||||
Entities.editEntity(this.entityID, {
|
||||
linePoints: this.points,
|
||||
normals: this.normals,
|
||||
strokeWidths: this.strokeWidths
|
||||
});
|
||||
};
|
||||
|
||||
PolyLine.prototype.getFirstPoint = function() {
|
||||
return Vec3.sum(this.position, this.points[0]);
|
||||
};
|
||||
|
||||
PolyLine.prototype.getLastPoint = function() {
|
||||
return Vec3.sum(this.position, this.points[this.points.length - 1]);
|
||||
};
|
||||
|
||||
PolyLine.prototype.getSize = function() {
|
||||
return this.points.length;
|
||||
}
|
||||
|
||||
PolyLine.prototype.isFull = function() {
|
||||
return this.points.length >= MAX_LINE_LENGTH;
|
||||
};
|
||||
|
||||
PolyLine.prototype.destroy = function() {
|
||||
Entities.deleteEntity(this.entityID);
|
||||
this.points = [];
|
||||
};
|
||||
|
||||
|
||||
// InfiniteLine
|
||||
InfiniteLine = function(position, color, lifetime) {
|
||||
this.position = position;
|
||||
this.color = color;
|
||||
this.lifetime = lifetime === undefined ? DEFAULT_LIFETIME : lifetime;
|
||||
this.lines = [];
|
||||
this.size = 0;
|
||||
};
|
||||
|
||||
InfiniteLine.prototype.enqueuePoint = function(position, strokeWidth) {
|
||||
var currentLine;
|
||||
|
||||
if (this.lines.length == 0) {
|
||||
currentLine = new PolyLine(position, this.color, this.lifetime);
|
||||
this.lines.push(currentLine);
|
||||
} else {
|
||||
currentLine = this.lines[this.lines.length - 1];
|
||||
}
|
||||
|
||||
if (currentLine.isFull()) {
|
||||
var newLine = new PolyLine(currentLine.getLastPoint(), this.color, this.lifetime);
|
||||
newLine.enqueuePoint(currentLine.getLastPoint(), strokeWidth);
|
||||
this.lines.push(newLine);
|
||||
currentLine = newLine;
|
||||
}
|
||||
|
||||
currentLine.enqueuePoint(position, strokeWidth);
|
||||
|
||||
++this.size;
|
||||
};
|
||||
|
||||
InfiniteLine.prototype.dequeuePoint = function() {
|
||||
if (this.lines.length == 0) {
|
||||
error("Trying to dequeue from InfiniteLine when no points are left");
|
||||
return;
|
||||
}
|
||||
|
||||
var lastLine = this.lines[0];
|
||||
lastLine.dequeuePoint();
|
||||
|
||||
if (lastLine.getSize() <= 1) {
|
||||
this.lines = this.lines.slice(1);
|
||||
}
|
||||
|
||||
--this.size;
|
||||
};
|
||||
|
||||
InfiniteLine.prototype.getFirstPoint = function() {
|
||||
return this.lines.length > 0 ? this.lines[0].getFirstPoint() : null;
|
||||
};
|
||||
|
||||
InfiniteLine.prototype.getLastPoint = function() {
|
||||
return this.lines.length > 0 ? this.lines[lines.length - 1].getLastPoint() : null;
|
||||
};
|
||||
|
||||
InfiniteLine.prototype.destroy = function() {
|
||||
for (var i = 0; i < this.lines.length; ++i) {
|
||||
this.lines[i].destroy();
|
||||
}
|
||||
|
||||
this.size = 0;
|
||||
};
|
|
@ -15,16 +15,18 @@ Script.include("omniTool/models/invisibleWand.js");
|
|||
|
||||
OmniToolModules = {};
|
||||
OmniToolModuleType = null;
|
||||
LOG_DEBUG = 1;
|
||||
|
||||
OmniTool = function(side) {
|
||||
OmniTool = function(left) {
|
||||
this.OMNI_KEY = "OmniTool";
|
||||
this.MAX_FRAMERATE = 60;
|
||||
this.UPDATE_INTERVAL = 1.0 / this.MAX_FRAMERATE
|
||||
this.SIDE = side;
|
||||
this.PALM = 2 * side;
|
||||
this.ACTION = findAction(side ? "ACTION2" : "ACTION1");
|
||||
this.ALT_ACTION = findAction(side ? "ACTION1" : "ACTION2");
|
||||
|
||||
this.left = left;
|
||||
this.triggered = false;
|
||||
var actions = Controller.Actions;
|
||||
var standard = Controller.Standard;
|
||||
this.palmControl = left ? actions.LeftHand : actions.RightHand;
|
||||
logDebug("Init OmniTool " + (left ? "left" : "right"));
|
||||
this.highlighter = new Highlighter();
|
||||
this.ignoreEntities = {};
|
||||
this.nearestOmniEntity = {
|
||||
|
@ -47,22 +49,25 @@ OmniTool = function(side) {
|
|||
this.showWand(false);
|
||||
|
||||
// Connect to desired events
|
||||
var _this = this;
|
||||
Controller.actionEvent.connect(function(action, state) {
|
||||
_this.onActionEvent(action, state);
|
||||
});
|
||||
var that = this;
|
||||
|
||||
Script.update.connect(function(deltaTime) {
|
||||
_this.lastUpdateInterval += deltaTime;
|
||||
if (_this.lastUpdateInterval >= _this.UPDATE_INTERVAL) {
|
||||
_this.onUpdate(_this.lastUpdateInterval);
|
||||
_this.lastUpdateInterval = 0;
|
||||
that.lastUpdateInterval += deltaTime;
|
||||
if (that.lastUpdateInterval >= that.UPDATE_INTERVAL) {
|
||||
that.onUpdate(that.lastUpdateInterval);
|
||||
that.lastUpdateInterval = 0;
|
||||
}
|
||||
});
|
||||
|
||||
Script.scriptEnding.connect(function() {
|
||||
_this.onCleanup();
|
||||
that.onCleanup();
|
||||
});
|
||||
|
||||
this.mapping = Controller.newMapping();
|
||||
this.mapping.from(left ? standard.LeftPrimaryThumb : standard.RightPrimaryThumb).to(function(value){
|
||||
that.onUpdateTrigger(value);
|
||||
})
|
||||
this.mapping.enable();
|
||||
}
|
||||
|
||||
OmniTool.prototype.showWand = function(show) {
|
||||
|
@ -81,30 +86,23 @@ OmniTool.prototype.showWand = function(show) {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
OmniTool.prototype.onCleanup = function(action) {
|
||||
this.mapping.disable();
|
||||
this.unloadModule();
|
||||
}
|
||||
|
||||
OmniTool.prototype.onActionEvent = function(action, state) {
|
||||
// FIXME figure out the issues when only one spatial controller is active
|
||||
// logDebug("Action: " + action + " " + state);
|
||||
|
||||
if (this.module && this.module.onActionEvent) {
|
||||
this.module.onActionEvent(action, state);
|
||||
}
|
||||
|
||||
if (action == this.ACTION) {
|
||||
if (state) {
|
||||
OmniTool.prototype.onUpdateTrigger = function (value) {
|
||||
//logDebug("Trigger update value " + value);
|
||||
var triggered = value != 0;
|
||||
if (triggered != this.triggered) {
|
||||
this.triggered = triggered;
|
||||
if (this.triggered) {
|
||||
this.onClick();
|
||||
} else {
|
||||
this.onRelease();
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME Does not work
|
||||
//// with only one controller active (listed as 2 here because 'tip' + 'palm')
|
||||
//// then treat the alt action button as the action button
|
||||
}
|
||||
|
||||
OmniTool.prototype.getOmniToolData = function(entityId) {
|
||||
|
@ -127,7 +125,7 @@ OmniTool.prototype.setActive = function(active) {
|
|||
if (active === this.active) {
|
||||
return;
|
||||
}
|
||||
logDebug("OmniTool changing active state: " + active);
|
||||
logDebug("OmniTool " + this.left + " changing active state: " + active);
|
||||
this.active = active;
|
||||
this.model.setVisible(this.active);
|
||||
if (this.module && this.module.onActiveChanged) {
|
||||
|
@ -138,17 +136,17 @@ OmniTool.prototype.setActive = function(active) {
|
|||
|
||||
OmniTool.prototype.onUpdate = function(deltaTime) {
|
||||
// FIXME this returns data if either the left or right controller is not on the base
|
||||
this.position = Controller.getSpatialControlPosition(this.PALM);
|
||||
this.pose = Controller.getPoseValue(this.palmControl);
|
||||
this.position = this.left ? MyAvatar.leftHandTipPosition : MyAvatar.rightHandTipPosition;
|
||||
// When on the base, hydras report a position of 0
|
||||
this.setActive(Vec3.length(this.position) > 0.001);
|
||||
if (!this.active) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if (this.model) {
|
||||
// Update the wand
|
||||
var rawRotation = Controller.getSpatialControlRawRotation(this.PALM);
|
||||
var rawRotation = this.pose.rotation;
|
||||
this.rotation = Quat.multiply(MyAvatar.orientation, rawRotation);
|
||||
this.model.setTransform({
|
||||
rotation: this.rotation,
|
||||
|
@ -306,6 +304,7 @@ OmniTool.prototype.scan = function() {
|
|||
}
|
||||
|
||||
OmniTool.prototype.unloadModule = function() {
|
||||
logDebug("Unloading omniTool module")
|
||||
if (this.module && this.module.onUnload) {
|
||||
this.module.onUnload();
|
||||
}
|
||||
|
@ -348,4 +347,4 @@ OmniTool.prototype.activateNewOmniModule = function() {
|
|||
}
|
||||
|
||||
// FIXME find a good way to sync the two omni tools
|
||||
OMNI_TOOLS = [ new OmniTool(0), new OmniTool(1) ];
|
||||
OMNI_TOOLS = [ new OmniTool(true), new OmniTool(false) ];
|
||||
|
|
|
@ -31,13 +31,7 @@ scaleLine = function (start, end, scale) {
|
|||
}
|
||||
|
||||
findAction = function(name) {
|
||||
var actions = Controller.getAllActions();
|
||||
for (var i = 0; i < actions.length; i++) {
|
||||
if (actions[i].actionName == name) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
return Controller.findAction(name);
|
||||
}
|
||||
|
||||
addLine = function(origin, vector, color) {
|
||||
|
|
|
@ -18,24 +18,8 @@ Script.include("./libraries/walkConstants.js");
|
|||
|
||||
Avatar = function() {
|
||||
// if Hydras are connected, the only way to enable use is to never set any arm joint rotation
|
||||
this.hydraCheck = function() {
|
||||
// function courtesy of Thijs Wenker (frisbee.js)
|
||||
var numberOfButtons = Controller.getNumberOfButtons();
|
||||
var numberOfTriggers = Controller.getNumberOfTriggers();
|
||||
var numberOfSpatialControls = Controller.getNumberOfSpatialControls();
|
||||
const HYDRA_BUTTONS = 12;
|
||||
const HYDRA_TRIGGERS = 2;
|
||||
const HYDRA_CONTROLLERS_PER_TRIGGER = 2;
|
||||
var controllersPerTrigger = numberOfSpatialControls / numberOfTriggers;
|
||||
if (numberOfButtons == HYDRA_BUTTONS &&
|
||||
numberOfTriggers == HYDRA_TRIGGERS &&
|
||||
controllersPerTrigger == HYDRA_CONTROLLERS_PER_TRIGGER) {
|
||||
print('walk.js info: Razer Hydra detected. Setting arms free (not controlled by script)');
|
||||
return true;
|
||||
} else {
|
||||
print('walk.js info: Razer Hydra not detected. Arms will be controlled by script.');
|
||||
return false;
|
||||
}
|
||||
this.hydraCheck = function () {
|
||||
return Controller.Hardware.Hydra !== undefined;
|
||||
}
|
||||
// settings
|
||||
this.headFree = true;
|
||||
|
|
|
@ -38,7 +38,7 @@ var mouseLook = (function () {
|
|||
keyboardID = 0;
|
||||
|
||||
function onKeyPressEvent(event) {
|
||||
if (event.text == 'M') {
|
||||
if (event.text == 'm') {
|
||||
active = !active;
|
||||
updateMapping();
|
||||
}
|
||||
|
|
|
@ -47,6 +47,7 @@
|
|||
if (this.painting) {
|
||||
return;
|
||||
}
|
||||
this.whichHand = this.hand;
|
||||
if (this.hand === RIGHT_HAND) {
|
||||
this.getHandPosition = MyAvatar.getRightPalmPosition;
|
||||
this.getHandRotation = MyAvatar.getRightPalmRotation;
|
||||
|
@ -183,6 +184,9 @@
|
|||
},
|
||||
|
||||
releaseGrab: function() {
|
||||
if(this.hand !== this.whichHand) {
|
||||
return;
|
||||
}
|
||||
this.stopPainting();
|
||||
|
||||
},
|
||||
|
@ -241,10 +245,8 @@
|
|||
Overlays.deleteOverlay(this.laserPointer);
|
||||
// this.eraseBoard();
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
// entity scripts always need to return a newly constructed object of our type
|
||||
return new Whiteboard();
|
||||
});
|
|
@ -16,186 +16,199 @@
|
|||
|
||||
Script.include("../../libraries/utils.js");
|
||||
var scriptURL = Script.resolvePath("whiteboardEntityScript.js");
|
||||
var modelURL = "https://s3.amazonaws.com/hifi-public/eric/models/whiteboard.fbx";
|
||||
|
||||
var colorIndicatorBorderModelURL = "https://s3.amazonaws.com/hifi-public/eric/models/colorIndicatorBorder.fbx";
|
||||
var eraserModelURL = "https://s3.amazonaws.com/hifi-public/eric/models/eraser.fbx";
|
||||
var surfaceModelURL = "https://s3.amazonaws.com/hifi-public/eric/models/boardSurface.fbx";
|
||||
var rotation = Quat.safeEulerAngles(Camera.getOrientation());
|
||||
rotation = Quat.fromPitchYawRollDegrees(0, rotation.y, 0);
|
||||
var center = Vec3.sum(MyAvatar.position, Vec3.multiply(3, Quat.getFront(rotation)));
|
||||
center.y += 0.4;
|
||||
|
||||
var whiteboardDimensions, colorIndicatorBoxDimensions, colorIndicatorBox, eraser, blocker;
|
||||
var colorBoxes = [];
|
||||
|
||||
var colors = [
|
||||
hexToRgb("#2F8E84"),
|
||||
hexToRgb("#66CCB3"),
|
||||
hexToRgb("#A43C37"),
|
||||
hexToRgb("#491849"),
|
||||
hexToRgb("#6AB03B"),
|
||||
hexToRgb("#993369"),
|
||||
hexToRgb("#9B47C2")
|
||||
hexToRgb("#000000")
|
||||
];
|
||||
|
||||
//WHITEBOARD
|
||||
var whiteboardDimensions = {
|
||||
x: 2,
|
||||
y: 1.5,
|
||||
z: 0.08
|
||||
};
|
||||
var whiteboard = Entities.addEntity({
|
||||
type: "Model",
|
||||
modelURL: "https://hifi-public.s3.amazonaws.com/ozan/support/for_eric/whiteboard/whiteboard.fbx",
|
||||
name: "whiteboard",
|
||||
shapeType: "box",
|
||||
modelURL: modelURL,
|
||||
name: "whiteboard base",
|
||||
position: center,
|
||||
rotation: rotation,
|
||||
script: scriptURL,
|
||||
dimensions: whiteboardDimensions,
|
||||
color: {
|
||||
red: 255,
|
||||
green: 255,
|
||||
blue: 255
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
// COLOR INDICATOR BOX
|
||||
var colorIndicatorDimensions = {
|
||||
x: whiteboardDimensions.x,
|
||||
y: 0.05,
|
||||
z: 0.02
|
||||
var colorIndicatorPosition = {
|
||||
x: center.x,
|
||||
y: center.y,
|
||||
z: center.z
|
||||
};
|
||||
scriptURL = Script.resolvePath("colorIndicatorEntityScript.js");
|
||||
var colorIndicatorPosition = Vec3.sum(center, {
|
||||
x: 0,
|
||||
y: whiteboardDimensions.y / 2 + colorIndicatorDimensions.y / 2,
|
||||
z: 0
|
||||
});
|
||||
var colorIndicatorBox = Entities.addEntity({
|
||||
type: "Box",
|
||||
name: "Color Indicator",
|
||||
color: colors[0],
|
||||
rotation: rotation,
|
||||
colorIndicatorPosition.y += 1.55;
|
||||
colorIndicatorPosition = Vec3.sum(colorIndicatorPosition, Vec3.multiply(-0.1, Quat.getFront(rotation)));
|
||||
var colorIndicatorBorder = Entities.addEntity({
|
||||
type: "Model",
|
||||
position: colorIndicatorPosition,
|
||||
dimensions: colorIndicatorDimensions,
|
||||
script: scriptURL,
|
||||
userData: JSON.stringify({
|
||||
whiteboard: whiteboard
|
||||
})
|
||||
modelURL: colorIndicatorBorderModelURL,
|
||||
rotation: rotation,
|
||||
shapeType: "box"
|
||||
});
|
||||
|
||||
Entities.editEntity(whiteboard, {
|
||||
var surfaceCenter = Vec3.sum(center, Vec3.multiply(-0.1, Quat.getFront(rotation)));
|
||||
surfaceCenter.y += 0.6;
|
||||
var drawingSurface = Entities.addEntity({
|
||||
type: "Model",
|
||||
modelURL: surfaceModelURL,
|
||||
shapeType: "box",
|
||||
name: "whiteboard surface",
|
||||
position: surfaceCenter,
|
||||
script: scriptURL,
|
||||
rotation: rotation,
|
||||
userData: JSON.stringify({
|
||||
color: {
|
||||
currentColor: colors[0]
|
||||
},
|
||||
colorIndicator: colorIndicatorBox
|
||||
})
|
||||
});
|
||||
|
||||
//COLOR BOXES
|
||||
var direction = Quat.getRight(rotation);
|
||||
var colorBoxPosition = Vec3.subtract(center, Vec3.multiply(direction, whiteboardDimensions.x / 2));
|
||||
var colorBoxes = [];
|
||||
var colorSquareDimensions = {
|
||||
x: (whiteboardDimensions.x / 2) / (colors.length - 1),
|
||||
y: 0.1,
|
||||
z: 0.05
|
||||
};
|
||||
colorBoxPosition.y += whiteboardDimensions.y / 2 + colorIndicatorDimensions.y + colorSquareDimensions.y / 2;
|
||||
var spaceBetweenColorBoxes = Vec3.multiply(direction, colorSquareDimensions.x * 2);
|
||||
var scriptURL = Script.resolvePath("colorSelectorEntityScript.js");
|
||||
for (var i = 0; i < colors.length; i++) {
|
||||
var colorBox = Entities.addEntity({
|
||||
type: "Box",
|
||||
name: "Color Selector",
|
||||
position: colorBoxPosition,
|
||||
dimensions: colorSquareDimensions,
|
||||
rotation: rotation,
|
||||
color: colors[i],
|
||||
script: scriptURL,
|
||||
userData: JSON.stringify({
|
||||
whiteboard: whiteboard,
|
||||
colorIndicator: colorIndicatorBox
|
||||
})
|
||||
});
|
||||
colorBoxes.push(colorBox);
|
||||
colorBoxPosition = Vec3.sum(colorBoxPosition, spaceBetweenColorBoxes);
|
||||
}
|
||||
|
||||
|
||||
// BLACK BOX
|
||||
var blackBoxDimensions = {
|
||||
x: 0.3,
|
||||
y: 0.3,
|
||||
z: 0.01
|
||||
};
|
||||
|
||||
colorBoxPosition = Vec3.subtract(center, Vec3.multiply(direction, whiteboardDimensions.x / 2 + blackBoxDimensions.x / 2 - 0.01));
|
||||
colorBoxPosition.y += 0.3;
|
||||
var fragShaderURL = Script.resolvePath('blackInk.fs?v1' + Math.random());
|
||||
var blackBox = Entities.addEntity({
|
||||
type: 'Box',
|
||||
name: "Black Color",
|
||||
position: colorBoxPosition,
|
||||
dimensions: blackBoxDimensions,
|
||||
rotation: rotation,
|
||||
color: {
|
||||
red: 0,
|
||||
green: 0,
|
||||
blue: 0
|
||||
},
|
||||
script: scriptURL,
|
||||
userData: JSON.stringify({
|
||||
whiteboard: whiteboard,
|
||||
version: 2,
|
||||
ProceduralEntity: {
|
||||
shaderUrl: fragShaderURL
|
||||
}
|
||||
})
|
||||
|
||||
});
|
||||
|
||||
var lightPosition = Vec3.sum(center, Vec3.multiply(-3, Quat.getFront(rotation)));
|
||||
var light = Entities.addEntity({
|
||||
type: 'Light',
|
||||
name: 'whiteboard light',
|
||||
position: lightPosition,
|
||||
dimensions: {x: 10, y: 10, z: 10},
|
||||
intensity: 2,
|
||||
color: {red: 255, green: 255, blue: 255}
|
||||
});
|
||||
|
||||
var eraseBoxDimensions = {
|
||||
x: 0.5,
|
||||
y: 0.1,
|
||||
z: 0.01
|
||||
};
|
||||
|
||||
|
||||
var eraseBoxPosition = Vec3.sum(center, Vec3.multiply(direction, whiteboardDimensions.x / 2 + eraseBoxDimensions.x / 2 + 0.01));
|
||||
eraseBoxPosition.y += 0.3;
|
||||
var eraserPosition = Vec3.sum(center, {x: 0, y: 2.05, z: 0 });
|
||||
eraserPosition = Vec3.sum(eraserPosition, Vec3.multiply(-0.1, rotation));
|
||||
scriptURL = Script.resolvePath("eraseBoardEntityScript.js");
|
||||
var eraseAllText = Entities.addEntity({
|
||||
type: "Text",
|
||||
position: eraseBoxPosition,
|
||||
var eraser = Entities.addEntity({
|
||||
type: "Model",
|
||||
modelURL: eraserModelURL,
|
||||
position: eraserPosition,
|
||||
name: "Eraser",
|
||||
script: scriptURL,
|
||||
rotation: rotation,
|
||||
dimensions: eraseBoxDimensions,
|
||||
backgroundColor: {
|
||||
red: 0,
|
||||
green: 60,
|
||||
blue: 0
|
||||
},
|
||||
textColor: {
|
||||
red: 255,
|
||||
green: 10,
|
||||
blue: 10
|
||||
},
|
||||
text: "ERASE BOARD",
|
||||
lineHeight: 0.07,
|
||||
userData: JSON.stringify({
|
||||
whiteboard: whiteboard
|
||||
whiteboard: drawingSurface
|
||||
})
|
||||
});
|
||||
|
||||
Script.setTimeout(function() {
|
||||
whiteboardDimensions = Entities.getEntityProperties(whiteboard, "naturalDimensions").naturalDimensions;
|
||||
colorIndicatorBorderDimensions = Entities.getEntityProperties(colorIndicatorBorder, "naturalDimensions").naturalDimensions;
|
||||
setUp();
|
||||
}, 2000)
|
||||
|
||||
|
||||
function setUp() {
|
||||
var blockerPosition = Vec3.sum(center, {x: 0, y: -1, z: 0 });
|
||||
blockerPosition = Vec3.sum(blockerPosition, Vec3.multiply(-1, Quat.getFront(rotation)));
|
||||
blocker = Entities.addEntity({
|
||||
type: "Box",
|
||||
rotation: rotation,
|
||||
position: blockerPosition,
|
||||
dimensions: {x: whiteboardDimensions.x, y: 1, z: 0.1},
|
||||
shapeType: "box",
|
||||
visible: false
|
||||
});
|
||||
|
||||
var eraseModelDimensions = Entities.getEntityProperties(eraser, "naturalDimensions").naturalDimensions;
|
||||
Entities.editEntity(eraser, {dimensions: eraseModelDimensions});
|
||||
Entities.editEntity(colorIndicatorBorder, {dimensions: colorIndicatorBorderDimensions});
|
||||
|
||||
scriptURL = Script.resolvePath("colorIndicatorEntityScript.js");
|
||||
var colorIndicatorPosition = Vec3.sum(center, {
|
||||
x: 0,
|
||||
y: whiteboardDimensions.y / 2 + colorIndicatorBorderDimensions.y / 2,
|
||||
z: 0
|
||||
});
|
||||
colorIndicatorPosition = Vec3.sum(colorIndicatorPosition, Vec3.multiply(-.1, Quat.getFront(rotation)));
|
||||
var colorIndicatorBoxDimensions = Vec3.multiply(colorIndicatorBorderDimensions, 0.9);
|
||||
colorIndicatorBox = Entities.addEntity({
|
||||
type: "Box",
|
||||
name: "Color Indicator",
|
||||
color: colors[0],
|
||||
rotation: rotation,
|
||||
position: colorIndicatorPosition,
|
||||
dimensions: colorIndicatorBoxDimensions,
|
||||
script: scriptURL,
|
||||
userData: JSON.stringify({
|
||||
whiteboard: drawingSurface
|
||||
})
|
||||
});
|
||||
|
||||
Entities.editEntity(drawingSurface, {
|
||||
userData: JSON.stringify({
|
||||
color: {
|
||||
currentColor: colors[0]
|
||||
},
|
||||
colorIndicator: colorIndicatorBox
|
||||
})
|
||||
});
|
||||
|
||||
//COLOR BOXES
|
||||
var direction = Quat.getRight(rotation);
|
||||
var colorBoxPosition = Vec3.subtract(center, Vec3.multiply(direction, whiteboardDimensions.x / 2));
|
||||
var colorSquareDimensions = {
|
||||
x: 0.13,
|
||||
y: 0.13,
|
||||
z: 0.002
|
||||
};
|
||||
|
||||
var palleteDepthOffset = -0.07;
|
||||
var palleteHeightOffset = -0.28;
|
||||
|
||||
colorBoxPosition = Vec3.sum(colorBoxPosition, Vec3.multiply(palleteDepthOffset, Quat.getFront(rotation)));
|
||||
colorBoxPosition.y += palleteHeightOffset;
|
||||
var spaceBetweenColorBoxes = Vec3.multiply(direction, colorSquareDimensions.x * 1.76);
|
||||
var palleteXOffset = Vec3.multiply(direction, 0.43);
|
||||
colorBoxPosition = Vec3.sum(colorBoxPosition, palleteXOffset);
|
||||
var scriptURL = Script.resolvePath("colorSelectorEntityScript.js");
|
||||
for (var i = 0; i < colors.length; i++) {
|
||||
var colorBox = Entities.addEntity({
|
||||
type: "Box",
|
||||
name: "Color Selector",
|
||||
position: colorBoxPosition,
|
||||
dimensions: colorSquareDimensions,
|
||||
rotation: rotation,
|
||||
color: colors[i],
|
||||
script: scriptURL,
|
||||
userData: JSON.stringify({
|
||||
whiteboard: drawingSurface,
|
||||
colorIndicator: colorIndicatorBox
|
||||
})
|
||||
});
|
||||
colorBoxes.push(colorBox);
|
||||
colorBoxPosition = Vec3.sum(colorBoxPosition, spaceBetweenColorBoxes);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function cleanup() {
|
||||
Entities.deleteEntity(whiteboard);
|
||||
Entities.deleteEntity(eraseAllText);
|
||||
Entities.deleteEntity(blackBox);
|
||||
Entities.deleteEntity(drawingSurface);
|
||||
Entities.deleteEntity(colorIndicatorBorder);
|
||||
Entities.deleteEntity(eraser);
|
||||
Entities.deleteEntity(colorIndicatorBox);
|
||||
Entities.deleteEntity(blocker);
|
||||
Entities.deleteEntity(light);
|
||||
colorBoxes.forEach(function(colorBox) {
|
||||
Entities.deleteEntity(colorBox);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Uncomment this line to delete whiteboard and all associated entity on script close
|
||||
Script.scriptEnding.connect(cleanup);
|
||||
// Script.scriptEnding.connect(cleanup);
|
|
@ -10,7 +10,7 @@
|
|||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
var hand = "left";
|
||||
var hand = "right";
|
||||
var nullActionID = "00000000-0000-0000-0000-000000000000";
|
||||
var controllerID;
|
||||
var controllerActive;
|
||||
|
@ -32,7 +32,7 @@ function makeNewStick() {
|
|||
modelURL: "https://hifi-public.s3.amazonaws.com/eric/models/stick.fbx",
|
||||
compoundShapeURL: "https://hifi-public.s3.amazonaws.com/eric/models/stick.obj",
|
||||
dimensions: {x: .11, y: .11, z: 1.0},
|
||||
position: MyAvatar.getRightPalmPosition(), // initial position doesn't matter, as long as it's close
|
||||
position: MyAvatar.rightHandPosition, // initial position doesn't matter, as long as it's close
|
||||
rotation: MyAvatar.orientation,
|
||||
damping: .1,
|
||||
collisionSoundURL: "http://public.highfidelity.io/sounds/Collisions-hitsandslaps/67LCollision07.wav",
|
||||
|
@ -84,23 +84,15 @@ function mouseMoveEvent(event) {
|
|||
}
|
||||
|
||||
|
||||
function initControls(){
|
||||
if (hand == "right") {
|
||||
controllerID = 3; // right handed
|
||||
} else {
|
||||
controllerID = 4; // left handed
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function update(deltaTime){
|
||||
var palmPosition = Controller.getSpatialControlPosition(controllerID);
|
||||
var handPose = (hand == "right") ? MyAvatar.rightHandPose : MyAvatar.leftHandPose;
|
||||
var palmPosition = handPose.translation;
|
||||
controllerActive = (Vec3.length(palmPosition) > 0);
|
||||
if(!controllerActive){
|
||||
return;
|
||||
}
|
||||
|
||||
stickOrientation = Controller.getSpatialControlRawRotation(controllerID);
|
||||
stickOrientation = handPose.rotation;
|
||||
var adjustment = Quat.fromPitchYawRollDegrees(180, 0, 0);
|
||||
stickOrientation = Quat.multiply(stickOrientation, adjustment);
|
||||
|
||||
|
|
77
examples/tests/controllerInterfaceTest.js
Normal file
77
examples/tests/controllerInterfaceTest.js
Normal file
|
@ -0,0 +1,77 @@
|
|||
ControllerTest = function() {
|
||||
var standard = Controller.Standard;
|
||||
var actions = Controller.Actions;
|
||||
var xbox = Controller.Hardware.GamePad;
|
||||
this.mappingEnabled = false;
|
||||
this.mapping = Controller.newMapping();
|
||||
this.mapping.from(standard.LX).when([standard.LB, standard.RB]).to(actions.Yaw);
|
||||
this.mapping.from(standard.RX).to(actions.StepYaw);
|
||||
this.mapping.from(standard.RY).invert().to(actions.Pitch);
|
||||
this.mapping.from(standard.RY).invert().to(actions.Pitch);
|
||||
|
||||
|
||||
var testMakeAxis = false;
|
||||
if (testMakeAxis) {
|
||||
this.mapping.makeAxis(standard.LB, standard.RB).pulse(0.25).scale(40.0).to(actions.StepYaw);
|
||||
}
|
||||
|
||||
var testStepYaw = false;
|
||||
if (!testMakeAxis && testStepYaw){
|
||||
this.mapping.from(standard.LB).pulse(0.10).invert().scale(40.0).to(actions.StepYaw);
|
||||
this.mapping.from(standard.RB).pulse(0.10).scale(15.0).to(actions.StepYaw);
|
||||
}
|
||||
|
||||
var testFunctionSource = false;
|
||||
if (testFunctionSource) {
|
||||
this.mapping.from(function(){
|
||||
return Math.sin(Date.now() / 250);
|
||||
}).to(actions.Yaw);
|
||||
}
|
||||
|
||||
var testFunctionDest = true;
|
||||
if (testFunctionDest) {
|
||||
this.mapping.from(standard.DU).pulse(1.0).to(function(value){
|
||||
if (value != 0.0) {
|
||||
print(value);
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
this.mapping.enable();
|
||||
this.mappingEnabled = true;
|
||||
|
||||
var dumpInputs = false;
|
||||
if (dumpInputs) {
|
||||
print("Actions");
|
||||
for (var prop in Controller.Actions) {
|
||||
print("\t" + prop);
|
||||
}
|
||||
print("Standard");
|
||||
for (var prop in Controller.Standard) {
|
||||
print("\t" + prop);
|
||||
}
|
||||
print("Hardware");
|
||||
for (var prop in Controller.Hardware) {
|
||||
print("\t" + prop);
|
||||
for (var prop2 in Controller.Hardware[prop]) {
|
||||
print("\t\t" + prop2);
|
||||
}
|
||||
}
|
||||
print("Done");
|
||||
}
|
||||
|
||||
var that = this;
|
||||
Script.scriptEnding.connect(function() {
|
||||
that.onCleanup();
|
||||
});
|
||||
}
|
||||
|
||||
ControllerTest.prototype.onCleanup = function() {
|
||||
if (this.mappingEnabled) {
|
||||
this.mapping.disable();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
new ControllerTest();
|
|
@ -45,6 +45,12 @@
|
|||
green: 255,
|
||||
blue: 255
|
||||
};
|
||||
|
||||
var TRIGGER_CONTROLS = [
|
||||
Controller.Standard.LT,
|
||||
Controller.Standard.RT,
|
||||
];
|
||||
|
||||
|
||||
PingPongGun.prototype = {
|
||||
hand: null,
|
||||
|
@ -53,11 +59,11 @@
|
|||
canShoot: false,
|
||||
canShootTimeout: null,
|
||||
setRightHand: function() {
|
||||
this.hand = 'RIGHT';
|
||||
this.hand = 1;
|
||||
},
|
||||
|
||||
setLeftHand: function() {
|
||||
this.hand = 'LEFT';
|
||||
this.hand = 0;
|
||||
},
|
||||
|
||||
startNearGrab: function() {
|
||||
|
@ -92,12 +98,7 @@
|
|||
},
|
||||
|
||||
checkTriggerPressure: function(gunHand) {
|
||||
var handClickString = gunHand + "_HAND_CLICK";
|
||||
|
||||
var handClick = Controller.findAction(handClickString);
|
||||
|
||||
this.triggerValue = Controller.getActionValue(handClick);
|
||||
|
||||
this.triggerValue = Controller.getValue(TRIGGER_CONTROLS[gunHand]);
|
||||
if (this.triggerValue < RELOAD_THRESHOLD) {
|
||||
// print('RELOAD');
|
||||
this.canShoot = true;
|
||||
|
|
|
@ -33,12 +33,17 @@
|
|||
var MIN_POINT_DISTANCE = 0.01;
|
||||
var STROKE_WIDTH = 0.02;
|
||||
|
||||
var TRIGGER_CONTROLS = [
|
||||
Controller.Standard.LT,
|
||||
Controller.Standard.RT,
|
||||
];
|
||||
|
||||
this.setRightHand = function () {
|
||||
this.hand = 'RIGHT';
|
||||
this.hand = 1;
|
||||
}
|
||||
|
||||
this.setLeftHand = function () {
|
||||
this.hand = 'LEFT';
|
||||
this.hand = 0;
|
||||
}
|
||||
|
||||
this.startNearGrab = function () {
|
||||
|
@ -46,11 +51,7 @@
|
|||
}
|
||||
|
||||
this.toggleWithTriggerPressure = function () {
|
||||
var handClickString = this.whichHand + "_HAND_CLICK";
|
||||
|
||||
var handClick = Controller.findAction(handClickString);
|
||||
|
||||
this.triggerValue = Controller.getActionValue(handClick);
|
||||
this.triggerValue = Controller.getValue(TRIGGER_CONTROLS[this.whichHand]);
|
||||
if (this.triggerValue < DISABLE_SPRAY_THRESHOLD && this.spraying === true) {
|
||||
this.spraying = false;
|
||||
this.disableStream();
|
||||
|
|
|
@ -2,7 +2,12 @@ set(TARGET_NAME interface)
|
|||
project(${TARGET_NAME})
|
||||
|
||||
# set a default root dir for each of our optional externals if it was not passed
|
||||
set(OPTIONAL_EXTERNALS "Faceshift" "LeapMotion" "RtMidi" "RSSDK" "3DConnexionClient" "iViewHMD")
|
||||
set(OPTIONAL_EXTERNALS "LeapMotion" "RtMidi" "RSSDK" "iViewHMD")
|
||||
|
||||
if(WIN32)
|
||||
list(APPEND OPTIONAL_EXTERNALS "3DConnexionClient")
|
||||
endif()
|
||||
|
||||
foreach(EXTERNAL ${OPTIONAL_EXTERNALS})
|
||||
string(TOUPPER ${EXTERNAL} ${EXTERNAL}_UPPERCASE)
|
||||
if (NOT ${${EXTERNAL}_UPPERCASE}_ROOT_DIR)
|
||||
|
@ -99,15 +104,17 @@ endif()
|
|||
link_hifi_libraries(shared octree environment gpu gl procedural model render
|
||||
fbx networking model-networking entities avatars
|
||||
audio audio-client animation script-engine physics
|
||||
render-utils entities-renderer ui auto-updater
|
||||
plugins display-plugins input-plugins)
|
||||
render-utils entities-renderer ui auto-updater
|
||||
controllers plugins display-plugins input-plugins )
|
||||
|
||||
#fixme find a way to express faceshift as a plugin
|
||||
target_bullet()
|
||||
target_glew()
|
||||
target_opengl()
|
||||
|
||||
|
||||
add_dependency_external_projects(sdl2)
|
||||
if (WIN32 OR APPLE)
|
||||
target_faceshift()
|
||||
endif()
|
||||
|
||||
# perform standard include and linking for found externals
|
||||
foreach(EXTERNAL ${OPTIONAL_EXTERNALS})
|
||||
|
|
26
interface/external/faceshift/readme.txt
vendored
26
interface/external/faceshift/readme.txt
vendored
|
@ -1,26 +0,0 @@
|
|||
|
||||
Instructions for adding the Faceshift library to Interface
|
||||
Stephen Birarda, July 18th, 2014
|
||||
|
||||
OS X users: You can also use homebrew to get the Faceshift library by tapping our repo - highfidelity/homebrew-formulas
|
||||
and then calling 'brew install highfidelity/formulas/faceshift'.
|
||||
|
||||
You can download the Faceshift SDK from http://download.faceshift.com/faceshift-network.zip.
|
||||
|
||||
Create a ‘faceshift’ folder under interface/externals.
|
||||
|
||||
You may optionally choose to place this folder in a location outside the repository (so you can re-use with different checkouts and different projects).
|
||||
|
||||
If so our CMake find module expects you to set the ENV variable 'HIFI_LIB_DIR' to a directory containing a subfolder ‘faceshift’ that contains the lib and include folders.
|
||||
|
||||
1. Build a Faceshift static library from the fsbinarystream.cpp file.
|
||||
Windows: Win32 console application; no precompiled header or SDL checks; no ATL or MFC headers; Project Properties, Configuration Type = Static Library (.lib).
|
||||
|
||||
2. Copy the library files to the ‘lib’ folder in your Faceshift folder.
|
||||
OSX: If you build a release version call it libfaceshift.a. The debug version should be called libfaceshiftd.a.
|
||||
Windows: The release and debug versions should be called faceshift.lib and faceshiftd.lib, respectively. Copy them into a ‘Win32’ folder in your ‘lib’ folder.
|
||||
|
||||
3. Copy the fsbinarystream.h header file from the Faceshift SDK into the ‘include’ folder in your Faceshift folder.
|
||||
|
||||
4. Clear your build directory, run cmake and build, and you should be all set.
|
||||
|
13
interface/external/sdl2/readme.txt
vendored
13
interface/external/sdl2/readme.txt
vendored
|
@ -1,13 +0,0 @@
|
|||
|
||||
Instructions for adding the SDL library (SDL2) to Interface
|
||||
David Rowe, 11 Jan 2015
|
||||
|
||||
You can download the SDL development library from https://www.libsdl.org/. Interface has been tested with version 2.0.3.
|
||||
|
||||
1. Copy the include and lib folders into the interface/externals/sdl2 folder.
|
||||
This readme.txt should be there as well.
|
||||
|
||||
You may optionally choose to copy the SDK folders to a location outside the repository (so you can re-use with different checkouts and different projects).
|
||||
If so our CMake find module expects you to set the ENV variable 'HIFI_LIB_DIR' to a directory containing a subfolder 'sdl2' that contains the two folders mentioned above.
|
||||
|
||||
2. Clear your build directory, run cmake and build, and you should be all set.
|
10
interface/external/sixense/readme.txt
vendored
10
interface/external/sixense/readme.txt
vendored
|
@ -1,10 +0,0 @@
|
|||
|
||||
Instructions for adding the Sixense driver to Interface
|
||||
Andrzej Kapolka, November 18, 2013
|
||||
|
||||
1. Copy the Sixense sdk folders (bin, include, lib, and samples) into the interface/external/Sixense folder. This readme.txt should be there as well.
|
||||
|
||||
You may optionally choose to copy the SDK folders to a location outside the repository (so you can re-use with different checkouts and different projects).
|
||||
If so our CMake find module expects you to set the ENV variable 'HIFI_LIB_DIR' to a directory containing a subfolder 'sixense' that contains the folders mentioned above.
|
||||
|
||||
3. Delete your build directory, run cmake and build, and you should be all set.
|
31
interface/resources/controllers/hydra.json
Normal file
31
interface/resources/controllers/hydra.json
Normal file
|
@ -0,0 +1,31 @@
|
|||
{
|
||||
"name": "Hydra to Standard",
|
||||
"channels": [
|
||||
{ "from": "Hydra.LY", "filters": "invert", "to": "Standard.LY" },
|
||||
{ "from": "Hydra.LX", "to": "Standard.LX" },
|
||||
{ "from": "Hydra.LT", "to": "Standard.LT" },
|
||||
{ "from": "Hydra.RY", "filters": "invert", "to": "Standard.RY" },
|
||||
{ "from": "Hydra.RX", "to": "Standard.RX" },
|
||||
{ "from": "Hydra.RT", "to": "Standard.RT" },
|
||||
|
||||
{ "from": "Hydra.LB", "to": "Standard.LB" },
|
||||
{ "from": "Hydra.LS", "to": "Standard.LS" },
|
||||
{ "from": "Hydra.RB", "to": "Standard.RB" },
|
||||
{ "from": "Hydra.RS", "to": "Standard.RS" },
|
||||
|
||||
{ "from": "Hydra.L0", "to": "Standard.Back" },
|
||||
{ "from": "Hydra.L1", "to": "Standard.DL" },
|
||||
{ "from": "Hydra.L2", "to": "Standard.DD" },
|
||||
{ "from": "Hydra.L3", "to": "Standard.DR" },
|
||||
{ "from": "Hydra.L4", "to": "Standard.DU" },
|
||||
|
||||
{ "from": "Hydra.R0", "to": "Standard.Start" },
|
||||
{ "from": "Hydra.R1", "to": "Standard.X" },
|
||||
{ "from": "Hydra.R2", "to": "Standard.A" },
|
||||
{ "from": "Hydra.R3", "to": "Standard.B" },
|
||||
{ "from": "Hydra.R4", "to": "Standard.Y" },
|
||||
|
||||
{ "from": "Hydra.LeftHand", "to": "Standard.LeftHand" },
|
||||
{ "from": "Hydra.RightHand", "to": "Standard.RightHand" }
|
||||
]
|
||||
}
|
86
interface/resources/controllers/keyboardMouse.json
Normal file
86
interface/resources/controllers/keyboardMouse.json
Normal file
|
@ -0,0 +1,86 @@
|
|||
{
|
||||
"name": "Keyboard/Mouse to Actions",
|
||||
"channels": [
|
||||
|
||||
{ "from": "Keyboard.A", "when": "Keyboard.Shift", "to": "Actions.LATERAL_LEFT" },
|
||||
{ "from": "Keyboard.D", "when": "Keyboard.Shift", "to": "Actions.LATERAL_RIGHT" },
|
||||
{ "from": "Keyboard.A", "when": "Keyboard.RightMouseClick", "to": "Actions.LATERAL_LEFT" },
|
||||
{ "from": "Keyboard.D", "when": "Keyboard.RightMouseClick", "to": "Actions.LATERAL_RIGHT" },
|
||||
{ "from": "Keyboard.E", "when": "Keyboard.Shift", "to": "Actions.BOOM_IN", "filters": [ { "type": "scale", "scale": 0.05 } ] },
|
||||
{ "from": "Keyboard.C", "when": "Keyboard.Shift", "to": "Actions.BOOM_OUT", "filters": [ { "type": "scale", "scale": 0.05 } ] },
|
||||
{ "from": "Keyboard.S", "when": "Keyboard.Shift", "to": "Actions.PITCH_DOWN" },
|
||||
{ "from": "Keyboard.W", "when": "Keyboard.Shift", "to": "Actions.PITCH_UP" },
|
||||
|
||||
|
||||
{ "from": { "makeAxis" : ["Keyboard.MouseMoveLeft", "Keyboard.MouseMoveRight"] },
|
||||
"when": [ "Application.InHMD", "Application.ComfortMode", "Keyboard.RightMouseClick" ],
|
||||
"to": "Actions.StepYaw",
|
||||
"filters":
|
||||
[
|
||||
"constrainToInteger",
|
||||
{ "type": "pulse", "interval": 0.5 },
|
||||
{ "type": "scale", "scale": 15 }
|
||||
]
|
||||
},
|
||||
|
||||
{ "from": { "makeAxis" : [
|
||||
["Keyboard.A", "Keyboard.Left", "Keyboard.TouchpadLeft"],
|
||||
["Keyboard.D", "Keyboard.Right", "Keyboard.TouchpadRight"]
|
||||
]
|
||||
},
|
||||
"when": [ "Application.InHMD", "Application.ComfortMode" ],
|
||||
"to": "Actions.StepYaw",
|
||||
"filters":
|
||||
[
|
||||
{ "type": "pulse", "interval": 0.5 },
|
||||
{ "type": "scale", "scale": 15 }
|
||||
]
|
||||
},
|
||||
|
||||
{ "from": { "makeAxis" : [
|
||||
["Keyboard.A", "Keyboard.Left", "Keyboard.TouchpadLeft"],
|
||||
["Keyboard.D", "Keyboard.Right", "Keyboard.TouchpadRight"]
|
||||
]
|
||||
},
|
||||
"to": "Actions.Yaw"
|
||||
},
|
||||
|
||||
{ "from": { "makeAxis" : ["Keyboard.MouseMoveLeft", "Keyboard.MouseMoveRight"] },
|
||||
"when": "Keyboard.RightMouseClick",
|
||||
"to": "Actions.Yaw"
|
||||
},
|
||||
|
||||
{ "from": "Keyboard.W", "to": "Actions.LONGITUDINAL_FORWARD" },
|
||||
{ "from": "Keyboard.S", "to": "Actions.LONGITUDINAL_BACKWARD" },
|
||||
{ "from": "Keyboard.C", "to": "Actions.VERTICAL_DOWN" },
|
||||
{ "from": "Keyboard.E", "to": "Actions.VERTICAL_UP" },
|
||||
|
||||
{ "from": "Keyboard.Left", "when": "Keyboard.RightMouseClick", "to": "Actions.LATERAL_LEFT" },
|
||||
{ "from": "Keyboard.Right", "when": "Keyboard.RightMouseClick", "to": "Actions.LATERAL_RIGHT" },
|
||||
{ "from": "Keyboard.Left", "when": "Keyboard.Shift", "to": "Actions.LATERAL_LEFT" },
|
||||
{ "from": "Keyboard.Right", "when": "Keyboard.Shift", "to": "Actions.LATERAL_RIGHT" },
|
||||
{ "from": "Keyboard.Down", "when": "Keyboard.Shift", "to": "Actions.PITCH_DOWN" },
|
||||
{ "from": "Keyboard.Up", "when": "Keyboard.Shift", "to": "Actions.PITCH_UP" },
|
||||
|
||||
{ "from": "Keyboard.Up", "to": "Actions.LONGITUDINAL_FORWARD" },
|
||||
{ "from": "Keyboard.Down", "to": "Actions.LONGITUDINAL_BACKWARD" },
|
||||
|
||||
{ "from": "Keyboard.PgDown", "to": "Actions.VERTICAL_DOWN" },
|
||||
{ "from": "Keyboard.PgUp", "to": "Actions.VERTICAL_UP" },
|
||||
|
||||
{ "from": "Keyboard.MouseMoveUp", "when": "Keyboard.RightMouseClick", "to": "Actions.PITCH_UP" },
|
||||
{ "from": "Keyboard.MouseMoveDown", "when": "Keyboard.RightMouseClick", "to": "Actions.PITCH_DOWN" },
|
||||
|
||||
{ "from": "Keyboard.TouchpadDown", "to": "Actions.PITCH_DOWN" },
|
||||
{ "from": "Keyboard.TouchpadUp", "to": "Actions.PITCH_UP" },
|
||||
|
||||
{ "from": "Keyboard.MouseWheelUp", "to": "Actions.LATERAL_RIGHT" },
|
||||
{ "from": "Keyboard.MouseWheelDown", "to": "Actions.LATERAL_LEFT" },
|
||||
{ "from": "Keyboard.MouseWheelLeft", "to": "Actions.BOOM_OUT", "filters": [ { "type": "scale", "scale": 0.02 } ]},
|
||||
{ "from": "Keyboard.MouseWheelRight", "to": "Actions.BOOM_IN", "filters": [ { "type": "scale", "scale": 0.02 } ]},
|
||||
|
||||
{ "from": "Keyboard.Space", "to": "Actions.SHIFT" },
|
||||
{ "from": "Keyboard.R", "to": "Actions.ACTION1" },
|
||||
{ "from": "Keyboard.T", "to": "Actions.ACTION2" }
|
||||
]
|
||||
}
|
24
interface/resources/controllers/mapping-config.json
Normal file
24
interface/resources/controllers/mapping-config.json
Normal file
|
@ -0,0 +1,24 @@
|
|||
{
|
||||
"name": "Full Mapping config including the standard hydra and gamepad and one more thing",
|
||||
"mappings": [
|
||||
{ "src": "./mapping-hydra.json" },
|
||||
{ "src": "./mapping-xbox.json" },
|
||||
{
|
||||
"name": "example mapping for standard to js function",
|
||||
"channels": [ {
|
||||
"from": "Standard.B",
|
||||
"to": {
|
||||
"type":"js",
|
||||
"function": "function(value){ print(\"Standard.B = \" + value );}"
|
||||
}
|
||||
}, {
|
||||
"from": "Standard.B",
|
||||
"to": {
|
||||
"type":"js",
|
||||
"src": "http://www.theNextBigThing.com/hifiInputSignalHandler.js"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
36
interface/resources/controllers/mapping-test0.json
Normal file
36
interface/resources/controllers/mapping-test0.json
Normal file
|
@ -0,0 +1,36 @@
|
|||
{
|
||||
"name": "example mapping from Standard to actions",
|
||||
"channels": [ {
|
||||
"from": "Standard.LY",
|
||||
"filters": [ {
|
||||
"type": "clamp",
|
||||
"min": 0,
|
||||
"max": 1
|
||||
}
|
||||
],
|
||||
"to": "Actions.Forward"
|
||||
}, {
|
||||
"from": "Standard.LY",
|
||||
"filters": [ {
|
||||
"type": "clamp",
|
||||
"min": -1,
|
||||
"max": 0
|
||||
}, {
|
||||
"type": "invert"
|
||||
}
|
||||
],
|
||||
"to": "Actions.Backward"
|
||||
}, {
|
||||
"from": "Standard.LX",
|
||||
"filters": [ {
|
||||
"type": "scale",
|
||||
"scale": 2.0
|
||||
}
|
||||
],
|
||||
"to": "Actions.Yaw"
|
||||
}, {
|
||||
"from": "Standard.A",
|
||||
"to": "Actions.Action0"
|
||||
}
|
||||
]
|
||||
}
|
43
interface/resources/controllers/standard-old.json
Normal file
43
interface/resources/controllers/standard-old.json
Normal file
|
@ -0,0 +1,43 @@
|
|||
{
|
||||
"name": "Standard to Action",
|
||||
"channels": [
|
||||
{ "from": "Standard.LY", "to": "Actions.TranslateZ" },
|
||||
{ "from": "Standard.LX", "to": "Actions.TranslateX" },
|
||||
{ "from": "Standard.RX", "to": "Actions.Yaw" },
|
||||
{ "from": "Standard.RY", "to": "Actions.Pitch" },
|
||||
{
|
||||
"from": "Standard.DU",
|
||||
"to": "Actions.LONGITUDINAL_FORWARD",
|
||||
"filters": [ { "type": "scale", "scale": 0.5 } ]
|
||||
},
|
||||
{
|
||||
"from": "Standard.DD",
|
||||
"to": "Actions.LONGITUDINAL_BACKWARD",
|
||||
"filters": [ { "type": "scale", "scale": 0.5 } ]
|
||||
},
|
||||
{
|
||||
"from": "Standard.DR",
|
||||
"to": "Actions.LATERAL_RIGHT",
|
||||
"filters": [ { "type": "scale", "scale": 0.5 } ]
|
||||
},
|
||||
{
|
||||
"from": "Standard.DL",
|
||||
"to": "Actions.LATERAL_LEFT",
|
||||
"filters": [ { "type": "scale", "scale": 0.5 } ]
|
||||
},
|
||||
{ "from": "Standard.Y", "to": "Actions.VERTICAL_UP" },
|
||||
{ "from": "Standard.X", "to": "Actions.VERTICAL_DOWN" },
|
||||
{
|
||||
"from": "Standard.RT",
|
||||
"to": "Actions.BOOM_IN",
|
||||
"filters": [ { "type": "scale", "scale": 0.1 } ]
|
||||
},
|
||||
{
|
||||
"from": "Standard.LT",
|
||||
"to": "Actions.BOOM_OUT",
|
||||
"filters": [ { "type": "scale", "scale": 0.1 } ]
|
||||
},
|
||||
{ "from": "Standard.LeftHand", "to": "Actions.LEFT_HAND" },
|
||||
{ "from": "Standard.RightHand", "to": "Actions.RIGHT_HAND" }
|
||||
]
|
||||
}
|
39
interface/resources/controllers/standard.json
Normal file
39
interface/resources/controllers/standard.json
Normal file
|
@ -0,0 +1,39 @@
|
|||
{
|
||||
"name": "Standard to Action",
|
||||
"channels": [
|
||||
{ "from": "Standard.LY", "to": "Actions.TranslateZ" },
|
||||
{ "from": "Standard.LX", "to": "Actions.TranslateX" },
|
||||
|
||||
{ "from": "Standard.RX",
|
||||
"when": [ "Application.InHMD", "Application.ComfortMode" ],
|
||||
"to": "Actions.StepYaw",
|
||||
"filters":
|
||||
[
|
||||
{ "type": "pulse", "interval": 0.5 },
|
||||
{ "type": "scale", "scale": 15 }
|
||||
]
|
||||
},
|
||||
|
||||
|
||||
{ "from": "Standard.RX", "to": "Actions.Yaw" },
|
||||
{ "from": "Standard.RY", "filters": "invert", "to": "Actions.TranslateY" },
|
||||
|
||||
|
||||
{ "from": [ "Standard.DU", "Standard.DL", "Standard.DR", "Standard.DD" ], "to": "Standard.LeftPrimaryThumb" },
|
||||
{ "from": "Standard.Back", "to": "Standard.LeftSecondaryThumb" },
|
||||
|
||||
{ "from": [ "Standard.A", "Standard.B", "Standard.X", "Standard.Y" ], "to": "Standard.RightPrimaryThumb" },
|
||||
{ "from": "Standard.Start", "to": "Standard.RightSecondaryThumb" },
|
||||
|
||||
{ "from": "Standard.LeftSecondaryThumb", "to": "Actions.CycleCamera" },
|
||||
{ "from": "Standard.RightSecondaryThumb", "to": "Actions.ContextMenu" },
|
||||
|
||||
{ "from": "Standard.LT", "to": "Actions.LeftHandClick" },
|
||||
{ "from": "Standard.RT", "to": "Actions.RightHandClick" },
|
||||
|
||||
{ "from": "Standard.LeftHand", "to": "Actions.LeftHand" },
|
||||
{ "from": "Standard.RightHand", "to": "Actions.RightHand" }
|
||||
]
|
||||
}
|
||||
|
||||
|
26
interface/resources/controllers/vive.json
Normal file
26
interface/resources/controllers/vive.json
Normal file
|
@ -0,0 +1,26 @@
|
|||
{
|
||||
"name": "Vive to Standard",
|
||||
"channels": [
|
||||
{ "from": "Vive.LY", "filters": [ "invert", { "type": "deadZone", "min": 0.7 } ], "to": "Standard.LY" },
|
||||
{ "from": "Vive.LX", "filters": { "type": "deadZone", "min": 0.7 }, "to": "Standard.LX" },
|
||||
|
||||
{ "from": "Vive.LT", "to": "Standard.LT" },
|
||||
{ "from": "Vive.LB", "to": "Standard.LB" },
|
||||
{ "from": "Vive.LS", "to": "Standard.LS" },
|
||||
|
||||
{ "from": "Vive.RY", "filters": "invert", "to": "Standard.RY" },
|
||||
{ "from": "Vive.RX", "to": "Standard.RX" },
|
||||
|
||||
{ "from": "Vive.RT", "to": "Standard.RT" },
|
||||
{ "from": "Vive.RB", "to": "Standard.RB" },
|
||||
{ "from": "Vive.RS", "to": "Standard.RS" },
|
||||
|
||||
{ "from": "Vive.LeftPrimaryThumb", "to": "Standard.LeftPrimaryThumb" },
|
||||
{ "from": "Vive.RightPrimaryThumb", "to": "Standard.RightPrimaryThumb" },
|
||||
{ "from": "Vive.LeftSecondaryThumb", "to": "Standard.LeftSecondaryThumb" },
|
||||
{ "from": "Vive.RightSecondaryThumb", "to": "Standard.RightSecondaryThumb" },
|
||||
|
||||
{ "from": "Vive.LeftHand", "to": "Standard.LeftHand" },
|
||||
{ "from": "Vive.RightHand", "to": "Standard.RightHand" }
|
||||
]
|
||||
}
|
29
interface/resources/controllers/xbox.json
Normal file
29
interface/resources/controllers/xbox.json
Normal file
|
@ -0,0 +1,29 @@
|
|||
{
|
||||
"name": "XBox to Standard",
|
||||
"channels": [
|
||||
{ "from": "GamePad.LY", "to": "Standard.LY" },
|
||||
{ "from": "GamePad.LX", "to": "Standard.LX" },
|
||||
{ "from": "GamePad.LT", "to": "Standard.LT" },
|
||||
{ "from": "GamePad.LB", "to": "Standard.LB" },
|
||||
{ "from": "GamePad.LS", "to": "Standard.LS" },
|
||||
|
||||
{ "from": "GamePad.RY", "to": "Standard.RY" },
|
||||
{ "from": "GamePad.RX", "to": "Standard.RX" },
|
||||
{ "from": "GamePad.RT", "to": "Standard.RT" },
|
||||
{ "from": "GamePad.RB", "to": "Standard.RB" },
|
||||
{ "from": "GamePad.RS", "to": "Standard.RS" },
|
||||
|
||||
{ "from": "GamePad.Back", "to": "Standard.Back" },
|
||||
{ "from": "GamePad.Start", "to": "Standard.Start" },
|
||||
|
||||
{ "from": "GamePad.DU", "to": "Standard.DU" },
|
||||
{ "from": "GamePad.DD", "to": "Standard.DD" },
|
||||
{ "from": "GamePad.DL", "to": "Standard.DL" },
|
||||
{ "from": "GamePad.DR", "to": "Standard.DR" },
|
||||
|
||||
{ "from": "GamePad.A", "to": "Standard.A" },
|
||||
{ "from": "GamePad.B", "to": "Standard.B" },
|
||||
{ "from": "GamePad.X", "to": "Standard.X" },
|
||||
{ "from": "GamePad.Y", "to": "Standard.Y" }
|
||||
]
|
||||
}
|
|
@ -197,7 +197,7 @@
|
|||
"id": "rightHandOpen",
|
||||
"type": "clip",
|
||||
"data": {
|
||||
"url": "http://hifi-public.s3.amazonaws.com/ozan/anim/hand_anims/point_right_hand.fbx",
|
||||
"url": "https://hifi-public.s3.amazonaws.com/ozan/anim/grab/grab_right.fbx",
|
||||
"startFrame": 0.0,
|
||||
"endFrame": 0.0,
|
||||
"timeScale": 1.0,
|
||||
|
@ -209,9 +209,9 @@
|
|||
"id": "rightHandClose",
|
||||
"type": "clip",
|
||||
"data": {
|
||||
"url": "http://hifi-public.s3.amazonaws.com/ozan/anim/squeeze_hands/right_hand_anim.fbx",
|
||||
"startFrame": 15.0,
|
||||
"endFrame": 15.0,
|
||||
"url": "https://hifi-public.s3.amazonaws.com/ozan/anim/grab/grab_right.fbx",
|
||||
"startFrame": 10.0,
|
||||
"endFrame": 10.0,
|
||||
"timeScale": 1.0,
|
||||
"loopFlag": true
|
||||
},
|
||||
|
@ -346,7 +346,7 @@
|
|||
"id": "leftHandOpen",
|
||||
"type": "clip",
|
||||
"data": {
|
||||
"url": "http://hifi-public.s3.amazonaws.com/ozan/anim/hand_anims/point_left_hand.fbx",
|
||||
"url": "https://hifi-public.s3.amazonaws.com/ozan/anim/grab/grab_left.fbx",
|
||||
"startFrame": 0.0,
|
||||
"endFrame": 0.0,
|
||||
"timeScale": 1.0,
|
||||
|
@ -358,9 +358,9 @@
|
|||
"id": "leftHandClose",
|
||||
"type": "clip",
|
||||
"data": {
|
||||
"url": "http://hifi-public.s3.amazonaws.com/ozan/anim/squeeze_hands/left_hand_anim.fbx",
|
||||
"startFrame": 15.0,
|
||||
"endFrame": 15.0,
|
||||
"url": "https://hifi-public.s3.amazonaws.com/ozan/anim/grab/grab_left.fbx",
|
||||
"startFrame": 10.0,
|
||||
"endFrame": 10.0,
|
||||
"timeScale": 1.0,
|
||||
"loopFlag": true
|
||||
},
|
||||
|
|
111
interface/resources/qml/ScrollingGraph.qml
Normal file
111
interface/resources/qml/ScrollingGraph.qml
Normal file
|
@ -0,0 +1,111 @@
|
|||
import QtQuick 2.1
|
||||
import QtQuick.Controls 1.0
|
||||
import QtQuick.Layouts 1.0
|
||||
import QtQuick.Dialogs 1.0
|
||||
|
||||
Rectangle {
|
||||
id: root
|
||||
property int size: 64
|
||||
width: size
|
||||
height: size
|
||||
color: 'black'
|
||||
property int controlId: 0
|
||||
property real value: 0.5
|
||||
property int scrollWidth: 1
|
||||
property real min: 0.0
|
||||
property real max: 1.0
|
||||
property bool log: false
|
||||
property real range: max - min
|
||||
property color lineColor: 'yellow'
|
||||
property bool bar: false
|
||||
property real lastHeight: -1
|
||||
property string label: ""
|
||||
|
||||
function update() {
|
||||
value = Controller.getValue(controlId);
|
||||
if (log) {
|
||||
var log = Math.log(10) / Math.log(Math.abs(value));
|
||||
var sign = Math.sign(value);
|
||||
value = log * sign;
|
||||
}
|
||||
canvas.requestPaint();
|
||||
}
|
||||
|
||||
function drawHeight() {
|
||||
if (value < min) {
|
||||
return 0;
|
||||
}
|
||||
if (value > max) {
|
||||
return height;
|
||||
}
|
||||
return ((value - min) / range) * height;
|
||||
}
|
||||
|
||||
Timer {
|
||||
interval: 50; running: true; repeat: true
|
||||
onTriggered: root.update()
|
||||
}
|
||||
|
||||
Canvas {
|
||||
id: canvas
|
||||
anchors.fill: parent
|
||||
antialiasing: false
|
||||
|
||||
Text {
|
||||
anchors.top: parent.top
|
||||
text: root.label
|
||||
color: 'white'
|
||||
}
|
||||
|
||||
Text {
|
||||
anchors.right: parent.right
|
||||
anchors.top: parent.top
|
||||
text: root.max
|
||||
color: 'white'
|
||||
}
|
||||
|
||||
Text {
|
||||
anchors.right: parent.right
|
||||
anchors.bottom: parent.bottom
|
||||
text: root.min
|
||||
color: 'white'
|
||||
}
|
||||
|
||||
function scroll() {
|
||||
var ctx = canvas.getContext('2d');
|
||||
var image = ctx.getImageData(0, 0, canvas.width, canvas.height);
|
||||
ctx.beginPath();
|
||||
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
||||
ctx.drawImage(image, -root.scrollWidth, 0, canvas.width, canvas.height)
|
||||
ctx.restore()
|
||||
}
|
||||
|
||||
onPaint: {
|
||||
scroll();
|
||||
var ctx = canvas.getContext('2d');
|
||||
ctx.save();
|
||||
var currentHeight = root.drawHeight();
|
||||
if (root.lastHeight == -1) {
|
||||
root.lastHeight = currentHeight
|
||||
}
|
||||
|
||||
// var x = canvas.width - root.drawWidth;
|
||||
// var y = canvas.height - drawHeight;
|
||||
// ctx.fillStyle = root.color
|
||||
// ctx.fillRect(x, y, root.drawWidth, root.bar ? drawHeight : 1)
|
||||
// ctx.fill();
|
||||
// ctx.restore()
|
||||
|
||||
|
||||
ctx.beginPath();
|
||||
ctx.lineWidth = 1
|
||||
ctx.strokeStyle = root.lineColor
|
||||
ctx.moveTo(canvas.width - root.scrollWidth, root.lastHeight).lineTo(canvas.width, currentHeight)
|
||||
ctx.stroke()
|
||||
ctx.restore()
|
||||
root.lastHeight = currentHeight
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
161
interface/resources/qml/TestControllers.qml
Normal file
161
interface/resources/qml/TestControllers.qml
Normal file
|
@ -0,0 +1,161 @@
|
|||
import QtQuick 2.3
|
||||
import QtQuick.Controls 1.2
|
||||
import QtQuick.Layouts 1.0
|
||||
import QtQuick.Dialogs 1.0
|
||||
|
||||
import "controller"
|
||||
import "controls" as HifiControls
|
||||
import "styles"
|
||||
|
||||
HifiControls.VrDialog {
|
||||
id: root
|
||||
HifiConstants { id: hifi }
|
||||
title: "Controller Test"
|
||||
resizable: true
|
||||
contentImplicitWidth: clientArea.implicitWidth
|
||||
contentImplicitHeight: clientArea.implicitHeight
|
||||
backgroundColor: "beige"
|
||||
|
||||
property var actions: Controller.Actions
|
||||
property var standard: Controller.Standard
|
||||
property var hydra: null
|
||||
property var testMapping: null
|
||||
property bool testMappingEnabled: false
|
||||
property var xbox: null
|
||||
|
||||
function buildMapping() {
|
||||
testMapping = Controller.newMapping();
|
||||
testMapping.fromQml(standard.RY).invert().toQml(actions.Pitch);
|
||||
testMapping.fromQml(function(){
|
||||
return Math.sin(Date.now() / 250);
|
||||
}).toQml(actions.Yaw);
|
||||
//testMapping.makeAxis(standard.LB, standard.RB).to(actions.Yaw);
|
||||
// Step yaw takes a number of degrees
|
||||
testMapping.fromQml(standard.LB).pulse(0.10).invert().scale(40.0).toQml(actions.StepYaw);
|
||||
testMapping.fromQml(standard.RB).pulse(0.10).scale(15.0).toQml(actions.StepYaw);
|
||||
testMapping.fromQml(standard.RX).scale(15.0).toQml(actions.StepYaw);
|
||||
}
|
||||
|
||||
function toggleMapping() {
|
||||
testMapping.enable(!testMappingEnabled);
|
||||
testMappingEnabled = !testMappingEnabled;
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
enabled = true
|
||||
var xboxRegex = /^GamePad/;
|
||||
var hydraRegex = /^Hydra/;
|
||||
for (var prop in Controller.Hardware) {
|
||||
if(xboxRegex.test(prop)) {
|
||||
root.xbox = Controller.Hardware[prop]
|
||||
print("found xbox")
|
||||
continue
|
||||
}
|
||||
if (hydraRegex.test(prop)) {
|
||||
root.hydra = Controller.Hardware[prop]
|
||||
print("found hydra")
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Column {
|
||||
id: clientArea
|
||||
spacing: 12
|
||||
x: root.clientX
|
||||
y: root.clientY
|
||||
|
||||
Row {
|
||||
spacing: 8
|
||||
|
||||
Button {
|
||||
text: !root.testMapping ? "Build Mapping" : (root.testMappingEnabled ? "Disable Mapping" : "Enable Mapping")
|
||||
onClicked: {
|
||||
|
||||
if (!root.testMapping) {
|
||||
root.buildMapping()
|
||||
} else {
|
||||
root.toggleMapping();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Row {
|
||||
Standard { device: root.standard; label: "Standard"; width: 180 }
|
||||
}
|
||||
|
||||
Row {
|
||||
spacing: 8
|
||||
Xbox { device: root.xbox; label: "XBox"; width: 180 }
|
||||
Hydra { device: root.hydra; width: 180 }
|
||||
}
|
||||
|
||||
Row {
|
||||
spacing: 4
|
||||
ScrollingGraph {
|
||||
controlId: Controller.Actions.Yaw
|
||||
label: "Yaw"
|
||||
min: -2.0
|
||||
max: 2.0
|
||||
size: 64
|
||||
}
|
||||
|
||||
ScrollingGraph {
|
||||
controlId: Controller.Actions.YawLeft
|
||||
label: "Yaw Left"
|
||||
min: -2.0
|
||||
max: 2.0
|
||||
size: 64
|
||||
}
|
||||
|
||||
ScrollingGraph {
|
||||
controlId: Controller.Actions.YawRight
|
||||
label: "Yaw Right"
|
||||
min: -2.0
|
||||
max: 2.0
|
||||
size: 64
|
||||
}
|
||||
|
||||
ScrollingGraph {
|
||||
controlId: Controller.Actions.StepYaw
|
||||
label: "StepYaw"
|
||||
min: -20.0
|
||||
max: 20.0
|
||||
size: 64
|
||||
}
|
||||
}
|
||||
|
||||
Row {
|
||||
ScrollingGraph {
|
||||
controlId: Controller.Actions.TranslateZ
|
||||
label: "TranslateZ"
|
||||
min: -2.0
|
||||
max: 2.0
|
||||
size: 64
|
||||
}
|
||||
|
||||
ScrollingGraph {
|
||||
controlId: Controller.Actions.Forward
|
||||
label: "Forward"
|
||||
min: -2.0
|
||||
max: 2.0
|
||||
size: 64
|
||||
}
|
||||
|
||||
ScrollingGraph {
|
||||
controlId: Controller.Actions.Backward
|
||||
label: "Backward"
|
||||
min: -2.0
|
||||
max: 2.0
|
||||
size: 64
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
} // dialog
|
||||
|
||||
|
||||
|
||||
|
||||
|
45
interface/resources/qml/controller/AnalogButton.qml
Normal file
45
interface/resources/qml/controller/AnalogButton.qml
Normal file
|
@ -0,0 +1,45 @@
|
|||
import QtQuick 2.1
|
||||
import QtQuick.Controls 1.0
|
||||
import QtQuick.Layouts 1.0
|
||||
import QtQuick.Dialogs 1.0
|
||||
|
||||
Item {
|
||||
id: root
|
||||
property int size: 64
|
||||
width: size
|
||||
height: size
|
||||
property int controlId: 0
|
||||
property real value: 0
|
||||
property color color: 'black'
|
||||
|
||||
function update() {
|
||||
value = controlId ? Controller.getValue(controlId) : 0;
|
||||
canvas.requestPaint();
|
||||
}
|
||||
|
||||
Timer {
|
||||
interval: 50; running: true; repeat: true
|
||||
onTriggered: root.update();
|
||||
}
|
||||
|
||||
Canvas {
|
||||
id: canvas
|
||||
anchors.fill: parent
|
||||
antialiasing: false
|
||||
|
||||
onPaint: {
|
||||
var ctx = canvas.getContext('2d');
|
||||
ctx.save();
|
||||
ctx.beginPath();
|
||||
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
||||
var fillHeight = root.value * canvas.height;
|
||||
|
||||
ctx.fillStyle = 'red'
|
||||
ctx.fillRect(0, canvas.height - fillHeight, canvas.width, fillHeight);
|
||||
ctx.fill();
|
||||
ctx.restore()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
55
interface/resources/qml/controller/AnalogStick.qml
Normal file
55
interface/resources/qml/controller/AnalogStick.qml
Normal file
|
@ -0,0 +1,55 @@
|
|||
import QtQuick 2.1
|
||||
import QtQuick.Controls 1.0
|
||||
import QtQuick.Layouts 1.0
|
||||
import QtQuick.Dialogs 1.0
|
||||
|
||||
Item {
|
||||
id: root
|
||||
property int size: 64
|
||||
width: size
|
||||
height: size
|
||||
property bool invertY: false
|
||||
|
||||
|
||||
property int halfSize: size / 2
|
||||
property var controlIds: [ 0, 0 ]
|
||||
property vector2d value: Qt.vector2d(0, 0)
|
||||
|
||||
function update() {
|
||||
value = Qt.vector2d(
|
||||
controlIds[0] ? Controller.getValue(controlIds[0]) : 0,
|
||||
controlIds[1] ? Controller.getValue(controlIds[1]) : 0
|
||||
);
|
||||
if (root.invertY) {
|
||||
value.y = value.y * -1.0
|
||||
}
|
||||
canvas.requestPaint();
|
||||
}
|
||||
|
||||
Timer {
|
||||
interval: 50; running: controlIds; repeat: true
|
||||
onTriggered: root.update()
|
||||
}
|
||||
|
||||
Canvas {
|
||||
id: canvas
|
||||
anchors.fill: parent
|
||||
antialiasing: false
|
||||
|
||||
onPaint: {
|
||||
var ctx = canvas.getContext('2d');
|
||||
ctx.save();
|
||||
ctx.beginPath();
|
||||
ctx.clearRect(0, 0, width, height);
|
||||
ctx.fill();
|
||||
ctx.translate(root.halfSize, root.halfSize)
|
||||
ctx.lineWidth = 4
|
||||
ctx.strokeStyle = Qt.rgba(Math.max(Math.abs(value.x), Math.abs(value.y)), 0, 0, 1)
|
||||
ctx.moveTo(0, 0).lineTo(root.value.x * root.halfSize, root.value.y * root.halfSize)
|
||||
ctx.stroke()
|
||||
ctx.restore()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
34
interface/resources/qml/controller/Hydra.qml
Normal file
34
interface/resources/qml/controller/Hydra.qml
Normal file
|
@ -0,0 +1,34 @@
|
|||
import QtQuick 2.1
|
||||
import QtQuick.Controls 1.0
|
||||
import QtQuick.Layouts 1.0
|
||||
import QtQuick.Dialogs 1.0
|
||||
|
||||
import "hydra"
|
||||
|
||||
Item {
|
||||
id: root
|
||||
width: 480
|
||||
height: width * 3.0 / 4.0
|
||||
property var device
|
||||
property real scale: width / 480
|
||||
property real rightOffset: (width / 2) * scale
|
||||
|
||||
Image {
|
||||
anchors.fill: parent
|
||||
source: "hydra/hydra.png"
|
||||
|
||||
HydraStick {
|
||||
leftStick: true
|
||||
scale: root.scale
|
||||
device: root.device
|
||||
}
|
||||
|
||||
|
||||
HydraStick {
|
||||
leftStick: false
|
||||
scale: root.scale
|
||||
device: root.device
|
||||
}
|
||||
|
||||
}
|
||||
}
|
35
interface/resources/qml/controller/Standard.qml
Normal file
35
interface/resources/qml/controller/Standard.qml
Normal file
|
@ -0,0 +1,35 @@
|
|||
import QtQuick 2.1
|
||||
import QtQuick.Controls 1.0
|
||||
import QtQuick.Layouts 1.0
|
||||
import QtQuick.Dialogs 1.0
|
||||
|
||||
import "xbox"
|
||||
|
||||
Item {
|
||||
id: root
|
||||
property real aspect: 300.0 / 215.0
|
||||
width: 300
|
||||
height: width / aspect
|
||||
property var device
|
||||
property string label: ""
|
||||
property real scale: width / 300.0
|
||||
|
||||
Xbox {
|
||||
width: root.width; height: root.height
|
||||
device: root.device
|
||||
}
|
||||
|
||||
// Left primary
|
||||
ToggleButton {
|
||||
x: 0; y: parent.height - height;
|
||||
controlId: root.device.LeftPrimaryThumb
|
||||
width: 16 * root.scale; height: 16 * root.scale
|
||||
}
|
||||
|
||||
// Left primary
|
||||
ToggleButton {
|
||||
x: parent.width - width; y: parent.height - height;
|
||||
controlId: root.device.RightPrimaryThumb
|
||||
width: 16 * root.scale; height: 16 * root.scale
|
||||
}
|
||||
}
|
45
interface/resources/qml/controller/ToggleButton.qml
Normal file
45
interface/resources/qml/controller/ToggleButton.qml
Normal file
|
@ -0,0 +1,45 @@
|
|||
import QtQuick 2.1
|
||||
import QtQuick.Controls 1.0
|
||||
import QtQuick.Layouts 1.0
|
||||
import QtQuick.Dialogs 1.0
|
||||
|
||||
Item {
|
||||
id: root
|
||||
width: size
|
||||
height: size
|
||||
property int size: 64
|
||||
property int controlId: 0
|
||||
property real value: 0
|
||||
property color color: 'black'
|
||||
|
||||
function update() {
|
||||
value = controlId ? Controller.getValue(controlId) : 0;
|
||||
canvas.requestPaint();
|
||||
}
|
||||
|
||||
Timer {
|
||||
interval: 50; running: root.controlId; repeat: true
|
||||
onTriggered: root.update()
|
||||
}
|
||||
|
||||
Canvas {
|
||||
id: canvas
|
||||
anchors.fill: parent
|
||||
antialiasing: false
|
||||
|
||||
onPaint: {
|
||||
var ctx = canvas.getContext('2d');
|
||||
ctx.save();
|
||||
ctx.beginPath();
|
||||
ctx.clearRect(0, 0, width, height);
|
||||
if (root.value > 0.0) {
|
||||
ctx.fillStyle = root.color
|
||||
ctx.fillRect(0, 0, canvas.width, canvas.height);
|
||||
}
|
||||
ctx.fill();
|
||||
ctx.restore()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
104
interface/resources/qml/controller/Xbox.qml
Normal file
104
interface/resources/qml/controller/Xbox.qml
Normal file
|
@ -0,0 +1,104 @@
|
|||
import QtQuick 2.1
|
||||
import QtQuick.Controls 1.0
|
||||
import QtQuick.Layouts 1.0
|
||||
import QtQuick.Dialogs 1.0
|
||||
|
||||
import "xbox"
|
||||
|
||||
Item {
|
||||
id: root
|
||||
property real aspect: 300.0 / 215.0
|
||||
width: 300
|
||||
height: width / aspect
|
||||
property var device
|
||||
property string label: ""
|
||||
property real scale: width / 300.0
|
||||
|
||||
Image {
|
||||
Text {
|
||||
anchors.left: parent.left
|
||||
anchors.top: parent.top
|
||||
text: root.label
|
||||
visible: root.label != ""
|
||||
}
|
||||
anchors.fill: parent
|
||||
source: "xbox/xbox360-controller-md.png"
|
||||
|
||||
LeftAnalogStick {
|
||||
device: root.device
|
||||
x: (65 * root.scale) - width / 2; y: (42 * root.scale) - height / 2
|
||||
}
|
||||
|
||||
// Left stick press
|
||||
ToggleButton {
|
||||
controlId: root.device.LS
|
||||
width: 16 * root.scale; height: 16 * root.scale
|
||||
x: (65 * root.scale) - width / 2; y: (42 * root.scale) - height / 2
|
||||
}
|
||||
|
||||
|
||||
RightAnalogStick {
|
||||
device: root.device
|
||||
x: (193 * root.scale) - width / 2; y: (96 * root.scale) - height / 2
|
||||
}
|
||||
|
||||
// Right stick press
|
||||
ToggleButton {
|
||||
controlId: root.device.RS
|
||||
width: 16 * root.scale; height: 16 * root.scale
|
||||
x: (193 * root.scale) - width / 2; y: (96 * root.scale) - height / 2
|
||||
}
|
||||
|
||||
// Left trigger
|
||||
AnalogButton {
|
||||
controlId: root.device.LT
|
||||
width: 8; height: 64
|
||||
x: (20 * root.scale); y: (7 * root.scale)
|
||||
}
|
||||
|
||||
// Right trigger
|
||||
AnalogButton {
|
||||
controlId: root.device.RT
|
||||
width: 8; height: 64
|
||||
x: (272 * root.scale); y: (7 * root.scale)
|
||||
}
|
||||
|
||||
// Left bumper
|
||||
ToggleButton {
|
||||
controlId: root.device.LB
|
||||
width: 32 * root.scale; height: 16 * root.scale
|
||||
x: (40 * root.scale); y: (7 * root.scale)
|
||||
}
|
||||
|
||||
// Right bumper
|
||||
ToggleButton {
|
||||
controlId: root.device.RB
|
||||
width: 32 * root.scale; height: 16 * root.scale
|
||||
x: (root.width - width) - (40 * root.scale); y: (7 * root.scale)
|
||||
}
|
||||
|
||||
DPad {
|
||||
device: root.device
|
||||
size: 48 * root.scale
|
||||
x: (80 * root.scale); y: (71 * root.scale)
|
||||
}
|
||||
|
||||
XboxButtons {
|
||||
device: root.device
|
||||
size: 65 * root.scale
|
||||
x: (206 * root.scale); y: (19 * root.scale)
|
||||
}
|
||||
|
||||
ToggleButton {
|
||||
controlId: root.device.Back
|
||||
width: 16 * root.scale; height: 12 * root.scale
|
||||
x: (112 * root.scale); y: (45 * root.scale)
|
||||
}
|
||||
|
||||
ToggleButton {
|
||||
controlId: root.device.Start
|
||||
width: 16 * root.scale; height: 12 * root.scale
|
||||
x: (177 * root.scale); y: (45 * root.scale)
|
||||
}
|
||||
}
|
||||
}
|
18
interface/resources/qml/controller/hydra/HydraButtons.qml
Normal file
18
interface/resources/qml/controller/hydra/HydraButtons.qml
Normal file
|
@ -0,0 +1,18 @@
|
|||
import QtQuick 2.1
|
||||
import QtQuick.Controls 1.0
|
||||
import QtQuick.Layouts 1.0
|
||||
import QtQuick.Dialogs 1.0
|
||||
|
||||
import ".."
|
||||
|
||||
Item {
|
||||
id: root
|
||||
width: 72 * scale
|
||||
height: 48 * scale
|
||||
property var device
|
||||
property real scale: 1.0
|
||||
property bool leftStick: true
|
||||
|
||||
}
|
||||
|
||||
|
91
interface/resources/qml/controller/hydra/HydraStick.qml
Normal file
91
interface/resources/qml/controller/hydra/HydraStick.qml
Normal file
|
@ -0,0 +1,91 @@
|
|||
import QtQuick 2.1
|
||||
import QtQuick.Controls 1.0
|
||||
import QtQuick.Layouts 1.0
|
||||
import QtQuick.Dialogs 1.0
|
||||
|
||||
import ".."
|
||||
|
||||
Item {
|
||||
id: root
|
||||
property var device
|
||||
property real scale: 1.0
|
||||
property bool leftStick: true
|
||||
width: parent.width / 2; height: parent.height
|
||||
x: leftStick ? 0 : parent.width / 2
|
||||
|
||||
Text {
|
||||
x: parent.width / 2 - width / 2; y: parent.height / 2 - height / 2
|
||||
text: root.leftStick ? "L" : "R"
|
||||
color: 'green'
|
||||
}
|
||||
|
||||
// Analog Stick
|
||||
AnalogStick {
|
||||
size: 64 * root.scale
|
||||
x: 127 * root.scale - width / 2; y: 45 * root.scale - width / 2; z: 100
|
||||
invertY: true
|
||||
controlIds: [
|
||||
root.leftStick ? root.device.LX : root.device.RX,
|
||||
root.leftStick ? root.device.LY : root.device.RY
|
||||
]
|
||||
}
|
||||
|
||||
// Stick press
|
||||
ToggleButton {
|
||||
controlId: root.leftStick ? root.device.LS : root.device.RS
|
||||
width: 16 * root.scale; height: 16 * root.scale
|
||||
x: 127 * root.scale - width / 2; y: 45 * root.scale - width / 2;
|
||||
color: 'yellow'
|
||||
}
|
||||
|
||||
// Trigger
|
||||
AnalogButton {
|
||||
controlId: root.leftStick ? root.device.LT : root.device.RT
|
||||
width: 8 * root.scale ; height: 64 * root.scale
|
||||
y: 24 * root.scale
|
||||
x: root.leftStick ? (48 * root.scale) : root.width - (48 * root.scale) - width / 2
|
||||
}
|
||||
|
||||
// Bumper
|
||||
ToggleButton {
|
||||
controlId: root.leftStick ? root.device.LB : root.device.RB
|
||||
height: 16 * root.scale; width: 32 * root.scale
|
||||
x: 128 * root.scale - width / 2; y: 24 * root.scale
|
||||
color: 'red'
|
||||
}
|
||||
|
||||
ToggleButton {
|
||||
controlId: root.leftStick ? root.device.L0 : root.device.R0
|
||||
height: 16 * root.scale; width: 4 * root.scale
|
||||
x: 128 * root.scale - width / 2; y: 109 * root.scale
|
||||
color: 'yellow'
|
||||
}
|
||||
|
||||
ToggleButton {
|
||||
controlId: root.leftStick ? root.device.L1 : root.device.R1
|
||||
width: 16 * root.scale; height: 16 * root.scale
|
||||
x: 103 * root.scale - width / 2; y: 100 * root.scale - height / 2
|
||||
color: 'yellow'
|
||||
}
|
||||
|
||||
ToggleButton {
|
||||
controlId: root.leftStick ? root.device.L2 : root.device.R2
|
||||
width: 16 * root.scale; height: 16 * root.scale
|
||||
x: 148 * root.scale - width / 2; y: 100 * root.scale - height / 2
|
||||
color: 'yellow'
|
||||
}
|
||||
|
||||
ToggleButton {
|
||||
controlId: root.leftStick ? root.device.L3 : root.device.R3
|
||||
width: 16 * root.scale; height: 16 * root.scale
|
||||
x: 97 * root.scale - width / 2; y: 76 * root.scale - height / 2
|
||||
color: 'yellow'
|
||||
}
|
||||
|
||||
ToggleButton {
|
||||
controlId: root.leftStick ? root.device.L4 : root.device.R4
|
||||
width: 16 * root.scale; height: 16 * root.scale
|
||||
x: 155 * root.scale - width / 2; y: 76 * root.scale - height / 2
|
||||
color: 'yellow'
|
||||
}
|
||||
}
|
BIN
interface/resources/qml/controller/hydra/hydra.png
Normal file
BIN
interface/resources/qml/controller/hydra/hydra.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 21 KiB |
42
interface/resources/qml/controller/xbox/DPad.qml
Normal file
42
interface/resources/qml/controller/xbox/DPad.qml
Normal file
|
@ -0,0 +1,42 @@
|
|||
import QtQuick 2.1
|
||||
import QtQuick.Controls 1.0
|
||||
import QtQuick.Layouts 1.0
|
||||
import QtQuick.Dialogs 1.0
|
||||
|
||||
import ".."
|
||||
|
||||
Item {
|
||||
id: root
|
||||
property int size: 64
|
||||
width: size
|
||||
height: size
|
||||
property int spacer: size / 3
|
||||
property var device
|
||||
property color color: 'black'
|
||||
|
||||
ToggleButton {
|
||||
controlId: device.Up
|
||||
x: spacer
|
||||
width: spacer; height: spacer
|
||||
}
|
||||
|
||||
ToggleButton {
|
||||
controlId: device.Left
|
||||
y: spacer
|
||||
width: spacer; height: spacer
|
||||
}
|
||||
|
||||
ToggleButton {
|
||||
controlId: device.Right
|
||||
x: spacer * 2; y: spacer
|
||||
width: spacer; height: spacer
|
||||
}
|
||||
|
||||
ToggleButton {
|
||||
controlId: device.Down
|
||||
x: spacer; y: spacer * 2
|
||||
width: spacer; height: spacer
|
||||
}
|
||||
}
|
||||
|
||||
|
21
interface/resources/qml/controller/xbox/LeftAnalogStick.qml
Normal file
21
interface/resources/qml/controller/xbox/LeftAnalogStick.qml
Normal file
|
@ -0,0 +1,21 @@
|
|||
import QtQuick 2.1
|
||||
import QtQuick.Controls 1.0
|
||||
import QtQuick.Layouts 1.0
|
||||
import QtQuick.Dialogs 1.0
|
||||
|
||||
import ".."
|
||||
|
||||
Item {
|
||||
id: root
|
||||
property int size: 64
|
||||
width: size
|
||||
height: size
|
||||
property var device
|
||||
|
||||
AnalogStick {
|
||||
size: size
|
||||
controlIds: [ device.LX, device.LY ]
|
||||
}
|
||||
}
|
||||
|
||||
|
21
interface/resources/qml/controller/xbox/RightAnalogStick.qml
Normal file
21
interface/resources/qml/controller/xbox/RightAnalogStick.qml
Normal file
|
@ -0,0 +1,21 @@
|
|||
import QtQuick 2.1
|
||||
import QtQuick.Controls 1.0
|
||||
import QtQuick.Layouts 1.0
|
||||
import QtQuick.Dialogs 1.0
|
||||
|
||||
import ".."
|
||||
|
||||
Item {
|
||||
id: root
|
||||
property int size: 64
|
||||
width: size
|
||||
height: size
|
||||
property var device
|
||||
|
||||
AnalogStick {
|
||||
size: size
|
||||
controlIds: [ device.RX, device.RY ]
|
||||
}
|
||||
}
|
||||
|
||||
|
46
interface/resources/qml/controller/xbox/XboxButtons.qml
Normal file
46
interface/resources/qml/controller/xbox/XboxButtons.qml
Normal file
|
@ -0,0 +1,46 @@
|
|||
import QtQuick 2.1
|
||||
import QtQuick.Controls 1.0
|
||||
import QtQuick.Layouts 1.0
|
||||
import QtQuick.Dialogs 1.0
|
||||
|
||||
import ".."
|
||||
|
||||
Item {
|
||||
id: root
|
||||
property int size: 64
|
||||
width: size
|
||||
height: size
|
||||
property int spacer: size / 3
|
||||
property var device
|
||||
property color color: 'black'
|
||||
|
||||
ToggleButton {
|
||||
controlId: device.Y
|
||||
x: spacer
|
||||
width: spacer; height: spacer
|
||||
color: 'yellow'
|
||||
}
|
||||
|
||||
ToggleButton {
|
||||
controlId: device.X
|
||||
y: spacer
|
||||
width: spacer; height: spacer
|
||||
color: 'blue'
|
||||
}
|
||||
|
||||
ToggleButton {
|
||||
controlId: device.B
|
||||
x: spacer * 2; y: spacer
|
||||
width: spacer; height: spacer
|
||||
color: 'red'
|
||||
}
|
||||
|
||||
ToggleButton {
|
||||
controlId: device.A
|
||||
x: spacer; y: spacer * 2
|
||||
width: spacer; height: spacer
|
||||
color: 'green'
|
||||
}
|
||||
}
|
||||
|
||||
|
Binary file not shown.
After Width: | Height: | Size: 29 KiB |
|
@ -17,27 +17,32 @@
|
|||
#include <glm/gtx/vector_angle.hpp>
|
||||
#include <glm/gtc/type_ptr.hpp>
|
||||
|
||||
#include <QAbstractNativeEventFilter>
|
||||
#include <QActionGroup>
|
||||
#include <QDebug>
|
||||
#include <QDesktopServices>
|
||||
#include <QDesktopWidget>
|
||||
#include <QImage>
|
||||
#include <QFileDialog>
|
||||
#include <QInputDialog>
|
||||
#include <QKeyEvent>
|
||||
#include <QMediaPlayer>
|
||||
#include <QMenuBar>
|
||||
#include <QMessageBox>
|
||||
#include <QMimeData>
|
||||
#include <QMouseEvent>
|
||||
#include <QNetworkDiskCache>
|
||||
#include <QObject>
|
||||
#include <QScreen>
|
||||
#include <QTimer>
|
||||
#include <QUrl>
|
||||
#include <QWheelEvent>
|
||||
#include <QWindow>
|
||||
#include <QtCore/QDebug>
|
||||
#include <QtCore/QObject>
|
||||
#include <QtCore/QUrl>
|
||||
#include <QtCore/QTimer>
|
||||
#include <QtCore/QAbstractNativeEventFilter>
|
||||
#include <QtCore/QMimeData>
|
||||
|
||||
#include <QtGui/QScreen>
|
||||
#include <QtGui/QImage>
|
||||
#include <QtGui/QWheelEvent>
|
||||
#include <QtGui/QWindow>
|
||||
#include <QtQml/QQmlContext>
|
||||
#include <QtGui/QKeyEvent>
|
||||
#include <QtGui/QMouseEvent>
|
||||
#include <QtGui/QDesktopServices>
|
||||
|
||||
#include <QtWidgets/QActionGroup>
|
||||
#include <QtWidgets/QDesktopWidget>
|
||||
#include <QtWidgets/QFileDialog>
|
||||
#include <QtWidgets/QInputDialog>
|
||||
#include <QtWidgets/QMenuBar>
|
||||
#include <QtWidgets/QMessageBox>
|
||||
|
||||
#include <QtMultimedia/QMediaPlayer>
|
||||
|
||||
#include <QtNetwork/QNetworkDiskCache>
|
||||
|
||||
#include <AccountManager.h>
|
||||
#include <AddressManager.h>
|
||||
|
@ -60,7 +65,8 @@
|
|||
#include <InfoView.h>
|
||||
#include <input-plugins/InputPlugin.h>
|
||||
#include <input-plugins/Joystick.h> // this should probably be removed
|
||||
#include <input-plugins/UserInputMapper.h>
|
||||
#include <controllers/UserInputMapper.h>
|
||||
#include <controllers/StateController.h>
|
||||
#include <LogHandler.h>
|
||||
#include <MainWindow.h>
|
||||
#include <MessageDialog.h>
|
||||
|
@ -120,6 +126,7 @@
|
|||
#include "scripting/SettingsScriptingInterface.h"
|
||||
#include "scripting/WebWindowClass.h"
|
||||
#include "scripting/WindowScriptingInterface.h"
|
||||
#include "scripting/ControllerScriptingInterface.h"
|
||||
#if defined(Q_OS_MAC) || defined(Q_OS_WIN)
|
||||
#include "SpeechRecognizer.h"
|
||||
#endif
|
||||
|
@ -137,6 +144,7 @@
|
|||
#include "ui/UpdateDialog.h"
|
||||
#include "Util.h"
|
||||
|
||||
|
||||
// ON WIndows PC, NVidia Optimus laptop, we want to enable NVIDIA GPU
|
||||
// FIXME seems to be broken.
|
||||
#if defined(Q_OS_WIN)
|
||||
|
@ -316,6 +324,7 @@ bool setupEssentials(int& argc, char** argv) {
|
|||
DependencyManager::set<EntityScriptingInterface>();
|
||||
DependencyManager::set<WindowScriptingInterface>();
|
||||
DependencyManager::set<HMDScriptingInterface>();
|
||||
|
||||
#if defined(Q_OS_MAC) || defined(Q_OS_WIN)
|
||||
DependencyManager::set<SpeechRecognizer>();
|
||||
#endif
|
||||
|
@ -327,7 +336,7 @@ bool setupEssentials(int& argc, char** argv) {
|
|||
DependencyManager::set<InterfaceActionFactory>();
|
||||
DependencyManager::set<AssetClient>();
|
||||
DependencyManager::set<UserInputMapper>();
|
||||
|
||||
DependencyManager::set<controller::ScriptingInterface, ControllerScriptingInterface>();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -339,49 +348,50 @@ int _keyboardFocusHighlightID{ -1 };
|
|||
PluginContainer* _pluginContainer;
|
||||
|
||||
Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) :
|
||||
QApplication(argc, argv),
|
||||
_dependencyManagerIsSetup(setupEssentials(argc, argv)),
|
||||
_window(new MainWindow(desktop())),
|
||||
_toolWindow(NULL),
|
||||
_undoStackScriptingInterface(&_undoStack),
|
||||
_frameCount(0),
|
||||
_fps(60.0f),
|
||||
_physicsEngine(new PhysicsEngine(Vectors::ZERO)),
|
||||
_entities(true, this, this),
|
||||
_entityClipboardRenderer(false, this, this),
|
||||
_entityClipboard(new EntityTree()),
|
||||
_lastQueriedTime(usecTimestampNow()),
|
||||
_mirrorViewRect(QRect(MIRROR_VIEW_LEFT_PADDING, MIRROR_VIEW_TOP_PADDING, MIRROR_VIEW_WIDTH, MIRROR_VIEW_HEIGHT)),
|
||||
_firstRun("firstRun", true),
|
||||
_previousScriptLocation("LastScriptLocation", DESKTOP_LOCATION),
|
||||
_scriptsLocationHandle("scriptsLocation", DESKTOP_LOCATION),
|
||||
_fieldOfView("fieldOfView", DEFAULT_FIELD_OF_VIEW_DEGREES),
|
||||
_scaleMirror(1.0f),
|
||||
_rotateMirror(0.0f),
|
||||
_raiseMirror(0.0f),
|
||||
_lastMouseMoveWasSimulated(false),
|
||||
_enableProcessOctreeThread(true),
|
||||
_runningScriptsWidget(NULL),
|
||||
_runningScriptsWidgetWasVisible(false),
|
||||
_lastNackTime(usecTimestampNow()),
|
||||
_lastSendDownstreamAudioStats(usecTimestampNow()),
|
||||
_aboutToQuit(false),
|
||||
_notifiedPacketVersionMismatchThisDomain(false),
|
||||
_maxOctreePPS(maxOctreePacketsPerSecond.get()),
|
||||
_lastFaceTrackerUpdate(0)
|
||||
QApplication(argc, argv),
|
||||
_dependencyManagerIsSetup(setupEssentials(argc, argv)),
|
||||
_window(new MainWindow(desktop())),
|
||||
_toolWindow(NULL),
|
||||
_undoStackScriptingInterface(&_undoStack),
|
||||
_frameCount(0),
|
||||
_fps(60.0f),
|
||||
_physicsEngine(new PhysicsEngine(Vectors::ZERO)),
|
||||
_entities(true, this, this),
|
||||
_entityClipboardRenderer(false, this, this),
|
||||
_entityClipboard(new EntityTree()),
|
||||
_lastQueriedTime(usecTimestampNow()),
|
||||
_mirrorViewRect(QRect(MIRROR_VIEW_LEFT_PADDING, MIRROR_VIEW_TOP_PADDING, MIRROR_VIEW_WIDTH, MIRROR_VIEW_HEIGHT)),
|
||||
_firstRun("firstRun", true),
|
||||
_previousScriptLocation("LastScriptLocation", DESKTOP_LOCATION),
|
||||
_scriptsLocationHandle("scriptsLocation", DESKTOP_LOCATION),
|
||||
_fieldOfView("fieldOfView", DEFAULT_FIELD_OF_VIEW_DEGREES),
|
||||
_scaleMirror(1.0f),
|
||||
_rotateMirror(0.0f),
|
||||
_raiseMirror(0.0f),
|
||||
_lastMouseMoveWasSimulated(false),
|
||||
_enableProcessOctreeThread(true),
|
||||
_runningScriptsWidget(NULL),
|
||||
_runningScriptsWidgetWasVisible(false),
|
||||
_lastNackTime(usecTimestampNow()),
|
||||
_lastSendDownstreamAudioStats(usecTimestampNow()),
|
||||
_aboutToQuit(false),
|
||||
_notifiedPacketVersionMismatchThisDomain(false),
|
||||
_maxOctreePPS(maxOctreePacketsPerSecond.get()),
|
||||
_lastFaceTrackerUpdate(0)
|
||||
{
|
||||
thread()->setObjectName("Main Thread");
|
||||
|
||||
|
||||
setInstance(this);
|
||||
|
||||
|
||||
auto controllerScriptingInterface = DependencyManager::get<controller::ScriptingInterface>().data();
|
||||
_controllerScriptingInterface = dynamic_cast<ControllerScriptingInterface*>(controllerScriptingInterface);
|
||||
// to work around the Qt constant wireless scanning, set the env for polling interval very high
|
||||
const QByteArray EXTREME_BEARER_POLL_TIMEOUT = QString::number(INT_MAX).toLocal8Bit();
|
||||
qputenv("QT_BEARER_POLL_TIMEOUT", EXTREME_BEARER_POLL_TIMEOUT);
|
||||
|
||||
|
||||
_entityClipboard->createRootElement();
|
||||
|
||||
_pluginContainer = new PluginContainerProxy();
|
||||
Plugin::setContainer(_pluginContainer);
|
||||
#ifdef Q_OS_WIN
|
||||
installNativeEventFilter(&MyNativeEventFilter::getInstance());
|
||||
#endif
|
||||
|
@ -440,7 +450,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) :
|
|||
audioIO->moveToThread(audioThread);
|
||||
|
||||
auto& audioScriptingInterface = AudioScriptingInterface::getInstance();
|
||||
|
||||
|
||||
connect(audioThread, &QThread::started, audioIO.data(), &AudioClient::start);
|
||||
connect(audioIO.data(), &AudioClient::destroyed, audioThread, &QThread::quit);
|
||||
connect(audioThread, &QThread::finished, audioThread, &QThread::deleteLater);
|
||||
|
@ -479,7 +489,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) :
|
|||
connect(&domainHandler, SIGNAL(disconnectedFromDomain()), SLOT(clearDomainOctreeDetails()));
|
||||
connect(&domainHandler, &DomainHandler::settingsReceived, this, &Application::domainSettingsReceived);
|
||||
connect(&domainHandler, &DomainHandler::hostnameChanged,
|
||||
DependencyManager::get<AddressManager>().data(), &AddressManager::storeCurrentAddress);
|
||||
DependencyManager::get<AddressManager>().data(), &AddressManager::storeCurrentAddress);
|
||||
|
||||
// update our location every 5 seconds in the metaverse server, assuming that we are authenticated with one
|
||||
const qint64 DATA_SERVER_LOCATION_CHANGE_UPDATE_MSECS = 5 * 1000;
|
||||
|
@ -490,7 +500,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) :
|
|||
|
||||
// if we get a domain change, immediately attempt update location in metaverse server
|
||||
connect(&nodeList->getDomainHandler(), &DomainHandler::connectedToDomain,
|
||||
discoverabilityManager.data(), &DiscoverabilityManager::updateLocation);
|
||||
discoverabilityManager.data(), &DiscoverabilityManager::updateLocation);
|
||||
|
||||
connect(nodeList.data(), &NodeList::nodeAdded, this, &Application::nodeAdded);
|
||||
connect(nodeList.data(), &NodeList::nodeKilled, this, &Application::nodeKilled);
|
||||
|
@ -529,14 +539,14 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) :
|
|||
connect(addressManager.data(), &AddressManager::hostChanged, this, &Application::updateWindowTitle);
|
||||
connect(this, &QCoreApplication::aboutToQuit, addressManager.data(), &AddressManager::storeCurrentAddress);
|
||||
|
||||
#ifdef _WIN32
|
||||
#ifdef _WIN32
|
||||
WSADATA WsaData;
|
||||
int wsaresult = WSAStartup(MAKEWORD(2,2), &WsaData);
|
||||
#endif
|
||||
int wsaresult = WSAStartup(MAKEWORD(2, 2), &WsaData);
|
||||
#endif
|
||||
|
||||
// tell the NodeList instance who to tell the domain server we care about
|
||||
nodeList->addSetOfNodeTypesToNodeInterestSet(NodeSet() << NodeType::AudioMixer << NodeType::AvatarMixer
|
||||
<< NodeType::EntityServer << NodeType::AssetServer);
|
||||
<< NodeType::EntityServer << NodeType::AssetServer);
|
||||
|
||||
// connect to the packet sent signal of the _entityEditSender
|
||||
connect(&_entityEditSender, &EntityEditPacketSender::packetSent, this, &Application::packetSent);
|
||||
|
@ -609,29 +619,44 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) :
|
|||
// hook up bandwidth estimator
|
||||
QSharedPointer<BandwidthRecorder> bandwidthRecorder = DependencyManager::get<BandwidthRecorder>();
|
||||
connect(nodeList.data(), &LimitedNodeList::dataSent,
|
||||
bandwidthRecorder.data(), &BandwidthRecorder::updateOutboundData);
|
||||
bandwidthRecorder.data(), &BandwidthRecorder::updateOutboundData);
|
||||
connect(&nodeList->getPacketReceiver(), &PacketReceiver::dataReceived,
|
||||
bandwidthRecorder.data(), &BandwidthRecorder::updateInboundData);
|
||||
bandwidthRecorder.data(), &BandwidthRecorder::updateInboundData);
|
||||
|
||||
connect(&getMyAvatar()->getSkeletonModel(), &SkeletonModel::skeletonLoaded,
|
||||
this, &Application::checkSkeleton, Qt::QueuedConnection);
|
||||
this, &Application::checkSkeleton, Qt::QueuedConnection);
|
||||
|
||||
// Setup the userInputMapper with the actions
|
||||
auto userInputMapper = DependencyManager::get<UserInputMapper>();
|
||||
connect(userInputMapper.data(), &UserInputMapper::actionEvent, &_controllerScriptingInterface, &AbstractControllerScriptingInterface::actionEvent);
|
||||
connect(userInputMapper.data(), &UserInputMapper::actionEvent, [this](int action, float state) {
|
||||
if (state) {
|
||||
switch (action) {
|
||||
case UserInputMapper::Action::TOGGLE_MUTE:
|
||||
if (action == controller::toInt(controller::Action::TOGGLE_MUTE)) {
|
||||
DependencyManager::get<AudioClient>()->toggleMute();
|
||||
break;
|
||||
} else if (action == controller::toInt(controller::Action::CYCLE_CAMERA)) {
|
||||
cycleCamera();
|
||||
} else if (action == controller::toInt(controller::Action::CONTEXT_MENU)) {
|
||||
VrMenu::toggle(); // show context menu even on non-stereo displays
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// A new controllerInput device used to reflect current values from the application state
|
||||
_applicationStateDevice = std::make_shared<controller::StateController>();
|
||||
|
||||
_applicationStateDevice->addInputVariant(QString("InHMD"), controller::StateController::ReadLambda([]() -> float {
|
||||
return (float)qApp->getAvatarUpdater()->isHMDMode();
|
||||
}));
|
||||
_applicationStateDevice->addInputVariant(QString("ComfortMode"), controller::StateController::ReadLambda([]() -> float {
|
||||
return (float)Menu::getInstance()->isOptionChecked(MenuOption::ComfortMode);
|
||||
}));
|
||||
|
||||
userInputMapper->registerDevice(_applicationStateDevice);
|
||||
|
||||
// Setup the keyboardMouseDevice and the user input mapper with the default bindings
|
||||
_keyboardMouseDevice->registerToUserInputMapper(*userInputMapper);
|
||||
_keyboardMouseDevice->assignDefaultInputMapping(*userInputMapper);
|
||||
userInputMapper->registerDevice(_keyboardMouseDevice);
|
||||
|
||||
|
||||
userInputMapper->loadDefaultMapping(userInputMapper->getStandardDeviceID());
|
||||
|
||||
// check first run...
|
||||
if (_firstRun.get()) {
|
||||
|
@ -704,8 +729,10 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) :
|
|||
// Now that menu is initalized we can sync myAvatar with it's state.
|
||||
getMyAvatar()->updateMotionBehaviorFromMenu();
|
||||
|
||||
#if 0
|
||||
// the 3Dconnexion device wants to be initiliazed after a window is displayed.
|
||||
ConnexionClient::getInstance().init();
|
||||
#endif
|
||||
|
||||
auto& packetReceiver = nodeList->getPacketReceiver();
|
||||
packetReceiver.registerListener(PacketType::DomainConnectionDenied, this, "handleDomainConnectionDeniedPacket");
|
||||
|
@ -792,6 +819,9 @@ void Application::cleanupBeforeQuit() {
|
|||
|
||||
AnimDebugDraw::getInstance().shutdown();
|
||||
|
||||
// FIXME: once we move to shared pointer for the INputDevice we shoud remove this naked delete:
|
||||
_applicationStateDevice.reset();
|
||||
|
||||
if (_keyboardFocusHighlightID > 0) {
|
||||
getOverlays().deleteOverlay(_keyboardFocusHighlightID);
|
||||
_keyboardFocusHighlightID = -1;
|
||||
|
@ -902,7 +932,10 @@ Application::~Application() {
|
|||
|
||||
Leapmotion::destroy();
|
||||
RealSense::destroy();
|
||||
|
||||
#if 0
|
||||
ConnexionClient::getInstance().destroy();
|
||||
#endif
|
||||
|
||||
qInstallMessageHandler(NULL); // NOTE: Do this as late as possible so we continue to get our log messages
|
||||
}
|
||||
|
@ -975,6 +1008,8 @@ void Application::initializeUi() {
|
|||
offscreenUi->setBaseUrl(QUrl::fromLocalFile(PathUtils::resourcesPath() + "/qml/"));
|
||||
offscreenUi->load("Root.qml");
|
||||
offscreenUi->load("RootMenu.qml");
|
||||
auto scriptingInterface = DependencyManager::get<controller::ScriptingInterface>();
|
||||
offscreenUi->getRootContext()->setContextProperty("Controller", scriptingInterface.data());
|
||||
_glWidget->installEventFilter(offscreenUi.data());
|
||||
VrMenu::load();
|
||||
VrMenu::executeQueuedLambdas();
|
||||
|
@ -1003,7 +1038,10 @@ void Application::initializeUi() {
|
|||
foreach(auto inputPlugin, PluginManager::getInstance()->getInputPlugins()) {
|
||||
QString name = inputPlugin->getName();
|
||||
if (name == KeyboardMouseDevice::NAME) {
|
||||
_keyboardMouseDevice = static_cast<KeyboardMouseDevice*>(inputPlugin.data()); // TODO: this seems super hacky
|
||||
auto kbm = static_cast<KeyboardMouseDevice*>(inputPlugin.data());
|
||||
// FIXME incredibly evil.... _keyboardMouseDevice is now owned by
|
||||
// both a QSharedPointer and a std::shared_ptr
|
||||
_keyboardMouseDevice = std::shared_ptr<KeyboardMouseDevice>(kbm);
|
||||
}
|
||||
}
|
||||
updateInputModes();
|
||||
|
@ -1456,7 +1494,7 @@ bool Application::event(QEvent* event) {
|
|||
}
|
||||
|
||||
if (HFActionEvent::types().contains(event->type())) {
|
||||
_controllerScriptingInterface.handleMetaEvent(static_cast<HFMetaEvent*>(event));
|
||||
_controllerScriptingInterface->handleMetaEvent(static_cast<HFMetaEvent*>(event));
|
||||
}
|
||||
|
||||
return QApplication::event(event);
|
||||
|
@ -1470,7 +1508,7 @@ bool Application::eventFilter(QObject* object, QEvent* event) {
|
|||
}
|
||||
|
||||
// Filter out captured keys before they're used for shortcut actions.
|
||||
if (_controllerScriptingInterface.isKeyCaptured(static_cast<QKeyEvent*>(event))) {
|
||||
if (_controllerScriptingInterface->isKeyCaptured(static_cast<QKeyEvent*>(event))) {
|
||||
event->accept();
|
||||
return true;
|
||||
}
|
||||
|
@ -1485,10 +1523,10 @@ void Application::keyPressEvent(QKeyEvent* event) {
|
|||
_altPressed = event->key() == Qt::Key_Alt;
|
||||
_keysPressed.insert(event->key());
|
||||
|
||||
_controllerScriptingInterface.emitKeyPressEvent(event); // send events to any registered scripts
|
||||
_controllerScriptingInterface->emitKeyPressEvent(event); // send events to any registered scripts
|
||||
|
||||
// if one of our scripts have asked to capture this event, then stop processing it
|
||||
if (_controllerScriptingInterface.isKeyCaptured(event)) {
|
||||
if (_controllerScriptingInterface->isKeyCaptured(event)) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1518,6 +1556,13 @@ void Application::keyPressEvent(QKeyEvent* event) {
|
|||
if (isMeta) {
|
||||
auto offscreenUi = DependencyManager::get<OffscreenUi>();
|
||||
offscreenUi->load("Browser.qml");
|
||||
}
|
||||
break;
|
||||
|
||||
case Qt::Key_X:
|
||||
if (isMeta && isShifted) {
|
||||
auto offscreenUi = DependencyManager::get<OffscreenUi>();
|
||||
offscreenUi->load("TestControllers.qml");
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -1745,17 +1790,15 @@ void Application::keyPressEvent(QKeyEvent* event) {
|
|||
|
||||
void Application::keyReleaseEvent(QKeyEvent* event) {
|
||||
if (event->key() == Qt::Key_Alt && _altPressed && hasFocus()) {
|
||||
if (getActiveDisplayPlugin()->isStereo()) {
|
||||
VrMenu::toggle();
|
||||
}
|
||||
VrMenu::toggle(); // show context menu even on non-stereo displays
|
||||
}
|
||||
|
||||
_keysPressed.remove(event->key());
|
||||
|
||||
_controllerScriptingInterface.emitKeyReleaseEvent(event); // send events to any registered scripts
|
||||
_controllerScriptingInterface->emitKeyReleaseEvent(event); // send events to any registered scripts
|
||||
|
||||
// if one of our scripts have asked to capture this event, then stop processing it
|
||||
if (_controllerScriptingInterface.isKeyCaptured(event)) {
|
||||
if (_controllerScriptingInterface->isKeyCaptured(event)) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1796,7 +1839,9 @@ void Application::focusOutEvent(QFocusEvent* event) {
|
|||
inputPlugin->pluginFocusOutEvent();
|
||||
}
|
||||
}
|
||||
#if 0
|
||||
ConnexionData::getInstance().focusOutEvent();
|
||||
#endif
|
||||
|
||||
// synthesize events for keys currently pressed, since we may not get their release events
|
||||
foreach (int key, _keysPressed) {
|
||||
|
@ -1844,10 +1889,10 @@ void Application::mouseMoveEvent(QMouseEvent* event, unsigned int deviceID) {
|
|||
|
||||
|
||||
_entities.mouseMoveEvent(&mappedEvent, deviceID);
|
||||
_controllerScriptingInterface.emitMouseMoveEvent(&mappedEvent, deviceID); // send events to any registered scripts
|
||||
_controllerScriptingInterface->emitMouseMoveEvent(&mappedEvent, deviceID); // send events to any registered scripts
|
||||
|
||||
// if one of our scripts have asked to capture this event, then stop processing it
|
||||
if (_controllerScriptingInterface.isMouseCaptured()) {
|
||||
if (_controllerScriptingInterface->isMouseCaptured()) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1872,10 +1917,10 @@ void Application::mousePressEvent(QMouseEvent* event, unsigned int deviceID) {
|
|||
_entities.mousePressEvent(&mappedEvent, deviceID);
|
||||
}
|
||||
|
||||
_controllerScriptingInterface.emitMousePressEvent(&mappedEvent); // send events to any registered scripts
|
||||
_controllerScriptingInterface->emitMousePressEvent(&mappedEvent); // send events to any registered scripts
|
||||
|
||||
// if one of our scripts have asked to capture this event, then stop processing it
|
||||
if (_controllerScriptingInterface.isMouseCaptured()) {
|
||||
if (_controllerScriptingInterface->isMouseCaptured()) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1897,11 +1942,11 @@ void Application::mousePressEvent(QMouseEvent* event, unsigned int deviceID) {
|
|||
|
||||
void Application::mouseDoublePressEvent(QMouseEvent* event, unsigned int deviceID) {
|
||||
// if one of our scripts have asked to capture this event, then stop processing it
|
||||
if (_controllerScriptingInterface.isMouseCaptured()) {
|
||||
if (_controllerScriptingInterface->isMouseCaptured()) {
|
||||
return;
|
||||
}
|
||||
|
||||
_controllerScriptingInterface.emitMouseDoublePressEvent(event);
|
||||
_controllerScriptingInterface->emitMouseDoublePressEvent(event);
|
||||
}
|
||||
|
||||
void Application::mouseReleaseEvent(QMouseEvent* event, unsigned int deviceID) {
|
||||
|
@ -1917,10 +1962,10 @@ void Application::mouseReleaseEvent(QMouseEvent* event, unsigned int deviceID) {
|
|||
_entities.mouseReleaseEvent(&mappedEvent, deviceID);
|
||||
}
|
||||
|
||||
_controllerScriptingInterface.emitMouseReleaseEvent(&mappedEvent); // send events to any registered scripts
|
||||
_controllerScriptingInterface->emitMouseReleaseEvent(&mappedEvent); // send events to any registered scripts
|
||||
|
||||
// if one of our scripts have asked to capture this event, then stop processing it
|
||||
if (_controllerScriptingInterface.isMouseCaptured()) {
|
||||
if (_controllerScriptingInterface->isMouseCaptured()) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1943,12 +1988,12 @@ void Application::touchUpdateEvent(QTouchEvent* event) {
|
|||
|
||||
if (event->type() == QEvent::TouchUpdate) {
|
||||
TouchEvent thisEvent(*event, _lastTouchEvent);
|
||||
_controllerScriptingInterface.emitTouchUpdateEvent(thisEvent); // send events to any registered scripts
|
||||
_controllerScriptingInterface->emitTouchUpdateEvent(thisEvent); // send events to any registered scripts
|
||||
_lastTouchEvent = thisEvent;
|
||||
}
|
||||
|
||||
// if one of our scripts have asked to capture this event, then stop processing it
|
||||
if (_controllerScriptingInterface.isTouchCaptured()) {
|
||||
if (_controllerScriptingInterface->isTouchCaptured()) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1960,13 +2005,13 @@ void Application::touchUpdateEvent(QTouchEvent* event) {
|
|||
void Application::touchBeginEvent(QTouchEvent* event) {
|
||||
_altPressed = false;
|
||||
TouchEvent thisEvent(*event); // on touch begin, we don't compare to last event
|
||||
_controllerScriptingInterface.emitTouchBeginEvent(thisEvent); // send events to any registered scripts
|
||||
_controllerScriptingInterface->emitTouchBeginEvent(thisEvent); // send events to any registered scripts
|
||||
|
||||
_lastTouchEvent = thisEvent; // and we reset our last event to this event before we call our update
|
||||
touchUpdateEvent(event);
|
||||
|
||||
// if one of our scripts have asked to capture this event, then stop processing it
|
||||
if (_controllerScriptingInterface.isTouchCaptured()) {
|
||||
if (_controllerScriptingInterface->isTouchCaptured()) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1979,11 +2024,11 @@ void Application::touchBeginEvent(QTouchEvent* event) {
|
|||
void Application::touchEndEvent(QTouchEvent* event) {
|
||||
_altPressed = false;
|
||||
TouchEvent thisEvent(*event, _lastTouchEvent);
|
||||
_controllerScriptingInterface.emitTouchEndEvent(thisEvent); // send events to any registered scripts
|
||||
_controllerScriptingInterface->emitTouchEndEvent(thisEvent); // send events to any registered scripts
|
||||
_lastTouchEvent = thisEvent;
|
||||
|
||||
// if one of our scripts have asked to capture this event, then stop processing it
|
||||
if (_controllerScriptingInterface.isTouchCaptured()) {
|
||||
if (_controllerScriptingInterface->isTouchCaptured()) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1996,10 +2041,10 @@ void Application::touchEndEvent(QTouchEvent* event) {
|
|||
|
||||
void Application::wheelEvent(QWheelEvent* event) {
|
||||
_altPressed = false;
|
||||
_controllerScriptingInterface.emitWheelEvent(event); // send events to any registered scripts
|
||||
_controllerScriptingInterface->emitWheelEvent(event); // send events to any registered scripts
|
||||
|
||||
// if one of our scripts have asked to capture this event, then stop processing it
|
||||
if (_controllerScriptingInterface.isWheelCaptured()) {
|
||||
if (_controllerScriptingInterface->isWheelCaptured()) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -2164,7 +2209,7 @@ float Application::getAvatarSimrate() {
|
|||
}
|
||||
|
||||
void Application::setLowVelocityFilter(bool lowVelocityFilter) {
|
||||
InputDevice::setLowVelocityFilter(lowVelocityFilter);
|
||||
controller::InputDevice::setLowVelocityFilter(lowVelocityFilter);
|
||||
}
|
||||
|
||||
ivec2 Application::getMouse() const {
|
||||
|
@ -2578,6 +2623,30 @@ void Application::updateThreads(float deltaTime) {
|
|||
}
|
||||
}
|
||||
|
||||
void Application::cycleCamera() {
|
||||
auto menu = Menu::getInstance();
|
||||
if (menu->isOptionChecked(MenuOption::FullscreenMirror)) {
|
||||
|
||||
menu->setIsOptionChecked(MenuOption::FullscreenMirror, false);
|
||||
menu->setIsOptionChecked(MenuOption::FirstPerson, true);
|
||||
|
||||
} else if (menu->isOptionChecked(MenuOption::FirstPerson)) {
|
||||
|
||||
menu->setIsOptionChecked(MenuOption::FirstPerson, false);
|
||||
menu->setIsOptionChecked(MenuOption::ThirdPerson, true);
|
||||
|
||||
} else if (menu->isOptionChecked(MenuOption::ThirdPerson)) {
|
||||
|
||||
menu->setIsOptionChecked(MenuOption::ThirdPerson, false);
|
||||
menu->setIsOptionChecked(MenuOption::FullscreenMirror, true);
|
||||
|
||||
} else if (menu->isOptionChecked(MenuOption::IndependentMode)) {
|
||||
// do nothing if in independe mode
|
||||
return;
|
||||
}
|
||||
cameraMenuChanged(); // handle the menu change
|
||||
}
|
||||
|
||||
void Application::cameraMenuChanged() {
|
||||
if (Menu::getInstance()->isOptionChecked(MenuOption::FullscreenMirror)) {
|
||||
if (_myCamera.getMode() != CAMERA_MODE_MIRROR) {
|
||||
|
@ -2694,13 +2763,9 @@ void Application::update(float deltaTime) {
|
|||
userInputMapper->setSensorToWorldMat(myAvatar->getSensorToWorldMatrix());
|
||||
userInputMapper->update(deltaTime);
|
||||
|
||||
// This needs to go after userInputMapper->update() because of the keyboard
|
||||
bool jointsCaptured = false;
|
||||
auto inputPlugins = PluginManager::getInstance()->getInputPlugins();
|
||||
foreach(auto inputPlugin, inputPlugins) {
|
||||
QString name = inputPlugin->getName();
|
||||
QAction* action = Menu::getInstance()->getActionForOption(name);
|
||||
if (action && action->isChecked()) {
|
||||
for (auto inputPlugin : PluginManager::getInstance()->getInputPlugins()) {
|
||||
if (inputPlugin->isActive()) {
|
||||
inputPlugin->pluginUpdate(deltaTime, jointsCaptured);
|
||||
if (inputPlugin->isJointController()) {
|
||||
jointsCaptured = true;
|
||||
|
@ -2708,19 +2773,14 @@ void Application::update(float deltaTime) {
|
|||
}
|
||||
}
|
||||
|
||||
// Dispatch input events
|
||||
_controllerScriptingInterface.updateInputControllers();
|
||||
|
||||
// Transfer the user inputs to the driveKeys
|
||||
// FIXME can we drop drive keys and just have the avatar read the action states directly?
|
||||
myAvatar->clearDriveKeys();
|
||||
if (_myCamera.getMode() != CAMERA_MODE_INDEPENDENT) {
|
||||
if (!_controllerScriptingInterface.areActionsCaptured()) {
|
||||
myAvatar->setDriveKeys(FWD, userInputMapper->getActionState(UserInputMapper::LONGITUDINAL_FORWARD));
|
||||
myAvatar->setDriveKeys(BACK, userInputMapper->getActionState(UserInputMapper::LONGITUDINAL_BACKWARD));
|
||||
myAvatar->setDriveKeys(UP, userInputMapper->getActionState(UserInputMapper::VERTICAL_UP));
|
||||
myAvatar->setDriveKeys(DOWN, userInputMapper->getActionState(UserInputMapper::VERTICAL_DOWN));
|
||||
myAvatar->setDriveKeys(LEFT, userInputMapper->getActionState(UserInputMapper::LATERAL_LEFT));
|
||||
myAvatar->setDriveKeys(RIGHT, userInputMapper->getActionState(UserInputMapper::LATERAL_RIGHT));
|
||||
if (!_controllerScriptingInterface->areActionsCaptured()) {
|
||||
myAvatar->setDriveKeys(TRANSLATE_Z, -1.0f * userInputMapper->getActionState(controller::Action::TRANSLATE_Z));
|
||||
myAvatar->setDriveKeys(TRANSLATE_Y, userInputMapper->getActionState(controller::Action::TRANSLATE_Y));
|
||||
myAvatar->setDriveKeys(TRANSLATE_X, userInputMapper->getActionState(controller::Action::TRANSLATE_X));
|
||||
if (deltaTime > FLT_EPSILON) {
|
||||
// For rotations what we really want are meausures of "angles per second" (in order to prevent
|
||||
// fps-dependent spin rates) so we need to scale the units of the controller contribution.
|
||||
|
@ -2728,25 +2788,24 @@ void Application::update(float deltaTime) {
|
|||
// controllers to provide a delta_per_second value rather than a raw delta.)
|
||||
const float EXPECTED_FRAME_RATE = 60.0f;
|
||||
float timeFactor = EXPECTED_FRAME_RATE * deltaTime;
|
||||
myAvatar->setDriveKeys(ROT_UP, userInputMapper->getActionState(UserInputMapper::PITCH_UP) / timeFactor);
|
||||
myAvatar->setDriveKeys(ROT_DOWN, userInputMapper->getActionState(UserInputMapper::PITCH_DOWN) / timeFactor);
|
||||
myAvatar->setDriveKeys(ROT_LEFT, userInputMapper->getActionState(UserInputMapper::YAW_LEFT) / timeFactor);
|
||||
myAvatar->setDriveKeys(ROT_RIGHT, userInputMapper->getActionState(UserInputMapper::YAW_RIGHT) / timeFactor);
|
||||
myAvatar->setDriveKeys(PITCH, -1.0f * userInputMapper->getActionState(controller::Action::PITCH) / timeFactor);
|
||||
myAvatar->setDriveKeys(YAW, -1.0f * userInputMapper->getActionState(controller::Action::YAW) / timeFactor);
|
||||
myAvatar->setDriveKeys(STEP_YAW, -1.0f * userInputMapper->getActionState(controller::Action::STEP_YAW) / timeFactor);
|
||||
}
|
||||
}
|
||||
myAvatar->setDriveKeys(BOOM_IN, userInputMapper->getActionState(UserInputMapper::BOOM_IN));
|
||||
myAvatar->setDriveKeys(BOOM_OUT, userInputMapper->getActionState(UserInputMapper::BOOM_OUT));
|
||||
myAvatar->setDriveKeys(ZOOM, userInputMapper->getActionState(controller::Action::TRANSLATE_CAMERA_Z));
|
||||
}
|
||||
UserInputMapper::PoseValue leftHand = userInputMapper->getPoseState(UserInputMapper::LEFT_HAND);
|
||||
UserInputMapper::PoseValue rightHand = userInputMapper->getPoseState(UserInputMapper::RIGHT_HAND);
|
||||
|
||||
controller::Pose leftHand = userInputMapper->getPoseState(controller::Action::LEFT_HAND);
|
||||
controller::Pose rightHand = userInputMapper->getPoseState(controller::Action::RIGHT_HAND);
|
||||
Hand* hand = DependencyManager::get<AvatarManager>()->getMyAvatar()->getHand();
|
||||
setPalmData(hand, leftHand, deltaTime, LEFT_HAND_INDEX, userInputMapper->getActionState(UserInputMapper::LEFT_HAND_CLICK));
|
||||
setPalmData(hand, rightHand, deltaTime, RIGHT_HAND_INDEX, userInputMapper->getActionState(UserInputMapper::RIGHT_HAND_CLICK));
|
||||
setPalmData(hand, leftHand, deltaTime, HandData::LeftHand, userInputMapper->getActionState(controller::Action::LEFT_HAND_CLICK));
|
||||
setPalmData(hand, rightHand, deltaTime, HandData::RightHand, userInputMapper->getActionState(controller::Action::RIGHT_HAND_CLICK));
|
||||
if (Menu::getInstance()->isOptionChecked(MenuOption::EnableHandMouseInput)) {
|
||||
emulateMouse(hand, userInputMapper->getActionState(UserInputMapper::LEFT_HAND_CLICK),
|
||||
userInputMapper->getActionState(UserInputMapper::SHIFT), LEFT_HAND_INDEX);
|
||||
emulateMouse(hand, userInputMapper->getActionState(UserInputMapper::RIGHT_HAND_CLICK),
|
||||
userInputMapper->getActionState(UserInputMapper::SHIFT), RIGHT_HAND_INDEX);
|
||||
emulateMouse(hand, userInputMapper->getActionState(controller::Action::LEFT_HAND_CLICK),
|
||||
userInputMapper->getActionState(controller::Action::SHIFT), HandData::LeftHand);
|
||||
emulateMouse(hand, userInputMapper->getActionState(controller::Action::RIGHT_HAND_CLICK),
|
||||
userInputMapper->getActionState(controller::Action::SHIFT), HandData::RightHand);
|
||||
}
|
||||
|
||||
updateThreads(deltaTime); // If running non-threaded, then give the threads some time to process...
|
||||
|
@ -4807,86 +4866,80 @@ mat4 Application::getHMDSensorPose() const {
|
|||
return mat4();
|
||||
}
|
||||
|
||||
void Application::setPalmData(Hand* hand, UserInputMapper::PoseValue pose, float deltaTime, int index, float triggerValue) {
|
||||
PalmData* palm;
|
||||
bool foundHand = false;
|
||||
for (size_t j = 0; j < hand->getNumPalms(); j++) {
|
||||
if (hand->getPalms()[j].getSixenseID() == index) {
|
||||
palm = &(hand->getPalms()[j]);
|
||||
foundHand = true;
|
||||
break;
|
||||
void Application::setPalmData(Hand* hand, const controller::Pose& pose, float deltaTime, HandData::Hand whichHand, float triggerValue) {
|
||||
|
||||
// NOTE: the Hand::modifyPalm() will allow the lambda to modify the palm data while ensuring some other user isn't
|
||||
// reading or writing to the Palms. This is definitely not the best way of handling this, and I'd like to see more
|
||||
// of this palm manipulation in the Hand class itself. But unfortunately the Hand and Palm don't knbow about
|
||||
// controller::Pose. More work is needed to clean this up.
|
||||
hand->modifyPalm(whichHand, [&](PalmData& palm) {
|
||||
auto myAvatar = DependencyManager::get<AvatarManager>()->getMyAvatar();
|
||||
palm.setActive(pose.isValid());
|
||||
|
||||
// transform from sensor space, to world space, to avatar model space.
|
||||
glm::mat4 poseMat = createMatFromQuatAndPos(pose.getRotation(), pose.getTranslation());
|
||||
glm::mat4 sensorToWorldMat = myAvatar->getSensorToWorldMatrix();
|
||||
glm::mat4 modelMat = createMatFromQuatAndPos(myAvatar->getOrientation(), myAvatar->getPosition());
|
||||
glm::mat4 objectPose = glm::inverse(modelMat) * sensorToWorldMat * poseMat;
|
||||
|
||||
glm::vec3 position = extractTranslation(objectPose);
|
||||
glm::quat rotation = glm::quat_cast(objectPose);
|
||||
|
||||
// Compute current velocity from position change
|
||||
glm::vec3 rawVelocity;
|
||||
if (deltaTime > 0.0f) {
|
||||
rawVelocity = (position - palm.getRawPosition()) / deltaTime;
|
||||
} else {
|
||||
rawVelocity = glm::vec3(0.0f);
|
||||
}
|
||||
}
|
||||
if (!foundHand) {
|
||||
PalmData newPalm(hand);
|
||||
hand->getPalms().push_back(newPalm);
|
||||
palm = &(hand->getPalms()[hand->getNumPalms() - 1]);
|
||||
palm->setSixenseID(index);
|
||||
}
|
||||
palm.setRawVelocity(rawVelocity); // meters/sec
|
||||
|
||||
palm->setActive(pose.isValid());
|
||||
// Angular Velocity of Palm
|
||||
glm::quat deltaRotation = rotation * glm::inverse(palm.getRawRotation());
|
||||
glm::vec3 angularVelocity(0.0f);
|
||||
float rotationAngle = glm::angle(deltaRotation);
|
||||
if ((rotationAngle > EPSILON) && (deltaTime > 0.0f)) {
|
||||
angularVelocity = glm::normalize(glm::axis(deltaRotation));
|
||||
angularVelocity *= (rotationAngle / deltaTime);
|
||||
palm.setRawAngularVelocity(angularVelocity);
|
||||
} else {
|
||||
palm.setRawAngularVelocity(glm::vec3(0.0f));
|
||||
}
|
||||
|
||||
// transform from sensor space, to world space, to avatar model space.
|
||||
glm::mat4 poseMat = createMatFromQuatAndPos(pose.getRotation(), pose.getTranslation());
|
||||
glm::mat4 sensorToWorldMat = getMyAvatar()->getSensorToWorldMatrix();
|
||||
glm::mat4 modelMat = createMatFromQuatAndPos(getMyAvatar()->getOrientation(), getMyAvatar()->getPosition());
|
||||
glm::mat4 objectPose = glm::inverse(modelMat) * sensorToWorldMat * poseMat;
|
||||
if (controller::InputDevice::getLowVelocityFilter()) {
|
||||
// Use a velocity sensitive filter to damp small motions and preserve large ones with
|
||||
// no latency.
|
||||
float velocityFilter = glm::clamp(1.0f - glm::length(rawVelocity), 0.0f, 1.0f);
|
||||
position = palm.getRawPosition() * velocityFilter + position * (1.0f - velocityFilter);
|
||||
rotation = safeMix(palm.getRawRotation(), rotation, 1.0f - velocityFilter);
|
||||
}
|
||||
palm.setRawPosition(position);
|
||||
palm.setRawRotation(rotation);
|
||||
|
||||
glm::vec3 position = extractTranslation(objectPose);
|
||||
glm::quat rotation = glm::quat_cast(objectPose);
|
||||
|
||||
// Compute current velocity from position change
|
||||
glm::vec3 rawVelocity;
|
||||
if (deltaTime > 0.0f) {
|
||||
rawVelocity = (position - palm->getRawPosition()) / deltaTime;
|
||||
} else {
|
||||
rawVelocity = glm::vec3(0.0f);
|
||||
}
|
||||
palm->setRawVelocity(rawVelocity); // meters/sec
|
||||
|
||||
// Angular Velocity of Palm
|
||||
glm::quat deltaRotation = rotation * glm::inverse(palm->getRawRotation());
|
||||
glm::vec3 angularVelocity(0.0f);
|
||||
float rotationAngle = glm::angle(deltaRotation);
|
||||
if ((rotationAngle > EPSILON) && (deltaTime > 0.0f)) {
|
||||
angularVelocity = glm::normalize(glm::axis(deltaRotation));
|
||||
angularVelocity *= (rotationAngle / deltaTime);
|
||||
palm->setRawAngularVelocity(angularVelocity);
|
||||
} else {
|
||||
palm->setRawAngularVelocity(glm::vec3(0.0f));
|
||||
}
|
||||
|
||||
if (InputDevice::getLowVelocityFilter()) {
|
||||
// Use a velocity sensitive filter to damp small motions and preserve large ones with
|
||||
// no latency.
|
||||
float velocityFilter = glm::clamp(1.0f - glm::length(rawVelocity), 0.0f, 1.0f);
|
||||
position = palm->getRawPosition() * velocityFilter + position * (1.0f - velocityFilter);
|
||||
rotation = safeMix(palm->getRawRotation(), rotation, 1.0f - velocityFilter);
|
||||
}
|
||||
palm->setRawPosition(position);
|
||||
palm->setRawRotation(rotation);
|
||||
|
||||
// Store the one fingertip in the palm structure so we can track velocity
|
||||
const float FINGER_LENGTH = 0.3f; // meters
|
||||
const glm::vec3 FINGER_VECTOR(0.0f, FINGER_LENGTH, 0.0f);
|
||||
const glm::vec3 newTipPosition = position + rotation * FINGER_VECTOR;
|
||||
glm::vec3 oldTipPosition = palm->getTipRawPosition();
|
||||
if (deltaTime > 0.0f) {
|
||||
palm->setTipVelocity((newTipPosition - oldTipPosition) / deltaTime);
|
||||
} else {
|
||||
palm->setTipVelocity(glm::vec3(0.0f));
|
||||
}
|
||||
palm->setTipPosition(newTipPosition);
|
||||
palm->setTrigger(triggerValue);
|
||||
// Store the one fingertip in the palm structure so we can track velocity
|
||||
const float FINGER_LENGTH = 0.3f; // meters
|
||||
const glm::vec3 FINGER_VECTOR(0.0f, FINGER_LENGTH, 0.0f);
|
||||
const glm::vec3 newTipPosition = position + rotation * FINGER_VECTOR;
|
||||
glm::vec3 oldTipPosition = palm.getTipRawPosition();
|
||||
if (deltaTime > 0.0f) {
|
||||
palm.setTipVelocity((newTipPosition - oldTipPosition) / deltaTime);
|
||||
} else {
|
||||
palm.setTipVelocity(glm::vec3(0.0f));
|
||||
}
|
||||
palm.setTipPosition(newTipPosition);
|
||||
palm.setTrigger(triggerValue); // FIXME - we want to get rid of this idea of PalmData having a trigger
|
||||
});
|
||||
}
|
||||
|
||||
void Application::emulateMouse(Hand* hand, float click, float shift, int index) {
|
||||
void Application::emulateMouse(Hand* hand, float click, float shift, HandData::Hand whichHand) {
|
||||
auto palms = hand->getCopyOfPalms();
|
||||
|
||||
// Locate the palm, if it exists and is active
|
||||
PalmData* palm;
|
||||
bool foundHand = false;
|
||||
for (size_t j = 0; j < hand->getNumPalms(); j++) {
|
||||
if (hand->getPalms()[j].getSixenseID() == index) {
|
||||
palm = &(hand->getPalms()[j]);
|
||||
for (size_t j = 0; j < palms.size(); j++) {
|
||||
if (palms[j].whichHand() == whichHand) {
|
||||
palm = &(palms[j]);
|
||||
foundHand = true;
|
||||
break;
|
||||
}
|
||||
|
@ -4898,12 +4951,14 @@ void Application::emulateMouse(Hand* hand, float click, float shift, int index)
|
|||
// Process the mouse events
|
||||
QPoint pos;
|
||||
|
||||
unsigned int deviceID = index == 0 ? CONTROLLER_0_EVENT : CONTROLLER_1_EVENT;
|
||||
|
||||
// FIXME - this mouse emulation stuff needs to be reworked for new controller input plugins
|
||||
unsigned int deviceID = whichHand == HandData::LeftHand ? CONTROLLER_0_EVENT : CONTROLLER_1_EVENT;
|
||||
int index = (int)whichHand; // FIXME - hack attack
|
||||
|
||||
if (isHMDMode()) {
|
||||
pos = getApplicationCompositor().getPalmClickLocation(palm);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
// Get directon relative to avatar orientation
|
||||
glm::vec3 direction = glm::inverse(getMyAvatar()->getOrientation()) * palm->getFingerDirection();
|
||||
|
||||
|
@ -4912,7 +4967,7 @@ void Application::emulateMouse(Hand* hand, float click, float shift, int index)
|
|||
float yAngle = 0.5f - ((atan2f(direction.z, direction.y) + (float)M_PI_2));
|
||||
auto canvasSize = getCanvasSize();
|
||||
// Get the pixel range over which the xAngle and yAngle are scaled
|
||||
float cursorRange = canvasSize.x * InputDevice::getCursorPixelRangeMult();
|
||||
float cursorRange = canvasSize.x * controller::InputDevice::getCursorPixelRangeMult();
|
||||
|
||||
pos.setX(canvasSize.x / 2.0f + cursorRange * xAngle);
|
||||
pos.setY(canvasSize.y / 2.0f + cursorRange * yAngle);
|
||||
|
|
|
@ -14,13 +14,15 @@
|
|||
|
||||
#include <functional>
|
||||
|
||||
#include <QApplication>
|
||||
#include <QHash>
|
||||
#include <QImage>
|
||||
#include <QPointer>
|
||||
#include <QSet>
|
||||
#include <QStringList>
|
||||
#include <QUndoStack>
|
||||
#include <QtCore/QHash>
|
||||
#include <QtCore/QPointer>
|
||||
#include <QtCore/QSet>
|
||||
#include <QtCore/QStringList>
|
||||
|
||||
#include <QtGui/QImage>
|
||||
|
||||
#include <QtWidgets/QApplication>
|
||||
#include <QtWidgets/QUndoStack>
|
||||
|
||||
#include <AbstractScriptingServicesInterface.h>
|
||||
#include <AbstractViewStateInterface.h>
|
||||
|
@ -69,6 +71,10 @@ class FaceTracker;
|
|||
class MainWindow;
|
||||
class AssetUpload;
|
||||
|
||||
namespace controller {
|
||||
class StateController;
|
||||
}
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
static const UINT UWM_IDENTIFY_INSTANCES =
|
||||
RegisterWindowMessage("UWM_IDENTIFY_INSTANCES_{8AB82783-B74A-4258-955B-8188C22AA0D6}_" + qgetenv("USERNAME"));
|
||||
|
@ -161,7 +167,7 @@ public:
|
|||
|
||||
ToolWindow* getToolWindow() { return _toolWindow ; }
|
||||
|
||||
virtual AbstractControllerScriptingInterface* getControllerScriptingInterface() { return &_controllerScriptingInterface; }
|
||||
virtual controller::ScriptingInterface* getControllerScriptingInterface() { return _controllerScriptingInterface; }
|
||||
virtual void registerScriptEngineWithApplicationServices(ScriptEngine* scriptEngine);
|
||||
|
||||
QImage renderAvatarBillboard(RenderArgs* renderArgs);
|
||||
|
@ -287,8 +293,9 @@ public slots:
|
|||
void aboutApp();
|
||||
void showEditEntitiesHelp();
|
||||
|
||||
void cycleCamera();
|
||||
void cameraMenuChanged();
|
||||
|
||||
|
||||
void reloadResourceCaches();
|
||||
|
||||
void crashApplication();
|
||||
|
@ -350,8 +357,8 @@ private:
|
|||
|
||||
void update(float deltaTime);
|
||||
|
||||
void setPalmData(Hand* hand, UserInputMapper::PoseValue pose, float deltaTime, int index, float triggerValue);
|
||||
void emulateMouse(Hand* hand, float click, float shift, int index);
|
||||
void setPalmData(Hand* hand, const controller::Pose& pose, float deltaTime, HandData::Hand whichHand, float triggerValue);
|
||||
void emulateMouse(Hand* hand, float click, float shift, HandData::Hand whichHand);
|
||||
|
||||
// Various helper functions called during update()
|
||||
void updateLOD();
|
||||
|
@ -440,7 +447,8 @@ private:
|
|||
|
||||
OctreeQuery _octreeQuery; // NodeData derived class for querying octee cells from octree servers
|
||||
|
||||
KeyboardMouseDevice* _keyboardMouseDevice{ nullptr }; // Default input device, the good old keyboard mouse and maybe touchpad
|
||||
std::shared_ptr<controller::StateController> _applicationStateDevice; // Default ApplicationDevice reflecting the state of different properties of the session
|
||||
std::shared_ptr<KeyboardMouseDevice> _keyboardMouseDevice; // Default input device, the good old keyboard mouse and maybe touchpad
|
||||
AvatarUpdate* _avatarUpdate {nullptr};
|
||||
SimpleMovingAverage _avatarSimsPerSecond {10};
|
||||
int _avatarSimsPerSecondReport {0};
|
||||
|
@ -474,8 +482,7 @@ private:
|
|||
|
||||
NodeToJurisdictionMap _entityServerJurisdictions;
|
||||
NodeToOctreeSceneStats _octreeServerSceneStats;
|
||||
|
||||
ControllerScriptingInterface _controllerScriptingInterface;
|
||||
ControllerScriptingInterface* _controllerScriptingInterface{ nullptr };
|
||||
QPointer<LogDialog> _logDialog;
|
||||
QPointer<SnapshotShareDialog> _snapshotShareDialog;
|
||||
|
||||
|
@ -521,10 +528,13 @@ private:
|
|||
ApplicationCompositor _compositor;
|
||||
OverlayConductor _overlayConductor;
|
||||
|
||||
int _oldHandMouseX[2];
|
||||
int _oldHandMouseY[2];
|
||||
bool _oldHandLeftClick[2];
|
||||
bool _oldHandRightClick[2];
|
||||
|
||||
// FIXME - Hand Controller to mouse emulation helpers. This is crufty and should be moved
|
||||
// into the input plugins or something.
|
||||
int _oldHandMouseX[(int)HandData::NUMBER_OF_HANDS];
|
||||
int _oldHandMouseY[(int)HandData::NUMBER_OF_HANDS];
|
||||
bool _oldHandLeftClick[(int)HandData::NUMBER_OF_HANDS];
|
||||
bool _oldHandRightClick[(int)HandData::NUMBER_OF_HANDS];
|
||||
|
||||
DialogsManagerScriptingInterface* _dialogsManagerScriptingInterface = new DialogsManagerScriptingInterface();
|
||||
|
||||
|
|
|
@ -464,11 +464,13 @@ Menu::Menu() {
|
|||
addCheckableActionToQMenuAndActionHash(avatarDebugMenu, MenuOption::MeshVisible, 0, true,
|
||||
avatar, SLOT(setEnableMeshVisible(bool)));
|
||||
addCheckableActionToQMenuAndActionHash(avatarDebugMenu, MenuOption::DisableEyelidAdjustment, 0, false);
|
||||
#if 0
|
||||
addCheckableActionToQMenuAndActionHash(avatarDebugMenu,
|
||||
MenuOption::Connexion,
|
||||
0, false,
|
||||
&ConnexionClient::getInstance(),
|
||||
SLOT(toggleConnexion(bool)));
|
||||
#endif
|
||||
addCheckableActionToQMenuAndActionHash(avatarDebugMenu, MenuOption::ComfortMode, 0, true);
|
||||
|
||||
MenuWrapper* handOptionsMenu = developerMenu->addMenu("Hands");
|
||||
|
|
|
@ -13,7 +13,6 @@
|
|||
#include "ui/DialogsManager.h"
|
||||
|
||||
PluginContainerProxy::PluginContainerProxy() {
|
||||
Plugin::setContainer(this);
|
||||
}
|
||||
|
||||
PluginContainerProxy::~PluginContainerProxy() {
|
||||
|
|
|
@ -1177,22 +1177,6 @@ glm::vec3 Avatar::getLeftPalmPosition() {
|
|||
return leftHandPosition;
|
||||
}
|
||||
|
||||
glm::vec3 Avatar::getLeftPalmVelocity() {
|
||||
const PalmData* palm = getHand()->getPalm(LEFT_HAND_INDEX);
|
||||
if (palm != NULL) {
|
||||
return palm->getVelocity();
|
||||
}
|
||||
return glm::vec3(0.0f);
|
||||
}
|
||||
|
||||
glm::vec3 Avatar::getLeftPalmAngularVelocity() {
|
||||
const PalmData* palm = getHand()->getPalm(LEFT_HAND_INDEX);
|
||||
if (palm != NULL) {
|
||||
return palm->getRawAngularVelocity();
|
||||
}
|
||||
return glm::vec3(0.0f);
|
||||
}
|
||||
|
||||
glm::quat Avatar::getLeftPalmRotation() {
|
||||
glm::quat leftRotation;
|
||||
getSkeletonModel().getJointRotationInWorldFrame(getSkeletonModel().getLeftHandJointIndex(), leftRotation);
|
||||
|
@ -1208,22 +1192,6 @@ glm::vec3 Avatar::getRightPalmPosition() {
|
|||
return rightHandPosition;
|
||||
}
|
||||
|
||||
glm::vec3 Avatar::getRightPalmVelocity() {
|
||||
const PalmData* palm = getHand()->getPalm(RIGHT_HAND_INDEX);
|
||||
if (palm != NULL) {
|
||||
return palm->getVelocity();
|
||||
}
|
||||
return glm::vec3(0.0f);
|
||||
}
|
||||
|
||||
glm::vec3 Avatar::getRightPalmAngularVelocity() {
|
||||
const PalmData* palm = getHand()->getPalm(RIGHT_HAND_INDEX);
|
||||
if (palm != NULL) {
|
||||
return palm->getRawAngularVelocity();
|
||||
}
|
||||
return glm::vec3(0.0f);
|
||||
}
|
||||
|
||||
glm::quat Avatar::getRightPalmRotation() {
|
||||
glm::quat rightRotation;
|
||||
getSkeletonModel().getJointRotationInWorldFrame(getSkeletonModel().getRightHandJointIndex(), rightRotation);
|
||||
|
|
|
@ -43,21 +43,6 @@ static const float BILLBOARD_DISTANCE = 5.56f; // meters
|
|||
extern const float CHAT_MESSAGE_SCALE;
|
||||
extern const float CHAT_MESSAGE_HEIGHT;
|
||||
|
||||
enum DriveKeys {
|
||||
FWD = 0,
|
||||
BACK,
|
||||
LEFT,
|
||||
RIGHT,
|
||||
UP,
|
||||
DOWN,
|
||||
ROT_LEFT,
|
||||
ROT_RIGHT,
|
||||
ROT_UP,
|
||||
ROT_DOWN,
|
||||
BOOM_IN,
|
||||
BOOM_OUT,
|
||||
MAX_DRIVE_KEYS
|
||||
};
|
||||
|
||||
enum ScreenTintLayer {
|
||||
SCREEN_TINT_BEFORE_LANDSCAPE = 0,
|
||||
|
@ -175,13 +160,11 @@ public:
|
|||
AvatarMotionState* getMotionState() { return _motionState; }
|
||||
|
||||
public slots:
|
||||
|
||||
// FIXME - these should be migrated to use Pose data instead
|
||||
glm::vec3 getLeftPalmPosition();
|
||||
glm::vec3 getLeftPalmVelocity();
|
||||
glm::vec3 getLeftPalmAngularVelocity();
|
||||
glm::quat getLeftPalmRotation();
|
||||
glm::vec3 getRightPalmPosition();
|
||||
glm::vec3 getRightPalmVelocity();
|
||||
glm::vec3 getRightPalmAngularVelocity();
|
||||
glm::quat getRightPalmRotation();
|
||||
|
||||
protected:
|
||||
|
|
|
@ -119,6 +119,8 @@ void AvatarActionHold::doKinematicUpdate(float deltaTimeStep) {
|
|||
worldTrans.setRotation(glmToBullet(_rotationalTarget));
|
||||
rigidBody->setWorldTransform(worldTrans);
|
||||
|
||||
motionState->dirtyInternalKinematicChanges();
|
||||
|
||||
_previousPositionalTarget = _positionalTarget;
|
||||
_previousRotationalTarget = _rotationalTarget;
|
||||
_previousSet = true;
|
||||
|
@ -224,6 +226,8 @@ QVariantMap AvatarActionHold::getArguments() {
|
|||
arguments["relativeRotation"] = glmToQMap(_relativeRotation);
|
||||
arguments["timeScale"] = _linearTimeScale;
|
||||
arguments["hand"] = _hand;
|
||||
arguments["kinematic"] = _kinematic;
|
||||
arguments["kinematicSetVelocity"] = _kinematicSetVelocity;
|
||||
});
|
||||
return arguments;
|
||||
}
|
||||
|
|
|
@ -248,6 +248,16 @@ QVector<AvatarManager::LocalLight> AvatarManager::getLocalLights() const {
|
|||
return _localLights;
|
||||
}
|
||||
|
||||
QVector<QUuid> AvatarManager::getAvatarIdentifiers() {
|
||||
QReadLocker locker(&_hashLock);
|
||||
return _avatarHash.keys().toVector();
|
||||
}
|
||||
AvatarData* AvatarManager::getAvatar(QUuid avatarID) {
|
||||
QReadLocker locker(&_hashLock);
|
||||
return _avatarHash[avatarID].get(); // Non-obvious: A bogus avatarID answers your own avatar.
|
||||
}
|
||||
|
||||
|
||||
void AvatarManager::getObjectsToDelete(VectorOfMotionStates& result) {
|
||||
result.clear();
|
||||
result.swap(_motionStatesToDelete);
|
||||
|
@ -356,5 +366,10 @@ AvatarSharedPointer AvatarManager::getAvatarBySessionID(const QUuid& sessionID)
|
|||
return std::static_pointer_cast<Avatar>(_myAvatar);
|
||||
}
|
||||
QReadLocker locker(&_hashLock);
|
||||
return _avatarHash[sessionID];
|
||||
auto iter = _avatarHash.find(sessionID);
|
||||
if (iter != _avatarHash.end()) {
|
||||
return iter.value();
|
||||
} else {
|
||||
return AvatarSharedPointer();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -52,6 +52,10 @@ public:
|
|||
|
||||
Q_INVOKABLE void setLocalLights(const QVector<AvatarManager::LocalLight>& localLights);
|
||||
Q_INVOKABLE QVector<AvatarManager::LocalLight> getLocalLights() const;
|
||||
// Currently, your own avatar will be included as the null avatar id.
|
||||
Q_INVOKABLE QVector<QUuid> getAvatarIdentifiers();
|
||||
Q_INVOKABLE AvatarData* getAvatar(QUuid avatarID);
|
||||
|
||||
|
||||
void getObjectsToDelete(VectorOfMotionStates& motionStates);
|
||||
void getObjectsToAdd(VectorOfMotionStates& motionStates);
|
||||
|
|
|
@ -31,13 +31,7 @@ Hand::Hand(Avatar* owningAvatar) :
|
|||
}
|
||||
|
||||
void Hand::simulate(float deltaTime, bool isMine) {
|
||||
if (isMine) {
|
||||
// Iterate hand controllers, take actions as needed
|
||||
for (size_t i = 0; i < getNumPalms(); ++i) {
|
||||
PalmData& palm = getPalms()[i];
|
||||
palm.setLastControllerButtons(palm.getControllerButtons());
|
||||
}
|
||||
}
|
||||
// nothing to do here
|
||||
}
|
||||
|
||||
void Hand::renderHandTargets(RenderArgs* renderArgs, bool isMine) {
|
||||
|
@ -53,10 +47,11 @@ void Hand::renderHandTargets(RenderArgs* renderArgs, bool isMine) {
|
|||
const glm::vec3 grayColor(0.5f);
|
||||
const float SPHERE_RADIUS = 0.03f * avatarScale;
|
||||
|
||||
auto palms = getCopyOfPalms();
|
||||
|
||||
gpu::Batch& batch = *renderArgs->_batch;
|
||||
if (isMine) {
|
||||
for (size_t i = 0; i < getNumPalms(); i++) {
|
||||
PalmData& palm = getPalms()[i];
|
||||
for (const auto& palm : palms) {
|
||||
if (!palm.isActive()) {
|
||||
continue;
|
||||
}
|
||||
|
@ -82,8 +77,7 @@ void Hand::renderHandTargets(RenderArgs* renderArgs, bool isMine) {
|
|||
const float AXIS_LENGTH = 10.0f * SPHERE_RADIUS;
|
||||
|
||||
// Draw the coordinate frames of the hand targets
|
||||
for (size_t i = 0; i < getNumPalms(); ++i) {
|
||||
PalmData& palm = getPalms()[i];
|
||||
for (const auto& palm : palms) {
|
||||
if (palm.isActive()) {
|
||||
glm::vec3 root = palm.getPosition();
|
||||
|
||||
|
|
|
@ -53,6 +53,7 @@
|
|||
|
||||
using namespace std;
|
||||
|
||||
static quint64 COMFORT_MODE_PULSE_TIMING = USECS_PER_SECOND / 2; // turn once per half second
|
||||
const glm::vec3 DEFAULT_UP_DIRECTION(0.0f, 1.0f, 0.0f);
|
||||
const float YAW_SPEED = 150.0f; // degrees/sec
|
||||
const float PITCH_SPEED = 100.0f; // degrees/sec
|
||||
|
@ -246,8 +247,31 @@ void MyAvatar::simulate(float deltaTime) {
|
|||
|
||||
{
|
||||
PerformanceTimer perfTimer("transform");
|
||||
bool stepAction = false;
|
||||
// When there are no step values, we zero out the last step pulse.
|
||||
// This allows a user to do faster snapping by tapping a control
|
||||
for (int i = STEP_TRANSLATE_X; !stepAction && i <= STEP_YAW; ++i) {
|
||||
if (_driveKeys[i] != 0.0f) {
|
||||
stepAction = true;
|
||||
}
|
||||
}
|
||||
quint64 now = usecTimestampNow();
|
||||
quint64 pulseDeltaTime = now - _lastStepPulse;
|
||||
if (!stepAction) {
|
||||
_lastStepPulse = 0;
|
||||
}
|
||||
|
||||
if (stepAction && pulseDeltaTime > COMFORT_MODE_PULSE_TIMING) {
|
||||
_pulseUpdate = true;
|
||||
}
|
||||
|
||||
updateOrientation(deltaTime);
|
||||
updatePosition(deltaTime);
|
||||
|
||||
if (_pulseUpdate) {
|
||||
_lastStepPulse = now;
|
||||
_pulseUpdate = false;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
|
@ -531,6 +555,50 @@ void MyAvatar::updateFromTrackers(float deltaTime) {
|
|||
}
|
||||
|
||||
|
||||
glm::vec3 MyAvatar::getLeftHandPosition() const {
|
||||
auto palmData = getHandData()->getCopyOfPalmData(HandData::LeftHand);
|
||||
return palmData.isValid() ? palmData.getPosition() : glm::vec3(0.0f);
|
||||
}
|
||||
|
||||
glm::vec3 MyAvatar::getRightHandPosition() const {
|
||||
auto palmData = getHandData()->getCopyOfPalmData(HandData::RightHand);
|
||||
return palmData.isValid() ? palmData.getPosition() : glm::vec3(0.0f);
|
||||
}
|
||||
|
||||
glm::vec3 MyAvatar::getLeftHandTipPosition() const {
|
||||
auto palmData = getHandData()->getCopyOfPalmData(HandData::LeftHand);
|
||||
return palmData.isValid() ? palmData.getTipPosition() : glm::vec3(0.0f);
|
||||
}
|
||||
|
||||
glm::vec3 MyAvatar::getRightHandTipPosition() const {
|
||||
auto palmData = getHandData()->getCopyOfPalmData(HandData::RightHand);
|
||||
return palmData.isValid() ? palmData.getTipPosition() : glm::vec3(0.0f);
|
||||
}
|
||||
|
||||
controller::Pose MyAvatar::getLeftHandPose() const {
|
||||
auto palmData = getHandData()->getCopyOfPalmData(HandData::LeftHand);
|
||||
return palmData.isValid() ? controller::Pose(palmData.getPosition(), palmData.getRotation(),
|
||||
palmData.getVelocity(), palmData.getRawAngularVelocityAsQuat()) : controller::Pose();
|
||||
}
|
||||
|
||||
controller::Pose MyAvatar::getRightHandPose() const {
|
||||
auto palmData = getHandData()->getCopyOfPalmData(HandData::RightHand);
|
||||
return palmData.isValid() ? controller::Pose(palmData.getPosition(), palmData.getRotation(),
|
||||
palmData.getVelocity(), palmData.getRawAngularVelocityAsQuat()) : controller::Pose();
|
||||
}
|
||||
|
||||
controller::Pose MyAvatar::getLeftHandTipPose() const {
|
||||
auto palmData = getHandData()->getCopyOfPalmData(HandData::LeftHand);
|
||||
return palmData.isValid() ? controller::Pose(palmData.getTipPosition(), palmData.getRotation(),
|
||||
palmData.getTipVelocity(), palmData.getRawAngularVelocityAsQuat()) : controller::Pose();
|
||||
}
|
||||
|
||||
controller::Pose MyAvatar::getRightHandTipPose() const {
|
||||
auto palmData = getHandData()->getCopyOfPalmData(HandData::RightHand);
|
||||
return palmData.isValid() ? controller::Pose(palmData.getTipPosition(), palmData.getRotation(),
|
||||
palmData.getTipVelocity(), palmData.getRawAngularVelocityAsQuat()) : controller::Pose();
|
||||
}
|
||||
|
||||
// virtual
|
||||
void MyAvatar::render(RenderArgs* renderArgs, const glm::vec3& cameraPosition) {
|
||||
// don't render if we've been asked to disable local rendering
|
||||
|
@ -1533,69 +1601,44 @@ bool MyAvatar::shouldRenderHead(const RenderArgs* renderArgs) const {
|
|||
|
||||
void MyAvatar::updateOrientation(float deltaTime) {
|
||||
// Smoothly rotate body with arrow keys
|
||||
float targetSpeed = 0.0f;
|
||||
|
||||
// FIXME - this comfort mode code is a total hack, remove it when we have new input mapping
|
||||
bool isComfortMode = Menu::getInstance()->isOptionChecked(MenuOption::ComfortMode);
|
||||
bool isHMDMode = qApp->getAvatarUpdater()->isHMDMode();
|
||||
|
||||
if (!isHMDMode || !isComfortMode) {
|
||||
targetSpeed = (_driveKeys[ROT_LEFT] - _driveKeys[ROT_RIGHT]) * YAW_SPEED;
|
||||
|
||||
if (targetSpeed != 0.0f) {
|
||||
const float ROTATION_RAMP_TIMESCALE = 0.1f;
|
||||
float blend = deltaTime / ROTATION_RAMP_TIMESCALE;
|
||||
if (blend > 1.0f) {
|
||||
blend = 1.0f;
|
||||
}
|
||||
_bodyYawDelta = (1.0f - blend) * _bodyYawDelta + blend * targetSpeed;
|
||||
} else if (_bodyYawDelta != 0.0f) {
|
||||
// attenuate body rotation speed
|
||||
const float ROTATION_DECAY_TIMESCALE = 0.05f;
|
||||
float attenuation = 1.0f - deltaTime / ROTATION_DECAY_TIMESCALE;
|
||||
if (attenuation < 0.0f) {
|
||||
attenuation = 0.0f;
|
||||
}
|
||||
_bodyYawDelta *= attenuation;
|
||||
|
||||
float MINIMUM_ROTATION_RATE = 2.0f;
|
||||
if (fabsf(_bodyYawDelta) < MINIMUM_ROTATION_RATE) {
|
||||
_bodyYawDelta = 0.0f;
|
||||
}
|
||||
float targetSpeed = _driveKeys[YAW] * YAW_SPEED;
|
||||
if (targetSpeed != 0.0f) {
|
||||
const float ROTATION_RAMP_TIMESCALE = 0.1f;
|
||||
float blend = deltaTime / ROTATION_RAMP_TIMESCALE;
|
||||
if (blend > 1.0f) {
|
||||
blend = 1.0f;
|
||||
}
|
||||
_bodyYawDelta = (1.0f - blend) * _bodyYawDelta + blend * targetSpeed;
|
||||
} else if (_bodyYawDelta != 0.0f) {
|
||||
// attenuate body rotation speed
|
||||
const float ROTATION_DECAY_TIMESCALE = 0.05f;
|
||||
float attenuation = 1.0f - deltaTime / ROTATION_DECAY_TIMESCALE;
|
||||
if (attenuation < 0.0f) {
|
||||
attenuation = 0.0f;
|
||||
}
|
||||
_bodyYawDelta *= attenuation;
|
||||
|
||||
// update body orientation by movement inputs
|
||||
setOrientation(getOrientation() *
|
||||
glm::quat(glm::radians(glm::vec3(0.0f, _bodyYawDelta * deltaTime, 0.0f))));
|
||||
|
||||
} else {
|
||||
// Comfort Mode: If you press any of the left/right rotation drive keys or input, you'll
|
||||
// get an instantaneous 15 degree turn. If you keep holding the key down you'll get another
|
||||
// snap turn every half second.
|
||||
_bodyYawDelta = 0.0f;
|
||||
|
||||
static quint64 lastPulse = 0;
|
||||
quint64 now = usecTimestampNow();
|
||||
quint64 COMFORT_MODE_PULSE_TIMING = USECS_PER_SECOND / 2; // turn once per half second
|
||||
|
||||
float driveLeft = _driveKeys[ROT_LEFT];
|
||||
float driveRight= _driveKeys[ROT_RIGHT];
|
||||
|
||||
if ((driveLeft != 0.0f || driveRight != 0.0f) && (now - lastPulse > COMFORT_MODE_PULSE_TIMING)) {
|
||||
lastPulse = now;
|
||||
|
||||
const float SNAP_TURN_DELTA = 15.0f; // degrees
|
||||
float direction = (driveLeft - driveRight) < 0.0f ? -1.0f : 1.0f;
|
||||
float turnAmount = direction * SNAP_TURN_DELTA;
|
||||
|
||||
// update body orientation by movement inputs
|
||||
setOrientation(getOrientation() *
|
||||
glm::quat(glm::radians(glm::vec3(0.0f, turnAmount, 0.0f))));
|
||||
|
||||
float MINIMUM_ROTATION_RATE = 2.0f;
|
||||
if (fabsf(_bodyYawDelta) < MINIMUM_ROTATION_RATE) {
|
||||
_bodyYawDelta = 0.0f;
|
||||
}
|
||||
}
|
||||
|
||||
getHead()->setBasePitch(getHead()->getBasePitch() + (_driveKeys[ROT_UP] - _driveKeys[ROT_DOWN]) * PITCH_SPEED * deltaTime);
|
||||
float totalBodyYaw = _bodyYawDelta * deltaTime;
|
||||
|
||||
|
||||
// Comfort Mode: If you press any of the left/right rotation drive keys or input, you'll
|
||||
// get an instantaneous 15 degree turn. If you keep holding the key down you'll get another
|
||||
// snap turn every half second.
|
||||
quint64 now = usecTimestampNow();
|
||||
if (_driveKeys[STEP_YAW] != 0.0f && now - _lastStepPulse > COMFORT_MODE_PULSE_TIMING) {
|
||||
totalBodyYaw += _driveKeys[STEP_YAW];
|
||||
}
|
||||
|
||||
// update body orientation by movement inputs
|
||||
setOrientation(getOrientation() * glm::quat(glm::radians(glm::vec3(0.0f, totalBodyYaw, 0.0f))));
|
||||
|
||||
getHead()->setBasePitch(getHead()->getBasePitch() + _driveKeys[PITCH] * PITCH_SPEED * deltaTime);
|
||||
|
||||
if (qApp->getAvatarUpdater()->isHMDMode()) {
|
||||
glm::quat orientation = glm::quat_cast(getSensorToWorldMatrix()) * getHMDSensorOrientation();
|
||||
|
@ -1655,14 +1698,18 @@ glm::vec3 MyAvatar::applyKeyboardMotor(float deltaTime, const glm::vec3& localVe
|
|||
float motorEfficiency = glm::clamp(deltaTime / timescale, 0.0f, 1.0f);
|
||||
|
||||
glm::vec3 newLocalVelocity = localVelocity;
|
||||
float keyboardInput = fabsf(_driveKeys[FWD] - _driveKeys[BACK]) +
|
||||
(fabsf(_driveKeys[RIGHT] - _driveKeys[LEFT])) +
|
||||
fabsf(_driveKeys[UP] - _driveKeys[DOWN]);
|
||||
float stepControllerInput = fabsf(_driveKeys[STEP_TRANSLATE_Z]) + fabsf(_driveKeys[STEP_TRANSLATE_Z]) + fabsf(_driveKeys[STEP_TRANSLATE_Z]);
|
||||
quint64 now = usecTimestampNow();
|
||||
// FIXME how do I implement step translation as well?
|
||||
if (stepControllerInput && now - _lastStepPulse > COMFORT_MODE_PULSE_TIMING) {
|
||||
}
|
||||
|
||||
float keyboardInput = fabsf(_driveKeys[TRANSLATE_Z]) + fabsf(_driveKeys[TRANSLATE_X]) + fabsf(_driveKeys[TRANSLATE_Y]);
|
||||
if (keyboardInput) {
|
||||
// Compute keyboard input
|
||||
glm::vec3 front = (_driveKeys[FWD] - _driveKeys[BACK]) * IDENTITY_FRONT;
|
||||
glm::vec3 right = (_driveKeys[RIGHT] - _driveKeys[LEFT]) * IDENTITY_RIGHT;
|
||||
glm::vec3 up = (_driveKeys[UP] - _driveKeys[DOWN]) * IDENTITY_UP;
|
||||
glm::vec3 front = (_driveKeys[TRANSLATE_Z]) * IDENTITY_FRONT;
|
||||
glm::vec3 right = (_driveKeys[TRANSLATE_X]) * IDENTITY_RIGHT;
|
||||
glm::vec3 up = (_driveKeys[TRANSLATE_Y]) * IDENTITY_UP;
|
||||
|
||||
glm::vec3 direction = front + right + up;
|
||||
float directionLength = glm::length(direction);
|
||||
|
@ -1713,7 +1760,7 @@ glm::vec3 MyAvatar::applyKeyboardMotor(float deltaTime, const glm::vec3& localVe
|
|||
}
|
||||
}
|
||||
|
||||
float boomChange = _driveKeys[BOOM_OUT] - _driveKeys[BOOM_IN];
|
||||
float boomChange = _driveKeys[ZOOM];
|
||||
_boomLength += 2.0f * _boomLength * boomChange + boomChange * boomChange;
|
||||
_boomLength = glm::clamp<float>(_boomLength, ZOOM_MIN, ZOOM_MAX);
|
||||
|
||||
|
@ -1915,28 +1962,6 @@ void MyAvatar::updateMotionBehaviorFromMenu() {
|
|||
_characterController.setEnabled(menu->isOptionChecked(MenuOption::EnableCharacterController));
|
||||
}
|
||||
|
||||
//Renders sixense laser pointers for UI selection with controllers
|
||||
void MyAvatar::renderLaserPointers(gpu::Batch& batch) {
|
||||
const float PALM_TIP_ROD_RADIUS = 0.002f;
|
||||
|
||||
//If the Oculus is enabled, we will draw a blue cursor ray
|
||||
|
||||
for (size_t i = 0; i < getHand()->getNumPalms(); ++i) {
|
||||
PalmData& palm = getHand()->getPalms()[i];
|
||||
if (palm.isActive()) {
|
||||
glm::vec3 tip = getLaserPointerTipPosition(&palm);
|
||||
glm::vec3 root = palm.getPosition();
|
||||
|
||||
//Scale the root vector with the avatar scale
|
||||
scaleVectorRelativeToPosition(root);
|
||||
Transform transform = Transform();
|
||||
transform.setTranslation(glm::vec3());
|
||||
batch.setModelTransform(transform);
|
||||
Avatar::renderJointConnectingCone(batch, root, tip, PALM_TIP_ROD_RADIUS, PALM_TIP_ROD_RADIUS, glm::vec4(0, 1, 1, 1));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Gets the tip position for the laser pointer
|
||||
glm::vec3 MyAvatar::getLaserPointerTipPosition(const PalmData* palm) {
|
||||
glm::vec3 direction = glm::normalize(palm->getTipPosition() - palm->getPosition());
|
||||
|
@ -1962,7 +1987,7 @@ void MyAvatar::clearDriveKeys() {
|
|||
}
|
||||
|
||||
void MyAvatar::relayDriveKeysToCharacterController() {
|
||||
if (_driveKeys[UP] > 0.0f) {
|
||||
if (_driveKeys[TRANSLATE_Y] > 0.0f) {
|
||||
_characterController.jump();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,6 +17,8 @@
|
|||
#include <SettingHandle.h>
|
||||
#include <Rig.h>
|
||||
|
||||
#include <controllers/Pose.h>
|
||||
|
||||
#include "Avatar.h"
|
||||
#include "AtRestDetector.h"
|
||||
#include "MyCharacterController.h"
|
||||
|
@ -24,6 +26,20 @@
|
|||
|
||||
class ModelItemID;
|
||||
|
||||
enum DriveKeys {
|
||||
TRANSLATE_X = 0,
|
||||
TRANSLATE_Y,
|
||||
TRANSLATE_Z,
|
||||
YAW,
|
||||
STEP_TRANSLATE_X,
|
||||
STEP_TRANSLATE_Y,
|
||||
STEP_TRANSLATE_Z,
|
||||
STEP_YAW,
|
||||
PITCH,
|
||||
ZOOM,
|
||||
MAX_DRIVE_KEYS
|
||||
};
|
||||
|
||||
enum eyeContactTarget {
|
||||
LEFT_EYE,
|
||||
RIGHT_EYE,
|
||||
|
@ -37,7 +53,6 @@ enum AudioListenerMode {
|
|||
};
|
||||
Q_DECLARE_METATYPE(AudioListenerMode);
|
||||
|
||||
|
||||
class MyAvatar : public Avatar {
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(bool shouldRenderLocally READ getShouldRenderLocally WRITE setShouldRenderLocally)
|
||||
|
@ -53,6 +68,17 @@ class MyAvatar : public Avatar {
|
|||
Q_PROPERTY(AudioListenerMode CUSTOM READ getAudioListenerModeCustom)
|
||||
//TODO: make gravity feature work Q_PROPERTY(glm::vec3 gravity READ getGravity WRITE setGravity)
|
||||
|
||||
|
||||
Q_PROPERTY(glm::vec3 leftHandPosition READ getLeftHandPosition)
|
||||
Q_PROPERTY(glm::vec3 rightHandPosition READ getRightHandPosition)
|
||||
Q_PROPERTY(glm::vec3 leftHandTipPosition READ getLeftHandTipPosition)
|
||||
Q_PROPERTY(glm::vec3 rightHandTipPosition READ getRightHandTipPosition)
|
||||
|
||||
Q_PROPERTY(controller::Pose leftHandPose READ getLeftHandPose)
|
||||
Q_PROPERTY(controller::Pose rightHandPose READ getRightHandPose)
|
||||
Q_PROPERTY(controller::Pose leftHandTipPose READ getLeftHandTipPose)
|
||||
Q_PROPERTY(controller::Pose rightHandTipPose READ getRightHandTipPose)
|
||||
|
||||
public:
|
||||
MyAvatar(RigPointer rig);
|
||||
~MyAvatar();
|
||||
|
@ -111,6 +137,18 @@ public:
|
|||
Q_INVOKABLE AnimationDetails getAnimationDetailsByRole(const QString& role);
|
||||
Q_INVOKABLE AnimationDetails getAnimationDetails(const QString& url);
|
||||
void clearJointAnimationPriorities();
|
||||
// Adds handler(animStateDictionaryIn) => animStateDictionaryOut, which will be invoked just before each animGraph state update.
|
||||
// The handler will be called with an animStateDictionaryIn that has all those properties specified by the (possibly empty)
|
||||
// propertiesList argument. However for debugging, if the properties argument is null, all internal animGraph state is provided.
|
||||
// The animStateDictionaryOut can be a different object than animStateDictionaryIn. Any properties set in animStateDictionaryOut
|
||||
// will override those of the internal animation machinery.
|
||||
// The animStateDictionaryIn may be shared among multiple handlers, and thus may contain additional properties specified when
|
||||
// adding one of the other handlers. While any handler may change a value in animStateDictionaryIn (or supply different values in animStateDictionaryOut)
|
||||
// a handler must not remove properties from animStateDictionaryIn, nor change property values that it does not intend to change.
|
||||
// It is not specified in what order multiple handlers are called.
|
||||
Q_INVOKABLE QScriptValue addAnimationStateHandler(QScriptValue handler, QScriptValue propertiesList) { return _rig->addAnimationStateHandler(handler, propertiesList); }
|
||||
// Removes a handler previously added by addAnimationStateHandler.
|
||||
Q_INVOKABLE void removeAnimationStateHandler(QScriptValue handler) { _rig->removeAnimationStateHandler(handler); }
|
||||
|
||||
// get/set avatar data
|
||||
void saveData();
|
||||
|
@ -141,6 +179,16 @@ public:
|
|||
|
||||
Q_INVOKABLE glm::vec3 getTargetAvatarPosition() const { return _targetAvatarPosition; }
|
||||
|
||||
Q_INVOKABLE glm::vec3 getLeftHandPosition() const;
|
||||
Q_INVOKABLE glm::vec3 getRightHandPosition() const;
|
||||
Q_INVOKABLE glm::vec3 getLeftHandTipPosition() const;
|
||||
Q_INVOKABLE glm::vec3 getRightHandTipPosition() const;
|
||||
|
||||
Q_INVOKABLE controller::Pose getLeftHandPose() const;
|
||||
Q_INVOKABLE controller::Pose getRightHandPose() const;
|
||||
Q_INVOKABLE controller::Pose getLeftHandTipPose() const;
|
||||
Q_INVOKABLE controller::Pose getRightHandTipPose() const;
|
||||
|
||||
AvatarWeakPointer getLookAtTargetAvatar() const { return _lookAtTargetAvatar; }
|
||||
void updateLookAtTargetAvatar();
|
||||
void clearLookAtTargetAvatar();
|
||||
|
@ -265,7 +313,6 @@ private:
|
|||
const glm::vec3& translation = glm::vec3(), const glm::quat& rotation = glm::quat(), float scale = 1.0f,
|
||||
bool allowDuplicates = false, bool useSaved = true) override;
|
||||
|
||||
void renderLaserPointers(gpu::Batch& batch);
|
||||
const RecorderPointer getRecorder() const { return _recorder; }
|
||||
const PlayerPointer getPlayer() const { return _player; }
|
||||
|
||||
|
@ -281,6 +328,8 @@ private:
|
|||
|
||||
void setVisibleInSceneIfReady(Model* model, render::ScenePointer scene, bool visiblity);
|
||||
|
||||
PalmData getActivePalmData(int palmIndex) const;
|
||||
|
||||
// derive avatar body position and orientation from the current HMD Sensor location.
|
||||
// results are in sensor space
|
||||
glm::mat4 deriveBodyFromHMDSensor() const;
|
||||
|
@ -370,6 +419,8 @@ private:
|
|||
AtRestDetector _hmdAtRestDetector;
|
||||
glm::vec3 _lastPosition;
|
||||
bool _lastIsMoving { false };
|
||||
quint64 _lastStepPulse { 0 };
|
||||
bool _pulseUpdate { false };
|
||||
};
|
||||
|
||||
QScriptValue audioListenModeToScriptValue(QScriptEngine* engine, const AudioListenerMode& audioListenerMode);
|
||||
|
|
|
@ -97,23 +97,9 @@ void SkeletonModel::initJointStates(QVector<JointState> states) {
|
|||
emit skeletonLoaded();
|
||||
}
|
||||
|
||||
static const PalmData* getPalmWithIndex(Hand* hand, int index) {
|
||||
const PalmData* palm = nullptr;
|
||||
for (size_t j = 0; j < hand->getNumPalms(); j++) {
|
||||
if (hand->getPalms()[j].getSixenseID() == index) {
|
||||
palm = &(hand->getPalms()[j]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return palm;
|
||||
}
|
||||
|
||||
const float PALM_PRIORITY = DEFAULT_PRIORITY;
|
||||
// Called within Model::simulate call, below.
|
||||
void SkeletonModel::updateRig(float deltaTime, glm::mat4 parentTransform) {
|
||||
if (_owningAvatar->isMyAvatar()) {
|
||||
_rig->computeMotionAnimationState(deltaTime, _owningAvatar->getPosition(), _owningAvatar->getVelocity(), _owningAvatar->getOrientation());
|
||||
}
|
||||
Head* head = _owningAvatar->getHead();
|
||||
if (_owningAvatar->isMyAvatar()) {
|
||||
MyAvatar* myAvatar = static_cast<MyAvatar*>(_owningAvatar);
|
||||
|
@ -160,28 +146,30 @@ void SkeletonModel::updateRig(float deltaTime, glm::mat4 parentTransform) {
|
|||
_rig->updateFromHeadParameters(headParams, deltaTime);
|
||||
|
||||
Rig::HandParameters handParams;
|
||||
const PalmData* leftPalm = getPalmWithIndex(myAvatar->getHand(), LEFT_HAND_INDEX);
|
||||
if (leftPalm && leftPalm->isActive()) {
|
||||
|
||||
auto leftPalm = myAvatar->getHand()->getCopyOfPalmData(HandData::LeftHand);
|
||||
if (leftPalm.isValid() && leftPalm.isActive()) {
|
||||
handParams.isLeftEnabled = true;
|
||||
handParams.leftPosition = leftPalm->getRawPosition();
|
||||
handParams.leftOrientation = leftPalm->getRawRotation();
|
||||
handParams.leftTrigger = leftPalm->getTrigger();
|
||||
handParams.leftPosition = leftPalm.getRawPosition();
|
||||
handParams.leftOrientation = leftPalm.getRawRotation();
|
||||
handParams.leftTrigger = leftPalm.getTrigger();
|
||||
} else {
|
||||
handParams.isLeftEnabled = false;
|
||||
}
|
||||
|
||||
const PalmData* rightPalm = getPalmWithIndex(myAvatar->getHand(), RIGHT_HAND_INDEX);
|
||||
if (rightPalm && rightPalm->isActive()) {
|
||||
auto rightPalm = myAvatar->getHand()->getCopyOfPalmData(HandData::RightHand);
|
||||
if (rightPalm.isValid() && rightPalm.isActive()) {
|
||||
handParams.isRightEnabled = true;
|
||||
handParams.rightPosition = rightPalm->getRawPosition();
|
||||
handParams.rightOrientation = rightPalm->getRawRotation();
|
||||
handParams.rightTrigger = rightPalm->getTrigger();
|
||||
handParams.rightPosition = rightPalm.getRawPosition();
|
||||
handParams.rightOrientation = rightPalm.getRawRotation();
|
||||
handParams.rightTrigger = rightPalm.getTrigger();
|
||||
} else {
|
||||
handParams.isRightEnabled = false;
|
||||
}
|
||||
|
||||
_rig->updateFromHandParameters(handParams, deltaTime);
|
||||
|
||||
_rig->computeMotionAnimationState(deltaTime, _owningAvatar->getPosition(), _owningAvatar->getVelocity(), _owningAvatar->getOrientation());
|
||||
// evaluate AnimGraph animation and update jointStates.
|
||||
Model::updateRig(deltaTime, parentTransform);
|
||||
|
||||
|
@ -196,7 +184,7 @@ void SkeletonModel::updateRig(float deltaTime, glm::mat4 parentTransform) {
|
|||
|
||||
_rig->updateFromEyeParameters(eyeParams);
|
||||
|
||||
// rebuild the jointState transform for the eyes only
|
||||
// rebuild the jointState transform for the eyes only. Must be after updateRig.
|
||||
_rig->updateJointState(eyeParams.leftEyeJointIndex, parentTransform);
|
||||
_rig->updateJointState(eyeParams.rightEyeJointIndex, parentTransform);
|
||||
|
||||
|
@ -266,15 +254,15 @@ void SkeletonModel::simulate(float deltaTime, bool fullUpdate) {
|
|||
|
||||
const FBXGeometry& geometry = _geometry->getFBXGeometry();
|
||||
|
||||
// find the left and rightmost active palms
|
||||
int leftPalmIndex, rightPalmIndex;
|
||||
Hand* hand = _owningAvatar->getHand();
|
||||
hand->getLeftRightPalmIndices(leftPalmIndex, rightPalmIndex);
|
||||
|
||||
// Don't Relax toward hand positions when in animGraph mode.
|
||||
if (!_rig->getEnableAnimGraph()) {
|
||||
|
||||
Hand* hand = _owningAvatar->getHand();
|
||||
auto leftPalm = hand->getCopyOfPalmData(HandData::LeftHand);
|
||||
auto rightPalm = hand->getCopyOfPalmData(HandData::RightHand);
|
||||
|
||||
const float HAND_RESTORATION_RATE = 0.25f;
|
||||
if (leftPalmIndex == -1 && rightPalmIndex == -1) {
|
||||
if (!leftPalm.isActive() && !rightPalm.isActive()) {
|
||||
// palms are not yet set, use mouse
|
||||
if (_owningAvatar->getHandState() == HAND_STATE_NULL) {
|
||||
restoreRightHandPosition(HAND_RESTORATION_RATE, PALM_PRIORITY);
|
||||
|
@ -284,20 +272,14 @@ void SkeletonModel::simulate(float deltaTime, bool fullUpdate) {
|
|||
applyHandPosition(geometry.rightHandJointIndex, handPosition);
|
||||
}
|
||||
restoreLeftHandPosition(HAND_RESTORATION_RATE, PALM_PRIORITY);
|
||||
|
||||
} else if (leftPalmIndex == rightPalmIndex) {
|
||||
// right hand only
|
||||
applyPalmData(geometry.rightHandJointIndex, hand->getPalms()[leftPalmIndex]);
|
||||
restoreLeftHandPosition(HAND_RESTORATION_RATE, PALM_PRIORITY);
|
||||
|
||||
} else {
|
||||
if (leftPalmIndex != -1) {
|
||||
applyPalmData(geometry.leftHandJointIndex, hand->getPalms()[leftPalmIndex]);
|
||||
if (leftPalm.isActive()) {
|
||||
applyPalmData(geometry.leftHandJointIndex, leftPalm);
|
||||
} else {
|
||||
restoreLeftHandPosition(HAND_RESTORATION_RATE, PALM_PRIORITY);
|
||||
}
|
||||
if (rightPalmIndex != -1) {
|
||||
applyPalmData(geometry.rightHandJointIndex, hand->getPalms()[rightPalmIndex]);
|
||||
if (rightPalm.isActive()) {
|
||||
applyPalmData(geometry.rightHandJointIndex, rightPalm);
|
||||
} else {
|
||||
restoreRightHandPosition(HAND_RESTORATION_RATE, PALM_PRIORITY);
|
||||
}
|
||||
|
@ -348,7 +330,7 @@ void SkeletonModel::applyHandPosition(int jointIndex, const glm::vec3& position)
|
|||
PALM_PRIORITY);
|
||||
}
|
||||
|
||||
void SkeletonModel::applyPalmData(int jointIndex, PalmData& palm) {
|
||||
void SkeletonModel::applyPalmData(int jointIndex, const PalmData& palm) {
|
||||
if (jointIndex == -1 || jointIndex >= _rig->getJointStateCount()) {
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -118,7 +118,7 @@ protected:
|
|||
/// \param position position of joint in model-frame
|
||||
void applyHandPosition(int jointIndex, const glm::vec3& position);
|
||||
|
||||
void applyPalmData(int jointIndex, PalmData& palm);
|
||||
void applyPalmData(int jointIndex, const PalmData& palm);
|
||||
private:
|
||||
|
||||
void renderJointConstraints(gpu::Batch& batch, int jointIndex);
|
||||
|
|
|
@ -9,9 +9,14 @@
|
|||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
|
||||
#include "3DConnexionClient.h"
|
||||
|
||||
#if 0
|
||||
#include <UserActivityLogger.h>
|
||||
#include <PathUtils.h>
|
||||
|
||||
#include "Menu.h"
|
||||
#include "UserActivityLogger.h"
|
||||
|
||||
const float MAX_AXIS = 75.0f; // max forward = 2x speed
|
||||
|
||||
|
@ -25,22 +30,19 @@ ConnexionData& ConnexionData::getInstance() {
|
|||
return sharedInstance;
|
||||
}
|
||||
|
||||
ConnexionData::ConnexionData() {
|
||||
}
|
||||
|
||||
ConnexionData::ConnexionData() : InputDevice("ConnexionClient") {}
|
||||
|
||||
|
||||
void ConnexionData::handleAxisEvent() {
|
||||
_axisStateMap[makeInput(ROTATION_AXIS_Y_POS).getChannel()] = (cc_rotation.y > 0.0f) ? cc_rotation.y / MAX_AXIS : 0.0f;
|
||||
_axisStateMap[makeInput(ROTATION_AXIS_Y_NEG).getChannel()] = (cc_rotation.y < 0.0f) ? -cc_rotation.y / MAX_AXIS : 0.0f;
|
||||
_axisStateMap[makeInput(POSITION_AXIS_X_POS).getChannel()] = (cc_position.x > 0.0f) ? cc_position.x / MAX_AXIS : 0.0f;
|
||||
_axisStateMap[makeInput(POSITION_AXIS_X_NEG).getChannel()] = (cc_position.x < 0.0f) ? -cc_position.x / MAX_AXIS : 0.0f;
|
||||
_axisStateMap[makeInput(POSITION_AXIS_Y_POS).getChannel()] = (cc_position.y > 0.0f) ? cc_position.y / MAX_AXIS : 0.0f;
|
||||
_axisStateMap[makeInput(POSITION_AXIS_Y_NEG).getChannel()] = (cc_position.y < 0.0f) ? -cc_position.y / MAX_AXIS : 0.0f;
|
||||
_axisStateMap[makeInput(POSITION_AXIS_Z_POS).getChannel()] = (cc_position.z > 0.0f) ? cc_position.z / MAX_AXIS : 0.0f;
|
||||
_axisStateMap[makeInput(POSITION_AXIS_Z_NEG).getChannel()] = (cc_position.z < 0.0f) ? -cc_position.z / MAX_AXIS : 0.0f;
|
||||
_axisStateMap[makeInput(ROTATION_AXIS_X_POS).getChannel()] = (cc_rotation.x > 0.0f) ? cc_rotation.x / MAX_AXIS : 0.0f;
|
||||
_axisStateMap[makeInput(ROTATION_AXIS_X_NEG).getChannel()] = (cc_rotation.x < 0.0f) ? -cc_rotation.x / MAX_AXIS : 0.0f;
|
||||
_axisStateMap[makeInput(ROTATION_AXIS_Z_POS).getChannel()] = (cc_rotation.z > 0.0f) ? cc_rotation.z / MAX_AXIS : 0.0f;
|
||||
_axisStateMap[makeInput(ROTATION_AXIS_Z_NEG).getChannel()] = (cc_rotation.z < 0.0f) ? -cc_rotation.z / MAX_AXIS : 0.0f;
|
||||
auto rotation = cc_rotation / MAX_AXIS;
|
||||
_axisStateMap[ROTATE_X] = rotation.x;
|
||||
_axisStateMap[ROTATE_Y] = rotation.y;
|
||||
_axisStateMap[ROTATE_Z] = rotation.z;
|
||||
auto position = cc_rotation / MAX_AXIS;
|
||||
_axisStateMap[TRANSLATE_X] = position.x;
|
||||
_axisStateMap[TRANSLATE_Y] = position.y;
|
||||
_axisStateMap[TRANSLATE_Z] = position.z;
|
||||
}
|
||||
|
||||
void ConnexionData::setButton(int lastButtonState) {
|
||||
|
@ -48,76 +50,65 @@ void ConnexionData::setButton(int lastButtonState) {
|
|||
_buttonPressedMap.insert(lastButtonState);
|
||||
}
|
||||
|
||||
void ConnexionData::registerToUserInputMapper(UserInputMapper& mapper) {
|
||||
// Grab the current free device ID
|
||||
_deviceID = mapper.getFreeDeviceID();
|
||||
|
||||
auto proxy = UserInputMapper::DeviceProxy::Pointer(new UserInputMapper::DeviceProxy("ConnexionClient"));
|
||||
proxy->getButton = [this](const UserInputMapper::Input& input, int timestamp) -> bool { return this->getButton(input.getChannel()); };
|
||||
proxy->getAxis = [this](const UserInputMapper::Input& input, int timestamp) -> float { return this->getAxis(input.getChannel()); };
|
||||
proxy->getAvailabeInputs = [this]() -> QVector<UserInputMapper::InputPair> {
|
||||
QVector<UserInputMapper::InputPair> availableInputs;
|
||||
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(BUTTON_1), "Left button"));
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(BUTTON_2), "Right button"));
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(BUTTON_3), "Both buttons"));
|
||||
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(POSITION_AXIS_Y_NEG), "Move backward"));
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(POSITION_AXIS_Y_POS), "Move forward"));
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(POSITION_AXIS_X_POS), "Move right"));
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(POSITION_AXIS_X_NEG), "Move Left"));
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(POSITION_AXIS_Z_POS), "Move up"));
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(POSITION_AXIS_Z_NEG), "Move down"));
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(ROTATION_AXIS_Y_NEG), "Rotate backward"));
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(ROTATION_AXIS_Y_POS), "Rotate forward"));
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(ROTATION_AXIS_X_POS), "Rotate right"));
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(ROTATION_AXIS_X_NEG), "Rotate left"));
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(ROTATION_AXIS_Z_POS), "Rotate up"));
|
||||
availableInputs.append(UserInputMapper::InputPair(makeInput(ROTATION_AXIS_Z_NEG), "Rotate down"));
|
||||
|
||||
void ConnexionData::buildDeviceProxy(controller::DeviceProxy::Pointer proxy) {
|
||||
proxy->_name = _name = "ConnexionClient";
|
||||
proxy->getButton = [this](const controller::Input& input, int timestamp) -> bool { return this->getButton(input.getChannel()); };
|
||||
proxy->getAxis = [this](const controller::Input& input, int timestamp) -> float { return this->getAxis(input.getChannel()); };
|
||||
proxy->getAvailabeInputs = [this]() -> QVector<controller::Input::NamedPair> {
|
||||
using namespace controller;
|
||||
static QVector<controller::Input::NamedPair> availableInputs {
|
||||
Input::NamedPair(makeInput(BUTTON_1), "LeftButton"),
|
||||
Input::NamedPair(makeInput(BUTTON_2), "RightButton"),
|
||||
Input::NamedPair(makeInput(BUTTON_3), "BothButtons"),
|
||||
Input::NamedPair(makeInput(TRANSLATE_X), "TranslateX"),
|
||||
Input::NamedPair(makeInput(TRANSLATE_Y), "TranslateY"),
|
||||
Input::NamedPair(makeInput(TRANSLATE_Z), "TranslateZ"),
|
||||
Input::NamedPair(makeInput(ROTATE_X), "RotateX"),
|
||||
Input::NamedPair(makeInput(ROTATE_Y), "RotateY"),
|
||||
Input::NamedPair(makeInput(ROTATE_Z), "RotateZ"),
|
||||
};
|
||||
return availableInputs;
|
||||
};
|
||||
proxy->resetDeviceBindings = [this, &mapper]() -> bool {
|
||||
mapper.removeAllInputChannelsForDevice(_deviceID);
|
||||
this->assignDefaultInputMapping(mapper);
|
||||
return true;
|
||||
};
|
||||
mapper.registerDevice(_deviceID, proxy);
|
||||
}
|
||||
|
||||
void ConnexionData::assignDefaultInputMapping(UserInputMapper& mapper) {
|
||||
const float JOYSTICK_MOVE_SPEED = 1.0f;
|
||||
//const float DPAD_MOVE_SPEED = 0.5f;
|
||||
const float JOYSTICK_YAW_SPEED = 0.5f;
|
||||
const float JOYSTICK_PITCH_SPEED = 0.25f;
|
||||
const float BOOM_SPEED = 0.1f;
|
||||
|
||||
// Y axes are flipped (up is negative)
|
||||
// postion: Movement, strafing
|
||||
mapper.addInputChannel(UserInputMapper::LONGITUDINAL_FORWARD, makeInput(POSITION_AXIS_Y_NEG), JOYSTICK_MOVE_SPEED);
|
||||
mapper.addInputChannel(UserInputMapper::LONGITUDINAL_BACKWARD, makeInput(POSITION_AXIS_Y_POS), JOYSTICK_MOVE_SPEED);
|
||||
mapper.addInputChannel(UserInputMapper::LATERAL_RIGHT, makeInput(POSITION_AXIS_X_POS), JOYSTICK_MOVE_SPEED);
|
||||
mapper.addInputChannel(UserInputMapper::LATERAL_LEFT, makeInput(POSITION_AXIS_X_NEG), JOYSTICK_MOVE_SPEED);
|
||||
mapper.addInputChannel(UserInputMapper::VERTICAL_UP, makeInput(POSITION_AXIS_Z_NEG), JOYSTICK_MOVE_SPEED);
|
||||
mapper.addInputChannel(UserInputMapper::VERTICAL_DOWN, makeInput(POSITION_AXIS_Z_POS), JOYSTICK_MOVE_SPEED);
|
||||
|
||||
// Rotation: Camera orientation with button 1
|
||||
mapper.addInputChannel(UserInputMapper::YAW_RIGHT, makeInput(ROTATION_AXIS_Z_POS), JOYSTICK_YAW_SPEED);
|
||||
mapper.addInputChannel(UserInputMapper::YAW_LEFT, makeInput(ROTATION_AXIS_Z_NEG), JOYSTICK_YAW_SPEED);
|
||||
mapper.addInputChannel(UserInputMapper::PITCH_DOWN, makeInput(ROTATION_AXIS_Y_NEG), JOYSTICK_PITCH_SPEED);
|
||||
mapper.addInputChannel(UserInputMapper::PITCH_UP, makeInput(ROTATION_AXIS_Y_POS), JOYSTICK_PITCH_SPEED);
|
||||
|
||||
// Button controls
|
||||
// Zoom
|
||||
mapper.addInputChannel(UserInputMapper::BOOM_IN, makeInput(BUTTON_1), BOOM_SPEED);
|
||||
mapper.addInputChannel(UserInputMapper::BOOM_OUT, makeInput(BUTTON_2), BOOM_SPEED);
|
||||
|
||||
// Zoom
|
||||
// mapper.addInputChannel(UserInputMapper::BOOM_IN, makeInput(ROTATION_AXIS_Z_NEG), BOOM_SPEED);
|
||||
// mapper.addInputChannel(UserInputMapper::BOOM_OUT, makeInput(ROTATION_AXIS_Z_POS), BOOM_SPEED);
|
||||
|
||||
QString ConnexionData::getDefaultMappingConfig() {
|
||||
static const QString MAPPING_JSON = PathUtils::resourcesPath() + "/controllers/vive.json";
|
||||
return MAPPING_JSON;
|
||||
}
|
||||
|
||||
//void ConnexionData::assignDefaultInputMapping(UserInputMapper& mapper) {
|
||||
// const float JOYSTICK_MOVE_SPEED = 1.0f;
|
||||
// //const float DPAD_MOVE_SPEED = 0.5f;
|
||||
// const float JOYSTICK_YAW_SPEED = 0.5f;
|
||||
// const float JOYSTICK_PITCH_SPEED = 0.25f;
|
||||
// const float BOOM_SPEED = 0.1f;
|
||||
//
|
||||
// // Y axes are flipped (up is negative)
|
||||
// // postion: Movement, strafing
|
||||
// mapper.addInputChannel(UserInputMapper::LONGITUDINAL_FORWARD, makeInput(POSITION_AXIS_Y_NEG), JOYSTICK_MOVE_SPEED);
|
||||
// mapper.addInputChannel(UserInputMapper::LONGITUDINAL_BACKWARD, makeInput(POSITION_AXIS_Y_POS), JOYSTICK_MOVE_SPEED);
|
||||
// mapper.addInputChannel(UserInputMapper::LATERAL_RIGHT, makeInput(POSITION_AXIS_X_POS), JOYSTICK_MOVE_SPEED);
|
||||
// mapper.addInputChannel(UserInputMapper::LATERAL_LEFT, makeInput(POSITION_AXIS_X_NEG), JOYSTICK_MOVE_SPEED);
|
||||
// mapper.addInputChannel(UserInputMapper::VERTICAL_UP, makeInput(POSITION_AXIS_Z_NEG), JOYSTICK_MOVE_SPEED);
|
||||
// mapper.addInputChannel(UserInputMapper::VERTICAL_DOWN, makeInput(POSITION_AXIS_Z_POS), JOYSTICK_MOVE_SPEED);
|
||||
//
|
||||
// // Rotation: Camera orientation with button 1
|
||||
// mapper.addInputChannel(UserInputMapper::YAW_RIGHT, makeInput(ROTATION_AXIS_Z_POS), JOYSTICK_YAW_SPEED);
|
||||
// mapper.addInputChannel(UserInputMapper::YAW_LEFT, makeInput(ROTATION_AXIS_Z_NEG), JOYSTICK_YAW_SPEED);
|
||||
// mapper.addInputChannel(UserInputMapper::PITCH_DOWN, makeInput(ROTATION_AXIS_Y_NEG), JOYSTICK_PITCH_SPEED);
|
||||
// mapper.addInputChannel(UserInputMapper::PITCH_UP, makeInput(ROTATION_AXIS_Y_POS), JOYSTICK_PITCH_SPEED);
|
||||
//
|
||||
// // Button controls
|
||||
// // Zoom
|
||||
// mapper.addInputChannel(UserInputMapper::BOOM_IN, makeInput(BUTTON_1), BOOM_SPEED);
|
||||
// mapper.addInputChannel(UserInputMapper::BOOM_OUT, makeInput(BUTTON_2), BOOM_SPEED);
|
||||
//
|
||||
// // Zoom
|
||||
// // mapper.addInputChannel(UserInputMapper::BOOM_IN, makeInput(ROTATION_AXIS_Z_NEG), BOOM_SPEED);
|
||||
// // mapper.addInputChannel(UserInputMapper::BOOM_OUT, makeInput(ROTATION_AXIS_Z_POS), BOOM_SPEED);
|
||||
//
|
||||
//}
|
||||
|
||||
float ConnexionData::getButton(int channel) const {
|
||||
if (!_buttonPressedMap.empty()) {
|
||||
if (_buttonPressedMap.find(channel) != _buttonPressedMap.end()) {
|
||||
|
@ -138,15 +129,15 @@ float ConnexionData::getAxis(int channel) const {
|
|||
}
|
||||
}
|
||||
|
||||
UserInputMapper::Input ConnexionData::makeInput(ConnexionData::ButtonChannel button) {
|
||||
return UserInputMapper::Input(_deviceID, button, UserInputMapper::ChannelType::BUTTON);
|
||||
controller::Input ConnexionData::makeInput(ConnexionData::ButtonChannel button) {
|
||||
return controller::Input(_deviceID, button, controller::ChannelType::BUTTON);
|
||||
}
|
||||
|
||||
UserInputMapper::Input ConnexionData::makeInput(ConnexionData::PositionChannel axis) {
|
||||
return UserInputMapper::Input(_deviceID, axis, UserInputMapper::ChannelType::AXIS);
|
||||
controller::Input ConnexionData::makeInput(ConnexionData::PositionChannel axis) {
|
||||
return controller::Input(_deviceID, axis, controller::ChannelType::AXIS);
|
||||
}
|
||||
|
||||
void ConnexionData::update() {
|
||||
void ConnexionData::update(float deltaTime, bool jointsCaptured) {
|
||||
// the update is done in the ConnexionClient class.
|
||||
// for windows in the nativeEventFilter the inputmapper is connected or registed or removed when an 3Dconnnexion device is attached or detached
|
||||
// for osx the api will call DeviceAddedHandler or DeviceRemoveHandler when a 3Dconnexion device is attached or detached
|
||||
|
@ -187,7 +178,6 @@ void ConnexionClient::destroy() {
|
|||
QAbstractEventDispatcher::instance()->removeNativeEventFilter(this);
|
||||
ConnexionData& connexiondata = ConnexionData::getInstance();
|
||||
int deviceid = connexiondata.getDeviceID();
|
||||
connexiondata.setDeviceID(0);
|
||||
auto userInputMapper = DependencyManager::get<UserInputMapper>();
|
||||
userInputMapper->removeDevice(deviceid);
|
||||
}
|
||||
|
@ -295,13 +285,10 @@ bool ConnexionClient::RawInputEventFilter(void* msg, long* result) {
|
|||
ConnexionData& connexiondata = ConnexionData::getInstance();
|
||||
auto userInputMapper = DependencyManager::get<UserInputMapper>();
|
||||
if (Is3dmouseAttached() && connexiondata.getDeviceID() == 0) {
|
||||
connexiondata.registerToUserInputMapper(*userInputMapper);
|
||||
connexiondata.assignDefaultInputMapping(*userInputMapper);
|
||||
userInputMapper->registerDevice(&connexiondata);
|
||||
UserActivityLogger::getInstance().connectedDevice("controller", "3Dconnexion");
|
||||
} else if (!Is3dmouseAttached() && connexiondata.getDeviceID() != 0) {
|
||||
int deviceid = connexiondata.getDeviceID();
|
||||
connexiondata.setDeviceID(0);
|
||||
userInputMapper->removeDevice(deviceid);
|
||||
userInputMapper->removeDevice(connexiondata.getDeviceID());
|
||||
}
|
||||
|
||||
if (!Is3dmouseAttached()) {
|
||||
|
@ -894,8 +881,7 @@ void ConnexionClient::init() {
|
|||
|
||||
if (Is3dmouseAttached() && connexiondata.getDeviceID() == 0) {
|
||||
auto userInputMapper = DependencyManager::get<UserInputMapper>();
|
||||
connexiondata.registerToUserInputMapper(*userInputMapper);
|
||||
connexiondata.assignDefaultInputMapping(*userInputMapper);
|
||||
userInputMapper->registerDevice(&connexiondata);
|
||||
UserActivityLogger::getInstance().connectedDevice("controller", "3Dconnexion");
|
||||
}
|
||||
//let one axis be dominant
|
||||
|
@ -926,8 +912,7 @@ void DeviceAddedHandler(unsigned int connection) {
|
|||
if (connexiondata.getDeviceID() == 0) {
|
||||
qCWarning(interfaceapp) << "3Dconnexion device added ";
|
||||
auto userInputMapper = DependencyManager::get<UserInputMapper>();
|
||||
connexiondata.registerToUserInputMapper(*userInputMapper);
|
||||
connexiondata.assignDefaultInputMapping(*userInputMapper);
|
||||
userInputMapper->registerDevice(&connexiondata);
|
||||
UserActivityLogger::getInstance().connectedDevice("controller", "3Dconnexion");
|
||||
}
|
||||
}
|
||||
|
@ -984,3 +969,4 @@ void MessageHandler(unsigned int connection, unsigned int messageType, void *mes
|
|||
#endif // __APPLE__
|
||||
|
||||
#endif // HAVE_3DCONNEXIONCLIENT
|
||||
#endif
|
|
@ -11,9 +11,10 @@
|
|||
#ifndef hifi_3DConnexionClient_h
|
||||
#define hifi_3DConnexionClient_h
|
||||
|
||||
#if 0
|
||||
#include <QObject>
|
||||
#include <QLibrary>
|
||||
#include <input-plugins/UserInputMapper.h>
|
||||
#include <controllers/UserInputMapper.h>
|
||||
|
||||
#include "InterfaceLogging.h"
|
||||
|
||||
|
@ -175,26 +176,19 @@ public slots:
|
|||
|
||||
|
||||
// connnects to the userinputmapper
|
||||
class ConnexionData : public QObject {
|
||||
class ConnexionData : public QObject, public controller::InputDevice {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
static ConnexionData& getInstance();
|
||||
ConnexionData();
|
||||
|
||||
enum PositionChannel {
|
||||
POSITION_AXIS_X_POS = 1,
|
||||
POSITION_AXIS_X_NEG = 2,
|
||||
POSITION_AXIS_Y_POS = 3,
|
||||
POSITION_AXIS_Y_NEG = 4,
|
||||
POSITION_AXIS_Z_POS = 5,
|
||||
POSITION_AXIS_Z_NEG = 6,
|
||||
ROTATION_AXIS_X_POS = 7,
|
||||
ROTATION_AXIS_X_NEG = 8,
|
||||
ROTATION_AXIS_Y_POS = 9,
|
||||
ROTATION_AXIS_Y_NEG = 10,
|
||||
ROTATION_AXIS_Z_POS = 11,
|
||||
ROTATION_AXIS_Z_NEG = 12
|
||||
TRANSLATE_X,
|
||||
TRANSLATE_Y,
|
||||
TRANSLATE_Z,
|
||||
ROTATE_X,
|
||||
ROTATE_Y,
|
||||
ROTATE_Z,
|
||||
};
|
||||
|
||||
enum ButtonChannel {
|
||||
|
@ -209,19 +203,12 @@ public:
|
|||
float getButton(int channel) const;
|
||||
float getAxis(int channel) const;
|
||||
|
||||
UserInputMapper::Input makeInput(ConnexionData::PositionChannel axis);
|
||||
UserInputMapper::Input makeInput(ConnexionData::ButtonChannel button);
|
||||
|
||||
void registerToUserInputMapper(UserInputMapper& mapper);
|
||||
void assignDefaultInputMapping(UserInputMapper& mapper);
|
||||
|
||||
void update();
|
||||
void focusOutEvent();
|
||||
|
||||
int getDeviceID() { return _deviceID; }
|
||||
void setDeviceID(int deviceID) { _deviceID = deviceID; }
|
||||
|
||||
QString _name;
|
||||
controller::Input makeInput(ConnexionData::PositionChannel axis);
|
||||
controller::Input makeInput(ConnexionData::ButtonChannel button);
|
||||
virtual void buildDeviceProxy(controller::DeviceProxy::Pointer proxy) override;
|
||||
virtual QString getDefaultMappingConfig() override;
|
||||
virtual void update(float deltaTime, bool jointsCaptured) override;
|
||||
virtual void focusOutEvent() override;
|
||||
|
||||
glm::vec3 cc_position;
|
||||
glm::vec3 cc_rotation;
|
||||
|
@ -229,12 +216,8 @@ public:
|
|||
|
||||
void setButton(int lastButtonState);
|
||||
void handleAxisEvent();
|
||||
|
||||
protected:
|
||||
int _deviceID = 0;
|
||||
|
||||
ButtonPressedMap _buttonPressedMap;
|
||||
AxisStateMap _axisStateMap;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
#endif // defined(hifi_3DConnexionClient_h)
|
||||
|
|
|
@ -9,120 +9,20 @@
|
|||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include "ControllerScriptingInterface.h"
|
||||
|
||||
#include <avatar/AvatarManager.h>
|
||||
#include <avatar/MyAvatar.h>
|
||||
#include <HandData.h>
|
||||
#include <HFBackEvent.h>
|
||||
#include <plugins/PluginManager.h>
|
||||
|
||||
#include "Application.h"
|
||||
#include "devices/MotionTracker.h"
|
||||
#include "ControllerScriptingInterface.h"
|
||||
|
||||
// TODO: this needs to be removed, as well as any related controller-specific information
|
||||
#include <input-plugins/SixenseManager.h>
|
||||
|
||||
|
||||
ControllerScriptingInterface::ControllerScriptingInterface() :
|
||||
_mouseCaptured(false),
|
||||
_touchCaptured(false),
|
||||
_wheelCaptured(false),
|
||||
_actionsCaptured(false)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
static int actionMetaTypeId = qRegisterMetaType<UserInputMapper::Action>();
|
||||
static int inputChannelMetaTypeId = qRegisterMetaType<UserInputMapper::InputChannel>();
|
||||
static int inputMetaTypeId = qRegisterMetaType<UserInputMapper::Input>();
|
||||
static int inputPairMetaTypeId = qRegisterMetaType<UserInputMapper::InputPair>();
|
||||
|
||||
QScriptValue inputToScriptValue(QScriptEngine* engine, const UserInputMapper::Input& input);
|
||||
void inputFromScriptValue(const QScriptValue& object, UserInputMapper::Input& input);
|
||||
QScriptValue inputChannelToScriptValue(QScriptEngine* engine, const UserInputMapper::InputChannel& inputChannel);
|
||||
void inputChannelFromScriptValue(const QScriptValue& object, UserInputMapper::InputChannel& inputChannel);
|
||||
QScriptValue actionToScriptValue(QScriptEngine* engine, const UserInputMapper::Action& action);
|
||||
void actionFromScriptValue(const QScriptValue& object, UserInputMapper::Action& action);
|
||||
QScriptValue inputPairToScriptValue(QScriptEngine* engine, const UserInputMapper::InputPair& inputPair);
|
||||
void inputPairFromScriptValue(const QScriptValue& object, UserInputMapper::InputPair& inputPair);
|
||||
|
||||
QScriptValue inputToScriptValue(QScriptEngine* engine, const UserInputMapper::Input& input) {
|
||||
QScriptValue obj = engine->newObject();
|
||||
obj.setProperty("device", input.getDevice());
|
||||
obj.setProperty("channel", input.getChannel());
|
||||
obj.setProperty("type", (unsigned short) input.getType());
|
||||
obj.setProperty("id", input.getID());
|
||||
return obj;
|
||||
}
|
||||
|
||||
void inputFromScriptValue(const QScriptValue& object, UserInputMapper::Input& input) {
|
||||
input.setDevice(object.property("device").toUInt16());
|
||||
input.setChannel(object.property("channel").toUInt16());
|
||||
input.setType(object.property("type").toUInt16());
|
||||
input.setID(object.property("id").toInt32());
|
||||
}
|
||||
|
||||
QScriptValue inputChannelToScriptValue(QScriptEngine* engine, const UserInputMapper::InputChannel& inputChannel) {
|
||||
QScriptValue obj = engine->newObject();
|
||||
obj.setProperty("input", inputToScriptValue(engine, inputChannel.getInput()));
|
||||
obj.setProperty("modifier", inputToScriptValue(engine, inputChannel.getModifier()));
|
||||
obj.setProperty("action", inputChannel.getAction());
|
||||
obj.setProperty("scale", inputChannel.getScale());
|
||||
return obj;
|
||||
}
|
||||
|
||||
void inputChannelFromScriptValue(const QScriptValue& object, UserInputMapper::InputChannel& inputChannel) {
|
||||
UserInputMapper::Input input;
|
||||
UserInputMapper::Input modifier;
|
||||
inputFromScriptValue(object.property("input"), input);
|
||||
inputChannel.setInput(input);
|
||||
inputFromScriptValue(object.property("modifier"), modifier);
|
||||
inputChannel.setModifier(modifier);
|
||||
inputChannel.setAction(UserInputMapper::Action(object.property("action").toVariant().toInt()));
|
||||
inputChannel.setScale(object.property("scale").toVariant().toFloat());
|
||||
}
|
||||
|
||||
QScriptValue actionToScriptValue(QScriptEngine* engine, const UserInputMapper::Action& action) {
|
||||
QScriptValue obj = engine->newObject();
|
||||
auto userInputMapper = DependencyManager::get<UserInputMapper>();
|
||||
QVector<UserInputMapper::InputChannel> inputChannels = userInputMapper->getInputChannelsForAction(action);
|
||||
QScriptValue _inputChannels = engine->newArray(inputChannels.size());
|
||||
for (int i = 0; i < inputChannels.size(); i++) {
|
||||
_inputChannels.setProperty(i, inputChannelToScriptValue(engine, inputChannels[i]));
|
||||
}
|
||||
obj.setProperty("action", (int) action);
|
||||
obj.setProperty("actionName", userInputMapper->getActionName(action));
|
||||
obj.setProperty("inputChannels", _inputChannels);
|
||||
return obj;
|
||||
}
|
||||
|
||||
void actionFromScriptValue(const QScriptValue& object, UserInputMapper::Action& action) {
|
||||
action = UserInputMapper::Action(object.property("action").toVariant().toInt());
|
||||
}
|
||||
|
||||
QScriptValue inputPairToScriptValue(QScriptEngine* engine, const UserInputMapper::InputPair& inputPair) {
|
||||
QScriptValue obj = engine->newObject();
|
||||
obj.setProperty("input", inputToScriptValue(engine, inputPair.first));
|
||||
obj.setProperty("inputName", inputPair.second);
|
||||
return obj;
|
||||
}
|
||||
|
||||
void inputPairFromScriptValue(const QScriptValue& object, UserInputMapper::InputPair& inputPair) {
|
||||
inputFromScriptValue(object.property("input"), inputPair.first);
|
||||
inputPair.second = QString(object.property("inputName").toVariant().toString());
|
||||
}
|
||||
|
||||
void ControllerScriptingInterface::registerControllerTypes(ScriptEngine* engine) {
|
||||
qScriptRegisterSequenceMetaType<QVector<UserInputMapper::Action> >(engine);
|
||||
qScriptRegisterSequenceMetaType<QVector<UserInputMapper::InputChannel> >(engine);
|
||||
qScriptRegisterSequenceMetaType<QVector<UserInputMapper::InputPair> >(engine);
|
||||
qScriptRegisterMetaType(engine, actionToScriptValue, actionFromScriptValue);
|
||||
qScriptRegisterMetaType(engine, inputChannelToScriptValue, inputChannelFromScriptValue);
|
||||
qScriptRegisterMetaType(engine, inputToScriptValue, inputFromScriptValue);
|
||||
qScriptRegisterMetaType(engine, inputPairToScriptValue, inputPairFromScriptValue);
|
||||
|
||||
wireUpControllers(engine);
|
||||
}
|
||||
|
||||
void ControllerScriptingInterface::handleMetaEvent(HFMetaEvent* event) {
|
||||
if (event->type() == HFActionEvent::startType()) {
|
||||
emit actionStartEvent(static_cast<HFActionEvent&>(*event));
|
||||
|
@ -135,205 +35,6 @@ void ControllerScriptingInterface::handleMetaEvent(HFMetaEvent* event) {
|
|||
}
|
||||
}
|
||||
|
||||
const PalmData* ControllerScriptingInterface::getPrimaryPalm() const {
|
||||
int leftPalmIndex, rightPalmIndex;
|
||||
|
||||
const HandData* handData = DependencyManager::get<AvatarManager>()->getMyAvatar()->getHandData();
|
||||
handData->getLeftRightPalmIndices(leftPalmIndex, rightPalmIndex);
|
||||
|
||||
if (rightPalmIndex != -1) {
|
||||
return &handData->getPalms()[rightPalmIndex];
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int ControllerScriptingInterface::getNumberOfActivePalms() const {
|
||||
const HandData* handData = DependencyManager::get<AvatarManager>()->getMyAvatar()->getHandData();
|
||||
int numberOfPalms = handData->getNumPalms();
|
||||
int numberOfActivePalms = 0;
|
||||
for (int i = 0; i < numberOfPalms; i++) {
|
||||
if (getPalm(i)->isActive()) {
|
||||
numberOfActivePalms++;
|
||||
}
|
||||
}
|
||||
return numberOfActivePalms;
|
||||
}
|
||||
|
||||
const PalmData* ControllerScriptingInterface::getPalm(int palmIndex) const {
|
||||
const HandData* handData = DependencyManager::get<AvatarManager>()->getMyAvatar()->getHandData();
|
||||
return &handData->getPalms()[palmIndex];
|
||||
}
|
||||
|
||||
const PalmData* ControllerScriptingInterface::getActivePalm(int palmIndex) const {
|
||||
const HandData* handData = DependencyManager::get<AvatarManager>()->getMyAvatar()->getHandData();
|
||||
int numberOfPalms = handData->getNumPalms();
|
||||
int numberOfActivePalms = 0;
|
||||
for (int i = 0; i < numberOfPalms; i++) {
|
||||
if (getPalm(i)->isActive()) {
|
||||
if (numberOfActivePalms == palmIndex) {
|
||||
return &handData->getPalms()[i];
|
||||
}
|
||||
numberOfActivePalms++;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool ControllerScriptingInterface::isPrimaryButtonPressed() const {
|
||||
const PalmData* primaryPalm = getPrimaryPalm();
|
||||
if (primaryPalm) {
|
||||
if (primaryPalm->getControllerButtons() & BUTTON_FWD) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
glm::vec2 ControllerScriptingInterface::getPrimaryJoystickPosition() const {
|
||||
const PalmData* primaryPalm = getPrimaryPalm();
|
||||
if (primaryPalm) {
|
||||
return glm::vec2(primaryPalm->getJoystickX(), primaryPalm->getJoystickY());
|
||||
}
|
||||
|
||||
return glm::vec2(0);
|
||||
}
|
||||
|
||||
int ControllerScriptingInterface::getNumberOfButtons() const {
|
||||
return getNumberOfActivePalms() * NUMBER_OF_BUTTONS_PER_PALM;
|
||||
}
|
||||
|
||||
bool ControllerScriptingInterface::isButtonPressed(int buttonIndex) const {
|
||||
int palmIndex = buttonIndex / NUMBER_OF_BUTTONS_PER_PALM;
|
||||
int buttonOnPalm = buttonIndex % NUMBER_OF_BUTTONS_PER_PALM;
|
||||
const PalmData* palmData = getActivePalm(palmIndex);
|
||||
if (palmData) {
|
||||
switch (buttonOnPalm) {
|
||||
case 0:
|
||||
return palmData->getControllerButtons() & BUTTON_0;
|
||||
case 1:
|
||||
return palmData->getControllerButtons() & BUTTON_1;
|
||||
case 2:
|
||||
return palmData->getControllerButtons() & BUTTON_2;
|
||||
case 3:
|
||||
return palmData->getControllerButtons() & BUTTON_3;
|
||||
case 4:
|
||||
return palmData->getControllerButtons() & BUTTON_4;
|
||||
case 5:
|
||||
return palmData->getControllerButtons() & BUTTON_FWD;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
int ControllerScriptingInterface::getNumberOfTriggers() const {
|
||||
return getNumberOfActivePalms() * NUMBER_OF_TRIGGERS_PER_PALM;
|
||||
}
|
||||
|
||||
float ControllerScriptingInterface::getTriggerValue(int triggerIndex) const {
|
||||
// we know there's one trigger per palm, so the triggerIndex is the palm Index
|
||||
int palmIndex = triggerIndex;
|
||||
const PalmData* palmData = getActivePalm(palmIndex);
|
||||
if (palmData) {
|
||||
return palmData->getTrigger();
|
||||
}
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
int ControllerScriptingInterface::getNumberOfJoysticks() const {
|
||||
return getNumberOfActivePalms() * NUMBER_OF_JOYSTICKS_PER_PALM;
|
||||
}
|
||||
|
||||
glm::vec2 ControllerScriptingInterface::getJoystickPosition(int joystickIndex) const {
|
||||
// we know there's one joystick per palm, so the joystickIndex is the palm Index
|
||||
int palmIndex = joystickIndex;
|
||||
const PalmData* palmData = getActivePalm(palmIndex);
|
||||
if (palmData) {
|
||||
return glm::vec2(palmData->getJoystickX(), palmData->getJoystickY());
|
||||
}
|
||||
return glm::vec2(0);
|
||||
}
|
||||
|
||||
int ControllerScriptingInterface::getNumberOfSpatialControls() const {
|
||||
return getNumberOfActivePalms() * NUMBER_OF_SPATIALCONTROLS_PER_PALM;
|
||||
}
|
||||
|
||||
glm::vec3 ControllerScriptingInterface::getSpatialControlPosition(int controlIndex) const {
|
||||
int palmIndex = controlIndex / NUMBER_OF_SPATIALCONTROLS_PER_PALM;
|
||||
int controlOfPalm = controlIndex % NUMBER_OF_SPATIALCONTROLS_PER_PALM;
|
||||
const PalmData* palmData = getActivePalm(palmIndex);
|
||||
if (palmData) {
|
||||
switch (controlOfPalm) {
|
||||
case PALM_SPATIALCONTROL:
|
||||
return palmData->getPosition();
|
||||
case TIP_SPATIALCONTROL:
|
||||
return palmData->getTipPosition();
|
||||
}
|
||||
}
|
||||
return glm::vec3(0); // bad index
|
||||
}
|
||||
|
||||
glm::vec3 ControllerScriptingInterface::getSpatialControlVelocity(int controlIndex) const {
|
||||
int palmIndex = controlIndex / NUMBER_OF_SPATIALCONTROLS_PER_PALM;
|
||||
int controlOfPalm = controlIndex % NUMBER_OF_SPATIALCONTROLS_PER_PALM;
|
||||
const PalmData* palmData = getActivePalm(palmIndex);
|
||||
if (palmData) {
|
||||
switch (controlOfPalm) {
|
||||
case PALM_SPATIALCONTROL:
|
||||
return palmData->getVelocity();
|
||||
case TIP_SPATIALCONTROL:
|
||||
return palmData->getTipVelocity();
|
||||
}
|
||||
}
|
||||
return glm::vec3(0); // bad index
|
||||
}
|
||||
|
||||
glm::quat ControllerScriptingInterface::getSpatialControlRawRotation(int controlIndex) const {
|
||||
int palmIndex = controlIndex / NUMBER_OF_SPATIALCONTROLS_PER_PALM;
|
||||
int controlOfPalm = controlIndex % NUMBER_OF_SPATIALCONTROLS_PER_PALM;
|
||||
const PalmData* palmData = getActivePalm(palmIndex);
|
||||
if (palmData) {
|
||||
switch (controlOfPalm) {
|
||||
case PALM_SPATIALCONTROL:
|
||||
return palmData->getRawRotation();
|
||||
case TIP_SPATIALCONTROL:
|
||||
return palmData->getRawRotation(); // currently the tip doesn't have a unique rotation, use the palm rotation
|
||||
}
|
||||
}
|
||||
return glm::quat(); // bad index
|
||||
}
|
||||
|
||||
glm::vec3 ControllerScriptingInterface::getSpatialControlRawAngularVelocity(int controlIndex) const {
|
||||
int palmIndex = controlIndex / NUMBER_OF_SPATIALCONTROLS_PER_PALM;
|
||||
int controlOfPalm = controlIndex % NUMBER_OF_SPATIALCONTROLS_PER_PALM;
|
||||
const PalmData* palmData = getActivePalm(palmIndex);
|
||||
if (palmData) {
|
||||
switch (controlOfPalm) {
|
||||
case PALM_SPATIALCONTROL:
|
||||
return palmData->getRawAngularVelocity();
|
||||
case TIP_SPATIALCONTROL:
|
||||
return palmData->getRawAngularVelocity(); // Tip = palm angular velocity
|
||||
}
|
||||
}
|
||||
return glm::vec3(0); // bad index
|
||||
}
|
||||
|
||||
glm::vec3 ControllerScriptingInterface::getSpatialControlNormal(int controlIndex) const {
|
||||
int palmIndex = controlIndex / NUMBER_OF_SPATIALCONTROLS_PER_PALM;
|
||||
int controlOfPalm = controlIndex % NUMBER_OF_SPATIALCONTROLS_PER_PALM;
|
||||
const PalmData* palmData = getActivePalm(palmIndex);
|
||||
if (palmData) {
|
||||
switch (controlOfPalm) {
|
||||
case PALM_SPATIALCONTROL:
|
||||
return palmData->getNormal();
|
||||
case TIP_SPATIALCONTROL:
|
||||
return palmData->getFingerDirection();
|
||||
}
|
||||
}
|
||||
return glm::vec3(0); // bad index
|
||||
}
|
||||
|
||||
bool ControllerScriptingInterface::isKeyCaptured(QKeyEvent* event) const {
|
||||
return isKeyCaptured(KeyEvent(*event));
|
||||
}
|
||||
|
@ -383,157 +84,45 @@ glm::vec2 ControllerScriptingInterface::getViewportDimensions() const {
|
|||
return qApp->getUiSize();
|
||||
}
|
||||
|
||||
QString ControllerScriptingInterface::sanatizeName(const QString& name) {
|
||||
QString cleanName { name };
|
||||
cleanName.remove(QRegularExpression{"[\\(\\)\\.\\s]"});
|
||||
return cleanName;
|
||||
}
|
||||
|
||||
void ControllerScriptingInterface::wireUpControllers(ScriptEngine* engine) {
|
||||
|
||||
// Controller.Standard.*
|
||||
auto standardDevice = DependencyManager::get<UserInputMapper>()->getStandardDevice();
|
||||
if (standardDevice) {
|
||||
auto deviceName = sanatizeName(standardDevice->getName());
|
||||
auto deviceInputs = standardDevice->getAvailabeInputs();
|
||||
for (const auto& inputMapping : deviceInputs) {
|
||||
auto input = inputMapping.first;
|
||||
auto inputName = sanatizeName(inputMapping.second);
|
||||
QString deviceInputName{ "Controller." + deviceName + "." + inputName };
|
||||
engine->registerValue(deviceInputName, input.getID());
|
||||
}
|
||||
}
|
||||
|
||||
// Controller.Hardware.*
|
||||
auto devices = DependencyManager::get<UserInputMapper>()->getDevices();
|
||||
for(const auto& deviceMapping : devices) {
|
||||
auto device = deviceMapping.second.get();
|
||||
auto deviceName = sanatizeName(device->getName());
|
||||
auto deviceInputs = device->getAvailabeInputs();
|
||||
for (const auto& inputMapping : deviceInputs) {
|
||||
auto input = inputMapping.first;
|
||||
auto inputName = sanatizeName(inputMapping.second);
|
||||
QString deviceInputName { "Controller.Hardware." + deviceName + "." + inputName };
|
||||
engine->registerValue(deviceInputName, input.getID());
|
||||
}
|
||||
}
|
||||
|
||||
// Controller.Actions.*
|
||||
auto actionNames = DependencyManager::get<UserInputMapper>()->getActionNames();
|
||||
int actionNumber = 0;
|
||||
for (const auto& actionName : actionNames) {
|
||||
QString safeActionName { "Controller.Actions." + sanatizeName(actionName) };
|
||||
engine->registerValue(safeActionName, actionNumber);
|
||||
actionNumber++;
|
||||
}
|
||||
}
|
||||
|
||||
AbstractInputController* ControllerScriptingInterface::createInputController(const QString& deviceName, const QString& tracker) {
|
||||
controller::InputController::Pointer ControllerScriptingInterface::createInputController(const QString& deviceName, const QString& tracker) {
|
||||
// This is where we retreive the Device Tracker category and then the sub tracker within it
|
||||
//TODO C++11 auto icIt = _inputControllers.find(0);
|
||||
InputControllerMap::iterator icIt = _inputControllers.find(0);
|
||||
|
||||
auto icIt = _inputControllers.find(0);
|
||||
if (icIt != _inputControllers.end()) {
|
||||
return (*icIt).second;
|
||||
} else {
|
||||
}
|
||||
|
||||
// Look for device
|
||||
DeviceTracker::ID deviceID = DeviceTracker::getDeviceID(deviceName.toStdString());
|
||||
if (deviceID < 0) {
|
||||
deviceID = 0;
|
||||
}
|
||||
// TODO in this current implementation, we just pick the device assuming there is one (normally the Leapmotion)
|
||||
// in the near future we need to change that to a real mapping between the devices and the deviceName
|
||||
// ALso we need to expand the spec so we can fall back on the "default" controller per categories
|
||||
|
||||
if (deviceID >= 0) {
|
||||
// TODO here again the assumption it's the LeapMotion and so it's a MOtionTracker, this would need to be changed to support different types of devices
|
||||
MotionTracker* motionTracker = dynamic_cast< MotionTracker* > (DeviceTracker::getDevice(deviceID));
|
||||
if (motionTracker) {
|
||||
MotionTracker::Index trackerID = motionTracker->findJointIndex(tracker.toStdString());
|
||||
if (trackerID >= 0) {
|
||||
AbstractInputController* inputController = new InputController(deviceID, trackerID, this);
|
||||
// Look for device
|
||||
DeviceTracker::ID deviceID = DeviceTracker::getDeviceID(deviceName.toStdString());
|
||||
if (deviceID < 0) {
|
||||
deviceID = 0;
|
||||
}
|
||||
// TODO in this current implementation, we just pick the device assuming there is one (normally the Leapmotion)
|
||||
// in the near future we need to change that to a real mapping between the devices and the deviceName
|
||||
// ALso we need to expand the spec so we can fall back on the "default" controller per categories
|
||||
|
||||
_inputControllers.insert(InputControllerMap::value_type(inputController->getKey(), inputController));
|
||||
|
||||
return inputController;
|
||||
}
|
||||
if (deviceID >= 0) {
|
||||
// TODO here again the assumption it's the LeapMotion and so it's a MOtionTracker, this would need to be changed to support different types of devices
|
||||
MotionTracker* motionTracker = dynamic_cast< MotionTracker* > (DeviceTracker::getDevice(deviceID));
|
||||
if (motionTracker) {
|
||||
MotionTracker::Index trackerID = motionTracker->findJointIndex(tracker.toStdString());
|
||||
if (trackerID >= 0) {
|
||||
controller::InputController::Pointer inputController = std::make_shared<InputController>(deviceID, trackerID, this);
|
||||
controller::InputController::Key key = inputController->getKey();
|
||||
_inputControllers.insert(InputControllerMap::value_type(key, inputController));
|
||||
return inputController;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
return controller::InputController::Pointer();
|
||||
}
|
||||
|
||||
void ControllerScriptingInterface::releaseInputController(AbstractInputController* input) {
|
||||
void ControllerScriptingInterface::releaseInputController(controller::InputController::Pointer input) {
|
||||
_inputControllers.erase(input->getKey());
|
||||
}
|
||||
|
||||
void ControllerScriptingInterface::updateInputControllers() {
|
||||
//TODO C++11 for (auto it = _inputControllers.begin(); it != _inputControllers.end(); it++) {
|
||||
for (InputControllerMap::iterator it = _inputControllers.begin(); it != _inputControllers.end(); it++) {
|
||||
(*it).second->update();
|
||||
}
|
||||
}
|
||||
|
||||
QVector<UserInputMapper::Action> ControllerScriptingInterface::getAllActions() {
|
||||
return DependencyManager::get<UserInputMapper>()->getAllActions();
|
||||
}
|
||||
|
||||
QVector<UserInputMapper::InputChannel> ControllerScriptingInterface::getInputChannelsForAction(UserInputMapper::Action action) {
|
||||
return DependencyManager::get<UserInputMapper>()->getInputChannelsForAction(action);
|
||||
}
|
||||
|
||||
QString ControllerScriptingInterface::getDeviceName(unsigned int device) {
|
||||
return DependencyManager::get<UserInputMapper>()->getDeviceName((unsigned short)device);
|
||||
}
|
||||
|
||||
QVector<UserInputMapper::InputChannel> ControllerScriptingInterface::getAllInputsForDevice(unsigned int device) {
|
||||
return DependencyManager::get<UserInputMapper>()->getAllInputsForDevice(device);
|
||||
}
|
||||
|
||||
bool ControllerScriptingInterface::addInputChannel(UserInputMapper::InputChannel inputChannel) {
|
||||
return DependencyManager::get<UserInputMapper>()->addInputChannel(inputChannel._action, inputChannel._input, inputChannel._modifier, inputChannel._scale);
|
||||
}
|
||||
|
||||
bool ControllerScriptingInterface::removeInputChannel(UserInputMapper::InputChannel inputChannel) {
|
||||
return DependencyManager::get<UserInputMapper>()->removeInputChannel(inputChannel);
|
||||
}
|
||||
|
||||
QVector<UserInputMapper::InputPair> ControllerScriptingInterface::getAvailableInputs(unsigned int device) {
|
||||
return DependencyManager::get<UserInputMapper>()->getAvailableInputs((unsigned short)device);
|
||||
}
|
||||
|
||||
void ControllerScriptingInterface::resetAllDeviceBindings() {
|
||||
DependencyManager::get<UserInputMapper>()->resetAllDeviceBindings();
|
||||
}
|
||||
|
||||
void ControllerScriptingInterface::resetDevice(unsigned int device) {
|
||||
DependencyManager::get<UserInputMapper>()->resetDevice(device);
|
||||
}
|
||||
|
||||
int ControllerScriptingInterface::findDevice(QString name) {
|
||||
return DependencyManager::get<UserInputMapper>()->findDevice(name);
|
||||
}
|
||||
|
||||
QVector<QString> ControllerScriptingInterface::getDeviceNames() {
|
||||
return DependencyManager::get<UserInputMapper>()->getDeviceNames();
|
||||
}
|
||||
|
||||
float ControllerScriptingInterface::getActionValue(int action) {
|
||||
return DependencyManager::get<UserInputMapper>()->getActionState(UserInputMapper::Action(action));
|
||||
}
|
||||
|
||||
int ControllerScriptingInterface::findAction(QString actionName) {
|
||||
return DependencyManager::get<UserInputMapper>()->findAction(actionName);
|
||||
}
|
||||
|
||||
QVector<QString> ControllerScriptingInterface::getActionNames() const {
|
||||
return DependencyManager::get<UserInputMapper>()->getActionNames();
|
||||
}
|
||||
|
||||
InputController::InputController(int deviceTrackerId, int subTrackerId, QObject* parent) :
|
||||
AbstractInputController(),
|
||||
_deviceTrackerId(deviceTrackerId),
|
||||
_subTrackerId(subTrackerId),
|
||||
_isActive(false)
|
||||
|
@ -556,7 +145,7 @@ void InputController::update() {
|
|||
joint->getLocFrame().getRotation(_eventCache.locRotation);
|
||||
|
||||
_isActive = true;
|
||||
emit spatialEvent(_eventCache);
|
||||
//emit spatialEvent(_eventCache);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -568,3 +157,19 @@ const unsigned int INPUTCONTROLLER_KEY_DEVICE_MASK = 16;
|
|||
InputController::Key InputController::getKey() const {
|
||||
return (((_deviceTrackerId & INPUTCONTROLLER_KEY_DEVICE_MASK) << INPUTCONTROLLER_KEY_DEVICE_OFFSET) | _subTrackerId);
|
||||
}
|
||||
|
||||
|
||||
void ControllerScriptingInterface::emitKeyPressEvent(QKeyEvent* event) { emit keyPressEvent(KeyEvent(*event)); }
|
||||
void ControllerScriptingInterface::emitKeyReleaseEvent(QKeyEvent* event) { emit keyReleaseEvent(KeyEvent(*event)); }
|
||||
|
||||
void ControllerScriptingInterface::emitMouseMoveEvent(QMouseEvent* event, unsigned int deviceID) { emit mouseMoveEvent(MouseEvent(*event, deviceID)); }
|
||||
void ControllerScriptingInterface::emitMousePressEvent(QMouseEvent* event, unsigned int deviceID) { emit mousePressEvent(MouseEvent(*event, deviceID)); }
|
||||
void ControllerScriptingInterface::emitMouseDoublePressEvent(QMouseEvent* event, unsigned int deviceID) { emit mouseDoublePressEvent(MouseEvent(*event, deviceID)); }
|
||||
void ControllerScriptingInterface::emitMouseReleaseEvent(QMouseEvent* event, unsigned int deviceID) { emit mouseReleaseEvent(MouseEvent(*event, deviceID)); }
|
||||
|
||||
void ControllerScriptingInterface::emitTouchBeginEvent(const TouchEvent& event) { emit touchBeginEvent(event); }
|
||||
void ControllerScriptingInterface::emitTouchEndEvent(const TouchEvent& event) { emit touchEndEvent(event); }
|
||||
void ControllerScriptingInterface::emitTouchUpdateEvent(const TouchEvent& event) { emit touchUpdateEvent(event); }
|
||||
|
||||
void ControllerScriptingInterface::emitWheelEvent(QWheelEvent* event) { emit wheelEvent(*event); }
|
||||
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue