3
0
Fork 0
mirror of https://github.com/lubosz/overte.git synced 2025-04-27 20:35:29 +02:00

Merge branch 'master' of https://github.com/highfidelity/hifi into controllers

This commit is contained in:
samcake 2015-11-02 09:48:32 -08:00
commit 543f322ffe
118 changed files with 1521 additions and 664 deletions
BUILD.mdBUILD_WIN.mdCMakeLists.txt
assignment-client/src
cmake
examples
interface
libraries
animation/src
controllers/src/controllers
display-plugins
entities
input-plugins/src/input-plugins
physics/src
plugins/src/plugins
procedural
shared
plugins

View file

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

View file

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

View file

@ -203,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 ()

View file

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

View file

@ -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>();

View file

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

View file

@ -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,12 +61,8 @@ 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)
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")
elseif (WIN32)
ExternalProject_Get_Property(${EXTERNAL_NAME} SOURCE_DIR)
set(${EXTERNAL_NAME_UPPER}_INCLUDE_DIR ${SOURCE_DIR}/include CACHE PATH "Location of SDL2 include directory")

View file

@ -6,8 +6,8 @@ string(TOUPPER ${EXTERNAL_NAME} EXTERNAL_NAME_UPPER)
ExternalProject_Add(
${EXTERNAL_NAME}
URL http://hifi-public.s3.amazonaws.com/dependencies/SixenseSDK_071615.zip
URL_MD5 752a3901f334124e9cffc2ba4136ef7d
URL https://hifi-public.s3.amazonaws.com/dependencies/SixenseSDK_102215.zip
URL_MD5 93c3a6795cce777a0f472b09532935f1
CONFIGURE_COMMAND ""
BUILD_COMMAND ""
INSTALL_COMMAND ""
@ -30,17 +30,40 @@ if (WIN32)
set(ARCH_SUFFIX "")
endif()
set(${EXTERNAL_NAME_UPPER}_LIBRARIES "${SOURCE_DIR}/lib/${ARCH_DIR}/VS2013/release_dll/sixense${ARCH_SUFFIX}.lib" CACHE TYPE INTERNAL)
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)
set(${EXTERNAL_NAME_UPPER}_LIBRARIES ${SOURCE_DIR}/lib/osx_x64/release_dll/libsixense_x64.dylib CACHE TYPE INTERNAL)
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)
set(${EXTERNAL_NAME_UPPER}_LIBRARY_RELEASE ${SOURCE_DIR}/lib/linux_x64/release/libsixense_x64.so CACHE TYPE INTERNAL)
endif()

View file

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

View 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()

View 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()

View file

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

View file

@ -18,6 +18,10 @@
# See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
#
include(SelectLibraryConfigurations)
select_library_configurations(SIXENSE)
set(SIXENSE_REQUIREMENTS SIXENSE_INCLUDE_DIRS SIXENSE_LIBRARIES)
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(Sixense DEFAULT_MSG SIXENSE_INCLUDE_DIRS SIXENSE_LIBRARIES)
mark_as_advanced(SIXENSE_LIBRARIES SIXENSE_INCLUDE_DIRS SIXENSE_SEARCH_DIRS)

View file

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

View file

@ -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;
@ -196,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;
}
@ -254,7 +281,6 @@ function MyController(hand, triggerAction) {
// smooth out trigger value
this.triggerValue = (this.triggerValue * TRIGGER_SMOOTH_RATIO) +
(triggerValue * (1.0 - TRIGGER_SMOOTH_RATIO));
};
this.triggerSmoothedSqueezed = function() {
@ -353,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
@ -397,22 +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 = (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
@ -557,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();
@ -587,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;
@ -639,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);
}
@ -808,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;
@ -836,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;
@ -853,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;
}
@ -864,14 +904,14 @@ function MyController(hand, triggerAction) {
};
}
var rightController = new MyController(RIGHT_HAND, Controller.Standard.RT);
var leftController = new MyController(LEFT_HAND, Controller.Standard.LT);
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]).to(rightController.eitherTrigger);
mapping.from([Controller.Standard.LB, Controller.Standard.LT]).to(leftController.eitherTrigger);
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);

View 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);
}

161
examples/libraries/line.js Normal file
View 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;
};

View file

@ -4,8 +4,8 @@
{ "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.A", "when": "Keyboard.RightMouseButton", "to": "Actions.LATERAL_LEFT" },
{ "from": "Keyboard.D", "when": "Keyboard.RightMouseButton", "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" },
@ -13,7 +13,7 @@
{ "from": { "makeAxis" : ["Keyboard.MouseMoveLeft", "Keyboard.MouseMoveRight"] },
"when": [ "Application.InHMD", "Application.ComfortMode", "Keyboard.RightMouseClick" ],
"when": [ "Application.InHMD", "Application.ComfortMode", "Keyboard.RightMouseButton" ],
"to": "Actions.StepYaw",
"filters":
[
@ -46,7 +46,7 @@
},
{ "from": { "makeAxis" : ["Keyboard.MouseMoveLeft", "Keyboard.MouseMoveRight"] },
"when": "Keyboard.RightMouseClick",
"when": "Keyboard.RightMouseButton",
"to": "Actions.Yaw"
},
@ -55,8 +55,8 @@
{ "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.RightMouseButton", "to": "Actions.LATERAL_LEFT" },
{ "from": "Keyboard.Right", "when": "Keyboard.RightMouseButton", "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" },
@ -68,8 +68,8 @@
{ "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.MouseMoveUp", "when": "Keyboard.RightMouseButton", "to": "Actions.PITCH_UP" },
{ "from": "Keyboard.MouseMoveDown", "when": "Keyboard.RightMouseButton", "to": "Actions.PITCH_DOWN" },
{ "from": "Keyboard.TouchpadDown", "to": "Actions.PITCH_DOWN" },
{ "from": "Keyboard.TouchpadUp", "to": "Actions.PITCH_UP" },
@ -81,6 +81,7 @@
{ "from": "Keyboard.Space", "to": "Actions.SHIFT" },
{ "from": "Keyboard.R", "to": "Actions.ACTION1" },
{ "from": "Keyboard.T", "to": "Actions.ACTION2" }
{ "from": "Keyboard.T", "to": "Actions.ACTION2" },
{ "from": "Keyboard.RightMouseClicked", "to": "Actions.ContextMenu" }
]
}

View file

@ -16,7 +16,7 @@
{ "from": "Standard.RX", "to": "Actions.Yaw" },
{ "from": "Standard.RY", "to": "Actions.Pitch" },
{ "from": "Standard.RY", "filters": "invert", "to": "Actions.TranslateY" },
{ "from": [ "Standard.DU", "Standard.DL", "Standard.DR", "Standard.DD" ], "to": "Standard.LeftPrimaryThumb" },
@ -25,6 +25,9 @@
{ "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" },

View file

@ -392,7 +392,6 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) :
_entityClipboard->createRootElement();
_pluginContainer = new PluginContainerProxy();
Plugin::setContainer(_pluginContainer);
#ifdef Q_OS_WIN
installNativeEventFilter(&MyNativeEventFilter::getInstance());
#endif
@ -630,8 +629,14 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) :
// Setup the userInputMapper with the actions
auto userInputMapper = DependencyManager::get<UserInputMapper>();
connect(userInputMapper.data(), &UserInputMapper::actionEvent, [this](int action, float state) {
if (state && action == toInt(controller::Action::TOGGLE_MUTE)) {
DependencyManager::get<AudioClient>()->toggleMute();
if (state) {
if (action == controller::toInt(controller::Action::TOGGLE_MUTE)) {
DependencyManager::get<AudioClient>()->toggleMute();
} 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
}
}
});
@ -1785,9 +1790,7 @@ 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());
@ -2620,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) {

View file

@ -293,8 +293,9 @@ public slots:
void aboutApp();
void showEditEntitiesHelp();
void cycleCamera();
void cameraMenuChanged();
void reloadResourceCaches();
void crashApplication();

View file

@ -13,7 +13,6 @@
#include "ui/DialogsManager.h"
PluginContainerProxy::PluginContainerProxy() {
Plugin::setContainer(this);
}
PluginContainerProxy::~PluginContainerProxy() {

View file

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

View file

@ -44,7 +44,7 @@ QScriptValue AnimVariantMap::animVariantMapToScriptValue(QScriptEngine* engine,
break;
default:
// Note that we don't do mat4 in Javascript currently, and there's not yet a reason to start now.
assert("AnimVariant::Type" == "valid");
assert(QString("AnimVariant::Type") == QString("valid"));
}
};
if (useNames) { // copy only the requested names

View file

@ -60,6 +60,7 @@ namespace controller {
makeButtonPair(Action::ACTION2, "SecondaryAction"),
makeButtonPair(Action::CONTEXT_MENU, "ContextMenu"),
makeButtonPair(Action::TOGGLE_MUTE, "ToggleMute"),
makeButtonPair(Action::CYCLE_CAMERA, "CycleCamera"),
// Aliases and bisected versions
makeAxisPair(Action::LONGITUDINAL_BACKWARD, "Backward"),

View file

@ -51,6 +51,7 @@ enum class Action {
CONTEXT_MENU,
TOGGLE_MUTE,
CYCLE_CAMERA,
SHIFT,

View file

@ -7,8 +7,11 @@
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include "DeviceProxy.h"
namespace controller {
}
// NOTE: we don't need to include this header unless/until we add additional symbols.
// By removing this header we prevent these warnings on windows:
//
// warning LNK4221: This object file does not define any previously undefined public symbols,
// so it will not be used by any link operation that consumes this library
//
//#include "DeviceProxy.h"

View file

@ -118,41 +118,5 @@ QString StandardController::getDefaultMappingConfig() const {
return DEFAULT_MAPPING_JSON;
}
// FIXME figure out how to move the shifted version to JSON
//void StandardController::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;
//
// // Hold front right shoulder button for precision controls
// // Left Joystick: Movement, strafing
// mapper.addInputChannel(UserInputMapper::TRANSLATE_Z, makeInput(controller::LY), makeInput(controller::RB), JOYSTICK_MOVE_SPEED / 2.0f);
// mapper.addInputChannel(UserInputMapper::TRANSLATE_X, makeInput(controller::LY), makeInput(controller::RB), JOYSTICK_MOVE_SPEED / 2.0f);
//
// // Right Joystick: Camera orientation
// mapper.addInputChannel(UserInputMapper::YAW, makeInput(controller::RX), makeInput(controller::RB), JOYSTICK_YAW_SPEED / 2.0f);
// mapper.addInputChannel(UserInputMapper::PITCH, makeInput(controller::RY), makeInput(controller::RB), JOYSTICK_PITCH_SPEED / 2.0f);
//
// // Dpad movement
// mapper.addInputChannel(UserInputMapper::LONGITUDINAL_FORWARD, makeInput(controller::DU), makeInput(controller::RB), DPAD_MOVE_SPEED / 2.0f);
// mapper.addInputChannel(UserInputMapper::LONGITUDINAL_BACKWARD, makeInput(controller::DD), makeInput(controller::RB), DPAD_MOVE_SPEED / 2.0f);
// mapper.addInputChannel(UserInputMapper::LATERAL_RIGHT, makeInput(controller::DR), makeInput(controller::RB), DPAD_MOVE_SPEED / 2.0f);
// mapper.addInputChannel(UserInputMapper::LATERAL_LEFT, makeInput(controller::DL), makeInput(controller::RB), DPAD_MOVE_SPEED / 2.0f);
//
// // Button controls
// mapper.addInputChannel(UserInputMapper::VERTICAL_UP, makeInput(controller::Y), makeInput(controller::RB), DPAD_MOVE_SPEED / 2.0f);
// mapper.addInputChannel(UserInputMapper::VERTICAL_DOWN, makeInput(controller::X), makeInput(controller::RB), DPAD_MOVE_SPEED / 2.0f);
//
// // Zoom
// mapper.addInputChannel(UserInputMapper::BOOM_IN, makeInput(controller::RT), makeInput(controller::RB), BOOM_SPEED / 2.0f);
// mapper.addInputChannel(UserInputMapper::BOOM_OUT, makeInput(controller::LT), makeInput(controller::RB), BOOM_SPEED / 2.0f);
//
// mapper.addInputChannel(UserInputMapper::SHIFT, makeInput(controller::RB));
//
// mapper.addInputChannel(UserInputMapper::ACTION1, makeInput(controller::B));
// mapper.addInputChannel(UserInputMapper::ACTION2, makeInput(controller::A));
//}
}

View file

@ -58,15 +58,15 @@ namespace controller {
// Left Analog stick
LX = 0,
LY,
LZ,
// Right Analog stick
RX,
RY,
RZ,
// Triggers
LT,
RT,
NUM_STANDARD_AXES
NUM_STANDARD_AXES,
LZ = LT,
RZ = RT
};
// No correlation to SDL

View file

@ -74,7 +74,7 @@ void UserInputMapper::registerDevice(InputDevice::Pointer device) {
}
const auto& deviceID = device->_deviceID;
int numberOfType = recordDeviceOfType(device->getName());
recordDeviceOfType(device->getName());
qCDebug(controllers) << "Registered input device <" << device->getName() << "> deviceID = " << deviceID;
for (const auto& inputMapping : device->getAvailableInputs()) {
@ -266,7 +266,7 @@ void UserInputMapper::update(float deltaTime) {
}
auto standardInputs = getStandardInputs();
if (_lastStandardStates.size() != standardInputs.size()) {
if ((int)_lastStandardStates.size() != standardInputs.size()) {
_lastStandardStates.resize(standardInputs.size());
for (auto& lastValue : _lastStandardStates) {
lastValue = 0;
@ -513,7 +513,7 @@ bool UserInputMapper::applyRoute(const Route::Pointer& route, bool force) {
// and someone else wires it to CONTEXT_MENU, I don't want both to occur when
// I press the button. The exception is if I'm wiring a control back to itself
// in order to adjust my interface, like inverting the Y axis on an analog stick
if (!source->readable()) {
if (!route->peek && !source->readable()) {
if (debugRoutes && route->debug) {
qCDebug(controllers) << "Source unreadable";
}
@ -539,7 +539,7 @@ bool UserInputMapper::applyRoute(const Route::Pointer& route, bool force) {
// Fetch the value, may have been overriden by previous loopback routes
if (source->isPose()) {
Pose value = getPose(source);
Pose value = getPose(source, route->peek);
static const Pose IDENTITY_POSE { vec3(), quat() };
if (debugRoutes && route->debug) {
if (!value.valid) {
@ -554,7 +554,7 @@ bool UserInputMapper::applyRoute(const Route::Pointer& route, bool force) {
destination->apply(value, source);
} else {
// Fetch the value, may have been overriden by previous loopback routes
float value = getValue(source);
float value = getValue(source, route->peek);
if (debugRoutes && route->debug) {
qCDebug(controllers) << "Value was " << value;
@ -691,8 +691,8 @@ void UserInputMapper::enableMapping(const QString& mappingName, bool enable) {
}
}
float UserInputMapper::getValue(const Endpoint::Pointer& endpoint) {
return endpoint->value();
float UserInputMapper::getValue(const Endpoint::Pointer& endpoint, bool peek) {
return peek ? endpoint->peek() : endpoint->value();
}
float UserInputMapper::getValue(const Input& input) const {
@ -704,11 +704,11 @@ float UserInputMapper::getValue(const Input& input) const {
return endpoint->value();
}
Pose UserInputMapper::getPose(const Endpoint::Pointer& endpoint) {
Pose UserInputMapper::getPose(const Endpoint::Pointer& endpoint, bool peek) {
if (!endpoint->isPose()) {
return Pose();
}
return endpoint->pose();
return peek ? endpoint->peekPose() : endpoint->pose();
}
Pose UserInputMapper::getPose(const Input& input) const {
@ -742,6 +742,7 @@ static const QString JSON_NAME = QStringLiteral("name");
static const QString JSON_CHANNELS = QStringLiteral("channels");
static const QString JSON_CHANNEL_FROM = QStringLiteral("from");
static const QString JSON_CHANNEL_DEBUG = QStringLiteral("debug");
static const QString JSON_CHANNEL_PEEK = QStringLiteral("peek");
static const QString JSON_CHANNEL_WHEN = QStringLiteral("when");
static const QString JSON_CHANNEL_TO = QStringLiteral("to");
static const QString JSON_CHANNEL_FILTERS = QStringLiteral("filters");
@ -970,6 +971,7 @@ Route::Pointer UserInputMapper::parseRoute(const QJsonValue& value) {
result->json = QString(QJsonDocument(obj).toJson());
result->source = parseSource(obj[JSON_CHANNEL_FROM]);
result->debug = obj[JSON_CHANNEL_DEBUG].toBool();
result->debug = obj[JSON_CHANNEL_PEEK].toBool();
if (!result->source) {
qWarning() << "Invalid route source " << obj[JSON_CHANNEL_FROM];
return Route::Pointer();

View file

@ -38,8 +38,8 @@ namespace controller {
class UserInputMapper : public QObject, public Dependency {
Q_OBJECT
SINGLETON_DEPENDENCY
Q_ENUMS(Action)
SINGLETON_DEPENDENCY
Q_ENUMS(Action)
public:
// FIXME move to unordered set / map
@ -135,8 +135,8 @@ namespace controller {
int recordDeviceOfType(const QString& deviceName);
QHash<const QString&, int> _deviceCounts;
static float getValue(const EndpointPointer& endpoint);
static Pose getPose(const EndpointPointer& endpoint);
static float getValue(const EndpointPointer& endpoint, bool peek = false);
static Pose getPose(const EndpointPointer& endpoint, bool peek = false);
friend class RouteBuilderProxy;
friend class MappingBuilderProxy;

View file

@ -6,9 +6,11 @@
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include "Endpoint.h"
namespace controller {
}
// NOTE: we don't need to include this header unless/until we add additional symbols.
// By removing this header we prevent these warnings on windows:
//
// warning LNK4221: This object file does not define any previously undefined public symbols,
// so it will not be used by any link operation that consumes this library
//
//#include "Endpoint.h"

View file

@ -36,12 +36,13 @@ namespace controller {
using WriteLambda = std::function<void(float)>;
Endpoint(const Input& input) : _input(input) {}
virtual float value() = 0;
virtual float value() { return peek(); }
virtual float peek() const = 0;
virtual void apply(float value, const Pointer& source) = 0;
virtual Pose pose() { return Pose(); }
virtual Pose peekPose() const { return Pose(); };
virtual Pose pose() { return peekPose(); }
virtual void apply(const Pose& value, const Pointer& source) {}
virtual const bool isPose() { return _input.isPose(); }
virtual bool isPose() const { return _input.isPose(); }
virtual bool writeable() const { return true; }
virtual bool readable() const { return true; }
virtual void reset() { }
@ -54,10 +55,11 @@ namespace controller {
class LambdaEndpoint : public Endpoint {
public:
using Endpoint::apply;
LambdaEndpoint(ReadLambda readLambda, WriteLambda writeLambda = [](float) {})
: Endpoint(Input::INVALID_INPUT), _readLambda(readLambda), _writeLambda(writeLambda) { }
virtual float value() override { return _readLambda(); }
virtual float peek() const override { return _readLambda(); }
virtual void apply(float value, const Pointer& source) override { _writeLambda(value); }
private:
@ -72,10 +74,10 @@ namespace controller {
: Endpoint(id) {
}
virtual float value() override { return _currentValue; }
virtual float peek() const override { return _currentValue; }
virtual void apply(float value, const Pointer& source) override { _currentValue = value; }
virtual Pose pose() override { return _currentPose; }
virtual Pose peekPose() const override { return _currentPose; }
virtual void apply(const Pose& value, const Pointer& source) override {
_currentPose = value;
}

View file

@ -5,4 +5,11 @@
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include "Mapping.h"
// NOTE: we don't need to include this header unless/until we add additional symbols.
// By removing this header we prevent these warnings on windows:
//
// warning LNK4221: This object file does not define any previously undefined public symbols,
// so it will not be used by any link operation that consumes this library
//
//#include "Mapping.h"

View file

@ -6,4 +6,10 @@
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include "Route.h"
// NOTE: we don't need to include this header unless/until we add additional symbols.
// By removing this header we prevent these warnings on windows:
//
// warning LNK4221: This object file does not define any previously undefined public symbols,
// so it will not be used by any link operation that consumes this library
//
//#include "Route.h"

View file

@ -26,6 +26,7 @@ namespace controller {
Filter::List filters;
QString json;
bool debug { false };
bool peek { false };
using Pointer = std::shared_ptr<Route>;
using List = std::list<Pointer>;

View file

@ -52,6 +52,11 @@ QObject* RouteBuilderProxy::debug(bool enable) {
return this;
}
QObject* RouteBuilderProxy::peek(bool enable) {
_route->peek = enable;
return this;
}
QObject* RouteBuilderProxy::when(const QScriptValue& expression) {
_route->conditional = _parent.conditionalFor(expression);
return this;

View file

@ -38,6 +38,7 @@ class RouteBuilderProxy : public QObject {
Q_INVOKABLE void to(const QScriptValue& destination);
Q_INVOKABLE QObject* debug(bool enable = true);
Q_INVOKABLE QObject* peek(bool enable = true);
Q_INVOKABLE QObject* when(const QScriptValue& expression);
Q_INVOKABLE QObject* clamp(float min, float max);
Q_INVOKABLE QObject* hysteresis(float min, float max);
@ -48,7 +49,7 @@ class RouteBuilderProxy : public QObject {
Q_INVOKABLE QObject* constrainToInteger();
Q_INVOKABLE QObject* constrainToPositiveInteger();
private:
private:
void to(const Endpoint::Pointer& destination);
void conditional(const Conditional::Pointer& conditional);
void addFilter(Filter::Pointer filter);

View file

@ -6,4 +6,10 @@
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include "EndpointConditional.h"
// NOTE: we don't need to include this header unless/until we add additional symbols.
// By removing this header we prevent these warnings on windows:
//
// warning LNK4221: This object file does not define any previously undefined public symbols,
// so it will not be used by any link operation that consumes this library
//
//#include "EndpointConditional.h"

View file

@ -18,7 +18,7 @@ namespace controller {
class EndpointConditional : public Conditional {
public:
EndpointConditional(Endpoint::Pointer endpoint) : _endpoint(endpoint) {}
virtual bool satisfied() override { return _endpoint && _endpoint->value() != 0.0; }
virtual bool satisfied() override { return _endpoint && _endpoint->peek() != 0.0f; }
private:
Endpoint::Pointer _endpoint;
};

View file

@ -6,4 +6,10 @@
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include "NotConditional.h"
// NOTE: we don't need to include this header unless/until we add additional symbols.
// By removing this header we prevent these warnings on windows:
//
// warning LNK4221: This object file does not define any previously undefined public symbols,
// so it will not be used by any link operation that consumes this library
//
//#include "NotConditional.h"

View file

@ -23,10 +23,10 @@ class ActionEndpoint : public Endpoint {
public:
ActionEndpoint(const Input& id = Input::INVALID_INPUT) : Endpoint(id) { }
virtual float value() override { return _currentValue; }
virtual float peek() const { return _currentValue; }
virtual void apply(float newValue, const Pointer& source) override;
virtual Pose pose() override { return _currentPose; }
virtual Pose peekPose() const { return _currentPose; }
virtual void apply(const Pose& value, const Pointer& source) override;
virtual void reset() override;

View file

@ -27,13 +27,19 @@ AnyEndpoint::AnyEndpoint(Endpoint::List children) : Endpoint(Input::INVALID_INPU
}
}
float AnyEndpoint::peek() const {
float result = 0;
for (auto& child : _children) {
result = std::max(result, child->peek());
}
return result;
}
// Fetching the value must trigger any necessary side effects of value() on ALL the children.
float AnyEndpoint::value() {
float result = 0;
for (auto& child : _children) {
float childResult = child->value();
if (childResult != 0.0f) {
result = childResult;
}
result = std::max(result, child->value());
}
return result;
}

View file

@ -17,7 +17,9 @@ namespace controller {
class AnyEndpoint : public Endpoint {
friend class UserInputMapper;
public:
using Endpoint::apply;
AnyEndpoint(Endpoint::List children);
virtual float peek() const override;
virtual float value() override;
virtual void apply(float newValue, const Endpoint::Pointer& source) override;
virtual bool writeable() const override;

View file

@ -6,4 +6,10 @@
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include "ArrayEndpoint.h"
// NOTE: we don't need to include this header unless/until we add additional symbols.
// By removing this header we prevent these warnings on windows:
//
// warning LNK4221: This object file does not define any previously undefined public symbols,
// so it will not be used by any link operation that consumes this library
//
//#include "ArrayEndpoint.h"

View file

@ -17,12 +17,11 @@ namespace controller {
class ArrayEndpoint : public Endpoint {
friend class UserInputMapper;
public:
using Endpoint::apply;
using Pointer = std::shared_ptr<ArrayEndpoint>;
ArrayEndpoint() : Endpoint(Input::INVALID_INPUT) { }
virtual float value() override {
return 0.0;
}
virtual float peek() const override { return 0.0f; }
virtual void apply(float value, const Endpoint::Pointer& source) override {
for (auto& child : _children) {

View file

@ -24,6 +24,12 @@ bool CompositeEndpoint::readable() const {
return first->readable() && second->readable();
}
float CompositeEndpoint::peek() const {
float result = first->peek() * -1.0f + second->peek();
return result;
}
// Fetching via value() must trigger any side effects of value() on the children
float CompositeEndpoint::value() {
float result = first->value() * -1.0f + second->value();
return result;

View file

@ -15,8 +15,10 @@
namespace controller {
class CompositeEndpoint : public Endpoint, Endpoint::Pair {
public:
using Endpoint::apply;
CompositeEndpoint(Endpoint::Pointer first, Endpoint::Pointer second);
virtual float peek() const override;
virtual float value() override;
virtual void apply(float newValue, const Pointer& source) override;
virtual bool readable() const override;

View file

@ -13,10 +13,10 @@
#include "../../UserInputMapper.h"
using namespace controller;
float InputEndpoint::value(){
_read = true;
float InputEndpoint::peek() const {
if (isPose()) {
return pose().valid ? 1.0f : 0.0f;
return peekPose().valid ? 1.0f : 0.0f;
}
auto userInputMapper = DependencyManager::get<UserInputMapper>();
auto deviceProxy = userInputMapper->getDevice(_input);
@ -26,8 +26,12 @@ float InputEndpoint::value(){
return deviceProxy->getValue(_input);
}
Pose InputEndpoint::pose() {
float InputEndpoint::value(){
_read = true;
return peek();
}
Pose InputEndpoint::peekPose() const {
if (!isPose()) {
return Pose();
}
@ -39,3 +43,8 @@ Pose InputEndpoint::pose() {
return deviceProxy->getPose(_input.channel);
}
Pose InputEndpoint::pose() {
_read = true;
return peekPose();
}

View file

@ -20,9 +20,11 @@ public:
: Endpoint(id) {
}
virtual float peek() const override;
virtual float value() override;
// FIXME need support for writing back to vibration / force feedback effects
virtual void apply(float newValue, const Pointer& source) override {}
virtual Pose peekPose() const override;
virtual Pose pose() override;
virtual void apply(const Pose& value, const Pointer& source) override { }

View file

@ -6,4 +6,10 @@
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include "JSEndpoint.h"
// NOTE: we don't need to include this header unless/until we add additional symbols.
// By removing this header we prevent these warnings on windows:
//
// warning LNK4221: This object file does not define any previously undefined public symbols,
// so it will not be used by any link operation that consumes this library
//
//#include "JSEndpoint.h"

View file

@ -19,13 +19,13 @@ namespace controller {
class JSEndpoint : public Endpoint {
public:
using Endpoint::apply;
JSEndpoint(const QJSValue& callable)
: Endpoint(Input::INVALID_INPUT), _callable(callable) {
}
virtual float value() {
float result = (float)_callable.call().toNumber();
return result;
virtual float peek() const {
return (float)const_cast<JSEndpoint*>(this)->_callable.call().toNumber();
}
virtual void apply(float newValue, const Pointer& source) {

View file

@ -12,8 +12,8 @@
using namespace controller;
float ScriptEndpoint::value() {
updateValue();
float ScriptEndpoint::peek() const {
const_cast<ScriptEndpoint*>(this)->updateValue();
return _lastValueRead;
}

View file

@ -19,12 +19,13 @@ namespace controller {
class ScriptEndpoint : public Endpoint {
Q_OBJECT;
public:
using Endpoint::apply;
ScriptEndpoint(const QScriptValue& callable)
: Endpoint(Input::INVALID_INPUT), _callable(callable) {
}
virtual float value();
virtual void apply(float newValue, const Pointer& source);
virtual float peek() const override;
virtual void apply(float newValue, const Pointer& source) override;
protected:
Q_INVOKABLE void updateValue();

View file

@ -6,4 +6,10 @@
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include "StandardEndpoint.h"
// NOTE: we don't need to include this header unless/until we add additional symbols.
// By removing this header we prevent these warnings on windows:
//
// warning LNK4221: This object file does not define any previously undefined public symbols,
// so it will not be used by any link operation that consumes this library
//
//#include "StandardEndpoint.h"

View file

@ -32,7 +32,7 @@ public:
virtual void apply(float value, const Pointer& source) override {
// For standard endpoints, the first NON-ZERO write counts.
if (value != 0.0) {
if (value != 0.0f) {
_written = true;
}
VirtualEndpoint::apply(value, source);

View file

@ -6,4 +6,10 @@
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include "ConstrainToIntegerFilter.h"
// NOTE: we don't need to include this header unless/until we add additional symbols.
// By removing this header we prevent these warnings on windows:
//
// warning LNK4221: This object file does not define any previously undefined public symbols,
// so it will not be used by any link operation that consumes this library
//
//#include "ConstrainToIntegerFilter.h"

View file

@ -6,4 +6,10 @@
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include "ConstrainToPositiveIntegerFilter.h"
// NOTE: we don't need to include this header unless/until we add additional symbols.
// By removing this header we prevent these warnings on windows:
//
// warning LNK4221: This object file does not define any previously undefined public symbols,
// so it will not be used by any link operation that consumes this library
//
//#include "ConstrainToPositiveIntegerFilter.h"

View file

@ -6,4 +6,10 @@
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include "InvertFilter.h"
// NOTE: we don't need to include this header unless/until we add additional symbols.
// By removing this header we prevent these warnings on windows:
//
// warning LNK4221: This object file does not define any previously undefined public symbols,
// so it will not be used by any link operation that consumes this library
//
//#include "InvertFilter.h"

View file

@ -17,6 +17,7 @@ namespace controller {
class InvertFilter : public ScaleFilter {
REGISTER_FILTER_CLASS(InvertFilter);
public:
using ScaleFilter::parseParameters;
InvertFilter() : ScaleFilter(-1.0f) {}
virtual bool parseParameters(const QJsonArray& parameters) { return true; }

View file

@ -1,6 +1,6 @@
set(TARGET_NAME display-plugins)
setup_hifi_library(OpenGL)
link_hifi_libraries(shared plugins gpu gl)
link_hifi_libraries(shared plugins gl)
target_opengl()
@ -8,11 +8,6 @@ GroupSources("src/display-plugins")
target_oglplus()
add_dependency_external_projects(LibOVR)
find_package(LibOVR REQUIRED)
target_include_directories(${TARGET_NAME} PRIVATE ${LIBOVR_INCLUDE_DIRS})
target_link_libraries(${TARGET_NAME} ${LIBOVR_LIBRARIES})
if (WIN32)
add_dependency_external_projects(OpenVR)
find_package(OpenVR REQUIRED)

View file

@ -12,7 +12,6 @@
#include "DisplayPlugin.h"
#include <plugins/PluginContainer.h>
#include <OVR_CAPI_Keys.h>
static Setting::Handle<float> IPD_SCALE_HANDLE("hmd.ipdScale", 1.0f);
@ -26,12 +25,12 @@ float AbstractHMDScriptingInterface::getIPD() const {
float AbstractHMDScriptingInterface::getEyeHeight() const {
// FIXME update the display plugin interface to expose per-plugin settings
return OVR_DEFAULT_EYE_HEIGHT;
return getPlayerHeight() - 0.10f;
}
float AbstractHMDScriptingInterface::getPlayerHeight() const {
// FIXME update the display plugin interface to expose per-plugin settings
return OVR_DEFAULT_PLAYER_HEIGHT;
return 1.755f;
}
float AbstractHMDScriptingInterface::getIPDScale() const {

View file

@ -35,36 +35,36 @@ QAction* _vsyncAction{ nullptr };
void Basic2DWindowOpenGLDisplayPlugin::activate() {
_framerateActions.clear();
CONTAINER->addMenuItem(MENU_PATH(), FULLSCREEN,
_container->addMenuItem(MENU_PATH(), FULLSCREEN,
[this](bool clicked) {
if (clicked) {
CONTAINER->setFullscreen(getFullscreenTarget());
_container->setFullscreen(getFullscreenTarget());
} else {
CONTAINER->unsetFullscreen();
_container->unsetFullscreen();
}
}, true, false);
CONTAINER->addMenu(FRAMERATE);
_container->addMenu(FRAMERATE);
_framerateActions.push_back(
CONTAINER->addMenuItem(FRAMERATE, FRAMERATE_UNLIMITED,
_container->addMenuItem(FRAMERATE, FRAMERATE_UNLIMITED,
[this](bool) { updateFramerate(); }, true, true, FRAMERATE));
_framerateActions.push_back(
CONTAINER->addMenuItem(FRAMERATE, FRAMERATE_60,
_container->addMenuItem(FRAMERATE, FRAMERATE_60,
[this](bool) { updateFramerate(); }, true, false, FRAMERATE));
_framerateActions.push_back(
CONTAINER->addMenuItem(FRAMERATE, FRAMERATE_50,
_container->addMenuItem(FRAMERATE, FRAMERATE_50,
[this](bool) { updateFramerate(); }, true, false, FRAMERATE));
_framerateActions.push_back(
CONTAINER->addMenuItem(FRAMERATE, FRAMERATE_40,
_container->addMenuItem(FRAMERATE, FRAMERATE_40,
[this](bool) { updateFramerate(); }, true, false, FRAMERATE));
_framerateActions.push_back(
CONTAINER->addMenuItem(FRAMERATE, FRAMERATE_30,
_container->addMenuItem(FRAMERATE, FRAMERATE_30,
[this](bool) { updateFramerate(); }, true, false, FRAMERATE));
WindowOpenGLDisplayPlugin::activate();
// Vsync detection happens in the parent class activate, so we need to check after that
if (_vsyncSupported) {
_vsyncAction = CONTAINER->addMenuItem(MENU_PATH(), VSYNC_ON, [this](bool) {}, true, true);
_vsyncAction = _container->addMenuItem(MENU_PATH(), VSYNC_ON, [this](bool) {}, true, true);
} else {
_vsyncAction = nullptr;
}
@ -107,7 +107,7 @@ int Basic2DWindowOpenGLDisplayPlugin::getDesiredInterval() const {
bool Basic2DWindowOpenGLDisplayPlugin::isThrottled() const {
static const QString ThrottleFPSIfNotFocus = "Throttle FPS If Not Focus"; // FIXME - this value duplicated in Menu.h
bool shouldThrottle = (!CONTAINER->isForeground() && CONTAINER->isOptionChecked(ThrottleFPSIfNotFocus));
bool shouldThrottle = (!_container->isForeground() && _container->isOptionChecked(ThrottleFPSIfNotFocus));
if (_isThrottled != shouldThrottle) {
_isThrottled = shouldThrottle;

View file

@ -15,9 +15,6 @@
#include "Basic2DWindowOpenGLDisplayPlugin.h"
#include "openvr/OpenVrDisplayPlugin.h"
#include "oculus/OculusDisplayPlugin.h"
#include "oculus/OculusDebugDisplayPlugin.h"
#include "oculus/OculusLegacyDisplayPlugin.h"
const QString& DisplayPlugin::MENU_PATH() {
static const QString value = "Display";
@ -40,15 +37,6 @@ DisplayPluginList getDisplayPlugins() {
new InterleavedStereoDisplayPlugin(),
// HMDs
// Windows Oculus SDK
new OculusDisplayPlugin(),
// Windows Oculus Simulator... uses head tracking and the same rendering
// as the connected hardware, but without using the SDK to display to the
// Rift. Useful for debugging Rift performance with nSight.
new OculusDebugDisplayPlugin(),
// Mac/Linux Oculus SDK (0.5)
new OculusLegacyDisplayPlugin(),
#ifdef Q_OS_WIN
// SteamVR SDK
new OpenVrDisplayPlugin(),

View file

@ -5,135 +5,6 @@
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#pragma once
#include "plugins/Plugin.h"
#include <QSize>
#include <QPoint>
#include <functional>
#include <gl/Config.h>
#include <GLMHelpers.h>
#include <glm/glm.hpp>
#include <glm/gtc/quaternion.hpp>
#include <RegisteredMetaTypes.h>
enum Eye {
Left,
Right,
Mono
};
/*
* Helper method to iterate over each eye
*/
template <typename F>
void for_each_eye(F f) {
f(Left);
f(Right);
}
/*
* Helper method to iterate over each eye, with an additional lambda to take action between the eyes
*/
template <typename F, typename FF>
void for_each_eye(F f, FF ff) {
f(Eye::Left);
ff();
f(Eye::Right);
}
class QWindow;
#define AVERAGE_HUMAN_IPD 0.064f
class DisplayPlugin : public Plugin {
Q_OBJECT
public:
virtual bool isHmd() const { return false; }
virtual int getHmdScreen() const { return -1; }
/// By default, all HMDs are stereo
virtual bool isStereo() const { return isHmd(); }
virtual bool isThrottled() const { return false; }
// Rendering support
// Stop requesting renders, but don't do full deactivation
// needed to work around the issues caused by Oculus
// processing messages in the middle of submitFrame
virtual void stop() = 0;
/**
* Called by the application before the frame rendering. Can be used for
* render timing related calls (for instance, the Oculus begin frame timing
* call)
*/
virtual void preRender() = 0;
/**
* Called by the application immediately before calling the display function.
* For OpenGL based plugins, this is the best place to put activate the output
* OpenGL context
*/
virtual void preDisplay() = 0;
/**
* Sends the scene texture to the display plugin.
*/
virtual void display(GLuint sceneTexture, const glm::uvec2& sceneSize) = 0;
/**
* Called by the application immeidately after display. For OpenGL based
* displays, this is the best place to put the buffer swap
*/
virtual void finishFrame() = 0;
// Does the rendering surface have current focus?
virtual bool hasFocus() const = 0;
// The size of the rendering target (may be larger than the device size due to distortion)
virtual glm::uvec2 getRecommendedRenderSize() const = 0;
// The size of the UI
virtual glm::uvec2 getRecommendedUiSize() const {
return getRecommendedRenderSize();
}
// By default the aspect ratio is just the render size
virtual float getRecommendedAspectRatio() const {
return aspect(getRecommendedRenderSize());
}
// Stereo specific methods
virtual glm::mat4 getProjection(Eye eye, const glm::mat4& baseProjection) const {
return baseProjection;
}
// HMD specific methods
// TODO move these into another class?
virtual glm::mat4 getEyeToHeadTransform(Eye eye) const {
static const glm::mat4 transform; return transform;
}
virtual glm::mat4 getHeadPose() const {
static const glm::mat4 pose; return pose;
}
// Needed for timewarp style features
virtual void setEyeRenderPose(Eye eye, const glm::mat4& pose) {
// NOOP
}
virtual float getIPD() const { return AVERAGE_HUMAN_IPD; }
virtual void abandonCalibration() {}
virtual void resetSensors() {}
virtual float devicePixelRatio() { return 1.0; }
static const QString& MENU_PATH();
signals:
void recommendedFramebufferSizeChanged(const QSize & size);
void requestRender();
};
#include <plugins/DisplayPlugin.h>

View file

@ -25,6 +25,6 @@ bool NullDisplayPlugin::hasFocus() const {
void NullDisplayPlugin::preRender() {}
void NullDisplayPlugin::preDisplay() {}
void NullDisplayPlugin::display(GLuint sceneTexture, const glm::uvec2& sceneSize) {}
void NullDisplayPlugin::display(uint32_t sceneTexture, const glm::uvec2& sceneSize) {}
void NullDisplayPlugin::finishFrame() {}
void NullDisplayPlugin::stop() {}

View file

@ -21,7 +21,7 @@ public:
virtual bool hasFocus() const override;
virtual void preRender() override;
virtual void preDisplay() override;
virtual void display(GLuint sceneTexture, const glm::uvec2& sceneSize) override;
virtual void display(uint32_t sceneTexture, const glm::uvec2& sceneSize) override;
virtual void finishFrame() override;
private:

View file

@ -9,6 +9,7 @@
#include <QOpenGLContext>
#include <QCoreApplication>
#include <gl/Config.h>
#include <gl/GlWindow.h>
#include <GLMHelpers.h>

View file

@ -42,7 +42,7 @@ bool WindowOpenGLDisplayPlugin::hasFocus() const {
void WindowOpenGLDisplayPlugin::activate() {
OpenGLDisplayPlugin::activate();
_window = CONTAINER->getPrimarySurface();
_window = _container->getPrimarySurface();
_window->makeCurrent();
customizeContext();
_window->doneCurrent();

View file

@ -89,7 +89,7 @@ bool OpenVrDisplayPlugin::isSupported() const {
}
void OpenVrDisplayPlugin::activate() {
CONTAINER->setIsOptionChecked(StandingHMDSensorMode, true);
_container->setIsOptionChecked(StandingHMDSensorMode, true);
hmdRefCount++;
vr::HmdError eError = vr::HmdError_None;
@ -132,7 +132,7 @@ void OpenVrDisplayPlugin::activate() {
}
void OpenVrDisplayPlugin::deactivate() {
CONTAINER->setIsOptionChecked(StandingHMDSensorMode, false);
_container->setIsOptionChecked(StandingHMDSensorMode, false);
hmdRefCount--;

View file

@ -74,21 +74,21 @@ void StereoDisplayPlugin::activate() {
if (screen == qApp->primaryScreen()) {
checked = true;
}
auto action = CONTAINER->addMenuItem(MENU_PATH(), name,
auto action = _container->addMenuItem(MENU_PATH(), name,
[this](bool clicked) { updateScreen(); }, true, checked, "Screens");
_screenActions[i] = action;
}
CONTAINER->removeMenu(FRAMERATE);
_container->removeMenu(FRAMERATE);
CONTAINER->setFullscreen(qApp->primaryScreen());
_container->setFullscreen(qApp->primaryScreen());
WindowOpenGLDisplayPlugin::activate();
}
void StereoDisplayPlugin::updateScreen() {
for (uint32_t i = 0; i < _screenActions.size(); ++i) {
if (_screenActions[i]->isChecked()) {
CONTAINER->setFullscreen(qApp->screens().at(i));
_container->setFullscreen(qApp->screens().at(i));
break;
}
}
@ -96,7 +96,7 @@ void StereoDisplayPlugin::updateScreen() {
void StereoDisplayPlugin::deactivate() {
_screenActions.clear();
CONTAINER->unsetFullscreen();
_container->unsetFullscreen();
WindowOpenGLDisplayPlugin::deactivate();
}

View file

@ -1,6 +1,6 @@
set(TARGET_NAME entities)
setup_hifi_library(Network Script)
link_hifi_libraries(avatars shared octree gpu model fbx networking animation environment)
link_hifi_libraries(avatars shared audio octree gpu model fbx networking animation environment)
target_bullet()

View file

@ -10,14 +10,4 @@
//
#pragma once
#include <plugins/Plugin.h>
class InputPlugin : public Plugin {
public:
virtual bool isJointController() const = 0;
virtual void pluginFocusOutEvent() = 0;
virtual void pluginUpdate(float deltaTime, bool jointsCaptured) = 0;
};
#include <plugins/InputPlugin.h>

View file

@ -59,11 +59,27 @@ void KeyboardMouseDevice::mousePressEvent(QMouseEvent* event, unsigned int devic
// key pressed again ? without catching the release event ?
}
_lastCursor = event->pos();
_mousePressAt = event->pos();
eraseMouseClicked();
}
void KeyboardMouseDevice::mouseReleaseEvent(QMouseEvent* event, unsigned int deviceID) {
auto input = makeInput((Qt::MouseButton) event->button());
_buttonPressedMap.erase(input.getChannel());
// if we pressed and released at the same location, then create a "_CLICKED" input for this button
// we might want to add some small tolerance to this so if you do a small drag it still counts as
// a clicked.
if (_mousePressAt == event->pos()) {
_buttonPressedMap.insert(makeInput((Qt::MouseButton) event->button(), true).getChannel());
}
}
void KeyboardMouseDevice::eraseMouseClicked() {
_buttonPressedMap.erase(makeInput(Qt::LeftButton, true).getChannel());
_buttonPressedMap.erase(makeInput(Qt::MiddleButton, true).getChannel());
_buttonPressedMap.erase(makeInput(Qt::RightButton, true).getChannel());
}
void KeyboardMouseDevice::mouseMoveEvent(QMouseEvent* event, unsigned int deviceID) {
@ -77,6 +93,8 @@ void KeyboardMouseDevice::mouseMoveEvent(QMouseEvent* event, unsigned int device
_axisStateMap[makeInput(MOUSE_AXIS_Y_NEG).getChannel()] = (currentMove.y() > 0 ? currentMove.y() : 0.0f);
_lastCursor = currentPos;
eraseMouseClicked();
}
void KeyboardMouseDevice::wheelEvent(QWheelEvent* event) {
@ -138,14 +156,17 @@ controller::Input KeyboardMouseDevice::makeInput(Qt::Key code) const {
return controller::Input(_deviceID, shortCode, controller::ChannelType::BUTTON);
}
controller::Input KeyboardMouseDevice::makeInput(Qt::MouseButton code) const {
controller::Input KeyboardMouseDevice::makeInput(Qt::MouseButton code, bool clicked) const {
switch (code) {
case Qt::LeftButton:
return controller::Input(_deviceID, MOUSE_BUTTON_LEFT, controller::ChannelType::BUTTON);
return controller::Input(_deviceID, clicked ? MOUSE_BUTTON_LEFT_CLICKED :
MOUSE_BUTTON_LEFT, controller::ChannelType::BUTTON);
case Qt::RightButton:
return controller::Input(_deviceID, MOUSE_BUTTON_RIGHT, controller::ChannelType::BUTTON);
return controller::Input(_deviceID, clicked ? MOUSE_BUTTON_RIGHT_CLICKED :
MOUSE_BUTTON_RIGHT, controller::ChannelType::BUTTON);
case Qt::MiddleButton:
return controller::Input(_deviceID, MOUSE_BUTTON_MIDDLE, controller::ChannelType::BUTTON);
return controller::Input(_deviceID, clicked ? MOUSE_BUTTON_MIDDLE_CLICKED :
MOUSE_BUTTON_MIDDLE, controller::ChannelType::BUTTON);
default:
return controller::Input();
};
@ -182,9 +203,13 @@ controller::Input::NamedVector KeyboardMouseDevice::getAvailableInputs() const {
availableInputs.append(Input::NamedPair(makeInput(Qt::Key_PageUp), QKeySequence(Qt::Key_PageUp).toString()));
availableInputs.append(Input::NamedPair(makeInput(Qt::Key_PageDown), QKeySequence(Qt::Key_PageDown).toString()));
availableInputs.append(Input::NamedPair(makeInput(Qt::LeftButton), "LeftMouseClick"));
availableInputs.append(Input::NamedPair(makeInput(Qt::MiddleButton), "MiddleMouseClick"));
availableInputs.append(Input::NamedPair(makeInput(Qt::RightButton), "RightMouseClick"));
availableInputs.append(Input::NamedPair(makeInput(Qt::LeftButton), "LeftMouseButton"));
availableInputs.append(Input::NamedPair(makeInput(Qt::MiddleButton), "MiddleMouseButton"));
availableInputs.append(Input::NamedPair(makeInput(Qt::RightButton), "RightMouseButton"));
availableInputs.append(Input::NamedPair(makeInput(Qt::LeftButton, true), "LeftMouseClicked"));
availableInputs.append(Input::NamedPair(makeInput(Qt::MiddleButton, true), "MiddleMouseClicked"));
availableInputs.append(Input::NamedPair(makeInput(Qt::RightButton, true), "RightMouseClicked"));
availableInputs.append(Input::NamedPair(makeInput(MOUSE_AXIS_X_POS), "MouseMoveRight"));
availableInputs.append(Input::NamedPair(makeInput(MOUSE_AXIS_X_NEG), "MouseMoveLeft"));
@ -209,72 +234,3 @@ QString KeyboardMouseDevice::getDefaultMappingConfig() const {
return MAPPING_JSON;
}
//void KeyboardMouseDevice::assignDefaultInputMapping(UserInputMapper& mapper) {
// const float BUTTON_MOVE_SPEED = 1.0f;
// const float BUTTON_YAW_SPEED = 0.75f;
// const float BUTTON_PITCH_SPEED = 0.5f;
// const float MOUSE_YAW_SPEED = 0.5f;
// const float MOUSE_PITCH_SPEED = 0.25f;
// const float TOUCH_YAW_SPEED = 0.5f;
// const float TOUCH_PITCH_SPEED = 0.25f;
// const float BUTTON_BOOM_SPEED = 0.1f;
//
// // AWSD keys mapping
//
// mapper.addInputChannel(controller::BOOM_IN, makeInput(Qt::Key_E), makeInput(Qt::Key_Shift), BUTTON_BOOM_SPEED);
// mapper.addInputChannel(controller::BOOM_OUT, makeInput(Qt::Key_C), makeInput(Qt::Key_Shift), BUTTON_BOOM_SPEED);
// mapper.addInputChannel(controller::LATERAL_LEFT, makeInput(Qt::Key_A), makeInput(Qt::RightButton), BUTTON_YAW_SPEED);
// mapper.addInputChannel(controller::LATERAL_RIGHT, makeInput(Qt::Key_D), makeInput(Qt::RightButton), BUTTON_YAW_SPEED);
// mapper.addInputChannel(controller::LATERAL_LEFT, makeInput(Qt::Key_A), makeInput(Qt::Key_Shift), BUTTON_YAW_SPEED);
// mapper.addInputChannel(controller::LATERAL_RIGHT, makeInput(Qt::Key_D), makeInput(Qt::Key_Shift), BUTTON_YAW_SPEED);
// mapper.addInputChannel(controller::PITCH_DOWN, makeInput(Qt::Key_S), makeInput(Qt::Key_Shift), BUTTON_PITCH_SPEED);
// mapper.addInputChannel(controller::PITCH_UP, makeInput(Qt::Key_W), makeInput(Qt::Key_Shift), BUTTON_PITCH_SPEED);
//
// // Arrow keys mapping
// mapper.addInputChannel(controller::LONGITUDINAL_BACKWARD, makeInput(Qt::Key_Down), BUTTON_MOVE_SPEED);
// mapper.addInputChannel(controller::LONGITUDINAL_FORWARD, makeInput(Qt::Key_Up), BUTTON_MOVE_SPEED);
// mapper.addInputChannel(controller::YAW_LEFT, makeInput(Qt::Key_Left), BUTTON_MOVE_SPEED);
// mapper.addInputChannel(controller::YAW_RIGHT, makeInput(Qt::Key_Right), BUTTON_MOVE_SPEED);
// mapper.addInputChannel(controller::VERTICAL_DOWN, makeInput(Qt::Key_PageDown), BUTTON_MOVE_SPEED);
// mapper.addInputChannel(controller::VERTICAL_UP, makeInput(Qt::Key_PageUp), BUTTON_MOVE_SPEED);
//
// mapper.addInputChannel(controller::LATERAL_LEFT, makeInput(Qt::Key_Left), makeInput(Qt::RightButton), BUTTON_YAW_SPEED);
// mapper.addInputChannel(controller::LATERAL_RIGHT, makeInput(Qt::Key_Right), makeInput(Qt::RightButton), BUTTON_YAW_SPEED);
// mapper.addInputChannel(controller::LATERAL_LEFT, makeInput(Qt::Key_Left), makeInput(Qt::Key_Shift), BUTTON_YAW_SPEED);
// mapper.addInputChannel(controller::LATERAL_RIGHT, makeInput(Qt::Key_Right), makeInput(Qt::Key_Shift), BUTTON_YAW_SPEED);
// mapper.addInputChannel(controller::PITCH_DOWN, makeInput(Qt::Key_Down), makeInput(Qt::Key_Shift), BUTTON_PITCH_SPEED);
// mapper.addInputChannel(controller::PITCH_UP, makeInput(Qt::Key_Up), makeInput(Qt::Key_Shift), BUTTON_PITCH_SPEED);
//
// // Mouse move
// mapper.addInputChannel(controller::PITCH_DOWN, makeInput(MOUSE_AXIS_Y_NEG), makeInput(Qt::RightButton), MOUSE_PITCH_SPEED);
// mapper.addInputChannel(controller::PITCH_UP, makeInput(MOUSE_AXIS_Y_POS), makeInput(Qt::RightButton), MOUSE_PITCH_SPEED);
// mapper.addInputChannel(controller::YAW_LEFT, makeInput(MOUSE_AXIS_X_NEG), makeInput(Qt::RightButton), MOUSE_YAW_SPEED);
// mapper.addInputChannel(controller::YAW_RIGHT, makeInput(MOUSE_AXIS_X_POS), makeInput(Qt::RightButton), MOUSE_YAW_SPEED);
//
//
//#ifdef Q_OS_MAC
// // wheel event modifier on Mac collide with the touchpad scroll event
// mapper.addInputChannel(controller::PITCH_DOWN, makeInput(TOUCH_AXIS_Y_NEG), TOUCH_PITCH_SPEED);
// mapper.addInputChannel(controller::PITCH_UP, makeInput(TOUCH_AXIS_Y_POS), TOUCH_PITCH_SPEED);
// mapper.addInputChannel(controller::YAW_LEFT, makeInput(TOUCH_AXIS_X_NEG), TOUCH_YAW_SPEED);
// mapper.addInputChannel(controller::YAW_RIGHT, makeInput(TOUCH_AXIS_X_POS), TOUCH_YAW_SPEED);
//#else
// // Touch pad yaw pitch
// mapper.addInputChannel(controller::PITCH_DOWN, makeInput(TOUCH_AXIS_Y_NEG), TOUCH_PITCH_SPEED);
// mapper.addInputChannel(controller::PITCH_UP, makeInput(TOUCH_AXIS_Y_POS), TOUCH_PITCH_SPEED);
// mapper.addInputChannel(controller::YAW_LEFT, makeInput(TOUCH_AXIS_X_NEG), TOUCH_YAW_SPEED);
// mapper.addInputChannel(controller::YAW_RIGHT, makeInput(TOUCH_AXIS_X_POS), TOUCH_YAW_SPEED);
//
// // Wheel move
// mapper.addInputChannel(controller::BOOM_IN, makeInput(MOUSE_AXIS_WHEEL_Y_POS), BUTTON_BOOM_SPEED);
// mapper.addInputChannel(controller::BOOM_OUT, makeInput(MOUSE_AXIS_WHEEL_Y_NEG), BUTTON_BOOM_SPEED);
// mapper.addInputChannel(controller::LATERAL_LEFT, makeInput(MOUSE_AXIS_WHEEL_X_NEG), BUTTON_YAW_SPEED);
// mapper.addInputChannel(controller::LATERAL_RIGHT, makeInput(MOUSE_AXIS_WHEEL_X_POS), BUTTON_YAW_SPEED);
//
//#endif
//
// mapper.addInputChannel(controller::SHIFT, makeInput(Qt::Key_Space));
// mapper.addInputChannel(controller::ACTION1, makeInput(Qt::Key_R));
// mapper.addInputChannel(controller::ACTION2, makeInput(Qt::Key_T));
//}

View file

@ -37,6 +37,9 @@ public:
MOUSE_BUTTON_LEFT = KEYBOARD_LAST + 1,
MOUSE_BUTTON_RIGHT,
MOUSE_BUTTON_MIDDLE,
MOUSE_BUTTON_LEFT_CLICKED,
MOUSE_BUTTON_RIGHT_CLICKED,
MOUSE_BUTTON_MIDDLE_CLICKED,
};
enum MouseAxisChannel {
@ -83,6 +86,7 @@ public:
void mouseMoveEvent(QMouseEvent* event, unsigned int deviceID = 0);
void mousePressEvent(QMouseEvent* event, unsigned int deviceID = 0);
void mouseReleaseEvent(QMouseEvent* event, unsigned int deviceID = 0);
void eraseMouseClicked();
void touchBeginEvent(const QTouchEvent* event);
void touchEndEvent(const QTouchEvent* event);
@ -92,7 +96,7 @@ public:
// Let's make it easy for Qt because we assume we love Qt forever
controller::Input makeInput(Qt::Key code) const;
controller::Input makeInput(Qt::MouseButton code) const;
controller::Input makeInput(Qt::MouseButton code, bool clicked = false) const;
controller::Input makeInput(MouseAxisChannel axis) const;
controller::Input makeInput(TouchAxisChannel axis) const;
controller::Input makeInput(TouchButtonChannel button) const;
@ -101,6 +105,7 @@ public:
protected:
QPoint _lastCursor;
QPoint _mousePressAt;
glm::vec2 _lastTouch;
bool _isTouching = false;

View file

@ -18,6 +18,33 @@
#include "SDL2Manager.h"
#ifdef HAVE_SDL2
static_assert(
(int)controller::A == (int)SDL_CONTROLLER_BUTTON_A &&
(int)controller::B == (int)SDL_CONTROLLER_BUTTON_B &&
(int)controller::X == (int)SDL_CONTROLLER_BUTTON_X &&
(int)controller::Y == (int)SDL_CONTROLLER_BUTTON_Y &&
(int)controller::BACK == (int)SDL_CONTROLLER_BUTTON_BACK &&
(int)controller::GUIDE == (int)SDL_CONTROLLER_BUTTON_GUIDE &&
(int)controller::START == (int)SDL_CONTROLLER_BUTTON_START &&
(int)controller::LS == (int)SDL_CONTROLLER_BUTTON_LEFTSTICK &&
(int)controller::RS == (int)SDL_CONTROLLER_BUTTON_RIGHTSTICK &&
(int)controller::LB == (int)SDL_CONTROLLER_BUTTON_LEFTSHOULDER &&
(int)controller::RB == (int)SDL_CONTROLLER_BUTTON_RIGHTSHOULDER &&
(int)controller::DU == (int)SDL_CONTROLLER_BUTTON_DPAD_UP &&
(int)controller::DD == (int)SDL_CONTROLLER_BUTTON_DPAD_DOWN &&
(int)controller::DL == (int)SDL_CONTROLLER_BUTTON_DPAD_LEFT &&
(int)controller::DR == (int)SDL_CONTROLLER_BUTTON_DPAD_RIGHT &&
(int)controller::LX == (int)SDL_CONTROLLER_AXIS_LEFTX &&
(int)controller::LY == (int)SDL_CONTROLLER_AXIS_LEFTY &&
(int)controller::RX == (int)SDL_CONTROLLER_AXIS_RIGHTX &&
(int)controller::RY == (int)SDL_CONTROLLER_AXIS_RIGHTY &&
(int)controller::LT == (int)SDL_CONTROLLER_AXIS_TRIGGERLEFT &&
(int)controller::RT == (int)SDL_CONTROLLER_AXIS_TRIGGERRIGHT,
"SDL2 equvalence: Enums and values from StandardControls.h are assumed to match enums from SDL_gamecontroller.h");
#endif
const QString SDL2Manager::NAME = "SDL2";
#ifdef HAVE_SDL2
@ -82,6 +109,7 @@ void SDL2Manager::activate() {
emit joystickAdded(joystick.get());
}
#endif
InputPlugin::activate();
}
void SDL2Manager::deactivate() {
@ -92,6 +120,7 @@ void SDL2Manager::deactivate() {
emit joystickRemoved(joystick.get());
}
#endif
InputPlugin::deactivate();
}

View file

@ -12,6 +12,8 @@
#include <vector>
#include <QCoreApplication>
#include <QtCore/QSysInfo>
#include <QtGlobal>
#include <GLMHelpers.h>
#include <NumericalConstants.h>
@ -74,7 +76,13 @@ SixenseManager::SixenseManager() :
bool SixenseManager::isSupported() const {
#ifdef HAVE_SIXENSE
#if defined(Q_OS_OSX)
return QSysInfo::macVersion() <= QSysInfo::MV_MAVERICKS;
#else
return true;
#endif
#else
return false;
#endif
@ -86,8 +94,8 @@ void SixenseManager::activate() {
_calibrationState = CALIBRATION_STATE_IDLE;
_avatarPosition = DEFAULT_AVATAR_POSITION;
CONTAINER->addMenu(MENU_PATH);
CONTAINER->addMenuItem(MENU_PATH, TOGGLE_SMOOTH,
_container->addMenu(MENU_PATH);
_container->addMenuItem(MENU_PATH, TOGGLE_SMOOTH,
[this] (bool clicked) { this->setSixenseFilter(clicked); },
true, true);
@ -128,8 +136,8 @@ void SixenseManager::deactivate() {
InputPlugin::deactivate();
#ifdef HAVE_SIXENSE
CONTAINER->removeMenuItem(MENU_NAME, TOGGLE_SMOOTH);
CONTAINER->removeMenu(MENU_PATH);
_container->removeMenuItem(MENU_NAME, TOGGLE_SMOOTH);
_container->removeMenu(MENU_PATH);
_poseStateMap.clear();
_collectedSamples.clear();
@ -311,7 +319,7 @@ void SixenseManager::updateCalibration(void* controllersX) {
_avatarRotation = glm::inverse(glm::quat_cast(glm::mat3(xAxis, Vectors::UNIT_Y, zAxis)));
const float Y_OFFSET_CALIBRATED_HANDS_TO_AVATAR = -0.3f;
_avatarPosition.y += Y_OFFSET_CALIBRATED_HANDS_TO_AVATAR;
CONTAINER->requestReset();
_container->requestReset();
qCDebug(inputplugins, "succeess: sixense calibration");
}
break;
@ -548,49 +556,6 @@ QString SixenseManager::getDefaultMappingConfig() const {
return MAPPING_JSON;
}
//
//void SixenseManager::assignDefaultInputMapping(UserInputMapper& mapper) {
// const float JOYSTICK_MOVE_SPEED = 1.0f;
// const float JOYSTICK_YAW_SPEED = 0.5f;
// const float JOYSTICK_PITCH_SPEED = 0.25f;
// const float BUTTON_MOVE_SPEED = 1.0f;
// const float BOOM_SPEED = 0.1f;
// using namespace controller;
//
// // Left Joystick: Movement, strafing
// mapper.addInputChannel(UserInputMapper::TRANSLATE_Z, makeInput(LY), JOYSTICK_MOVE_SPEED);
// mapper.addInputChannel(UserInputMapper::TRANSLATE_X, makeInput(LX), JOYSTICK_MOVE_SPEED);
//
// // Right Joystick: Camera orientation
// mapper.addInputChannel(UserInputMapper::YAW, makeInput(RX), JOYSTICK_YAW_SPEED);
// mapper.addInputChannel(UserInputMapper::PITCH, makeInput(RY), JOYSTICK_PITCH_SPEED);
//
// // Buttons
// mapper.addInputChannel(UserInputMapper::BOOM_IN, makeInput(L3), BOOM_SPEED);
// mapper.addInputChannel(UserInputMapper::BOOM_OUT, makeInput(L1), BOOM_SPEED);
//
// mapper.addInputChannel(UserInputMapper::VERTICAL_UP, makeInput(R3), BUTTON_MOVE_SPEED);
// mapper.addInputChannel(UserInputMapper::VERTICAL_DOWN, makeInput(R1), BUTTON_MOVE_SPEED);
//
// mapper.addInputChannel(UserInputMapper::SHIFT, makeInput(L2));
// mapper.addInputChannel(UserInputMapper::SHIFT, makeInput(R2));
//
// mapper.addInputChannel(UserInputMapper::ACTION1, makeInput(L4));
// mapper.addInputChannel(UserInputMapper::ACTION2, makeInput(R4));
//
// // FIXME
//// mapper.addInputChannel(UserInputMapper::LEFT_HAND, makeInput(LEFT_HAND));
//// mapper.addInputChannel(UserInputMapper::RIGHT_HAND, makeInput(RIGHT_HAND));
//
// mapper.addInputChannel(UserInputMapper::LEFT_HAND_CLICK, makeInput(LT));
// mapper.addInputChannel(UserInputMapper::RIGHT_HAND_CLICK, makeInput(RT));
//
// // TODO find a mechanism to allow users to navigate the context menu via
// mapper.addInputChannel(UserInputMapper::CONTEXT_MENU, makeInput(L0));
// mapper.addInputChannel(UserInputMapper::TOGGLE_MUTE, makeInput(R0));
//
//}
// virtual
void SixenseManager::saveSettings() const {
Settings settings;

View file

@ -75,8 +75,8 @@ bool ViveControllerManager::isSupported() const {
void ViveControllerManager::activate() {
InputPlugin::activate();
#ifdef Q_OS_WIN
CONTAINER->addMenu(MENU_PATH);
CONTAINER->addMenuItem(MENU_PATH, RENDER_CONTROLLERS,
_container->addMenu(MENU_PATH);
_container->addMenuItem(MENU_PATH, RENDER_CONTROLLERS,
[this] (bool clicked) { this->setRenderControllers(clicked); },
true, true);
@ -146,8 +146,8 @@ void ViveControllerManager::deactivate() {
InputPlugin::deactivate();
#ifdef Q_OS_WIN
CONTAINER->removeMenuItem(MENU_NAME, RENDER_CONTROLLERS);
CONTAINER->removeMenu(MENU_PATH);
_container->removeMenuItem(MENU_NAME, RENDER_CONTROLLERS);
_container->removeMenu(MENU_PATH);
hmdRefCount--;

View file

@ -146,7 +146,7 @@ MotionType EntityMotionState::computeObjectMotionType() const {
if (_entity->getCollisionsWillMove()) {
return MOTION_TYPE_DYNAMIC;
}
return _entity->isMoving() ? MOTION_TYPE_KINEMATIC : MOTION_TYPE_STATIC;
return (_entity->isMoving() || _entity->hasActions()) ? MOTION_TYPE_KINEMATIC : MOTION_TYPE_STATIC;
}
bool EntityMotionState::isMoving() const {
@ -184,6 +184,7 @@ void EntityMotionState::setWorldTransform(const btTransform& worldTrans) {
if (!_entity) {
return;
}
assert(entityTreeIsLocked());
measureBodyAcceleration();
_entity->setPosition(bulletToGLM(worldTrans.getOrigin()) + ObjectMotionState::getWorldOffset());

View file

@ -16,7 +16,6 @@
ObjectAction::ObjectAction(EntityActionType type, const QUuid& id, EntityItemPointer ownerEntity) :
btActionInterface(),
EntityActionInterface(type, id),
_active(false),
_ownerEntity(ownerEntity) {
}
@ -35,7 +34,9 @@ void ObjectAction::updateAction(btCollisionWorld* collisionWorld, btScalar delta
if (ownerEntityExpired) {
qDebug() << "warning -- action with no entity removing self from btCollisionWorld.";
btDynamicsWorld* dynamicsWorld = static_cast<btDynamicsWorld*>(collisionWorld);
dynamicsWorld->removeAction(this);
if (dynamicsWorld) {
dynamicsWorld->removeAction(this);
}
return;
}
@ -120,6 +121,17 @@ QVariantMap ObjectAction::getArguments() {
arguments["ttl"] = (float)(_expires - now) / (float)USECS_PER_SECOND;
}
arguments["tag"] = _tag;
EntityItemPointer entity = _ownerEntity.lock();
if (entity) {
ObjectMotionState* motionState = static_cast<ObjectMotionState*>(entity->getPhysicsInfo());
if (motionState) {
arguments["::active"] = motionState->isActive();
arguments["::motion-type"] = motionTypeToString(motionState->getMotionType());
} else {
arguments["::no-motion-state"] = true;
}
}
});
return arguments;
}

View file

@ -50,6 +50,8 @@ public:
virtual quint64 getExpires() { return _expires; }
protected:
quint64 localTimeToServerTime(quint64 timeValue) const;
quint64 serverTimeToLocalTime(quint64 timeValue) const;
virtual btRigidBody* getRigidBody();
virtual glm::vec3 getPosition();
@ -62,14 +64,10 @@ protected:
virtual void setAngularVelocity(glm::vec3 angularVelocity);
virtual void activateBody();
bool _active;
EntityItemWeakPointer _ownerEntity;
quint64 _expires; // in seconds since epoch
QString _tag;
quint64 localTimeToServerTime(quint64 timeValue) const;
quint64 serverTimeToLocalTime(quint64 timeValue) const;
quint64 _expires { 0 }; // in seconds since epoch
bool _active { false };
private:
int getEntityServerClockSkew() const;

View file

@ -20,17 +20,17 @@
// origin of physics simulation in world-frame
glm::vec3 _worldOffset(0.0f);
// static
// static
void ObjectMotionState::setWorldOffset(const glm::vec3& offset) {
_worldOffset = offset;
}
// static
// static
const glm::vec3& ObjectMotionState::getWorldOffset() {
return _worldOffset;
}
// static
// static
uint32_t worldSimulationStep = 0;
void ObjectMotionState::setWorldSimulationStep(uint32_t step) {
assert(step > worldSimulationStep);
@ -41,7 +41,7 @@ uint32_t ObjectMotionState::getWorldSimulationStep() {
return worldSimulationStep;
}
// static
// static
ShapeManager* shapeManager = nullptr;
void ObjectMotionState::setShapeManager(ShapeManager* manager) {
assert(manager);
@ -85,7 +85,7 @@ glm::vec3 ObjectMotionState::getBodyLinearVelocity() const {
glm::vec3 ObjectMotionState::getBodyLinearVelocityGTSigma() const {
// NOTE: the threshold to use here relates to the linear displacement threshold (dX) for sending updates
// to objects that are tracked server-side (e.g. entities which use dX = 2mm). Hence an object moving
// to objects that are tracked server-side (e.g. entities which use dX = 2mm). Hence an object moving
// just under this velocity threshold would trigger an update about V/dX times per second.
const float MIN_LINEAR_SPEED_SQUARED = 0.0036f; // 6 mm/sec

View file

@ -29,18 +29,27 @@ enum MotionType {
MOTION_TYPE_KINEMATIC // keyframed motion
};
inline QString motionTypeToString(MotionType motionType) {
switch(motionType) {
case MOTION_TYPE_STATIC: return QString("static");
case MOTION_TYPE_DYNAMIC: return QString("dynamic");
case MOTION_TYPE_KINEMATIC: return QString("kinematic");
}
return QString("unknown");
}
enum MotionStateType {
MOTIONSTATE_TYPE_INVALID,
MOTIONSTATE_TYPE_ENTITY,
MOTIONSTATE_TYPE_AVATAR
};
// The update flags trigger two varieties of updates: "hard" which require the body to be pulled
// The update flags trigger two varieties of updates: "hard" which require the body to be pulled
// and re-added to the physics engine and "easy" which just updates the body properties.
const uint32_t HARD_DIRTY_PHYSICS_FLAGS = (uint32_t)(Simulation::DIRTY_MOTION_TYPE | Simulation::DIRTY_SHAPE |
const uint32_t HARD_DIRTY_PHYSICS_FLAGS = (uint32_t)(Simulation::DIRTY_MOTION_TYPE | Simulation::DIRTY_SHAPE |
Simulation::DIRTY_COLLISION_GROUP);
const uint32_t EASY_DIRTY_PHYSICS_FLAGS = (uint32_t)(Simulation::DIRTY_TRANSFORM | Simulation::DIRTY_VELOCITIES |
Simulation::DIRTY_MASS | Simulation::DIRTY_MATERIAL |
Simulation::DIRTY_MASS | Simulation::DIRTY_MATERIAL |
Simulation::DIRTY_SIMULATOR_ID | Simulation::DIRTY_SIMULATOR_OWNERSHIP);
// These are the set of incoming flags that the PhysicsEngine needs to hear about:
@ -57,7 +66,7 @@ class PhysicsEngine;
class ObjectMotionState : public btMotionState {
public:
// These poroperties of the PhysicsEngine are "global" within the context of all ObjectMotionStates
// (assuming just one PhysicsEngine). They are cached as statics for fast calculations in the
// (assuming just one PhysicsEngine). They are cached as statics for fast calculations in the
// ObjectMotionState context.
static void setWorldOffset(const glm::vec3& offset);
static const glm::vec3& getWorldOffset();
@ -112,7 +121,7 @@ public:
virtual float getObjectFriction() const = 0;
virtual float getObjectLinearDamping() const = 0;
virtual float getObjectAngularDamping() const = 0;
virtual glm::vec3 getObjectPosition() const = 0;
virtual glm::quat getObjectRotation() const = 0;
virtual glm::vec3 getObjectLinearVelocity() const = 0;
@ -131,6 +140,11 @@ public:
bool isActive() const { return _body ? _body->isActive() : false; }
bool hasInternalKinematicChanges() const { return _hasInternalKinematicChanges; }
void dirtyInternalKinematicChanges() { _hasInternalKinematicChanges = true; }
void clearInternalKinematicChanges() { _hasInternalKinematicChanges = false; }
friend class PhysicsEngine;
protected:
@ -151,6 +165,7 @@ protected:
float _mass;
uint32_t _lastKinematicStep;
bool _hasInternalKinematicChanges { false };
};
typedef QSet<ObjectMotionState*> SetOfMotionStates;

View file

@ -82,12 +82,12 @@ void PhysicsEngine::addObject(ObjectMotionState* motionState) {
btCollisionShape* shape = motionState->getShape();
assert(shape);
body = new btRigidBody(mass, motionState, shape, inertia);
motionState->setRigidBody(body);
} else {
body->setMassProps(mass, inertia);
}
body->setCollisionFlags(btCollisionObject::CF_KINEMATIC_OBJECT);
body->updateInertiaTensor();
motionState->setRigidBody(body);
motionState->updateBodyVelocities();
const float KINEMATIC_LINEAR_VELOCITY_THRESHOLD = 0.01f; // 1 cm/sec
const float KINEMATIC_ANGULAR_VELOCITY_THRESHOLD = 0.01f; // ~1 deg/sec
@ -101,12 +101,15 @@ void PhysicsEngine::addObject(ObjectMotionState* motionState) {
shape->calculateLocalInertia(mass, inertia);
if (!body) {
body = new btRigidBody(mass, motionState, shape, inertia);
motionState->setRigidBody(body);
} else {
body->setMassProps(mass, inertia);
}
body->setCollisionFlags(body->getCollisionFlags() & ~(btCollisionObject::CF_KINEMATIC_OBJECT |
btCollisionObject::CF_STATIC_OBJECT));
body->updateInertiaTensor();
motionState->setRigidBody(body);
motionState->updateBodyVelocities();
// NOTE: Bullet will deactivate any object whose velocity is below these thresholds for longer than 2 seconds.
// (the 2 seconds is determined by: static btRigidBody::gDeactivationTime
const float DYNAMIC_LINEAR_VELOCITY_THRESHOLD = 0.05f; // 5 cm/sec
@ -123,12 +126,12 @@ void PhysicsEngine::addObject(ObjectMotionState* motionState) {
if (!body) {
assert(motionState->getShape());
body = new btRigidBody(mass, motionState, motionState->getShape(), inertia);
motionState->setRigidBody(body);
} else {
body->setMassProps(mass, inertia);
}
body->setCollisionFlags(btCollisionObject::CF_STATIC_OBJECT);
body->updateInertiaTensor();
motionState->setRigidBody(body);
break;
}
}

View file

@ -4,8 +4,8 @@
*
* This software is provided 'as-is', without any express or implied warranty.
* In no event will the authors be held liable for any damages arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it freely,
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it freely,
* subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
@ -75,7 +75,7 @@ int ThreadSafeDynamicsWorld::stepSimulationWithSubstepCallback(btScalar timeStep
}
}
// NOTE: We do NOT call synchronizeMotionState() after each substep (to avoid multiple locks on the
// NOTE: We do NOT call synchronizeMotionStates() after each substep (to avoid multiple locks on the
// object data outside of the physics engine). A consequence of this is that the transforms of the
// external objects only ever update at the end of the full step.
@ -87,6 +87,33 @@ int ThreadSafeDynamicsWorld::stepSimulationWithSubstepCallback(btScalar timeStep
return subSteps;
}
// call this instead of non-virtual btDiscreteDynamicsWorld::synchronizeSingleMotionState()
void ThreadSafeDynamicsWorld::synchronizeMotionState(btRigidBody* body) {
btAssert(body);
if (body->getMotionState() && !body->isStaticObject()) {
//we need to call the update at least once, even for sleeping objects
//otherwise the 'graphics' transform never updates properly
///@todo: add 'dirty' flag
//if (body->getActivationState() != ISLAND_SLEEPING)
{
if (body->isKinematicObject()) {
ObjectMotionState* objectMotionState = static_cast<ObjectMotionState*>(body->getMotionState());
if (objectMotionState->hasInternalKinematicChanges()) {
objectMotionState->clearInternalKinematicChanges();
body->getMotionState()->setWorldTransform(body->getWorldTransform());
}
return;
}
btTransform interpolatedTransform;
btTransformUtil::integrateTransform(body->getInterpolationWorldTransform(),
body->getInterpolationLinearVelocity(),body->getInterpolationAngularVelocity(),
(m_latencyMotionStateInterpolation && m_fixedTimeStep) ? m_localTime - m_fixedTimeStep : m_localTime*body->getHitFraction(),
interpolatedTransform);
body->getMotionState()->setWorldTransform(interpolatedTransform);
}
}
}
void ThreadSafeDynamicsWorld::synchronizeMotionStates() {
_changedMotionStates.clear();
BT_PROFILE("synchronizeMotionStates");
@ -97,22 +124,22 @@ void ThreadSafeDynamicsWorld::synchronizeMotionStates() {
btRigidBody* body = btRigidBody::upcast(colObj);
if (body) {
if (body->getMotionState()) {
synchronizeSingleMotionState(body);
synchronizeMotionState(body);
_changedMotionStates.push_back(static_cast<ObjectMotionState*>(body->getMotionState()));
}
}
}
} else {
} else {
//iterate over all active rigid bodies
for (int i=0;i<m_nonStaticRigidBodies.size();i++) {
btRigidBody* body = m_nonStaticRigidBodies[i];
if (body->isActive()) {
if (body->getMotionState()) {
synchronizeSingleMotionState(body);
synchronizeMotionState(body);
_changedMotionStates.push_back(static_cast<ObjectMotionState*>(body->getMotionState()));
}
}
}
}
}
}
}

View file

@ -4,8 +4,8 @@
*
* This software is provided 'as-is', without any express or implied warranty.
* In no event will the authors be held liable for any damages arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it freely,
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it freely,
* subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
@ -43,13 +43,16 @@ public:
void synchronizeMotionStates();
// btDiscreteDynamicsWorld::m_localTime is the portion of real-time that has not yet been simulated
// but is used for MotionState::setWorldTransform() extrapolation (a feature that Bullet uses to provide
// but is used for MotionState::setWorldTransform() extrapolation (a feature that Bullet uses to provide
// smoother rendering of objects when the physics simulation loop is ansynchronous to the render loop).
float getLocalTimeAccumulation() const { return m_localTime; }
VectorOfMotionStates& getChangedMotionStates() { return _changedMotionStates; }
private:
// call this instead of non-virtual btDiscreteDynamicsWorld::synchronizeSingleMotionState()
void synchronizeMotionState(btRigidBody* body);
VectorOfMotionStates _changedMotionStates;
};

View file

@ -0,0 +1,140 @@
//
// Created by Bradley Austin Davis on 2015/05/29
// 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
//
#pragma once
#include <functional>
#include <glm/glm.hpp>
#include <glm/gtc/quaternion.hpp>
#include <QtCore/QSize>
#include <QtCore/QPoint>
#include <GLMHelpers.h>
#include <RegisteredMetaTypes.h>
#include "Plugin.h"
enum Eye {
Left,
Right,
Mono
};
/*
* Helper method to iterate over each eye
*/
template <typename F>
void for_each_eye(F f) {
f(Left);
f(Right);
}
/*
* Helper method to iterate over each eye, with an additional lambda to take action between the eyes
*/
template <typename F, typename FF>
void for_each_eye(F f, FF ff) {
f(Eye::Left);
ff();
f(Eye::Right);
}
class QWindow;
#define AVERAGE_HUMAN_IPD 0.064f
class DisplayPlugin : public Plugin {
Q_OBJECT
public:
virtual bool isHmd() const { return false; }
virtual int getHmdScreen() const { return -1; }
/// By default, all HMDs are stereo
virtual bool isStereo() const { return isHmd(); }
virtual bool isThrottled() const { return false; }
// Rendering support
// Stop requesting renders, but don't do full deactivation
// needed to work around the issues caused by Oculus
// processing messages in the middle of submitFrame
virtual void stop() = 0;
/**
* Called by the application before the frame rendering. Can be used for
* render timing related calls (for instance, the Oculus begin frame timing
* call)
*/
virtual void preRender() = 0;
/**
* Called by the application immediately before calling the display function.
* For OpenGL based plugins, this is the best place to put activate the output
* OpenGL context
*/
virtual void preDisplay() = 0;
/**
* Sends the scene texture to the display plugin.
*/
virtual void display(uint32_t sceneTexture, const glm::uvec2& sceneSize) = 0;
/**
* Called by the application immeidately after display. For OpenGL based
* displays, this is the best place to put the buffer swap
*/
virtual void finishFrame() = 0;
// Does the rendering surface have current focus?
virtual bool hasFocus() const = 0;
// The size of the rendering target (may be larger than the device size due to distortion)
virtual glm::uvec2 getRecommendedRenderSize() const = 0;
// The size of the UI
virtual glm::uvec2 getRecommendedUiSize() const {
return getRecommendedRenderSize();
}
// By default the aspect ratio is just the render size
virtual float getRecommendedAspectRatio() const {
return aspect(getRecommendedRenderSize());
}
// Stereo specific methods
virtual glm::mat4 getProjection(Eye eye, const glm::mat4& baseProjection) const {
return baseProjection;
}
// HMD specific methods
// TODO move these into another class?
virtual glm::mat4 getEyeToHeadTransform(Eye eye) const {
static const glm::mat4 transform; return transform;
}
virtual glm::mat4 getHeadPose() const {
static const glm::mat4 pose; return pose;
}
// Needed for timewarp style features
virtual void setEyeRenderPose(Eye eye, const glm::mat4& pose) {
// NOOP
}
virtual float getIPD() const { return AVERAGE_HUMAN_IPD; }
virtual void abandonCalibration() {}
virtual void resetSensors() {}
virtual float devicePixelRatio() { return 1.0; }
static const QString& MENU_PATH();
signals:
void recommendedFramebufferSizeChanged(const QSize & size);
void requestRender();
};

View file

@ -21,3 +21,4 @@ using DisplayPluginPointer = QSharedPointer<DisplayPlugin>;
using DisplayPluginList = QVector<DisplayPluginPointer>;
using InputPluginPointer = QSharedPointer<InputPlugin>;
using InputPluginList = QVector<InputPluginPointer>;

View file

@ -0,0 +1,23 @@
//
// InputPlugin.h
// input-plugins/src/input-plugins
//
// Created by Sam Gondelman on 7/13/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
//
#pragma once
#include "Plugin.h"
class InputPlugin : public Plugin {
public:
virtual bool isJointController() const = 0;
virtual void pluginFocusOutEvent() = 0;
virtual void pluginUpdate(float deltaTime, bool jointsCaptured) = 0;
};

View file

@ -7,12 +7,10 @@
//
#include "Plugin.h"
PluginContainer* Plugin::CONTAINER{ nullptr };
QString Plugin::UNKNOWN_PLUGIN_ID("unknown");
void Plugin::setContainer(PluginContainer* container) {
CONTAINER = container;
_container = container;
}
bool Plugin::isSupported() const { return true; }

View file

@ -24,7 +24,7 @@ public:
virtual bool isSupported() const;
static void setContainer(PluginContainer* container);
void setContainer(PluginContainer* container);
/// Called when plugin is initially loaded, typically at application start
virtual void init();
@ -57,8 +57,8 @@ public:
virtual void loadSettings() {}
protected:
bool _active{ false };
static PluginContainer* CONTAINER;
bool _active { false };
PluginContainer* _container { nullptr };
static QString UNKNOWN_PLUGIN_ID;
};

View file

@ -6,15 +6,54 @@
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include "PluginManager.h"
#include <mutex>
#include "Forward.h"
#include <QtCore/QCoreApplication>
#include <QtCore/QDir>
#include <QtCore/QDebug>
#include <QtCore/QPluginLoader>
#include "RuntimePlugin.h"
#include "DisplayPlugin.h"
#include "InputPlugin.h"
#include "PluginContainer.h"
PluginManager* PluginManager::getInstance() {
static PluginManager _manager;
return &_manager;
}
using Loader = QSharedPointer<QPluginLoader>;
using LoaderList = QList<Loader>;
const LoaderList& getLoadedPlugins() {
static std::once_flag once;
static LoaderList loadedPlugins;
std::call_once(once, [&] {
QString pluginPath = QCoreApplication::applicationDirPath() + "/plugins/";
QDir pluginDir(pluginPath);
pluginDir.setFilter(QDir::Files);
if (pluginDir.exists()) {
qDebug() << "Loading runtime plugins from " << pluginPath;
auto candidates = pluginDir.entryList();
for (auto plugin : candidates) {
qDebug() << "Attempting plugins " << plugin;
QSharedPointer<QPluginLoader> loader(new QPluginLoader(pluginPath + plugin));
if (loader->load()) {
qDebug() << "Plugins " << plugin << " success";
loadedPlugins.push_back(loader);
}
}
}
});
return loadedPlugins;
}
PluginManager::PluginManager() {
}
// TODO migrate to a DLL model where plugins are discovered and loaded at runtime by the PluginManager class
extern DisplayPluginList getDisplayPlugins();
extern InputPluginList getInputPlugins();
@ -23,8 +62,25 @@ extern void saveInputPluginSettings(const InputPluginList& plugins);
const DisplayPluginList& PluginManager::getDisplayPlugins() {
static DisplayPluginList displayPlugins;
static std::once_flag once;
std::call_once(once, [&] {
// Grab the built in plugins
displayPlugins = ::getDisplayPlugins();
// Now grab the dynamic plugins
for (auto loader : getLoadedPlugins()) {
DisplayProvider* displayProvider = qobject_cast<DisplayProvider*>(loader->instance());
if (displayProvider) {
for (auto displayPlugin : displayProvider->getDisplayPlugins()) {
displayPlugins.push_back(displayPlugin);
}
}
}
auto& container = PluginContainer::getInstance();
for (auto plugin : displayPlugins) {
plugin->setContainer(&container);
}
});
return displayPlugins;
}
@ -34,6 +90,21 @@ const InputPluginList& PluginManager::getInputPlugins() {
static std::once_flag once;
std::call_once(once, [&] {
inputPlugins = ::getInputPlugins();
// Now grab the dynamic plugins
for (auto loader : getLoadedPlugins()) {
InputProvider* inputProvider = qobject_cast<InputProvider*>(loader->instance());
if (inputProvider) {
for (auto inputPlugin : inputProvider->getInputPlugins()) {
inputPlugins.push_back(inputPlugin);
}
}
}
auto& container = PluginContainer::getInstance();
for (auto plugin : inputPlugins) {
plugin->setContainer(&container);
}
});
return inputPlugins;
}

View file

@ -12,6 +12,7 @@
class PluginManager : public QObject {
public:
static PluginManager* getInstance();
PluginManager();
const DisplayPluginList& getDisplayPlugins();
const InputPluginList& getInputPlugins();

View file

@ -0,0 +1,36 @@
//
// Created by Bradley Austin Davis on 2015/10/24
// 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
//
#pragma once
#include <assert.h>
#include <QString>
#include <QObject>
#include "Forward.h"
class DisplayProvider {
public:
virtual ~DisplayProvider() {}
virtual DisplayPluginList getDisplayPlugins() = 0;
};
#define DisplayProvider_iid "com.highfidelity.plugins.display"
Q_DECLARE_INTERFACE(DisplayProvider, DisplayProvider_iid)
class InputProvider {
public:
virtual ~InputProvider() {}
virtual InputPluginList getInputPlugins() = 0;
};
#define InputProvider_iid "com.highfidelity.plugins.input"
Q_DECLARE_INTERFACE(InputProvider, InputProvider_iid)

View file

@ -1,5 +1,5 @@
set(TARGET_NAME procedural)
AUTOSCRIBE_SHADER_LIB(gpu model)
setup_hifi_library()
link_hifi_libraries(shared gpu model model-networking)
link_hifi_libraries(shared gpu networking model model-networking)

View file

@ -3,14 +3,4 @@ set(TARGET_NAME shared)
# TODO: there isn't really a good reason to have Script linked here - let's get what is requiring it out (RegisteredMetaTypes.cpp)
setup_hifi_library(Gui Network Script Widgets)
find_package(ZLIB REQUIRED)
target_link_libraries(${TARGET_NAME} ${ZLIB_LIBRARIES})
target_include_directories(${TARGET_NAME} PUBLIC ${ZLIB_INCLUDE_DIRS})
if (WIN32)
# Birarda will fix this when he finds it.
get_filename_component(ZLIB_LIB_DIR "${ZLIB_LIBRARIES}" DIRECTORY)
get_filename_component(ZLIB_DIR "${ZLIB_LIB_DIR}" DIRECTORY)
set(ZLIB_BIN_DIR "${ZLIB_DIR}/bin")
add_paths_to_fixup_libs(${ZLIB_BIN_DIR})
endif ()
target_zlib()

View file

@ -12,9 +12,12 @@
#include <qcoreapplication.h>
#include <qdatetime.h>
#include <qdebug.h>
#include <qtimer.h>
#include <QDateTime>
#include <QDebug>
#include <QTimer>
#include <QThread>
#include <QMutexLocker>
#include <QRegExp>
#include "LogHandler.h"
@ -24,13 +27,14 @@ LogHandler& LogHandler::getInstance() {
}
LogHandler::LogHandler() :
_shouldOutputPID(false)
_shouldOutputProcessID(false),
_shouldOutputThreadID(false)
{
// setup our timer to flush the verbose logs every 5 seconds
QTimer* logFlushTimer = new QTimer(this);
connect(logFlushTimer, &QTimer::timeout, this, &LogHandler::flushRepeatedMessages);
logFlushTimer->start(VERBOSE_LOG_INTERVAL_SECONDS * 1000);
// when the log handler is first setup we should print our timezone
QString timezoneString = "Time zone: " + QDateTime::currentDateTime().toString("t");
printf("%s\n", qPrintable(timezoneString));
@ -57,51 +61,55 @@ const char* stringForLogType(LogMsgType msgType) {
const QString DATE_STRING_FORMAT = "MM/dd hh:mm:ss";
void LogHandler::flushRepeatedMessages() {
QMutexLocker locker(&_repeatedMessageLock);
QHash<QString, int>::iterator message = _repeatMessageCountHash.begin();
while (message != _repeatMessageCountHash.end()) {
if (message.value() > 0) {
QString repeatMessage = QString("%1 repeated log entries matching \"%2\" - Last entry: \"%3\"")
.arg(message.value()).arg(message.key()).arg(_lastRepeatedMessage.value(message.key()));
QMessageLogContext emptyContext;
printMessage(LogSuppressed, emptyContext, repeatMessage);
}
_lastRepeatedMessage.remove(message.key());
message = _repeatMessageCountHash.erase(message);
}
}
QString LogHandler::printMessage(LogMsgType type, const QMessageLogContext& context, const QString& message) {
if (message.isEmpty()) {
return QString();
}
if (type == LogDebug) {
// for debug messages, check if this matches any of our regexes for repeated log messages
QMutexLocker locker(&_repeatedMessageLock);
foreach(const QString& regexString, getInstance()._repeatedMessageRegexes) {
QRegExp repeatRegex(regexString);
if (repeatRegex.indexIn(message) != -1) {
if (!_repeatMessageCountHash.contains(regexString)) {
// we have a match but didn't have this yet - output the first one
_repeatMessageCountHash[regexString] = 0;
// break the foreach so we output the first match
break;
} else {
// we have a match - add 1 to the count of repeats for this message and set this as the last repeated message
_repeatMessageCountHash[regexString] += 1;
_lastRepeatedMessage[regexString] = message;
// return out, we're not printing this one
return QString();
}
}
}
}
if (type == LogDebug) {
QMutexLocker locker(&_onlyOnceMessageLock);
// see if this message is one we should only print once
foreach(const QString& regexString, getInstance()._onlyOnceMessageRegexes) {
QRegExp onlyOnceRegex(regexString);
@ -118,23 +126,27 @@ QString LogHandler::printMessage(LogMsgType type, const QMessageLogContext& cont
}
}
}
// log prefix is in the following format
// [TIMESTAMP] [DEBUG] [PID] [TARGET] logged string
// [TIMESTAMP] [DEBUG] [PID] [TID] [TARGET] logged string
QString prefixString = QString("[%1]").arg(QDateTime::currentDateTime().toString(DATE_STRING_FORMAT));
prefixString.append(QString(" [%1]").arg(stringForLogType(type)));
if (_shouldOutputPID) {
if (_shouldOutputProcessID) {
prefixString.append(QString(" [%1]").arg(QCoreApplication::instance()->applicationPid()));
}
if (_shouldOutputThreadID) {
size_t threadID = (size_t)QThread::currentThreadId();
prefixString.append(QString(" [%1]").arg(threadID));
}
if (!_targetName.isEmpty()) {
prefixString.append(QString(" [%1]").arg(_targetName));
}
QString logMessage = QString("%1 %2").arg(prefixString, message.split("\n").join("\n" + prefixString + " "));
fprintf(stdout, "%s\n", qPrintable(logMessage));
return logMessage;
@ -143,3 +155,13 @@ QString LogHandler::printMessage(LogMsgType type, const QMessageLogContext& cont
void LogHandler::verboseMessageHandler(QtMsgType type, const QMessageLogContext& context, const QString& message) {
getInstance().printMessage((LogMsgType) type, context, message);
}
const QString& LogHandler::addRepeatedMessageRegex(const QString& regexString) {
QMutexLocker locker(&_repeatedMessageLock);
return *_repeatedMessageRegexes.insert(regexString);
}
const QString& LogHandler::addOnlyOnceMessageRegex(const QString& regexString) {
QMutexLocker locker(&_onlyOnceMessageLock);
return *_onlyOnceMessageRegexes.insert(regexString);
}

View file

@ -13,11 +13,11 @@
#ifndef hifi_LogHandler_h
#define hifi_LogHandler_h
#include <qhash.h>
#include <qobject.h>
#include <qregexp.h>
#include <qset.h>
#include <qstring.h>
#include <QHash>
#include <QObject>
#include <QSet>
#include <QString>
#include <QMutex>
const int VERBOSE_LOG_INTERVAL_SECONDS = 5;
@ -34,34 +34,38 @@ class LogHandler : public QObject {
Q_OBJECT
public:
static LogHandler& getInstance();
/// sets the target name to output via the verboseMessageHandler, called once before logging begins
/// \param targetName the desired target name to output in logs
void setTargetName(const QString& targetName) { _targetName = targetName; }
void setShouldOutputPID(bool shouldOutputPID) { _shouldOutputPID = shouldOutputPID; }
void setShouldOutputProcessID(bool shouldOutputProcessID) { _shouldOutputProcessID = shouldOutputProcessID; }
void setShouldOutputThreadID(bool shouldOutputThreadID) { _shouldOutputThreadID = shouldOutputThreadID; }
QString printMessage(LogMsgType type, const QMessageLogContext& context, const QString &message);
/// a qtMessageHandler that can be hooked up to a target that links to Qt
/// prints various process, message type, and time information
static void verboseMessageHandler(QtMsgType type, const QMessageLogContext& context, const QString &message);
const QString& addRepeatedMessageRegex(const QString& regexString) { return *_repeatedMessageRegexes.insert(regexString); }
const QString& addOnlyOnceMessageRegex(const QString& regexString) { return *_onlyOnceMessageRegexes.insert(regexString); }
const QString& addRepeatedMessageRegex(const QString& regexString);
const QString& addOnlyOnceMessageRegex(const QString& regexString);
private:
LogHandler();
void flushRepeatedMessages();
QString _targetName;
bool _shouldOutputPID;
bool _shouldOutputProcessID;
bool _shouldOutputThreadID;
QSet<QString> _repeatedMessageRegexes;
QHash<QString, int> _repeatMessageCountHash;
QHash<QString, QString> _lastRepeatedMessage;
QMutex _repeatedMessageLock;
QSet<QString> _onlyOnceMessageRegexes;
QHash<QString, int> _onlyOnceMessageCountHash;
QMutex _onlyOnceMessageLock;
};
#endif // hifi_LogHandler_h

18
plugins/CMakeLists.txt Normal file
View file

@ -0,0 +1,18 @@
#
# 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
#
# add the plugin directories
file(GLOB PLUGIN_SUBDIRS RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" "${CMAKE_CURRENT_SOURCE_DIR}/*")
list(REMOVE_ITEM PLUGIN_SUBDIRS "CMakeFiles")
foreach(DIR ${PLUGIN_SUBDIRS})
if(IS_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/${DIR}")
add_subdirectory(${DIR})
endif()
endforeach()

View file

@ -0,0 +1,25 @@
#
# 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
#
if (WIN32)
# we're using static GLEW, so define GLEW_STATIC
add_definitions(-DGLEW_STATIC)
set(TARGET_NAME oculus)
setup_hifi_plugin()
link_hifi_libraries(shared gl plugins display-plugins)
include_hifi_library_headers(octree)
add_dependency_external_projects(LibOVR)
find_package(LibOVR REQUIRED)
target_include_directories(${TARGET_NAME} PRIVATE ${LIBOVR_INCLUDE_DIRS})
target_link_libraries(${TARGET_NAME} ${LIBOVR_LIBRARIES})
endif()

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